From: Marko Kreen Date: Sun, 22 Jun 2014 14:37:49 +0000 (+0300) Subject: string: memstring functions X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=98655be803733da090074cf4d8f7ae355990f142;p=libusual.git string: memstring functions --- diff --git a/doc/mainpage.dox b/doc/mainpage.dox index d2fae42..6c4f2d0 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -55,6 +55,7 @@ * Refcounted strings * Data Processing * Bit arithmetic + * Byte processing * Config parser * Endianess conversion * Misc arithmetic diff --git a/m4/usual.m4 b/m4/usual.m4 index 56bf8ad..cf7f46d 100644 --- a/m4/usual.m4 +++ b/m4/usual.m4 @@ -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) diff --git a/test/test_string.c b/test/test_string.c index b321961..cf4e3c0 100644 --- a/test/test_string.c +++ b/test/test_string.c @@ -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 index 0000000..e1e5265 --- /dev/null +++ b/usual/bytemap.h @@ -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 + diff --git a/usual/string.c b/usual/string.c index 3246b97..e4f7f34 100644 --- a/usual/string.c +++ b/usual/string.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -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; +} diff --git a/usual/string.h b/usual/string.h index f642723..8fce683 100644 --- a/usual/string.h +++ b/usual/string.h @@ -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)