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
38static 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
41int 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
80int 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
115int 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
163int 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
208int 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
256int
257cf_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
285int
286cf_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
312int
313cf_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
339unsigned int
340cf_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
373unsigned int
374cf_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
400unsigned int
401cf_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
427void
428cf_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