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