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_ */