1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * Copyright (c) 1994-2009 Red Hat, Inc. 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 are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * 3. Neither the name of the copyright holder nor the names of its 17 * contributors may be used to endorse or promote products derived from this 18 * software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 FUNCTION 35 <<strchr>>---search for character in string 36 37 INDEX 38 strchr 39 40 ANSI_SYNOPSIS 41 #include <string.h> 42 char * strchr(const char *<[string]>, int <[c]>); 43 44 TRAD_SYNOPSIS 45 #include <string.h> 46 char * strchr(<[string]>, <[c]>); 47 const char *<[string]>; 48 int <[c]>; 49 50 DESCRIPTION 51 This function finds the first occurence of <[c]> (converted to 52 a char) in the string pointed to by <[string]> (including the 53 terminating null character). 54 55 RETURNS 56 Returns a pointer to the located character, or a null pointer 57 if <[c]> does not occur in <[string]>. 58 59 PORTABILITY 60 <<strchr>> is ANSI C. 61 62 <<strchr>> requires no supporting OS subroutines. 63 64 QUICKREF 65 strchr ansi pure 66 */ 67 68 #include <string.h> 69 #include <limits.h> 70 #include "_ansi.h" 71 72 /* Nonzero if X is not aligned on a "long" boundary. */ 73 #define UNALIGNED(X) ((long)X & (sizeof (long) - 1)) 74 75 /* How many bytes are loaded each iteration of the word copy loop. */ 76 #define LBLOCKSIZE (sizeof (long)) 77 78 #if LONG_MAX == 2147483647L 79 #define DETECTNULL(X) (((X) - 0x01010101L) & ~(X) & 0x80808080UL) 80 #else 81 #if LONG_MAX == 9223372036854775807L 82 /* Nonzero if X (a long int) contains a NULL byte. */ 83 #define DETECTNULL(X) (((X) - 0x0101010101010101L) & ~(X) & \ 84 0x8080808080808080UL) 85 #else 86 #error long int is not a 32bit or 64bit type. 87 #endif 88 #endif 89 90 /* DETECTCHAR returns nonzero if (long)X contains the byte used 91 to fill (long)MASK. */ 92 #define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK)) 93 94 char * 95 _DEFUN (strchr, (s1, i), 96 _CONST char *s1 _AND 97 int i) 98 { 99 _CONST unsigned char *s = (_CONST unsigned char *)s1; 100 unsigned char c = i; 101 102 #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) 103 unsigned long mask,j; 104 unsigned long *aligned_addr; 105 106 /* Special case for finding 0. */ 107 if (!c) 108 { 109 while (UNALIGNED (s)) 110 { 111 if (!*s) 112 return (char *) s; 113 s++; 114 } 115 /* Operate a word at a time. */ 116 aligned_addr = (unsigned long *) s; 117 while (!DETECTNULL (*aligned_addr)) 118 aligned_addr++; 119 /* Found the end of string. */ 120 s = (const unsigned char *) aligned_addr; 121 while (*s) 122 s++; 123 return (char *) s; 124 } 125 126 /* All other bytes. Align the pointer, then search a long at a time. */ 127 while (UNALIGNED (s)) 128 { 129 if (!*s) 130 return NULL; 131 if (*s == c) 132 return (char *) s; 133 s++; 134 } 135 136 mask = c; 137 for (j = 8; j < LBLOCKSIZE * 8; j <<= 1) 138 mask = (mask << j) | mask; 139 140 aligned_addr = (unsigned long *) s; 141 while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask)) 142 aligned_addr++; 143 144 /* The block of bytes currently pointed to by aligned_addr 145 contains either a null or the target char, or both. We 146 catch it using the bytewise search. */ 147 148 s = (unsigned char *) aligned_addr; 149 150 #endif /* not PREFER_SIZE_OVER_SPEED */ 151 152 while (*s && *s != c) 153 s++; 154 if (*s == c) 155 return (char *)s; 156 return NULL; 157 } 158