Annotation of parser3/src/main/pa_int.C, revision 1.1
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:
! 12: volatile const char * IDENT_PA_STRING_C="$Id: pa_int.C,v 1.1 2025/05/26 00:52:15 moko Exp $" IDENT_PA_INT_H;
! 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: