Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/compat/strtoul.c @ 47

Last change on this file since 47 was 25, checked in by landauf, 16 years ago

added tcl to libs

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