/
githubmirror
/
sudo
Обзор
Документация
Войти
/
githubmirror
/
sudo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/util/strtonum.c
187 строк
4 KB
Todd C. Miller
Remove Open Source PVS-Studio comments
28 сен 2025, 18:40
28 сен 2025, 18:40
2a33699
Код
Авторство
О чём код?
/* * SPDX-License-Identifier: ISC * * Copyright (c) 2013-2015, 2019-2020 Todd C. Miller <Todd.Miller@sudo.ws> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <config.h> #include <ctype.h> #include <errno.h> #include <sudo_compat.h> #include <sudo_gettext.h> #include <sudo_util.h> enum strtonum_err { STN_INITIAL, STN_VALID, STN_INVALID, STN_TOOSMALL, STN_TOOBIG }; /* * Convert a string to a number in the range [minval, maxval] * Unlike strtonum(), this returns the first non-digit in endp (if not NULL). */ long long sudo_strtonumx(const char *str, long long minval, long long maxval, char **endp, const char **errstrp) { enum strtonum_err errval = STN_INITIAL; long long lastval, result = 0; const char *cp = str; int remainder; char ch, sign; if (minval > maxval) { errval = STN_INVALID; goto done; } /* Trim leading space and check sign, if any. */ do { ch = *cp++; } while (isspace((unsigned char)ch)); switch (ch) { case '-': sign = '-'; ch = *cp++; break; case '+': ch = *cp++; FALLTHROUGH; default: sign = '+'; break; } /* * To prevent overflow we determine the highest (or lowest in * the case of negative numbers) value result can have *before* * if its multiplied (divided) by 10 as well as the remainder. * If result matches this value and the next digit is larger than * the remainder, we know the result is out of range. * The remainder is always positive since it is compared against * an unsigned digit. */ if (sign == '-') { lastval = minval / 10; remainder = -(int)(minval % 10); if (remainder < 0) { lastval += 1; remainder += 10; } for (;; ch = *cp++) { if (!isdigit((unsigned char)ch)) break; ch -= '0'; if (result < lastval || (result == lastval && ch > remainder)) { /* Skip remaining digits. */ do { ch = *cp++; } while (isdigit((unsigned char)ch)); errval = STN_TOOSMALL; break; } else { result *= 10; result -= ch; errval = STN_VALID; } } if (result > maxval) errval = STN_TOOBIG; } else { lastval = maxval / 10; remainder = (int)(maxval % 10); for (;; ch = *cp++) { if (!isdigit((unsigned char)ch)) break; ch -= '0'; if (result > lastval || (result == lastval && ch > remainder)) { /* Skip remaining digits. */ do { ch = *cp++; } while (isdigit((unsigned char)ch)); errval = STN_TOOBIG; break; } else { result *= 10; result += ch; errval = STN_VALID; } } if (result < minval) errval = STN_TOOSMALL; } done: switch (errval) { case STN_INITIAL: case STN_VALID: if (errstrp != NULL) *errstrp = NULL; break; case STN_INVALID: result = 0; errno = EINVAL; if (errstrp != NULL) *errstrp = N_("invalid value"); break; case STN_TOOSMALL: result = 0; errno = ERANGE; if (errstrp != NULL) *errstrp = N_("value too small"); break; case STN_TOOBIG: result = 0; errno = ERANGE; if (errstrp != NULL) *errstrp = N_("value too large"); break; } if (endp != NULL) { if (errval == STN_INITIAL || errval == STN_INVALID) *endp = (char *)str; else *endp = (char *)(cp - 1); } return result; } /* * Convert a string to a number in the range [minval, maxval] */ long long sudo_strtonum(const char *str, long long minval, long long maxval, const char **errstrp) { const char *errstr; char *ep; long long ret; ret = sudo_strtonumx(str, minval, maxval, &ep, &errstr); /* Check for empty string and terminating NUL. */ if (str == ep || *ep != '\0') { errno = EINVAL; errstr = N_("invalid value"); ret = 0; } if (errstrp != NULL) *errstrp = errstr; return ret; }