Ignore:
Timestamp:
02/05/15 00:26:20 (9 years ago)
Author:
Maciej Komosinski
Message:

More strict parsing of int and float numbers from string

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/util/extvalue.cpp

    r286 r325  
    1212#include <common/nonstd_math.h>
    1313#include <common/Convert.h>
     14#include <climits>
    1415
    1516#ifndef NO_BARRIER
     
    609610}
    610611
    611 paInt ExtValue::getInt(const char* s)
    612 {
    613 if ((s[0]=='0')&&(s[1]=='x'))
    614         {
    615         paInt val;
    616         sscanf(s+2,PA_INT_SCANF_X,&val);
    617         return val;
    618         }
    619 else
    620         {
    621         if (strchr(s,'e')||(strchr(s,'E')))
    622                 return (paInt)atof(s);
    623         else
    624                 return atoi(s);
    625         }
     612bool ExtValue::parseInt(const char* s, paInt &result, bool strict)
     613{
     614        ExtValue tmp;
     615        const char* after = tmp.parseNumber(s, strict ? TInt : TUnknown);
     616        if (after == NULL) return false;
     617        if (after[0] != 0) return false;
     618        result = tmp.getInt();
     619        return true;
     620}
     621
     622bool ExtValue::parseDouble(const char* s, double &result)
     623{
     624        ExtValue tmp;
     625        const char* after = tmp.parseNumber(s, TDouble);
     626        if (after == NULL) return false;
     627        if (after[0] != 0) return false;
     628        result = tmp.getDouble();
     629        return true;
     630}
     631
     632paInt ExtValue::getInt(const char* s,bool strict)
     633{
     634        paInt result;
     635        if (parseInt(s, result, strict))
     636                return result;
     637        FMprintf("ExtValue", "getInt", FMLV_ERROR, "Could not parse '%s'%s", s, strict?" (strict)":"");
     638        return 0;
    626639}
    627640
    628641double ExtValue::getDouble(const char* s)
    629642{
    630 if ((s[0]=='0')&&(s[1]=='x'))
    631         {
    632         paInt val;
    633         sscanf(s+2,PA_INT_SCANF_X,&val);
    634         return val;
    635         }
    636 else
    637         return atof(s);
     643        double result;
     644        if (parseDouble(s, result))
     645                return result;
     646        FMprintf("ExtValue", "getDouble", FMLV_ERROR, "Could not parse '%s'", s);
     647        return 0;
    638648}
    639649
    640650paInt ExtValue::getInt() const
    641651{
    642 switch(type)
     652        switch (type)
    643653        {
    644654        case TInt: return idata();
     
    646656        case TString: return getInt((const char*)sdata());
    647657        case TObj:
    648                 FMprintf("ExtValue","getInt",FMLV_WARN,"Getting integer value from object reference (%s)",(const char*)getString());
     658                FMprintf("ExtValue", "getInt", FMLV_WARN, "Getting integer value from object reference (%s)", (const char*)getString());
    649659                return (paInt)(intptr_t)odata().param;
    650660        default:;
    651661        }
    652 return 0;
     662        return 0;
    653663}
    654664
    655665double ExtValue::getDouble() const
    656666{
    657 switch(type)
     667        switch (type)
    658668        {
    659669        case TDouble: return ddata();
     
    661671        case TString: return getDouble((const char*)sdata());
    662672        case TObj:
    663                 FMprintf("ExtValue","getDouble",FMLV_WARN,"Getting floating point value from object reference (%s)",(const char*)getString());
     673                FMprintf("ExtValue", "getDouble", FMLV_WARN, "Getting floating point value from object reference (%s)", (const char*)getString());
    664674                return (double)(intptr_t)odata().param;
    665675        default:;
    666676        }
    667 return 0.0;
    668 }
     677        return 0.0;
     678}
     679
    669680SString ExtValue::getString() const
    670681{
    671 switch(type)
     682        switch (type)
    672683        {
    673684        case TString: return sdata();
     
    682693const SString* ExtValue::getStringPtr() const
    683694{
    684 if (type==TString)
    685         return &sdata();
    686 return NULL;
     695        if (type == TString)
     696                return &sdata();
     697        return NULL;
    687698}
    688699
     
    710721}
    711722
    712 //returns the first character after the parsed number or NULL if not a number
    713 const char* ExtValue::parseNumber(const char* in)
    714 {
    715 if (isdigit(*in)||((*in=='-')&&(isdigit(in[1]))))
    716         {
    717         const char* p=in;
    718         if (*p=='-') p++;
    719         while(isdigit(*p)) p++;
    720         bool fp=false;
    721         if ((*p=='.') && isdigit(p[1]))
    722                 {
    723                 p++;
    724                 while(isdigit(*p)) p++;
    725                 fp=true;
    726                 }
    727         if (((*p=='e')||(*p=='E')) && (isdigit(p[1]) || (((p[1]=='-') || (p[1]=='+')) && isdigit(p[2]))))
    728                 {
    729                 p++;
    730                 if ((*p=='-')||(*p=='+')) p++;
    731                 while(isdigit(*p)) p++;
    732                 fp=true;
    733                 }
    734 
    735         if (fp)
    736                 {
    737                 setDouble(atof(in));
    738                 return p;
    739                 }
    740         else
    741                 {
    742                 setInt(atoi(in));
    743                 return p;
    744                 }
    745         }
    746 return NULL;
     723/// returns the first character after the parsed number, or NULL if not a number
     724/// @param strict_type = restrict the allowed return value (TUnknown = unrestricted)
     725const char* ExtValue::parseNumber(const char* in, ExtPType strict_type)
     726{
     727        char* after;
     728        if (in == NULL) return NULL;
     729        if (in[0] == 0) return NULL;
     730        while (isspace(*in)) in++;
     731        bool minus = false;
     732        if (((in[0] == '0') && (in[1] == 'x'))
     733                || (((minus = (in[0] == '-')) && (in[1] == '0') && (in[2] == 'x'))))
     734        {
     735                in += minus ? 3 : 2;
     736                if (isspace(*in)) return NULL;
     737                errno = 0;
     738                unsigned long intvalue = strtoul(in, &after, 16);
     739                if ((after > in) && (errno == 0) && (intvalue <= 0xffffffff))
     740                {
     741                        if (strict_type == TDouble)
     742                                setDouble(minus ? -(double)intvalue : (double)intvalue);
     743                        else
     744                                setInt(minus ? -intvalue : intvalue);
     745                        return after;
     746                }
     747                else
     748                        return NULL;
     749        }
     750
     751        errno = 0;
     752        double fpvalue = strtod(in, &after);
     753        if ((after > in) && (errno == 0))
     754        {
     755                if (strict_type != TDouble)
     756                {
     757                        if ((memchr(in, '.', after - in) == NULL) && (memchr(in, 'e', after - in) == NULL) && (memchr(in, 'E', after - in) == NULL) // no "special" characters
     758                                && (fpvalue == floor(fpvalue)) // value is integer
     759                                && (fpvalue >= INT_MIN) && (fpvalue <= INT_MAX)) // within limits
     760                        {
     761                                setInt(fpvalue);
     762                                return after;
     763                        }
     764                        else if (strict_type == TInt)
     765                                return NULL;
     766                }
     767                setDouble(fpvalue);
     768                return after;
     769        }
     770        return NULL;
    747771}
    748772
     
    858882        in++;
    859883        ExtValue ref;
    860         ret=ref.parseNumber(in);
     884        ret=ref.parseNumber(in,TInt);
    861885        if (ret && (ref.getType()==TInt))
    862886                {
Note: See TracChangeset for help on using the changeset viewer.