os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/compat/strtoul.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /* 
     2  * strtoul.c --
     3  *
     4  *	Source code for the "strtoul" 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: strtoul.c,v 1.5 2002/02/25 10:36:32 dkf Exp $
    13  */
    14 
    15 #include "tclInt.h"
    16 #include "tclPort.h"
    17 
    18 /*
    19  * The table below is used to convert from ASCII digits to a
    20  * numerical equivalent.  It maps from '0' through 'z' to integers
    21  * (100 for non-digit characters).
    22  */
    23 
    24 static char cvtIn[] = {
    25     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,		/* '0' - '9' */
    26     100, 100, 100, 100, 100, 100, 100,		/* punctuation */
    27     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'A' - 'Z' */
    28     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
    29     30, 31, 32, 33, 34, 35,
    30     100, 100, 100, 100, 100, 100,		/* punctuation */
    31     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,	/* 'a' - 'z' */
    32     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
    33     30, 31, 32, 33, 34, 35};
    34 
    35 /*
    36  *----------------------------------------------------------------------
    37  *
    38  * strtoul --
    39  *
    40  *	Convert an ASCII string into an integer.
    41  *
    42  * Results:
    43  *	The return value is the integer equivalent of string.  If endPtr
    44  *	is non-NULL, then *endPtr is filled in with the character
    45  *	after the last one that was part of the integer.  If string
    46  *	doesn't contain a valid integer value, then zero is returned
    47  *	and *endPtr is set to string.
    48  *
    49  * Side effects:
    50  *	None.
    51  *
    52  *----------------------------------------------------------------------
    53  */
    54 
    55 unsigned long int
    56 strtoul(string, endPtr, base)
    57     CONST char *string;		/* String of ASCII digits, possibly
    58 				 * preceded by white space.  For bases
    59 				 * greater than 10, either lower- or
    60 				 * upper-case digits may be used.
    61 				 */
    62     char **endPtr;		/* Where to store address of terminating
    63 				 * character, or NULL. */
    64     int base;			/* Base for conversion.  Must be less
    65 				 * than 37.  If 0, then the base is chosen
    66 				 * from the leading characters of string:
    67 				 * "0x" means hex, "0" means octal, anything
    68 				 * else means decimal.
    69 				 */
    70 {
    71     register CONST char *p;
    72     register unsigned long int result = 0;
    73     register unsigned digit;
    74     int anyDigits = 0;
    75     int negative=0;
    76     int overflow=0;
    77 
    78     /*
    79      * Skip any leading blanks.
    80      */
    81 
    82     p = string;
    83     while (isspace(UCHAR(*p))) {
    84 	p += 1;
    85     }
    86     if (*p == '-') {
    87         negative = 1;
    88         p += 1;
    89     } else {
    90         if (*p == '+') {
    91             p += 1;
    92         }
    93     }
    94 
    95     /*
    96      * If no base was provided, pick one from the leading characters
    97      * of the string.
    98      */
    99     
   100     if (base == 0)
   101     {
   102 	if (*p == '0') {
   103 	    p += 1;
   104 	    if ((*p == 'x') || (*p == 'X')) {
   105 		p += 1;
   106 		base = 16;
   107 	    } else {
   108 
   109 		/*
   110 		 * Must set anyDigits here, otherwise "0" produces a
   111 		 * "no digits" error.
   112 		 */
   113 
   114 		anyDigits = 1;
   115 		base = 8;
   116 	    }
   117 	}
   118 	else base = 10;
   119     } else if (base == 16) {
   120 
   121 	/*
   122 	 * Skip a leading "0x" from hex numbers.
   123 	 */
   124 
   125 	if ((p[0] == '0') && ((p[1] == 'x') || (p[1] == 'X'))) {
   126 	    p += 2;
   127 	}
   128     }
   129 
   130     /*
   131      * Sorry this code is so messy, but speed seems important.  Do
   132      * different things for base 8, 10, 16, and other.
   133      */
   134 
   135     if (base == 8) {
   136 	unsigned long maxres = ULONG_MAX >> 3;
   137 	for ( ; ; p += 1) {
   138 	    digit = *p - '0';
   139 	    if (digit > 7) {
   140 		break;
   141 	    }
   142 	    if (result > maxres) { overflow = 1; }
   143 	    result = (result << 3);
   144 	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
   145 	    result += digit;
   146 	    anyDigits = 1;
   147 	}
   148     } else if (base == 10) {
   149 	unsigned long maxres = ULONG_MAX / 10;
   150 	for ( ; ; p += 1) {
   151 	    digit = *p - '0';
   152 	    if (digit > 9) {
   153 		break;
   154 	    }
   155 	    if (result > maxres) { overflow = 1; }
   156 	    result *= 10;
   157 	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
   158 	    result += digit;
   159 	    anyDigits = 1;
   160 	}
   161     } else if (base == 16) {
   162 	unsigned long maxres = ULONG_MAX >> 4;
   163 	for ( ; ; p += 1) {
   164 	    digit = *p - '0';
   165 	    if (digit > ('z' - '0')) {
   166 		break;
   167 	    }
   168 	    digit = cvtIn[digit];
   169 	    if (digit > 15) {
   170 		break;
   171 	    }
   172 	    if (result > maxres) { overflow = 1; }
   173 	    result = (result << 4);
   174 	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
   175 	    result += digit;
   176 	    anyDigits = 1;
   177 	}
   178     } else if ( base >= 2 && base <= 36 ) {
   179 	unsigned long maxres = ULONG_MAX / base;
   180 	for ( ; ; p += 1) {
   181 	    digit = *p - '0';
   182 	    if (digit > ('z' - '0')) {
   183 		break;
   184 	    }
   185 	    digit = cvtIn[digit];
   186 	    if (digit >= ( (unsigned) base )) {
   187 		break;
   188 	    }
   189 	    if (result > maxres) { overflow = 1; }
   190 	    result *= base;
   191 	    if (digit > (ULONG_MAX - result)) { overflow = 1; }
   192 	    result += digit;
   193 	    anyDigits = 1;
   194 	}
   195     }
   196 
   197     /*
   198      * See if there were any digits at all.
   199      */
   200 
   201     if (!anyDigits) {
   202 	p = string;
   203     }
   204 
   205     if (endPtr != 0) {
   206 	/* unsafe, but required by the strtoul prototype */
   207 	*endPtr = (char *) p;
   208     }
   209 
   210     if (overflow) {
   211 	errno = ERANGE;
   212 	return ULONG_MAX;
   213     } 
   214     if (negative) {
   215 	return -result;
   216     }
   217     return result;
   218 }