source: trunk/essentials/sys-apps/gawk/missing_d/strtoul.c

Last change on this file was 3076, checked in by bird, 18 years ago

gawk 3.1.5

File size: 5.8 KB
Line 
1/*
2 * Very simple implementation of strtoul() for gawk,
3 * for old systems. Descriptive prose from the Linux man page.
4 *
5 * May 2004
6 */
7
8/* #define TEST 1 */
9
10#ifdef TEST
11#include <stdio.h>
12#include <stdlib.h>
13#include <ctype.h>
14#include <string.h>
15#include <errno.h>
16#include <limits.h>
17#define TRUE 1
18#define FALSE 0
19#define strtoul mystrtoul
20#endif
21
22#ifndef ULONG_MAX
23#define ULONG_MAX (~ 0UL)
24#endif
25
26unsigned long int
27strtoul(nptr, endptr, base)
28const char *nptr;
29char **endptr;
30int base;
31{
32 static char lower[] = "abcdefghijklmnopqrstuvwxyz";
33
34 unsigned long result = 0UL;
35 char *nptr_orig = (char *) nptr;
36 int neg = FALSE;
37 char *cp, c;
38 int val;
39 int sawdigs = FALSE;
40
41 /*
42 * The strtoul() function converts the initial part of the
43 * string in nptr to an unsigned long integer value according
44 * to the given base, which must be between 2 and 36 inclusive,
45 * or be the special value 0.
46 */
47
48 if ((base != 0 && (base < 2 || base > 36)) || nptr == NULL) {
49 if (endptr != NULL)
50 *endptr = nptr_orig;
51 errno = EINVAL;
52 return 0;
53 }
54
55 /*
56 * The string must [sic] begin with an arbitrary amount of white space
57 * (as determined by isspace(3)) followed by a single optional
58 * `+' or `-' sign.
59 */
60 while (isspace(*nptr))
61 nptr++;
62
63 if (*nptr == '+')
64 nptr++;
65 else if (*nptr == '-') {
66 nptr++;
67 neg = TRUE;
68 }
69
70 /*
71 * If base is zero or 16, the string may then include a `0x' prefix,
72 * and the number will be read in base 16; otherwise, a zero base is
73 * taken as 10 (decimal) unless the next character is `0', in which
74 * case it is taken as 8 (octal).
75 */
76 if ((base == 0 || base == 16)
77 && nptr[0] == '0'
78 && (nptr[1] == 'x' || nptr[1] == 'X')) {
79 base = 16; /* force it */
80 nptr += 2; /* skip 0x */
81 } else if ((base == 0 || base == 8) && nptr[0] == '0') {
82 base = 8;
83 nptr++;
84 } else if (base == 0)
85 base = 10;
86
87 /*
88 * The remainder of the string is converted to an unsigned long int
89 * value in the obvious manner, stopping at the first character
90 * which is not a valid digit in the given base. (In bases above 10,
91 * the letter `A' in either upper or lower case represents 10,
92 * `B' represents 11, and so forth, with `Z' representing 35.)
93 */
94 for (; *nptr != '\0'; nptr++) {
95 c = *nptr;
96#if defined(HAVE_LOCALE_H)
97 if (base == 10
98 && loc.thousands_sep != NULL
99 && loc.thousands_sep[0] != '\0'
100 && c == loc.thousands_sep[0])
101 continue;
102#endif
103 switch (c) {
104 case '0': case '1': case '2':
105 case '3': case '4': case '5':
106 case '6': case '7': case '8':
107 case '9':
108 val = c - '0';
109 if (val >= base) /* even base 2 allowed ... */
110 goto out;
111 result *= base;
112 result += val;
113 sawdigs = TRUE;
114 break;
115 case 'A': case 'B': case 'C': case 'D': case 'E':
116 case 'F': case 'G': case 'H': case 'I': case 'J':
117 case 'K': case 'L': case 'M': case 'N': case 'O':
118 case 'P': case 'Q': case 'R': case 'S': case 'T':
119 case 'U': case 'V': case 'W': case 'X': case 'Y':
120 case 'Z':
121 c += 'a' - 'A'; /* downcase */
122 /* fall through */
123 case 'a': case 'b': case 'c': case 'd': case 'e':
124 case 'f': case 'g': case 'h': case 'i': case 'j':
125 case 'k': case 'l': case 'm': case 'n': case 'o':
126 case 'p': case 'q': case 'r': case 's': case 't':
127 case 'u': case 'v': case 'w': case 'x': case 'y':
128 case 'z':
129 cp = strchr(lower, c);
130 val = cp - lower;
131 val += 10; /* 'a' == 10 */
132 if (val >= base)
133 goto out;
134 result *= base;
135 result += val;
136 sawdigs = TRUE;
137 break;
138 default:
139 goto out;
140 }
141 }
142out:
143 /*
144 * If endptr is not NULL, strtoul() stores the address of the
145 * first invalid character in *endptr. If there were no digits
146 * at all, strtoul() stores the original value of nptr in *endptr
147 * (and returns 0). In particular, if *nptr is not `\0' but
148 * **endptr is `\0' on return, the entire string is valid.
149 */
150 if (endptr != NULL) {
151 if (! sawdigs) {
152 *endptr = nptr_orig;
153 return 0;
154 } else
155 *endptr = (char *) nptr;
156 }
157
158 /*
159 * RETURN VALUE
160 * The strtoul() function returns either the result of the
161 * conversion or, if there was a leading minus sign, the
162 * negation of the result of the conversion, unless the original
163 * (non-negated) value would overflow; in the latter case,
164 * strtoul() returns ULONG_MAX and sets the global variable errno
165 * to ERANGE.
166 */
167
168 /*
169 * ADR: This computation is probably bogus. If it's a
170 * problem, upgrade to a modern system.
171 */
172 if (neg && result == ULONG_MAX) {
173 errno = ERANGE;
174 return ULONG_MAX;
175 } else if (neg)
176 result = -result;
177
178 return result;
179}
180
181#ifdef TEST
182#undef strtoul
183int main(void)
184{
185 char *endptr;
186 unsigned long res1, res2;
187
188 res1 = strtoul("0xdeadBeeF", & endptr, 0),
189 res2 = mystrtoul("0xdeadBeeF", & endptr, 0),
190printf("(real,my)strtoul(\"0xdeadBeeF\", & endptr, 0) is %lu, %lu *endptr = %d\n",
191 res1, res2, *endptr);
192
193 res1 = strtoul("0101101", & endptr, 2),
194 res2 = mystrtoul("0101101", & endptr, 2),
195printf("(real,my)strtoul(\"0101101\", & endptr, 2) is %lu, %lu *endptr = %d\n",
196 res1, res2, *endptr);
197
198 res1 = strtoul("01011012", & endptr, 2),
199 res2 = mystrtoul("01011012", & endptr, 2),
200printf("(real,my)strtoul(\"01011012\", & endptr, 2) is %lu, %lu *endptr = %d\n",
201 res1, res2, *endptr);
202
203 res1 = strtoul(" +42a", & endptr, 0),
204 res2 = mystrtoul(" +42a", & endptr, 0),
205printf("(real,my)strtoul(\" +42a\", & endptr, 0) is %lu, %lu *endptr = %d\n",
206 res1, res2, *endptr);
207
208 res1 = strtoul("0377", & endptr, 0),
209 res2 = mystrtoul("0377", & endptr, 0),
210printf("(real,my)strtoul(\"0377\", & endptr, 0) is %lu, %lu *endptr = %d\n",
211 res1, res2, *endptr);
212
213 res1 = strtoul("Z", & endptr, 36),
214 res2 = mystrtoul("Z", & endptr, 36),
215printf("(real,my)strtoul(\"Z\", & endptr, 36) is %lu, %lu *endptr = %d\n",
216 res1, res2, *endptr);
217
218 res1 = strtoul("qZ*", & endptr, 36),
219 res2 = mystrtoul("qZ*", & endptr, 36),
220printf("(real,my)strtoul(\"qZ*\", & endptr, 36) is %lu, %lu *endptr = %d\n",
221 res1, res2, *endptr);
222}
223#endif
Note: See TracBrowser for help on using the repository browser.