source: mainline/uspace/lib/c/generic/str.c@ 58898d1d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 58898d1d was c8dc9ac, checked in by Jakub Jermar <jakub@…>, 9 years ago

Merge from lp:~werkov/helenos/various-fixes

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