source: trunk/third/perl/uts/strtol_wrap.c @ 18450

Revision 18450, 3.6 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18449, which included commits to RCS files with non-trunk default branches.
Line 
1/* A wrapper around strtol() and strtoul() to correct some
2 * "out of bounds" cases that don't work well on at least UTS.
3 * If a value is Larger than the max, strto[u]l should return
4 * the max value, and set errno to ERANGE
5 *  The same if a value is smaller than the min value (only
6 * relevant for strtol(); not strtoul()), except the minimum
7 * value is returned (and errno == ERANGE).
8 */
9
10#include        <ctype.h>
11#include        <string.h>
12#include        <sys/errno.h>
13#include        <stdlib.h>
14
15extern int      errno;
16
17#undef  I32
18#undef  U32
19
20#define I32     int
21#define U32     unsigned int
22
23struct  base_info {
24        char    *ValidChars;
25
26        char    *Ulong_max_str;
27        char    *Long_max_str;
28        char    *Long_min_str;  /* Absolute value */
29
30        int     Ulong_max_str_len;
31        int     Long_max_str_len;
32        int     Long_min_str_len;       /* Absolute value */
33
34        U32     Ulong_max;
35        I32     Long_max;
36        I32     Long_min;       /* NOT Absolute value */
37};
38static struct   base_info Base_info[37];
39
40static struct base_info Base_info_16 = {
41        "0123456789abcdefABCDEF",
42        "4294967295", "2147483648" /* <== ABS VAL */ , "2147483647",
43        10, 10, 10,
44        4294967295, 2147483647, - 2147483648,
45};
46
47static struct base_info Base_info_10 = {
48        "0123456789",
49        "4294967295", "2147483648" /* <== ABS VAL */ , "2147483647",
50        10, 10, 10,
51        4294967295, 2147483647, - 2147483648,
52};
53
54 /* Used eventually (if this is fully developed) to hold info
55  * for processing bases 2-36.  So that we can just plug the
56  * base in as a selector for its info, we sacrifice
57  * Base_info[0] and Base_info[1] (unless they are used
58  * at some point for special information).
59  */
60
61/* This may be replaced later by something more universal */
62static void
63init_Base_info()
64{
65        if(Base_info[10].ValidChars) return;
66        Base_info[10] = Base_info_10;
67        Base_info[16] = Base_info_16;
68}
69
70unsigned int
71strtoul_wrap32(char *s, char **pEnd, int base)
72{
73        int     Len;
74        int     isNegated = 0;
75        char    *sOrig = s;
76
77        init_Base_info();
78
79        while(*s && isspace(*s)) ++s;
80
81        if(*s == '-') {
82                ++isNegated;
83                ++s;
84                while(*s && isspace(*s)) ++s;
85        }
86        if(base == 0) {
87                if(*s == '0') {
88                        if(s[1] == 'x' || s[1] == 'X') {
89                                s += 2;
90                                base = 16;
91                        } else {
92                                ++s;
93                                base = 8;
94                        }
95                } else if(isdigit(*s)) {
96                        base = 10;
97                }
98        }
99        if(base != 10) {
100                return strtoul(sOrig, pEnd, base);
101        }
102       
103        Len = strspn(s, Base_info[base].ValidChars);
104
105        if(Len > Base_info[base].Ulong_max_str_len
106                ||
107           (Len == Base_info[base].Ulong_max_str_len
108                        &&
109            strncmp(Base_info[base].Ulong_max_str, s, Len) < 0)
110          ) {
111                /* In case isNegated is set - what to do?? */
112                /* Mightn't we say a negative number is ERANGE for strtoul? */
113                errno = ERANGE;
114                return Base_info[base].Ulong_max;
115        }
116
117        return strtoul(sOrig, pEnd, base);
118}
119
120int
121strtol_wrap32(char *s, char **pEnd, int base)
122{
123        int     Len;
124        int     isNegated = 0;
125        char    *sOrig = s;
126
127        init_Base_info();
128
129        while(*s && isspace(*s)) ++s;
130
131        if(*s == '-') {
132                ++isNegated;
133                ++s;
134                while(*s && isspace(*s)) ++s;
135        }
136        if(base == 0) {
137                if(*s == '0') {
138                        if(s[1] == 'x' || s[1] == 'X') {
139                                s += 2;
140                                base = 16;
141                        } else {
142                                ++s;
143                                base = 8;
144                        }
145                } else if(isdigit(*s)) {
146                        base = 10;
147                }
148        }
149        if(base != 10) {
150                return strtol(sOrig, pEnd, base);
151        }
152       
153        Len = strspn(s, Base_info[base].ValidChars);
154
155        if(Len > Base_info[base].Long_max_str_len
156                                ||
157           (!isNegated && Len == Base_info[base].Long_max_str_len
158                &&
159            strncmp(Base_info[base].Long_max_str, s, Len) < 0)
160                                ||
161           (isNegated && Len == Base_info[base].Long_min_str_len
162                &&
163            strncmp(Base_info[base].Long_min_str, s, Len) < 0)
164          ) {
165                /* In case isNegated is set - what to do?? */
166                /* Mightn't we say a negative number is ERANGE for strtol? */
167                errno = ERANGE;
168                return(isNegated ? Base_info[base].Long_min
169                                        :
170                                   Base_info[base].Long_min);
171        }
172
173        return strtol(sOrig, pEnd, base);
174}
Note: See TracBrowser for help on using the repository browser.