source: mainline/uspace/lib/libc/generic/string.c@ 576845ec

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

Replace BSD strtok() and strtok_r() with our own.

  • Property mode set to 100644
File size: 11.6 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>
[672a24d]37#include <unistd.h>
38#include <ctype.h>
39#include <limits.h>
[7f079d9]40#include <align.h>
[5d4e90f0]41#include <sys/types.h>
[566987b0]42#include <malloc.h>
[936351c1]43
[6b080e54]44/** Fill memory block with a constant value. */
45void *memset(void *dest, int b, size_t n)
[936351c1]46{
[6b080e54]47 char *pb;
48 unsigned long *pw;
49 size_t word_size;
50 size_t n_words;
51
52 unsigned long pattern;
53 size_t i;
54 size_t fill;
55
56 /* Fill initial segment. */
57 word_size = sizeof(unsigned long);
58 fill = word_size - ((uintptr_t) dest & (word_size - 1));
59 if (fill > n) fill = n;
60
61 pb = dest;
62
63 i = fill;
64 while (i-- != 0)
65 *pb++ = b;
66
67 /* Compute remaining size. */
68 n -= fill;
69 if (n == 0) return dest;
70
71 n_words = n / word_size;
72 n = n % word_size;
73 pw = (unsigned long *) pb;
74
75 /* Create word-sized pattern for aligned segment. */
76 pattern = 0;
77 i = word_size;
78 while (i-- != 0)
79 pattern = (pattern << 8) | (uint8_t) b;
80
81 /* Fill aligned segment. */
82 i = n_words;
83 while (i-- != 0)
84 *pw++ = pattern;
85
86 pb = (char *) pw;
87
88 /* Fill final segment. */
89 i = n;
90 while (i-- != 0)
91 *pb++ = b;
92
93 return dest;
[936351c1]94}
95
[a46da63]96struct along {
97 unsigned long n;
98} __attribute__ ((packed));
[7f079d9]99
[a46da63]100static void *unaligned_memcpy(void *dst, const void *src, size_t n)
[7f079d9]101{
102 int i, j;
103 struct along *adst = dst;
104 const struct along *asrc = src;
105
[a46da63]106 for (i = 0; i < n / sizeof(unsigned long); i++)
[7f079d9]107 adst[i].n = asrc[i].n;
108
[a46da63]109 for (j = 0; j < n % sizeof(unsigned long); j++)
[838e14e2]110 ((unsigned char *) (((unsigned long *) dst) + i))[j] =
111 ((unsigned char *) (((unsigned long *) src) + i))[j];
[7f079d9]112
[da349da0]113 return (char *) dst;
[7f079d9]114}
115
[47acd58]116/** Copy memory block. */
[a46da63]117void *memcpy(void *dst, const void *src, size_t n)
[936351c1]118{
[47acd58]119 size_t i;
120 size_t mod, fill;
121 size_t word_size;
122 size_t n_words;
123
124 const unsigned long *srcw;
125 unsigned long *dstw;
126 const uint8_t *srcb;
127 uint8_t *dstb;
128
129 word_size = sizeof(unsigned long);
130
131 /*
132 * Are source and destination addresses congruent modulo word_size?
133 * If not, use unaligned_memcpy().
134 */
[a2ae4f4]135
[47acd58]136 if (((uintptr_t) dst & (word_size - 1)) !=
137 ((uintptr_t) src & (word_size - 1)))
[7f079d9]138 return unaligned_memcpy(dst, src, n);
139
[47acd58]140 /*
141 * mod is the address modulo word size. fill is the length of the
142 * initial buffer segment before the first word boundary.
143 * If the buffer is very short, use unaligned_memcpy(), too.
144 */
145
146 mod = (uintptr_t) dst & (word_size - 1);
147 fill = word_size - mod;
148 if (fill > n) fill = n;
149
150 /* Copy the initial segment. */
151
152 srcb = src;
153 dstb = dst;
154
155 i = fill;
[6b080e54]156 while (i-- != 0)
[47acd58]157 *dstb++ = *srcb++;
158
159 /* Compute remaining length. */
160
161 n -= fill;
162 if (n == 0) return dst;
163
164 /* Pointers to aligned segment. */
165
166 dstw = (unsigned long *) dstb;
167 srcw = (const unsigned long *) srcb;
168
169 n_words = n / word_size; /* Number of whole words to copy. */
170 n -= n_words * word_size; /* Remaining bytes at the end. */
171
172 /* "Fast" copy. */
173 i = n_words;
[6b080e54]174 while (i-- != 0)
[47acd58]175 *dstw++ = *srcw++;
176
177 /*
178 * Copy the rest.
179 */
180
181 srcb = (const uint8_t *) srcw;
182 dstb = (uint8_t *) dstw;
183
184 i = n;
[6b080e54]185 while (i-- != 0)
[47acd58]186 *dstb++ = *srcb++;
187
188 return dst;
[936351c1]189}
[c9857c6]190
[7a817d00]191/** Move memory block with possible overlapping. */
[a46da63]192void *memmove(void *dst, const void *src, size_t n)
[a2ae4f4]193{
[7a817d00]194 uint8_t *dp, *sp;
195
196 /* Nothing to do? */
197 if (src == dst)
198 return dst;
199
200 /* Non-overlapping? */
201 if (dst >= src + n || src >= dst + n) {
[a2ae4f4]202 return memcpy(dst, src, n);
[7a817d00]203 }
[a2ae4f4]204
[7a817d00]205 /* Which direction? */
206 if (src > dst) {
207 /* Forwards. */
208 sp = src;
209 dp = dst;
[a2ae4f4]210
[7a817d00]211 while (n-- != 0)
212 *dp++ = *sp++;
213 } else {
214 /* Backwards. */
215 sp = src + (n - 1);
216 dp = dst + (n - 1);
217
218 while (n-- != 0)
219 *dp-- = *sp--;
220 }
221
222 return dst;
[a2ae4f4]223}
224
[df24ec3]225/** Compare two memory areas.
226 *
[838e14e2]227 * @param s1 Pointer to the first area to compare.
228 * @param s2 Pointer to the second area to compare.
229 * @param len Size of the first area in bytes. Both areas must have
230 * the same length.
231 * @return If len is 0, return zero. If the areas match, return
232 * zero. Otherwise return non-zero.
[df24ec3]233 */
234int bcmp(const char *s1, const char *s2, size_t len)
235{
236 for (; len && *s1++ == *s2++; len--)
237 ;
238 return len;
239}
[a2ae4f4]240
[672a24d]241/** Count the number of characters in the string, not including terminating 0.
[838e14e2]242 *
243 * @param str String.
244 * @return Number of characters in string.
[672a24d]245 */
[c9857c6]246size_t strlen(const char *str)
247{
[523fad8]248 size_t counter = 0;
[c9857c6]249
[a46da63]250 while (str[counter] != 0)
[c9857c6]251 counter++;
252
253 return counter;
254}
[672a24d]255
[a46da63]256int strcmp(const char *a, const char *b)
[c0535f80]257{
[a46da63]258 int c = 0;
[c0535f80]259
[a46da63]260 while (a[c] && b[c] && (!(a[c] - b[c])))
261 c++;
[c0535f80]262
[a46da63]263 return (a[c] - b[c]);
[c0535f80]264}
265
[5832e9b]266int strncmp(const char *a, const char *b, size_t n)
267{
268 size_t c = 0;
269
270 while (c < n && a[c] && b[c] && (!(a[c] - b[c])))
271 c++;
272
273 return ( c < n ? a[c] - b[c] : 0);
274
275}
[c0535f80]276
[2dd7288]277int stricmp(const char *a, const char *b)
278{
279 int c = 0;
280
281 while (a[c] && b[c] && (!(tolower(a[c]) - tolower(b[c]))))
282 c++;
283
284 return (tolower(a[c]) - tolower(b[c]));
285}
286
[838e14e2]287/** Return pointer to the first occurence of character c in string.
288 *
289 * @param str Scanned string.
290 * @param c Searched character (taken as one byte).
291 * @return Pointer to the matched character or NULL if it is not
292 * found in given string.
[672a24d]293 */
294char *strchr(const char *str, int c)
295{
296 while (*str != '\0') {
[a46da63]297 if (*str == (char) c)
298 return (char *) str;
[672a24d]299 str++;
300 }
301
302 return NULL;
303}
304
[838e14e2]305/** Return pointer to the last occurence of character c in string.
306 *
307 * @param str Scanned string.
308 * @param c Searched character (taken as one byte).
309 * @return Pointer to the matched character or NULL if it is not
310 * found in given string.
[672a24d]311 */
312char *strrchr(const char *str, int c)
313{
314 char *retval = NULL;
315
316 while (*str != '\0') {
[a46da63]317 if (*str == (char) c)
318 retval = (char *) str;
[672a24d]319 str++;
320 }
321
[a46da63]322 return (char *) retval;
[672a24d]323}
324
325/** Convert string to a number.
326 * Core of strtol and strtoul functions.
[838e14e2]327 *
328 * @param nptr Pointer to string.
329 * @param endptr If not NULL, function stores here pointer to the first
330 * invalid character.
331 * @param base Zero or number between 2 and 36 inclusive.
332 * @param sgn It's set to 1 if minus found.
333 * @return Result of conversion.
[672a24d]334 */
[838e14e2]335static unsigned long
336_strtoul(const char *nptr, char **endptr, int base, char *sgn)
[672a24d]337{
338 unsigned char c;
339 unsigned long result = 0;
340 unsigned long a, b;
341 const char *str = nptr;
342 const char *tmpptr;
343
344 while (isspace(*str))
345 str++;
346
347 if (*str == '-') {
348 *sgn = 1;
349 ++str;
350 } else if (*str == '+')
351 ++str;
352
353 if (base) {
354 if ((base == 1) || (base > 36)) {
355 /* FIXME: set errno to EINVAL */
356 return 0;
357 }
[838e14e2]358 if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
359 (str[1] == 'X'))) {
[672a24d]360 str += 2;
361 }
362 } else {
363 base = 10;
364
365 if (*str == '0') {
366 base = 8;
367 if ((str[1] == 'X') || (str[1] == 'x')) {
368 base = 16;
369 str += 2;
370 }
371 }
372 }
373
374 tmpptr = str;
375
376 while (*str) {
377 c = *str;
[838e14e2]378 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
379 (c <= '9' ? c - '0' : 0xff)));
[672a24d]380 if (c > base) {
381 break;
382 }
383
384 a = (result & 0xff) * base + c;
385 b = (result >> 8) * base + (a >> 8);
386
387 if (b > (ULONG_MAX >> 8)) {
388 /* overflow */
389 /* FIXME: errno = ERANGE*/
390 return ULONG_MAX;
391 }
392
393 result = (b << 8) + (a & 0xff);
394 ++str;
395 }
396
397 if (str == tmpptr) {
[838e14e2]398 /*
399 * No number was found => first invalid character is the first
400 * character of the string.
401 */
[672a24d]402 /* FIXME: set errno to EINVAL */
403 str = nptr;
404 result = 0;
405 }
406
407 if (endptr)
[a46da63]408 *endptr = (char *) str;
[672a24d]409
410 if (nptr == str) {
411 /*FIXME: errno = EINVAL*/
412 return 0;
413 }
414
415 return result;
416}
417
418/** Convert initial part of string to long int according to given base.
[838e14e2]419 * The number may begin with an arbitrary number of whitespaces followed by
420 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
421 * inserted and the number will be taken as hexadecimal one. If the base is 0
422 * and the number begin with a zero, number will be taken as octal one (as with
423 * base 8). Otherwise the base 0 is taken as decimal.
424 *
425 * @param nptr Pointer to string.
426 * @param endptr If not NULL, function stores here pointer to the first
427 * invalid character.
428 * @param base Zero or number between 2 and 36 inclusive.
429 * @return Result of conversion.
[672a24d]430 */
431long int strtol(const char *nptr, char **endptr, int base)
432{
433 char sgn = 0;
434 unsigned long number = 0;
435
436 number = _strtoul(nptr, endptr, base, &sgn);
437
438 if (number > LONG_MAX) {
[a46da63]439 if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
[672a24d]440 /* FIXME: set 0 to errno */
441 return number;
442 }
443 /* FIXME: set ERANGE to errno */
[a46da63]444 return (sgn ? LONG_MIN : LONG_MAX);
[672a24d]445 }
446
[a46da63]447 return (sgn ? -number : number);
[672a24d]448}
449
450
451/** Convert initial part of string to unsigned long according to given base.
[838e14e2]452 * The number may begin with an arbitrary number of whitespaces followed by
453 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
454 * inserted and the number will be taken as hexadecimal one. If the base is 0
455 * and the number begin with a zero, number will be taken as octal one (as with
456 * base 8). Otherwise the base 0 is taken as decimal.
457 *
458 * @param nptr Pointer to string.
459 * @param endptr If not NULL, function stores here pointer to the first
460 * invalid character
461 * @param base Zero or number between 2 and 36 inclusive.
462 * @return Result of conversion.
[672a24d]463 */
464unsigned long strtoul(const char *nptr, char **endptr, int base)
465{
466 char sgn = 0;
467 unsigned long number = 0;
468
469 number = _strtoul(nptr, endptr, base, &sgn);
470
[a46da63]471 return (sgn ? -number : number);
[672a24d]472}
[c594489]473
474char *strcpy(char *dest, const char *src)
475{
[a46da63]476 char *orig = dest;
477
[1526594c]478 while ((*(dest++) = *(src++)))
479 ;
[a46da63]480 return orig;
[c594489]481}
482
483char *strncpy(char *dest, const char *src, size_t n)
484{
[a46da63]485 char *orig = dest;
486
[1526594c]487 while ((*(dest++) = *(src++)) && --n)
488 ;
489 return orig;
490}
491
492char *strcat(char *dest, const char *src)
493{
494 char *orig = dest;
495 while (*dest++)
496 ;
497 --dest;
498 while ((*dest++ = *src++))
499 ;
[a46da63]500 return orig;
[c594489]501}
[b2951e2]502
[566987b0]503char * strdup(const char *s1)
504{
505 size_t len = strlen(s1) + 1;
506 void *ret = malloc(len);
507
508 if (ret == NULL)
509 return (char *) NULL;
510
511 return (char *) memcpy(ret, s1, len);
512}
513
[576845ec]514char *strtok(char *s, const char *delim)
[69df837f]515{
[576845ec]516 static char *next;
[69df837f]517
[576845ec]518 return strtok_r(s, delim, &next);
519}
[69df837f]520
[576845ec]521char *strtok_r(char *s, const char *delim, char **next)
522{
523 char *start, *end;
[69df837f]524
[576845ec]525 if (s == NULL)
526 s = *next;
[69df837f]527
[576845ec]528 /* Skip over leading delimiters. */
529 while (*s && (strchr(delim, *s) != NULL)) ++s;
530 start = s;
[69df837f]531
[576845ec]532 /* Skip over token characters. */
533 while (*s && (strchr(delim, *s) == NULL)) ++s;
534 end = s;
535 *next = (*s ? s + 1 : s);
536
537 if (start == end) {
538 return NULL; /* No more tokens. */
539 }
[69df837f]540
[576845ec]541 /* Overwrite delimiter with NULL terminator. */
542 *end = '\0';
543 return start;
[69df837f]544}
545
[a46da63]546/** @}
[b2951e2]547 */
Note: See TracBrowser for help on using the repository browser.