165 lines
3.8 KiB
C
165 lines
3.8 KiB
C
/*
|
|
* $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 <stdlib.h>
|
|
#include <limits.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
|
|
#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;
|
|
}
|
|
}
|
|
|