parse_int.c (4146B)
1 /* Copyright (c) 2003, Roger Dingledine 2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 3 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 4 /* See LICENSE for licensing information */ 5 6 /** 7 * \file parse_int.c 8 * \brief Convert strings into the integers they encode, with bounds checking. 9 **/ 10 11 #include "lib/string/parse_int.h" 12 #include "lib/cc/compat_compiler.h" 13 14 #include <errno.h> 15 #include <stdlib.h> 16 #include <string.h> 17 18 /* Helper: common code to check whether the result of a strtol or strtoul or 19 * strtoll is correct. */ 20 #define CHECK_STRTOX_RESULT() \ 21 STMT_BEGIN \ 22 /* Did an overflow occur? */ \ 23 if (errno == ERANGE) \ 24 goto err; \ 25 /* Was at least one character converted? */ \ 26 if (endptr == s) \ 27 goto err; \ 28 /* Were there unexpected unconverted characters? */ \ 29 if (!next && *endptr) \ 30 goto err; \ 31 /* Illogical (max, min) inputs? */ \ 32 if (max < min) \ 33 goto err; \ 34 /* Is r within limits? */ \ 35 if (r < min || r > max) \ 36 goto err; \ 37 if (ok) *ok = 1; \ 38 if (next) *next = endptr; \ 39 return r; \ 40 err: \ 41 if (ok) *ok = 0; \ 42 if (next) *next = endptr; \ 43 return 0; \ 44 STMT_END 45 46 /** Extract a long from the start of <b>s</b>, in the given numeric 47 * <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal, 48 * octal, or hex number in the syntax of a C integer literal. If 49 * there is unconverted data and <b>next</b> is provided, set 50 * *<b>next</b> to the first unconverted character. An error has 51 * occurred if no characters are converted; or if there are 52 * unconverted characters and <b>next</b> is NULL; or if the parsed 53 * value is not between <b>min</b> and <b>max</b>. When no error 54 * occurs, return the parsed value and set *<b>ok</b> (if provided) to 55 * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided) 56 * to 0. 57 */ 58 long 59 tor_parse_long(const char *s, int base, long min, long max, 60 int *ok, char **next) 61 { 62 char *endptr; 63 long r; 64 65 if (base < 0) { 66 if (ok) 67 *ok = 0; 68 return 0; 69 } 70 71 errno = 0; 72 r = strtol(s, &endptr, base); 73 CHECK_STRTOX_RESULT(); 74 } 75 76 /** As tor_parse_long(), but return an unsigned long. */ 77 unsigned long 78 tor_parse_ulong(const char *s, int base, unsigned long min, 79 unsigned long max, int *ok, char **next) 80 { 81 char *endptr; 82 unsigned long r; 83 84 if (base < 0) { 85 if (ok) 86 *ok = 0; 87 return 0; 88 } 89 90 errno = 0; 91 r = strtoul(s, &endptr, base); 92 CHECK_STRTOX_RESULT(); 93 } 94 95 /** As tor_parse_long(), but return a double. */ 96 double 97 tor_parse_double(const char *s, double min, double max, int *ok, char **next) 98 { 99 char *endptr; 100 double r; 101 102 errno = 0; 103 r = strtod(s, &endptr); 104 CHECK_STRTOX_RESULT(); 105 } 106 107 /** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to 108 * work for now. */ 109 uint64_t 110 tor_parse_uint64(const char *s, int base, uint64_t min, 111 uint64_t max, int *ok, char **next) 112 { 113 char *endptr; 114 uint64_t r; 115 116 if (base < 0) { 117 if (ok) 118 *ok = 0; 119 return 0; 120 } 121 122 errno = 0; 123 #ifdef HAVE_STRTOULL 124 r = (uint64_t)strtoull(s, &endptr, base); 125 #elif defined(_WIN32) 126 r = (uint64_t)_strtoui64(s, &endptr, base); 127 #elif SIZEOF_LONG == 8 128 r = (uint64_t)strtoul(s, &endptr, base); 129 #else 130 #error "I don't know how to parse 64-bit numbers." 131 #endif /* defined(HAVE_STRTOULL) || ... */ 132 133 CHECK_STRTOX_RESULT(); 134 }