Annotation of embedaddon/sudo/compat/strtonum.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 2013 Todd C. Miller <Todd.Miller@courtesan.com>
3: *
4: * Permission to use, copy, modify, and distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
7: *
8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15: */
16:
17: #include <config.h>
18:
19: #include <sys/types.h>
20:
21: #include <ctype.h>
22: #include <errno.h>
23: #include <limits.h>
24: #include <stdio.h>
25: #ifdef STDC_HEADERS
26: # include <stdlib.h>
27: # include <stddef.h>
28: #else
29: # ifdef HAVE_STDLIB_H
30: # include <stdlib.h>
31: # endif
32: #endif /* STDC_HEADERS */
33: #ifdef HAVE_STRING_H
34: # include <string.h>
35: #endif /* HAVE_STRING_H */
36: #ifdef HAVE_STRINGS_H
37: # include <strings.h>
38: #endif /* HAVE_STRINGS_H */
39:
40: #define DEFAULT_TEXT_DOMAIN "sudo"
41: #include "gettext.h" /* must be included before missing.h */
42:
43: #include "missing.h"
44:
45: #ifdef HAVE_STRTONUM
46:
47: /*
48: * The OpenBSD strtonum error string too short to be translated sensibly.
49: * This wrapper just changes errstr as follows:
50: * invalid -> invalid value
51: * too large -> value too large
52: * too small -> value too small
53: */
54: long long
55: rpl_strtonum(const char *str, long long minval, long long maxval,
56: const char **errstrp)
57: {
58: long long retval;
59: const char *errstr;
60:
61: # undef strtonum
62: retval = strtonum(str, minval, maxval, &errstr);
63: if (errstr != NULL) {
64: if (errno == EINVAL) {
65: errstr = N_("invalid value");
66: } else if (errno == ERANGE) {
67: errstr = strcmp(errstr, "too large") == 0 ?
68: N_("value too large") : N_("value too small");
69: }
70: }
71: if (errstrp != NULL)
72: *errstrp = errstr;
73: return retval;
74: }
75:
76: #else
77:
78: enum strtonum_err {
79: STN_VALID,
80: STN_INVALID,
81: STN_TOOSMALL,
82: STN_TOOBIG
83: };
84:
85: /*
86: * Convert a string to a number in the range [minval, maxval]
87: */
88: long long
89: rpl_strtonum(const char *str, long long minval, long long maxval,
90: const char **errstrp)
91: {
92: const unsigned char *ustr = (const unsigned char *)str;
93: enum strtonum_err errval = STN_VALID;
94: long long lastval, result = 0;
95: unsigned char dig, sign;
96: int remainder;
97:
98: if (minval > maxval) {
99: errval = STN_INVALID;
100: goto done;
101: }
102:
103: /* Trim leading space and check sign, if any. */
104: while (isspace(*ustr)) {
105: ustr++;
106: }
107: switch (*ustr) {
108: case '-':
109: sign = '-';
110: ustr++;
111: break;
112: case '+':
113: ustr++;
114: /* FALLTHROUGH */
115: default:
116: sign = '+';
117: break;
118: }
119:
120: /*
121: * To prevent overflow we determine the highest (or lowest in
122: * the case of negative numbers) value result can have *before*
123: * if its multiplied (divided) by 10 as well as the remainder.
124: * If result matches this value and the next digit is larger than
125: * the remainder, we know the result is out of range.
126: * The remainder is always positive since it is compared against
127: * an unsigned digit.
128: */
129: if (sign == '-') {
130: lastval = minval / 10;
131: remainder = -(minval % 10);
132: if (remainder < 0) {
133: lastval += 1;
134: remainder += 10;
135: }
136: while ((dig = *ustr++) != '\0') {
137: if (!isdigit(dig)) {
138: errval = STN_INVALID;
139: break;
140: }
141: dig -= '0';
142: if (result < lastval || (result == lastval && dig > remainder)) {
143: errval = STN_TOOSMALL;
144: break;
145: } else {
146: result *= 10;
147: result -= dig;
148: }
149: }
150: if (result > maxval)
151: errval = STN_TOOBIG;
152: } else {
153: lastval = maxval / 10;
154: remainder = maxval % 10;
155: while ((dig = *ustr++) != '\0') {
156: if (!isdigit(dig)) {
157: errval = STN_INVALID;
158: break;
159: }
160: dig -= '0';
161: if (result > lastval || (result == lastval && dig > remainder)) {
162: errval = STN_TOOBIG;
163: break;
164: } else {
165: result *= 10;
166: result += dig;
167: }
168: }
169: if (result < minval)
170: errval = STN_TOOSMALL;
171: }
172:
173: done:
174: switch (errval) {
175: case STN_VALID:
176: if (errstrp != NULL)
177: *errstrp = NULL;
178: break;
179: case STN_INVALID:
180: result = 0;
181: errno = EINVAL;
182: if (errstrp != NULL)
183: *errstrp = N_("invalid value");
184: break;
185: case STN_TOOSMALL:
186: result = 0;
187: errno = ERANGE;
188: if (errstrp != NULL)
189: *errstrp = N_("value too small");
190: break;
191: case STN_TOOBIG:
192: result = 0;
193: errno = ERANGE;
194: if (errstrp != NULL)
195: *errstrp = N_("value too large");
196: break;
197: }
198: return result;
199: }
200: #endif /* HAVE_STRTONUM */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>