1 | /* |
2 | * cf_str.c |
3 | * |
4 | * Copyright (C) 2008-2014 Aerospike, Inc. |
5 | * |
6 | * Portions may be licensed to Aerospike, Inc. under one or more contributor |
7 | * license agreements. |
8 | * |
9 | * This program is free software: you can redistribute it and/or modify it under |
10 | * the terms of the GNU Affero General Public License as published by the Free |
11 | * Software Foundation, either version 3 of the License, or (at your option) any |
12 | * later version. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, but WITHOUT |
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
16 | * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
17 | * details. |
18 | * |
19 | * You should have received a copy of the GNU Affero General Public License |
20 | * along with this program. If not, see http://www.gnu.org/licenses/ |
21 | */ |
22 | |
23 | /* |
24 | * String helper functions |
25 | * |
26 | */ |
27 | |
28 | #include "cf_str.h" |
29 | |
30 | #include <errno.h> |
31 | #include <stdbool.h> |
32 | #include <stdint.h> |
33 | #include <stdlib.h> |
34 | |
35 | #include <citrusleaf/cf_vector.h> |
36 | |
37 | |
38 | static char itoa_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N' }; |
39 | |
40 | // return 0 on success, -1 on fail |
41 | int cf_str_atoi(char *s, int *value) |
42 | { |
43 | int i = 0; |
44 | bool neg = false; |
45 | |
46 | if (*s == '-') { neg = true; s++; } |
47 | |
48 | while (*s >= '0' && *s <= '9') { |
49 | i *= 10; |
50 | i += *s - '0'; |
51 | s++; |
52 | } |
53 | switch (*s) { |
54 | case 'k': |
55 | case 'K': |
56 | i *= 1024L; |
57 | s++; |
58 | break; |
59 | case 'M': |
60 | case 'm': |
61 | i *= (1024L * 1024L); |
62 | s++; |
63 | break; |
64 | case 'G': |
65 | case 'g': |
66 | i *= (1024L * 1024L * 1024L); |
67 | s++; |
68 | break; |
69 | default: |
70 | break; |
71 | } |
72 | if (*s != 0) { |
73 | return(-1); // reached a non-num before EOL |
74 | } |
75 | *value = neg ? -i : i; |
76 | return(0); |
77 | } |
78 | |
79 | // return 0 on success, -1 on fail |
80 | int cf_str_atoi_u32(char *s, unsigned int *value) |
81 | { |
82 | unsigned int i = 0; |
83 | |
84 | while (*s >= '0' && *s <= '9') { |
85 | i *= 10; |
86 | i += *s - '0'; |
87 | s++; |
88 | } |
89 | switch (*s) { |
90 | case 'k': |
91 | case 'K': |
92 | i *= 1024L; |
93 | s++; |
94 | break; |
95 | case 'M': |
96 | case 'm': |
97 | i *= (1024L * 1024L); |
98 | s++; |
99 | break; |
100 | case 'G': |
101 | case 'g': |
102 | i *= (1024L * 1024L * 1024L); |
103 | s++; |
104 | break; |
105 | default: |
106 | break; |
107 | } |
108 | if (*s != 0) { |
109 | return(-1); // reached a non-num before EOL |
110 | } |
111 | *value = i; |
112 | return(0); |
113 | } |
114 | |
115 | int cf_str_atoi_64(char *s, int64_t *value) |
116 | { |
117 | int64_t i = 0; |
118 | bool neg = false; |
119 | |
120 | if (*s == '-') { neg = true; s++; } |
121 | |
122 | while (*s >= '0' && *s <= '9') { |
123 | i *= 10; |
124 | i += *s - '0'; |
125 | s++; |
126 | } |
127 | switch (*s) { |
128 | case 'k': |
129 | case 'K': |
130 | i *= 1024L; |
131 | s++; |
132 | break; |
133 | case 'M': |
134 | case 'm': |
135 | i *= (1024L * 1024L); |
136 | s++; |
137 | break; |
138 | case 'G': |
139 | case 'g': |
140 | i *= (1024L * 1024L * 1024L); |
141 | s++; |
142 | break; |
143 | case 'T': |
144 | case 't': |
145 | i *= (1024L * 1024L * 1024L * 1024L); |
146 | s++; |
147 | break; |
148 | case 'P': |
149 | case 'p': |
150 | i *= (1024L * 1024L * 1024L * 1024L * 1024L); |
151 | s++; |
152 | break; |
153 | default: |
154 | break; |
155 | } |
156 | if (*s != 0) { |
157 | return(-1); // reached a non-num before EOL |
158 | } |
159 | *value = neg ? -i : i; |
160 | return(0); |
161 | } |
162 | |
163 | int cf_str_atoi_u64(char *s, uint64_t *value) |
164 | { |
165 | uint64_t i = 0; |
166 | |
167 | while (*s >= '0' && *s <= '9') { |
168 | i *= 10; |
169 | i += *s - '0'; |
170 | s++; |
171 | } |
172 | switch (*s) { |
173 | case 'k': |
174 | case 'K': |
175 | i *= 1024L; |
176 | s++; |
177 | break; |
178 | case 'M': |
179 | case 'm': |
180 | i *= (1024L * 1024L); |
181 | s++; |
182 | break; |
183 | case 'G': |
184 | case 'g': |
185 | i *= (1024L * 1024L * 1024L); |
186 | s++; |
187 | break; |
188 | case 'T': |
189 | case 't': |
190 | i *= (1024L * 1024L * 1024L * 1024L); |
191 | s++; |
192 | break; |
193 | case 'P': |
194 | case 'p': |
195 | i *= (1024L * 1024L * 1024L * 1024L * 1024L); |
196 | s++; |
197 | break; |
198 | default: |
199 | break; |
200 | } |
201 | if (*s != 0) { |
202 | return(-1); // reached a non-num before EOL |
203 | } |
204 | *value = i; |
205 | return(0); |
206 | } |
207 | |
208 | int cf_str_atoi_seconds(char *s, uint32_t *value) |
209 | { |
210 | // Special case: treat -1 the same as 0. |
211 | if (*s == '-' && *(s + 1) == '1') { |
212 | *value = 0; |
213 | return 0; |
214 | } |
215 | |
216 | uint64_t i = 0; |
217 | |
218 | while (*s >= '0' && *s <= '9') { |
219 | i *= 10; |
220 | i += *s - '0'; |
221 | s++; |
222 | } |
223 | switch (*s) { |
224 | case 'S': |
225 | case 's': |
226 | s++; |
227 | break; |
228 | case 'M': |
229 | case 'm': |
230 | i *= 60; |
231 | s++; |
232 | break; |
233 | case 'H': |
234 | case 'h': |
235 | i *= (60 * 60); |
236 | s++; |
237 | break; |
238 | case 'D': |
239 | case 'd': |
240 | i *= (60 * 60 * 24); |
241 | s++; |
242 | break; |
243 | default: |
244 | break; |
245 | } |
246 | if (*s != 0) { |
247 | return(-1); // reached a non-num before EOL |
248 | } |
249 | if (i > UINT32_MAX) { |
250 | return(-1); // overflows a uint32_t |
251 | } |
252 | *value = (uint32_t)i; |
253 | return(0); |
254 | } |
255 | |
256 | int |
257 | cf_strtoul_x64(const char *s, uint64_t *value) |
258 | { |
259 | if (! ((*s >= '0' && *s <= '9') || |
260 | (*s >= 'a' && *s <= 'f') || |
261 | (*s >= 'A' && *s <= 'F'))) { |
262 | return -1; |
263 | } |
264 | |
265 | errno = 0; |
266 | |
267 | char* tail = NULL; |
268 | uint64_t i = strtoul(s, &tail, 16); |
269 | |
270 | // Check for overflow. |
271 | if (errno == ERANGE) { |
272 | return -1; |
273 | } |
274 | |
275 | // Don't allow trailing non-hex characters. |
276 | if (tail && *tail != 0) { |
277 | return -1; |
278 | } |
279 | |
280 | *value = i; |
281 | |
282 | return 0; |
283 | } |
284 | |
285 | int |
286 | cf_strtoul_u32(char *s, uint32_t *value) |
287 | { |
288 | if (! (*s >= '0' && *s <= '9')) { |
289 | return -1; |
290 | } |
291 | |
292 | errno = 0; |
293 | |
294 | char* tail = NULL; |
295 | uint64_t i = strtoul(s, &tail, 10); |
296 | |
297 | // Check for overflow. |
298 | if (errno == ERANGE || i > UINT32_MAX) { |
299 | return -1; |
300 | } |
301 | |
302 | // Don't allow trailing non-hex characters. |
303 | if (tail && *tail != 0) { |
304 | return -1; |
305 | } |
306 | |
307 | *value = (uint32_t)i; |
308 | |
309 | return 0; |
310 | } |
311 | |
312 | int |
313 | cf_strtoul_u64(char *s, uint64_t *value) |
314 | { |
315 | if (! (*s >= '0' && *s <= '9')) { |
316 | return -1; |
317 | } |
318 | |
319 | errno = 0; |
320 | |
321 | char* tail = NULL; |
322 | uint64_t i = strtoul(s, &tail, 10); |
323 | |
324 | // Check for overflow. |
325 | if (errno == ERANGE) { |
326 | return -1; |
327 | } |
328 | |
329 | // Don't allow trailing non-hex characters. |
330 | if (tail && *tail != 0) { |
331 | return -1; |
332 | } |
333 | |
334 | *value = i; |
335 | |
336 | return 0; |
337 | } |
338 | |
339 | unsigned int |
340 | cf_str_itoa(int _value, char *_s, int _radix) |
341 | { |
342 | // special case is the easy way |
343 | if (_value == 0) { |
344 | _s[0] = itoa_table[0]; |
345 | _s[1] = 0; |
346 | return(1); |
347 | } |
348 | |
349 | // Account for negatives |
350 | unsigned int sign_len = 0; |
351 | if (_value < 0) { |
352 | *_s++ = '-'; |
353 | _value = - _value; |
354 | sign_len = 1; |
355 | } |
356 | int _v = _value; |
357 | unsigned int _nd = 0; |
358 | while (_v) { |
359 | _nd++; |
360 | _v /= _radix; |
361 | } |
362 | |
363 | unsigned int rv = sign_len + _nd; |
364 | _s[_nd] = 0; |
365 | while (_nd) { |
366 | _nd --; |
367 | _s[_nd ] = itoa_table [ _value % _radix ]; |
368 | _value = _value / _radix; |
369 | } |
370 | return(rv); |
371 | } |
372 | |
373 | unsigned int |
374 | cf_str_itoa_u64(uint64_t _value, char *_s, int _radix) |
375 | { |
376 | // special case is the easy way |
377 | if (_value == 0) { |
378 | _s[0] = itoa_table[0]; |
379 | _s[1] = 0; |
380 | return(1); |
381 | } |
382 | |
383 | uint64_t _v = _value; |
384 | unsigned int _nd = 0; |
385 | while (_v) { |
386 | _nd++; |
387 | _v /= _radix; |
388 | } |
389 | |
390 | unsigned int rv = _nd; |
391 | _s[_nd] = 0; |
392 | while (_nd) { |
393 | _nd --; |
394 | _s[_nd ] = itoa_table [ _value % _radix ]; |
395 | _value = _value / _radix; |
396 | } |
397 | return(rv); |
398 | } |
399 | |
400 | unsigned int |
401 | cf_str_itoa_u32(uint32_t _value, char *_s, int _radix) |
402 | { |
403 | // special case is the easy way |
404 | if (_value == 0) { |
405 | _s[0] = itoa_table[0]; |
406 | _s[1] = 0; |
407 | return(1); |
408 | } |
409 | |
410 | uint32_t _v = _value; |
411 | unsigned int _nd = 0; |
412 | while (_v) { |
413 | _nd++; |
414 | _v /= _radix; |
415 | } |
416 | |
417 | unsigned int rv = _nd; |
418 | _s[_nd] = 0; |
419 | while (_nd) { |
420 | _nd --; |
421 | _s[_nd ] = itoa_table [ _value % _radix ]; |
422 | _value = _value / _radix; |
423 | } |
424 | return(rv); |
425 | } |
426 | |
427 | void |
428 | cf_str_split(char *fmt, char *str, cf_vector *v) |
429 | { |
430 | char c; |
431 | char *prev = str; |
432 | while ((c = *str)) { |
433 | for (uint32_t j = 0; fmt[j]; j++) { |
434 | if (fmt[j] == c) { |
435 | *str = 0; |
436 | cf_vector_append(v, &prev); |
437 | prev = str+1; |
438 | break; |
439 | } |
440 | } |
441 | str++; |
442 | } |
443 | if (prev != str) |
444 | cf_vector_append(v, &prev); |
445 | } |
446 | |