Line data Source code
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 185313 : tor_parse_long(const char *s, int base, long min, long max,
60 : int *ok, char **next)
61 : {
62 185313 : char *endptr;
63 185313 : long r;
64 :
65 185313 : if (base < 0) {
66 2 : if (ok)
67 1 : *ok = 0;
68 2 : return 0;
69 : }
70 :
71 185311 : errno = 0;
72 185311 : r = strtol(s, &endptr, base);
73 185311 : CHECK_STRTOX_RESULT();
74 : }
75 :
76 : /** As tor_parse_long(), but return an unsigned long. */
77 : unsigned long
78 60818 : tor_parse_ulong(const char *s, int base, unsigned long min,
79 : unsigned long max, int *ok, char **next)
80 : {
81 60818 : char *endptr;
82 60818 : unsigned long r;
83 :
84 60818 : if (base < 0) {
85 1 : if (ok)
86 1 : *ok = 0;
87 1 : return 0;
88 : }
89 :
90 60817 : errno = 0;
91 60817 : r = strtoul(s, &endptr, base);
92 60817 : CHECK_STRTOX_RESULT();
93 : }
94 :
95 : /** As tor_parse_long(), but return a double. */
96 : double
97 49 : tor_parse_double(const char *s, double min, double max, int *ok, char **next)
98 : {
99 49 : char *endptr;
100 49 : double r;
101 :
102 49 : errno = 0;
103 49 : r = strtod(s, &endptr);
104 49 : 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 85543 : tor_parse_uint64(const char *s, int base, uint64_t min,
111 : uint64_t max, int *ok, char **next)
112 : {
113 85543 : char *endptr;
114 85543 : uint64_t r;
115 :
116 85543 : if (base < 0) {
117 1 : if (ok)
118 1 : *ok = 0;
119 1 : return 0;
120 : }
121 :
122 85542 : errno = 0;
123 : #ifdef HAVE_STRTOULL
124 85542 : 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 85542 : CHECK_STRTOX_RESULT();
134 : }
|