File indexing completed on 2024-12-29 04:11:45
0001 /*************************************************************************** 0002 * * 0003 * Copyright : (C) 2010 The University of Toronto * 0004 * email : netterfield@astro.utoronto.ca * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 ***************************************************************************/ 0012 0013 // patched BSD V7 code 0014 // http://www.bsdlover.cn/study/UnixTree/V7/usr/src/libc/gen/atof.c.html 0015 0016 #include "kst_atof.h" 0017 #include "math_kst.h" 0018 0019 #include <math.h> 0020 #include <ctype.h> 0021 #include <locale.h> 0022 0023 #include <QLocale> 0024 #include <QTime> 0025 #include <QDateTime> 0026 #include <QDebug> 0027 0028 #define LOGHUGE 39 0029 0030 0031 //------------------------------------------------------------------------------------------- 0032 #ifdef KST_USE_KST_ATOF 0033 double LexicalCast::fromDouble(const char* signedp) const 0034 { 0035 unsigned char* p = (unsigned char*)signedp; 0036 unsigned char c; 0037 double fl, flexp, exp5; 0038 double big = 72057594037927936.; /*2^56*/ 0039 int nd; 0040 int eexp, exp, neg, negexp, bexp; 0041 0042 neg = 1; 0043 while((c = *p++) == ' ') 0044 ; 0045 if (c == '-') 0046 neg = -1; 0047 else if (c=='+') 0048 ; 0049 else 0050 --p; 0051 0052 if (_nanMode != NullValue && c != '-' && c != '+' && c != _separator && !isDigit(c)) { 0053 return nanValue(); 0054 } 0055 0056 0057 exp = 0; 0058 fl = 0; 0059 nd = 0; 0060 while ((c = *p++), isDigit(c)) { 0061 if (fl<big) 0062 fl = 10*fl + (c-'0'); 0063 else 0064 exp++; 0065 nd++; 0066 } 0067 0068 if (c == _separator) { 0069 while ((c = *p++), isDigit(c)) { 0070 if (fl<big) { 0071 fl = 10*fl + (c-'0'); 0072 exp--; 0073 } 0074 nd++; 0075 } 0076 } 0077 0078 negexp = 1; 0079 eexp = 0; 0080 if ((c == 'E') || (c == 'e')) { 0081 if ((c= *p++) == '+') 0082 ; 0083 else if (c=='-') 0084 negexp = -1; 0085 else 0086 --p; 0087 0088 while ((c = *p++), isDigit(c)) { 0089 eexp = 10*eexp+(c-'0'); 0090 } 0091 if (negexp<0) 0092 eexp = -eexp; 0093 exp = exp + eexp; 0094 } 0095 0096 negexp = 1; 0097 if (exp<0) { 0098 negexp = -1; 0099 exp = -exp; 0100 } 0101 0102 0103 if((nd+exp*negexp) < -LOGHUGE){ 0104 fl = 0; 0105 exp = 0; 0106 } 0107 flexp = 1; 0108 exp5 = 5; 0109 bexp = exp; 0110 for (;;) { 0111 if (exp&01) 0112 flexp *= exp5; 0113 exp >>= 1; 0114 if (exp==0) 0115 break; 0116 exp5 *= exp5; 0117 } 0118 if (negexp<0) 0119 fl /= flexp; 0120 else 0121 fl *= flexp; 0122 fl = ldexp(fl, negexp*bexp); 0123 if (neg<0) 0124 fl = -fl; 0125 _previousValue = fl; 0126 return(fl); 0127 } 0128 #endif 0129 0130 0131 //------------------------------------------------------------------------------------------- 0132 LexicalCast::AutoReset::AutoReset(bool useDot, NaNMode mode) 0133 { 0134 instance().setUseDotAsDecimalSeparator(useDot); 0135 instance()._nanMode = mode; 0136 } 0137 0138 //------------------------------------------------------------------------------------------- 0139 LexicalCast::AutoReset::~AutoReset() 0140 { 0141 instance().resetLocal(); 0142 instance()._isFormattedTime = false; 0143 instance()._timeFormat.clear(); 0144 instance()._nanMode = NullValue; 0145 } 0146 0147 //------------------------------------------------------------------------------------------- 0148 LexicalCast& LexicalCast::instance() 0149 { 0150 static LexicalCast lexcInstance; 0151 return lexcInstance; 0152 } 0153 0154 //------------------------------------------------------------------------------------------- 0155 LexicalCast::LexicalCast() : 0156 _nanMode(NullValue), 0157 _isFormattedTime(false), 0158 _timeWithDate(false) 0159 { 0160 } 0161 0162 KST_THREAD_LOCAL double LexicalCast::_previousValue = 0; 0163 0164 //------------------------------------------------------------------------------------------- 0165 LexicalCast::~LexicalCast() 0166 { 0167 resetLocal(); 0168 } 0169 0170 //------------------------------------------------------------------------------------------- 0171 void LexicalCast::resetLocal() 0172 { 0173 if (!_originalLocal.isEmpty()) { 0174 setlocale(LC_NUMERIC, _originalLocal.constData()); 0175 _originalLocal.clear(); 0176 } 0177 } 0178 0179 //------------------------------------------------------------------------------------------- 0180 void LexicalCast::setUseDotAsDecimalSeparator(bool useDot) 0181 { 0182 useDot ? _separator = '.' : _separator = ','; 0183 0184 if (_separator != localSeparator()) { 0185 _originalLocal = QByteArray((const char*) setlocale(LC_NUMERIC, 0)); 0186 if (useDot) { 0187 setlocale(LC_NUMERIC, "C"); 0188 } else { 0189 setlocale(LC_NUMERIC, "de"); 0190 } 0191 } else { 0192 resetLocal(); 0193 } 0194 } 0195 0196 //------------------------------------------------------------------------------------------- 0197 char LexicalCast::localSeparator() const 0198 { 0199 return *setlocale(LC_NUMERIC, 0); 0200 } 0201 0202 //------------------------------------------------------------------------------------------- 0203 void LexicalCast::setTimeFormat(const QString& format) 0204 { 0205 _timeFormat = format.trimmed(); // remove space at start/end 0206 _isFormattedTime = !format.isEmpty(); 0207 _timeWithDate = format.contains("d") || format.contains("M") || format.contains("y"); 0208 _timeFormatLength = _timeFormat.size(); 0209 } 0210 0211 //------------------------------------------------------------------------------------------- 0212 double LexicalCast::fromTime(const char* p) const 0213 { 0214 for (int i = 0; i < _timeFormatLength; i++) { 0215 if (*(p + i) == '\0') 0216 return nanValue(); 0217 } 0218 0219 const QString time = QString::fromLatin1(p, _timeFormatLength); 0220 double sec = nanValue(); 0221 if (_timeWithDate) { 0222 QDateTime t = QDateTime::fromString(time, _timeFormat); 0223 if (!t.isValid()) { 0224 return nanValue(); 0225 } 0226 t.setTimeSpec(Qt::UTC); 0227 #if QT_VERSION >= 0x040700 0228 sec = t.toMSecsSinceEpoch() / 1000.0; 0229 #else 0230 sec = t.toTime_t(); 0231 #endif 0232 } else { 0233 const QTime t = QTime::fromString(time, _timeFormat); 0234 if (t.isValid()) 0235 sec = QTime(0, 0, 0).msecsTo(t) / 1000.0; 0236 } 0237 _previousValue = sec; 0238 return sec; 0239 } 0240 0241 0242 0243 // vim: ts=2 sw=2 et