diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d07224..7ce0749 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,8 @@ set(SOURCES src/libc/string/memset.c src/libc/string/strcmp.c src/libc/string/strdup.c - src/libc/string/strlen.c) + src/libc/string/strlen.c + src/libc/string/strnlen.c) if(vhex-generic IN_LIST TARGET_FOLDERS) # TODO @@ -169,6 +170,7 @@ if(sh-generic IN_LIST TARGET_FOLDERS) src/libc/setjmp/target/sh-generic/setjmp.S src/libc/setjmp/target/sh-generic/longjmp.S src/libc/string/target/sh-generic/memchr.S + src/libc/string/target/sh-generic/strlen.S src/target/sh-generic/cpucap.c) endif() diff --git a/STATUS b/STATUS index 7a7ebd5..60e6a7b 100644 --- a/STATUS +++ b/STATUS @@ -130,7 +130,7 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested ! 7.21.5.8 strtok: TODO 7.21.6.1 memset: DONE ! 7.21.6.2 strerror: TODO -! 7.21.6.3 strlen: TODO + 7.21.6.3 strlen: DONE Extensions: - strnlen: TODO - strchrnul: TODO diff --git a/src/libc/string/strlen.c b/src/libc/string/strlen.c index 718ddc2..aeb357c 100644 --- a/src/libc/string/strlen.c +++ b/src/libc/string/strlen.c @@ -1,37 +1,12 @@ #include -/* -** The strlen() function calculates the length of the string pointed to by s, -** excluding the termi‐nating null byte ('\0'). -** -** TODO: use quad-word access ! -*/ -size_t strlen(char const *str) -{ - size_t i; +#ifndef __SUPPORT_ARCH_SH - if (str == NULL) - return (0); - i = -1; - while (str[++i] != '\0') ; - return (i); +size_t strlen(char const *s) +{ + size_t i = 0; + while(s[i]) i++; + return i; } -/* -** The strnlen() function returns the number of bytes in the string pointed to -** by s, excluding the terminating null byte ('\0'), but at most maxlen. -** In doing this, strnlen() looks only at the first maxlen characters in the -** string pointed to by s and never beyond s+maxlen. -** -** TODO: use quad-word access ! -*/ -size_t strnlen(char const *str, size_t maxlen) -{ - size_t i; - - if (str == NULL) - return (0); - i = -1; - while (str[++i] != '\0' && (size_t)i < maxlen) ; - return (i); -} +#endif /*__SUPPORT_ARCH_SH*/ diff --git a/src/libc/string/strnlen.c b/src/libc/string/strnlen.c new file mode 100644 index 0000000..89b8305 --- /dev/null +++ b/src/libc/string/strnlen.c @@ -0,0 +1,8 @@ +#include + +size_t strnlen(char const *s, size_t n) +{ + size_t i = 0; + while(s[i] && i < n) i++; + return i; +} diff --git a/src/libc/string/target/sh-generic/strlen.S b/src/libc/string/target/sh-generic/strlen.S new file mode 100644 index 0000000..139d254 --- /dev/null +++ b/src/libc/string/target/sh-generic/strlen.S @@ -0,0 +1,36 @@ +.global _strlen +.type _strlen, @function + +_strlen: + mov r4, r0 + mov #0, r2 + + /* Check 3 bytes to make sure we don't skip any when aligning */ + mov.b @r0+, r1 + tst r1, r1 + bt .end + mov.b @r0+, r1 + tst r1, r1 + bt .end + mov.b @r0+, r1 + tst r1, r1 + bt .end + + /* Align to a 4-byte boundary */ + or #3, r0 + xor #3, r0 + + /* Read bytes by groups of 4 */ +1: mov.l @r0+, r1 + cmp/str r1, r2 + bf 1b + + /* Go back to find out which of the last 4 bytes is the NUL */ + add #-4, r0 +2: mov.b @r0+, r1 + tst r1, r1 + bf 2b + +.end: add #-1, r0 + rts + sub r4, r0