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
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 <unistd.h>
38#include <ctype.h>
39#include <limits.h>
40#include <align.h>
41#include <sys/types.h>
42#include <malloc.h>
43
44/** Fill memory block with a constant value. */
45void *memset(void *dest, int b, size_t n)
46{
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;
94}
95
96struct along {
97 unsigned long n;
98} __attribute__ ((packed));
99
100static void *unaligned_memcpy(void *dst, const void *src, size_t n)
101{
102 int i, j;
103 struct along *adst = dst;
104 const struct along *asrc = src;
105
106 for (i = 0; i < n / sizeof(unsigned long); i++)
107 adst[i].n = asrc[i].n;
108
109 for (j = 0; j < n % sizeof(unsigned long); j++)
110 ((unsigned char *) (((unsigned long *) dst) + i))[j] =
111 ((unsigned char *) (((unsigned long *) src) + i))[j];
112
113 return (char *) dst;
114}
115
116/** Copy memory block. */
117void *memcpy(void *dst, const void *src, size_t n)
118{
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 */
135
136 if (((uintptr_t) dst & (word_size - 1)) !=
137 ((uintptr_t) src & (word_size - 1)))
138 return unaligned_memcpy(dst, src, n);
139
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;
156 while (i-- != 0)
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;
174 while (i-- != 0)
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;
185 while (i-- != 0)
186 *dstb++ = *srcb++;
187
188 return dst;
189}
190
191/** Move memory block with possible overlapping. */
192void *memmove(void *dst, const void *src, size_t n)
193{
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) {
202 return memcpy(dst, src, n);
203 }
204
205 /* Which direction? */
206 if (src > dst) {
207 /* Forwards. */
208 sp = src;
209 dp = dst;
210
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;
223}
224
225/** Compare two memory areas.
226 *
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.
233 */
234int bcmp(const char *s1, const char *s2, size_t len)
235{
236 for (; len && *s1++ == *s2++; len--)
237 ;
238 return len;
239}
240
241/** Count the number of characters in the string, not including terminating 0.
242 *
243 * @param str String.
244 * @return Number of characters in string.
245 */
246size_t strlen(const char *str)
247{
248 size_t counter = 0;
249
250 while (str[counter] != 0)
251 counter++;
252
253 return counter;
254}
255
256int strcmp(const char *a, const char *b)
257{
258 int c = 0;
259
260 while (a[c] && b[c] && (!(a[c] - b[c])))
261 c++;
262
263 return (a[c] - b[c]);
264}
265
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}
276
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
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.
293 */
294char *strchr(const char *str, int c)
295{
296 while (*str != '\0') {
297 if (*str == (char) c)
298 return (char *) str;
299 str++;
300 }
301
302 return NULL;
303}
304
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.
311 */
312char *strrchr(const char *str, int c)
313{
314 char *retval = NULL;
315
316 while (*str != '\0') {
317 if (*str == (char) c)
318 retval = (char *) str;
319 str++;
320 }
321
322 return (char *) retval;
323}
324
325/** Convert string to a number.
326 * Core of strtol and strtoul functions.
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.
334 */
335static unsigned long
336_strtoul(const char *nptr, char **endptr, int base, char *sgn)
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 }
358 if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
359 (str[1] == 'X'))) {
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;
378 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
379 (c <= '9' ? c - '0' : 0xff)));
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) {
398 /*
399 * No number was found => first invalid character is the first
400 * character of the string.
401 */
402 /* FIXME: set errno to EINVAL */
403 str = nptr;
404 result = 0;
405 }
406
407 if (endptr)
408 *endptr = (char *) str;
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.
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.
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) {
439 if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
440 /* FIXME: set 0 to errno */
441 return number;
442 }
443 /* FIXME: set ERANGE to errno */
444 return (sgn ? LONG_MIN : LONG_MAX);
445 }
446
447 return (sgn ? -number : number);
448}
449
450
451/** Convert initial part of string to unsigned long according to given base.
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.
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
471 return (sgn ? -number : number);
472}
473
474char *strcpy(char *dest, const char *src)
475{
476 char *orig = dest;
477
478 while ((*(dest++) = *(src++)))
479 ;
480 return orig;
481}
482
483char *strncpy(char *dest, const char *src, size_t n)
484{
485 char *orig = dest;
486
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 ;
500 return orig;
501}
502
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
514char *strtok(char *s, const char *delim)
515{
516 static char *next;
517
518 return strtok_r(s, delim, &next);
519}
520
521char *strtok_r(char *s, const char *delim, char **next)
522{
523 char *start, *end;
524
525 if (s == NULL)
526 s = *next;
527
528 /* Skip over leading delimiters. */
529 while (*s && (strchr(delim, *s) != NULL)) ++s;
530 start = s;
531
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 }
540
541 /* Overwrite delimiter with NULL terminator. */
542 *end = '\0';
543 return start;
544}
545
546/** @}
547 */
Note: See TracBrowser for help on using the repository browser.