source: mainline/uspace/lib/libc/generic/string.c@ 3cc6a52

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3cc6a52 was 6eb2e96, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

str_cpy() and str_ncpy() in userspace. Nuke strcpy() and strncpy().

  • Property mode set to 100644
File size: 20.3 KB
RevLine 
[936351c1]1/*
[df4ed85]2 * Copyright (c) 2005 Martin Decky
[576845ec]3 * Copyright (c) 2008 Jiri Svoboda
[936351c1]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[a46da63]30/** @addtogroup libc
[b2951e2]31 * @{
32 */
33/** @file
34 */
35
[936351c1]36#include <string.h>
[e64c4b2]37#include <stdlib.h>
[672a24d]38#include <limits.h>
[e64c4b2]39#include <ctype.h>
[566987b0]40#include <malloc.h>
[171f9a1]41#include <errno.h>
[f2b8cdc]42#include <align.h>
[095003a8]43#include <mem.h>
[171f9a1]44#include <string.h>
45
46/** Byte mask consisting of lowest @n bits (out of 8) */
47#define LO_MASK_8(n) ((uint8_t) ((1 << (n)) - 1))
48
49/** Byte mask consisting of lowest @n bits (out of 32) */
50#define LO_MASK_32(n) ((uint32_t) ((1 << (n)) - 1))
51
52/** Byte mask consisting of highest @n bits (out of 8) */
53#define HI_MASK_8(n) (~LO_MASK_8(8 - (n)))
54
55/** Number of data bits in a UTF-8 continuation byte */
56#define CONT_BITS 6
57
58/** Decode a single character from a string.
59 *
60 * Decode a single character from a string of size @a size. Decoding starts
61 * at @a offset and this offset is moved to the beginning of the next
62 * character. In case of decoding error, offset generally advances at least
63 * by one. However, offset is never moved beyond size.
64 *
65 * @param str String (not necessarily NULL-terminated).
66 * @param offset Byte offset in string where to start decoding.
67 * @param size Size of the string (in bytes).
68 *
69 * @return Value of decoded character, U_SPECIAL on decoding error or
70 * NULL if attempt to decode beyond @a size.
71 *
72 */
73wchar_t str_decode(const char *str, size_t *offset, size_t size)
74{
75 if (*offset + 1 > size)
76 return 0;
77
78 /* First byte read from string */
79 uint8_t b0 = (uint8_t) str[(*offset)++];
80
81 /* Determine code length */
82
83 unsigned int b0_bits; /* Data bits in first byte */
84 unsigned int cbytes; /* Number of continuation bytes */
85
86 if ((b0 & 0x80) == 0) {
87 /* 0xxxxxxx (Plain ASCII) */
88 b0_bits = 7;
89 cbytes = 0;
90 } else if ((b0 & 0xe0) == 0xc0) {
91 /* 110xxxxx 10xxxxxx */
92 b0_bits = 5;
93 cbytes = 1;
94 } else if ((b0 & 0xf0) == 0xe0) {
95 /* 1110xxxx 10xxxxxx 10xxxxxx */
96 b0_bits = 4;
97 cbytes = 2;
98 } else if ((b0 & 0xf8) == 0xf0) {
99 /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
100 b0_bits = 3;
101 cbytes = 3;
102 } else {
103 /* 10xxxxxx -- unexpected continuation byte */
104 return U_SPECIAL;
105 }
106
107 if (*offset + cbytes > size)
108 return U_SPECIAL;
109
110 wchar_t ch = b0 & LO_MASK_8(b0_bits);
111
112 /* Decode continuation bytes */
113 while (cbytes > 0) {
114 uint8_t b = (uint8_t) str[(*offset)++];
115
116 /* Must be 10xxxxxx */
117 if ((b & 0xc0) != 0x80)
118 return U_SPECIAL;
119
120 /* Shift data bits to ch */
121 ch = (ch << CONT_BITS) | (wchar_t) (b & LO_MASK_8(CONT_BITS));
122 cbytes--;
123 }
124
125 return ch;
126}
127
128/** Encode a single character to string representation.
129 *
130 * Encode a single character to string representation (i.e. UTF-8) and store
131 * it into a buffer at @a offset. Encoding starts at @a offset and this offset
132 * is moved to the position where the next character can be written to.
133 *
134 * @param ch Input character.
135 * @param str Output buffer.
136 * @param offset Byte offset where to start writing.
137 * @param size Size of the output buffer (in bytes).
138 *
139 * @return EOK if the character was encoded successfully, EOVERFLOW if there
140 * was not enough space in the output buffer or EINVAL if the character
141 * code was invalid.
142 */
143int chr_encode(const wchar_t ch, char *str, size_t *offset, size_t size)
144{
145 if (*offset >= size)
146 return EOVERFLOW;
147
148 if (!chr_check(ch))
149 return EINVAL;
150
151 /* Unsigned version of ch (bit operations should only be done
152 on unsigned types). */
153 uint32_t cc = (uint32_t) ch;
154
155 /* Determine how many continuation bytes are needed */
156
157 unsigned int b0_bits; /* Data bits in first byte */
158 unsigned int cbytes; /* Number of continuation bytes */
159
160 if ((cc & ~LO_MASK_32(7)) == 0) {
161 b0_bits = 7;
162 cbytes = 0;
163 } else if ((cc & ~LO_MASK_32(11)) == 0) {
164 b0_bits = 5;
165 cbytes = 1;
166 } else if ((cc & ~LO_MASK_32(16)) == 0) {
167 b0_bits = 4;
168 cbytes = 2;
169 } else if ((cc & ~LO_MASK_32(21)) == 0) {
170 b0_bits = 3;
171 cbytes = 3;
172 } else {
173 /* Codes longer than 21 bits are not supported */
174 return EINVAL;
175 }
176
177 /* Check for available space in buffer */
178 if (*offset + cbytes >= size)
179 return EOVERFLOW;
180
181 /* Encode continuation bytes */
182 unsigned int i;
183 for (i = cbytes; i > 0; i--) {
184 str[*offset + i] = 0x80 | (cc & LO_MASK_32(CONT_BITS));
185 cc = cc >> CONT_BITS;
186 }
187
188 /* Encode first byte */
189 str[*offset] = (cc & LO_MASK_32(b0_bits)) | HI_MASK_8(8 - b0_bits - 1);
190
191 /* Advance offset */
192 *offset += cbytes + 1;
193
194 return EOK;
195}
196
[f2b8cdc]197/** Get size of string.
198 *
199 * Get the number of bytes which are used by the string @a str (excluding the
200 * NULL-terminator).
201 *
202 * @param str String to consider.
203 *
204 * @return Number of bytes used by the string
205 *
206 */
207size_t str_size(const char *str)
208{
209 size_t size = 0;
210
211 while (*str++ != 0)
212 size++;
213
214 return size;
215}
216
217/** Get size of wide string.
218 *
219 * Get the number of bytes which are used by the wide string @a str (excluding the
220 * NULL-terminator).
221 *
222 * @param str Wide string to consider.
223 *
224 * @return Number of bytes used by the wide string
225 *
226 */
227size_t wstr_size(const wchar_t *str)
228{
229 return (wstr_length(str) * sizeof(wchar_t));
230}
231
232/** Get size of string with length limit.
233 *
234 * Get the number of bytes which are used by up to @a max_len first
235 * characters in the string @a str. If @a max_len is greater than
236 * the length of @a str, the entire string is measured (excluding the
237 * NULL-terminator).
238 *
239 * @param str String to consider.
240 * @param max_len Maximum number of characters to measure.
241 *
242 * @return Number of bytes used by the characters.
243 *
244 */
245size_t str_lsize(const char *str, count_t max_len)
246{
247 count_t len = 0;
248 size_t offset = 0;
249
250 while (len < max_len) {
251 if (str_decode(str, &offset, STR_NO_LIMIT) == 0)
252 break;
253
254 len++;
255 }
256
257 return offset;
258}
259
260/** Get size of wide string with length limit.
261 *
262 * Get the number of bytes which are used by up to @a max_len first
263 * wide characters in the wide string @a str. If @a max_len is greater than
264 * the length of @a str, the entire wide string is measured (excluding the
265 * NULL-terminator).
266 *
267 * @param str Wide string to consider.
268 * @param max_len Maximum number of wide characters to measure.
269 *
270 * @return Number of bytes used by the wide characters.
271 *
272 */
273size_t wstr_lsize(const wchar_t *str, count_t max_len)
274{
275 return (wstr_nlength(str, max_len * sizeof(wchar_t)) * sizeof(wchar_t));
276}
277
278/** Get number of characters in a string.
279 *
280 * @param str NULL-terminated string.
281 *
282 * @return Number of characters in string.
283 *
284 */
285count_t str_length(const char *str)
286{
287 count_t len = 0;
288 size_t offset = 0;
289
290 while (str_decode(str, &offset, STR_NO_LIMIT) != 0)
291 len++;
292
293 return len;
294}
295
296/** Get number of characters in a wide string.
297 *
298 * @param str NULL-terminated wide string.
299 *
300 * @return Number of characters in @a str.
301 *
302 */
303count_t wstr_length(const wchar_t *wstr)
304{
305 count_t len = 0;
306
307 while (*wstr++ != 0)
308 len++;
309
310 return len;
311}
312
313/** Get number of characters in a string with size limit.
314 *
315 * @param str NULL-terminated string.
316 * @param size Maximum number of bytes to consider.
317 *
318 * @return Number of characters in string.
319 *
320 */
321count_t str_nlength(const char *str, size_t size)
322{
323 count_t len = 0;
324 size_t offset = 0;
325
326 while (str_decode(str, &offset, size) != 0)
327 len++;
328
329 return len;
330}
331
332/** Get number of characters in a string with size limit.
333 *
334 * @param str NULL-terminated string.
335 * @param size Maximum number of bytes to consider.
336 *
337 * @return Number of characters in string.
338 *
339 */
340count_t wstr_nlength(const wchar_t *str, size_t size)
341{
342 count_t len = 0;
343 count_t limit = ALIGN_DOWN(size, sizeof(wchar_t));
344 count_t offset = 0;
345
346 while ((offset < limit) && (*str++ != 0)) {
347 len++;
348 offset += sizeof(wchar_t);
349 }
350
351 return len;
352}
353
354/** Check whether character is plain ASCII.
355 *
356 * @return True if character is plain ASCII.
357 *
358 */
359bool ascii_check(wchar_t ch)
360{
361 if ((ch >= 0) && (ch <= 127))
362 return true;
363
364 return false;
365}
366
[171f9a1]367/** Check whether character is valid
368 *
369 * @return True if character is a valid Unicode code point.
370 *
371 */
[f2b8cdc]372bool chr_check(wchar_t ch)
[171f9a1]373{
374 if ((ch >= 0) && (ch <= 1114111))
375 return true;
376
377 return false;
378}
[936351c1]379
[f2b8cdc]380/** Compare two NULL terminated strings.
381 *
382 * Do a char-by-char comparison of two NULL-terminated strings.
383 * The strings are considered equal iff they consist of the same
384 * characters on the minimum of their lengths.
385 *
386 * @param s1 First string to compare.
387 * @param s2 Second string to compare.
388 *
389 * @return 0 if the strings are equal, -1 if first is smaller,
390 * 1 if second smaller.
391 *
392 */
393int str_cmp(const char *s1, const char *s2)
394{
395 wchar_t c1 = 0;
396 wchar_t c2 = 0;
397
398 size_t off1 = 0;
399 size_t off2 = 0;
400
401 while (true) {
402 c1 = str_decode(s1, &off1, STR_NO_LIMIT);
403 c2 = str_decode(s2, &off2, STR_NO_LIMIT);
404
405 if (c1 < c2)
406 return -1;
407
408 if (c1 > c2)
409 return 1;
410
411 if (c1 == 0 || c2 == 0)
412 break;
413 }
414
415 return 0;
416}
417
418/** Compare two NULL terminated strings with length limit.
419 *
420 * Do a char-by-char comparison of two NULL-terminated strings.
421 * The strings are considered equal iff they consist of the same
422 * characters on the minimum of their lengths and the length limit.
423 *
424 * @param s1 First string to compare.
425 * @param s2 Second string to compare.
426 * @param max_len Maximum number of characters to consider.
427 *
428 * @return 0 if the strings are equal, -1 if first is smaller,
429 * 1 if second smaller.
430 *
431 */
432int str_lcmp(const char *s1, const char *s2, count_t max_len)
433{
434 wchar_t c1 = 0;
435 wchar_t c2 = 0;
436
437 size_t off1 = 0;
438 size_t off2 = 0;
439
440 count_t len = 0;
441
442 while (true) {
443 if (len >= max_len)
444 break;
445
446 c1 = str_decode(s1, &off1, STR_NO_LIMIT);
447 c2 = str_decode(s2, &off2, STR_NO_LIMIT);
448
449 if (c1 < c2)
450 return -1;
451
452 if (c1 > c2)
453 return 1;
454
455 if (c1 == 0 || c2 == 0)
456 break;
457
458 ++len;
459 }
460
461 return 0;
462
463}
464
[6eb2e96]465/** Copy string.
[f2b8cdc]466 *
[6eb2e96]467 * Copy source string @a src to destination buffer @a dest.
468 * No more than @a size bytes are written. If the size of the output buffer
469 * is at least one byte, the output string will always be well-formed, i.e.
470 * null-terminated and containing only complete characters.
[f2b8cdc]471 *
472 * @param dst Destination buffer.
473 * @param count Size of the destination buffer.
[6eb2e96]474 * @param src Source string.
[f2b8cdc]475 */
[6eb2e96]476void str_cpy(char *dest, size_t size, const char *src)
[f2b8cdc]477{
[6eb2e96]478 wchar_t ch;
479 size_t src_off;
480 size_t dest_off;
481
482 /* No space for the NULL-terminator in the buffer. */
[f2b8cdc]483 if (size == 0)
484 return;
485
[6eb2e96]486 src_off = 0;
487 dest_off = 0;
488
489 while ((ch = str_decode(src, &src_off, STR_NO_LIMIT)) != 0) {
490 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
491 break;
492 }
493
494 dest[dest_off] = '\0';
495}
496
497/** Copy size-limited substring.
498 *
499 * Copy source string @a src to destination buffer @a dest.
500 * No more than @a size bytes are written. If the size of the output buffer
501 * is at least one byte, the output string will always be well-formed, i.e.
502 * null-terminated and containing only complete characters.
503 *
504 * No more than @a n bytes are read from the input string, so it does not
505 * have to be null-terminated.
506 *
507 * @param dst Destination buffer.
508 * @param count Size of the destination buffer.
509 * @param src Source string.
510 */
511void str_ncpy(char *dest, size_t size, const char *src, size_t n)
512{
[f2b8cdc]513 wchar_t ch;
[6eb2e96]514 size_t src_off;
515 size_t dest_off;
516
517 /* No space for the null terminator in the buffer. */
518 if (size == 0)
519 return;
[f2b8cdc]520
[6eb2e96]521 src_off = 0;
522 dest_off = 0;
523
524 while ((ch = str_decode(src, &src_off, n)) != 0) {
525 if (chr_encode(ch, dest, &dest_off, size - 1) != EOK)
[f2b8cdc]526 break;
527 }
[6eb2e96]528
529 dest[dest_off] = '\0';
[f2b8cdc]530}
531
532/** Copy NULL-terminated wide string to string
533 *
534 * Copy source wide string @a src to destination buffer @a dst.
535 * No more than @a size bytes are written. NULL-terminator is always
536 * written after the last succesfully copied character (i.e. if the
537 * destination buffer is has at least 1 byte, it will be always
538 * NULL-terminated).
539 *
540 * @param src Source wide string.
541 * @param dst Destination buffer.
542 * @param count Size of the destination buffer.
543 *
544 */
545void wstr_nstr(char *dst, const wchar_t *src, size_t size)
546{
547 /* No space for the NULL-terminator in the buffer */
548 if (size == 0)
549 return;
550
551 wchar_t ch;
552 count_t src_idx = 0;
553 size_t dst_off = 0;
554
555 while ((ch = src[src_idx++]) != 0) {
556 if (chr_encode(ch, dst, &dst_off, size) != EOK)
557 break;
558 }
559
560 if (dst_off >= size)
561 dst[size - 1] = 0;
562 else
563 dst[dst_off] = 0;
564}
565
566/** Find first occurence of character in string.
567 *
568 * @param str String to search.
569 * @param ch Character to look for.
570 *
571 * @return Pointer to character in @a str or NULL if not found.
572 */
573const char *str_chr(const char *str, wchar_t ch)
574{
575 wchar_t acc;
576 size_t off = 0;
577
578 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
579 if (acc == ch)
580 return (str + off);
581 }
582
583 return NULL;
584}
585
[7afb4a5]586/** Find last occurence of character in string.
587 *
588 * @param str String to search.
589 * @param ch Character to look for.
590 *
591 * @return Pointer to character in @a str or NULL if not found.
592 */
593const char *str_rchr(const char *str, wchar_t ch)
594{
595 wchar_t acc;
596 size_t off = 0;
597 char *res;
598
599 res = NULL;
600 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
601 if (acc == ch)
602 res = (str + off);
603 }
604
605 return res;
606}
607
[f2b8cdc]608/** Insert a wide character into a wide string.
609 *
610 * Insert a wide character into a wide string at position
611 * @a pos. The characters after the position are shifted.
612 *
613 * @param str String to insert to.
614 * @param ch Character to insert to.
615 * @param pos Character index where to insert.
616 @ @param max_pos Characters in the buffer.
617 *
618 * @return True if the insertion was sucessful, false if the position
619 * is out of bounds.
620 *
621 */
622bool wstr_linsert(wchar_t *str, wchar_t ch, count_t pos, count_t max_pos)
623{
624 count_t len = wstr_length(str);
625
626 if ((pos > len) || (pos + 1 > max_pos))
627 return false;
628
629 count_t i;
630 for (i = len; i + 1 > pos; i--)
631 str[i + 1] = str[i];
632
633 str[pos] = ch;
634
635 return true;
636}
637
638/** Remove a wide character from a wide string.
639 *
640 * Remove a wide character from a wide string at position
641 * @a pos. The characters after the position are shifted.
642 *
643 * @param str String to remove from.
644 * @param pos Character index to remove.
645 *
646 * @return True if the removal was sucessful, false if the position
647 * is out of bounds.
648 *
649 */
650bool wstr_remove(wchar_t *str, count_t pos)
651{
652 count_t len = wstr_length(str);
653
654 if (pos >= len)
655 return false;
656
657 count_t i;
658 for (i = pos + 1; i <= len; i++)
659 str[i - 1] = str[i];
660
661 return true;
662}
663
[5832e9b]664int strncmp(const char *a, const char *b, size_t n)
665{
666 size_t c = 0;
667
668 while (c < n && a[c] && b[c] && (!(a[c] - b[c])))
669 c++;
670
671 return ( c < n ? a[c] - b[c] : 0);
672
673}
[c0535f80]674
[2dd7288]675int stricmp(const char *a, const char *b)
676{
677 int c = 0;
678
679 while (a[c] && b[c] && (!(tolower(a[c]) - tolower(b[c]))))
680 c++;
681
682 return (tolower(a[c]) - tolower(b[c]));
683}
684
[672a24d]685/** Convert string to a number.
686 * Core of strtol and strtoul functions.
[838e14e2]687 *
688 * @param nptr Pointer to string.
689 * @param endptr If not NULL, function stores here pointer to the first
690 * invalid character.
691 * @param base Zero or number between 2 and 36 inclusive.
692 * @param sgn It's set to 1 if minus found.
693 * @return Result of conversion.
[672a24d]694 */
[838e14e2]695static unsigned long
696_strtoul(const char *nptr, char **endptr, int base, char *sgn)
[672a24d]697{
698 unsigned char c;
699 unsigned long result = 0;
700 unsigned long a, b;
701 const char *str = nptr;
702 const char *tmpptr;
703
704 while (isspace(*str))
705 str++;
706
707 if (*str == '-') {
708 *sgn = 1;
709 ++str;
710 } else if (*str == '+')
711 ++str;
712
713 if (base) {
714 if ((base == 1) || (base > 36)) {
715 /* FIXME: set errno to EINVAL */
716 return 0;
717 }
[838e14e2]718 if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
719 (str[1] == 'X'))) {
[672a24d]720 str += 2;
721 }
722 } else {
723 base = 10;
724
725 if (*str == '0') {
726 base = 8;
727 if ((str[1] == 'X') || (str[1] == 'x')) {
728 base = 16;
729 str += 2;
730 }
731 }
732 }
733
734 tmpptr = str;
735
736 while (*str) {
737 c = *str;
[838e14e2]738 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
739 (c <= '9' ? c - '0' : 0xff)));
[672a24d]740 if (c > base) {
741 break;
742 }
743
744 a = (result & 0xff) * base + c;
745 b = (result >> 8) * base + (a >> 8);
746
747 if (b > (ULONG_MAX >> 8)) {
748 /* overflow */
749 /* FIXME: errno = ERANGE*/
750 return ULONG_MAX;
751 }
752
753 result = (b << 8) + (a & 0xff);
754 ++str;
755 }
756
757 if (str == tmpptr) {
[838e14e2]758 /*
759 * No number was found => first invalid character is the first
760 * character of the string.
761 */
[672a24d]762 /* FIXME: set errno to EINVAL */
763 str = nptr;
764 result = 0;
765 }
766
767 if (endptr)
[a46da63]768 *endptr = (char *) str;
[672a24d]769
770 if (nptr == str) {
771 /*FIXME: errno = EINVAL*/
772 return 0;
773 }
774
775 return result;
776}
777
778/** Convert initial part of string to long int according to given base.
[838e14e2]779 * The number may begin with an arbitrary number of whitespaces followed by
780 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
781 * inserted and the number will be taken as hexadecimal one. If the base is 0
782 * and the number begin with a zero, number will be taken as octal one (as with
783 * base 8). Otherwise the base 0 is taken as decimal.
784 *
785 * @param nptr Pointer to string.
786 * @param endptr If not NULL, function stores here pointer to the first
787 * invalid character.
788 * @param base Zero or number between 2 and 36 inclusive.
789 * @return Result of conversion.
[672a24d]790 */
791long int strtol(const char *nptr, char **endptr, int base)
792{
793 char sgn = 0;
794 unsigned long number = 0;
795
796 number = _strtoul(nptr, endptr, base, &sgn);
797
798 if (number > LONG_MAX) {
[a46da63]799 if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
[672a24d]800 /* FIXME: set 0 to errno */
801 return number;
802 }
803 /* FIXME: set ERANGE to errno */
[a46da63]804 return (sgn ? LONG_MIN : LONG_MAX);
[672a24d]805 }
806
[a46da63]807 return (sgn ? -number : number);
[672a24d]808}
809
810
811/** Convert initial part of string to unsigned long according to given base.
[838e14e2]812 * The number may begin with an arbitrary number of whitespaces followed by
813 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
814 * inserted and the number will be taken as hexadecimal one. If the base is 0
815 * and the number begin with a zero, number will be taken as octal one (as with
816 * base 8). Otherwise the base 0 is taken as decimal.
817 *
818 * @param nptr Pointer to string.
819 * @param endptr If not NULL, function stores here pointer to the first
820 * invalid character
821 * @param base Zero or number between 2 and 36 inclusive.
822 * @return Result of conversion.
[672a24d]823 */
824unsigned long strtoul(const char *nptr, char **endptr, int base)
825{
826 char sgn = 0;
827 unsigned long number = 0;
828
829 number = _strtoul(nptr, endptr, base, &sgn);
830
[a46da63]831 return (sgn ? -number : number);
[672a24d]832}
[c594489]833
[1526594c]834char *strcat(char *dest, const char *src)
835{
836 char *orig = dest;
837 while (*dest++)
838 ;
839 --dest;
840 while ((*dest++ = *src++))
841 ;
[a46da63]842 return orig;
[c594489]843}
[b2951e2]844
[095003a8]845char *str_dup(const char *src)
[566987b0]846{
[095003a8]847 size_t size = str_size(src);
848 void *dest = malloc(size + 1);
[566987b0]849
[095003a8]850 if (dest == NULL)
[566987b0]851 return (char *) NULL;
852
[095003a8]853 return (char *) memcpy(dest, src, size + 1);
[566987b0]854}
855
[576845ec]856char *strtok(char *s, const char *delim)
[69df837f]857{
[576845ec]858 static char *next;
[69df837f]859
[576845ec]860 return strtok_r(s, delim, &next);
861}
[69df837f]862
[576845ec]863char *strtok_r(char *s, const char *delim, char **next)
864{
865 char *start, *end;
[69df837f]866
[576845ec]867 if (s == NULL)
868 s = *next;
[69df837f]869
[576845ec]870 /* Skip over leading delimiters. */
[7afb4a5]871 while (*s && (str_chr(delim, *s) != NULL)) ++s;
[576845ec]872 start = s;
[69df837f]873
[576845ec]874 /* Skip over token characters. */
[7afb4a5]875 while (*s && (str_chr(delim, *s) == NULL)) ++s;
[576845ec]876 end = s;
877 *next = (*s ? s + 1 : s);
878
879 if (start == end) {
880 return NULL; /* No more tokens. */
881 }
[69df837f]882
[576845ec]883 /* Overwrite delimiter with NULL terminator. */
884 *end = '\0';
885 return start;
[69df837f]886}
887
[a46da63]888/** @}
[b2951e2]889 */
Note: See TracBrowser for help on using the repository browser.