string: memstring functions
authorMarko Kreen <[email protected]>
Sun, 22 Jun 2014 14:37:49 +0000 (17:37 +0300)
committerMarko Kreen <[email protected]>
Fri, 27 Jun 2014 13:56:02 +0000 (16:56 +0300)
doc/mainpage.dox
m4/usual.m4
test/test_string.c
usual/bytemap.h [new file with mode: 0644]
usual/string.c
usual/string.h

index d2fae4223bf747138bf02e0bcc267a82c57537b4..6c4f2d04e63abea2a083152cf172e5acc128177c 100644 (file)
@@ -55,6 +55,7 @@
  * <tr><td>  <usual/strpool.h>       </td><td>  Refcounted strings   </td></tr>
  * <tr><th colspan=2>  Data Processing  </th></tr>
  * <tr><td>  <usual/bits.h>          </td><td>  Bit arithmetic   </td></tr>
+ * <tr><td>  <usual/bytemap.h>       </td><td>  Byte processing   </td></tr>
  * <tr><td>  <usual/cfparser.h>      </td><td>  Config parser   </td></tr>
  * <tr><td>  <usual/endian.h>        </td><td>  Endianess conversion   </td></tr>
  * <tr><td>  <usual/misc.h>          </td><td>  Misc arithmetic   </td></tr>
index 56bf8ad92fbd3b7fd21de03ddff9024e95921cf8..cf7f46d9465554d8b425c57874909d6ecba6da70 100644 (file)
@@ -201,7 +201,7 @@ dnl
 AC_DEFUN([AC_USUAL_FUNCTION_CHECK], [
 ### Functions provided if missing
 dnl AC_CHECK_FUNCS(basename dirname) # unstable, provide always
-AC_CHECK_FUNCS(strlcpy strlcat getpeereid sigaction sigqueue)
+AC_CHECK_FUNCS(strlcpy strlcat memmem getpeereid sigaction sigqueue)
 AC_CHECK_FUNCS(inet_ntop inet_pton poll getline memrchr regcomp)
 AC_CHECK_FUNCS(err errx warn warnx getprogname setprogname)
 AC_CHECK_FUNCS(posix_memalign memalign valloc)
index b3219618b59c74c15b06078b26a46f6170e57561..cf4e3c0ca30f00d24e11123cc2c3c36b63d600dd 100644 (file)
@@ -99,6 +99,49 @@ static void test_memrchr(void *p)
 end:;
 }
 
+/*
+ * memmem
+ */
+
+static int zmemm(const char *s, const char *q)
+{
+       char *r = memmem(s, strlen(s), q, strlen(q));
+       return r ? (r - s) : -1;
+}
+
+static void test_memmem(void *p)
+{
+       int_check(zmemm("qwe", ""), 0);
+       int_check(zmemm("qwe", "q"), 0);
+       int_check(zmemm("qwe", "w"), 1);
+       int_check(zmemm("qwe", "e"), 2);
+       int_check(zmemm("qwe", "x"), -1);
+       int_check(zmemm("qwe", "qw"), 0);
+       int_check(zmemm("qwe", "we"), 1);
+       int_check(zmemm("qwe", "qx"), -1);
+       int_check(zmemm("qwe", "wx"), -1);
+       int_check(zmemm("qwe", "ex"), -1);
+       int_check(zmemm("qwe", "qwe"), 0);
+       int_check(zmemm("qwe", "qwx"), -1);
+       int_check(zmemm("qwe", "qxe"), -1);
+       int_check(zmemm("qwe", "xwe"), -1);
+       int_check(zmemm("qweqweza", "qweza"), 3);
+       int_check(zmemm("qweqweza", "weza"), 4);
+       int_check(zmemm("qweqweza", "eza"), 5);
+       int_check(zmemm("qweqweza", "za"), 6);
+       int_check(zmemm("qweqweza", "a"), 7);
+       int_check(zmemm("qweqweza", "qwez"), 3);
+       int_check(zmemm("qweqweza", "wez"), 4);
+       int_check(zmemm("qweqweza", "ez"), 5);
+       int_check(zmemm("qweqweza", "z"), 6);
+       int_check(zmemm("qweqwez", "qweza"), -1);
+       int_check(zmemm("qweqwez", "weza"), -1);
+       int_check(zmemm("qweqwez", "eza"), -1);
+       int_check(zmemm("qweqwez", "za"), -1);
+       int_check(zmemm("qweqwez", "a"), -1);
+end:;
+}
+
 /*
  * basename
  */
@@ -244,6 +287,56 @@ static void test_wlist(void *p)
 end:;
 }
 
