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>