summaryrefslogtreecommitdiff
path: root/librols/findbytes.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2012-12-31 05:04:42 +0400
commit71dc8760ff4de5f365330d1bc571d934deb54af9 (patch)
tree7346d42a282562a3937d82307012b5857d642ce6 /librols/findbytes.c
downloadcdrkit-upstream.tar.gz
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'librols/findbytes.c')
-rw-r--r--librols/findbytes.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/librols/findbytes.c b/librols/findbytes.c
new file mode 100644
index 0000000..0b56597
--- /dev/null
+++ b/librols/findbytes.c
@@ -0,0 +1,164 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)findbytes.c 1.2 03/06/15 Copyright 2000-2003 J. Schilling */
+/*
+ * Find a byte with specific value in memory.
+ *
+ * Copyright (c) 2000-2003 J. Schilling
+ *
+ * Based on a strlen() idea from Torbjorn Granlund (tege@sics.se) and
+ * Dan Sahlin (dan@sics.se) and the memchr() suggestion
+ * from Dick Karpinski (dick@cca.ucsf.edu).
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <mconfig.h>
+#include <stdxlib.h>
+#include <utypes.h>
+#include <align.h>
+#include <standard.h>
+#include <strdefs.h>
+#include <schily.h>
+
+#ifdef PROTOTYPES
+EXPORT char *
+findbytes(const void *vp, int cnt, char val)
+#else
+EXPORT char *
+findbytes(vp, cnt, val)
+ const void *vp;
+ register int cnt;
+ char val;
+#endif
+{
+ register Uchar uval = (Uchar)val;
+ register const Uchar *cp = (Uchar *)vp;
+ register const Ulong *lp;
+ register Ulong lval;
+ register Ulong lmask;
+ register Ulong magic_mask;
+
+ /*
+ * Test byte-wise until cp is properly aligned for a long pointer.
+ */
+ while (--cnt >= 0 && !laligned(cp)) {
+ if (*cp++ == uval)
+ return ((char *)--cp);
+ }
+ cnt++;
+
+ /*
+ * The magic mask is a long word where all carry bits a clear.
+ * This are bits 8, 16, 24 ...
+ * In addition, the top bit is not set (e.g bit 31 or 63). The magic
+ * mask will look this way:
+ *
+ * bits: 01111110 11111110 ... 11111110 11111111
+ * bytes: AAAAAAAA BBBBBBBB ... CCCCCCCC DDDDDDDD
+ *
+ * If we add anything to this magic number, no carry bit will change if
+ * it is the first carry bit left to a 0 byte. Adding anything != 0
+ * to the magic number will just turn the carry bit left to the byte
+ * but does not propagate any further.
+ */
+#if SIZE_LONG == 4
+ magic_mask = 0x7EFEFEFFL;
+#else
+#if SIZE_LONG == 8
+ magic_mask = 0x7EFEFEFEFEFEFEFFL;
+#else
+ /*
+ * #error will not work for all compilers (e.g. sunos4)
+ * The following line will abort compilation on all compilers
+ * if none of the above is defines. And that's what we want.
+ */
+ error SIZE_LONG has unknown value
+#endif
+#endif
+
+ lmask = val & 0xFF;
+ lmask |= lmask << 8;
+ lmask |= lmask << 16;
+#if SIZE_LONG > 4
+ lmask |= lmask << 32;
+#endif
+#if SIZE_LONG > 8
+ error SIZE_LONG has unknown value
+#endif
+ for (lp = (const Ulong *)cp; cnt >= sizeof (long); cnt -= sizeof (long)) {
+ /*
+ * We are not looking for 0 bytes so we need to xor with the
+ * long mask of repeated bytes. If any of the bytes matches our
+ * wanted char, we will create a 0 byte in the current long.
+ * But how will we find if at least one byte in a long is zero?
+ *
+ * If we add 'magic_mask' and any of the holes in the magic
+ * mask do not change, we most likely found a 0 byte in the
+ * long word. It is only a most likely match because if bits
+ * 24..30 (ot bits 56..62) are 0 but bit 31 (or bit 63) is set
+ * we will believe that we found a match but there is none.
+ * This will happen if there is 0x80nnnnnn / 0x80nnnnnnnnnnnnnn
+ */
+ lval = (*lp++ ^ lmask); /* create 0 byte on match */
+ lval = (lval + magic_mask) ^ ~lval; /* set bits unchanged by +*/
+ if ((lval & ~magic_mask) != 0) { /* a magic hole was set */
+ /*
+ * If any of the hole bits did not change by addition,
+ * we most likely had a match.
+ * If this was a correct match, find the matching byte.
+ */
+ cp = (const Uchar *)(lp - 1);
+
+ if (cp[0] == uval)
+ return ((char *)cp);
+ if (cp[1] == uval)
+ return ((char *)&cp[1]);
+ if (cp[2] == uval)
+ return ((char *)&cp[2]);
+ if (cp[3] == uval)
+ return ((char *)&cp[3]);
+#if SIZE_LONG > 4
+ if (cp[4] == uval)
+ return ((char *)&cp[4]);
+ if (cp[5] == uval)
+ return ((char *)&cp[5]);
+ if (cp[6] == uval)
+ return ((char *)&cp[6]);
+ if (cp[7] == uval)
+ return ((char *)&cp[7]);
+#endif
+#if SIZE_LONG > 8
+ error SIZE_LONG has unknown value
+#endif
+ }
+ }
+
+ for (cp = (const Uchar *)lp; --cnt >= 0; ) {
+ if (*cp++ == uval)
+ return ((char *)--cp);
+ }
+ return ((char *)NULL);
+}