Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / libcc.ansi / stdlib / strtol.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 /* $Id: strtol.c,v 1.7 1995/08/17 10:03:43 ceriel Exp $ */
6
7 #include        <ctype.h>
8 #include        <errno.h>
9 #include        <limits.h>
10 #include        <stdlib.h>
11
12 static unsigned long
13 string2long(register const char *nptr, char **endptr,
14                         int base, int is_signed);
15
16 long int
17 strtol(register const char *nptr, char **endptr, int base)
18 {
19         return (signed long)string2long(nptr, endptr, base, 1);
20 }
21
22 unsigned long int
23 strtoul(register const char *nptr, char **endptr, int base)
24 {
25         return (unsigned long)string2long(nptr, endptr, base, 0);
26 }
27
28 static unsigned long
29 string2long(register const char *nptr, char ** const endptr,
30                         int base, int is_signed)
31 {
32         register unsigned int v;
33         register unsigned long val = 0;
34         register int c;
35         int ovfl = 0, sign = 1;
36         const char *startnptr = nptr, *nrstart;
37
38         if (endptr) *endptr = (char *)nptr;
39         while (isspace(*nptr)) nptr++;
40         c = *nptr;
41
42         if (c == '-' || c == '+') {
43                 if (c == '-') sign = -1;
44                 nptr++;
45         }
46         nrstart = nptr;                 /* start of the number */
47
48         /* When base is 0, the syntax determines the actual base */
49         if (base == 0)
50                 if (*nptr == '0')
51                         if (*++nptr == 'x' || *nptr == 'X') {
52                                 base = 16;
53                                 nptr++;
54                         }
55                         else    base = 8;
56                 else    base = 10;
57         else if (base==16 && *nptr=='0' && (*++nptr =='x' || *nptr =='X'))
58                 nptr++;
59
60         while (isdigit(c = *nptr) || isalpha(c)) {
61                 if (!ovfl) {
62                         if (isalpha(c))
63                                 v = 10 + (isupper(c) ? c - 'A' : c - 'a');
64                         else
65                                 v = c - '0';
66                         if (v >= base) break;
67                         if (val > (ULONG_MAX - v) / base) ++ovfl;
68                         else val = (val * base) + v;
69                 }
70                 nptr++;
71         }
72         if (endptr) {
73                 if (nrstart == nptr) *endptr = (char *)startnptr;
74                 else *endptr = (char *)nptr;
75         }
76
77         if (!ovfl) {
78                 /* Overflow is only possible when converting a signed long.
79                  * The "-(LONG_MIN+1)+(unsigned long) 1" construction is there
80                  * to prevent overflow warnings on -LONG_MIN.
81                  */
82                 if (is_signed
83                     && (   (sign < 0 && val > -(LONG_MIN+1)+(unsigned long) 1)
84                         || (sign > 0 && val > LONG_MAX)))
85                     ovfl++;
86         }
87
88         if (ovfl) {
89                 errno = ERANGE;
90                 if (is_signed)
91                         if (sign < 0) return LONG_MIN;
92                         else return LONG_MAX;
93                 else return ULONG_MAX;
94         }
95         return (sign * val);
96 }