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

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

Add functions chr_width() and str_width() to determine character and string display width on a character cell display.

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