From 58818a2b5d3042426d57846627b476b5f74591b8 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 17 Nov 2018 11:13:47 +0100 Subject: Add memelemscan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 1 + libsimple/mem.h | 20 ++++++++++ man0/libsimple.h.0 | 7 ++++ man3/libsimple_memelem.3 | 1 + man3/libsimple_memelemscan.3 | 87 ++++++++++++++++++++++++++++++++++++++++ man3/libsimple_memscan.3 | 4 +- man3/memelemscan.3libsimple | 1 + memelem.c | 3 +- memelemscan.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ memrelem.c | 3 +- 10 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 man3/libsimple_memelemscan.3 create mode 120000 man3/memelemscan.3libsimple create mode 100644 memelemscan.c diff --git a/Makefile b/Makefile index 3428753..5944817 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,7 @@ OBJ =\ memcasestarts.o\ memdup.o\ memelem.o\ + memelemscan.o\ memends.o\ memeqlen.o\ memisutf8.o\ diff --git a/libsimple/mem.h b/libsimple/mem.h index dacc78c..67834bc 100644 --- a/libsimple/mem.h +++ b/libsimple/mem.h @@ -268,6 +268,26 @@ void *libsimple_memelem(const void *, size_t, const void *, size_t); #endif +/** + * Finds the first element in an array, the comparison is case-sensitive + * + * @param haystack The array of bytes to search + * @param nhaystack The length of `haystack`, divided by `needle` + * @param needle The substring to search for + * @param nneedle The length of `needle` + * @return `haystack` with a minimal offset such that, + * `!memcmp(r, needle, nneedle)` where `r` is the + * returned pointer and such that `(r - haystack) % nneedle == 0`, + * `(void *)&((char *)haystack)[nhaystack * nneedle]` + * if no such offset exists + */ +_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__))) +void *libsimple_memelemscan(const void *, size_t, const void *, size_t); +#ifndef memelemscan +# define memelemscan libsimple_memelemscan +#endif + + /** * Finds the last element in an array, the comparison is case-sensitive * diff --git a/man0/libsimple.h.0 b/man0/libsimple.h.0 index 7cb93dd..d3c018d 100644 --- a/man0/libsimple.h.0 +++ b/man0/libsimple.h.0 @@ -541,6 +541,13 @@ Version of that operate on multibyte units rather than simple bytes. +.TP +.BR libsimple_memelemscan (3) +Version of +.BR memscan (3) +that operate on multibyte units +rather than simple bytes. + .TP .BR libsimple_memends (3), .RS 0 diff --git a/man3/libsimple_memelem.3 b/man3/libsimple_memelem.3 index 833e246..6eb3c0b 100644 --- a/man3/libsimple_memelem.3 +++ b/man3/libsimple_memelem.3 @@ -79,6 +79,7 @@ None. .SH BUGS None. .SH SEE ALSO +.BR libsimple_memelemscan (3), .BR libsimple_memrelem (3), .BR libsimple_memmem (3), .BR memchr (3) diff --git a/man3/libsimple_memelemscan.3 b/man3/libsimple_memelemscan.3 new file mode 100644 index 0000000..de70105 --- /dev/null +++ b/man3/libsimple_memelemscan.3 @@ -0,0 +1,87 @@ +.TH LIBSIMPLE_MEMELEMSCAN 3 2018-11-17 libsimple +.SH NAME +libsimple_memelemscan \- find aligned byte string in memory +.SH SYNOPSIS +.nf +#include + +void *libsimple_memelemscan(const void *\fIhaystack\fP, size_t \fInhaystack\fP, const void *\fIneedle\fP, size_t \fInneedle\fP); + +#ifndef memelemscan +# define memelemscan libsimple_memelemscan +#endif +.fi +.PP +Link with +.IR \-lsimple . +.SH DESCRIPTION +The +.BR libsimple_memelemscan () +function scans the memory segment +.IR haystack , +with the size +.IR nhaystack*nneedle , +for the first occurence of the byte string +.I needle +with the size +.IR nneedle , +and with an offset equivalent to zero modulo +.IR nneedle . +If no such character exist in the memory +segment, the memory segment's end is returned. +.PP +The comparison is case-sensitive. +.SH RETURN VALUE +The +.BR libsimple_memelemscan () +function returns the pointer +.I s +with a minimal offset such that +.IR !memcmp(r,needle,nneedle) , +where +.I r +is the returned pointer, and such that +the offset is equivalent to zero modulo +.IR nneedle . +If no such offset exists, +.I (void *)&((char *)haystack)[nhaystack*nneedle] +is returned. +.SH ERRORS +The +.BR libsimple_memelemscan () +function cannot fail. +.SH ATTRIBUTES +For an explanation of the terms used in this section, see +.BR attributes (7). +.TS +allbox; +lb lb lb +l l l. +Interface Attribute Value +T{ +.BR libsimple_memelemscan () +T} Thread safety MT-Safe +T{ +.BR libsimple_memelemscan () +T} Async-signal safety AS-Safe +T{ +.BR libsimple_memelemscan () +T} Async-cancel safety AC-Safe +.TE +.SH EXAMPLES +None. +.SH APPLICATION USAGE +None. +.SH RATIONALE +None. +.SH FUTURE DIRECTIONS +None. +.SH NOTES +None. +.SH BUGS +None. +.SH SEE ALSO +.BR libsimple_memelem (3), +.BR libsimple_memrelem (3), +.BR libsimple_memmem (3), +.BR libsimple_memchrscan (3) diff --git a/man3/libsimple_memscan.3 b/man3/libsimple_memscan.3 index c9db7da..0c5d14a 100644 --- a/man3/libsimple_memscan.3 +++ b/man3/libsimple_memscan.3 @@ -25,6 +25,8 @@ for the first occurence of the byte .I c (it is converted to a .BR char ). +If no such character exist in the memory +segment, the memory segment's end is returned. .PP The comparison is case-sensitive. .SH RETURN VALUE @@ -38,7 +40,7 @@ where .I r is the returned pointer. If no such offset exists, -.B NULL +.I &r[n] is returned. .SH ERRORS The diff --git a/man3/memelemscan.3libsimple b/man3/memelemscan.3libsimple new file mode 120000 index 0000000..3c612db --- /dev/null +++ b/man3/memelemscan.3libsimple @@ -0,0 +1 @@ +libsimple_memelemscan.3 \ No newline at end of file diff --git a/memelem.c b/memelem.c index 43cb298..3881832 100644 --- a/memelem.c +++ b/memelem.c @@ -52,7 +52,6 @@ libsimple_memelem(const void *hay_, size_t hayn, const void *sub_, size_t subn) next:; } break; - } } @@ -70,7 +69,7 @@ main(void) assert(!strcmpnul(libsimple_memelem("12345634", 0, "", 0), "12345634")); assert(!strcmpnul(libsimple_memelem("12345634", 8, "3", 1), "345634")); - assert(!libsimple_memelem("12345634", 8, "x", 1));; + assert(!libsimple_memelem("12345634", 8, "x", 1)); assert(!strcmpnul(libsimple_memelem("13456342", 8, "3", 1), "3456342")); assert(!libsimple_memelem("12345634", 0, "3", 1)); diff --git a/memelemscan.c b/memelemscan.c new file mode 100644 index 0000000..744989b --- /dev/null +++ b/memelemscan.c @@ -0,0 +1,94 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsimple.h" +#ifndef TEST + + +void * +libsimple_memelemscan(const void *hay_, size_t hayn, const void *sub_, size_t subn) +{ + if (!subn) + return (void *)hay_; + + switch (subn) { + case 1: + return libsimple_memscan(hay_, *(char *)sub_, hayn); + case 2: + { + uint16_t *hay = (void *)hay_; + uint16_t sub = *(uint16_t *)sub_; + for (; hayn-- && *hay != sub; hay++); + return hay; + } + case 4: + { + uint32_t *hay = (void *)hay_; + uint32_t sub = *(uint32_t *)sub_; + for (; hayn-- && *hay != sub; hay++); + return hay; + } + case 8: + { + uint64_t *hay = (void *)hay_; + uint64_t sub = *(uint64_t *)sub_; + for (; hayn-- && *hay != sub; hay++); + return hay; + } + default: + { + char *hay = (void *)hay_; + const char *sub = sub_; + size_t i; + for (; hayn--; hay += subn) { + for (i = 0; i < subn; i++) + if (hay[i] != sub[i]) + goto next; + return hay; + next:; + } + return hay; + } + } + + return NULL; +} + + +#else +#include "test.h" + +int +main(void) +{ + assert(!strcmpnul(libsimple_memelemscan("12345634", 8, "", 0), "12345634")); + assert(!strcmpnul(libsimple_memelemscan("12345634", 0, "", 0), "12345634")); + + assert(!strcmpnul(libsimple_memelemscan("12345634", 8, "3", 1), "345634")); + assert(!strcmpnul(libsimple_memelemscan("12345634", 8, "x", 1), "")); + assert(!strcmpnul(libsimple_memelemscan("13456342", 8, "3", 1), "3456342")); + assert(!strcmpnul(libsimple_memelemscan("12345634", 0, "3", 1), "12345634")); + + assert(!strcmpnul(libsimple_memelemscan("12345634", 4, "34", 2), "345634")); + assert(!strcmpnul(libsimple_memelemscan("12345634z", 4, "xx", 2), "z")); + assert(!strcmpnul(libsimple_memelemscan("13456342z", 4, "34", 2), "z")); + assert(!strcmpnul(libsimple_memelemscan("12345634z", 0, "34", 2), "12345634z")); + + assert(!strcmpnul(libsimple_memelemscan("abcd1234abcd1234", 4, "1234", 4), "1234abcd1234")); + assert(!strcmpnul(libsimple_memelemscan("abcd1234abcd1234z", 4, "zzzz", 4), "z")); + assert(!strcmpnul(libsimple_memelemscan("cd1234abcd1234abz", 4, "1234", 4), "z")); + assert(!strcmpnul(libsimple_memelemscan("abcd1234abcd1234z", 0, "1234", 4), "abcd1234abcd1234z")); + + assert(!strcmpnul(libsimple_memelemscan("abcdefgh12345678abcdefgh12345678", 4, "12345678", 8), "12345678abcdefgh12345678")); + assert(!strcmpnul(libsimple_memelemscan("abcdefgh12345678abcdefgh12345678z", 4, "zzzzzzzz", 8), "z")); + assert(!strcmpnul(libsimple_memelemscan("efgh12345678abcdefgh12345678abcdz", 4, "12345678", 8), "z")); + assert(!strcmpnul(libsimple_memelemscan("abcdefgh12345678abcdefgh12345678z", 0, "12345678", 8), + "abcdefgh12345678abcdefgh12345678z")); + + assert(!strcmpnul(libsimple_memelemscan("abc123abc123", 4, "123", 3), "123abc123")); + assert(!strcmpnul(libsimple_memelemscan("abc123abc123z", 4, "zzz", 3), "z")); + assert(!strcmpnul(libsimple_memelemscan("bc123abc123az", 4, "123", 3), "z")); + assert(!strcmpnul(libsimple_memelemscan("abc123abc123z", 0, "123", 3), "abc123abc123z")); + + return 0; +} + +#endif diff --git a/memrelem.c b/memrelem.c index b1e69ba..8317e8e 100644 --- a/memrelem.c +++ b/memrelem.c @@ -60,7 +60,6 @@ libsimple_memrelem(const void *hay_, size_t hayn, const void *sub_, size_t subn) next:; } break; - } } @@ -78,7 +77,7 @@ main(void) assert(!strcmpnul(libsimple_memrelem("12345634", 0, "", 0), "12345634")); assert(!strcmpnul(libsimple_memrelem("12345634", 8, "3", 1), "34")); - assert(!libsimple_memrelem("12345634", 8, "x", 1));; + assert(!libsimple_memrelem("12345634", 8, "x", 1)); assert(!strcmpnul(libsimple_memrelem("13456342", 8, "3", 1), "342")); assert(!libsimple_memrelem("12345634", 0, "3", 1)); -- cgit v1.2.3-70-g09d2