diff --git a/src/libc/include/string.h b/src/libc/include/string.h index 846c9b457..67cc527ec 100644 --- a/src/libc/include/string.h +++ b/src/libc/include/string.h @@ -29,6 +29,9 @@ void *memrchr(const void *s, int c, size_t n) void *memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) __NOEXCEPT __attribute__((nonnull(1, 3))) __attribute((__pure__)); +void *memrmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) + __NOEXCEPT __attribute__((nonnull(1, 3))) __attribute((__pure__)); + void *memccpy(void *__restrict dest, const void *__restrict src, int c, size_t n) __NOEXCEPT __attribute__((nonnull(1, 2))); @@ -65,12 +68,18 @@ char *strchr(const char *s, int c) char *strrchr(const char *s, int c) __attribute__((nonnull(1))); +char *strchrnul(const char *s, int c) + __NOEXCEPT __attribute__((nonnull(1))) __attribute__((__pure__)); + char *strpbrk(const char *s, const char *accept) __attribute__((nonnull(1, 2))); char *strstr(const char *haystack, const char *needle) __attribute__((nonnull(1, 2))); +char *strrstr(const char *haystack, const char *needle) + __NOEXCEPT __attribute__((nonnull(1, 2))) __attribute__((__pure__)); + char *strcasestr(const char *haystack, const char *needle) __NOEXCEPT __attribute__((nonnull(1, 2))) __attribute__((__pure__)); diff --git a/src/libc/memmem.src b/src/libc/memmem.src new file mode 100644 index 000000000..61c94a301 --- /dev/null +++ b/src/libc/memmem.src @@ -0,0 +1,77 @@ + assume adl=1 + + section .text + + public _memmem + +; void *memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) +haystack := iy + 3 +haystack_len := iy + 6 +needle := iy + 9 +needle_len := iy + 12 +_memmem: + ld iy, 0 + add iy, sp + ld hl, (haystack_len) + ld bc, (needle_len) + sbc hl, bc + jr c, .ret_null ; (haystack_len < needle_len) + ; (haystack_len >= needle_len) + + push hl + scf + sbc hl, hl + add hl, bc + pop bc + ld hl, (haystack) + ret nc ; return haystack if needle_len is zero + inc bc + ; BC = (haystack_len - needle_len + 1) = search_len + ; haystack_len >= needle_len && needle_len != 0, therefore haystack_len >= 1 + call .begin_loop + jr nz, .ret_null + ; test for a match at the last possible position + dec hl + push hl + call _memcmp_fast + pop hl + ret z +.ret_null: + or a, a + sbc hl, hl + ret + +.loop: + pop bc +.begin_loop: + ld de, (needle) + ld a, (de) + cpir ; search for the start of the string + ret po ; end of search_len + push bc + push hl + dec hl + call _memcmp_fast + pop hl + jr nz, .loop + ; pop bc + ld sp, iy + dec hl + ret + +_memcmp_fast: + ; Input: + ; HL = haystack + ; DE = needle + ; A = (DE) + ; Output: + ; Z = match + ; NZ = no match + ld bc, (needle_len) +.loop: + cpi + ret po + inc de + ld a, (de) + jr z, .loop + ret diff --git a/src/libc/memrmem.src b/src/libc/memrmem.src new file mode 100644 index 000000000..9b9688fb3 --- /dev/null +++ b/src/libc/memrmem.src @@ -0,0 +1,96 @@ + assume adl=1 + + section .text + + public _memrmem + +; void *memrmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) +haystack := iy + 3 +haystack_len := iy + 6 +needle := iy + 9 +needle_len := iy + 12 +_memrmem: + ld iy, 0 + add iy, sp + ld hl, (haystack_len) + ld bc, (needle_len) + sbc hl, bc + jr c, .ret_null ; (haystack_len < needle_len) + ; (haystack_len >= needle_len) + + push hl + adc hl, bc + ex de, hl + ; DE = needle_len + + ; move to the end of the needle + ld hl, (needle) + ; return haystack when haystack_len is zero (implies that needle_len is also zero) + jr z, .zero_haystack_len + add hl, bc + dec hl + ld (needle), hl + + sbc hl, hl + adc hl, bc + pop bc + ld hl, (haystack) + + ; move to the end of the haystack + add hl, de + dec hl + + ret z ; return (haystack + haystack_len - 1) if needle_len is zero + + inc bc + ; BC = (haystack_len - needle_len + 1) = search_len + ; haystack_len >= needle_len && needle_len != 0, therefore haystack_len >= 1 + call .begin_loop + jr nz, .ret_null + ; test for a match at the last possible position + call _memrcmp_fast + inc hl + ret z +.ret_null: + or a, a + sbc hl, hl + ret + +.loop: + pop hl + pop bc +.begin_loop: + ld de, (needle) + ld a, (de) + cpdr ; search for the start of the string + ret po ; end of search_len + push bc + push hl + call _memrcmp_fast + jr nz, .loop + inc hl + ld sp, iy + ret + +.zero_haystack_len: + pop hl + ld hl, (haystack) + ret + +_memrcmp_fast: + ; Input: + ; HL = haystack + needle_len - 1 + ; DE = needle + needle_len - 1 + ; A = (DE) + ; Output: + ; Z = match + ; NZ = no match + inc hl + ld bc, (needle_len) +.loop: + cpd + ret po + dec de + ld a, (de) + jr z, .loop + ret diff --git a/src/libc/stpncpy.src b/src/libc/stpncpy.src new file mode 100644 index 000000000..92ac007d7 --- /dev/null +++ b/src/libc/stpncpy.src @@ -0,0 +1,57 @@ + assume adl=1 + + section .text + + public _stpncpy + +_stpncpy: + ld iy, 0 + add iy, sp + ld bc, (iy + 9) ; max_len + + ; inlined strnlen + xor a, a + sbc hl, hl + sbc hl, bc + jr z, .zero_size + add hl, bc + ld de, (iy + 6) ; src + sbc hl, de + ex de, hl + cpir + jr z, .finish_strnlen + inc hl +.finish_strnlen: + xor a, a + adc hl, de +.zero_size: + + ; copy strnlen bytes from src + push hl + ld de, (iy + 3) ; dst + jr z, .zero_byte_copy + ld hl, (iy + 6) ; src + pop bc + push bc + ldir +.zero_byte_copy: + pop bc + + ; zero pad the remainder + ld hl, (iy + 9) ; max_len + scf + sbc hl, bc ; clear_size - 1 = max_len - src_len - 1 + ex de, hl + ret c ; clear_size <= 0 (or max_len <= src_len) + ; HL = dst + src_len + ; DE = clear_size - 1 + add hl, de + ld (hl), a + ret z ; clear_size == 1 + push de + pop bc + push hl + pop de + dec de + lddr + ret diff --git a/src/libc/strchrnul.src b/src/libc/strchrnul.src new file mode 100644 index 000000000..926f6aaee --- /dev/null +++ b/src/libc/strchrnul.src @@ -0,0 +1,25 @@ + assume adl=1 + + section .text + + public _strchrnul + +_strchrnul: + pop bc, hl, de + push de, hl, bc + xor a, a + ld bc, 0 + push hl + cpir + sbc hl, hl + sbc hl, bc + ex (sp), hl + pop bc + ld a, e + ; HL = str + ; BC = strlen(str) + 1 + ; A = ch + cpir + dec hl + ; points to the '\0' if ch was not found + ret diff --git a/src/libc/strlcat.src b/src/libc/strlcat.src new file mode 100644 index 000000000..749c867ca --- /dev/null +++ b/src/libc/strlcat.src @@ -0,0 +1,76 @@ + assume adl=1 + + section .text + + public _strlcat + +_strlcat: + ld iy, 0 + lea bc, iy + add iy, sp + ld hl, (iy + 6) ; src + xor a, a + cpir + sbc hl, hl + dec hl + sbc hl, bc + ; carry is clear + ex de, hl + + ; inlined strnlen + ld bc, (iy + 9) ; max_size + sbc hl, hl + sbc hl, bc + ; Allows dst to be NULL when max_size is zero + jr z, .zero_size ; return src_len + add hl, bc + push de ; src_len + ld de, (iy + 3) ; dst + sbc hl, de + ex de, hl + cpir + add hl, de + jr z, .finish_strnlen + inc hl +.finish_strnlen: + + ex de, hl + ld hl, (iy + 9) ; max_size + ; (copy_size + 1) = max_size - dst_len + xor a, a + sbc hl, de + jr z, .no_room + + pop bc ; src_len + push bc + + ; (copy_size + 1) - src_len - 1 + scf + sbc hl, bc + + jr c, .copy_size_lt_src_len + ; (copy_size + 1 - 1) >= src_len + ; copy_size >= src_len + sbc hl, hl +.copy_size_lt_src_len: + xor a, a + adc hl, bc + jr z, .zero_copy_size + push hl + pop bc + + push de ; dst_len + ld hl, (iy + 3) ; dst + add hl, de ; dst + dst_len + ex de, hl + ld hl, (iy + 6) ; src + ldir + ld (de), a ; null terminate + pop de ; dst_len +.zero_copy_size: +.no_room: + pop hl ; src_len +.zero_size: + ; return src_len + dst_len + add hl, de + ret diff --git a/src/libc/strrstr.src b/src/libc/strrstr.src new file mode 100644 index 000000000..2219ced5a --- /dev/null +++ b/src/libc/strrstr.src @@ -0,0 +1,38 @@ + assume adl=1 + + section .text + + public _strrstr + +_strrstr: + pop bc + pop de + ex (sp), hl + push de + push bc + + push hl + xor a, a + ld bc, 0 + cpir + sbc hl, hl + dec hl + sbc hl, bc ; carry will be cleared + ex (sp), hl ; strlen(needle) + push hl ; needle + + ex de, hl + push hl + ld bc, 0 + cpir + sbc hl, hl + dec hl + sbc hl, bc + ex (sp), hl ; strlen(haystack) + push hl ; haystack + + call _memrmem + pop bc, bc, bc, bc + ret + + extern _memrmem diff --git a/src/libcxx/include/cstring b/src/libcxx/include/cstring index 3297c3d4d..7adbf29d1 100644 --- a/src/libcxx/include/cstring +++ b/src/libcxx/include/cstring @@ -17,6 +17,7 @@ using ::memcmp; using ::memchr; using ::memrchr; using ::memmem; +using ::memrmem; using ::memccpy; using ::mempcpy; using ::strcpy; @@ -29,8 +30,10 @@ using ::strncat; using ::strlcat; using ::strchr; using ::strrchr; +using ::strchrnul; using ::strpbrk; using ::strstr; +using ::strrstr; using ::strcasestr; using ::strtok; using ::strdup; diff --git a/test/standalone/asprintf_fprintf/src/main.c b/test/standalone/asprintf_fprintf/src/main.c index 3bf27ccef..36659d348 100644 --- a/test/standalone/asprintf_fprintf/src/main.c +++ b/test/standalone/asprintf_fprintf/src/main.c @@ -8,7 +8,6 @@ #include #include - /** * @brief Tests the following functions/macros: * boot_sprintf @@ -22,6 +21,8 @@ #define C(expr) if (!(expr)) { return __LINE__; } +#define TEST(test) { ret = test; if (ret != 0) { return ret; }} + #define SINK (char*)0xE40000 /* pass NULL into functions without triggering -Wnonnull */ @@ -51,9 +52,21 @@ void *T_mempcpy(void *__restrict dest, const void *__restrict src, size_t n) void *T_memrchr(const void *s, int c, size_t n) __attribute__((nonnull(1))); +void *T_memmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) + __attribute__((nonnull(1, 3))); + +void *T_memrmem(const void *haystack, size_t haystack_len, const void *needle, size_t needle_len) + __attribute__((nonnull(1, 3))); + char *T_stpcpy(char *__restrict dest, const char *__restrict src) __attribute__((nonnull(1, 2))); +char *T_stpncpy(char *__restrict dest, const char *__restrict src, size_t n) + __attribute__((nonnull(1, 2))); + +size_t T_strlcat(void *__restrict dest, const void *__restrict src, size_t n) + __attribute__((nonnull(1, 2))); + size_t T_strlen(const char *s) __attribute__((nonnull(1))); @@ -63,6 +76,12 @@ int T_strcmp(const char *s1, const char *s2) int T_strncmp(const char *s1, const char *s2, size_t n) __attribute__((nonnull(1, 2))); +char *T_strchrnul(const char *s, int c) + __attribute__((nonnull(1))); + +char *T_strrstr(const char *haystack, const char *needle) + __attribute__((nonnull(1, 2))); + void T_bzero(void* s, size_t n); #else @@ -74,14 +93,28 @@ void T_bzero(void* s, size_t n); #define T_memccpy memccpy #define T_mempcpy mempcpy #define T_memrchr memrchr +#define T_memmem memmem +#define T_memrmem memrmem #define T_stpcpy stpcpy +#define T_stpncpy stpncpy +#define T_strlcat strlcat #define T_strlen strlen #define T_strcmp strcmp #define T_strncmp strncmp +#define T_strchrnul strchrnul +#define T_strrstr strrstr #define T_bzero bzero #endif +const char gnu_copypasta[] = + "I would just like to interject for a moment. What you're referring to "\ + "as Linux, is in fact, GNU/Linux, or as I\'ve recently taken to calling "\ + "it, GNU plus Linux. Linux is not an operating system unto itself, but "\ + "rather another free component of a fully functioning GNU system made "\ + "useful by the GNU corelibs, shell utilities and vital system "\ + "components comprising a full OS as defined by POSIX"; + static char const * const test_1 = "+123 asprintf% 076543 0x9abcd 0XFE1 0\n"; static char const * const test_2 = @@ -159,7 +192,7 @@ int boot_sprintf_tests(void) { printf("E: %d != %d\n", len_3, pos_3); return __LINE__; } - + // large string test static char const * const s = "Hello"; int len_4 = boot_snprintf(SINK, 300, @@ -271,7 +304,7 @@ int nano_tests(void) { printf("E: %d != %d\n", len_3s, pos_3); return __LINE__; } - + // https://en.cppreference.com/w/c/io/fprintf static char const * const s = "Hello"; int len_4 = snprintf(SINK, 300, @@ -360,7 +393,7 @@ int memccpy_tests(void) { return __LINE__; } file = fopen(file_name, "wb"); - + // Check if the file was opened successfully if (file == NULL) { perror("Error opening file"); @@ -371,24 +404,24 @@ int memccpy_tests(void) { const char terminal[] = {':', ' ', ',', '.', '!'}; char dest[sizeof src]; const char alt = '@'; - + for (size_t i = 0; i != sizeof terminal; ++i) { void* to = T_memccpy(dest, src, terminal[i], sizeof dest); - + fprintf(file,"Terminal '%c' (%s):\t\"", terminal[i], to ? "found" : "absent"); - + // if `terminal` character was not found - print the whole `dest` to = to ? to : dest + sizeof dest; - + for (char* from = dest; from != to; ++from) { fputc(isprint(*from) ? *from : alt, file); } - + fputs("\"\n", file); } - - + + fprintf(file, "%c%s", '\n', "Separate star names from distances (ly):\n"); const char *star_distance[] = { "Arcturus : 37", "Vega : 25", "Capella : 43", "Rigel : 860", "Procyon : 11" @@ -396,7 +429,7 @@ int memccpy_tests(void) { char names_only[64]; char *first = names_only; char *last = names_only + sizeof names_only; - + for (size_t t = 0; t != (sizeof star_distance) / (sizeof star_distance[0]); ++t) { if (first) { @@ -597,6 +630,355 @@ int memmove_test(void) { return 0; } +static bool strcmp_exact(const char* x, const char* y) { + if (strlen(x) != strlen(y)) { + return false; + } + if (strcmp(x, y) != 0) { + return false; + } + return true; +} + +int strlcat_test(void) { + const char* src1 = "Foo"; + const char* src2 = "Bar"; + char dst[10]; + + strcpy(dst, src1); C(T_strlcat(dst , src2, 0) == 3); C(strcmp_exact(dst, "Foo")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 1) == 4); C(strcmp_exact(dst, "Foo")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 2) == 5); C(strcmp_exact(dst, "Foo")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 3) == 6); C(strcmp_exact(dst, "Foo")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 4) == 6); C(strcmp_exact(dst, "Foo")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 5) == 6); C(strcmp_exact(dst, "FooB")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 6) == 6); C(strcmp_exact(dst, "FooBa")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 7) == 6); C(strcmp_exact(dst, "FooBar")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 8) == 6); C(strcmp_exact(dst, "FooBar")); + strcpy(dst, src1); C(T_strlcat(dst , src2, 9) == 6); C(strcmp_exact(dst, "FooBar")); + + strcpy(dst, src1); C(T_strlcat(dst , SINK, 0) == 0); C(strcmp_exact(dst, src1)); + strcpy(dst, src1); C(T_strlcat(dst , SINK, 1) == 1); C(strcmp_exact(dst, src1)); + strcpy(dst, src1); C(T_strlcat(dst , SINK, 2) == 2); C(strcmp_exact(dst, src1)); + strcpy(dst, src1); C(T_strlcat(dst , SINK, 3) == 3); C(strcmp_exact(dst, src1)); + strcpy(dst, src1); C(T_strlcat(dst , SINK, 4) == 3); C(strcmp_exact(dst, src1)); + strcpy(dst, src1); C(T_strlcat(dst , SINK, 5) == 3); C(strcmp_exact(dst, src1)); + + C(T_strlcat(NULL_ptr, SINK, 0) == 0); + C(T_strlcat(NULL_ptr, src1, 0) == 3); + + dst[0] = '\0'; C(T_strlcat(dst, SINK, 0) == 0); C(dst[0] == '\0'); + dst[0] = '\0'; C(T_strlcat(dst, SINK, 1) == 0); C(dst[0] == '\0'); + dst[0] = '\0'; C(T_strlcat(dst, SINK, 2) == 0); C(dst[0] == '\0'); + + dst[0] = '\0'; C(T_strlcat(dst, src1, 0) == 3); C(strcmp_exact(dst, "")); + dst[0] = '\0'; C(T_strlcat(dst, src1, 1) == 3); C(strcmp_exact(dst, "")); + dst[0] = '\0'; C(T_strlcat(dst, src1, 2) == 3); C(strcmp_exact(dst, "F")); + dst[0] = '\0'; C(T_strlcat(dst, src1, 3) == 3); C(strcmp_exact(dst, "Fo")); + dst[0] = '\0'; C(T_strlcat(dst, src1, 4) == 3); C(strcmp_exact(dst, "Foo")); + dst[0] = '\0'; C(T_strlcat(dst, src1, 5) == 3); C(strcmp_exact(dst, "Foo")); + + return 0; +} + +int stpncpy_test(void) { + char text[6]; + + C(T_stpncpy(NULL_ptr, "", 0) == NULL_ptr + 0); + C(T_stpncpy(NULL_ptr, "foobar", 0) == NULL_ptr + 0); + + memset(text, '\xee', 6); + + C(T_stpncpy(text, "1", 5) == text + 1); + C(memcmp(text, "1\0\0\0\0\xee", 6) == 0); + + C(T_stpncpy(text, "1234", 5) == text + 4); + C(memcmp(text, "1234\0\xee", 6) == 0); + + C(T_stpncpy(text, "12345", 5) == text + 5); + C(memcmp(text, "12345\xee", 6) == 0); + + C(T_stpncpy(text, "123456", 5) == text + 5); + C(memcmp(text, "12345\xee", 6) == 0); + + memset(text, '\xff', 6); + + C(T_stpncpy(text, "", 0) == text + 0); + C(memcmp(text, "\xff\xff\xff\xff\xff\xff", 6) == 0); + + C(T_stpncpy(text, "123456", 1) == text + 1); + C(memcmp(text, "1\xff\xff\xff\xff\xff", 1) == 0); + + C(T_stpncpy(text, "6", 1) == text + 1); + C(memcmp(text, "6\xff\xff\xff\xff\xff", 1) == 0); + + C(T_stpncpy(text, "", 1) == text + 0); + C(memcmp(text, "\0\xff\xff\xff\xff\xff", 1) == 0); + + C(T_stpncpy(text, "a", 2) == text + 1); + C(memcmp(text, "a\0\xff\xff\xff\xff", 1) == 0); + + C(T_stpncpy(text, "", 5) == text + 0); + C(memcmp(text, "\0\0\0\0\0\xff", 1) == 0); + + return 0; +} + +int memmem_test(void) { + const char str1[] = "abcdef123\0aababc123"; + const char str2[] = "wxyz"; + + /* Test NULL */ + + C(T_memmem(NULL_ptr, 0, NULL_ptr, 0) == NULL_ptr); + C(T_memmem(NULL_ptr, 0, SINK, 0) == NULL_ptr); + C(T_memmem(NULL_ptr, 0, SINK, 1) == NULL_ptr); + C(T_memmem(NULL_ptr, 0, SINK, 2) == NULL_ptr); + C(T_memmem(SINK, 0, NULL_ptr, 0) == SINK); + C(T_memmem(SINK, 1, NULL_ptr, 0) == SINK); + C(T_memmem(SINK, 2, NULL_ptr, 0) == SINK); + + /* Test same */ + + C(T_memmem(SINK, 0, SINK, 0) == SINK); + C(T_memmem(SINK, 1, SINK, 0) == SINK); + C(T_memmem(SINK, 2, SINK, 0) == SINK); + C(T_memmem(SINK, 0, SINK, 1) == NULL); + C(T_memmem(SINK, 1, SINK, 1) == SINK); + C(T_memmem(SINK, 2, SINK, 1) == SINK); + C(T_memmem(SINK, 0, SINK, 2) == NULL); + C(T_memmem(SINK, 1, SINK, 2) == NULL); + C(T_memmem(SINK, 2, SINK, 2) == SINK); + + C(T_memmem(SINK, 300, SINK, 300) == SINK); + C(T_memmem(SINK, 300, SINK, 301) == NULL); + C(T_memmem(SINK, 300, SINK, 299) == SINK); + C(T_memmem(SINK, 300, SINK, 30 ) == SINK); + C(T_memmem(SINK, 30, SINK, 300) == NULL); + + C(T_memmem(SINK + 30, 60, SINK + 0, 60) == SINK + 30); + C(T_memmem(SINK + 0, 60, SINK + 30, 60) == SINK + 0); + C(T_memmem(SINK + 30, 60, SINK + 0, 59) == SINK + 30); + C(T_memmem(SINK + 0, 60, SINK + 30, 59) == SINK + 0); + + C(T_memmem(str1, 20, str1, 0) == str1); + C(T_memmem(str1, 20, str1, 1) == str1); + C(T_memmem(str1, 20, str1, 2) == str1); + C(T_memmem(str1, 20, str1, 3) == str1); + C(T_memmem(str1, 20, str1, 9) == str1); + C(T_memmem(str1, 20, str1, 10) == str1); + C(T_memmem(str1, 20, str1, 19) == str1); + C(T_memmem(str1, 20, str1, 20) == str1); + + /* Test different */ + + C(T_memmem(str1, 0, SINK, 0) == str1); + C(T_memmem(str1, 1, SINK, 0) == str1); + C(T_memmem(str1, 2, SINK, 0) == str1); + C(T_memmem(str1, 0, SINK, 1) == NULL); + C(T_memmem(str1, 1, SINK, 1) == NULL); + C(T_memmem(str1, 2, SINK, 1) == NULL); + C(T_memmem(str1, 0, SINK, 2) == NULL); + C(T_memmem(str1, 1, SINK, 2) == NULL); + C(T_memmem(str1, 2, SINK, 2) == NULL); + + /* Other tests */ + + C(T_memmem(str1 + 1, 19, "abc", 3) == str1 + 13); + C(T_memmem(str1 + 0, 20, "123", 4) == str1 + 6); + C(T_memmem(str1 + 7, 13, "123", 4) == str1 + 16); + + C(T_memmem(str1 + 0, 20, "aabaab", 6) == NULL); + C(T_memmem(str1 + 0, 20, "\xff\x00\xff", 4) == NULL); + C(T_memmem(str1 + 0, 20, "\xff", 1) == NULL); + + C(T_memmem(SINK, 300, "\xff", 1) == NULL); + C(T_memmem(SINK, 300, "\xff\xff", 2) == NULL); + C(T_memmem(SINK, 300, "\xff", 2) == NULL); + C(T_memmem(SINK, 300, "\0\xff", 2) == NULL); + + C(T_memmem(str2 + 0, 5, "", 1) == str2 + 4); + C(T_memmem(str2 + 4, 1, "", 1) == str2 + 4); + C(T_memmem(str2 + 0, 5, "z", 1) == str2 + 3); + C(T_memmem(str2 + 0, 5, "z", 2) == str2 + 3); + C(T_memmem(str2 + 2, 5, "z", 1) == str2 + 3); + C(T_memmem(str2 + 2, 5, "z", 2) == str2 + 3); + C(T_memmem(str2 + 0, 3, "z", 1) == NULL); + C(T_memmem(str2 + 0, 4, "z", 2) == NULL); + C(T_memmem(str2 + 0, 5, "w", 1) == str2 + 0); + C(T_memmem(str2 + 0, 5, "x", 1) == str2 + 1); + C(T_memmem(str2 + 0, 5, "wx", 2) == str2 + 0); + C(T_memmem(str2 + 0, 5, "xy", 2) == str2 + 1); + C(T_memmem(str2 + 0, 5, "w", 2) == NULL); + C(T_memmem(str2 + 0, 5, "x", 2) == NULL); + C(T_memmem(str2 + 0, 5, "wx", 3) == NULL); + C(T_memmem(str2 + 0, 5, "xy", 3) == NULL); + + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "a" , 1) == gnu_copypasta + 35); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "by" , 2) == gnu_copypasta + 286); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "GNU" , 3) == gnu_copypasta + 92); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "full" , 4) == gnu_copypasta + 245); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "linux" , 5) == NULL); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "Linux" , 5) == gnu_copypasta + 73); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "I would" , 7) == gnu_copypasta + 0); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "POSIX" , 5) == gnu_copypasta + 386); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "POsIX" , 5) == NULL); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "POSIX" , 6) == gnu_copypasta + 386); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), "system" , 6) == gnu_copypasta + 186); + C(T_memmem(gnu_copypasta, sizeof(gnu_copypasta), " component", 10) == gnu_copypasta + 229); + + return 0; +} + +int memrmem_test(void) { + const char str1[] = "abcdef123\0aababc123"; + const char str2[] = "wxyz"; + + /* Test NULL */ + + C(T_memrmem(NULL_ptr, 0, NULL_ptr, 0) == NULL_ptr); + C(T_memrmem(NULL_ptr, 0, SINK, 0) == NULL_ptr); + C(T_memrmem(NULL_ptr, 0, SINK, 1) == NULL_ptr); + C(T_memrmem(NULL_ptr, 0, SINK, 2) == NULL_ptr); + C(T_memrmem(SINK, 0, NULL_ptr, 0) == SINK + 0); + C(T_memrmem(SINK, 1, NULL_ptr, 0) == SINK + 0); + C(T_memrmem(SINK, 2, NULL_ptr, 0) == SINK + 1); + + /* Test same */ + + C(T_memrmem(SINK, 0, SINK, 0) == SINK + 0); + C(T_memrmem(SINK, 1, SINK, 0) == SINK + 0); + C(T_memrmem(SINK, 2, SINK, 0) == SINK + 1); + C(T_memrmem(SINK, 0, SINK, 1) == NULL); + C(T_memrmem(SINK, 1, SINK, 1) == SINK + 0); + C(T_memrmem(SINK, 2, SINK, 1) == SINK + 1); + C(T_memrmem(SINK, 0, SINK, 2) == NULL); + C(T_memrmem(SINK, 1, SINK, 2) == NULL); + C(T_memrmem(SINK, 2, SINK, 2) == SINK + 0); + + C(T_memrmem(SINK, 300, SINK, 300) == SINK); + C(T_memrmem(SINK, 300, SINK, 301) == NULL); + C(T_memrmem(SINK, 300, SINK, 299) == SINK + 1); + C(T_memrmem(SINK, 300, SINK, 30 ) == SINK + 270); + C(T_memrmem(SINK, 30, SINK, 300) == NULL); + + C(T_memrmem(SINK + 30, 60, SINK + 0, 60) == SINK + 30); + C(T_memrmem(SINK + 0, 60, SINK + 30, 60) == SINK + 0); + C(T_memrmem(SINK + 30, 60, SINK + 0, 59) == SINK + 31); + C(T_memrmem(SINK + 0, 60, SINK + 30, 59) == SINK + 1); + + C(T_memrmem(str1, 20, str1, 0) == str1 + 20 - 1); + C(T_memrmem(str1, 20, str1, 1) == str1 + 20 - 7); + C(T_memrmem(str1, 20, str1, 2) == str1 + 20 - 7); + C(T_memrmem(str1, 20, str1, 3) == str1 + 20 - 7); + C(T_memrmem(str1, 15, str1, 3) == str1); + C(T_memrmem(str1, 20, str1, 9) == str1); + C(T_memrmem(str1, 20, str1, 10) == str1); + C(T_memrmem(str1, 20, str1, 19) == str1); + C(T_memrmem(str1, 20, str1, 20) == str1); + + /* Test different */ + + C(T_memrmem(str1, 0, SINK, 0) == str1 + 0); + C(T_memrmem(str1, 1, SINK, 0) == str1 + 0); + C(T_memrmem(str1, 2, SINK, 0) == str1 + 1); + C(T_memrmem(str1, 0, SINK, 1) == NULL); + C(T_memrmem(str1, 1, SINK, 1) == NULL); + C(T_memrmem(str1, 2, SINK, 1) == NULL); + C(T_memrmem(str1, 0, SINK, 2) == NULL); + C(T_memrmem(str1, 1, SINK, 2) == NULL); + C(T_memrmem(str1, 2, SINK, 2) == NULL); + + /* Other tests */ + + C(T_memrmem(str1 + 0, 20, "123", 4) == str1 + 16); + C(T_memrmem(str1 + 6, 13, "123", 4) == str1 + 6); + C(T_memrmem(str1 + 7, 13, "123", 4) == str1 + 16); + C(T_memrmem(str1 + 0, 18, "123", 4) == str1 + 6); + + C(T_memrmem(str1 + 0, 20, "aabaab", 6) == NULL); + C(T_memrmem(str1 + 0, 20, "\xff\x00\xff", 4) == NULL); + C(T_memrmem(str1 + 0, 20, "\xff", 1) == NULL); + + C(T_memrmem(SINK, 300, "\xff", 1) == NULL); + C(T_memrmem(SINK, 300, "\xff\xff", 2) == NULL); + C(T_memrmem(SINK, 300, "\xff", 2) == NULL); + C(T_memrmem(SINK, 300, "\0\xff", 2) == NULL); + + C(T_memrmem(str2 + 0, 5, "", 1) == str2 + 4); + C(T_memrmem(str2 + 4, 1, "", 1) == str2 + 4); + C(T_memrmem(str2 + 0, 5, "z", 1) == str2 + 3); + C(T_memrmem(str2 + 0, 5, "z", 2) == str2 + 3); + C(T_memrmem(str2 + 2, 5, "z", 1) == str2 + 3); + C(T_memrmem(str2 + 2, 5, "z", 2) == str2 + 3); + C(T_memrmem(str2 + 0, 3, "z", 1) == NULL); + C(T_memrmem(str2 + 0, 4, "z", 2) == NULL); + C(T_memrmem(str2 + 0, 5, "w", 1) == str2 + 0); + C(T_memrmem(str2 + 0, 5, "x", 1) == str2 + 1); + C(T_memrmem(str2 + 0, 5, "wx", 2) == str2 + 0); + C(T_memrmem(str2 + 0, 5, "xy", 2) == str2 + 1); + C(T_memrmem(str2 + 0, 5, "w", 2) == NULL); + C(T_memrmem(str2 + 0, 5, "x", 2) == NULL); + C(T_memrmem(str2 + 0, 5, "wx", 3) == NULL); + C(T_memrmem(str2 + 0, 5, "xy", 3) == NULL); + + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "a" , 1) == gnu_copypasta + 372); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "by" , 2) == gnu_copypasta + 383); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "GNU" , 3) == gnu_copypasta + 293); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "full" , 4) == gnu_copypasta + 364); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "linux" , 5) == NULL); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "Linux" , 5) == gnu_copypasta + 160); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "I would" , 7) == gnu_copypasta + 0); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "POSIX" , 5) == gnu_copypasta + 386); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "POsIX" , 5) == NULL); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "POSIX" , 6) == gnu_copypasta + 386); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), "system" , 6) == gnu_copypasta + 333); + C(T_memrmem(gnu_copypasta, sizeof(gnu_copypasta), " component", 10) == gnu_copypasta + 339); + + return 0; +} + +int strrstr_test(void) { + const char str1[] = "abcdef123\0aababc123"; + + C(T_strrstr(SINK, SINK) == SINK); + C(T_strrstr(SINK, str1) == NULL); + C(T_strrstr(str1, SINK) == str1 + 8); + C(T_strrstr(str1, str1) == str1); + + C(T_strrstr(str1 + 0, str1 + 6) == str1 + 6); + C(T_strrstr(str1 + 9, str1 + 9) == str1 + 9); + C(T_strrstr(str1 + 10, "ab") == str1 + 13); + C(T_strrstr(str1 + 10, "aa") == str1 + 10); + C(T_strrstr(str1 + 10, "b" ) == str1 + 14); + C(T_strrstr(str1 + 10, "ba") == str1 + 12); + C(T_strrstr(str1 + 10, "aac") == NULL); + + C(T_strrstr(gnu_copypasta, "a" ) == gnu_copypasta + 372); + C(T_strrstr(gnu_copypasta, "by" ) == gnu_copypasta + 383); + C(T_strrstr(gnu_copypasta, "GNU" ) == gnu_copypasta + 293); + C(T_strrstr(gnu_copypasta, "full" ) == gnu_copypasta + 364); + C(T_strrstr(gnu_copypasta, "linux" ) == NULL); + C(T_strrstr(gnu_copypasta, "Linux" ) == gnu_copypasta + 160); + C(T_strrstr(gnu_copypasta, "I would" ) == gnu_copypasta + 0); + C(T_strrstr(gnu_copypasta, "POSIX" ) == gnu_copypasta + 386); + C(T_strrstr(gnu_copypasta, "POsIX" ) == NULL); + C(T_strrstr(gnu_copypasta, "system" ) == gnu_copypasta + 333); + C(T_strrstr(gnu_copypasta, " component") == gnu_copypasta + 339); + + return 0; +} + +int strchrnul_test(void) { + C(T_strchrnul(SINK, '\0') == SINK); + C(T_strchrnul(SINK, '\xff') == SINK); + const size_t test_3_len = strlen(test_3); + C(T_strchrnul(test_3, '\0') == test_3 + test_3_len); + for (size_t i = 0; i < test_3_len; i++) { + C(T_strchrnul(test_3, test_3[i]) == strchr(test_3, test_3[i])); + } + return 0; +} + int run_tests(void) { int ret = 0; /* boot_asprintf */ @@ -618,25 +1000,17 @@ int run_tests(void) { } if (ret != 0) { return ret; } - /* mempcpy */ - ret = mempcpy_test(); - if (ret != 0) { return ret; } - - /* bzero */ - ret = bzero_test(); - if (ret != 0) { return ret; } - - /* strncmp */ - ret = strncmp_test(); - if (ret != 0) { return ret; } - - /* memrchr */ - ret = memrchr_test(); - if (ret != 0) { return ret; } - - /* memrchr */ - ret = memmove_test(); - if (ret != 0) { return ret; } + TEST(mempcpy_test()); + TEST(bzero_test()); + TEST(strncmp_test()); + TEST(memrchr_test()); + TEST(memmove_test()); + TEST(strlcat_test()); + TEST(stpncpy_test()); + TEST(memmem_test()); + TEST(memrmem_test()); + TEST(strrstr_test()); + TEST(strchrnul_test()); return 0; } @@ -675,7 +1049,7 @@ int main(void) printf("All tests %s", "passed"); #endif } - + while (!os_GetCSC()); return 0; diff --git a/test/standalone/asprintf_fprintf/src/rename.asm b/test/standalone/asprintf_fprintf/src/rename.asm index a14203fe8..14c6bd1b8 100644 --- a/test/standalone/asprintf_fprintf/src/rename.asm +++ b/test/standalone/asprintf_fprintf/src/rename.asm @@ -2,8 +2,8 @@ section .text - public _T_memset, _T_memcpy, _T_memmove, _T_memcmp, _T_memccpy, _T_mempcpy, _T_memrchr - public _T_strlen, _T_strcmp, _T_strncmp, _T_stpcpy + public _T_memset, _T_memcpy, _T_memmove, _T_memcmp, _T_memccpy, _T_mempcpy, _T_memrchr, _T_memmem, _T_memrmem + public _T_strlen, _T_strcmp, _T_strncmp, _T_stpcpy, _T_stpncpy, _T_strlcat, _T_strchrnul, _T_strrstr public _T_bzero _T_memset := _memset @@ -13,11 +13,17 @@ _T_memcmp := _memcmp _T_memccpy := _memccpy _T_mempcpy := _mempcpy _T_memrchr := _memrchr +_T_memmem := _memmem +_T_memrmem := _memrmem _T_strlen := _strlen _T_strcmp := _strcmp _T_strncmp := _strncmp _T_stpcpy := _stpcpy +_T_stpncpy := _stpncpy +_T_strlcat := _strlcat +_T_strchrnul := _strchrnul +_T_strrstr := _strrstr _T_bzero := _bzero @@ -27,6 +33,6 @@ _T_bzero := _bzero _NULL_ptr: db $00, $00, $00 - extern _memset, _memcpy, _memmove, _memcmp, _memccpy, _mempcpy, _memrchr - extern _strlen, _strcmp, _strncmp, _stpcpy + extern _memset, _memcpy, _memmove, _memcmp, _memccpy, _mempcpy, _memrchr, _memmem, _memrmem + extern _strlen, _strcmp, _strncmp, _stpcpy, _stpncpy, _strlcat, _strchrnul, _strrstr extern _bzero