+static void test_mempbrk(void *z)
+{
+       const char *p = "0123456789";
+       tt_assert(mempbrk(p, 10, "", 0) == NULL);
+       tt_assert(mempbrk(p, 10, "a", 0) == NULL);
+       tt_assert(mempbrk(p, 10, "ab", 0) == NULL);
+       tt_assert(mempbrk(p, 10, "abc", 0) == NULL);
+       tt_assert(mempbrk(p, 10, "1", 1) == p+1);
+       tt_assert(mempbrk(p, 10, "12", 2) == p+1);
+       tt_assert(mempbrk(p, 10, "21", 2) == p+1);
+       tt_assert(mempbrk(p, 10, "123", 3) == p+1);
+       tt_assert(mempbrk(p, 10, "321", 3) == p+1);
+       tt_assert(mempbrk(p, 11, "abc\0", 4) == p+10);
+end:;
+}
+
+static void test_memcspn(void *z)
+{
+       int_check(memcspn("qwe", 3, "", 0), 3);
+       int_check(memcspn("qwe", 3, "w", 1), 1);
+       int_check(memcspn("qwe", 3, "z", 1), 3);
+       int_check(memcspn("qwe", 3, "we", 2), 1);
+       int_check(memcspn("qwe", 3, "eq", 2), 0);
+       int_check(memcspn("qwe", 3, "zx", 2), 3);
+       int_check(memcspn("qwe", 3, "wez", 3), 1);
+       int_check(memcspn("qwe", 3, "ewz", 3), 1);
+       int_check(memcspn("qwe", 3, "zxa", 3), 3);
+       int_check(memcspn("qwe", 3, "weza", 4), 1);
+       int_check(memcspn("qwe", 3, "azew", 4), 1);
+       int_check(memcspn("qwe", 3, "zxab", 4), 3);
+end:;
+}
+
+static void test_memspn(void *z)
+{
+       const char *d = "0123456789";
+       int_check(memspn(d, 10, "", 0), 0);
+       int_check(memspn(d, 10, "0", 1), 1);
+       int_check(memspn(d, 10, "1", 1), 0);
+       int_check(memspn(d, 10, "23", 2), 0);
+       int_check(memspn(d, 10, "01", 2), 2);
+       int_check(memspn(d, 10, "456", 3), 0);
+       int_check(memspn(d, 10, "012", 3), 3);
+       int_check(memspn(d, 10, "4567", 4), 0);
+       int_check(memspn(d, 10, "0123", 4), 4);
+       int_check(memspn(d, 10, d, 10), 10);
+       int_check(memspn(d, 11, d, 11), 11);
+end:;
+}
+
 /*
  * Describe
  */
