source: mainline/kernel/generic/src/lib/str.c@ bf2042f9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bf2042f9 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 24.1 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup generic
30 * @{
31 */
32
33/**
34 * @file
35 * @brief String functions.
36 *
37 * Strings and characters use the Universal Character Set (UCS). The standard
38 * strings, called just strings are encoded in UTF-8. Wide strings (encoded
39 * in UTF-32) are supported to a limited degree. A single character is
40 * represented as wchar_t.@n
41 *
42 * Overview of the terminology:@n
43 *
44 * Term Meaning
45 * -------------------- ----------------------------------------------------
46 * byte 8 bits stored in uint8_t (unsigned 8 bit integer)
47 *
48 * character UTF-32 encoded Unicode character, stored in wchar_t
49 * (signed 32 bit integer), code points 0 .. 1114111
50 * are valid
51 *
52 * ASCII character 7 bit encoded ASCII character, stored in char
53 * (usually signed 8 bit integer), code points 0 .. 127
54 * are valid
55 *
56 * string UTF-8 encoded NULL-terminated Unicode string, char *
57 *
58 * wide string UTF-32 encoded NULL-terminated Unicode string,
59 * wchar_t *
60 *
61 * [wide] string size number of BYTES in a [wide] string (excluding
62 * the NULL-terminator), size_t
63 *
64 * [wide] string length number of CHARACTERS in a [wide] string (excluding
65 * the NULL-terminator), size_t
66 *
67 * [wide] string width number of display cells on a monospace display taken
68 * by a [wide] string, size_t
69 *
70 *
71 * Overview of string metrics:@n
72 *
73 * Metric Abbrev. Type Meaning
74 * ------ ------ ------ -------------------------------------------------
75 * size n size_t number of BYTES in a string (excluding the
76 * NULL-terminator)
77 *
78 * length l size_t number of CHARACTERS in a string (excluding the
79 * null terminator)
80 *
81 * width w size_t number of display cells on a monospace display
82 * taken by a string
83 *
84 *
85 * Function naming prefixes:@n
86 *
87 * chr_ operate on characters
88 * ascii_ operate on ASCII characters
89 * str_ operate on strings
90 * wstr_ operate on wide strings
91 *
92 * [w]str_[n|l|w] operate on a prefix limited by size, length
93 * or width
94 *
95 *
96 * A specific character inside a [wide] string can be referred to by:@n
97 *
98 * pointer (char *, wchar_t *)
99 * byte offset (size_t)
100 * character index (size_t)
101 *
102 */
103
104#include <str.h>
105#include <print.h>
106#include <cpu.h>
107#include <arch/asm.h>
108#include <arch.h>
109#include <errno.h>
110#include <align.h>
111#include <assert.h>
112#include <macros.h>
113#include <mm/slab.h>
114
115/** Check the condition if wchar_t is signed */
116#ifdef __WCHAR_UNSIGNED__
117 #define WCHAR_SIGNED_CHECK(cond) (true)
118#else
119 #define WCHAR_SIGNED_CHECK(cond) (cond)
120#endif
121
122/** Byte mask consisting of lowest @n bits (out of 8) */
123#define LO_MASK_8(n) ((uint8_t) ((1 << (n)) - 1))
124
125/** Byte mask consisting of lowest @n bits (out of 32) */
126#define LO_MASK_32(n) ((uint32_t) ((1 << (n)) - 1))
127
128/** Byte mask consisting of highest @n bits (out of 8) */
129#define HI_MASK_8(n) (~LO_MASK_8(8 - (n)))
130
131/** Number of data bits in a UTF-8 continuation byte */
132#define CONT_BITS 6
133
134/** Decode a single character from a string.
135 *
136 * Decode a single character from a string of size @a size. Decoding starts
137 * at @a offset and this offset is moved to the beginning of the next
138 * character. In case of decoding error, offset generally advances at least
139 * by one. However, offset is never moved beyond size.
140 *
141 * @param str String (not necessarily NULL-terminated).
142 * @param offset Byte offset in string where to start decoding.
143 * @param size Size of the string (in bytes).
144 *
145 * @return Value of decoded character, U_SPECIAL on decoding error or
146 * NULL if attempt to decode beyond @a size.
147 *
148 */
149wchar_t str_decode(const char *str, size_t *offset, size_t size)
150{
151 if (*offset + 1 > size)
152 return 0;
153
154 /* First byte read from string */
155 uint8_t b0 = (uint8_t) str[(*offset)++];
156
157 /* Determine code length */
158
159 unsigned int b0_bits; /* Data bits in first byte */
160 unsigned int cbytes; /* Number of continuation bytes */
161
162 if ((b0 & 0x80) == 0) {
163 /* 0xxxxxxx (Plain ASCII) */
164 b0_bits = 7;
165 cbytes = 0;
166 } else if ((b0 & 0xe0) == 0xc0) {
167 /* 110xxxxx 10xxxxxx */
168 b0_bits = 5;
169 cbytes = 1;
170 } else if ((b0 & 0xf0) == 0xe0) {
171 /* 1110xxxx 10xxxxxx 10xxxxxx */
172 b0_bits = 4;
173 cbytes = 2;
174 } else if ((b0 & 0xf8) == 0xf0) {
175 /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
176 b0_bits = 3;
177 cbytes = 3;
178 } else {
179 /* 10xxxxxx -- unexpected continuation byte */
180 return U_SPECIAL;
181 }
182
183 if (*offset + cbytes > size)
184 return U_SPECIAL;
185
186 wchar_t ch = b0 & LO_MASK_8(b0_bits);
187
188 /* Decode continuation bytes */
189 while (cbytes > 0) {
190 uint8_t b = (uint8_t) str[(*offset)++];
191
192 /* Must be 10xxxxxx */
193 if ((b & 0xc0) != 0x80)
194 return U_SPECIAL;
195
196 /* Shift data bits to ch */
197 ch = (ch << CONT_BITS) | (wchar_t) (b & LO_MASK_8(CONT_BITS));
198 cbytes--;
199 }
200
201 return ch;
202}
203
204/** Encode a single character to string representation.
205 *
206 * Encode a single character to string representation (i.e. UTF-8) and store
207 * it into a buffer at @a offset. Encoding starts at @a offset and this offset
208 * is moved to the position where the next character can be written to.
209 *
210 * @param ch Input character.
211 * @param str Output buffer.
212 * @param offset Byte offset where to start writing.
213 * @param size Size of the output buffer (in bytes).
214 *
215 * @return EOK if the character was encoded successfully, EOVERFLOW if there
216 * was not enough space in the output buffer or EINVAL if the character
217 * code was invalid.
218 */
219errno_t chr_encode(const wchar_t ch, char *str, size_t *offset, size_t size)
220{
221 if (*offset >= size)
222 return EOVERFLOW;
223
224 if (!chr_check(ch))
225 return EINVAL;
226
227 /* Unsigned version of ch (bit operations should only be done
228 on unsigned types). */
229 uint32_t cc = (uint32_t) ch;
230
231 /* Determine how many continuation bytes are needed */
232
233 unsigned int b0_bits; /* Data bits in first byte */
234 unsigned int cbytes; /* Number of continuation bytes */
235
236 if ((cc & ~LO_MASK_32(7)) == 0) {
237 b0_bits = 7;
238 cbytes = 0;
239 } else if ((cc & ~LO_MASK_32(11)) == 0) {
240 b0_bits = 5;
241 cbytes = 1;
242 } else if ((cc & ~LO_MASK_32(16)) == 0) {
243 b0_bits = 4;
244 cbytes = 2;
245 } else if ((cc & ~LO_MASK_32(21)) == 0) {
246 b0_bits = 3;
247 cbytes = 3;
248 } else {
249 /* Codes longer than 21 bits are not supported */
250 return EINVAL;
251 }
252
253 /* Check for available space in buffer */
254 if (*offset + cbytes >= size)
255 return EOVERFLOW;
256
257 /* Encode continuation bytes */
258 unsigned int i;
259 for (i = cbytes; i > 0; i--) {
260 str[*offset + i] = 0x80 | (cc & LO_MASK_32(CONT_BITS));
261 cc = cc >> CONT_BITS;
262 }
263
264 /* Encode first byte */
265 str[*offset] = (cc & LO_MASK_32(b0_bits)) | HI_MASK_8(8 - b0_bits - 1);
266
267 /* Advance offset */
268 *offset += cbytes + 1;
269
270 return EOK;
271}
272
273/** Get size of string.
274 *
275 * Get the number of bytes which are used by the string @a str (excluding the
276 * NULL-terminator).
277 *
278 * @param str String to consider.
279 *
280 * @return Number of bytes used by the string
281 *
282 */
283size_t str_size(const char *str)
284{
285 size_t size = 0;
286
287 while (*str++ != 0)
288 size++;
289
290 return size;
291}
292
293/** Get size of wide string.
294 *
295 * Get the number of bytes which are used by the wide string @a str (excluding the
296 * NULL-terminator).
297 *
298 * @param str Wide string to consider.
299 *
300 * @return Number of bytes used by the wide string
301 *
302 */
303size_t wstr_size(const wchar_t *str)
304{
305 return (wstr_length(str) * sizeof(wchar_t));
306}
307
308/** Get size of string with length limit.
309 *
310 * Get the number of bytes which are used by up to @a max_len first
311 * characters in the string @a str. If @a max_len is greater than
312 * the length of @a str, the entire string is measured (excluding the
313 * NULL-terminator).
314 *
315 * @param str String to consider.
316 * @param max_len Maximum number of characters to measure.
317 *
318 * @return Number of bytes used by the characters.
319 *
320 */
321size_t str_lsize(const char *str, size_t max_len)
322{
323 size_t len = 0;
324 size_t offset = 0;
325
326 while (len < max_len) {
327 if (str_decode(str, &offset, STR_NO_LIMIT) == 0)
328 break;
329
330 len++;
331 }
332
333 return offset;
334}
335
336/** Get size of wide string with length limit.
337 *
338 * Get the number of bytes which are used by up to @a max_len first
339 * wide characters in the wide string @a str. If @a max_len is greater than
340 * the length of @a str, the entire wide string is measured (excluding the
341 * NULL-terminator).
342 *
343 * @param str Wide string to consider.
344 * @param max_len Maximum number of wide characters to measure.
345 *
346 * @return Number of bytes used by the wide characters.
347 *
348 */
349size_t wstr_lsize(const wchar_t *str, size_t max_len)
350{
351 return (wstr_nlength(str, max_len * sizeof(wchar_t)) * sizeof(wchar_t));
352}
353
354/** Get number of characters in a string.
355 *
356 * @param str NULL-terminated string.
357 *
358 * @return Number of characters in string.
359 *
360 */
361size_t str_length(const char *str)
362{
363 size_t len = 0;
364 size_t offset = 0;
365
366 while (str_decode(str, &offset, STR_NO_LIMIT) != 0)
367 len++;
368
369 return len;
370}
371
372/** Get number of characters in a wide string.
373 *
374 * @param str NULL-terminated wide string.
375 *
376 * @return Number of characters in @a str.
377 *
378 */
379size_t wstr_length(const wchar_t *wstr)
380{
381 size_t len = 0;
382
383 while (*wstr++ != 0)
384 len++;
385
386 return len;
387}
388
389/** Get number of characters in a string with size limit.
390 *
391 * @param str NULL-terminated string.
392 * @param size Maximum number of bytes to consider.
393 *
394 * @return Number of characters in string.
395 *
396 */
397size_t str_nlength(const char *str, size_t size)
398{
399 size_t len = 0;
400 size_t offset = 0;
401
402 while (str_decode(str, &offset, size) != 0)
403 len++;
404
405 return len;
406}
407
408/** Get number of characters in a string with size limit.
409 *
410 * @param str NULL-terminated string.
411 * @param size Maximum number of bytes to consider.
412 *
413 * @return Number of characters in string.
414 *
415 */
416size_t wstr_nlength(const wchar_t *str, size_t size)
417{
418 size_t len = 0;
419 size_t limit = ALIGN_DOWN(size, sizeof(wchar_t));
420 size_t offset = 0;
421
422 while ((offset < limit) && (*str++ != 0)) {
423 len++;
424 offset += sizeof(wchar_t);
425 }
426
427 return len;
428}
429
430/** Check whether character is plain ASCII.
431 *
432 * @return True if character is plain ASCII.
433 *
434 */
435bool ascii_check(wchar_t ch)
436{
437 if (WCHAR_SIGNED_CHECK(ch >= 0) && (ch <= 127))
438 return true;
439
440 return false;
441}
442
443/** Check whether character is valid
444 *
445 * @return True if character is a valid Unicode code point.
446 *
447 */
448bool chr_check(wchar_t ch)
449{
450 if (WCHAR_SIGNED_CHECK(ch >= 0) && (ch <= 1114111))
451 return true;
452
453 return false;
454}
455
456/** Compare two NULL terminated strings.
457 *
458 * Do a char-by-char comparison of two NULL-terminated strings.
459 * The strings are considered equal iff their length is equal
460 * and both strings consist of the same sequence of characters.
461 *
462 * A string S1 is less than another string S2 if it has a character with
463 * lower value at the first character position where the strings differ.
464 * If the strings differ in length, the shorter one is treated as if
465 * padded by characters with a value of zero.
466 *
467 * @param s1 First string to compare.
468 * @param s2 Second string to compare.
469 *
470 * @return 0 if the strings are equal, -1 if the first is less than the second,
471 * 1 if the second is less than the first.
472 *
473 */
474int str_cmp(const char *s1, const char *s2)
475{
476 wchar_t c1 = 0;
477 wchar_t c2 = 0;
478
479 size_t off1 = 0;
480 size_t off2 = 0;
481
482 while (true) {
483 c1 = str_decode(s1, &off1, STR_NO_LIMIT);
484 c2 = str_decode(s2, &off2, STR_NO_LIMIT);
485
486 if (c1 < c2)
487 return -1;
488
489 if (c1 > c2)
490 return 1;
491
492 if (c1 == 0 || c2 == 0)
493 break;
494 }
495
496 return 0;
497}
498
499/** Compare two NULL terminated strings with length limit.
500 *
501 * Do a char-by-char comparison of two NULL-terminated strings.
502 * The strings are considered equal iff
503 * min(str_length(s1), max_len) == min(str_length(s2), max_len)
504 * and both strings consist of the same sequence of characters,
505 * up to max_len characters.
506 *
507 * A string S1 is less than another string S2 if it has a character with
508 * lower value at the first character position where the strings differ.
509 * If the strings differ in length, the shorter one is treated as if
510 * padded by characters with a value of zero. Only the first max_len
511 * characters are considered.
512 *
513 * @param s1 First string to compare.
514 * @param s2 Second string to compare.
515 * @param max_len Maximum number of characters to consider.
516 *
517 * @return 0 if the strings are equal, -1 if the first is less than the second,
518 * 1 if the second is less than the first.
519 *
520 */
521int str_lcmp(const char *s1, const char *s2, size_t max_len)
522{
523 wchar_t c1 = 0;
524 wchar_t c2 = 0;
525
526 size_t off1 = 0;
527 size_t off2 = 0;
528
529 size_t len = 0;
530
531 while (true) {
532 if (len >= max_len)
533 break;
534
535 c1 = str_decode(s1, &off1, STR_NO_LIMIT);
536 c2 = str_decode(s2, &off2, STR_NO_LIMIT);
537
538 if (c1 < c2)
539 return -1;
540
541 if (c1 > c2)
542 return 1;
543
544 if (c1 == 0 || c2 == 0)
545 break;
546
547 ++len;
548 }
549
550 return 0;
551
552}
553
554/** Copy string.
555 *
556 * Copy source string @a src to destination buffer @a dest.
557 * No more than @a size bytes are written. If the size of the output buffer
558 * is at least one byte, the output string will always be well-formed, i.e.
559 * null-terminated and containing only complete characters.
560 *
561 * @param dest Destination buffer.
562 * @param count Size of the destination buffer (must be > 0).
563 * @param src Source string.
564 *
565 */
566void str_cpy(char *dest, size_t size, const char *src)
567{
568 /* There must be space for a null terminator in the buffer. */
569 assert(size > 0);
570 assert(src != NULL);
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, STR_NO_LIMIT)) != 0) {
577 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
578 break;
579 }
580
581 dest[dest_off] = '\0';
582}
583
584/** Copy size-limited substring.
585 *
586 * Copy prefix of string @a src of max. size @a size to destination buffer
587 * @a dest. No more than @a size bytes are written. The output string will
588 * always be well-formed, i.e. null-terminated and containing only complete
589 * characters.
590 *
591 * No more than @a n bytes are read from the input string, so it does not
592 * have to be null-terminated.
593 *
594 * @param dest Destination buffer.
595 * @param count Size of the destination buffer (must be > 0).
596 * @param src Source string.
597 * @param n Maximum number of bytes to read from @a src.
598 *
599 */
600void str_ncpy(char *dest, size_t size, const char *src, size_t n)
601{
602 /* There must be space for a null terminator in the buffer. */
603 assert(size > 0);
604
605 size_t src_off = 0;
606 size_t dest_off = 0;
607
608 wchar_t ch;
609 while ((ch = str_decode(src, &src_off, n)) != 0) {
610 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
611 break;
612 }
613
614 dest[dest_off] = '\0';
615}
616
617/** Duplicate string.
618 *
619 * Allocate a new string and copy characters from the source
620 * string into it. The duplicate string is allocated via sleeping
621 * malloc(), thus this function can sleep in no memory conditions.
622 *
623 * The allocation cannot fail and the return value is always
624 * a valid pointer. The duplicate string is always a well-formed
625 * null-terminated UTF-8 string, but it can differ from the source
626 * string on the byte level.
627 *
628 * @param src Source string.
629 *
630 * @return Duplicate string.
631 *
632 */
633char *str_dup(const char *src)
634{
635 size_t size = str_size(src) + 1;
636 char *dest = malloc(size, 0);
637 assert(dest);
638
639 str_cpy(dest, size, src);
640 return dest;
641}
642
643/** Duplicate string with size limit.
644 *
645 * Allocate a new string and copy up to @max_size bytes from the source
646 * string into it. The duplicate string is allocated via sleeping
647 * malloc(), thus this function can sleep in no memory conditions.
648 * No more than @max_size + 1 bytes is allocated, but if the size
649 * occupied by the source string is smaller than @max_size + 1,
650 * less is allocated.
651 *
652 * The allocation cannot fail and the return value is always
653 * a valid pointer. The duplicate string is always a well-formed
654 * null-terminated UTF-8 string, but it can differ from the source
655 * string on the byte level.
656 *
657 * @param src Source string.
658 * @param n Maximum number of bytes to duplicate.
659 *
660 * @return Duplicate string.
661 *
662 */
663char *str_ndup(const char *src, size_t n)
664{
665 size_t size = str_size(src);
666 if (size > n)
667 size = n;
668
669 char *dest = malloc(size + 1, 0);
670 assert(dest);
671
672 str_ncpy(dest, size + 1, src, size);
673 return dest;
674}
675
676/** Convert wide string to string.
677 *
678 * Convert wide string @a src to string. The output is written to the buffer
679 * specified by @a dest and @a size. @a size must be non-zero and the string
680 * written will always be well-formed.
681 *
682 * @param dest Destination buffer.
683 * @param size Size of the destination buffer.
684 * @param src Source wide string.
685 */
686void wstr_to_str(char *dest, size_t size, const wchar_t *src)
687{
688 wchar_t ch;
689 size_t src_idx;
690 size_t dest_off;
691
692 /* There must be space for a null terminator in the buffer. */
693 assert(size > 0);
694
695 src_idx = 0;
696 dest_off = 0;
697
698 while ((ch = src[src_idx++]) != 0) {
699 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
700 break;
701 }
702
703 dest[dest_off] = '\0';
704}
705
706/** Find first occurence of character in string.
707 *
708 * @param str String to search.
709 * @param ch Character to look for.
710 *
711 * @return Pointer to character in @a str or NULL if not found.
712 *
713 */
714char *str_chr(const char *str, wchar_t ch)
715{
716 wchar_t acc;
717 size_t off = 0;
718 size_t last = 0;
719
720 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
721 if (acc == ch)
722 return (char *) (str + last);
723 last = off;
724 }
725
726 return NULL;
727}
728
729/** Insert a wide character into a wide string.
730 *
731 * Insert a wide character into a wide string at position
732 * @a pos. The characters after the position are shifted.
733 *
734 * @param str String to insert to.
735 * @param ch Character to insert to.
736 * @param pos Character index where to insert.
737 @ @param max_pos Characters in the buffer.
738 *
739 * @return True if the insertion was sucessful, false if the position
740 * is out of bounds.
741 *
742 */
743bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos)
744{
745 size_t len = wstr_length(str);
746
747 if ((pos > len) || (pos + 1 > max_pos))
748 return false;
749
750 size_t i;
751 for (i = len; i + 1 > pos; i--)
752 str[i + 1] = str[i];
753
754 str[pos] = ch;
755
756 return true;
757}
758
759/** Remove a wide character from a wide string.
760 *
761 * Remove a wide character from a wide string at position
762 * @a pos. The characters after the position are shifted.
763 *
764 * @param str String to remove from.
765 * @param pos Character index to remove.
766 *
767 * @return True if the removal was sucessful, false if the position
768 * is out of bounds.
769 *
770 */
771bool wstr_remove(wchar_t *str, size_t pos)
772{
773 size_t len = wstr_length(str);
774
775 if (pos >= len)
776 return false;
777
778 size_t i;
779 for (i = pos + 1; i <= len; i++)
780 str[i - 1] = str[i];
781
782 return true;
783}
784
785/** Convert string to uint64_t (internal variant).
786 *
787 * @param nptr Pointer to string.
788 * @param endptr Pointer to the first invalid character is stored here.
789 * @param base Zero or number between 2 and 36 inclusive.
790 * @param neg Indication of unary minus is stored here.
791 * @apram result Result of the conversion.
792 *
793 * @return EOK if conversion was successful.
794 *
795 */
796static errno_t str_uint(const char *nptr, char **endptr, unsigned int base,
797 bool *neg, uint64_t *result)
798{
799 assert(endptr != NULL);
800 assert(neg != NULL);
801 assert(result != NULL);
802
803 *neg = false;
804 const char *str = nptr;
805
806 /* Ignore leading whitespace */
807 while (isspace(*str))
808 str++;
809
810 if (*str == '-') {
811 *neg = true;
812 str++;
813 } else if (*str == '+')
814 str++;
815
816 if (base == 0) {
817 /* Decode base if not specified */
818 base = 10;
819
820 if (*str == '0') {
821 base = 8;
822 str++;
823
824 switch (*str) {
825 case 'b':
826 case 'B':
827 base = 2;
828 str++;
829 break;
830 case 'o':
831 case 'O':
832 base = 8;
833 str++;
834 break;
835 case 'd':
836 case 'D':
837 case 't':
838 case 'T':
839 base = 10;
840 str++;
841 break;
842 case 'x':
843 case 'X':
844 base = 16;
845 str++;
846 break;
847 default:
848 str--;
849 }
850 }
851 } else {
852 /* Check base range */
853 if ((base < 2) || (base > 36)) {
854 *endptr = (char *) str;
855 return EINVAL;
856 }
857 }
858
859 *result = 0;
860 const char *startstr = str;
861
862 while (*str != 0) {
863 unsigned int digit;
864
865 if ((*str >= 'a') && (*str <= 'z'))
866 digit = *str - 'a' + 10;
867 else if ((*str >= 'A') && (*str <= 'Z'))
868 digit = *str - 'A' + 10;
869 else if ((*str >= '0') && (*str <= '9'))
870 digit = *str - '0';
871 else
872 break;
873
874 if (digit >= base)
875 break;
876
877 uint64_t prev = *result;
878 *result = (*result) * base + digit;
879
880 if (*result < prev) {
881 /* Overflow */
882 *endptr = (char *) str;
883 return EOVERFLOW;
884 }
885
886 str++;
887 }
888
889 if (str == startstr) {
890 /*
891 * No digits were decoded => first invalid character is
892 * the first character of the string.
893 */
894 str = nptr;
895 }
896
897 *endptr = (char *) str;
898
899 if (str == nptr)
900 return EINVAL;
901
902 return EOK;
903}
904
905/** Convert string to uint64_t.
906 *
907 * @param nptr Pointer to string.
908 * @param endptr If not NULL, pointer to the first invalid character
909 * is stored here.
910 * @param base Zero or number between 2 and 36 inclusive.
911 * @param strict Do not allow any trailing characters.
912 * @param result Result of the conversion.
913 *
914 * @return EOK if conversion was successful.
915 *
916 */
917errno_t str_uint64_t(const char *nptr, char **endptr, unsigned int base,
918 bool strict, uint64_t *result)
919{
920 assert(result != NULL);
921
922 bool neg;
923 char *lendptr;
924 errno_t ret = str_uint(nptr, &lendptr, base, &neg, result);
925
926 if (endptr != NULL)
927 *endptr = (char *) lendptr;
928
929 if (ret != EOK)
930 return ret;
931
932 /* Do not allow negative values */
933 if (neg)
934 return EINVAL;
935
936 /* Check whether we are at the end of
937 the string in strict mode */
938 if ((strict) && (*lendptr != 0))
939 return EINVAL;
940
941 return EOK;
942}
943
944void order_suffix(const uint64_t val, uint64_t *rv, char *suffix)
945{
946 if (val > UINT64_C(10000000000000000000)) {
947 *rv = val / UINT64_C(1000000000000000000);
948 *suffix = 'Z';
949 } else if (val > UINT64_C(1000000000000000000)) {
950 *rv = val / UINT64_C(1000000000000000);
951 *suffix = 'E';
952 } else if (val > UINT64_C(1000000000000000)) {
953 *rv = val / UINT64_C(1000000000000);
954 *suffix = 'T';
955 } else if (val > UINT64_C(1000000000000)) {
956 *rv = val / UINT64_C(1000000000);
957 *suffix = 'G';
958 } else if (val > UINT64_C(1000000000)) {
959 *rv = val / UINT64_C(1000000);
960 *suffix = 'M';
961 } else if (val > UINT64_C(1000000)) {
962 *rv = val / UINT64_C(1000);
963 *suffix = 'k';
964 } else {
965 *rv = val;
966 *suffix = ' ';
967 }
968}
969
970void bin_order_suffix(const uint64_t val, uint64_t *rv, const char **suffix,
971 bool fixed)
972{
973 if (val > UINT64_C(1152921504606846976)) {
974 *rv = val / UINT64_C(1125899906842624);
975 *suffix = "EiB";
976 } else if (val > UINT64_C(1125899906842624)) {
977 *rv = val / UINT64_C(1099511627776);
978 *suffix = "TiB";
979 } else if (val > UINT64_C(1099511627776)) {
980 *rv = val / UINT64_C(1073741824);
981 *suffix = "GiB";
982 } else if (val > UINT64_C(1073741824)) {
983 *rv = val / UINT64_C(1048576);
984 *suffix = "MiB";
985 } else if (val > UINT64_C(1048576)) {
986 *rv = val / UINT64_C(1024);
987 *suffix = "KiB";
988 } else {
989 *rv = val;
990 if (fixed)
991 *suffix = "B ";
992 else
993 *suffix = "B";
994 }
995}
996
997/** @}
998 */
Note: See TracBrowser for help on using the repository browser.