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