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

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

Add a function to check if a string has a given prefix.

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