2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)findbytes.c 1.2 03/06/15 Copyright 2000-2003 J. Schilling */
15 * Find a byte with specific value in memory.
17 * Copyright (c) 2000-2003 J. Schilling
19 * Based on a strlen() idea from Torbjorn Granlund (tege@sics.se) and
20 * Dan Sahlin (dan@sics.se) and the memchr() suggestion
21 * from Dick Karpinski (dick@cca.ucsf.edu).
24 * This program is free software; you can redistribute it and/or modify
25 * it under the terms of the GNU General Public License version 2
26 * as published by the Free Software Foundation.
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License along with
34 * this program; see the file COPYING. If not, write to the Free Software
35 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
48 findbytes(const void *vp, int cnt, char val)
51 findbytes(vp, cnt, val)
57 register Uchar uval = (Uchar)val;
58 register const Uchar *cp = (Uchar *)vp;
59 register const Ulong *lp;
62 register Ulong magic_mask;
65 * Test byte-wise until cp is properly aligned for a long pointer.
67 while (--cnt >= 0 && !laligned(cp)) {
69 return ((char *)--cp);
74 * The magic mask is a long word where all carry bits a clear.
75 * This are bits 8, 16, 24 ...
76 * In addition, the top bit is not set (e.g bit 31 or 63). The magic
77 * mask will look this way:
79 * bits: 01111110 11111110 ... 11111110 11111111
80 * bytes: AAAAAAAA BBBBBBBB ... CCCCCCCC DDDDDDDD
82 * If we add anything to this magic number, no carry bit will change if
83 * it is the first carry bit left to a 0 byte. Adding anything != 0
84 * to the magic number will just turn the carry bit left to the byte
85 * but does not propagate any further.
88 magic_mask = 0x7EFEFEFFL;
91 magic_mask = 0x7EFEFEFEFEFEFEFFL;
94 * #error will not work for all compilers (e.g. sunos4)
95 * The following line will abort compilation on all compilers
96 * if none of the above is defines. And that's what we want.
98 error SIZE_LONG has unknown value
104 lmask |= lmask << 16;
106 lmask |= lmask << 32;
109 error SIZE_LONG has unknown value
111 for (lp = (const Ulong *)cp; cnt >= sizeof (long); cnt -= sizeof (long)) {
113 * We are not looking for 0 bytes so we need to xor with the
114 * long mask of repeated bytes. If any of the bytes matches our
115 * wanted char, we will create a 0 byte in the current long.
116 * But how will we find if at least one byte in a long is zero?
118 * If we add 'magic_mask' and any of the holes in the magic
119 * mask do not change, we most likely found a 0 byte in the
120 * long word. It is only a most likely match because if bits
121 * 24..30 (ot bits 56..62) are 0 but bit 31 (or bit 63) is set
122 * we will believe that we found a match but there is none.
123 * This will happen if there is 0x80nnnnnn / 0x80nnnnnnnnnnnnnn
125 lval = (*lp++ ^ lmask); /* create 0 byte on match */
126 lval = (lval + magic_mask) ^ ~lval; /* set bits unchanged by +*/
127 if ((lval & ~magic_mask) != 0) { /* a magic hole was set */
129 * If any of the hole bits did not change by addition,
130 * we most likely had a match.
131 * If this was a correct match, find the matching byte.
133 cp = (const Uchar *)(lp - 1);
138 return ((char *)&cp[1]);
140 return ((char *)&cp[2]);
142 return ((char *)&cp[3]);
145 return ((char *)&cp[4]);
147 return ((char *)&cp[5]);
149 return ((char *)&cp[6]);
151 return ((char *)&cp[7]);
154 error SIZE_LONG has unknown value
159 for (cp = (const Uchar *)lp; --cnt >= 0; ) {
161 return ((char *)--cp);
163 return ((char *)NULL);