Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/libc/include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)));

Expand Down Expand Up @@ -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__));

Expand Down
77 changes: 77 additions & 0 deletions src/libc/memmem.src
Original file line number Diff line number Diff line change
@@ -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
96 changes: 96 additions & 0 deletions src/libc/memrmem.src
Original file line number Diff line number Diff line change
@@ -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
57 changes: 57 additions & 0 deletions src/libc/stpncpy.src
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions src/libc/strchrnul.src
Original file line number Diff line number Diff line change
@@ -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
76 changes: 76 additions & 0 deletions src/libc/strlcat.src
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading