/* A wrapper around strtol() and strtoul() to correct some * "out of bounds" cases that don't work well on at least UTS. * If a value is Larger than the max, strto[u]l should return * the max value, and set errno to ERANGE * The same if a value is smaller than the min value (only * relevant for strtol(); not strtoul()), except the minimum * value is returned (and errno == ERANGE). */ #include #include #include #include extern int errno; #undef I32 #undef U32 #define I32 int #define U32 unsigned int struct base_info { char *ValidChars; char *Ulong_max_str; char *Long_max_str; char *Long_min_str; /* Absolute value */ int Ulong_max_str_len; int Long_max_str_len; int Long_min_str_len; /* Absolute value */ U32 Ulong_max; I32 Long_max; I32 Long_min; /* NOT Absolute value */ }; static struct base_info Base_info[37]; static struct base_info Base_info_16 = { "0123456789abcdefABCDEF", "4294967295", "2147483648" /* <== ABS VAL */ , "2147483647", 10, 10, 10, 4294967295, 2147483647, - 2147483648, }; static struct base_info Base_info_10 = { "0123456789", "4294967295", "2147483648" /* <== ABS VAL */ , "2147483647", 10, 10, 10, 4294967295, 2147483647, - 2147483648, }; /* Used eventually (if this is fully developed) to hold info * for processing bases 2-36. So that we can just plug the * base in as a selector for its info, we sacrifice * Base_info[0] and Base_info[1] (unless they are used * at some point for special information). */ /* This may be replaced later by something more universal */ static void init_Base_info() { if(Base_info[10].ValidChars) return; Base_info[10] = Base_info_10; Base_info[16] = Base_info_16; } unsigned int strtoul_wrap32(char *s, char **pEnd, int base) { int Len; int isNegated = 0; char *sOrig = s; init_Base_info(); while(*s && isspace(*s)) ++s; if(*s == '-') { ++isNegated; ++s; while(*s && isspace(*s)) ++s; } if(base == 0) { if(*s == '0') { if(s[1] == 'x' || s[1] == 'X') { s += 2; base = 16; } else { ++s; base = 8; } } else if(isdigit(*s)) { base = 10; } } if(base != 10) { return strtoul(sOrig, pEnd, base); } Len = strspn(s, Base_info[base].ValidChars); if(Len > Base_info[base].Ulong_max_str_len || (Len == Base_info[base].Ulong_max_str_len && strncmp(Base_info[base].Ulong_max_str, s, Len) < 0) ) { /* In case isNegated is set - what to do?? */ /* Mightn't we say a negative number is ERANGE for strtoul? */ errno = ERANGE; return Base_info[base].Ulong_max; } return strtoul(sOrig, pEnd, base); } int strtol_wrap32(char *s, char **pEnd, int base) { int Len; int isNegated = 0; char *sOrig = s; init_Base_info(); while(*s && isspace(*s)) ++s; if(*s == '-') { ++isNegated; ++s; while(*s && isspace(*s)) ++s; } if(base == 0) { if(*s == '0') { if(s[1] == 'x' || s[1] == 'X') { s += 2; base = 16; } else { ++s; base = 8; } } else if(isdigit(*s)) { base = 10; } } if(base != 10) { return strtol(sOrig, pEnd, base); } Len = strspn(s, Base_info[base].ValidChars); if(Len > Base_info[base].Long_max_str_len || (!isNegated && Len == Base_info[base].Long_max_str_len && strncmp(Base_info[base].Long_max_str, s, Len) < 0) || (isNegated && Len == Base_info[base].Long_min_str_len && strncmp(Base_info[base].Long_min_str, s, Len) < 0) ) { /* In case isNegated is set - what to do?? */ /* Mightn't we say a negative number is ERANGE for strtol? */ errno = ERANGE; return(isNegated ? Base_info[base].Long_min : Base_info[base].Long_min); } return strtol(sOrig, pEnd, base); }