source: mainline/uspace/lib/c/generic/str.c@ 69cf3a4

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

Update documentation for str_cmp and str_lcmp.

This is a modified version of formulation suggested by Jiri Zarevucky.

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