diff options
Diffstat (limited to 'firmware/libc')
-rw-r--r-- | firmware/libc/include/string.h | 1 | ||||
-rw-r--r-- | firmware/libc/memccpy.c | 119 |
2 files changed, 120 insertions, 0 deletions
diff --git a/firmware/libc/include/string.h b/firmware/libc/include/string.h index 9815c62805..4ec2f8dd67 100644 --- a/firmware/libc/include/string.h +++ b/firmware/libc/include/string.h | |||
@@ -20,6 +20,7 @@ extern "C" { | |||
20 | _PTR _EXFUN(memchr,(const _PTR, int, size_t)); | 20 | _PTR _EXFUN(memchr,(const _PTR, int, size_t)); |
21 | int _EXFUN(memcmp,(const _PTR, const _PTR, size_t)); | 21 | int _EXFUN(memcmp,(const _PTR, const _PTR, size_t)); |
22 | _PTR _EXFUN(memcpy,(_PTR, const _PTR, size_t)); | 22 | _PTR _EXFUN(memcpy,(_PTR, const _PTR, size_t)); |
23 | _PTR _EXFUN(memccpy,(_PTR, const _PTR, int, size_t)); | ||
23 | _PTR _EXFUN(mempcpy,(_PTR, const _PTR, size_t)); | 24 | _PTR _EXFUN(mempcpy,(_PTR, const _PTR, size_t)); |
24 | _PTR _EXFUN(memmove,(_PTR, const _PTR, size_t)); | 25 | _PTR _EXFUN(memmove,(_PTR, const _PTR, size_t)); |
25 | _PTR _EXFUN(memset,(_PTR, int, size_t)); | 26 | _PTR _EXFUN(memset,(_PTR, int, size_t)); |
diff --git a/firmware/libc/memccpy.c b/firmware/libc/memccpy.c new file mode 100644 index 0000000000..fa9316616e --- /dev/null +++ b/firmware/libc/memccpy.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | FUNCTION | ||
3 | <<memccpy>>---copy memory regions with end-token check | ||
4 | ANSI_SYNOPSIS | ||
5 | #include <string.h> | ||
6 | void* memccpy(void *restrict <[out]>, const void *restrict <[in]>, | ||
7 | int <[endchar]>, size_t <[n]>); | ||
8 | TRAD_SYNOPSIS | ||
9 | void *memccpy(<[out]>, <[in]>, <[endchar]>, <[n]> | ||
10 | void *<[out]>; | ||
11 | void *<[in]>; | ||
12 | int <[endchar]>; | ||
13 | size_t <[n]>; | ||
14 | DESCRIPTION | ||
15 | This function copies up to <[n]> bytes from the memory region | ||
16 | pointed to by <[in]> to the memory region pointed to by | ||
17 | <[out]>. If a byte matching the <[endchar]> is encountered, | ||
18 | the byte is copied and copying stops. | ||
19 | If the regions overlap, the behavior is undefined. | ||
20 | RETURNS | ||
21 | <<memccpy>> returns a pointer to the first byte following the | ||
22 | <[endchar]> in the <[out]> region. If no byte matching | ||
23 | <[endchar]> was copied, then <<NULL>> is returned. | ||
24 | PORTABILITY | ||
25 | <<memccpy>> is a GNU extension. | ||
26 | <<memccpy>> requires no supporting OS subroutines. | ||
27 | */ | ||
28 | #include <stddef.h> | ||
29 | #include <string.h> | ||
30 | #include <limits.h> | ||
31 | #include "_ansi.h" /* for _DEFUN */ | ||
32 | |||
33 | /* Nonzero if either X or Y is not aligned on a "long" boundary. */ | ||
34 | #define ROCKBOX_UNALIGNED(X, Y) \ | ||
35 | (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1))) | ||
36 | /* How many bytes are copied each iteration of the word copy loop. */ | ||
37 | #define LITTLEBLOCKSIZE (sizeof (long)) | ||
38 | /* Threshhold for punting to the byte copier. */ | ||
39 | #define TOO_SMALL(LEN) ((LEN) < LITTLEBLOCKSIZE) | ||
40 | /* Macros for detecting endchar */ | ||
41 | #if LONG_MAX == 2147483647L | ||
42 | #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) | ||
43 | #else | ||
44 | #if LONG_MAX == 9223372036854775807L | ||
45 | /* Nonzero if X (a long int) contains a NULL byte. */ | ||
46 | #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080) | ||
47 | #else | ||
48 | #error long int is not a 32bit or 64bit type. | ||
49 | #endif | ||
50 | #endif | ||
51 | _PTR | ||
52 | _DEFUN (memccpy, (dst0, src0, endchar, len0), | ||
53 | _PTR __restrict dst0 _AND | ||
54 | _CONST _PTR __restrict src0 _AND | ||
55 | int endchar0 _AND | ||
56 | size_t len0) | ||
57 | { | ||
58 | #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) | ||
59 | _PTR ptr = NULL; | ||
60 | char *dst = (char *) dst0; | ||
61 | char *src = (char *) src0; | ||
62 | char endchar = endchar0 & 0xff; | ||
63 | while (len0--) | ||
64 | { | ||
65 | if ((*dst++ = *src++) == endchar) | ||
66 | { | ||
67 | ptr = dst; | ||
68 | break; | ||
69 | } | ||
70 | } | ||
71 | return ptr; | ||
72 | #else | ||
73 | _PTR ptr = NULL; | ||
74 | char *dst = dst0; | ||
75 | _CONST char *src = src0; | ||
76 | long *aligned_dst; | ||
77 | _CONST long *aligned_src; | ||
78 | char endchar = endchar0 & 0xff; | ||
79 | /* If the size is small, or either SRC or DST is unaligned, | ||
80 | then punt into the byte copy loop. This should be rare. */ | ||
81 | if (!TOO_SMALL(len0) && !ROCKBOX_UNALIGNED (src, dst)) | ||
82 | { | ||
83 | unsigned int i; | ||
84 | unsigned long mask = 0; | ||
85 | aligned_dst = (long*)dst; | ||
86 | aligned_src = (long*)src; | ||
87 | /* The fast code reads the ASCII one word at a time and only | ||
88 | performs the bytewise search on word-sized segments if they | ||
89 | contain the search character, which is detected by XORing | ||
90 | the word-sized segment with a word-sized block of the search | ||
91 | character and then detecting for the presence of NULL in the | ||
92 | result. */ | ||
93 | for (i = 0; i < LITTLEBLOCKSIZE; i++) | ||
94 | mask = (mask << 8) + endchar; | ||
95 | /* Copy one long word at a time if possible. */ | ||
96 | while (len0 >= LITTLEBLOCKSIZE) | ||
97 | { | ||
98 | unsigned long buffer = (unsigned long)(*aligned_src); | ||
99 | buffer ^= mask; | ||
100 | if (DETECTNULL (buffer)) | ||
101 | break; /* endchar is found, go byte by byte from here */ | ||
102 | *aligned_dst++ = *aligned_src++; | ||
103 | len0 -= LITTLEBLOCKSIZE; | ||
104 | } | ||
105 | /* Pick up any residual with a byte copier. */ | ||
106 | dst = (char*)aligned_dst; | ||
107 | src = (char*)aligned_src; | ||
108 | } | ||
109 | while (len0--) | ||
110 | { | ||
111 | if ((*dst++ = *src++) == endchar) | ||
112 | { | ||
113 | ptr = dst; | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | return ptr; | ||
118 | #endif /* not PREFER_SIZE_OVER_SPEED */ | ||
119 | } | ||