source: mainline/uspace/lib/c/generic/str.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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