Raw
1 #include "git-compat-util.h"
2 #include "gettext.h"
3 #include "parse.h"
4
5 static uintmax_t get_unit_factor(const char *end)
6 {
7 if (!*end)
8 return 1;
9 else if (!strcasecmp(end, "k"))
10 return 1024;
11 else if (!strcasecmp(end, "m"))
12 return 1024 * 1024;
13 else if (!strcasecmp(end, "g"))
14 return 1024 * 1024 * 1024;
15 return 0;
16 }
17
18 int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
19 {
20 if (value && *value) {
21 char *end;
22 intmax_t val;
23 intmax_t factor;
24
25 if (max < 0)
26 BUG("max must be a positive integer");
27
28 errno = 0;
29 val = strtoimax(value, &end, 0);
30 if (errno == ERANGE)
31 return 0;
32 if (end == value) {
33 errno = EINVAL;
34 return 0;
35 }
36 factor = get_unit_factor(end);
37 if (!factor) {
38 errno = EINVAL;
39 return 0;
40 }
41 if ((val < 0 && (-max - 1) / factor > val) ||
42 (val > 0 && max / factor < val)) {
43 errno = ERANGE;
44 return 0;
45 }
46 val *= factor;
47 *ret = val;
48 return 1;
49 }
50 errno = EINVAL;
51 return 0;
52 }
53
54 int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
55 {
56 if (value && *value) {
57 char *end;
58 uintmax_t val;
59 uintmax_t factor;
60
61 /* negative values would be accepted by strtoumax */
62 if (strchr(value, '-')) {
63 errno = EINVAL;
64 return 0;
65 }
66 errno = 0;
67 val = strtoumax(value, &end, 0);
68 if (errno == ERANGE)
69 return 0;
70 if (end == value) {
71 errno = EINVAL;
72 return 0;
73 }
74 factor = get_unit_factor(end);
75 if (!factor) {
76 errno = EINVAL;
77 return 0;
78 }
79 if (unsigned_mult_overflows(factor, val) ||
80 factor * val > max) {
81 errno = ERANGE;
82 return 0;
83 }
84 val *= factor;
85 *ret = val;
86 return 1;
87 }
88 errno = EINVAL;
89 return 0;
90 }
91
92 int git_parse_int(const char *value, int *ret)
93 {
94 intmax_t tmp;
95 if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
96 return 0;
97 *ret = tmp;
98 return 1;
99 }
100
101 int git_parse_int64(const char *value, int64_t *ret)
102 {
103 intmax_t tmp;
104 if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
105 return 0;
106 *ret = tmp;
107 return 1;
108 }
109
110 int git_parse_uint(const char *value, unsigned int *ret)
111 {
112 uintmax_t tmp;
113 if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(unsigned int)))
114 return 0;
115 *ret = tmp;
116 return 1;
117 }
118
119 int git_parse_ulong(const char *value, unsigned long *ret)
120 {
121 uintmax_t tmp;
122 if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
123 return 0;
124 *ret = tmp;
125 return 1;
126 }
127
128 int git_parse_ssize_t(const char *value, ssize_t *ret)
129 {
130 intmax_t tmp;
131 if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
132 return 0;
133 *ret = tmp;
134 return 1;
135 }
136
137 int git_parse_double(const char *value, double *ret)
138 {
139 char *end;
140 double val;
141 uintmax_t factor;
142
143 if (!value || !*value) {
144 errno = EINVAL;
145 return 0;
146 }
147
148 errno = 0;
149 val = strtod(value, &end);
150 if (errno == ERANGE)
151 return 0;
152 if (end == value) {
153 errno = EINVAL;
154 return 0;
155 }
156 factor = get_unit_factor(end);
157 if (!factor) {
158 errno = EINVAL;
159 return 0;
160 }
161 val *= factor;
162 *ret = val;
163 return 1;
164 }
165
166 int git_parse_maybe_bool_text(const char *value)
167 {
168 if (!value)
169 return 1;
170 if (!*value)
171 return 0;
172 if (!strcasecmp(value, "true")
173 || !strcasecmp(value, "yes")
174 || !strcasecmp(value, "on"))
175 return 1;
176 if (!strcasecmp(value, "false")
177 || !strcasecmp(value, "no")
178 || !strcasecmp(value, "off"))
179 return 0;
180 return -1;
181 }
182
183 int git_parse_maybe_bool(const char *value)
184 {
185 int v = git_parse_maybe_bool_text(value);
186 if (0 <= v)
187 return v;
188 if (git_parse_int(value, &v))
189 return !!v;
190 return -1;
191 }
192
193 /*
194 * Parse environment variable 'k' as a boolean (in various
195 * possible spellings); if missing, use the default value 'def'.
196 */
197 int git_env_bool(const char *k, int def)
198 {
199 const char *v = getenv(k);
200 int val;
201 if (!v)
202 return def;
203 val = git_parse_maybe_bool(v);
204 if (val < 0)
205 die(_("bad boolean environment value '%s' for '%s'"),
206 v, k);
207 return val;
208 }
209
210 /*
211 * Parse environment variable 'k' as ulong with possibly a unit
212 * suffix; if missing, use the default value 'val'.
213 */
214 unsigned long git_env_ulong(const char *k, unsigned long val)
215 {
216 const char *v = getenv(k);
217 if (v && !git_parse_ulong(v, &val))
218 die(_("failed to parse %s"), k);
219 return val;
220 }