source: mainline/uspace/lib/c/generic/str.c@ 1433ecda

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1433ecda was 1433ecda, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix cstyle: make ccheck-fix and commit only files where all the changes are good.

  • Property mode set to 100644
File size: 40.9 KB
RevLine 
[936351c1]1/*
[df4ed85]2 * Copyright (c) 2005 Martin Decky
[576845ec]3 * Copyright (c) 2008 Jiri Svoboda
[22cf42d9]4 * Copyright (c) 2011 Martin Sucha
[c4bbca8]5 * Copyright (c) 2011 Oleg Romanenko
[936351c1]6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * - The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
[a46da63]32/** @addtogroup libc
[b2951e2]33 * @{
34 */
35/** @file
36 */
37
[19f857a]38#include <str.h>
[582a0b8]39#include <stddef.h>
[9539be6]40#include <stdint.h>
[38d150e]41#include <stdlib.h>
42#include <assert.h>
[e64c4b2]43#include <ctype.h>
[171f9a1]44#include <errno.h>
[f2b8cdc]45#include <align.h>
[095003a8]46#include <mem.h>
[16bfcd3]47#include <limits.h>
[171f9a1]48
[8e893ae]49/** Check the condition if wchar_t is signed */
[002fd5f]50#ifdef __WCHAR_UNSIGNED__
[1433ecda]51#define WCHAR_SIGNED_CHECK(cond) (true)
[8e893ae]52#else
[1433ecda]53#define WCHAR_SIGNED_CHECK(cond) (cond)
[8e893ae]54#endif
55
[171f9a1]56/** Byte mask consisting of lowest @n bits (out of 8) */
57#define LO_MASK_8(n) ((uint8_t) ((1 << (n)) - 1))
58
59/** Byte mask consisting of lowest @n bits (out of 32) */
60#define LO_MASK_32(n) ((uint32_t) ((1 << (n)) - 1))
61
62/** Byte mask consisting of highest @n bits (out of 8) */
63#define HI_MASK_8(n) (~LO_MASK_8(8 - (n)))
64
65/** Number of data bits in a UTF-8 continuation byte */
66#define CONT_BITS 6
67
68/** Decode a single character from a string.
69 *
70 * Decode a single character from a string of size @a size. Decoding starts
71 * at @a offset and this offset is moved to the beginning of the next
72 * character. In case of decoding error, offset generally advances at least
73 * by one. However, offset is never moved beyond size.
74 *
75 * @param str String (not necessarily NULL-terminated).
76 * @param offset Byte offset in string where to start decoding.
77 * @param size Size of the string (in bytes).
78 *
79 * @return Value of decoded character, U_SPECIAL on decoding error or
80 * NULL if attempt to decode beyond @a size.
81 *
82 */
83wchar_t str_decode(const char *str, size_t *offset, size_t size)
84{
85 if (*offset + 1 > size)
86 return 0;
[a35b458]87
[171f9a1]88 /* First byte read from string */
89 uint8_t b0 = (uint8_t) str[(*offset)++];
[a35b458]90
[171f9a1]91 /* Determine code length */
[a35b458]92
[171f9a1]93 unsigned int b0_bits; /* Data bits in first byte */
94 unsigned int cbytes; /* Number of continuation bytes */
[a35b458]95
[171f9a1]96 if ((b0 & 0x80) == 0) {
97 /* 0xxxxxxx (Plain ASCII) */
98 b0_bits = 7;
99 cbytes = 0;
100 } else if ((b0 & 0xe0) == 0xc0) {
101 /* 110xxxxx 10xxxxxx */
102 b0_bits = 5;
103 cbytes = 1;
104 } else if ((b0 & 0xf0) == 0xe0) {
105 /* 1110xxxx 10xxxxxx 10xxxxxx */
106 b0_bits = 4;
107 cbytes = 2;
108 } else if ((b0 & 0xf8) == 0xf0) {
109 /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
110 b0_bits = 3;
111 cbytes = 3;
112 } else {
113 /* 10xxxxxx -- unexpected continuation byte */
114 return U_SPECIAL;
115 }
[a35b458]116
[171f9a1]117 if (*offset + cbytes > size)
118 return U_SPECIAL;
[a35b458]119
[171f9a1]120 wchar_t ch = b0 & LO_MASK_8(b0_bits);
[a35b458]121
[171f9a1]122 /* Decode continuation bytes */
123 while (cbytes > 0) {
124 uint8_t b = (uint8_t) str[(*offset)++];
[a35b458]125
[171f9a1]126 /* Must be 10xxxxxx */
127 if ((b & 0xc0) != 0x80)
128 return U_SPECIAL;
[a35b458]129
[171f9a1]130 /* Shift data bits to ch */
131 ch = (ch << CONT_BITS) | (wchar_t) (b & LO_MASK_8(CONT_BITS));
132 cbytes--;
133 }
[a35b458]134
[171f9a1]135 return ch;
136}
137
[568693b]138/** Decode a single character from a string to the left.
139 *
140 * Decode a single character from a string of size @a size. Decoding starts
141 * at @a offset and this offset is moved to the beginning of the previous
142 * character. In case of decoding error, offset generally decreases at least
143 * by one. However, offset is never moved before 0.
144 *
145 * @param str String (not necessarily NULL-terminated).
146 * @param offset Byte offset in string where to start decoding.
147 * @param size Size of the string (in bytes).
148 *
149 * @return Value of decoded character, U_SPECIAL on decoding error or
150 * NULL if attempt to decode beyond @a start of str.
151 *
152 */
153wchar_t str_decode_reverse(const char *str, size_t *offset, size_t size)
154{
155 if (*offset == 0)
156 return 0;
[a35b458]157
[568693b]158 size_t processed = 0;
159 /* Continue while continuation bytes found */
160 while (*offset > 0 && processed < 4) {
161 uint8_t b = (uint8_t) str[--(*offset)];
[a35b458]162
[568693b]163 if (processed == 0 && (b & 0x80) == 0) {
164 /* 0xxxxxxx (Plain ASCII) */
165 return b & 0x7f;
[1433ecda]166 } else if ((b & 0xe0) == 0xc0 || (b & 0xf0) == 0xe0 ||
[568693b]167 (b & 0xf8) == 0xf0) {
168 /* Start byte */
169 size_t start_offset = *offset;
170 return str_decode(str, &start_offset, size);
[1433ecda]171 } else if ((b & 0xc0) != 0x80) {
[568693b]172 /* Not a continuation byte */
173 return U_SPECIAL;
174 }
175 processed++;
176 }
177 /* Too many continuation bytes */
178 return U_SPECIAL;
179}
180
[171f9a1]181/** Encode a single character to string representation.
182 *
183 * Encode a single character to string representation (i.e. UTF-8) and store
184 * it into a buffer at @a offset. Encoding starts at @a offset and this offset
185 * is moved to the position where the next character can be written to.
186 *
187 * @param ch Input character.
188 * @param str Output buffer.
189 * @param offset Byte offset where to start writing.
190 * @param size Size of the output buffer (in bytes).
191 *
192 * @return EOK if the character was encoded successfully, EOVERFLOW if there
[d4a3ee5]193 * was not enough space in the output buffer or EINVAL if the character
194 * code was invalid.
[171f9a1]195 */
[b7fd2a0]196errno_t chr_encode(const wchar_t ch, char *str, size_t *offset, size_t size)
[171f9a1]197{
198 if (*offset >= size)
199 return EOVERFLOW;
[a35b458]200
[171f9a1]201 if (!chr_check(ch))
202 return EINVAL;
[a35b458]203
[171f9a1]204 /* Unsigned version of ch (bit operations should only be done
205 on unsigned types). */
206 uint32_t cc = (uint32_t) ch;
[a35b458]207
[171f9a1]208 /* Determine how many continuation bytes are needed */
[a35b458]209
[171f9a1]210 unsigned int b0_bits; /* Data bits in first byte */
211 unsigned int cbytes; /* Number of continuation bytes */
[a35b458]212
[171f9a1]213 if ((cc & ~LO_MASK_32(7)) == 0) {
214 b0_bits = 7;
215 cbytes = 0;
216 } else if ((cc & ~LO_MASK_32(11)) == 0) {
217 b0_bits = 5;
218 cbytes = 1;
219 } else if ((cc & ~LO_MASK_32(16)) == 0) {
220 b0_bits = 4;
221 cbytes = 2;
222 } else if ((cc & ~LO_MASK_32(21)) == 0) {
223 b0_bits = 3;
224 cbytes = 3;
225 } else {
226 /* Codes longer than 21 bits are not supported */
227 return EINVAL;
228 }
[a35b458]229
[171f9a1]230 /* Check for available space in buffer */
231 if (*offset + cbytes >= size)
232 return EOVERFLOW;
[a35b458]233
[171f9a1]234 /* Encode continuation bytes */
235 unsigned int i;
236 for (i = cbytes; i > 0; i--) {
237 str[*offset + i] = 0x80 | (cc & LO_MASK_32(CONT_BITS));
238 cc = cc >> CONT_BITS;
239 }
[a35b458]240
[171f9a1]241 /* Encode first byte */
242 str[*offset] = (cc & LO_MASK_32(b0_bits)) | HI_MASK_8(8 - b0_bits - 1);
[a35b458]243
[171f9a1]244 /* Advance offset */
245 *offset += cbytes + 1;
[a35b458]246
[171f9a1]247 return EOK;
248}
249
[f2b8cdc]250/** Get size of string.
251 *
252 * Get the number of bytes which are used by the string @a str (excluding the
253 * NULL-terminator).
254 *
255 * @param str String to consider.
256 *
257 * @return Number of bytes used by the string
258 *
259 */
260size_t str_size(const char *str)
261{
262 size_t size = 0;
[a35b458]263
[f2b8cdc]264 while (*str++ != 0)
265 size++;
[a35b458]266
[f2b8cdc]267 return size;
268}
269
270/** Get size of wide string.
271 *
272 * Get the number of bytes which are used by the wide string @a str (excluding the
273 * NULL-terminator).
274 *
275 * @param str Wide string to consider.
276 *
277 * @return Number of bytes used by the wide string
278 *
279 */
280size_t wstr_size(const wchar_t *str)
281{
282 return (wstr_length(str) * sizeof(wchar_t));
283}
284
285/** Get size of string with length limit.
286 *
287 * Get the number of bytes which are used by up to @a max_len first
288 * characters in the string @a str. If @a max_len is greater than
289 * the length of @a str, the entire string is measured (excluding the
290 * NULL-terminator).
291 *
292 * @param str String to consider.
293 * @param max_len Maximum number of characters to measure.
294 *
295 * @return Number of bytes used by the characters.
296 *
297 */
[d4a3ee5]298size_t str_lsize(const char *str, size_t max_len)
[f2b8cdc]299{
[d4a3ee5]300 size_t len = 0;
[f2b8cdc]301 size_t offset = 0;
[a35b458]302
[f2b8cdc]303 while (len < max_len) {
304 if (str_decode(str, &offset, STR_NO_LIMIT) == 0)
305 break;
[a35b458]306
[f2b8cdc]307 len++;
308 }
[a35b458]309
[f2b8cdc]310 return offset;
311}
312
[560d79f]313/** Get size of string with size limit.
314 *
315 * Get the number of bytes which are used by the string @a str
316 * (excluding the NULL-terminator), but no more than @max_size bytes.
317 *
318 * @param str String to consider.
319 * @param max_size Maximum number of bytes to measure.
320 *
321 * @return Number of bytes used by the string
322 *
323 */
324size_t str_nsize(const char *str, size_t max_size)
325{
326 size_t size = 0;
[a35b458]327
[560d79f]328 while ((*str++ != 0) && (size < max_size))
329 size++;
[a35b458]330
[560d79f]331 return size;
332}
333
334/** Get size of wide string with size limit.
335 *
336 * Get the number of bytes which are used by the wide string @a str
337 * (excluding the NULL-terminator), but no more than @max_size bytes.
338 *
339 * @param str Wide string to consider.
340 * @param max_size Maximum number of bytes to measure.
341 *
342 * @return Number of bytes used by the wide string
343 *
344 */
345size_t wstr_nsize(const wchar_t *str, size_t max_size)
346{
347 return (wstr_nlength(str, max_size) * sizeof(wchar_t));
348}
349
[f2b8cdc]350/** Get size of wide string with length limit.
351 *
352 * Get the number of bytes which are used by up to @a max_len first
353 * wide characters in the wide string @a str. If @a max_len is greater than
354 * the length of @a str, the entire wide string is measured (excluding the
355 * NULL-terminator).
356 *
357 * @param str Wide string to consider.
358 * @param max_len Maximum number of wide characters to measure.
359 *
360 * @return Number of bytes used by the wide characters.
361 *
362 */
[d4a3ee5]363size_t wstr_lsize(const wchar_t *str, size_t max_len)
[f2b8cdc]364{
365 return (wstr_nlength(str, max_len * sizeof(wchar_t)) * sizeof(wchar_t));
366}
367
368/** Get number of characters in a string.
369 *
370 * @param str NULL-terminated string.
371 *
372 * @return Number of characters in string.
373 *
374 */
[d4a3ee5]375size_t str_length(const char *str)
[f2b8cdc]376{
[d4a3ee5]377 size_t len = 0;
[f2b8cdc]378 size_t offset = 0;
[a35b458]379
[f2b8cdc]380 while (str_decode(str, &offset, STR_NO_LIMIT) != 0)
381 len++;
[a35b458]382
[f2b8cdc]383 return len;
384}
385
386/** Get number of characters in a wide string.
387 *
388 * @param str NULL-terminated wide string.
389 *
390 * @return Number of characters in @a str.
391 *
392 */
[d4a3ee5]393size_t wstr_length(const wchar_t *wstr)
[f2b8cdc]394{
[d4a3ee5]395 size_t len = 0;
[a35b458]396
[f2b8cdc]397 while (*wstr++ != 0)
398 len++;
[a35b458]399
[f2b8cdc]400 return len;
401}
402
403/** Get number of characters in a string with size limit.
404 *
405 * @param str NULL-terminated string.
406 * @param size Maximum number of bytes to consider.
407 *
408 * @return Number of characters in string.
409 *
410 */
[d4a3ee5]411size_t str_nlength(const char *str, size_t size)
[f2b8cdc]412{
[d4a3ee5]413 size_t len = 0;
[f2b8cdc]414 size_t offset = 0;
[a35b458]415
[f2b8cdc]416 while (str_decode(str, &offset, size) != 0)
417 len++;
[a35b458]418
[f2b8cdc]419 return len;
420}
421
422/** Get number of characters in a string with size limit.
423 *
424 * @param str NULL-terminated string.
425 * @param size Maximum number of bytes to consider.
426 *
427 * @return Number of characters in string.
428 *
429 */
[d4a3ee5]430size_t wstr_nlength(const wchar_t *str, size_t size)
[f2b8cdc]431{
[d4a3ee5]432 size_t len = 0;
433 size_t limit = ALIGN_DOWN(size, sizeof(wchar_t));
434 size_t offset = 0;
[a35b458]435
[f2b8cdc]436 while ((offset < limit) && (*str++ != 0)) {
437 len++;
438 offset += sizeof(wchar_t);
439 }
[a35b458]440
[f2b8cdc]441 return len;
442}
443
[be2a38ad]444/** Get character display width on a character cell display.
445 *
446 * @param ch Character
447 * @return Width of character in cells.
448 */
449size_t chr_width(wchar_t ch)
450{
451 return 1;
452}
453
454/** Get string display width on a character cell display.
455 *
456 * @param str String
457 * @return Width of string in cells.
458 */
459size_t str_width(const char *str)
460{
461 size_t width = 0;
462 size_t offset = 0;
463 wchar_t ch;
[a35b458]464
[be2a38ad]465 while ((ch = str_decode(str, &offset, STR_NO_LIMIT)) != 0)
466 width += chr_width(ch);
[a35b458]467
[be2a38ad]468 return width;
469}
470
[f2b8cdc]471/** Check whether character is plain ASCII.
472 *
473 * @return True if character is plain ASCII.
474 *
475 */
476bool ascii_check(wchar_t ch)
477{
[8e893ae]478 if (WCHAR_SIGNED_CHECK(ch >= 0) && (ch <= 127))
[f2b8cdc]479 return true;
[a35b458]480
[f2b8cdc]481 return false;
482}
483
[171f9a1]484/** Check whether character is valid
485 *
486 * @return True if character is a valid Unicode code point.
487 *
488 */
[f2b8cdc]489bool chr_check(wchar_t ch)
[171f9a1]490{
[8e893ae]491 if (WCHAR_SIGNED_CHECK(ch >= 0) && (ch <= 1114111))
[171f9a1]492 return true;
[a35b458]493
[171f9a1]494 return false;
495}
[936351c1]496
[f2b8cdc]497/** Compare two NULL terminated strings.
498 *
499 * Do a char-by-char comparison of two NULL-terminated strings.
[4efeab5]500 * The strings are considered equal iff their length is equal
501 * and both strings consist of the same sequence of characters.
502 *
[1772e6d]503 * A string S1 is less than another string S2 if it has a character with
504 * lower value at the first character position where the strings differ.
505 * If the strings differ in length, the shorter one is treated as if
506 * padded by characters with a value of zero.
[f2b8cdc]507 *
508 * @param s1 First string to compare.
509 * @param s2 Second string to compare.
510 *
[1772e6d]511 * @return 0 if the strings are equal, -1 if the first is less than the second,
512 * 1 if the second is less than the first.
[f2b8cdc]513 *
514 */
515int str_cmp(const char *s1, const char *s2)
516{
517 wchar_t c1 = 0;
518 wchar_t c2 = 0;
[8227d63]519
[f2b8cdc]520 size_t off1 = 0;
521 size_t off2 = 0;
522
523 while (true) {
524 c1 = str_decode(s1, &off1, STR_NO_LIMIT);
525 c2 = str_decode(s2, &off2, STR_NO_LIMIT);
526
527 if (c1 < c2)
528 return -1;
[8227d63]529
[f2b8cdc]530 if (c1 > c2)
531 return 1;
532
533 if (c1 == 0 || c2 == 0)
[8227d63]534 break;
[f2b8cdc]535 }
536
537 return 0;
538}
539
540/** Compare two NULL terminated strings with length limit.
541 *
542 * Do a char-by-char comparison of two NULL-terminated strings.
[4efeab5]543 * The strings are considered equal iff
544 * min(str_length(s1), max_len) == min(str_length(s2), max_len)
545 * and both strings consist of the same sequence of characters,
546 * up to max_len characters.
547 *
[1772e6d]548 * A string S1 is less than another string S2 if it has a character with
549 * lower value at the first character position where the strings differ.
550 * If the strings differ in length, the shorter one is treated as if
551 * padded by characters with a value of zero. Only the first max_len
552 * characters are considered.
[f2b8cdc]553 *
554 * @param s1 First string to compare.
555 * @param s2 Second string to compare.
556 * @param max_len Maximum number of characters to consider.
557 *
[1772e6d]558 * @return 0 if the strings are equal, -1 if the first is less than the second,
559 * 1 if the second is less than the first.
[f2b8cdc]560 *
561 */
[d4a3ee5]562int str_lcmp(const char *s1, const char *s2, size_t max_len)
[f2b8cdc]563{
564 wchar_t c1 = 0;
565 wchar_t c2 = 0;
[8227d63]566
[f2b8cdc]567 size_t off1 = 0;
568 size_t off2 = 0;
[8227d63]569
[d4a3ee5]570 size_t len = 0;
[f2b8cdc]571
572 while (true) {
573 if (len >= max_len)
574 break;
575
576 c1 = str_decode(s1, &off1, STR_NO_LIMIT);
577 c2 = str_decode(s2, &off2, STR_NO_LIMIT);
578
[8227d63]579 if (c1 < c2)
580 return -1;
581
582 if (c1 > c2)
583 return 1;
584
585 if (c1 == 0 || c2 == 0)
586 break;
587
588 ++len;
589 }
590
591 return 0;
592
593}
594
595/** Compare two NULL terminated strings in case-insensitive manner.
596 *
597 * Do a char-by-char comparison of two NULL-terminated strings.
598 * The strings are considered equal iff their length is equal
599 * and both strings consist of the same sequence of characters
600 * when converted to lower case.
601 *
602 * A string S1 is less than another string S2 if it has a character with
603 * lower value at the first character position where the strings differ.
604 * If the strings differ in length, the shorter one is treated as if
605 * padded by characters with a value of zero.
606 *
607 * @param s1 First string to compare.
608 * @param s2 Second string to compare.
609 *
610 * @return 0 if the strings are equal, -1 if the first is less than the second,
611 * 1 if the second is less than the first.
612 *
613 */
614int str_casecmp(const char *s1, const char *s2)
615{
616 wchar_t c1 = 0;
617 wchar_t c2 = 0;
618
619 size_t off1 = 0;
620 size_t off2 = 0;
621
622 while (true) {
623 c1 = tolower(str_decode(s1, &off1, STR_NO_LIMIT));
624 c2 = tolower(str_decode(s2, &off2, STR_NO_LIMIT));
625
626 if (c1 < c2)
627 return -1;
628
629 if (c1 > c2)
630 return 1;
631
632 if (c1 == 0 || c2 == 0)
633 break;
634 }
635
636 return 0;
637}
638
639/** Compare two NULL terminated strings with length limit in case-insensitive
640 * manner.
641 *
642 * Do a char-by-char comparison of two NULL-terminated strings.
643 * The strings are considered equal iff
644 * min(str_length(s1), max_len) == min(str_length(s2), max_len)
645 * and both strings consist of the same sequence of characters,
646 * up to max_len characters.
647 *
648 * A string S1 is less than another string S2 if it has a character with
649 * lower value at the first character position where the strings differ.
650 * If the strings differ in length, the shorter one is treated as if
651 * padded by characters with a value of zero. Only the first max_len
652 * characters are considered.
653 *
654 * @param s1 First string to compare.
655 * @param s2 Second string to compare.
656 * @param max_len Maximum number of characters to consider.
657 *
658 * @return 0 if the strings are equal, -1 if the first is less than the second,
659 * 1 if the second is less than the first.
660 *
661 */
662int str_lcasecmp(const char *s1, const char *s2, size_t max_len)
663{
664 wchar_t c1 = 0;
665 wchar_t c2 = 0;
[a35b458]666
[8227d63]667 size_t off1 = 0;
668 size_t off2 = 0;
[a35b458]669
[8227d63]670 size_t len = 0;
671
672 while (true) {
673 if (len >= max_len)
674 break;
675
676 c1 = tolower(str_decode(s1, &off1, STR_NO_LIMIT));
677 c2 = tolower(str_decode(s2, &off2, STR_NO_LIMIT));
678
[f2b8cdc]679 if (c1 < c2)
680 return -1;
681
682 if (c1 > c2)
683 return 1;
684
685 if (c1 == 0 || c2 == 0)
686 break;
687
[1b20da0]688 ++len;
[f2b8cdc]689 }
690
691 return 0;
692
693}
694
[dce39b4]695/** Test whether p is a prefix of s.
696 *
697 * Do a char-by-char comparison of two NULL-terminated strings
698 * and determine if p is a prefix of s.
699 *
700 * @param s The string in which to look
701 * @param p The string to check if it is a prefix of s
702 *
703 * @return true iff p is prefix of s else false
704 *
705 */
706bool str_test_prefix(const char *s, const char *p)
707{
708 wchar_t c1 = 0;
709 wchar_t c2 = 0;
[a35b458]710
[dce39b4]711 size_t off1 = 0;
712 size_t off2 = 0;
713
714 while (true) {
715 c1 = str_decode(s, &off1, STR_NO_LIMIT);
716 c2 = str_decode(p, &off2, STR_NO_LIMIT);
[a35b458]717
[dce39b4]718 if (c2 == 0)
719 return true;
720
721 if (c1 != c2)
722 return false;
[a35b458]723
[dce39b4]724 if (c1 == 0)
725 break;
726 }
727
728 return false;
729}
730
[6eb2e96]731/** Copy string.
[f2b8cdc]732 *
[6eb2e96]733 * Copy source string @a src to destination buffer @a dest.
734 * No more than @a size bytes are written. If the size of the output buffer
735 * is at least one byte, the output string will always be well-formed, i.e.
736 * null-terminated and containing only complete characters.
[f2b8cdc]737 *
[abf09311]738 * @param dest Destination buffer.
[6700ee2]739 * @param count Size of the destination buffer (must be > 0).
[6eb2e96]740 * @param src Source string.
[8e893ae]741 *
[f2b8cdc]742 */
[6eb2e96]743void str_cpy(char *dest, size_t size, const char *src)
[f2b8cdc]744{
[6700ee2]745 /* There must be space for a null terminator in the buffer. */
746 assert(size > 0);
[a35b458]747
[abf09311]748 size_t src_off = 0;
749 size_t dest_off = 0;
[a35b458]750
[abf09311]751 wchar_t ch;
[6eb2e96]752 while ((ch = str_decode(src, &src_off, STR_NO_LIMIT)) != 0) {
753 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
754 break;
755 }
[a35b458]756
[6eb2e96]757 dest[dest_off] = '\0';
758}
759
760/** Copy size-limited substring.
761 *
[6700ee2]762 * Copy prefix of string @a src of max. size @a size to destination buffer
763 * @a dest. No more than @a size bytes are written. The output string will
764 * always be well-formed, i.e. null-terminated and containing only complete
765 * characters.
[6eb2e96]766 *
767 * No more than @a n bytes are read from the input string, so it does not
768 * have to be null-terminated.
769 *
[abf09311]770 * @param dest Destination buffer.
[6700ee2]771 * @param count Size of the destination buffer (must be > 0).
[6eb2e96]772 * @param src Source string.
[abf09311]773 * @param n Maximum number of bytes to read from @a src.
[8e893ae]774 *
[6eb2e96]775 */
776void str_ncpy(char *dest, size_t size, const char *src, size_t n)
777{
[6700ee2]778 /* There must be space for a null terminator in the buffer. */
779 assert(size > 0);
[a35b458]780
[abf09311]781 size_t src_off = 0;
782 size_t dest_off = 0;
[a35b458]783
[abf09311]784 wchar_t ch;
[6eb2e96]785 while ((ch = str_decode(src, &src_off, n)) != 0) {
786 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
[f2b8cdc]787 break;
788 }
[a35b458]789
[6eb2e96]790 dest[dest_off] = '\0';
[f2b8cdc]791}
792
[4482bc7]793/** Append one string to another.
794 *
795 * Append source string @a src to string in destination buffer @a dest.
796 * Size of the destination buffer is @a dest. If the size of the output buffer
797 * is at least one byte, the output string will always be well-formed, i.e.
798 * null-terminated and containing only complete characters.
799 *
[0f06dbc]800 * @param dest Destination buffer.
[4482bc7]801 * @param count Size of the destination buffer.
802 * @param src Source string.
803 */
804void str_append(char *dest, size_t size, const char *src)
805{
806 size_t dstr_size;
807
808 dstr_size = str_size(dest);
[3815efb]809 if (dstr_size >= size)
[a8bc7f8]810 return;
[a35b458]811
[4482bc7]812 str_cpy(dest + dstr_size, size - dstr_size, src);
813}
814
[dcb74c0a]815/** Convert space-padded ASCII to string.
816 *
817 * Common legacy text encoding in hardware is 7-bit ASCII fitted into
[c3d19ac]818 * a fixed-width byte buffer (bit 7 always zero), right-padded with spaces
[dcb74c0a]819 * (ASCII 0x20). Convert space-padded ascii to string representation.
820 *
821 * If the text does not fit into the destination buffer, the function converts
822 * as many characters as possible and returns EOVERFLOW.
823 *
824 * If the text contains non-ASCII bytes (with bit 7 set), the whole string is
825 * converted anyway and invalid characters are replaced with question marks
826 * (U_SPECIAL) and the function returns EIO.
827 *
828 * Regardless of return value upon return @a dest will always be well-formed.
829 *
830 * @param dest Destination buffer
831 * @param size Size of destination buffer
832 * @param src Space-padded ASCII.
833 * @param n Size of the source buffer in bytes.
834 *
835 * @return EOK on success, EOVERFLOW if the text does not fit
836 * destination buffer, EIO if the text contains
837 * non-ASCII bytes.
838 */
[b7fd2a0]839errno_t spascii_to_str(char *dest, size_t size, const uint8_t *src, size_t n)
[dcb74c0a]840{
841 size_t sidx;
842 size_t didx;
843 size_t dlast;
844 uint8_t byte;
[b7fd2a0]845 errno_t rc;
846 errno_t result;
[dcb74c0a]847
848 /* There must be space for a null terminator in the buffer. */
849 assert(size > 0);
850 result = EOK;
851
852 didx = 0;
853 dlast = 0;
854 for (sidx = 0; sidx < n; ++sidx) {
855 byte = src[sidx];
856 if (!ascii_check(byte)) {
857 byte = U_SPECIAL;
858 result = EIO;
859 }
860
861 rc = chr_encode(byte, dest, &didx, size - 1);
862 if (rc != EOK) {
863 assert(rc == EOVERFLOW);
864 dest[didx] = '\0';
865 return rc;
866 }
867
868 /* Remember dest index after last non-empty character */
869 if (byte != 0x20)
870 dlast = didx;
871 }
872
873 /* Terminate string after last non-empty character */
874 dest[dlast] = '\0';
875 return result;
876}
877
[0f06dbc]878/** Convert wide string to string.
[f2b8cdc]879 *
[0f06dbc]880 * Convert wide string @a src to string. The output is written to the buffer
881 * specified by @a dest and @a size. @a size must be non-zero and the string
882 * written will always be well-formed.
[f2b8cdc]883 *
[0f06dbc]884 * @param dest Destination buffer.
885 * @param size Size of the destination buffer.
886 * @param src Source wide string.
[f2b8cdc]887 */
[81e9cb3]888void wstr_to_str(char *dest, size_t size, const wchar_t *src)
[f2b8cdc]889{
890 wchar_t ch;
[0f06dbc]891 size_t src_idx;
892 size_t dest_off;
893
894 /* There must be space for a null terminator in the buffer. */
895 assert(size > 0);
[a35b458]896
[0f06dbc]897 src_idx = 0;
898 dest_off = 0;
899
[f2b8cdc]900 while ((ch = src[src_idx++]) != 0) {
[81e9cb3]901 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
[f2b8cdc]902 break;
903 }
[0f06dbc]904
905 dest[dest_off] = '\0';
[f2b8cdc]906}
907
[82374b2]908/** Convert UTF16 string to string.
909 *
910 * Convert utf16 string @a src to string. The output is written to the buffer
911 * specified by @a dest and @a size. @a size must be non-zero and the string
912 * written will always be well-formed. Surrogate pairs also supported.
913 *
914 * @param dest Destination buffer.
915 * @param size Size of the destination buffer.
916 * @param src Source utf16 string.
917 *
[cde999a]918 * @return EOK, if success, an error code otherwise.
[82374b2]919 */
[b7fd2a0]920errno_t utf16_to_str(char *dest, size_t size, const uint16_t *src)
[82374b2]921{
[abb7491c]922 size_t idx = 0, dest_off = 0;
[82374b2]923 wchar_t ch;
[b7fd2a0]924 errno_t rc = EOK;
[82374b2]925
926 /* There must be space for a null terminator in the buffer. */
927 assert(size > 0);
928
929 while (src[idx]) {
930 if ((src[idx] & 0xfc00) == 0xd800) {
[abb7491c]931 if (src[idx + 1] && (src[idx + 1] & 0xfc00) == 0xdc00) {
[82374b2]932 ch = 0x10000;
933 ch += (src[idx] & 0x03FF) << 10;
[abb7491c]934 ch += (src[idx + 1] & 0x03FF);
[82374b2]935 idx += 2;
[1433ecda]936 } else
[82374b2]937 break;
938 } else {
939 ch = src[idx];
940 idx++;
941 }
[abb7491c]942 rc = chr_encode(ch, dest, &dest_off, size - 1);
[82374b2]943 if (rc != EOK)
944 break;
945 }
946 dest[dest_off] = '\0';
947 return rc;
948}
949
[b06414f]950/** Convert string to UTF16 string.
951 *
952 * Convert string @a src to utf16 string. The output is written to the buffer
953 * specified by @a dest and @a dlen. @a dlen must be non-zero and the string
954 * written will always be well-formed. Surrogate pairs also supported.
955 *
956 * @param dest Destination buffer.
957 * @param dlen Number of utf16 characters that fit in the destination buffer.
958 * @param src Source string.
959 *
[cde999a]960 * @return EOK, if success, an error code otherwise.
[b06414f]961 */
[b7fd2a0]962errno_t str_to_utf16(uint16_t *dest, size_t dlen, const char *src)
[fc97128]963{
[b7fd2a0]964 errno_t rc = EOK;
[abb7491c]965 size_t offset = 0;
966 size_t idx = 0;
[fc97128]967 wchar_t c;
968
[b06414f]969 assert(dlen > 0);
[a35b458]970
[fc97128]971 while ((c = str_decode(src, &offset, STR_NO_LIMIT)) != 0) {
972 if (c > 0x10000) {
[b06414f]973 if (idx + 2 >= dlen - 1) {
[abb7491c]974 rc = EOVERFLOW;
[fc97128]975 break;
976 }
977 c = (c - 0x10000);
978 dest[idx] = 0xD800 | (c >> 10);
[abb7491c]979 dest[idx + 1] = 0xDC00 | (c & 0x3FF);
[fc97128]980 idx++;
981 } else {
[1433ecda]982 dest[idx] = c;
[fc97128]983 }
984
985 idx++;
[b06414f]986 if (idx >= dlen - 1) {
[abb7491c]987 rc = EOVERFLOW;
[fc97128]988 break;
989 }
990 }
991
992 dest[idx] = '\0';
993 return rc;
[f2b8cdc]994}
995
[b2906c0]996/** Get size of UTF-16 string.
997 *
998 * Get the number of words which are used by the UTF-16 string @a ustr
999 * (excluding the NULL-terminator).
1000 *
1001 * @param ustr UTF-16 string to consider.
1002 *
1003 * @return Number of words used by the UTF-16 string
1004 *
1005 */
1006size_t utf16_wsize(const uint16_t *ustr)
1007{
1008 size_t wsize = 0;
1009
1010 while (*ustr++ != 0)
1011 wsize++;
1012
1013 return wsize;
1014}
1015
[fc97128]1016
[b67c7d64]1017/** Convert wide string to new string.
1018 *
1019 * Convert wide string @a src to string. Space for the new string is allocated
1020 * on the heap.
1021 *
1022 * @param src Source wide string.
1023 * @return New string.
1024 */
1025char *wstr_to_astr(const wchar_t *src)
1026{
1027 char dbuf[STR_BOUNDS(1)];
1028 char *str;
1029 wchar_t ch;
1030
1031 size_t src_idx;
1032 size_t dest_off;
1033 size_t dest_size;
1034
1035 /* Compute size of encoded string. */
1036
1037 src_idx = 0;
1038 dest_size = 0;
1039
1040 while ((ch = src[src_idx++]) != 0) {
1041 dest_off = 0;
1042 if (chr_encode(ch, dbuf, &dest_off, STR_BOUNDS(1)) != EOK)
1043 break;
1044 dest_size += dest_off;
1045 }
1046
1047 str = malloc(dest_size + 1);
1048 if (str == NULL)
1049 return NULL;
1050
1051 /* Encode string. */
1052
1053 src_idx = 0;
1054 dest_off = 0;
1055
1056 while ((ch = src[src_idx++]) != 0) {
1057 if (chr_encode(ch, str, &dest_off, dest_size) != EOK)
1058 break;
1059 }
1060
1061 str[dest_size] = '\0';
1062 return str;
1063}
1064
1065
[da2bd08]1066/** Convert string to wide string.
1067 *
1068 * Convert string @a src to wide string. The output is written to the
[0f06dbc]1069 * buffer specified by @a dest and @a dlen. @a dlen must be non-zero
1070 * and the wide string written will always be null-terminated.
[da2bd08]1071 *
1072 * @param dest Destination buffer.
1073 * @param dlen Length of destination buffer (number of wchars).
1074 * @param src Source string.
1075 */
[81e9cb3]1076void str_to_wstr(wchar_t *dest, size_t dlen, const char *src)
[da2bd08]1077{
1078 size_t offset;
1079 size_t di;
1080 wchar_t c;
1081
1082 assert(dlen > 0);
1083
1084 offset = 0;
1085 di = 0;
1086
1087 do {
[81e9cb3]1088 if (di >= dlen - 1)
[da2bd08]1089 break;
1090
1091 c = str_decode(src, &offset, STR_NO_LIMIT);
1092 dest[di++] = c;
1093 } while (c != '\0');
1094
1095 dest[dlen - 1] = '\0';
1096}
1097
[22cf42d9]1098/** Convert string to wide string.
1099 *
1100 * Convert string @a src to wide string. A new wide NULL-terminated
1101 * string will be allocated on the heap.
1102 *
1103 * @param src Source string.
1104 */
1105wchar_t *str_to_awstr(const char *str)
1106{
1107 size_t len = str_length(str);
[a35b458]1108
[1433ecda]1109 wchar_t *wstr = calloc(len + 1, sizeof(wchar_t));
[b48d046]1110 if (wstr == NULL)
1111 return NULL;
[a35b458]1112
[b48d046]1113 str_to_wstr(wstr, len + 1, str);
[22cf42d9]1114 return wstr;
1115}
1116
[f2b8cdc]1117/** Find first occurence of character in string.
1118 *
1119 * @param str String to search.
1120 * @param ch Character to look for.
1121 *
1122 * @return Pointer to character in @a str or NULL if not found.
1123 */
[dd2cfa7]1124char *str_chr(const char *str, wchar_t ch)
[f2b8cdc]1125{
1126 wchar_t acc;
1127 size_t off = 0;
[f2d2c7ba]1128 size_t last = 0;
[a35b458]1129
[f2b8cdc]1130 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
1131 if (acc == ch)
[dd2cfa7]1132 return (char *) (str + last);
[f2d2c7ba]1133 last = off;
[f2b8cdc]1134 }
[a35b458]1135
[f2b8cdc]1136 return NULL;
1137}
1138
[1737bfb]1139/** Removes specified trailing characters from a string.
1140 *
1141 * @param str String to remove from.
1142 * @param ch Character to remove.
1143 */
1144void str_rtrim(char *str, wchar_t ch)
1145{
1146 size_t off = 0;
1147 size_t pos = 0;
1148 wchar_t c;
1149 bool update_last_chunk = true;
1150 char *last_chunk = NULL;
1151
1152 while ((c = str_decode(str, &off, STR_NO_LIMIT))) {
1153 if (c != ch) {
1154 update_last_chunk = true;
1155 last_chunk = NULL;
1156 } else if (update_last_chunk) {
1157 update_last_chunk = false;
1158 last_chunk = (str + pos);
1159 }
1160 pos = off;
1161 }
1162
1163 if (last_chunk)
1164 *last_chunk = '\0';
1165}
1166
1167/** Removes specified leading characters from a string.
1168 *
1169 * @param str String to remove from.
1170 * @param ch Character to remove.
1171 */
1172void str_ltrim(char *str, wchar_t ch)
1173{
1174 wchar_t acc;
1175 size_t off = 0;
1176 size_t pos = 0;
1177 size_t str_sz = str_size(str);
1178
1179 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
1180 if (acc != ch)
1181 break;
1182 else
1183 pos = off;
1184 }
1185
1186 if (pos > 0) {
1187 memmove(str, &str[pos], str_sz - pos);
1188 pos = str_sz - pos;
[a18a8b9]1189 str[pos] = '\0';
[1737bfb]1190 }
1191}
1192
[7afb4a5]1193/** Find last occurence of character in string.
1194 *
1195 * @param str String to search.
1196 * @param ch Character to look for.
1197 *
1198 * @return Pointer to character in @a str or NULL if not found.
1199 */
[dd2cfa7]1200char *str_rchr(const char *str, wchar_t ch)
[7afb4a5]1201{
1202 wchar_t acc;
1203 size_t off = 0;
[f2d2c7ba]1204 size_t last = 0;
[d4a3ee5]1205 const char *res = NULL;
[a35b458]1206
[7afb4a5]1207 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
1208 if (acc == ch)
[f2d2c7ba]1209 res = (str + last);
1210 last = off;
[7afb4a5]1211 }
[a35b458]1212
[dd2cfa7]1213 return (char *) res;
[7afb4a5]1214}
1215
[f2b8cdc]1216/** Insert a wide character into a wide string.
1217 *
1218 * Insert a wide character into a wide string at position
1219 * @a pos. The characters after the position are shifted.
1220 *
1221 * @param str String to insert to.
1222 * @param ch Character to insert to.
1223 * @param pos Character index where to insert.
1224 @ @param max_pos Characters in the buffer.
1225 *
1226 * @return True if the insertion was sucessful, false if the position
1227 * is out of bounds.
1228 *
1229 */
[d4a3ee5]1230bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos)
[f2b8cdc]1231{
[d4a3ee5]1232 size_t len = wstr_length(str);
[a35b458]1233
[f2b8cdc]1234 if ((pos > len) || (pos + 1 > max_pos))
1235 return false;
[a35b458]1236
[d4a3ee5]1237 size_t i;
[f2b8cdc]1238 for (i = len; i + 1 > pos; i--)
1239 str[i + 1] = str[i];
[a35b458]1240
[f2b8cdc]1241 str[pos] = ch;
[a35b458]1242
[f2b8cdc]1243 return true;
1244}
1245
1246/** Remove a wide character from a wide string.
1247 *
1248 * Remove a wide character from a wide string at position
1249 * @a pos. The characters after the position are shifted.
1250 *
1251 * @param str String to remove from.
1252 * @param pos Character index to remove.
1253 *
1254 * @return True if the removal was sucessful, false if the position
1255 * is out of bounds.
1256 *
1257 */
[d4a3ee5]1258bool wstr_remove(wchar_t *str, size_t pos)
[f2b8cdc]1259{
[d4a3ee5]1260 size_t len = wstr_length(str);
[a35b458]1261
[f2b8cdc]1262 if (pos >= len)
1263 return false;
[a35b458]1264
[d4a3ee5]1265 size_t i;
[f2b8cdc]1266 for (i = pos + 1; i <= len; i++)
1267 str[i - 1] = str[i];
[a35b458]1268
[f2b8cdc]1269 return true;
1270}
1271
[672a24d]1272
[abf09311]1273/** Duplicate string.
1274 *
1275 * Allocate a new string and copy characters from the source
1276 * string into it. The duplicate string is allocated via sleeping
1277 * malloc(), thus this function can sleep in no memory conditions.
1278 *
1279 * The allocation cannot fail and the return value is always
1280 * a valid pointer. The duplicate string is always a well-formed
1281 * null-terminated UTF-8 string, but it can differ from the source
1282 * string on the byte level.
1283 *
1284 * @param src Source string.
1285 *
1286 * @return Duplicate string.
1287 *
1288 */
[fc6dd18]1289char *str_dup(const char *src)
1290{
[abf09311]1291 size_t size = str_size(src) + 1;
1292 char *dest = (char *) malloc(size);
[fc6dd18]1293 if (dest == NULL)
1294 return (char *) NULL;
[a35b458]1295
[abf09311]1296 str_cpy(dest, size, src);
1297 return dest;
[fc6dd18]1298}
1299
[abf09311]1300/** Duplicate string with size limit.
1301 *
1302 * Allocate a new string and copy up to @max_size bytes from the source
1303 * string into it. The duplicate string is allocated via sleeping
1304 * malloc(), thus this function can sleep in no memory conditions.
1305 * No more than @max_size + 1 bytes is allocated, but if the size
1306 * occupied by the source string is smaller than @max_size + 1,
1307 * less is allocated.
1308 *
1309 * The allocation cannot fail and the return value is always
1310 * a valid pointer. The duplicate string is always a well-formed
1311 * null-terminated UTF-8 string, but it can differ from the source
1312 * string on the byte level.
1313 *
1314 * @param src Source string.
1315 * @param n Maximum number of bytes to duplicate.
1316 *
1317 * @return Duplicate string.
1318 *
1319 */
1320char *str_ndup(const char *src, size_t n)
[fc6dd18]1321{
1322 size_t size = str_size(src);
[abf09311]1323 if (size > n)
1324 size = n;
[a35b458]1325
[fc6dd18]1326 char *dest = (char *) malloc(size + 1);
1327 if (dest == NULL)
1328 return (char *) NULL;
[a35b458]1329
[abf09311]1330 str_ncpy(dest, size + 1, src, size);
[fc6dd18]1331 return dest;
1332}
1333
[ee3f6f6]1334/** Split string by delimiters.
1335 *
1336 * @param s String to be tokenized. May not be NULL.
1337 * @param delim String with the delimiters.
1338 * @param next Variable which will receive the pointer to the
1339 * continuation of the string following the first
1340 * occurrence of any of the delimiter characters.
1341 * May be NULL.
1342 * @return Pointer to the prefix of @a s before the first
1343 * delimiter character. NULL if no such prefix
1344 * exists.
1345 */
1346char *str_tok(char *s, const char *delim, char **next)
[576845ec]1347{
1348 char *start, *end;
[69df837f]1349
[ee3f6f6]1350 if (!s)
1351 return NULL;
[a35b458]1352
[ee3f6f6]1353 size_t len = str_size(s);
1354 size_t cur;
1355 size_t tmp;
1356 wchar_t ch;
[69df837f]1357
[576845ec]1358 /* Skip over leading delimiters. */
[948222e4]1359 tmp = 0;
1360 cur = 0;
1361 while ((ch = str_decode(s, &tmp, len)) && str_chr(delim, ch))
[ee3f6f6]1362 cur = tmp;
1363 start = &s[cur];
[69df837f]1364
[576845ec]1365 /* Skip over token characters. */
[948222e4]1366 tmp = cur;
1367 while ((ch = str_decode(s, &tmp, len)) && !str_chr(delim, ch))
[ee3f6f6]1368 cur = tmp;
1369 end = &s[cur];
1370 if (next)
1371 *next = (ch ? &s[tmp] : &s[cur]);
1372
1373 if (start == end)
[576845ec]1374 return NULL; /* No more tokens. */
[69df837f]1375
[576845ec]1376 /* Overwrite delimiter with NULL terminator. */
1377 *end = '\0';
1378 return start;
[69df837f]1379}
1380
[d47279b]1381/** Convert string to uint64_t (internal variant).
1382 *
1383 * @param nptr Pointer to string.
1384 * @param endptr Pointer to the first invalid character is stored here.
1385 * @param base Zero or number between 2 and 36 inclusive.
1386 * @param neg Indication of unary minus is stored here.
1387 * @apram result Result of the conversion.
1388 *
1389 * @return EOK if conversion was successful.
1390 *
1391 */
[b7fd2a0]1392static errno_t str_uint(const char *nptr, char **endptr, unsigned int base,
[d47279b]1393 bool *neg, uint64_t *result)
1394{
1395 assert(endptr != NULL);
1396 assert(neg != NULL);
1397 assert(result != NULL);
[a35b458]1398
[d47279b]1399 *neg = false;
1400 const char *str = nptr;
[a35b458]1401
[d47279b]1402 /* Ignore leading whitespace */
1403 while (isspace(*str))
1404 str++;
[a35b458]1405
[d47279b]1406 if (*str == '-') {
1407 *neg = true;
1408 str++;
1409 } else if (*str == '+')
1410 str++;
[a35b458]1411
[d47279b]1412 if (base == 0) {
1413 /* Decode base if not specified */
1414 base = 10;
[a35b458]1415
[d47279b]1416 if (*str == '0') {
1417 base = 8;
1418 str++;
[a35b458]1419
[d47279b]1420 switch (*str) {
1421 case 'b':
1422 case 'B':
1423 base = 2;
1424 str++;
1425 break;
1426 case 'o':
1427 case 'O':
1428 base = 8;
1429 str++;
1430 break;
1431 case 'd':
1432 case 'D':
1433 case 't':
1434 case 'T':
1435 base = 10;
1436 str++;
1437 break;
1438 case 'x':
1439 case 'X':
1440 base = 16;
1441 str++;
1442 break;
1443 default:
1444 str--;
1445 }
1446 }
1447 } else {
1448 /* Check base range */
1449 if ((base < 2) || (base > 36)) {
1450 *endptr = (char *) str;
1451 return EINVAL;
1452 }
1453 }
[a35b458]1454
[d47279b]1455 *result = 0;
1456 const char *startstr = str;
[a35b458]1457
[d47279b]1458 while (*str != 0) {
1459 unsigned int digit;
[a35b458]1460
[d47279b]1461 if ((*str >= 'a') && (*str <= 'z'))
1462 digit = *str - 'a' + 10;
1463 else if ((*str >= 'A') && (*str <= 'Z'))
1464 digit = *str - 'A' + 10;
1465 else if ((*str >= '0') && (*str <= '9'))
1466 digit = *str - '0';
1467 else
1468 break;
[a35b458]1469
[d47279b]1470 if (digit >= base)
1471 break;
[a35b458]1472
[d47279b]1473 uint64_t prev = *result;
1474 *result = (*result) * base + digit;
[a35b458]1475
[d47279b]1476 if (*result < prev) {
1477 /* Overflow */
1478 *endptr = (char *) str;
1479 return EOVERFLOW;
1480 }
[a35b458]1481
[d47279b]1482 str++;
1483 }
[a35b458]1484
[d47279b]1485 if (str == startstr) {
1486 /*
1487 * No digits were decoded => first invalid character is
1488 * the first character of the string.
1489 */
1490 str = nptr;
1491 }
[a35b458]1492
[d47279b]1493 *endptr = (char *) str;
[a35b458]1494
[d47279b]1495 if (str == nptr)
1496 return EINVAL;
[a35b458]1497
[d47279b]1498 return EOK;
1499}
1500
[d7f6248]1501/** Convert string to uint8_t.
1502 *
1503 * @param nptr Pointer to string.
1504 * @param endptr If not NULL, pointer to the first invalid character
1505 * is stored here.
1506 * @param base Zero or number between 2 and 36 inclusive.
1507 * @param strict Do not allow any trailing characters.
1508 * @param result Result of the conversion.
1509 *
1510 * @return EOK if conversion was successful.
1511 *
1512 */
[b7fd2a0]1513errno_t str_uint8_t(const char *nptr, const char **endptr, unsigned int base,
[d7f6248]1514 bool strict, uint8_t *result)
1515{
1516 assert(result != NULL);
[a35b458]1517
[d7f6248]1518 bool neg;
1519 char *lendptr;
1520 uint64_t res;
[b7fd2a0]1521 errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
[a35b458]1522
[d7f6248]1523 if (endptr != NULL)
1524 *endptr = (char *) lendptr;
[a35b458]1525
[d7f6248]1526 if (ret != EOK)
1527 return ret;
[a35b458]1528
[d7f6248]1529 /* Do not allow negative values */
1530 if (neg)
1531 return EINVAL;
[a35b458]1532
[d7f6248]1533 /* Check whether we are at the end of
1534 the string in strict mode */
1535 if ((strict) && (*lendptr != 0))
1536 return EINVAL;
[a35b458]1537
[d7f6248]1538 /* Check for overflow */
1539 uint8_t _res = (uint8_t) res;
1540 if (_res != res)
1541 return EOVERFLOW;
[a35b458]1542
[d7f6248]1543 *result = _res;
[a35b458]1544
[d7f6248]1545 return EOK;
1546}
1547
1548/** Convert string to uint16_t.
1549 *
1550 * @param nptr Pointer to string.
1551 * @param endptr If not NULL, pointer to the first invalid character
1552 * is stored here.
1553 * @param base Zero or number between 2 and 36 inclusive.
1554 * @param strict Do not allow any trailing characters.
1555 * @param result Result of the conversion.
1556 *
1557 * @return EOK if conversion was successful.
1558 *
1559 */
[b7fd2a0]1560errno_t str_uint16_t(const char *nptr, const char **endptr, unsigned int base,
[d7f6248]1561 bool strict, uint16_t *result)
1562{
1563 assert(result != NULL);
[a35b458]1564
[d7f6248]1565 bool neg;
1566 char *lendptr;
1567 uint64_t res;
[b7fd2a0]1568 errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
[a35b458]1569
[d7f6248]1570 if (endptr != NULL)
1571 *endptr = (char *) lendptr;
[a35b458]1572
[d7f6248]1573 if (ret != EOK)
1574 return ret;
[a35b458]1575
[d7f6248]1576 /* Do not allow negative values */
1577 if (neg)
1578 return EINVAL;
[a35b458]1579
[d7f6248]1580 /* Check whether we are at the end of
1581 the string in strict mode */
1582 if ((strict) && (*lendptr != 0))
1583 return EINVAL;
[a35b458]1584
[d7f6248]1585 /* Check for overflow */
1586 uint16_t _res = (uint16_t) res;
1587 if (_res != res)
1588 return EOVERFLOW;
[a35b458]1589
[d7f6248]1590 *result = _res;
[a35b458]1591
[d7f6248]1592 return EOK;
1593}
1594
1595/** Convert string to uint32_t.
1596 *
1597 * @param nptr Pointer to string.
1598 * @param endptr If not NULL, pointer to the first invalid character
1599 * is stored here.
1600 * @param base Zero or number between 2 and 36 inclusive.
1601 * @param strict Do not allow any trailing characters.
1602 * @param result Result of the conversion.
1603 *
1604 * @return EOK if conversion was successful.
1605 *
1606 */
[b7fd2a0]1607errno_t str_uint32_t(const char *nptr, const char **endptr, unsigned int base,
[d7f6248]1608 bool strict, uint32_t *result)
1609{
1610 assert(result != NULL);
[a35b458]1611
[d7f6248]1612 bool neg;
1613 char *lendptr;
1614 uint64_t res;
[b7fd2a0]1615 errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
[a35b458]1616
[d7f6248]1617 if (endptr != NULL)
1618 *endptr = (char *) lendptr;
[a35b458]1619
[d7f6248]1620 if (ret != EOK)
1621 return ret;
[a35b458]1622
[d7f6248]1623 /* Do not allow negative values */
1624 if (neg)
1625 return EINVAL;
[a35b458]1626
[d7f6248]1627 /* Check whether we are at the end of
1628 the string in strict mode */
1629 if ((strict) && (*lendptr != 0))
1630 return EINVAL;
[a35b458]1631
[d7f6248]1632 /* Check for overflow */
1633 uint32_t _res = (uint32_t) res;
1634 if (_res != res)
1635 return EOVERFLOW;
[a35b458]1636
[d7f6248]1637 *result = _res;
[a35b458]1638
[d7f6248]1639 return EOK;
1640}
1641
[d47279b]1642/** Convert string to uint64_t.
1643 *
1644 * @param nptr Pointer to string.
1645 * @param endptr If not NULL, pointer to the first invalid character
1646 * is stored here.
1647 * @param base Zero or number between 2 and 36 inclusive.
1648 * @param strict Do not allow any trailing characters.
1649 * @param result Result of the conversion.
1650 *
1651 * @return EOK if conversion was successful.
1652 *
1653 */
[b7fd2a0]1654errno_t str_uint64_t(const char *nptr, const char **endptr, unsigned int base,
[d47279b]1655 bool strict, uint64_t *result)
1656{
1657 assert(result != NULL);
[a35b458]1658
[d47279b]1659 bool neg;
1660 char *lendptr;
[b7fd2a0]1661 errno_t ret = str_uint(nptr, &lendptr, base, &neg, result);
[a35b458]1662
[d47279b]1663 if (endptr != NULL)
1664 *endptr = (char *) lendptr;
[a35b458]1665
[d47279b]1666 if (ret != EOK)
1667 return ret;
[a35b458]1668
[d47279b]1669 /* Do not allow negative values */
1670 if (neg)
1671 return EINVAL;
[a35b458]1672
[d47279b]1673 /* Check whether we are at the end of
1674 the string in strict mode */
1675 if ((strict) && (*lendptr != 0))
1676 return EINVAL;
[a35b458]1677
[d47279b]1678 return EOK;
1679}
1680
1681/** Convert string to size_t.
1682 *
1683 * @param nptr Pointer to string.
1684 * @param endptr If not NULL, pointer to the first invalid character
1685 * is stored here.
1686 * @param base Zero or number between 2 and 36 inclusive.
1687 * @param strict Do not allow any trailing characters.
1688 * @param result Result of the conversion.
1689 *
1690 * @return EOK if conversion was successful.
1691 *
1692 */
[b7fd2a0]1693errno_t str_size_t(const char *nptr, const char **endptr, unsigned int base,
[d47279b]1694 bool strict, size_t *result)
1695{
1696 assert(result != NULL);
[a35b458]1697
[d47279b]1698 bool neg;
1699 char *lendptr;
1700 uint64_t res;
[b7fd2a0]1701 errno_t ret = str_uint(nptr, &lendptr, base, &neg, &res);
[a35b458]1702
[d47279b]1703 if (endptr != NULL)
1704 *endptr = (char *) lendptr;
[a35b458]1705
[d47279b]1706 if (ret != EOK)
1707 return ret;
[a35b458]1708
[d47279b]1709 /* Do not allow negative values */
1710 if (neg)
1711 return EINVAL;
[a35b458]1712
[d47279b]1713 /* Check whether we are at the end of
1714 the string in strict mode */
1715 if ((strict) && (*lendptr != 0))
1716 return EINVAL;
[a35b458]1717
[d47279b]1718 /* Check for overflow */
1719 size_t _res = (size_t) res;
1720 if (_res != res)
1721 return EOVERFLOW;
[a35b458]1722
[d47279b]1723 *result = _res;
[a35b458]1724
[d47279b]1725 return EOK;
1726}
1727
[e535eeb]1728void order_suffix(const uint64_t val, uint64_t *rv, char *suffix)
1729{
[933cadf]1730 if (val > UINT64_C(10000000000000000000)) {
1731 *rv = val / UINT64_C(1000000000000000000);
[e535eeb]1732 *suffix = 'Z';
[933cadf]1733 } else if (val > UINT64_C(1000000000000000000)) {
1734 *rv = val / UINT64_C(1000000000000000);
[e535eeb]1735 *suffix = 'E';
[933cadf]1736 } else if (val > UINT64_C(1000000000000000)) {
1737 *rv = val / UINT64_C(1000000000000);
[e535eeb]1738 *suffix = 'T';
[933cadf]1739 } else if (val > UINT64_C(1000000000000)) {
1740 *rv = val / UINT64_C(1000000000);
[e535eeb]1741 *suffix = 'G';
[933cadf]1742 } else if (val > UINT64_C(1000000000)) {
1743 *rv = val / UINT64_C(1000000);
[e535eeb]1744 *suffix = 'M';
[933cadf]1745 } else if (val > UINT64_C(1000000)) {
1746 *rv = val / UINT64_C(1000);
[e535eeb]1747 *suffix = 'k';
1748 } else {
1749 *rv = val;
1750 *suffix = ' ';
1751 }
1752}
1753
[933cadf]1754void bin_order_suffix(const uint64_t val, uint64_t *rv, const char **suffix,
1755 bool fixed)
1756{
1757 if (val > UINT64_C(1152921504606846976)) {
1758 *rv = val / UINT64_C(1125899906842624);
1759 *suffix = "EiB";
1760 } else if (val > UINT64_C(1125899906842624)) {
1761 *rv = val / UINT64_C(1099511627776);
1762 *suffix = "TiB";
1763 } else if (val > UINT64_C(1099511627776)) {
1764 *rv = val / UINT64_C(1073741824);
1765 *suffix = "GiB";
1766 } else if (val > UINT64_C(1073741824)) {
1767 *rv = val / UINT64_C(1048576);
1768 *suffix = "MiB";
1769 } else if (val > UINT64_C(1048576)) {
1770 *rv = val / UINT64_C(1024);
1771 *suffix = "KiB";
1772 } else {
1773 *rv = val;
1774 if (fixed)
1775 *suffix = "B ";
1776 else
1777 *suffix = "B";
1778 }
1779}
1780
[a46da63]1781/** @}
[b2951e2]1782 */
Note: See TracBrowser for help on using the repository browser.