source: mainline/uspace/lib/libc/generic/string.c@ 47acd58

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

Rewrite memcpy() in C library. Now copies congruent blocks fast, not just aligned blocks.

  • Property mode set to 100644
File size: 11.1 KB
Line 
1/*
2 * Copyright (c) 2005 Martin Decky
3 * Copyright (C) 1998 by Wes Peters <wes@softweyr.com>
4 * Copyright (c) 1988, 1993 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libc
32 * @{
33 */
34/** @file
35 */
36
37#include <string.h>
38#include <unistd.h>
39#include <ctype.h>
40#include <limits.h>
41#include <align.h>
42#include <sys/types.h>
43#include <malloc.h>
44
45/* Dummy implementation of mem/ functions */
46
47void *memset(void *s, int c, size_t n)
48{
49 char *os = s;
50
51 while (n--)
52 *(os++) = c;
53
54 return s;
55}
56
57struct along {
58 unsigned long n;
59} __attribute__ ((packed));
60
61static void *unaligned_memcpy(void *dst, const void *src, size_t n)
62{
63 int i, j;
64 struct along *adst = dst;
65 const struct along *asrc = src;
66
67 for (i = 0; i < n / sizeof(unsigned long); i++)
68 adst[i].n = asrc[i].n;
69
70 for (j = 0; j < n % sizeof(unsigned long); j++)
71 ((unsigned char *) (((unsigned long *) dst) + i))[j] =
72 ((unsigned char *) (((unsigned long *) src) + i))[j];
73
74 return (char *) dst;
75}
76
77/** Copy memory block. */
78void *memcpy(void *dst, const void *src, size_t n)
79{
80 size_t i;
81 size_t mod, fill;
82 size_t word_size;
83 size_t n_words;
84
85 const unsigned long *srcw;
86 unsigned long *dstw;
87 const uint8_t *srcb;
88 uint8_t *dstb;
89
90 word_size = sizeof(unsigned long);
91
92 /*
93 * Are source and destination addresses congruent modulo word_size?
94 * If not, use unaligned_memcpy().
95 */
96
97 if (((uintptr_t) dst & (word_size - 1)) !=
98 ((uintptr_t) src & (word_size - 1)))
99 return unaligned_memcpy(dst, src, n);
100
101 /*
102 * mod is the address modulo word size. fill is the length of the
103 * initial buffer segment before the first word boundary.
104 * If the buffer is very short, use unaligned_memcpy(), too.
105 */
106
107 mod = (uintptr_t) dst & (word_size - 1);
108 fill = word_size - mod;
109 if (fill > n) fill = n;
110
111 /* Copy the initial segment. */
112
113 srcb = src;
114 dstb = dst;
115
116 i = fill;
117 while (i-- > 0)
118 *dstb++ = *srcb++;
119
120 /* Compute remaining length. */
121
122 n -= fill;
123 if (n == 0) return dst;
124
125 /* Pointers to aligned segment. */
126
127 dstw = (unsigned long *) dstb;
128 srcw = (const unsigned long *) srcb;
129
130 n_words = n / word_size; /* Number of whole words to copy. */
131 n -= n_words * word_size; /* Remaining bytes at the end. */
132
133 /* "Fast" copy. */
134 i = n_words;
135 while (i-- > 0)
136 *dstw++ = *srcw++;
137
138 /*
139 * Copy the rest.
140 */
141
142 srcb = (const uint8_t *) srcw;
143 dstb = (uint8_t *) dstw;
144
145 i = n;
146 while (i-- > 0)
147 *dstb++ = *srcb++;
148
149 return dst;
150}
151
152void *memmove(void *dst, const void *src, size_t n)
153{
154 int i, j;
155
156 if (src > dst)
157 return memcpy(dst, src, n);
158
159 for (j = (n % sizeof(unsigned long)) - 1; j >= 0; j--)
160 ((unsigned char *) ((unsigned long *) dst))[j] =
161 ((unsigned char *) ((unsigned long *) src))[j];
162
163 for (i = n / sizeof(unsigned long) - 1; i >=0 ; i--)
164 ((unsigned long *) dst)[i] = ((unsigned long *) src)[i];
165
166 return (char *) dst;
167}
168
169/** Compare two memory areas.
170 *
171 * @param s1 Pointer to the first area to compare.
172 * @param s2 Pointer to the second area to compare.
173 * @param len Size of the first area in bytes. Both areas must have
174 * the same length.
175 * @return If len is 0, return zero. If the areas match, return
176 * zero. Otherwise return non-zero.
177 */
178int bcmp(const char *s1, const char *s2, size_t len)
179{
180 for (; len && *s1++ == *s2++; len--)
181 ;
182 return len;
183}
184
185/** Count the number of characters in the string, not including terminating 0.
186 *
187 * @param str String.
188 * @return Number of characters in string.
189 */
190size_t strlen(const char *str)
191{
192 size_t counter = 0;
193
194 while (str[counter] != 0)
195 counter++;
196
197 return counter;
198}
199
200int strcmp(const char *a, const char *b)
201{
202 int c = 0;
203
204 while (a[c] && b[c] && (!(a[c] - b[c])))
205 c++;
206
207 return (a[c] - b[c]);
208}
209
210int strncmp(const char *a, const char *b, size_t n)
211{
212 size_t c = 0;
213
214 while (c < n && a[c] && b[c] && (!(a[c] - b[c])))
215 c++;
216
217 return ( c < n ? a[c] - b[c] : 0);
218
219}
220
221int stricmp(const char *a, const char *b)
222{
223 int c = 0;
224
225 while (a[c] && b[c] && (!(tolower(a[c]) - tolower(b[c]))))
226 c++;
227
228 return (tolower(a[c]) - tolower(b[c]));
229}
230
231/** Return pointer to the first occurence of character c in string.
232 *
233 * @param str Scanned string.
234 * @param c Searched character (taken as one byte).
235 * @return Pointer to the matched character or NULL if it is not
236 * found in given string.
237 */
238char *strchr(const char *str, int c)
239{
240 while (*str != '\0') {
241 if (*str == (char) c)
242 return (char *) str;
243 str++;
244 }
245
246 return NULL;
247}
248
249/** Return pointer to the last occurence of character c in string.
250 *
251 * @param str Scanned string.
252 * @param c Searched character (taken as one byte).
253 * @return Pointer to the matched character or NULL if it is not
254 * found in given string.
255 */
256char *strrchr(const char *str, int c)
257{
258 char *retval = NULL;
259
260 while (*str != '\0') {
261 if (*str == (char) c)
262 retval = (char *) str;
263 str++;
264 }
265
266 return (char *) retval;
267}
268
269/** Convert string to a number.
270 * Core of strtol and strtoul functions.
271 *
272 * @param nptr Pointer to string.
273 * @param endptr If not NULL, function stores here pointer to the first
274 * invalid character.
275 * @param base Zero or number between 2 and 36 inclusive.
276 * @param sgn It's set to 1 if minus found.
277 * @return Result of conversion.
278 */
279static unsigned long
280_strtoul(const char *nptr, char **endptr, int base, char *sgn)
281{
282 unsigned char c;
283 unsigned long result = 0;
284 unsigned long a, b;
285 const char *str = nptr;
286 const char *tmpptr;
287
288 while (isspace(*str))
289 str++;
290
291 if (*str == '-') {
292 *sgn = 1;
293 ++str;
294 } else if (*str == '+')
295 ++str;
296
297 if (base) {
298 if ((base == 1) || (base > 36)) {
299 /* FIXME: set errno to EINVAL */
300 return 0;
301 }
302 if ((base == 16) && (*str == '0') && ((str[1] == 'x') ||
303 (str[1] == 'X'))) {
304 str += 2;
305 }
306 } else {
307 base = 10;
308
309 if (*str == '0') {
310 base = 8;
311 if ((str[1] == 'X') || (str[1] == 'x')) {
312 base = 16;
313 str += 2;
314 }
315 }
316 }
317
318 tmpptr = str;
319
320 while (*str) {
321 c = *str;
322 c = (c >= 'a' ? c - 'a' + 10 : (c >= 'A' ? c - 'A' + 10 :
323 (c <= '9' ? c - '0' : 0xff)));
324 if (c > base) {
325 break;
326 }
327
328 a = (result & 0xff) * base + c;
329 b = (result >> 8) * base + (a >> 8);
330
331 if (b > (ULONG_MAX >> 8)) {
332 /* overflow */
333 /* FIXME: errno = ERANGE*/
334 return ULONG_MAX;
335 }
336
337 result = (b << 8) + (a & 0xff);
338 ++str;
339 }
340
341 if (str == tmpptr) {
342 /*
343 * No number was found => first invalid character is the first
344 * character of the string.
345 */
346 /* FIXME: set errno to EINVAL */
347 str = nptr;
348 result = 0;
349 }
350
351 if (endptr)
352 *endptr = (char *) str;
353
354 if (nptr == str) {
355 /*FIXME: errno = EINVAL*/
356 return 0;
357 }
358
359 return result;
360}
361
362/** Convert initial part of string to long int according to given base.
363 * The number may begin with an arbitrary number of whitespaces followed by
364 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
365 * inserted and the number will be taken as hexadecimal one. If the base is 0
366 * and the number begin with a zero, number will be taken as octal one (as with
367 * base 8). Otherwise the base 0 is taken as decimal.
368 *
369 * @param nptr Pointer to string.
370 * @param endptr If not NULL, function stores here pointer to the first
371 * invalid character.
372 * @param base Zero or number between 2 and 36 inclusive.
373 * @return Result of conversion.
374 */
375long int strtol(const char *nptr, char **endptr, int base)
376{
377 char sgn = 0;
378 unsigned long number = 0;
379
380 number = _strtoul(nptr, endptr, base, &sgn);
381
382 if (number > LONG_MAX) {
383 if ((sgn) && (number == (unsigned long) (LONG_MAX) + 1)) {
384 /* FIXME: set 0 to errno */
385 return number;
386 }
387 /* FIXME: set ERANGE to errno */
388 return (sgn ? LONG_MIN : LONG_MAX);
389 }
390
391 return (sgn ? -number : number);
392}
393
394
395/** Convert initial part of string to unsigned long according to given base.
396 * The number may begin with an arbitrary number of whitespaces followed by
397 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
398 * inserted and the number will be taken as hexadecimal one. If the base is 0
399 * and the number begin with a zero, number will be taken as octal one (as with
400 * base 8). Otherwise the base 0 is taken as decimal.
401 *
402 * @param nptr Pointer to string.
403 * @param endptr If not NULL, function stores here pointer to the first
404 * invalid character
405 * @param base Zero or number between 2 and 36 inclusive.
406 * @return Result of conversion.
407 */
408unsigned long strtoul(const char *nptr, char **endptr, int base)
409{
410 char sgn = 0;
411 unsigned long number = 0;
412
413 number = _strtoul(nptr, endptr, base, &sgn);
414
415 return (sgn ? -number : number);
416}
417
418char *strcpy(char *dest, const char *src)
419{
420 char *orig = dest;
421
422 while ((*(dest++) = *(src++)))
423 ;
424 return orig;
425}
426
427char *strncpy(char *dest, const char *src, size_t n)
428{
429 char *orig = dest;
430
431 while ((*(dest++) = *(src++)) && --n)
432 ;
433 return orig;
434}
435
436char *strcat(char *dest, const char *src)
437{
438 char *orig = dest;
439 while (*dest++)
440 ;
441 --dest;
442 while ((*dest++ = *src++))
443 ;
444 return orig;
445}
446
447char * strdup(const char *s1)
448{
449 size_t len = strlen(s1) + 1;
450 void *ret = malloc(len);
451
452 if (ret == NULL)
453 return (char *) NULL;
454
455 return (char *) memcpy(ret, s1, len);
456}
457
458/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
459char * strtok_r(char *s, const char *delim, char **last)
460{
461 char *spanp, *tok;
462 int c, sc;
463
464 if (s == NULL && (s = *last) == NULL)
465 return (NULL);
466
467cont:
468 c = *s++;
469 for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
470 if (c == sc)
471 goto cont;
472 }
473
474 if (c == 0) { /* no non-delimiter characters */
475 *last = NULL;
476 return (NULL);
477 }
478
479 tok = s - 1;
480
481 for (;;) {
482 c = *s++;
483 spanp = (char *)delim;
484 do {
485 if ((sc = *spanp++) == c) {
486 if (c == 0)
487 s = NULL;
488 else
489 s[-1] = '\0';
490 *last = s;
491 return (tok);
492 }
493 } while (sc != 0);
494 }
495}
496
497/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
498char * strtok(char *s, const char *delim)
499{
500 static char *last;
501
502 return (strtok_r(s, delim, &last));
503}
504
505/** @}
506 */
Note: See TracBrowser for help on using the repository browser.