Annotation of embedaddon/sudo/compat/strtonum.c, revision 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>