source: mainline/uspace/lib/c/generic/str.c@ 3ca2e36

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3ca2e36 was 568693b, checked in by Martin Sucha <sucha14@…>, 13 years ago

Add reverse variant of str_decode.

  • Property mode set to 100644
File size: 40.8 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#include <str.h>
48
49/** Check the condition if wchar_t is signed */
50#ifdef WCHAR_IS_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 */
198int 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/** Test whether p is a prefix of s.
598 *
599 * Do a char-by-char comparison of two NULL-terminated strings
600 * and determine if p is a prefix of s.
601 *
602 * @param s The string in which to look
603 * @param p The string to check if it is a prefix of s
604 *
605 * @return true iff p is prefix of s else false
606 *
607 */
608bool str_test_prefix(const char *s, const char *p)
609{
610 wchar_t c1 = 0;
611 wchar_t c2 = 0;
612
613 size_t off1 = 0;
614 size_t off2 = 0;
615
616 while (true) {
617 c1 = str_decode(s, &off1, STR_NO_LIMIT);
618 c2 = str_decode(p, &off2, STR_NO_LIMIT);
619
620 if (c2 == 0)
621 return true;
622
623 if (c1 != c2)
624 return false;
625
626 if (c1 == 0)
627 break;
628 }
629
630 return false;
631}
632
633/** Copy string.
634 *
635 * Copy source string @a src to destination buffer @a dest.
636 * No more than @a size bytes are written. If the size of the output buffer
637 * is at least one byte, the output string will always be well-formed, i.e.
638 * null-terminated and containing only complete characters.
639 *
640 * @param dest Destination buffer.
641 * @param count Size of the destination buffer (must be > 0).
642 * @param src Source string.
643 *
644 */
645void str_cpy(char *dest, size_t size, const char *src)
646{
647 /* There must be space for a null terminator in the buffer. */
648 assert(size > 0);
649
650 size_t src_off = 0;
651 size_t dest_off = 0;
652
653 wchar_t ch;
654 while ((ch = str_decode(src, &src_off, STR_NO_LIMIT)) != 0) {
655 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
656 break;
657 }
658
659 dest[dest_off] = '\0';
660}
661
662/** Copy size-limited substring.
663 *
664 * Copy prefix of string @a src of max. size @a size to destination buffer
665 * @a dest. No more than @a size bytes are written. The output string will
666 * always be well-formed, i.e. null-terminated and containing only complete
667 * characters.
668 *
669 * No more than @a n bytes are read from the input string, so it does not
670 * have to be null-terminated.
671 *
672 * @param dest Destination buffer.
673 * @param count Size of the destination buffer (must be > 0).
674 * @param src Source string.
675 * @param n Maximum number of bytes to read from @a src.
676 *
677 */
678void str_ncpy(char *dest, size_t size, const char *src, size_t n)
679{
680 /* There must be space for a null terminator in the buffer. */
681 assert(size > 0);
682
683 size_t src_off = 0;
684 size_t dest_off = 0;
685
686 wchar_t ch;
687 while ((ch = str_decode(src, &src_off, n)) != 0) {
688 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
689 break;
690 }
691
692 dest[dest_off] = '\0';
693}
694
695/** Append one string to another.
696 *
697 * Append source string @a src to string in destination buffer @a dest.
698 * Size of the destination buffer is @a dest. If the size of the output buffer
699 * is at least one byte, the output string will always be well-formed, i.e.
700 * null-terminated and containing only complete characters.
701 *
702 * @param dest Destination buffer.
703 * @param count Size of the destination buffer.
704 * @param src Source string.
705 */
706void str_append(char *dest, size_t size, const char *src)
707{
708 size_t dstr_size;
709
710 dstr_size = str_size(dest);
711 if (dstr_size >= size)
712 return;
713
714 str_cpy(dest + dstr_size, size - dstr_size, src);
715}
716
717/** Convert space-padded ASCII to string.
718 *
719 * Common legacy text encoding in hardware is 7-bit ASCII fitted into
720 * a fixed-width byte buffer (bit 7 always zero), right-padded with spaces
721 * (ASCII 0x20). Convert space-padded ascii to string representation.
722 *
723 * If the text does not fit into the destination buffer, the function converts
724 * as many characters as possible and returns EOVERFLOW.
725 *
726 * If the text contains non-ASCII bytes (with bit 7 set), the whole string is
727 * converted anyway and invalid characters are replaced with question marks
728 * (U_SPECIAL) and the function returns EIO.
729 *
730 * Regardless of return value upon return @a dest will always be well-formed.
731 *
732 * @param dest Destination buffer
733 * @param size Size of destination buffer
734 * @param src Space-padded ASCII.
735 * @param n Size of the source buffer in bytes.
736 *
737 * @return EOK on success, EOVERFLOW if the text does not fit
738 * destination buffer, EIO if the text contains
739 * non-ASCII bytes.
740 */
741int spascii_to_str(char *dest, size_t size, const uint8_t *src, size_t n)
742{
743 size_t sidx;
744 size_t didx;
745 size_t dlast;
746 uint8_t byte;
747 int rc;
748 int result;
749
750 /* There must be space for a null terminator in the buffer. */
751 assert(size > 0);
752 result = EOK;
753
754 didx = 0;
755 dlast = 0;
756 for (sidx = 0; sidx < n; ++sidx) {
757 byte = src[sidx];
758 if (!ascii_check(byte)) {
759 byte = U_SPECIAL;
760 result = EIO;
761 }
762
763 rc = chr_encode(byte, dest, &didx, size - 1);
764 if (rc != EOK) {
765 assert(rc == EOVERFLOW);
766 dest[didx] = '\0';
767 return rc;
768 }
769
770 /* Remember dest index after last non-empty character */
771 if (byte != 0x20)
772 dlast = didx;
773 }
774
775 /* Terminate string after last non-empty character */
776 dest[dlast] = '\0';
777 return result;
778}
779
780/** Convert wide string to string.
781 *
782 * Convert wide string @a src to string. The output is written to the buffer
783 * specified by @a dest and @a size. @a size must be non-zero and the string
784 * written will always be well-formed.
785 *
786 * @param dest Destination buffer.
787 * @param size Size of the destination buffer.
788 * @param src Source wide string.
789 */
790void wstr_to_str(char *dest, size_t size, const wchar_t *src)
791{
792 wchar_t ch;
793 size_t src_idx;
794 size_t dest_off;
795
796 /* There must be space for a null terminator in the buffer. */
797 assert(size > 0);
798
799 src_idx = 0;
800 dest_off = 0;
801
802 while ((ch = src[src_idx++]) != 0) {
803 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
804 break;
805 }
806
807 dest[dest_off] = '\0';
808}
809
810/** Convert UTF16 string to string.
811 *
812 * Convert utf16 string @a src to string. The output is written to the buffer
813 * specified by @a dest and @a size. @a size must be non-zero and the string
814 * written will always be well-formed. Surrogate pairs also supported.
815 *
816 * @param dest Destination buffer.
817 * @param size Size of the destination buffer.
818 * @param src Source utf16 string.
819 *
820 * @return EOK, if success, negative otherwise.
821 */
822int utf16_to_str(char *dest, size_t size, const uint16_t *src)
823{
824 size_t idx = 0, dest_off = 0;
825 wchar_t ch;
826 int rc = EOK;
827
828 /* There must be space for a null terminator in the buffer. */
829 assert(size > 0);
830
831 while (src[idx]) {
832 if ((src[idx] & 0xfc00) == 0xd800) {
833 if (src[idx + 1] && (src[idx + 1] & 0xfc00) == 0xdc00) {
834 ch = 0x10000;
835 ch += (src[idx] & 0x03FF) << 10;
836 ch += (src[idx + 1] & 0x03FF);
837 idx += 2;
838 }
839 else
840 break;
841 } else {
842 ch = src[idx];
843 idx++;
844 }
845 rc = chr_encode(ch, dest, &dest_off, size - 1);
846 if (rc != EOK)
847 break;
848 }
849 dest[dest_off] = '\0';
850 return rc;
851}
852
853int str_to_utf16(uint16_t *dest, size_t size, const char *src)
854{
855 int rc = EOK;
856 size_t offset = 0;
857 size_t idx = 0;
858 wchar_t c;
859
860 assert(size > 0);
861
862 while ((c = str_decode(src, &offset, STR_NO_LIMIT)) != 0) {
863 if (c > 0x10000) {
864 if (idx + 2 >= size - 1) {
865 rc = EOVERFLOW;
866 break;
867 }
868 c = (c - 0x10000);
869 dest[idx] = 0xD800 | (c >> 10);
870 dest[idx + 1] = 0xDC00 | (c & 0x3FF);
871 idx++;
872 } else {
873 dest[idx] = c;
874 }
875
876 idx++;
877 if (idx >= size - 1) {
878 rc = EOVERFLOW;
879 break;
880 }
881 }
882
883 dest[idx] = '\0';
884 return rc;
885}
886
887
888/** Convert wide string to new string.
889 *
890 * Convert wide string @a src to string. Space for the new string is allocated
891 * on the heap.
892 *
893 * @param src Source wide string.
894 * @return New string.
895 */
896char *wstr_to_astr(const wchar_t *src)
897{
898 char dbuf[STR_BOUNDS(1)];
899 char *str;
900 wchar_t ch;
901
902 size_t src_idx;
903 size_t dest_off;
904 size_t dest_size;
905
906 /* Compute size of encoded string. */
907
908 src_idx = 0;
909 dest_size = 0;
910
911 while ((ch = src[src_idx++]) != 0) {
912 dest_off = 0;
913 if (chr_encode(ch, dbuf, &dest_off, STR_BOUNDS(1)) != EOK)
914 break;
915 dest_size += dest_off;
916 }
917
918 str = malloc(dest_size + 1);
919 if (str == NULL)
920 return NULL;
921
922 /* Encode string. */
923
924 src_idx = 0;
925 dest_off = 0;
926
927 while ((ch = src[src_idx++]) != 0) {
928 if (chr_encode(ch, str, &dest_off, dest_size) != EOK)
929 break;
930 }
931
932 str[dest_size] = '\0';
933 return str;
934}
935
936
937/** Convert string to wide string.
938 *
939 * Convert string @a src to wide string. The output is written to the
940 * buffer specified by @a dest and @a dlen. @a dlen must be non-zero
941 * and the wide string written will always be null-terminated.
942 *
943 * @param dest Destination buffer.
944 * @param dlen Length of destination buffer (number of wchars).
945 * @param src Source string.
946 */
947void str_to_wstr(wchar_t *dest, size_t dlen, const char *src)
948{
949 size_t offset;
950 size_t di;
951 wchar_t c;
952
953 assert(dlen > 0);
954
955 offset = 0;
956 di = 0;
957
958 do {
959 if (di >= dlen - 1)
960 break;
961
962 c = str_decode(src, &offset, STR_NO_LIMIT);
963 dest[di++] = c;
964 } while (c != '\0');
965
966 dest[dlen - 1] = '\0';
967}
968
969/** Convert string to wide string.
970 *
971 * Convert string @a src to wide string. A new wide NULL-terminated
972 * string will be allocated on the heap.
973 *
974 * @param src Source string.
975 */
976wchar_t *str_to_awstr(const char *str)
977{
978 size_t len = str_length(str);
979
980 wchar_t *wstr = calloc(len+1, sizeof(wchar_t));
981 if (wstr == NULL)
982 return NULL;
983
984 str_to_wstr(wstr, len + 1, str);
985 return wstr;
986}
987
988/** Find first occurence of character in string.
989 *
990 * @param str String to search.
991 * @param ch Character to look for.
992 *
993 * @return Pointer to character in @a str or NULL if not found.
994 */
995char *str_chr(const char *str, wchar_t ch)
996{
997 wchar_t acc;
998 size_t off = 0;
999 size_t last = 0;
1000
1001 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
1002 if (acc == ch)
1003 return (char *) (str + last);
1004 last = off;
1005 }
1006
1007 return NULL;
1008}
1009
1010/** Removes specified trailing characters from a string.
1011 *
1012 * @param str String to remove from.
1013 * @param ch Character to remove.
1014 */
1015void str_rtrim(char *str, wchar_t ch)
1016{
1017 size_t off = 0;
1018 size_t pos = 0;
1019 wchar_t c;
1020 bool update_last_chunk = true;
1021 char *last_chunk = NULL;
1022
1023 while ((c = str_decode(str, &off, STR_NO_LIMIT))) {
1024 if (c != ch) {
1025 update_last_chunk = true;
1026 last_chunk = NULL;
1027 } else if (update_last_chunk) {
1028 update_last_chunk = false;
1029 last_chunk = (str + pos);
1030 }
1031 pos = off;
1032 }
1033
1034 if (last_chunk)
1035 *last_chunk = '\0';
1036}
1037
1038/** Removes specified leading characters from a string.
1039 *
1040 * @param str String to remove from.
1041 * @param ch Character to remove.
1042 */
1043void str_ltrim(char *str, wchar_t ch)
1044{
1045 wchar_t acc;
1046 size_t off = 0;
1047 size_t pos = 0;
1048 size_t str_sz = str_size(str);
1049
1050 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
1051 if (acc != ch)
1052 break;
1053 else
1054 pos = off;
1055 }
1056
1057 if (pos > 0) {
1058 memmove(str, &str[pos], str_sz - pos);
1059 pos = str_sz - pos;
1060 str[str_sz - pos] = '\0';
1061 }
1062}
1063
1064/** Find last occurence of character in string.
1065 *
1066 * @param str String to search.
1067 * @param ch Character to look for.
1068 *
1069 * @return Pointer to character in @a str or NULL if not found.
1070 */
1071char *str_rchr(const char *str, wchar_t ch)
1072{
1073 wchar_t acc;
1074 size_t off = 0;
1075 size_t last = 0;
1076 const char *res = NULL;
1077
1078 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
1079 if (acc == ch)
1080 res = (str + last);
1081 last = off;
1082 }
1083
1084 return (char *) res;
1085}
1086
1087/** Insert a wide character into a wide string.
1088 *
1089 * Insert a wide character into a wide string at position
1090 * @a pos. The characters after the position are shifted.
1091 *
1092 * @param str String to insert to.
1093 * @param ch Character to insert to.
1094 * @param pos Character index where to insert.
1095 @ @param max_pos Characters in the buffer.
1096 *
1097 * @return True if the insertion was sucessful, false if the position
1098 * is out of bounds.
1099 *
1100 */
1101bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos)
1102{
1103 size_t len = wstr_length(str);
1104
1105 if ((pos > len) || (pos + 1 > max_pos))
1106 return false;
1107
1108 size_t i;
1109 for (i = len; i + 1 > pos; i--)
1110 str[i + 1] = str[i];
1111
1112 str[pos] = ch;
1113
1114 return true;
1115}
1116
1117/** Remove a wide character from a wide string.
1118 *
1119 * Remove a wide character from a wide string at position
1120 * @a pos. The characters after the position are shifted.
1121 *
1122 * @param str String to remove from.
1123 * @param pos Character index to remove.
1124 *
1125 * @return True if the removal was sucessful, false if the position
1126 * is out of bounds.
1127 *
1128 */
1129bool wstr_remove(wchar_t *str, size_t pos)
1130{
1131 size_t len = wstr_length(str);
1132
1133 if (pos >= len)
1134 return false;
1135
1136 size_t i;
1137 for (i = pos + 1; i <= len; i++)
1138 str[i - 1] = str[i];
1139
1140 return true;
1141}
1142
1143int stricmp(const char *a, const char *b)
1144{
1145 int c = 0;
1146
1147 while (a[c] && b[c] && (!(tolower(a[c]) - tolower(b[c]))))
1148 c++;
1149
1150 return (tolower(a[c]) - tolower(b[c]));
1151}
1152
1153/** Convert string to a number.
1154 * Core of strtol and strtoul functions.
1155 *
1156 * @param nptr Pointer to string.
1157 * @param endptr If not NULL, function stores here pointer to the first
1158 * invalid character.
1159 * @param base Zero or number between 2 and 36 inclusive.
1160 * @param sgn It's set to 1 if minus found.
1161 * @return Result of conversion.
1162 */
1163static unsigned long
1164_strtoul(const char *nptr, char **endptr, int base, char *sgn)
1165{
1166 unsigned char c;
1167 unsigned long result = 0;
1168 unsigned long a, b;
1169 const char *str = nptr;
1170 const char *tmpptr;
1171
1172 while (isspace(*str))
1173 str++;
1174
1175 if (*str == '-') {
1176 *sgn = 1;
1177 ++str;
1178 } else if (*str == '+')
1179 ++str;
1180
1181 if (base) {
1182 if ((base == 1) || (base > 36)) {
1183 /* FIXME: set errno to EINVAL */
1184 return 0;
1185 }
1186 if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
1187 (str[1] == 'X'))) {
1188 str += 2;
1189 }
1190 } else {
1191 base = 10;
1192
1193 if (*str == '0') {
1194 base = 8;
1195 if ((str[1] == 'X') || (str[1] == 'x')) {
1196 base = 16;
1197 str += 2;
1198 }
1199 }
1200 }
1201
1202 tmpptr = str;
1203
1204 while (*str) {
1205 c = *str;
1206 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
1207 (c <= '9' ? c - '0' : 0xff)));
1208 if (c >= base) {
1209 break;
1210 }
1211
1212 a = (result & 0xff) * base + c;
1213 b = (result >> 8) * base + (a >> 8);
1214
1215 if (b > (ULONG_MAX >> 8)) {
1216 /* overflow */
1217 /* FIXME: errno = ERANGE*/
1218 return ULONG_MAX;
1219 }
1220
1221 result = (b << 8) + (a & 0xff);
1222 ++str;
1223 }
1224
1225 if (str == tmpptr) {
1226 /*
1227 * No number was found => first invalid character is the first
1228 * character of the string.
1229 */
1230 /* FIXME: set errno to EINVAL */
1231 str = nptr;
1232 result = 0;
1233 }
1234
1235 if (endptr)
1236 *endptr = (char *) str;
1237
1238 if (nptr == str) {
1239 /*FIXME: errno = EINVAL*/
1240 return 0;
1241 }
1242
1243 return result;
1244}
1245
1246/** Convert initial part of string to long int according to given base.
1247 * The number may begin with an arbitrary number of whitespaces followed by
1248 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
1249 * inserted and the number will be taken as hexadecimal one. If the base is 0
1250 * and the number begin with a zero, number will be taken as octal one (as with
1251 * base 8). Otherwise the base 0 is taken as decimal.
1252 *
1253 * @param nptr Pointer to string.
1254 * @param endptr If not NULL, function stores here pointer to the first
1255 * invalid character.
1256 * @param base Zero or number between 2 and 36 inclusive.
1257 * @return Result of conversion.
1258 */
1259long int strtol(const char *nptr, char **endptr, int base)
1260{
1261 char sgn = 0;
1262 unsigned long number = 0;
1263
1264 number = _strtoul(nptr, endptr, base, &sgn);
1265
1266 if (number > LONG_MAX) {
1267 if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
1268 /* FIXME: set 0 to errno */
1269 return number;
1270 }
1271 /* FIXME: set ERANGE to errno */
1272 return (sgn ? LONG_MIN : LONG_MAX);
1273 }
1274
1275 return (sgn ? -number : number);
1276}
1277
1278/** Duplicate string.
1279 *
1280 * Allocate a new string and copy characters from the source
1281 * string into it. The duplicate string is allocated via sleeping
1282 * malloc(), thus this function can sleep in no memory conditions.
1283 *
1284 * The allocation cannot fail and the return value is always
1285 * a valid pointer. The duplicate string is always a well-formed
1286 * null-terminated UTF-8 string, but it can differ from the source
1287 * string on the byte level.
1288 *
1289 * @param src Source string.
1290 *
1291 * @return Duplicate string.
1292 *
1293 */
1294char *str_dup(const char *src)
1295{
1296 size_t size = str_size(src) + 1;
1297 char *dest = (char *) malloc(size);
1298 if (dest == NULL)
1299 return (char *) NULL;
1300
1301 str_cpy(dest, size, src);
1302 return dest;
1303}
1304
1305/** Duplicate string with size limit.
1306 *
1307 * Allocate a new string and copy up to @max_size bytes from the source
1308 * string into it. The duplicate string is allocated via sleeping
1309 * malloc(), thus this function can sleep in no memory conditions.
1310 * No more than @max_size + 1 bytes is allocated, but if the size
1311 * occupied by the source string is smaller than @max_size + 1,
1312 * less is allocated.
1313 *
1314 * The allocation cannot fail and the return value is always
1315 * a valid pointer. The duplicate string is always a well-formed
1316 * null-terminated UTF-8 string, but it can differ from the source
1317 * string on the byte level.
1318 *
1319 * @param src Source string.
1320 * @param n Maximum number of bytes to duplicate.
1321 *
1322 * @return Duplicate string.
1323 *
1324 */
1325char *str_ndup(const char *src, size_t n)
1326{
1327 size_t size = str_size(src);
1328 if (size > n)
1329 size = n;
1330
1331 char *dest = (char *) malloc(size + 1);
1332 if (dest == NULL)
1333 return (char *) NULL;
1334
1335 str_ncpy(dest, size + 1, src, size);
1336 return dest;
1337}
1338
1339/** Convert initial part of string to unsigned long according to given base.
1340 * The number may begin with an arbitrary number of whitespaces followed by
1341 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
1342 * inserted and the number will be taken as hexadecimal one. If the base is 0
1343 * and the number begin with a zero, number will be taken as octal one (as with
1344 * base 8). Otherwise the base 0 is taken as decimal.
1345 *
1346 * @param nptr Pointer to string.
1347 * @param endptr If not NULL, function stores here pointer to the first
1348 * invalid character
1349 * @param base Zero or number between 2 and 36 inclusive.
1350 * @return Result of conversion.
1351 */
1352unsigned long strtoul(const char *nptr, char **endptr, int base)
1353{
1354 char sgn = 0;
1355 unsigned long number = 0;
1356
1357 number = _strtoul(nptr, endptr, base, &sgn);
1358
1359 return (sgn ? -number : number);
1360}
1361
1362char *strtok(char *s, const char *delim)
1363{
1364 static char *next;
1365
1366 return strtok_r(s, delim, &next);
1367}
1368
1369char *strtok_r(char *s, const char *delim, char **next)
1370{
1371 char *start, *end;
1372
1373 if (s == NULL)
1374 s = *next;
1375
1376 /* Skip over leading delimiters. */
1377 while (*s && (str_chr(delim, *s) != NULL)) ++s;
1378 start = s;
1379
1380 /* Skip over token characters. */
1381 while (*s && (str_chr(delim, *s) == NULL)) ++s;
1382 end = s;
1383 *next = (*s ? s + 1 : s);
1384
1385 if (start == end) {
1386 return NULL; /* No more tokens. */
1387 }
1388
1389 /* Overwrite delimiter with NULL terminator. */
1390 *end = '\0';
1391 return start;
1392}
1393
1394/** Convert string to uint64_t (internal variant).
1395 *
1396 * @param nptr Pointer to string.
1397 * @param endptr Pointer to the first invalid character is stored here.
1398 * @param base Zero or number between 2 and 36 inclusive.
1399 * @param neg Indication of unary minus is stored here.
1400 * @apram result Result of the conversion.
1401 *
1402 * @return EOK if conversion was successful.
1403 *
1404 */
1405static int str_uint(const char *nptr, char **endptr, unsigned int base,
1406 bool *neg, uint64_t *result)
1407{
1408 assert(endptr != NULL);
1409 assert(neg != NULL);
1410 assert(result != NULL);
1411
1412 *neg = false;
1413 const char *str = nptr;
1414
1415 /* Ignore leading whitespace */
1416 while (isspace(*str))
1417 str++;
1418
1419 if (*str == '-') {
1420 *neg = true;
1421 str++;
1422 } else if (*str == '+')
1423 str++;
1424
1425 if (base == 0) {
1426 /* Decode base if not specified */
1427 base = 10;
1428
1429 if (*str == '0') {
1430 base = 8;
1431 str++;
1432
1433 switch (*str) {
1434 case 'b':
1435 case 'B':
1436 base = 2;
1437 str++;
1438 break;
1439 case 'o':
1440 case 'O':
1441 base = 8;
1442 str++;
1443 break;
1444 case 'd':
1445 case 'D':
1446 case 't':
1447 case 'T':
1448 base = 10;
1449 str++;
1450 break;
1451 case 'x':
1452 case 'X':
1453 base = 16;
1454 str++;
1455 break;
1456 default:
1457 str--;
1458 }
1459 }
1460 } else {
1461 /* Check base range */
1462 if ((base < 2) || (base > 36)) {
1463 *endptr = (char *) str;
1464 return EINVAL;
1465 }
1466 }
1467
1468 *result = 0;
1469 const char *startstr = str;
1470
1471 while (*str != 0) {
1472 unsigned int digit;
1473
1474 if ((*str >= 'a') && (*str <= 'z'))
1475 digit = *str - 'a' + 10;
1476 else if ((*str >= 'A') && (*str <= 'Z'))
1477 digit = *str - 'A' + 10;
1478 else if ((*str >= '0') && (*str <= '9'))
1479 digit = *str - '0';
1480 else
1481 break;
1482
1483 if (digit >= base)
1484 break;
1485
1486 uint64_t prev = *result;
1487 *result = (*result) * base + digit;
1488
1489 if (*result < prev) {
1490 /* Overflow */
1491 *endptr = (char *) str;
1492 return EOVERFLOW;
1493 }
1494
1495 str++;
1496 }
1497
1498 if (str == startstr) {
1499 /*
1500 * No digits were decoded => first invalid character is
1501 * the first character of the string.
1502 */
1503 str = nptr;
1504 }
1505
1506 *endptr = (char *) str;
1507
1508 if (str == nptr)
1509 return EINVAL;
1510
1511 return EOK;
1512}
1513
1514/** Convert string to uint8_t.
1515 *
1516 * @param nptr Pointer to string.
1517 * @param endptr If not NULL, pointer to the first invalid character
1518 * is stored here.
1519 * @param base Zero or number between 2 and 36 inclusive.
1520 * @param strict Do not allow any trailing characters.
1521 * @param result Result of the conversion.
1522 *
1523 * @return EOK if conversion was successful.
1524 *
1525 */
1526int str_uint8_t(const char *nptr, char **endptr, unsigned int base,
1527 bool strict, uint8_t *result)
1528{
1529 assert(result != NULL);
1530
1531 bool neg;
1532 char *lendptr;
1533 uint64_t res;
1534 int ret = str_uint(nptr, &lendptr, base, &neg, &res);
1535
1536 if (endptr != NULL)
1537 *endptr = (char *) lendptr;
1538
1539 if (ret != EOK)
1540 return ret;
1541
1542 /* Do not allow negative values */
1543 if (neg)
1544 return EINVAL;
1545
1546 /* Check whether we are at the end of
1547 the string in strict mode */
1548 if ((strict) && (*lendptr != 0))
1549 return EINVAL;
1550
1551 /* Check for overflow */
1552 uint8_t _res = (uint8_t) res;
1553 if (_res != res)
1554 return EOVERFLOW;
1555
1556 *result = _res;
1557
1558 return EOK;
1559}
1560
1561/** Convert string to uint16_t.
1562 *
1563 * @param nptr Pointer to string.
1564 * @param endptr If not NULL, pointer to the first invalid character
1565 * is stored here.
1566 * @param base Zero or number between 2 and 36 inclusive.
1567 * @param strict Do not allow any trailing characters.
1568 * @param result Result of the conversion.
1569 *
1570 * @return EOK if conversion was successful.
1571 *
1572 */
1573int str_uint16_t(const char *nptr, char **endptr, unsigned int base,
1574 bool strict, uint16_t *result)
1575{
1576 assert(result != NULL);
1577
1578 bool neg;
1579 char *lendptr;
1580 uint64_t res;
1581 int ret = str_uint(nptr, &lendptr, base, &neg, &res);
1582
1583 if (endptr != NULL)
1584 *endptr = (char *) lendptr;
1585
1586 if (ret != EOK)
1587 return ret;
1588
1589 /* Do not allow negative values */
1590 if (neg)
1591 return EINVAL;
1592
1593 /* Check whether we are at the end of
1594 the string in strict mode */
1595 if ((strict) && (*lendptr != 0))
1596 return EINVAL;
1597
1598 /* Check for overflow */
1599 uint16_t _res = (uint16_t) res;
1600 if (_res != res)
1601 return EOVERFLOW;
1602
1603 *result = _res;
1604
1605 return EOK;
1606}
1607
1608/** Convert string to uint32_t.
1609 *
1610 * @param nptr Pointer to string.
1611 * @param endptr If not NULL, pointer to the first invalid character
1612 * is stored here.
1613 * @param base Zero or number between 2 and 36 inclusive.
1614 * @param strict Do not allow any trailing characters.
1615 * @param result Result of the conversion.
1616 *
1617 * @return EOK if conversion was successful.
1618 *
1619 */
1620int str_uint32_t(const char *nptr, char **endptr, unsigned int base,
1621 bool strict, uint32_t *result)
1622{
1623 assert(result != NULL);
1624
1625 bool neg;
1626 char *lendptr;
1627 uint64_t res;
1628 int ret = str_uint(nptr, &lendptr, base, &neg, &res);
1629
1630 if (endptr != NULL)
1631 *endptr = (char *) lendptr;
1632
1633 if (ret != EOK)
1634 return ret;
1635
1636 /* Do not allow negative values */
1637 if (neg)
1638 return EINVAL;
1639
1640 /* Check whether we are at the end of
1641 the string in strict mode */
1642 if ((strict) && (*lendptr != 0))
1643 return EINVAL;
1644
1645 /* Check for overflow */
1646 uint32_t _res = (uint32_t) res;
1647 if (_res != res)
1648 return EOVERFLOW;
1649
1650 *result = _res;
1651
1652 return EOK;
1653}
1654
1655/** Convert string to uint64_t.
1656 *
1657 * @param nptr Pointer to string.
1658 * @param endptr If not NULL, pointer to the first invalid character
1659 * is stored here.
1660 * @param base Zero or number between 2 and 36 inclusive.
1661 * @param strict Do not allow any trailing characters.
1662 * @param result Result of the conversion.
1663 *
1664 * @return EOK if conversion was successful.
1665 *
1666 */
1667int str_uint64_t(const char *nptr, char **endptr, unsigned int base,
1668 bool strict, uint64_t *result)
1669{
1670 assert(result != NULL);
1671
1672 bool neg;
1673 char *lendptr;
1674 int ret = str_uint(nptr, &lendptr, base, &neg, result);
1675
1676 if (endptr != NULL)
1677 *endptr = (char *) lendptr;
1678
1679 if (ret != EOK)
1680 return ret;
1681
1682 /* Do not allow negative values */
1683 if (neg)
1684 return EINVAL;
1685
1686 /* Check whether we are at the end of
1687 the string in strict mode */
1688 if ((strict) && (*lendptr != 0))
1689 return EINVAL;
1690
1691 return EOK;
1692}
1693
1694/** Convert string to size_t.
1695 *
1696 * @param nptr Pointer to string.
1697 * @param endptr If not NULL, pointer to the first invalid character
1698 * is stored here.
1699 * @param base Zero or number between 2 and 36 inclusive.
1700 * @param strict Do not allow any trailing characters.
1701 * @param result Result of the conversion.
1702 *
1703 * @return EOK if conversion was successful.
1704 *
1705 */
1706int str_size_t(const char *nptr, char **endptr, unsigned int base,
1707 bool strict, size_t *result)
1708{
1709 assert(result != NULL);
1710
1711 bool neg;
1712 char *lendptr;
1713 uint64_t res;
1714 int ret = str_uint(nptr, &lendptr, base, &neg, &res);
1715
1716 if (endptr != NULL)
1717 *endptr = (char *) lendptr;
1718
1719 if (ret != EOK)
1720 return ret;
1721
1722 /* Do not allow negative values */
1723 if (neg)
1724 return EINVAL;
1725
1726 /* Check whether we are at the end of
1727 the string in strict mode */
1728 if ((strict) && (*lendptr != 0))
1729 return EINVAL;
1730
1731 /* Check for overflow */
1732 size_t _res = (size_t) res;
1733 if (_res != res)
1734 return EOVERFLOW;
1735
1736 *result = _res;
1737
1738 return EOK;
1739}
1740
1741void order_suffix(const uint64_t val, uint64_t *rv, char *suffix)
1742{
1743 if (val > UINT64_C(10000000000000000000)) {
1744 *rv = val / UINT64_C(1000000000000000000);
1745 *suffix = 'Z';
1746 } else if (val > UINT64_C(1000000000000000000)) {
1747 *rv = val / UINT64_C(1000000000000000);
1748 *suffix = 'E';
1749 } else if (val > UINT64_C(1000000000000000)) {
1750 *rv = val / UINT64_C(1000000000000);
1751 *suffix = 'T';
1752 } else if (val > UINT64_C(1000000000000)) {
1753 *rv = val / UINT64_C(1000000000);
1754 *suffix = 'G';
1755 } else if (val > UINT64_C(1000000000)) {
1756 *rv = val / UINT64_C(1000000);
1757 *suffix = 'M';
1758 } else if (val > UINT64_C(1000000)) {
1759 *rv = val / UINT64_C(1000);
1760 *suffix = 'k';
1761 } else {
1762 *rv = val;
1763 *suffix = ' ';
1764 }
1765}
1766
1767void bin_order_suffix(const uint64_t val, uint64_t *rv, const char **suffix,
1768 bool fixed)
1769{
1770 if (val > UINT64_C(1152921504606846976)) {
1771 *rv = val / UINT64_C(1125899906842624);
1772 *suffix = "EiB";
1773 } else if (val > UINT64_C(1125899906842624)) {
1774 *rv = val / UINT64_C(1099511627776);
1775 *suffix = "TiB";
1776 } else if (val > UINT64_C(1099511627776)) {
1777 *rv = val / UINT64_C(1073741824);
1778 *suffix = "GiB";
1779 } else if (val > UINT64_C(1073741824)) {
1780 *rv = val / UINT64_C(1048576);
1781 *suffix = "MiB";
1782 } else if (val > UINT64_C(1048576)) {
1783 *rv = val / UINT64_C(1024);
1784 *suffix = "KiB";
1785 } else {
1786 *rv = val;
1787 if (fixed)
1788 *suffix = "B ";
1789 else
1790 *suffix = "B";
1791 }
1792}
1793
1794/** @}
1795 */
Note: See TracBrowser for help on using the repository browser.