@@ -253,6 +346,10 @@ struct testcase_t string_tests[] = {
        { "strlcat", test_strlcat },
        { "strerror_r", test_strerror_r },
        { "memrchr", test_memrchr },
+       { "memmem", test_memmem },
+       { "mempbrk", test_mempbrk },
+       { "memcspn", test_memcspn },
+       { "memspn", test_memspn},
        { "basename", test_basename },
        { "dirname", test_dirname },
        { "strlist", test_strlist },
diff --git a/usual/bytemap.h b/usual/bytemap.h
new file mode 100644 (file)
index 0000000..e1e5265
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * byte map
+ *
+ * Copyright (c) 2014  Marko Kreen
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * @file
+ *
+ * Map 256 byte values to bit or int.
+ */
+#ifndef _USUAL_BYTEMAP_H_
+#define _USUAL_BYTEMAP_H_
+
+#define BITMAP256_SHIFT        5
+#define BITMAP256_MASK ((1 << BITMAP256_SHIFT) - 1)
+
+/**
+ * Bitmap of 256 bits.
+ */
+struct Bitmap256 {
+       uint32_t bmap[256 / 32];
+};
+
+/**
+ * Clear bitmap.
+ */
+static inline void bitmap256_init(struct Bitmap256 *bmap)
+{
+       memset(bmap, 0, sizeof(*bmap));
+}
+
+/**
+ * Set one bit.
+ */
+static inline void bitmap256_set(struct Bitmap256 *bmap, uint8_t byte)
+{
+       bmap->bmap[byte >> BITMAP256_SHIFT] |= 1 << (byte & BITMAP256_MASK);
+}
+
+/**
+ * Check if bit is set.
+ */
+static inline bool bitmap256_is_set(const struct Bitmap256 *bmap, uint8_t byte)
+{
+       return bmap->bmap[byte >> BITMAP256_SHIFT] & (1 << (byte & BITMAP256_MASK));
+}
+
+/*
+ * Declare const value of bytemap
+ */
+
+/**
+ * Use C preprocessor to fill Bitmap256.
+ *
+ * Usage:
+ * @code
+ * #define check_isdigit(c) ((c) >= '0' && (c) <= '9')
+ * static const struct Bitmap256 map_isdigit = BITMAP256_CONST(check_isdigit);
+ * @endcode
+ */
+#define BITMAP256_CONST(check) {{ \
+       _BMAP256_V32(check,0), _BMAP256_V32(check,32), _BMAP256_V32(check,64), _BMAP256_V32(check,96), \
+       _BMAP256_V32(check,128), _BMAP256_V32(check,160), _BMAP256_V32(check,192), _BMAP256_V32(check,224) }}
+#define _BMAP256_V32(ck,p) \
+       _BMAP256_V8(ck,(p)+0) | _BMAP256_V8(ck,(p)+8) | _BMAP256_V8(ck,(p)+16) | _BMAP256_V8(ck,(p)+24)
+#define _BMAP256_V8(ck,p) \
+       _BMAP256_BIT(ck,(p)+0) | _BMAP256_BIT(ck,(p)+1) | _BMAP256_BIT(ck,(p)+2) | _BMAP256_BIT(ck,(p)+3) | \
+       _BMAP256_BIT(ck,(p)+4) | _BMAP256_BIT(ck,(p)+5) | _BMAP256_BIT(ck,(p)+6) | _BMAP256_BIT(ck,(p)+7)
+#define _BMAP256_BIT(ck,p) (ck(p) ? (1 << ((p) & BMAP256_MASK)) : 0)
+
+/**
+ * Use C preprocessor to generate array of 256 values.
+ *
+ * Usage:
+ * @code
+ * #define my_hexval(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : ( \
+ *                       ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : ( \
+ *                       ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : -1 )))
+ * static const int map_hexval[] = INTMAP256_CONST(my_hexval);
+ * @endcode
+ */
+#define INTMAP256_CONST(map_value) { _INTMAP_V128(map_value,0), _INTMAP_V128(map_value,128) }
+#define _INTMAP_V128(mf,n) _INTMAP_V32(mf,(n)+0*32), _INTMAP_V32(mf,(n)+1*32), _INTMAP_V32(mf,(n)+2*32), _INTMAP_V32(mf,(n)+3*32)
+#define _INTMAP_V32(mf,n) _INTMAP_V8(mf,(n)+0*8), _INTMAP_V8(mf,(n)+1*8), _INTMAP_V8(mf,(n)+2*8), _INTMAP_V8(mf,(n)+3*8)
+#define _INTMAP_V8(mf,n) mf((n)+0), mf((n)+1), mf((n)+2), mf((n)+3), mf((n)+4), mf((n)+5), mf((n)+6), mf((n)+7)
+
+
+#endif
+
index 3246b97655c09118c0951eee06776344ca65f56c..e4f7f34547dbbe8649172242dc8f703a2a3fc363 100644 (file)
@@ -21,6 +21,7 @@
 #include <usual/mbuf.h>
 #include <usual/statlist.h>
 #include <usual/ctype.h>
