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>