/* * $QNXLicenseC: * Copyright 2007, QNX Software Systems. All Rights Reserved. * * You must obtain a written license from and pay applicable license fees to QNX * Software Systems before you may reproduce, modify or distribute this software, * or any work that includes all or part of this software. Free development * licenses are available for evaluation and non-commercial purposes. For more * information visit http://licensing.qnx.com or email licensing@qnx.com. * * This file may contain contributions from others. Please review this entire * file for other proprietary rights or license notices, as well as the QNX * Development Suite License Guide at http://licensing.qnx.com/license-guide/ * for other information. * $ */ /* * This convert a string to a constant using the POSIX locale */ #include #include #include #include #define _STOINT_SIGNED 0x1 #define _STOINT_LLONG 0x2 #define LLONG_MAX 9223372036854775807LL #define LLONG_MIN (-LLONG_MAX - 1LL) #define ULLONG_MAX 18446744073709551615ULL u_int64_t _Stoint(const char *nptr, char **endptr, int base, int flags) { int neg, overflow, once; const char *p; u_int64_t ll_value; unsigned long l_value; int n; /* Part 1, skip white space characters */ p = nptr; while(isspace(*p)) { p++; } /* Part 2, Optional sign */ neg = 0; if(*p == '+') { p++; } else if(*p == '-') { neg = 1; p++; } /* start with 0 for octal, 0x or 0X for hex, rest is decimal */ if(base == 0) { if(*p == '0') { if(*(p+1) == 'x' || *(p+1) == 'X') { p += 2; base = 16; } else { base = 8; } } else { base = 10; } } else if(base == 16 && *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) { /* Base 16 is allowed to start with 0x or 0X if there */ p += 2; } ll_value = 0; l_value = 0; once = overflow = 0; /* Only valid bases are 2 to 36 */ if(base >= 2 && base <= 36) { while(n = *p) { u_int64_t ll_save; unsigned long l_save; /* Adjust character to from a char to an integer */ if(n >= '0' && n <= '9') { n -= '0'; } else if(n >= 'a' && n <= 'z') { n -= 'a' - 10; } else if(n >= 'A' && n <= 'Z') { n -= 'A' - 10; } else { /* Unknown, done */ break; } if(n >= base) { /* Out of radix range, done */ break; } /* Character is valid */ p++; /* Scale, and add digit, check for overflow */ if (flags & _STOINT_LLONG) { ll_save = ll_value; ll_value = ll_value * base + n; if(ll_value < ll_save) { overflow = 1; } } else { l_save = l_value; l_value = l_value * base + n; if(l_value < l_save) { overflow = 1; } } once = 1; } /* Check for a signed number overflow */ if(flags & _STOINT_SIGNED) { if(flags & _STOINT_LLONG) { if(((int64_t)ll_value < 0) && !(neg && (ll_value == -(u_int64_t)LLONG_MIN))) { overflow = 1; } } else { if(((long)l_value < 0) && !(neg && (l_value == -(unsigned long)LONG_MIN))) { overflow = 1; } } } } /* Store the end of part 2, so caller can get to part 3 */ if(endptr) { *endptr = (char *)(once ? p : nptr); } /* If base not supported or no conversion was done, return 0 setting errno to EINVAL (UNIX98) */ if(!once) { errno = EINVAL; return 0; } /* If no conversion was done, return respective max setting errno to ERANGE (UNIX98) */ if(overflow) { errno = ERANGE; if (flags & _STOINT_LLONG) { return (flags & _STOINT_SIGNED) ? (neg ? LLONG_MIN : LLONG_MAX) : ULLONG_MAX; } else { return (flags & _STOINT_SIGNED) ? (neg ? LONG_MIN : LONG_MAX) : ULONG_MAX; } } /* Everything OK, return the number */ if (flags & _STOINT_LLONG) { return neg ? -ll_value : ll_value; } else { return neg ? -l_value : l_value; } }