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 
15 extern int	errno;
16 
17 #undef	I32
18 #undef	U32
19 
20 #define	I32	int
21 #define	U32	unsigned int
22 
23 struct	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 };
38 static struct	base_info Base_info[37];
39 
40 static struct base_info Base_info_16 = {
41 	"0123456789abcdefABCDEF",
42 	"4294967295", "2147483648" /* <== ABS VAL */ , "2147483647",
43 	10, 10, 10,
44 	4294967295, 2147483647, - 2147483648,
45 };
46 
47 static 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 */
62 static void
init_Base_info()63 init_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 
70 unsigned int
strtoul_wrap32(char * s,char ** pEnd,int base)71 strtoul_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 
120 int
strtol_wrap32(char * s,char ** pEnd,int base)121 strtol_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 }
175