OSDN Git Service

9f5d66882fd6fa7f3cc11d6c9feb0b6d5ac66a62
[pf3gnuchains/sourceware.git] / tcl / compat / strtoul.c
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$
13  */
14
15 #include <ctype.h>
16
17 /*
18  * The table below is used to convert from ASCII digits to a
19  * numerical equivalent.  It maps from '0' through 'z' to integers
20  * (100 for non-digit characters).
21  */
22
23 static char cvtIn[] = {
24     0, 1, 2, 3, 4, 5, 6, 7, 8, 9,               /* '0' - '9' */
25     100, 100, 100, 100, 100, 100, 100,          /* punctuation */
26     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,     /* 'A' - 'Z' */
27     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
28     30, 31, 32, 33, 34, 35,
29     100, 100, 100, 100, 100, 100,               /* punctuation */
30     10, 11, 12, 13, 14, 15, 16, 17, 18, 19,     /* 'a' - 'z' */
31     20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
32     30, 31, 32, 33, 34, 35};
33 \f
34 /*
35  *----------------------------------------------------------------------
36  *
37  * strtoul --
38  *
39  *      Convert an ASCII string into an integer.
40  *
41  * Results:
42  *      The return value is the integer equivalent of string.  If endPtr
43  *      is non-NULL, then *endPtr is filled in with the character
44  *      after the last one that was part of the integer.  If string
45  *      doesn't contain a valid integer value, then zero is returned
46  *      and *endPtr is set to string.
47  *
48  * Side effects:
49  *      None.
50  *
51  *----------------------------------------------------------------------
52  */
53
54 unsigned long int
55 strtoul(string, endPtr, base)
56     char *string;               /* String of ASCII digits, possibly
57                                  * preceded by white space.  For bases
58                                  * greater than 10, either lower- or
59                                  * upper-case digits may be used.
60                                  */
61     char **endPtr;              /* Where to store address of terminating
62                                  * character, or NULL. */
63     int base;                   /* Base for conversion.  Must be less
64                                  * than 37.  If 0, then the base is chosen
65                                  * from the leading characters of string:
66                                  * "0x" means hex, "0" means octal, anything
67                                  * else means decimal.
68                                  */
69 {
70     register char *p;
71     register unsigned long int result = 0;
72     register unsigned digit;
73     int anyDigits = 0;
74
75     /*
76      * Skip any leading blanks.
77      */
78
79     p = string;
80     while (isspace(*p)) {
81         p += 1;
82     }
83
84     /*
85      * If no base was provided, pick one from the leading characters
86      * of the string.
87      */
88     
89     if (base == 0)
90     {
91         if (*p == '0') {
92             p += 1;
93             if (*p == 'x') {
94                 p += 1;
95                 base = 16;
96             } else {
97
98                 /*
99                  * Must set anyDigits here, otherwise "0" produces a
100                  * "no digits" error.
101                  */
102
103                 anyDigits = 1;
104                 base = 8;
105             }
106         }
107         else base = 10;
108     } else if (base == 16) {
109
110         /*
111          * Skip a leading "0x" from hex numbers.
112          */
113
114         if ((p[0] == '0') && (p[1] == 'x')) {
115             p += 2;
116         }
117     }
118
119     /*
120      * Sorry this code is so messy, but speed seems important.  Do
121      * different things for base 8, 10, 16, and other.
122      */
123
124     if (base == 8) {
125         for ( ; ; p += 1) {
126             digit = *p - '0';
127             if (digit > 7) {
128                 break;
129             }
130             result = (result << 3) + digit;
131             anyDigits = 1;
132         }
133     } else if (base == 10) {
134         for ( ; ; p += 1) {
135             digit = *p - '0';
136             if (digit > 9) {
137                 break;
138             }
139             result = (10*result) + digit;
140             anyDigits = 1;
141         }
142     } else if (base == 16) {
143         for ( ; ; p += 1) {
144             digit = *p - '0';
145             if (digit > ('z' - '0')) {
146                 break;
147             }
148             digit = cvtIn[digit];
149             if (digit > 15) {
150                 break;
151             }
152             result = (result << 4) + digit;
153             anyDigits = 1;
154         }
155     } else {
156         for ( ; ; p += 1) {
157             digit = *p - '0';
158             if (digit > ('z' - '0')) {
159                 break;
160             }
161             digit = cvtIn[digit];
162             if (digit >= base) {
163                 break;
164             }
165             result = result*base + digit;
166             anyDigits = 1;
167         }
168     }
169
170     /*
171      * See if there were any digits at all.
172      */
173
174     if (!anyDigits) {
175         p = string;
176     }
177
178     if (endPtr != 0) {
179         *endPtr = p;
180     }
181
182     return result;
183 }