From 1054a875c7f96e5799c8bfbf8a73e41dd064b606 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 12 Aug 2018 22:02:07 +0200 Subject: Add memrmem, strrstr, and strrcasestr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 3 +++ README | 10 ++++++++ TODO | 5 ++-- libsimple.h | 21 +++++++++++++++++ memrmem.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ strrcasestr.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ strrstr.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 memrmem.c create mode 100644 strrcasestr.c create mode 100644 strrstr.c diff --git a/Makefile b/Makefile index 2ffbaad..ae5830b 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ OBJ =\ memends.o\ memmem.o\ memrchr.o\ + memrmem.o\ memstarts.o\ multimespec.o\ multimeval.o\ @@ -39,6 +40,8 @@ OBJ =\ strchrnul.o\ strends.o\ strndup.o\ + strrcasestr.o\ + strrstr.o\ strstarts.o\ strtotimespec.o\ strtotimeval.o\ diff --git a/README b/README index 28dfac8..5310275 100644 --- a/README +++ b/README @@ -123,6 +123,10 @@ The following functions are defined (some as inline functions): Finds the first occurrence of `t` in `s`. Length of `s` is `sn`. Length of `t` is `tn`. + void *libsimple_memrmem(const void *s, size_t sn, const void *t, size_t tn) + Finds the last occurrence of `t` in `s`. + Length of `s` is `sn`. Length of `t` is `tn`. + int libsimple_memstarts(const void *s, size_t sn, const void *t, size_t tn) Returns 1 if `s` starts with `t`, 0 otherwise. Length of `s` is `sn`. Length of `t` is `tn`. @@ -131,6 +135,9 @@ The following functions are defined (some as inline functions): Returns 1 if `s` ends with `t`, 0 otherwise. Length of `s` is `sn`. Length of `t` is `tn`. + char *libsimple_strrstr(const char *s, const char *t) + Finds the last occurrence of `t` in `s`. + int libsimple_strstarts(const char *s, const char *t) Returns 1 if `s` starts with `t`, 0 otherwise. @@ -146,6 +153,9 @@ The following functions are defined (some as inline functions): char *libsimple_strcasestr(const char *, const char *) Like strstr except case-insensitive. + char *libsimple_strrcasestr(const char *, const char *) + Like strrstr except case-insensitive. + int libsimple_streq(const char *a, const char *b) !strncmp(a, b) diff --git a/TODO b/TODO index 2f0feae..2b24a41 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ -memrmem -strrstr strnstr +strrnstr +strncasestr +strrncasestr diff --git a/libsimple.h b/libsimple.h index 8a6395f..85f741f 100644 --- a/libsimple.h +++ b/libsimple.h @@ -673,6 +673,13 @@ void *libsimple_memmem(const void *, size_t, const void *, size_t); #endif +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memrmem(const void *, size_t, const void *, size_t); +#ifndef memrmem +# define memrmem libsimple_memrmem +#endif + + _LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) int libsimple_memstarts(const void *, size_t, const void *, size_t); #ifndef memstarts @@ -687,6 +694,13 @@ int libsimple_memends(const void *, size_t, const void *, size_t); #endif +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strrstr(const char *, const char *); +#ifndef strrstr +# define strrstr libsimple_strrstr +#endif + + _LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) int libsimple_strstarts(const char *, const char *); #ifndef strstarts @@ -722,6 +736,13 @@ char *libsimple_strcasestr(const char *, const char *); #endif +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) +char *libsimple_strrcasestr(const char *, const char *); +#ifndef strrcasestr +# define strrcasestr libsimple_strrcasestr +#endif + + _LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__))) static inline int streq(const char *__a, const char *__b) { return !strcmp(__a, __b); } /* TODO test */ diff --git a/memrmem.c b/memrmem.c new file mode 100644 index 0000000..713ba34 --- /dev/null +++ b/memrmem.c @@ -0,0 +1,57 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" + + +void * +libsimple_memrmem(const void *hay_, size_t hayn, const void *sub_, size_t subn) +{ + char *hay = (void *)hay_, *start; + const char *sub = sub_; + + if (!subn) + return hay; + if (hayn < subn) + return NULL; + if (subn == 1) + return libsimple_memrchr(hay, *sub, hayn); + + start = hay; + hay = &hay[hayn - subn]; + do { + if (*hay == *sub && !memcmp(hay, sub, subn)) + return hay; + } while (hay-- != start); + + return NULL; +} + + +#ifdef TEST +#include + +int +main(void) +{ + assert(!strcmp(libsimple_memrmem("test", 4, "test", 4), "test")); + assert(!strcmp(libsimple_memrmem("", 0, "", 0), "")); + assert(!strcmp(libsimple_memrmem("test", 4, "", 0), "")); + assert(!libsimple_memrmem("", 0, "test", 4)); + assert(!libsimple_memrmem("t", 1, "test", 4)); + assert(!strcmp(libsimple_memrmem("test", 4, "t", 1), "t")); + assert(!strcmp(libsimple_memrmem("test", 4, "e", 1), "est")); + assert(!strcmp(libsimple_memrmem("test", 4, "s", 1), "st")); + assert(!libsimple_memrmem("test", 4, "x", 1)); + assert(!strcmp(libsimple_memrmem("test", 4, "te", 2), "test")); + assert(!strcmp(libsimple_memrmem("test", 4, "es", 2), "est")); + assert(!strcmp(libsimple_memrmem("test", 4, "st", 2), "st")); + assert(!strcmp(libsimple_memrmem("test", 5, "t", 2), "t")); + assert(!libsimple_memrmem("test", 4, "xx", 2)); + assert(!strcmp(libsimple_memrmem("abc", 3, "c", 1), "c")); + assert(!strcmp(libsimple_memrmem("abc", 3, "bc", 2), "bc")); + assert(!strcmp(libsimple_memrmem("abc", 3, "abc", 3), "abc")); + assert(!libsimple_memrmem("abc", 3, "abc", 4)); + assert(!strcmp(libsimple_memrmem("abcabc", 6, "bc", 2), "bc")); + return 0; +} + +#endif diff --git a/strrcasestr.c b/strrcasestr.c new file mode 100644 index 0000000..9bd40b3 --- /dev/null +++ b/strrcasestr.c @@ -0,0 +1,75 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" + + +char * +libsimple_strrcasestr(const char *h_, const char *n) +{ + char *h = *(char **)(void *)&h_; + size_t hn = strlen(h); + size_t nn = strlen(n); + if (hn < nn) + return NULL; + for (h += hn -= nn; hn--; h--) + if (!strcasecmp(h, n)) + return h; + return NULL; +} + + +#ifdef TEST +#include + +int +main(void) +{ + assert(!strcmp(libsimple_strrcasestr("", ""), "")); + assert(!strcmp(libsimple_strrcasestr("test", ""), "")); + assert(!libsimple_strrcasestr("", "")); + assert(!libsimple_strrcasestr("t", "t")); + assert(!strcmp(libsimple_strrcasestr("test", "t"), "t")); + assert(!strcmp(libsimple_strrcasestr("test", "e"), "est")); + assert(!strcmp(libsimple_strrcasestr("test", "s"), "st")); + assert(!libsimple_strrcasestr("test", "x")); + assert(!strcmp(libsimple_strrcasestr("test", "te"), "test")); + assert(!strcmp(libsimple_strrcasestr("test", "es"), "est")); + assert(!strcmp(libsimple_strrcasestr("test", "st"), "st")); + assert(!libsimple_strrcasestr("test", "xx")); + assert(!strcmp(libsimple_strrcasestr("abc", "c"), "c")); + assert(!strcmp(libsimple_strrcasestr("abc", "bc"), "bc")); + assert(!strcmp(libsimple_strrcasestr("abc", "abc"), "abc")); + assert(!strcmp(libsimple_strrcasestr("abcabc", "bc"), "bc")); + + assert(!strcmp(libsimple_strrcasestr("TEST", ""), "")); + assert(!libsimple_strrcasestr("T", "test")); + assert(!strcmp(libsimple_strrcasestr("TEST", "t"), "T")); + assert(!strcmp(libsimple_strrcasestr("TEST", "e"), "EST")); + assert(!strcmp(libsimple_strrcasestr("TEST", "s"), "ST")); + assert(!libsimple_strrcasestr("TEST", "x")); + assert(!strcmp(libsimple_strrcasestr("TEST", "te"), "TEST")); + assert(!strcmp(libsimple_strrcasestr("TEST", "es"), "EST")); + assert(!strcmp(libsimple_strrcasestr("TEST", "st"), "ST")); + assert(!libsimple_strrcasestr("TEST", "xx")); + assert(!strcmp(libsimple_strrcasestr("ABC", "c"), "C")); + assert(!strcmp(libsimple_strrcasestr("ABC", "bc"), "BC")); + assert(!strcmp(libsimple_strrcasestr("ABC", "abc"), "ABC")); + assert(!strcmp(libsimple_strrcasestr("ABCABC", "bc"), "BC")); + + assert(!libsimple_strrcasestr("", "TEST")); + assert(!libsimple_strrcasestr("t", "TEST")); + assert(!strcmp(libsimple_strrcasestr("test", "T"), "t")); + assert(!strcmp(libsimple_strrcasestr("test", "E"), "est")); + assert(!strcmp(libsimple_strrcasestr("test", "S"), "st")); + assert(!libsimple_strrcasestr("test", "X")); + assert(!strcmp(libsimple_strrcasestr("test", "TE"), "test")); + assert(!strcmp(libsimple_strrcasestr("test", "ES"), "est")); + assert(!strcmp(libsimple_strrcasestr("test", "ST"), "st")); + assert(!libsimple_strrcasestr("test", "XX")); + assert(!strcmp(libsimple_strrcasestr("abc", "C"), "c")); + assert(!strcmp(libsimple_strrcasestr("abc", "BC"), "bc")); + assert(!strcmp(libsimple_strrcasestr("abc", "ABC"), "abc")); + assert(!strcmp(libsimple_strrcasestr("abcabc", "BC"), "bc")); + return 0; +} + +#endif diff --git a/strrstr.c b/strrstr.c new file mode 100644 index 0000000..5d64744 --- /dev/null +++ b/strrstr.c @@ -0,0 +1,70 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" + + +char * +libsimple_strrstr(const char *hay, const char *sub) +{ + return libsimple_memrmem(hay, strlen(hay), sub, strlen(sub)); +} + + +#ifdef TEST +#include + +int +main(void) +{ + assert(!strcmp(libsimple_strrstr("test", "test"), "test")); + assert(!strcmp(libsimple_strrstr("", ""), "")); + assert(!strcmp(libsimple_strrstr("test", ""), "")); + assert(!libsimple_strrstr("", "test")); + assert(!libsimple_strrstr("t", "test")); + assert(!strcmp(libsimple_strrstr("test", "t"), "t")); + assert(!strcmp(libsimple_strrstr("test", "e"), "est")); + assert(!strcmp(libsimple_strrstr("test", "s"), "st")); + assert(!libsimple_strrstr("test", "x")); + assert(!strcmp(libsimple_strrstr("test", "te"), "test")); + assert(!strcmp(libsimple_strrstr("test", "es"), "est")); + assert(!strcmp(libsimple_strrstr("test", "st"), "st")); + assert(!libsimple_strrstr("test", "xx")); + assert(!strcmp(libsimple_strrstr("abc", "c"), "c")); + assert(!strcmp(libsimple_strrstr("abc", "bc"), "bc")); + assert(!strcmp(libsimple_strrstr("abc", "abc"), "abc")); + assert(!strcmp(libsimple_strrstr("abcabc", "bc"), "bc")); + + assert(!strcmp(libsimple_strrcasestr("TEST", "test"), "TEST")); + assert(!strcmp(libsimple_strrcasestr("TEST", ""), "")); + assert(!libsimple_strrcasestr("T", "test")); + assert(!strcmp(libsimple_strrcasestr("TEST", "t"), "T")); + assert(!strcmp(libsimple_strrcasestr("TEST", "e"), "EST")); + assert(!strcmp(libsimple_strrcasestr("TEST", "s"), "ST")); + assert(!libsimple_strrcasestr("TEST", "x")); + assert(!strcmp(libsimple_strrcasestr("TEST", "te"), "TEST")); + assert(!strcmp(libsimple_strrcasestr("TEST", "es"), "EST")); + assert(!strcmp(libsimple_strrcasestr("TEST", "st"), "ST")); + assert(!libsimple_strrcasestr("TEST", "xx")); + assert(!strcmp(libsimple_strrcasestr("ABC", "c"), "C")); + assert(!strcmp(libsimple_strrcasestr("ABC", "bc"), "BC")); + assert(!strcmp(libsimple_strrcasestr("ABC", "abc"), "ABC")); + assert(!strcmp(libsimple_strrcasestr("ABCABC", "bc"), "BC")); + + assert(!strcmp(libsimple_strrcasestr("test", "TEST"), "test")); + assert(!libsimple_strrcasestr("", "TEST")); + assert(!libsimple_strrcasestr("t", "TEST")); + assert(!strcmp(libsimple_strrcasestr("test", "T"), "t")); + assert(!strcmp(libsimple_strrcasestr("test", "E"), "est")); + assert(!strcmp(libsimple_strrcasestr("test", "S"), "st")); + assert(!libsimple_strrcasestr("test", "X")); + assert(!strcmp(libsimple_strrcasestr("test", "TE"), "test")); + assert(!strcmp(libsimple_strrcasestr("test", "ES"), "est")); + assert(!strcmp(libsimple_strrcasestr("test", "ST"), "st")); + assert(!libsimple_strrcasestr("test", "XX")); + assert(!strcmp(libsimple_strrcasestr("abc", "C"), "c")); + assert(!strcmp(libsimple_strrcasestr("abc", "BC"), "bc")); + assert(!strcmp(libsimple_strrcasestr("abc", "ABC"), "abc")); + assert(!strcmp(libsimple_strrcasestr("abcabc", "BC"), "bc")); + return 0; +} + +#endif -- cgit v1.2.3-70-g09d2