xref: /optee_os/lib/libutils/isoc/newlib/memchr.c (revision b01047730e77127c23a36591643eeb8bb0487d68)
1 /*
2  * Copyright (c) 1994-2009  Red Hat, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  * contributors may be used to endorse or promote products derived from this
17  * software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33 FUNCTION
34 	<<memchr>>---find character in memory
35 
36 INDEX
37 	memchr
38 
39 ANSI_SYNOPSIS
40 	#include <string.h>
41 	void *memchr(const void *<[src]>, int <[c]>, size_t <[length]>);
42 
43 TRAD_SYNOPSIS
44 	#include <string.h>
45 	void *memchr(<[src]>, <[c]>, <[length]>)
46 	void *<[src]>;
47 	void *<[c]>;
48 	size_t <[length]>;
49 
50 DESCRIPTION
51 	This function searches memory starting at <<*<[src]>>> for the
52 	character <[c]>.  The search only ends with the first
53 	occurrence of <[c]>, or after <[length]> characters; in
54 	particular, <<NUL>> does not terminate the search.
55 
56 RETURNS
57 	If the character <[c]> is found within <[length]> characters
58 	of <<*<[src]>>>, a pointer to the character is returned. If
59 	<[c]> is not found, then <<NULL>> is returned.
60 
61 PORTABILITY
62 <<memchr>> is ANSI C.
63 
64 <<memchr>> requires no supporting OS subroutines.
65 
66 QUICKREF
67 	memchr ansi pure
68 */
69 
70 #include "_ansi.h"
71 #include <string.h>
72 #include <limits.h>
73 
74 /* Nonzero if either X or Y is not aligned on a "long" boundary.  */
75 #define UNALIGNED(X) ((long)X & (sizeof(long) - 1))
76 
77 /* How many bytes are loaded each iteration of the word copy loop.  */
78 #define LBLOCKSIZE (sizeof(long))
79 
80 /* Threshhold for punting to the bytewise iterator.  */
81 #define TOO_SMALL(LEN)  ((LEN) < LBLOCKSIZE)
82 
83 #if LONG_MAX == 2147483647L
84 #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
85 #else
86 #if LONG_MAX == 9223372036854775807L
87 /* Nonzero if X (a long int) contains a NULL byte. */
88 #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
89 #else
90 #error long int is not a 32bit or 64bit type.
91 #endif
92 #endif
93 
94 #ifndef DETECTNULL
95 #error long int is not a 32bit or 64bit byte
96 #endif
97 
98 /* DETECTCHAR returns nonzero if (long)X contains the byte used
99    to fill (long)MASK. */
100 #define DETECTCHAR(X, MASK) (DETECTNULL(X ^ MASK))
101 
102 _PTR
103 _DEFUN(memchr, (src_void, c, length), _CONST _PTR src_void _AND int c
104 	_AND size_t length)
105 {
106 	_CONST unsigned char *src = (_CONST unsigned char *)src_void;
107 	unsigned char d = c;
108 
109 #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
110 	unsigned long *asrc;
111 	unsigned long mask;
112 	int i;
113 
114 	while (UNALIGNED(src)) {
115 		if (!length--)
116 			return NULL;
117 		if (*src == d)
118 			return (void *)src;
119 		src++;
120 	}
121 
122 	if (!TOO_SMALL(length)) {
123 		/* If we get this far, we know that length is large and src is
124 		   word-aligned. */
125 		/* The fast code reads the source one word at a time and only
126 		   performs the bytewise search on word-sized segments if they
127 		   contain the search character, which is detected by XORing
128 		   the word-sized segment with a word-sized block of the search
129 		   character and then detecting for the presence of NUL in the
130 		   result.  */
131 		asrc = (unsigned long *)src;
132 		mask = d << 8 | d;
133 		mask = mask << 16 | mask;
134 		for (i = 32; i < LBLOCKSIZE * 8; i <<= 1)
135 			mask = (mask << i) | mask;
136 
137 		while (length >= LBLOCKSIZE) {
138 			if (DETECTCHAR(*asrc, mask))
139 				break;
140 			length -= LBLOCKSIZE;
141 			asrc++;
142 		}
143 
144 		/* If there are fewer than LBLOCKSIZE characters left,
145 		   then we resort to the bytewise loop.  */
146 
147 		src = (unsigned char *)asrc;
148 	}
149 #endif /* not PREFER_SIZE_OVER_SPEED */
150 
151 	while (length--) {
152 		if (*src == d)
153 			return (void *)src;
154 		src++;
155 	}
156 
157 	return NULL;
158 }
159