Annotation of parser3/src/main/pa_int.C, revision 1.2

1.1       moko        1: /** @file
                      2:        Parser: pa_int support functions
                      3: 
                      4:        Copyright (c) 2001-2026 Art. Lebedev Studio (http://www.artlebedev.com)
                      5:        Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
                      6: */
                      7: 
                      8: #include "pa_int.h"
                      9: #include "pa_string.h"
                     10: #include "pa_exception.h"
                     11: 
1.2     ! moko       12: volatile const char * IDENT_PA_INT_C="$Id: pa_int.C,v 1.1 2026/01/06 13:07:58 moko Exp $" IDENT_PA_INT_H;
1.1       moko       13: 
                     14: // pa_atoui is based on Manuel Novoa III _strto_l for uClibc
                     15: 
                     16: template<typename T> inline T pa_ato_any(const char *str, int base, const String* problem_source,const T max){
                     17:        T result = 0;
                     18:        const char *pos = str;
                     19: 
                     20:        while (isspace(*pos)) /* skip leading whitespace */
                     21:                ++pos;
                     22: 
                     23:        if (base == 16 && *pos == '0') { /* handle option prefix */
                     24:                ++pos;
                     25:                if (*pos == 'x' || *pos == 'X') {
                     26:                        ++pos;
                     27:                }
                     28:        }
                     29: 
                     30:        if (base == 0) { /* dynamic base */
                     31:                base = 10; /* default is 10 */
                     32:                if (*pos == '0') {
                     33:                        ++pos;
                     34:                        if (*pos == 'x' || *pos == 'X'){
                     35:                                ++pos;
                     36:                                base=16;
                     37:                        }
                     38:                }
                     39:        }
                     40: 
                     41:        if (base < 2 || base > 16) /* illegal base */
                     42:                throw Exception(PARSER_RUNTIME, 0, "base to must be an integer from 2 to 16");
                     43:        if (*pos == '-')
                     44:                throw Exception("number.format", problem_source, problem_source ? "out of range (negative)" : "'%s' is out if range (negative)", str);
                     45: 
                     46:        T cutoff = max / base;
                     47:        int cutoff_digit = (int)(max - cutoff * base);
                     48: 
                     49:        while(true) {
                     50:                int digit;
                     51:                
                     52:                if ((*pos >= '0') && (*pos <= '9')) {
                     53:                        digit = (*pos - '0');
                     54:                } else if (*pos >= 'a') {
                     55:                        digit = (*pos - 'a' + 10);
                     56:                } else if (*pos >= 'A') {
                     57:                        digit = (*pos - 'A' + 10);
                     58:                } else break;
                     59: 
                     60:                if (digit >= base) {
                     61:                        break;
                     62:                }
                     63:                
                     64:                ++pos;
                     65:                
                     66:                /* adjust number, with overflow check */
                     67:                if ((result > cutoff) || ((result == cutoff) && (digit > cutoff_digit))) {
                     68:                        throw Exception("number.format", problem_source, problem_source ? "out of range (int)" : "'%s' is out of range (int)", str);
                     69:                } else {
                     70:                        result  = result * base + digit;
                     71:                }
                     72:        }
                     73: 
                     74:        while(char c=*pos++)
                     75:                if(!isspace(c))
                     76:                        throw Exception("number.format", problem_source, problem_source ? "invalid number (int)" : "'%s' is an invalid number (int)", str);
                     77: 
                     78:        return result;
                     79: }
                     80: 
                     81: unsigned int pa_atoui(const char *str, int base, const String* problem_source){
                     82:        if(!str)
                     83:                return 0;
                     84: 
                     85:        return pa_ato_any<unsigned int>(str, base, problem_source, UINT_MAX);
                     86: }
                     87: 
                     88: uint64_t pa_atoul(const char *str, int base, const String* problem_source){
                     89:        if(!str)
                     90:                return 0;
                     91: 
                     92:        return pa_ato_any<uint64_t>(str, base, problem_source, ULLONG_MAX);
                     93: }
                     94: 
                     95: int pa_atoi(const char* str, int base, const String* problem_source) {
                     96:        if(!str)
                     97:                return 0;
                     98: 
                     99:        while(isspace(*str))
                    100:                str++;
                    101: 
                    102:        if(!*str)
                    103:                return 0;
                    104: 
                    105:        const char *str_copy=str;
                    106:        bool negative=false;
                    107:        if(str[0]=='-') {
                    108:                negative=true;
                    109:                str++;
                    110:                if(!*str || isspace(*str))
                    111:                        throw Exception("number.format", problem_source, problem_source ? "invalid number (int)" : "'%s' is an invalid number (int)", str_copy);
                    112:        } else if(str[0]=='+') {
                    113:                str++;
                    114:                if(!*str || isspace(*str))
                    115:                        throw Exception("number.format", problem_source, problem_source ? "invalid number (int)" : "'%s' is an invalid number (int)", str_copy);
                    116:        }
                    117: 
                    118:        if(negative){
                    119:                const uint min_abs = (uint)(-( (uint)INT_MIN + 1 )) + 1;
                    120:                uint result=pa_ato_any<uint>(str, base, problem_source, min_abs);
                    121:                if(result==min_abs) return INT_MIN;
                    122:                return -(int)result;
                    123:        } else {
                    124:                return (int)pa_ato_any<uint>(str, base, problem_source, INT_MAX);
                    125:        }
                    126: }
                    127: 
                    128: pa_wint pa_atowi(const char* str, int base, const String* problem_source) {
                    129:        if(!str)
                    130:                return 0;
                    131: 
                    132:        while(isspace(*str))
                    133:                str++;
                    134: 
                    135:        if(!*str)
                    136:                return 0;
                    137: 
                    138:        const char *str_copy=str;
                    139:        bool negative=false;
                    140:        if(str[0]=='-') {
                    141:                negative=true;
                    142:                str++;
                    143:                if(!*str || isspace(*str))
                    144:                        throw Exception("number.format", problem_source, problem_source ? "invalid number (int)" : "'%s' is an invalid number (int)", str_copy);
                    145:        } else if(str[0]=='+') {
                    146:                str++;
                    147:                if(!*str || isspace(*str))
                    148:                        throw Exception("number.format", problem_source, problem_source ? "invalid number (int)" : "'%s' is an invalid number (int)", str_copy);
                    149:        }
                    150: 
                    151:        if(negative){
                    152:                const pa_uwint min_abs = (pa_uwint)(-( (pa_wint)PA_WINT_MIN + 1 )) + 1;
                    153:                pa_uwint result=pa_ato_any<pa_uwint>(str, base, problem_source, min_abs);
                    154:                if(result==min_abs) return PA_WINT_MIN;
                    155:                return -(pa_wint)result;
                    156:        } else {
                    157:                return (pa_wint)pa_ato_any<pa_uwint>(str, base, problem_source, PA_WINT_MAX);
                    158:        }
                    159: }
                    160: 
                    161: double pa_atod(const char* str, const String* problem_source /* never null */) {
                    162:        if(!str)
                    163:                return 0;
                    164: 
                    165:        while(isspace(*str))
                    166:                str++;
                    167: 
                    168:        if(!*str)
                    169:                return 0;
                    170: 
                    171:        bool negative=false;
                    172:        if(str[0]=='-') {
                    173:                negative=true;
                    174:                str++;
                    175:                if(!*str || isspace(*str))
                    176:                        throw Exception("number.format", problem_source, "invalid number (double)");
                    177:        } else if(str[0]=='+') {
                    178:                str++;
                    179:                if(!*str || isspace(*str))
                    180:                        throw Exception("number.format", problem_source, "invalid number (double)");
                    181:        }
                    182: 
                    183:        double result;
                    184:        if(str[0]=='0') {
                    185:                if(str[1]=='x' || str[1]=='X') {
                    186:                        // 0xABC
                    187:                        result=(double)pa_atoul(str, 0, problem_source);
                    188:                        return negative ? -result : result;
                    189:                } else {
                    190:                         // skip leading 0000, to disable octal interpretation
                    191:                        do str++; while(*str=='0');
                    192:                }
                    193:        }
                    194: 
                    195:        char *error_pos;
                    196:        result=strtod(str, &error_pos);
                    197: 
                    198:        while(const char c=*error_pos++)
                    199:                if(!isspace(c))
                    200:                        throw Exception("number.format", problem_source, "invalid number (double)");
                    201: 
                    202:        return negative ? -result : result;
                    203: }
                    204: 

E-mail: