os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/compat/strtoull.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* 
sl@0
     2
 * strtoull.c --
sl@0
     3
 *
sl@0
     4
 *	Source code for the "strtoull" library procedure.
sl@0
     5
 *
sl@0
     6
 * Copyright (c) 1988 The Regents of the University of California.
sl@0
     7
 * Copyright (c) 1994 Sun Microsystems, Inc.
sl@0
     8
 *
sl@0
     9
 * See the file "license.terms" for information on usage and redistribution
sl@0
    10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    11
 *
sl@0
    12
 * RCS: @(#) $Id: strtoull.c,v 1.5 2002/02/24 02:53:25 dgp Exp $
sl@0
    13
 */
sl@0
    14
sl@0
    15
#include "tcl.h"
sl@0
    16
#include "tclPort.h"
sl@0
    17
#include <ctype.h>
sl@0
    18
sl@0
    19
/*
sl@0
    20
 * The table below is used to convert from ASCII digits to a
sl@0
    21
 * numerical equivalent.  It maps from '0' through 'z' to integers
sl@0
    22
 * (100 for non-digit characters).
sl@0
    23
 */
sl@0
    24
sl@0
    25
static char cvtIn[] = {
sl@0
    26
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,		/* '0' - '9' */
sl@0
    27
    100, 100, 100, 100, 100, 100, 100,		/* punctuation */
sl@0
    28
    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'A' - 'Z' */
sl@0
    29
    20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
sl@0
    30
    30, 31, 32, 33, 34, 35,
sl@0
    31
    100, 100, 100, 100, 100, 100,		/* punctuation */
sl@0
    32
    10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'a' - 'z' */
sl@0
    33
    20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
sl@0
    34
    30, 31, 32, 33, 34, 35};
sl@0
    35
sl@0
    36

sl@0
    37
/*
sl@0
    38
 *----------------------------------------------------------------------
sl@0
    39
 *
sl@0
    40
 * strtoull --
sl@0
    41
 *
sl@0
    42
 *	Convert an ASCII string into an integer.
sl@0
    43
 *
sl@0
    44
 * Results:
sl@0
    45
 *	The return value is the integer equivalent of string.  If endPtr
sl@0
    46
 *	is non-NULL, then *endPtr is filled in with the character
sl@0
    47
 *	after the last one that was part of the integer.  If string
sl@0
    48
 *	doesn't contain a valid integer value, then zero is returned
sl@0
    49
 *	and *endPtr is set to string.
sl@0
    50
 *
sl@0
    51
 * Side effects:
sl@0
    52
 *	None.
sl@0
    53
 *
sl@0
    54
 *----------------------------------------------------------------------
sl@0
    55
 */
sl@0
    56
sl@0
    57
#if TCL_WIDE_INT_IS_LONG
sl@0
    58
unsigned long long
sl@0
    59
#else
sl@0
    60
Tcl_WideUInt
sl@0
    61
#endif
sl@0
    62
strtoull(string, endPtr, base)
sl@0
    63
    CONST char *string;		/* String of ASCII digits, possibly
sl@0
    64
				 * preceded by white space.  For bases
sl@0
    65
				 * greater than 10, either lower- or
sl@0
    66
				 * upper-case digits may be used.
sl@0
    67
				 */
sl@0
    68
    char **endPtr;		/* Where to store address of terminating
sl@0
    69
				 * character, or NULL. */
sl@0
    70
    int base;			/* Base for conversion.  Must be less
sl@0
    71
				 * than 37.  If 0, then the base is chosen
sl@0
    72
				 * from the leading characters of string:
sl@0
    73
				 * "0x" means hex, "0" means octal, anything
sl@0
    74
				 * else means decimal.
sl@0
    75
				 */
sl@0
    76
{
sl@0
    77
    register CONST char *p;
sl@0
    78
    register Tcl_WideUInt result = 0;
sl@0
    79
    register unsigned digit;
sl@0
    80
    register Tcl_WideUInt shifted;
sl@0
    81
    int anyDigits = 0, negative = 0;
sl@0
    82
sl@0
    83
    /*
sl@0
    84
     * Skip any leading blanks.
sl@0
    85
     */
sl@0
    86
sl@0
    87
    p = string;
sl@0
    88
    while (isspace(UCHAR(*p))) {	/* INTL: locale-dependent */
sl@0
    89
	p += 1;
sl@0
    90
    }
sl@0
    91
sl@0
    92
    /*
sl@0
    93
     * Check for a sign.
sl@0
    94
     */
sl@0
    95
sl@0
    96
    if (*p == '-') {
sl@0
    97
	p += 1;
sl@0
    98
	negative = 1;
sl@0
    99
    } else {
sl@0
   100
	if (*p == '+') {
sl@0
   101
	    p += 1;
sl@0
   102
	}
sl@0
   103
    }
sl@0
   104
sl@0
   105
    /*
sl@0
   106
     * If no base was provided, pick one from the leading characters
sl@0
   107
     * of the string.
sl@0
   108
     */
sl@0
   109
    
sl@0
   110
    if (base == 0) {
sl@0
   111
	if (*p == '0') {
sl@0
   112
	    p += 1;
sl@0
   113
	    if (*p == 'x' || *p == 'X') {
sl@0
   114
		p += 1;
sl@0
   115
		base = 16;
sl@0
   116
	    } else {
sl@0
   117
sl@0
   118
		/*
sl@0
   119
		 * Must set anyDigits here, otherwise "0" produces a
sl@0
   120
		 * "no digits" error.
sl@0
   121
		 */
sl@0
   122
sl@0
   123
		anyDigits = 1;
sl@0
   124
		base = 8;
sl@0
   125
	    }
sl@0
   126
	} else {
sl@0
   127
	    base = 10;
sl@0
   128
	}
sl@0
   129
    } else if (base == 16) {
sl@0
   130
sl@0
   131
	/*
sl@0
   132
	 * Skip a leading "0x" from hex numbers.
sl@0
   133
	 */
sl@0
   134
sl@0
   135
	if ((p[0] == '0') && (p[1] == 'x' || *p == 'X')) {
sl@0
   136
	    p += 2;
sl@0
   137
	}
sl@0
   138
    }
sl@0
   139
sl@0
   140
    /*
sl@0
   141
     * Sorry this code is so messy, but speed seems important.  Do
sl@0
   142
     * different things for base 8, 10, 16, and other.
sl@0
   143
     */
sl@0
   144
sl@0
   145
    if (base == 8) {
sl@0
   146
	for ( ; ; p += 1) {
sl@0
   147
	    digit = *p - '0';
sl@0
   148
	    if (digit > 7) {
sl@0
   149
		break;
sl@0
   150
	    }
sl@0
   151
	    shifted = result << 3;
sl@0
   152
	    if ((shifted >> 3) != result) {
sl@0
   153
		goto overflow;
sl@0
   154
	    }
sl@0
   155
	    result = shifted + digit;
sl@0
   156
	    if ( result < shifted ) {
sl@0
   157
		goto overflow;
sl@0
   158
	    }
sl@0
   159
	    anyDigits = 1;
sl@0
   160
	}
sl@0
   161
    } else if (base == 10) {
sl@0
   162
	for ( ; ; p += 1) {
sl@0
   163
	    digit = *p - '0';
sl@0
   164
	    if (digit > 9) {
sl@0
   165
		break;
sl@0
   166
	    }
sl@0
   167
	    shifted = 10 * result;
sl@0
   168
	    if ((shifted / 10) != result) {
sl@0
   169
		goto overflow;
sl@0
   170
	    }
sl@0
   171
	    result = shifted + digit;
sl@0
   172
	    if ( result < shifted ) {
sl@0
   173
		goto overflow;
sl@0
   174
	    }
sl@0
   175
	    anyDigits = 1;
sl@0
   176
	}
sl@0
   177
    } else if (base == 16) {
sl@0
   178
	for ( ; ; p += 1) {
sl@0
   179
	    digit = *p - '0';
sl@0
   180
	    if (digit > ('z' - '0')) {
sl@0
   181
		break;
sl@0
   182
	    }
sl@0
   183
	    digit = cvtIn[digit];
sl@0
   184
	    if (digit > 15) {
sl@0
   185
		break;
sl@0
   186
	    }
sl@0
   187
	    shifted = result << 4;
sl@0
   188
	    if ((shifted >> 4) != result) {
sl@0
   189
		goto overflow;
sl@0
   190
	    }
sl@0
   191
	    result = shifted + digit;
sl@0
   192
	    if ( result < shifted ) {
sl@0
   193
		goto overflow;
sl@0
   194
	    }
sl@0
   195
	    anyDigits = 1;
sl@0
   196
	}
sl@0
   197
    } else if ( base >= 2 && base <= 36 ) {
sl@0
   198
	for ( ; ; p += 1) {
sl@0
   199
	    digit = *p - '0';
sl@0
   200
	    if (digit > ('z' - '0')) {
sl@0
   201
		break;
sl@0
   202
	    }
sl@0
   203
	    digit = cvtIn[digit];
sl@0
   204
	    if (digit >= (unsigned) base) {
sl@0
   205
		break;
sl@0
   206
	    }
sl@0
   207
	    shifted = result * base;
sl@0
   208
	    if ((shifted/base) != result) {
sl@0
   209
		goto overflow;
sl@0
   210
	    }
sl@0
   211
	    result = shifted + digit;
sl@0
   212
	    if ( result < shifted ) {
sl@0
   213
		goto overflow;
sl@0
   214
	    }
sl@0
   215
	    anyDigits = 1;
sl@0
   216
	}
sl@0
   217
    }
sl@0
   218
sl@0
   219
    /*
sl@0
   220
     * Negate if we found a '-' earlier.
sl@0
   221
     */
sl@0
   222
sl@0
   223
    if (negative) {
sl@0
   224
	result = (Tcl_WideUInt)(-((Tcl_WideInt)result));
sl@0
   225
    }
sl@0
   226
sl@0
   227
    /*
sl@0
   228
     * See if there were any digits at all.
sl@0
   229
     */
sl@0
   230
sl@0
   231
    if (!anyDigits) {
sl@0
   232
	p = string;
sl@0
   233
    }
sl@0
   234
sl@0
   235
    if (endPtr != 0) {
sl@0
   236
	*endPtr = (char *) p;
sl@0
   237
    }
sl@0
   238
sl@0
   239
    return result;
sl@0
   240
sl@0
   241
    /*
sl@0
   242
     * On overflow generate the right output
sl@0
   243
     */
sl@0
   244
sl@0
   245
 overflow:
sl@0
   246
    errno = ERANGE;
sl@0
   247
    if (endPtr != 0) {
sl@0
   248
	for ( ; ; p += 1) {
sl@0
   249
	    digit = *p - '0';
sl@0
   250
	    if (digit > ('z' - '0')) {
sl@0
   251
		break;
sl@0
   252
	    }
sl@0
   253
	    digit = cvtIn[digit];
sl@0
   254
	    if (digit >= (unsigned) base) {
sl@0
   255
		break;
sl@0
   256
	    }
sl@0
   257
	}
sl@0
   258
	*endPtr = (char *) p;
sl@0
   259
    }
sl@0
   260
    return (Tcl_WideUInt)Tcl_LongAsWide(-1);
sl@0
   261
}