···11+/*
22+FUNCTION
33+ <<memccpy>>---copy memory regions with end-token check
44+ANSI_SYNOPSIS
55+ #include <string.h>
66+ void* memccpy(void *restrict <[out]>, const void *restrict <[in]>,
77+ int <[endchar]>, size_t <[n]>);
88+TRAD_SYNOPSIS
99+ void *memccpy(<[out]>, <[in]>, <[endchar]>, <[n]>
1010+ void *<[out]>;
1111+ void *<[in]>;
1212+ int <[endchar]>;
1313+ size_t <[n]>;
1414+DESCRIPTION
1515+ This function copies up to <[n]> bytes from the memory region
1616+ pointed to by <[in]> to the memory region pointed to by
1717+ <[out]>. If a byte matching the <[endchar]> is encountered,
1818+ the byte is copied and copying stops.
1919+ If the regions overlap, the behavior is undefined.
2020+RETURNS
2121+ <<memccpy>> returns a pointer to the first byte following the
2222+ <[endchar]> in the <[out]> region. If no byte matching
2323+ <[endchar]> was copied, then <<NULL>> is returned.
2424+PORTABILITY
2525+<<memccpy>> is a GNU extension.
2626+<<memccpy>> requires no supporting OS subroutines.
2727+ */
2828+#include <stddef.h>
2929+#include <string.h>
3030+#include <limits.h>
3131+#include "_ansi.h" /* for _DEFUN */
3232+3333+/* Nonzero if either X or Y is not aligned on a "long" boundary. */
3434+#define ROCKBOX_UNALIGNED(X, Y) \
3535+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
3636+/* How many bytes are copied each iteration of the word copy loop. */
3737+#define LITTLEBLOCKSIZE (sizeof (long))
3838+/* Threshhold for punting to the byte copier. */
3939+#define TOO_SMALL(LEN) ((LEN) < LITTLEBLOCKSIZE)
4040+/* Macros for detecting endchar */
4141+#if LONG_MAX == 2147483647L
4242+#define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
4343+#else
4444+#if LONG_MAX == 9223372036854775807L
4545+/* Nonzero if X (a long int) contains a NULL byte. */
4646+#define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
4747+#else
4848+#error long int is not a 32bit or 64bit type.
4949+#endif
5050+#endif
5151+_PTR
5252+_DEFUN (memccpy, (dst0, src0, endchar, len0),
5353+ _PTR __restrict dst0 _AND
5454+ _CONST _PTR __restrict src0 _AND
5555+ int endchar0 _AND
5656+ size_t len0)
5757+{
5858+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
5959+ _PTR ptr = NULL;
6060+ char *dst = (char *) dst0;
6161+ char *src = (char *) src0;
6262+ char endchar = endchar0 & 0xff;
6363+ while (len0--)
6464+ {
6565+ if ((*dst++ = *src++) == endchar)
6666+ {
6767+ ptr = dst;
6868+ break;
6969+ }
7070+ }
7171+ return ptr;
7272+#else
7373+ _PTR ptr = NULL;
7474+ char *dst = dst0;
7575+ _CONST char *src = src0;
7676+ long *aligned_dst;
7777+ _CONST long *aligned_src;
7878+ char endchar = endchar0 & 0xff;
7979+ /* If the size is small, or either SRC or DST is unaligned,
8080+ then punt into the byte copy loop. This should be rare. */
8181+ if (!TOO_SMALL(len0) && !ROCKBOX_UNALIGNED (src, dst))
8282+ {
8383+ unsigned int i;
8484+ unsigned long mask = 0;
8585+ aligned_dst = (long*)dst;
8686+ aligned_src = (long*)src;
8787+ /* The fast code reads the ASCII one word at a time and only
8888+ performs the bytewise search on word-sized segments if they
8989+ contain the search character, which is detected by XORing
9090+ the word-sized segment with a word-sized block of the search
9191+ character and then detecting for the presence of NULL in the
9292+ result. */
9393+ for (i = 0; i < LITTLEBLOCKSIZE; i++)
9494+ mask = (mask << 8) + endchar;
9595+ /* Copy one long word at a time if possible. */
9696+ while (len0 >= LITTLEBLOCKSIZE)
9797+ {
9898+ unsigned long buffer = (unsigned long)(*aligned_src);
9999+ buffer ^= mask;
100100+ if (DETECTNULL (buffer))
101101+ break; /* endchar is found, go byte by byte from here */
102102+ *aligned_dst++ = *aligned_src++;
103103+ len0 -= LITTLEBLOCKSIZE;
104104+ }
105105+ /* Pick up any residual with a byte copier. */
106106+ dst = (char*)aligned_dst;
107107+ src = (char*)aligned_src;
108108+ }
109109+ while (len0--)
110110+ {
111111+ if ((*dst++ = *src++) == endchar)
112112+ {
113113+ ptr = dst;
114114+ break;
115115+ }
116116+ }
117117+ return ptr;
118118+#endif /* not PREFER_SIZE_OVER_SPEED */
119119+}