source: mainline/uspace/lib/c/generic/str.c@ 4efeab5

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

Update documentation for str_cmp and str_lcmp

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