This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add handling of NV_ZERO_IS_ALLBITS_ZERO for Netware and epoc
[perl5.git] / uts / strtol_wrap.c
CommitLineData
8935ee17
HM
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}