source: mainline/uspace/lib/libc/generic/string.c@ 0f06dbc

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

Rename wstr_nstr() to wstr_to_str() and align it better with the rest of string functions.

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