source: mainline/uspace/lib/libc/generic/string.c@ 095003a8

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

strdup() → str_dup()

  • Property mode set to 100644
File size: 19.6 KB
Line 
1/*
2 * Copyright (c) 2005 Martin Decky
3 * Copyright (c) 2008 Jiri Svoboda
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
30/** @addtogroup libc
31 * @{
32 */
33/** @file
34 */
35
36#include <string.h>
37#include <stdlib.h>
38#include <limits.h>
39#include <ctype.h>
40#include <malloc.h>
41#include <errno.h>
42#include <align.h>
43#include <mem.h>
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
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
367/** Check whether character is valid
368 *
369 * @return True if character is a valid Unicode code point.
370 *
371 */
372bool chr_check(wchar_t ch)
373{
374 if ((ch >= 0) && (ch <= 1114111))
375 return true;
376
377 return false;
378}
379
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
465/** Copy NULL-terminated string.
466 *
467 * Copy source string @a src to destination buffer @a dst.
468 * No more than @a size bytes are written. NULL-terminator is always
469 * written after the last succesfully copied character (i.e. if the
470 * destination buffer is has at least 1 byte, it will be always
471 * NULL-terminated).
472 *
473 * @param src Source string.
474 * @param dst Destination buffer.
475 * @param count Size of the destination buffer.
476 *
477 */
478void str_ncpy(char *dst, const char *src, size_t size)
479{
480 /* No space for the NULL-terminator in the buffer */
481 if (size == 0)
482 return;
483
484 wchar_t ch;
485 size_t str_off = 0;
486 size_t dst_off = 0;
487
488 while ((ch = str_decode(src, &str_off, STR_NO_LIMIT)) != 0) {
489 if (chr_encode(ch, dst, &dst_off, size) != EOK)
490 break;
491 }
492
493 if (dst_off >= size)
494 dst[size - 1] = 0;
495 else
496 dst[dst_off] = 0;
497}
498
499/** Copy NULL-terminated wide string to string
500 *
501 * Copy source wide string @a src to destination buffer @a dst.
502 * No more than @a size bytes are written. NULL-terminator is always
503 * written after the last succesfully copied character (i.e. if the
504 * destination buffer is has at least 1 byte, it will be always
505 * NULL-terminated).
506 *
507 * @param src Source wide string.
508 * @param dst Destination buffer.
509 * @param count Size of the destination buffer.
510 *
511 */
512void wstr_nstr(char *dst, const wchar_t *src, size_t size)
513{
514 /* No space for the NULL-terminator in the buffer */
515 if (size == 0)
516 return;
517
518 wchar_t ch;
519 count_t src_idx = 0;
520 size_t dst_off = 0;
521
522 while ((ch = src[src_idx++]) != 0) {
523 if (chr_encode(ch, dst, &dst_off, size) != EOK)
524 break;
525 }
526
527 if (dst_off >= size)
528 dst[size - 1] = 0;
529 else
530 dst[dst_off] = 0;
531}
532
533/** Find first occurence of character in string.
534 *
535 * @param str String to search.
536 * @param ch Character to look for.
537 *
538 * @return Pointer to character in @a str or NULL if not found.
539 */
540const char *str_chr(const char *str, wchar_t ch)
541{
542 wchar_t acc;
543 size_t off = 0;
544
545 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
546 if (acc == ch)
547 return (str + off);
548 }
549
550 return NULL;
551}
552
553/** Find last occurence of character in string.
554 *
555 * @param str String to search.
556 * @param ch Character to look for.
557 *
558 * @return Pointer to character in @a str or NULL if not found.
559 */
560const char *str_rchr(const char *str, wchar_t ch)
561{
562 wchar_t acc;
563 size_t off = 0;
564 char *res;
565
566 res = NULL;
567 while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
568 if (acc == ch)
569 res = (str + off);
570 }
571
572 return res;
573}
574
575/** Insert a wide character into a wide string.
576 *
577 * Insert a wide character into a wide string at position
578 * @a pos. The characters after the position are shifted.
579 *
580 * @param str String to insert to.
581 * @param ch Character to insert to.
582 * @param pos Character index where to insert.
583 @ @param max_pos Characters in the buffer.
584 *
585 * @return True if the insertion was sucessful, false if the position
586 * is out of bounds.
587 *
588 */
589bool wstr_linsert(wchar_t *str, wchar_t ch, count_t pos, count_t max_pos)
590{
591 count_t len = wstr_length(str);
592
593 if ((pos > len) || (pos + 1 > max_pos))
594 return false;
595
596 count_t i;
597 for (i = len; i + 1 > pos; i--)
598 str[i + 1] = str[i];
599
600 str[pos] = ch;
601
602 return true;
603}
604
605/** Remove a wide character from a wide string.
606 *
607 * Remove a wide character from a wide string at position
608 * @a pos. The characters after the position are shifted.
609 *
610 * @param str String to remove from.
611 * @param pos Character index to remove.
612 *
613 * @return True if the removal was sucessful, false if the position
614 * is out of bounds.
615 *
616 */
617bool wstr_remove(wchar_t *str, count_t pos)
618{
619 count_t len = wstr_length(str);
620
621 if (pos >= len)
622 return false;
623
624 count_t i;
625 for (i = pos + 1; i <= len; i++)
626 str[i - 1] = str[i];
627
628 return true;
629}
630
631int strncmp(const char *a, const char *b, size_t n)
632{
633 size_t c = 0;
634
635 while (c < n && a[c] && b[c] && (!(a[c] - b[c])))
636 c++;
637
638 return ( c < n ? a[c] - b[c] : 0);
639
640}
641
642int stricmp(const char *a, const char *b)
643{
644 int c = 0;
645
646 while (a[c] && b[c] && (!(tolower(a[c]) - tolower(b[c]))))
647 c++;
648
649 return (tolower(a[c]) - tolower(b[c]));
650}
651
652/** Convert string to a number.
653 * Core of strtol and strtoul functions.
654 *
655 * @param nptr Pointer to string.
656 * @param endptr If not NULL, function stores here pointer to the first
657 * invalid character.
658 * @param base Zero or number between 2 and 36 inclusive.
659 * @param sgn It's set to 1 if minus found.
660 * @return Result of conversion.
661 */
662static unsigned long
663_strtoul(const char *nptr, char **endptr, int base, char *sgn)
664{
665 unsigned char c;
666 unsigned long result = 0;
667 unsigned long a, b;
668 const char *str = nptr;
669 const char *tmpptr;
670
671 while (isspace(*str))
672 str++;
673
674 if (*str == '-') {
675 *sgn = 1;
676 ++str;
677 } else if (*str == '+')
678 ++str;
679
680 if (base) {
681 if ((base == 1) || (base > 36)) {
682 /* FIXME: set errno to EINVAL */
683 return 0;
684 }
685 if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
686 (str[1] == 'X'))) {
687 str += 2;
688 }
689 } else {
690 base = 10;
691
692 if (*str == '0') {
693 base = 8;
694 if ((str[1] == 'X') || (str[1] == 'x')) {
695 base = 16;
696 str += 2;
697 }
698 }
699 }
700
701 tmpptr = str;
702
703 while (*str) {
704 c = *str;
705 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
706 (c <= '9' ? c - '0' : 0xff)));
707 if (c > base) {
708 break;
709 }
710
711 a = (result & 0xff) * base + c;
712 b = (result >> 8) * base + (a >> 8);
713
714 if (b > (ULONG_MAX >> 8)) {
715 /* overflow */
716 /* FIXME: errno = ERANGE*/
717 return ULONG_MAX;
718 }
719
720 result = (b << 8) + (a & 0xff);
721 ++str;
722 }
723
724 if (str == tmpptr) {
725 /*
726 * No number was found => first invalid character is the first
727 * character of the string.
728 */
729 /* FIXME: set errno to EINVAL */
730 str = nptr;
731 result = 0;
732 }
733
734 if (endptr)
735 *endptr = (char *) str;
736
737 if (nptr == str) {
738 /*FIXME: errno = EINVAL*/
739 return 0;
740 }
741
742 return result;
743}
744
745/** Convert initial part of string to long int according to given base.
746 * The number may begin with an arbitrary number of whitespaces followed by
747 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
748 * inserted and the number will be taken as hexadecimal one. If the base is 0
749 * and the number begin with a zero, number will be taken as octal one (as with
750 * base 8). Otherwise the base 0 is taken as decimal.
751 *
752 * @param nptr Pointer to string.
753 * @param endptr If not NULL, function stores here pointer to the first
754 * invalid character.
755 * @param base Zero or number between 2 and 36 inclusive.
756 * @return Result of conversion.
757 */
758long int strtol(const char *nptr, char **endptr, int base)
759{
760 char sgn = 0;
761 unsigned long number = 0;
762
763 number = _strtoul(nptr, endptr, base, &sgn);
764
765 if (number > LONG_MAX) {
766 if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
767 /* FIXME: set 0 to errno */
768 return number;
769 }
770 /* FIXME: set ERANGE to errno */
771 return (sgn ? LONG_MIN : LONG_MAX);
772 }
773
774 return (sgn ? -number : number);
775}
776
777
778/** Convert initial part of string to unsigned long according to given base.
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.
790 */
791unsigned long strtoul(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 return (sgn ? -number : number);
799}
800
801char *strcpy(char *dest, const char *src)
802{
803 char *orig = dest;
804
805 while ((*(dest++) = *(src++)))
806 ;
807 return orig;
808}
809
810char *strcat(char *dest, const char *src)
811{
812 char *orig = dest;
813 while (*dest++)
814 ;
815 --dest;
816 while ((*dest++ = *src++))
817 ;
818 return orig;
819}
820
821char *str_dup(const char *src)
822{
823 size_t size = str_size(src);
824 void *dest = malloc(size + 1);
825
826 if (dest == NULL)
827 return (char *) NULL;
828
829 return (char *) memcpy(dest, src, size + 1);
830}
831
832char *strtok(char *s, const char *delim)
833{
834 static char *next;
835
836 return strtok_r(s, delim, &next);
837}
838
839char *strtok_r(char *s, const char *delim, char **next)
840{
841 char *start, *end;
842
843 if (s == NULL)
844 s = *next;
845
846 /* Skip over leading delimiters. */
847 while (*s && (str_chr(delim, *s) != NULL)) ++s;
848 start = s;
849
850 /* Skip over token characters. */
851 while (*s && (str_chr(delim, *s) == NULL)) ++s;
852 end = s;
853 *next = (*s ? s + 1 : s);
854
855 if (start == end) {
856 return NULL; /* No more tokens. */
857 }
858
859 /* Overwrite delimiter with NULL terminator. */
860 *end = '\0';
861 return start;
862}
863
864/** @}
865 */
Note: See TracBrowser for help on using the repository browser.