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
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
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
153 changes: 122 additions & 31 deletions test/standalone/asprintf_fprintf/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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 */
Expand Down Expand Up @@ -54,6 +56,12 @@ void *T_memrchr(const void *s, int c, size_t n)
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)));

Expand All @@ -75,6 +83,8 @@ void T_bzero(void* s, size_t n);
#define T_mempcpy mempcpy
#define T_memrchr memrchr
#define T_stpcpy stpcpy
#define T_stpncpy stpncpy
#define T_strlcat strlcat
#define T_strlen strlen
#define T_strcmp strcmp
#define T_strncmp strncmp
Expand Down Expand Up @@ -159,7 +169,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,
Expand Down Expand Up @@ -271,7 +281,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,
Expand Down Expand Up @@ -360,7 +370,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");
Expand All @@ -371,32 +381,32 @@ 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"
};
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) {
Expand Down Expand Up @@ -597,6 +607,99 @@ 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 run_tests(void) {
int ret = 0;
/* boot_asprintf */
Expand All @@ -618,25 +721,13 @@ 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());

return 0;
}
Expand Down Expand Up @@ -675,7 +766,7 @@ int main(void)
printf("All tests %s", "passed");
#endif
}

while (!os_GetCSC());

return 0;
Expand Down
Loading
Loading