+#include <usual/bytemap.h>
 
 #include <errno.h>
 
@@ -221,6 +222,31 @@ void *memrchr(const void *s, int c, size_t n)
 }
 #endif
 
+#ifndef HAVE_MEMMEM
+void *memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen)
+{
+       const uint8_t *s = haystack;
+       const uint8_t *q = needle;
+       const uint8_t *s2;
+       size_t i;
+
+       if (nlen == 0)
+               return (void *)haystack;
+       if (nlen > hlen)
+               return NULL;
+       s2 = memchr(haystack, *q, hlen);
+       if (!s2 || nlen == 1)
+               return (void *)s2;
+       for (i = s2 - s; i <= hlen - nlen; i++) {
+               if (s[i] == q[0] && s[i+1] == q[1]) {
+                       if (memcmp(s + i + 2, q + 2, nlen - 2) == 0)
+                               return (void *)(s + i);
+               }
+       }
+       return NULL;
+}
+#endif
+
 #ifndef HAVE_BASENAME
 const char *basename(const char *path)
 {
@@ -319,4 +345,61 @@ const char *usual_strerror_r(int e, char *dst, size_t dstlen)
        return dst;
 }
 
+void *mempbrk(const void *data, size_t dlen, const void *find, size_t flen)
+{
+       const uint8_t *s = data;
+       const uint8_t *fb = find;
+       size_t i;
+       struct Bitmap256 bmap;
+
+       if (flen == 0)
+               return NULL;
+       if (flen == 1)
+               return memchr(data, fb[0], dlen);
+
+       bitmap256_init(&bmap);
+       for (i = 0; i < flen; i++)
+               bitmap256_set(&bmap, fb[i]);
+       for (i = 0; i < dlen; i++) {
+               if (bitmap256_is_set(&bmap, s[i]))
+                       return (void *)(s + i);
+       }
+       return NULL;
+}
+
+size_t memspn(const void *data, size_t dlen, const void *accept, size_t alen)
+{
+       const uint8_t *s = data;
+       const uint8_t *fb = accept;
+       size_t i;
+       struct Bitmap256 bmap;
+
+       if (alen == 0)
+               return 0;
+       if (alen == 1) {
+               for (i = 0; i < dlen; i++)
+                       if (s[i] != fb[0])
+                               break;
+               return i;
+       }
+
+       bitmap256_init(&bmap);
+       for (i = 0; i < alen; i++)
+               bitmap256_set(&bmap, fb[i]);
+       for (i = 0; i < dlen; i++) {
+               if (!bitmap256_is_set(&bmap, s[i]))
+                       break;
+       }
+       return i;
+}
+
+size_t memcspn(const void *data, size_t dlen, const void *reject, size_t rlen)
+{
+       const void *p;
+
+       p = mempbrk(data, dlen, reject, rlen);
+       if (p != NULL)
+               return (char *)p - (char *)data;
+       return dlen;
+}
 
index f6427236a41198ee4f95057946db63558ee7889f..8fce6831e9f6c0ba38728bdfb305f322273956d6 100644 (file)
@@ -72,6 +72,21 @@ size_t strlcat(char *dst, const char *src, size_t n);
 void *memrchr(const void *s, int c, size_t n);
 #endif
 
+#ifndef HAVE_MEMMEM
+#define memmem(a,b,c,d) usual_memmem(a,b,c,d)
+/** Compat: find memory area */
+void *memmem(const void *s, size_t slen, const void *q, size_t qlen);
+#endif
+
+/** Return position to first byte that is in 'find'. */
+void *mempbrk(const void *data, size_t dlen, const void *find, size_t flen);
+
+/** Return number of bytes where none are in reject. */
+size_t memcspn(const void *data, size_t dlen, const void *reject, size_t rlen);
+
+/** Return number of bytes where all are in accept. */
+size_t memspn(const void *data, size_t dlen, const void *accept, size_t alen);
+
 #ifndef HAVE_BASENAME
 #undef basename
 #define basename(a) usual_basename(a)