1 /*
2 * \brief String utilities
3 * \author Norman Feske
4 * \author Sebastian Sumpf
5 * \date 2006-05-10
6 */
7
8 /*
9 * Copyright (C) 2006-2013 Genode Labs GmbH
10 *
11 * This file is part of the Genode OS framework, which is distributed
12 * under the terms of the GNU General Public License version 2.
13 */
14
15 #ifndef _INCLUDE__UTIL__STRING_H_
16 #define _INCLUDE__UTIL__STRING_H_
17
18 #include <base/stdint.h>
19 #include <util/misc_math.h>
20 #include <cpu/string.h>
21
22 namespace Genode {
23
24 class Number_of_bytes;
25 template <Genode::size_t> class String;
26 }
27
28
29 /**
30 * Wrapper of `size_t` for selecting the `ascii_to` function to parse byte values
31 */
32 class Genode::Number_of_bytes
33 {
34 size_t _n;
35
36 public:
37
38 /**
39 * Default constructor
40 */
41 Number_of_bytes() : _n(0) { }
42
43 /**
44 * Constructor, to be used implicitly via assignment operator
45 */
46 Number_of_bytes(size_t n) : _n(n) { }
47
48 /**
49 * Convert number of bytes to `size_t` value
50 */
51 operator size_t() const { return _n; }
52 };
53
54
55 /***********************
56 ** Utility functions **
57 ***********************/
58
59 namespace Genode {
60
61 /**
62 * Return length of null-terminated string in bytes
63 */
64 inline size_t strlen(const char *s)
65 {
66 size_t res = 0;
67 for (; s && *s; s++, res++);
68 return res;
69 }
70
71
72 /**
73 * Compare two strings
74 *
75 * \param len maximum number of characters to compare,
76 * default is unlimited
77 *
78 * \return 0 if both strings are equal, or
79 * a positive number if s1 is higher than s2, or
80 * a negative number if s1 is lower than s2
81 */
82 inline int strcmp(const char *s1, const char *s2, size_t len = ~0UL)
83 {
84 for (; *s1 && *s1 == *s2 && len; s1++, s2++, len--) ;
85 return len ? *s1 - *s2 : 0;
86 }
87
88
89 /**
90 * Copy memory buffer to a potentially overlapping destination buffer
91 *
92 * \param dst destination memory block
93 * \param src source memory block
94 * \param size number of bytes to move
95 *
96 * \return pointer to destination memory block
97 */
98 inline void *memmove(void *dst, const void *src, size_t size)
99 {
100 char *d = (char *)dst, *s = (char *)src;
101 size_t i;
102
103 if (s > d)
104 for (i = 0; i < size; i++, *d++ = *s++);
105 else
106 for (s += size - 1, d += size - 1, i = size; i-- > 0; *d-- = *s--);
107
108 return dst;
109 }
110
111
112 /**
113 * Copy memory buffer to a non-overlapping destination buffer
114 *
115 * \param dst destination memory block
116 * \param src source memory block
117 * \param size number of bytes to copy
118 *
119 * \return pointer to destination memory block
120 */
121 inline void *memcpy(void *dst, const void *src, size_t size)
122 {
123 char *d = (char *)dst, *s = (char *)src;
124 size_t i;
125
126 /* check for overlap */
127 if ((d + size > s) && (s + size > d))
128 return memmove(dst, src, size);
129
130 /* try cpu specific version first */
131 if ((i = size - memcpy_cpu(dst, src, size)) == size)
132 return dst;
133
134 d += i; s += i; size -= i;
135
136 /* copy eight byte chunks */
137 for (i = size >> 3; i > 0; i--, *d++ = *s++,
138 *d++ = *s++,
139 *d++ = *s++,
140 *d++ = *s++,
141 *d++ = *s++,
142 *d++ = *s++,
143 *d++ = *s++,
144 *d++ = *s++);
145
146 /* copy left over */
147 for (i = 0; i < (size & 0x7); i++, *d++ = *s++);
148
149 return dst;
150 }
151
152
153 /**
154 * Copy string
155 *
156 * \param dst destination buffer
157 * \param src buffer holding the null-terminated source string
158 * \param size maximum number of characters to copy
159 * \return pointer to destination string
160 *
161 * Note that this function is not fully compatible to the C standard, in
162 * particular there is no zero-padding if the length of `src` is smaller
163 * than `size`. Furthermore, in contrast to the libc version, this function
164 * always produces a null-terminated string in the `dst` buffer if the
165 * `size` argument is greater than 0.
166 */
167 inline char *strncpy(char *dst, const char *src, size_t size)
168 {
169 /* sanity check for corner case of a zero-size destination buffer */
170 if (size == 0) return dst;
171
172 /* backup original `dst` for the use as return value */
173 char *orig_dst = dst;
174
175 /*
176 * Copy characters from `src` to `dst` respecting the `size` limit.
177 * In each iteration, the `size` variable holds the maximum remaining
178 * size. We have to leave at least one character free to add the null
179 * termination afterwards.
180 */
181 while ((size-- > 1UL) && *src)
182 *dst++ = *src++;
183
184 /* append null termination to the destination buffer */
185 *dst = 0;
186
187 return orig_dst;
188 }
189
190
191 /**
192 * Compare memory blocks
193 *
194 * \return 0 if both memory blocks are equal, or
195 * a negative number if `p0` is less than `p1`, or
196 * a positive number if `p0` is greater than `p1`
197 */
198 inline int memcmp(const void *p0, const void *p1, size_t size)
199 {
200 const unsigned char *c0 = (const unsigned char *)p0;
201 const unsigned char *c1 = (const unsigned char *)p1;
202
203 size_t i;
204 for (i = 0; i < size; i++)
205 if (c0[i] != c1[i]) return c0[i] - c1[i];
206
207 return 0;
208 }
209
210
211 /**
212 * Fill destination buffer with given value
213 *
214 * \param dst destination buffer
215 * \param i byte value
216 * \param size buffer size in bytes
217 */
218 inline void *memset(void *dst, int i, size_t size)
219 {
220 while (size--) ((char *)dst)[size] = i;
221 return dst;
222 }
223
224
225 /**
226 * Convert ASCII character to digit
227 *
228 * \param hex consider hexadecimals
229 * \return digit or -1 on error
230 */
231 inline int digit(char c, bool hex = false)
232 {
233 if (c >= `0` && c <= `9`) return c - `0`;
234 if (hex && c >= `a` && c <= `f`) return c - `a` + 10;
235 if (hex && c >= `A` && c <= `F`) return c - `A` + 10;
236 return -1;
237 }
238
239
240 /**
241 * Return true if character is a letter
242 */
243 inline bool is_letter(char c)
244 {
245 return (((c >= `a`) && (c <= `z`)) || ((c >= `A`) && (c <= `Z`)));
246 }
247
248
249 /**
250 * Return true if character is a digit
251 */
252 inline bool is_digit(char c, bool hex = false)
253 {
254 return (digit(c, hex) >= 0);
255 }
256
257
258 /**
259 * Return true if character is whitespace
260 */
261 inline bool is_whitespace(char c)
262 {
263 return (c == `\t` || c == ` ` || c == `\n`);
264 }
265
266
267 /**
268 * Read unsigned long value from string
269 *
270 * \param s source string
271 * \param result destination variable
272 * \param base integer base
273 * \return number of consumed characters
274 *
275 * If the base argument is 0, the integer base is detected based on the
276 * characters in front of the number. If the number is prefixed with "0x",
277 * a base of 16 is used, otherwise a base of 10.
278 */
279 template <typename T>
280 inline size_t ascii_to_unsigned(const char *s, T &result, unsigned base)
281 {
282 T i = 0, value = 0;
283
284 if (!*s) return i;
285
286 /* autodetect hexadecimal base, default is a base of 10 */
287 if (base == 0) {
288
289 /* read `0x` prefix */
290 if (*s == `0` && (s[1] == `x` || s[1] == `X`)) {
291 s += 2; i += 2;
292 base = 16;
293 } else
294 base = 10;
295 }
296
297 /* read number */
298 for (int d; ; s++, i++) {
299
300 /* read digit, stop when hitting a non-digit character */
301 if ((d = digit(*s, base == 16)) < 0) break;
302
303 /* append digit to integer value */
304 value = value*base + d;
305 }
306
307 result = value;
308 return i;
309 }
310
311
312 /**
313 * Read boolean value from string
314 *
315 * \return number of consumed characters
316 */
317 inline size_t ascii_to(char const *s, bool &result)
318 {
319 if (!strcmp(s, "yes", 3)) { result = true; return 3; }
320 if (!strcmp(s, "true", 4)) { result = true; return 4; }
321 if (!strcmp(s, "on", 2)) { result = true; return 2; }
322 if (!strcmp(s, "no", 2)) { result = false; return 2; }
323 if (!strcmp(s, "false", 5)) { result = false; return 5; }
324 if (!strcmp(s, "off", 3)) { result = false; return 3; }
325
326 return 0;
327 }
328
329
330 /**
331 * Read unsigned long value from string
332 *
333 * \return number of consumed characters
334 */
335 inline size_t ascii_to(const char *s, unsigned long &result)
336 {
337 return ascii_to_unsigned(s, result, 0);
338 }
339
340
341 /**
342 * Read unsigned long long value from string
343 *
344 * \return number of consumed characters
345 */
346 inline size_t ascii_to(const char *s, unsigned long long &result)
347 {
348 return ascii_to_unsigned(s, result, 0);
349 }
350
351
352
353 /**
354 * Read unsigned int value from string
355 *
356 * \return number of consumed characters
357 */
358 inline size_t ascii_to(const char *s, unsigned int &result)
359 {
360 return ascii_to_unsigned(s, result, 0);
361 }
362
363
364 /**
365 * Read signed long value from string
366 *
367 * \return number of consumed characters
368 */
369 inline size_t ascii_to(const char *s, long &result)
370 {
371 int i = 0;
372
373 /* read sign */
374 int sign = (*s == `-`) ? -1 : 1;
375
376 if (*s == `-` || *s == `+`) { s++; i++; }
377
378 int j = 0;
379 unsigned long value = 0;
380
381 j = ascii_to_unsigned(s, value, 10);
382
383 if (!j) return i;
384
385 result = sign*value;
386 return i + j;
387 }
388
389
390 /**
391 * Read `Number_of_bytes` value from string and handle the size suffixes
392 *
393 * This function scales the resulting size value according to the suffixes
394 * for G (2^30), M (2^20), and K (2^10) if present.
395 *
396 * \return number of consumed characters
397 */
398 inline size_t ascii_to(const char *s, Number_of_bytes &result)
399 {
400 unsigned long res = 0;
401
402 /* convert numeric part of string */
403 int i = ascii_to_unsigned(s, res, 0);
404
405 /* handle suffixes */
406 if (i > 0)
407 switch (s[i]) {
408 case `G`: res *= 1024;
409 case `M`: res *= 1024;
410 case `K`: res *= 1024; i++;
411 default: break;
412 }
413
414 result = res;
415 return i;
416 }
417
418
419 /**
420 * Read double float value from string
421 *
422 * \return number of consumed characters
423 */
424 inline size_t ascii_to(const char *s, double &result)
425 {
426 double v = 0.0; /* decimal part */
427 double d = 0.1; /* power of fractional digit */
428 bool neg = false; /* sign */
429 int i = 0; /* character counter */
430
431 if (s[i] == `-`) {
432 neg = true;
433 i++;
434 }
435
436 /* parse decimal part of number */
437 for (; s[i] && is_digit(s[i]); i++)
438 v = 10*v + digit(s[i], false);
439
440 /* if no fractional part exists, return current value */
441 if (s[i] != `.`) {
442 result = neg ? -v : v;
443 return i;
444 }
445
446 /* skip comma */
447 i++;
448
449 /* parse fractional part of number */
450 for (; s[i] && is_digit(s[i]); i++, d *= 0.1)
451 v += d*digit(s[i], false);
452
453 result = neg ? -v : v;
454 return i;
455 }
456
457
458 /**
459 * Check for end of quotation
460 *
461 * Checks if next character is non-backslashed quotation mark.
462 */
463 inline bool end_of_quote(const char *s) {
464 return s[0] != `\\` && s[1] == `\"`; }
465
466
467 /**
468 * Unpack quoted string
469 *
470 * \param src source string including the quotation marks ("...")
471 * \param dst destination buffer
472 *
473 * \return number of characters or negative error code
474 */
475 inline int unpack_string(const char *src, char *dst, int dst_len)
476 {
477 /* check if quoted string */
478 if (*src != `"`) return -1;
479
480 src++;
481
482 int i = 0;
483 for (; *src && !end_of_quote(src - 1) && (i < dst_len - 1); i++) {
484
485 /* transform `\"` to `"` */
486 if (src[0] == `\\` && src[1] == `\"`) {
487 *dst++ = `"`;
488 src += 2;
489 } else
490 *dst++ = *src++;
491 }
492
493 /* write terminating null */
494 *dst = 0;
495
496 return i;
497 }
498 }
499
500
501 /**
502 * Buffer that contains a null-terminated string
503 *
504 * \param CAPACITY buffer size including the terminating zero
505 */
506 template <Genode::size_t CAPACITY>
507 class Genode::String
508 {
509 private:
510
511 char _buf[CAPACITY];
512 size_t _length;
513
514 public:
515
516 constexpr static size_t size() { return CAPACITY; }
517
518 String() : _length(0) { }
519
520 String(char const *str, size_t len = ~0UL - 1)
521 :
522 _length(min(len + 1, min(strlen(str) + 1, CAPACITY)))
523 {
524 strncpy(_buf, str, _length);
525 }
526
527 size_t length() const { return _length; }
528
529 static constexpr size_t capacity() { return CAPACITY; }
530
531 bool valid() const {
532 return (_length <= CAPACITY) && (_length != 0) && (_buf[_length - 1] == `\0`); }
533
534 char const *string() const { return valid() ? _buf : ""; }
535
536 bool operator == (char const *other) const
537 {
538 return strcmp(string(), other) == 0;
539 }
540
541 bool operator != (char const *other) const
542 {
543 return strcmp(string(), other) != 0;
544 }
545
546 template <size_t OTHER_CAPACITY>
547 bool operator == (String<OTHER_CAPACITY> const &other) const
548 {
549 return strcmp(string(), other.string()) == 0;
550 }
551
552 template <size_t OTHER_CAPACITY>
553 bool operator != (String<OTHER_CAPACITY> const &other) const
554 {
555 return strcmp(string(), other.string()) != 0;
556 }
557 };
558
559 #endif /* _INCLUDE__UTIL__STRING_H_ */