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