summaryrefslogtreecommitdiff
path: root/lib/mlibc/tests/ansi
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2024-03-07 17:28:00 -0500
committerIan Moffett <ian@osmora.org>2024-03-07 17:28:32 -0500
commitbd5969fc876a10b18613302db7087ef3c40f18e1 (patch)
tree7c2b8619afe902abf99570df2873fbdf40a4d1a1 /lib/mlibc/tests/ansi
parenta95b38b1b92b172e6cc4e8e56a88a30cc65907b0 (diff)
lib: Add mlibc
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'lib/mlibc/tests/ansi')
-rw-r--r--lib/mlibc/tests/ansi/abs.c16
-rw-r--r--lib/mlibc/tests/ansi/alloc.c37
-rw-r--r--lib/mlibc/tests/ansi/calloc.c20
-rw-r--r--lib/mlibc/tests/ansi/creal-cimag.c37
-rw-r--r--lib/mlibc/tests/ansi/fenv.c91
-rw-r--r--lib/mlibc/tests/ansi/fopen.c59
-rw-r--r--lib/mlibc/tests/ansi/freopen.c49
-rw-r--r--lib/mlibc/tests/ansi/locale.c17
-rw-r--r--lib/mlibc/tests/ansi/longjmp.c29
-rw-r--r--lib/mlibc/tests/ansi/mbrtoc32.c53
-rw-r--r--lib/mlibc/tests/ansi/memmem.c22
-rw-r--r--lib/mlibc/tests/ansi/qsort.c31
-rw-r--r--lib/mlibc/tests/ansi/snprintf.c23
-rw-r--r--lib/mlibc/tests/ansi/sprintf.c191
-rw-r--r--lib/mlibc/tests/ansi/sscanf.c143
-rw-r--r--lib/mlibc/tests/ansi/strchr.c20
-rw-r--r--lib/mlibc/tests/ansi/strftime.c48
-rw-r--r--lib/mlibc/tests/ansi/strrchr.c11
-rw-r--r--lib/mlibc/tests/ansi/strtof.c83
-rw-r--r--lib/mlibc/tests/ansi/strtol.c140
-rw-r--r--lib/mlibc/tests/ansi/strverscmp.c16
-rw-r--r--lib/mlibc/tests/ansi/strxfrm.c14
-rw-r--r--lib/mlibc/tests/ansi/timegm.c45
-rw-r--r--lib/mlibc/tests/ansi/ungetc.c74
-rw-r--r--lib/mlibc/tests/ansi/utf8.c63
-rw-r--r--lib/mlibc/tests/ansi/wcsdup.c11
-rw-r--r--lib/mlibc/tests/ansi/wcsncasecmp.c11
-rw-r--r--lib/mlibc/tests/ansi/wcsrtombs.c12
-rw-r--r--lib/mlibc/tests/ansi/wmemcmp.c19
29 files changed, 1385 insertions, 0 deletions
diff --git a/lib/mlibc/tests/ansi/abs.c b/lib/mlibc/tests/ansi/abs.c
new file mode 100644
index 0000000..492040c
--- /dev/null
+++ b/lib/mlibc/tests/ansi/abs.c
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+
+int main(){
+ assert(abs(-10) == 10);
+ assert(abs(2021) == 2021);
+
+ assert(labs(-256) == 256);
+ assert(labs(10034890) == 10034890);
+
+ assert(llabs(-0x2deadbeef) == 0x2deadbeef);
+ assert(llabs(49238706947) == 49238706947);
+
+ return 0;
+} \ No newline at end of file
diff --git a/lib/mlibc/tests/ansi/alloc.c b/lib/mlibc/tests/ansi/alloc.c
new file mode 100644
index 0000000..c6ce870
--- /dev/null
+++ b/lib/mlibc/tests/ansi/alloc.c
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+int main() {
+ void *p;
+
+ p = aligned_alloc(sizeof(void *), sizeof(void *));
+ assert(p != NULL && (uintptr_t)p % sizeof(void *) == 0);
+ free(p);
+
+ p = aligned_alloc(256, 256);
+ assert(p != NULL && (uintptr_t)p % 256 == 0);
+ free(p);
+
+ // small alignments are okay
+ p = aligned_alloc(1, 8);
+ assert(p != NULL);
+ free(p);
+ p = aligned_alloc(1, 1);
+ assert(p != NULL);
+ free(p);
+
+ // It seems that glibc doesn't report error in these cases.
+#if !(defined(USE_HOST_LIBC) && defined(__GLIBC__))
+ // size % align must be 0
+ p = aligned_alloc(256, 1);
+ assert(errno == EINVAL);
+ assert(p == NULL);
+
+ // align must be a 'valid alignment supported by the implementation'
+ p = aligned_alloc(3, 1);
+ assert(errno == EINVAL);
+ assert(p == NULL);
+#endif
+}
diff --git a/lib/mlibc/tests/ansi/calloc.c b/lib/mlibc/tests/ansi/calloc.c
new file mode 100644
index 0000000..6cfc87d
--- /dev/null
+++ b/lib/mlibc/tests/ansi/calloc.c
@@ -0,0 +1,20 @@
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+int main() {
+ errno = 0;
+ void *ptr = calloc((SIZE_MAX / 2) + 2, 2);
+ assert(!ptr);
+ assert(errno);
+
+ errno = 0;
+ ptr = calloc(sizeof(size_t), 10);
+ assert(ptr);
+ for(size_t i = 0; i < 10; i++) {
+ size_t *p = ptr;
+ assert(!p[i]);
+ }
+}
diff --git a/lib/mlibc/tests/ansi/creal-cimag.c b/lib/mlibc/tests/ansi/creal-cimag.c
new file mode 100644
index 0000000..fc70aa3
--- /dev/null
+++ b/lib/mlibc/tests/ansi/creal-cimag.c
@@ -0,0 +1,37 @@
+#include <assert.h>
+#include <math.h>
+#include <complex.h>
+
+// FIXME: We should create a proper floating point facility
+// in order for other functions to be tested properly
+
+#define APPROXIMATELY_EQUAL(calculated, expected) fabs((calculated) - (expected)) <= 0.0000005
+#define APPROXIMATELY_EQUALF(calculated, expected) fabsf((calculated) - (expected)) <= 0.0000005f
+#define APPROXIMATELY_EQUALL(calculated, expected) fabsl((calculated) - (expected)) <= 0.0000005L
+
+#define IS_COMPLEX_NUMBER(Z) \
+ _Generic((Z), \
+ double complex: 1, \
+ float complex: 1, \
+ long double complex: 1, \
+ default: 0 \
+ )
+
+int main() {
+ assert(IS_COMPLEX_NUMBER(CMPLX(5.2, 4.3)));
+ double complex cz = CMPLX(5.2, 4.3);
+ assert(APPROXIMATELY_EQUAL(creal(cz), 5.2));
+ assert(APPROXIMATELY_EQUAL(cimag(cz), 4.3));
+
+ assert(IS_COMPLEX_NUMBER(CMPLXF(1.2f, 2.5f)));
+ float complex czf = CMPLXF(1.2f, 2.5f);
+ assert(APPROXIMATELY_EQUALF(crealf(czf), 1.2f));
+ assert(APPROXIMATELY_EQUALF(cimagf(czf), 2.5f));
+
+ assert(IS_COMPLEX_NUMBER(CMPLXL(0.1L, 123.54L)));
+ long double complex czl = CMPLXL(0.1L, 123.54L);
+ assert(APPROXIMATELY_EQUALL(creall(czl), 0.1L));
+ assert(APPROXIMATELY_EQUALL(cimagl(czl), 123.54L));
+
+ return 0;
+} \ No newline at end of file
diff --git a/lib/mlibc/tests/ansi/fenv.c b/lib/mlibc/tests/ansi/fenv.c
new file mode 100644
index 0000000..629a5cb
--- /dev/null
+++ b/lib/mlibc/tests/ansi/fenv.c
@@ -0,0 +1,91 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <fenv.h>
+#include <float.h>
+#include <math.h>
+
+#define NO_OPTIMIZE(x) asm volatile("" :: "r,m" (x) : "memory")
+
+static void div_by_zero() {
+ volatile float zero = 0.0f;
+ NO_OPTIMIZE(69.0f / zero);
+}
+
+static bool float_cmp(float a, float b) {
+ return a == b || fabs(a - b) < (fabs(a) + fabs(b)) * FLT_EPSILON;
+}
+
+static void test_rounding(float expectation1, float expectation2) {
+ float x;
+ volatile float f = 1.968750f;
+ volatile float m = 0x1.0p23f;
+
+ NO_OPTIMIZE(x = f + m);
+ assert(float_cmp(expectation1, x));
+ NO_OPTIMIZE(x = x - m);
+ assert(x == expectation2);
+}
+
+void test0() {
+ // test whether the divide-by-zero exception is raised
+ feclearexcept(FE_ALL_EXCEPT);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+
+ div_by_zero();
+ int raised = fetestexcept(FE_DIVBYZERO);
+ assert((raised & FE_DIVBYZERO));
+}
+
+void test1() {
+ // test various rounding modes
+ feclearexcept(FE_DIVBYZERO);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+
+ fesetround(FE_UPWARD);
+ assert(fegetround() == FE_UPWARD);
+ test_rounding(8388610.0f, 2.0f);
+
+ fesetround(FE_DOWNWARD);
+ assert(fegetround() == FE_DOWNWARD);
+ test_rounding(8388609.0f, 1.0f);
+
+ fesetround(FE_TONEAREST);
+ assert(fegetround() == FE_TONEAREST);
+ test_rounding(8388610.0f, 2.0f);
+
+ fesetround(FE_TOWARDZERO);
+ assert(fegetround() == FE_TOWARDZERO);
+ test_rounding(8388609.0f, 1.0f);
+}
+
+void test2() {
+ // test feraiseexcept
+ feclearexcept(FE_ALL_EXCEPT);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ assert(feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW));
+}
+
+void test3() {
+ // test fe{get,set}env
+ feclearexcept(FE_ALL_EXCEPT);
+ assert(fetestexcept(FE_ALL_EXCEPT) == 0);
+ assert(feraiseexcept(FE_OVERFLOW) == 0);
+
+ fenv_t state;
+ assert(fegetenv(&state) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW);
+
+ div_by_zero();
+ assert(fetestexcept(FE_ALL_EXCEPT) == (FE_DIVBYZERO | FE_OVERFLOW));
+
+ assert(fesetenv(&state) == 0);
+ assert(fetestexcept(FE_ALL_EXCEPT) == FE_OVERFLOW);
+}
+
+int main() {
+ test0();
+ test1();
+ test2();
+ test3();
+}
diff --git a/lib/mlibc/tests/ansi/fopen.c b/lib/mlibc/tests/ansi/fopen.c
new file mode 100644
index 0000000..f4818b2
--- /dev/null
+++ b/lib/mlibc/tests/ansi/fopen.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef USE_HOST_LIBC
+#define TEST_FILE "fopen-host-libc.tmp"
+#else
+#define TEST_FILE "fopen.tmp"
+#endif
+
+int main() {
+ FILE *file;
+ char str[] = "mlibc fopen test";
+ char str2[] = " mlibc appending";
+ char completestr[] = "mlibc fopen test mlibc appending";
+ char buffer[100];
+ char buffer2[100];
+
+ // Clear all the buffers to zero.
+ memset(buffer, 0, sizeof(buffer));
+ memset(buffer2, 0, sizeof(buffer2));
+
+ // Open the file for writing.
+ file = fopen(TEST_FILE, "w");
+ assert(file);
+
+ // Write string minus null terminator, flush and close.
+ fwrite(str, 1, sizeof(str) - 1, file);
+ fflush(file);
+ fclose(file);
+
+ // Open the file for reading.
+ file = fopen(TEST_FILE, "r");
+ assert(file);
+
+ // Verify that we read back the written string and close the file.
+ assert(fread(buffer, 1, sizeof(str) - 1, file));
+ assert(!strcmp(buffer, str));
+ fclose(file);
+
+ // Open the file in appending mode, append string 2 (minus the null terminator) to the file, flush and close.
+ file = fopen(TEST_FILE, "a");
+ fwrite(str2, 1, sizeof(str2) - 1, file);
+ fflush(file);
+ fclose(file);
+
+ // Open the file for reading again, verify the contents, close the file and return.
+ file = fopen(TEST_FILE, "r");
+ assert(fread(buffer2, 1, sizeof(completestr) - 1, file));
+ assert(!strcmp(buffer2, completestr));
+ fclose(file);
+
+ // Check that stdout, stdin and stderr can be closed by the application (issue #12).
+ fclose(stdout);
+ fclose(stdin);
+ fclose(stderr);
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/freopen.c b/lib/mlibc/tests/ansi/freopen.c
new file mode 100644
index 0000000..c91577f
--- /dev/null
+++ b/lib/mlibc/tests/ansi/freopen.c
@@ -0,0 +1,49 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef USE_HOST_LIBC
+#define TEST_FILE "freopen-host-libc.tmp"
+#else
+#define TEST_FILE "freopen.tmp"
+#endif
+
+int main() {
+ FILE *file = fopen(TEST_FILE, "w");
+ assert(file);
+
+ assert(freopen("/dev/null", "w", file));
+
+ char str[] = "mlibc freopen test";
+ fwrite(str, 1, sizeof(str) - 1, file);
+ fflush(file);
+ fclose(file);
+
+ file = fopen(TEST_FILE, "r");
+ assert(file);
+
+ char buf[sizeof(str)];
+ memset(buf, 0, sizeof(buf));
+ int ret = fread(buf, 1, sizeof(buf) - 1, file);
+ fprintf(stderr, "ret %d\n", ret);
+ assert(ret == 0);
+ fclose(file);
+
+ file = fopen("/dev/null", "w");
+ assert(file);
+
+ assert(freopen(TEST_FILE, "w", file));
+ fwrite(str, 1, sizeof(str) - 1, file);
+ fflush(file);
+ fclose(file);
+
+ memset(buf, 0, sizeof(buf));
+ file = fopen(TEST_FILE, "r");
+ assert(fread(buf, 1, sizeof(buf) - 1, file));
+
+ fprintf(stderr, "buffer content '%s'\n", buf);
+ assert(!strcmp(buf, "mlibc freopen test"));
+ fclose(file);
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/locale.c b/lib/mlibc/tests/ansi/locale.c
new file mode 100644
index 0000000..056298b
--- /dev/null
+++ b/lib/mlibc/tests/ansi/locale.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <wchar.h>
+#include <locale.h>
+#include <assert.h>
+
+int main() {
+ wchar_t c = 0xC9;
+ unsigned char buf[sizeof(wchar_t)] = { 0 };
+ setlocale(LC_ALL, "");
+ if (sprintf(buf, "%lc", c) < 0)
+ return -1;
+
+ assert(buf[0] == 0xc3 && buf[1] == 0x89
+ && buf[2] == '\0' && buf[3] == '\0');
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/longjmp.c b/lib/mlibc/tests/ansi/longjmp.c
new file mode 100644
index 0000000..9f9c1ed
--- /dev/null
+++ b/lib/mlibc/tests/ansi/longjmp.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <setjmp.h>
+#include <stdnoreturn.h>
+#include <assert.h>
+
+jmp_buf buf;
+
+noreturn void do_jump(int arg) {
+ longjmp(buf, 2 * arg);
+}
+
+int main(void) {
+ volatile int times_called = 0;
+
+ if (setjmp(buf) != 8) {
+ do_jump(++times_called);
+ }
+
+ assert(times_called == 4);
+
+ times_called = 0;
+ int ret = setjmp(buf);
+ assert(ret == times_called);
+
+ if (!ret) {
+ times_called = 1;
+ longjmp(buf, 0);
+ }
+}
diff --git a/lib/mlibc/tests/ansi/mbrtoc32.c b/lib/mlibc/tests/ansi/mbrtoc32.c
new file mode 100644
index 0000000..781bc71
--- /dev/null
+++ b/lib/mlibc/tests/ansi/mbrtoc32.c
@@ -0,0 +1,53 @@
+#include <assert.h>
+#include <locale.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <uchar.h>
+
+struct {
+ size_t ret;
+ char32_t c32;
+ uint8_t bytes[4];
+} expected_results[] = {
+ {1, 0x7A, {0x7A, 0, 0, 0}},
+ {2, 0xDF, {0xC3, 0x9F, 0, 0}},
+ {3, 0x6C34, {0xE6, 0xB0, 0xB4, 0}},
+ {4, 0x1F34C, {0xF0, 0x9F, 0x8D, 0x8C}},
+};
+
+int main() {
+ setlocale(LC_ALL, "en_US.utf8");
+
+ size_t ret = 0;
+
+ char *str = "z\u00df\u6c34\U0001F34C";
+
+ fprintf(stderr, "string: '%s'\n", str);
+
+ mbstate_t state = {};
+ char32_t c32;
+ size_t loop = 0;
+ while((ret = mbrtoc32(&c32, str, strlen(str), &state))) {
+ assert(ret != (size_t)-3);
+ if(ret == (size_t)-1)
+ break;
+ if(ret == (size_t)-2)
+ break;
+
+ fprintf(stderr, "Next UTF-32 char: 0x%x obtained from %zu bytes [", c32, ret);
+ for(size_t n = 0; n < ret; ++n) {
+ fprintf(stderr, " 0x%02x ", (uint8_t) str[n]);
+ }
+ fprintf(stderr, "]\n");
+
+ assert(ret == expected_results[loop].ret);
+ assert(c32 == expected_results[loop].c32);
+ for(size_t n = 0; n < ret; ++n) {
+ assert((uint8_t) str[n] == expected_results[loop].bytes[n]);
+ }
+
+ str += ret;
+ loop++;
+ }
+}
diff --git a/lib/mlibc/tests/ansi/memmem.c b/lib/mlibc/tests/ansi/memmem.c
new file mode 100644
index 0000000..8de558f
--- /dev/null
+++ b/lib/mlibc/tests/ansi/memmem.c
@@ -0,0 +1,22 @@
+#include <string.h>
+#include <assert.h>
+
+int main() {
+ char *haystack = "abc123\0x45";
+
+ char *needle1 = "abc";
+ void *rv = memmem(haystack, strlen(haystack), needle1, strlen(needle1));
+ assert(rv == haystack);
+
+ char *needle2 = "123";
+ rv = memmem(haystack, strlen(haystack), needle2, strlen(needle2));
+ assert(rv == haystack + 3);
+
+ char *needle3 = "1234";
+ rv = memmem(haystack, strlen(haystack), needle3, strlen(needle3));
+ assert(rv == NULL);
+
+ char *needle4 = "23\0x45";
+ rv = memmem(haystack, 10, needle4, 6);
+ assert(rv == haystack + 4);
+}
diff --git a/lib/mlibc/tests/ansi/qsort.c b/lib/mlibc/tests/ansi/qsort.c
new file mode 100644
index 0000000..bb48a23
--- /dev/null
+++ b/lib/mlibc/tests/ansi/qsort.c
@@ -0,0 +1,31 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char *arr[] = { "xyz", "abc", "ghi", "def" };
+
+static const size_t magic = 0xDEADBEEF;
+
+static int cmpstringp(const void *p1, const void *p2, void *ctx) {
+ /* The actual arguments to this function are "pointers to
+ * pointers to char", but strcmp(3) arguments are "pointers
+ * to char", hence the following cast plus dereference. */
+ assert(*(size_t *) ctx == magic);
+ return strcmp(*(const char **) p1, *(const char **) p2);
+}
+
+int main() {
+ qsort_r(&arr[0], sizeof(arr) / sizeof(*arr), sizeof(char *), cmpstringp, (void *) &magic);
+
+ assert(!strcmp(arr[0], "abc"));
+ assert(!strcmp(arr[1], "def"));
+ assert(!strcmp(arr[2], "ghi"));
+ assert(!strcmp(arr[3], "xyz"));
+
+ for(size_t i = 0; i < sizeof(arr) / sizeof(*arr); i++) {
+ fprintf(stderr, "%s\n", arr[i]);
+ }
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/snprintf.c b/lib/mlibc/tests/ansi/snprintf.c
new file mode 100644
index 0000000..82e4640
--- /dev/null
+++ b/lib/mlibc/tests/ansi/snprintf.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+int main() {
+ char buffer[10];
+ int ret = snprintf(buffer, 10, "%d", 123456789);
+ assert(strncmp("123456789", buffer, 10) == 0);
+ assert(ret == 9);
+
+ // We deliberately induce a warning here.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-truncation"
+ ret = snprintf(buffer, 10, "%d", 1234567890);
+ assert(strncmp("123456789", buffer, 10) == 0);
+ assert(ret == 10);
+#pragma GCC diagnostic pop
+
+ // mlibc issue #118.
+ ret = snprintf(NULL, 0, "%d", 123456789);
+ assert(ret == 9);
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/sprintf.c b/lib/mlibc/tests/ansi/sprintf.c
new file mode 100644
index 0000000..fd9398c
--- /dev/null
+++ b/lib/mlibc/tests/ansi/sprintf.c
@@ -0,0 +1,191 @@
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+int main() {
+ char buf[11] = { 0 };
+ sprintf(buf, "%d", 12);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%f", 3.14);
+ assert(!strcmp(buf, "3.140000"));
+
+ // Test %c right padding.
+ sprintf(buf, "%-2c", 'a');
+ assert(!strcmp(buf, "a "));
+
+ // Test %c left padding.
+ sprintf(buf, "%2c", 'a');
+ assert(!strcmp(buf, " a"));
+
+ // Test %d right padding - mlibc issue #58.
+ sprintf(buf, "%-2d", 1);
+ assert(!strcmp(buf, "1 "));
+ sprintf(buf, "%-2.2d", 1);
+ assert(!strcmp(buf, "01"));
+ sprintf(buf, "%-3.2d", 1);
+ assert(!strcmp(buf, "01 "));
+ sprintf(buf, "%-3.2d", 12);
+ assert(!strcmp(buf, "12 "));
+ sprintf(buf, "%-3.2d", 123);
+ assert(!strcmp(buf, "123"));
+ sprintf(buf, "%-3.2u", 12);
+ assert(!strcmp(buf, "12 "));
+
+ // Test %d left padding.
+ sprintf(buf, "%2d", 1);
+ assert(!strcmp(buf, " 1"));
+ sprintf(buf, "%3.2d", 1);
+ assert(!strcmp(buf, " 01"));
+ sprintf(buf, "%3.2d", 12);
+ assert(!strcmp(buf, " 12"));
+ sprintf(buf, "%3.2d", 123);
+ assert(!strcmp(buf, "123"));
+ sprintf(buf, "%3.2u", 12);
+ assert(!strcmp(buf, " 12"));
+
+ // Test %f padding.
+ // TODO: Test printing of huge numbers (larger than 2^64)
+ sprintf(buf, "%2.f", 1.2);
+ assert(!strcmp(buf, " 1"));
+ sprintf(buf, "%2.f", 12.3);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%5.2f", 1.0);
+ assert(!strcmp(buf, " 1.00"));
+ sprintf(buf, "%.1f", -4.0);
+ assert(!strcmp(buf, "-4.0"));
+ sprintf(buf, "%-3.f", 8.0);
+ assert(!strcmp(buf, "8 "));
+ sprintf(buf, "%4f", INFINITY);
+ assert(!strcmp(buf, " inf") || !strcmp(buf, "infinity"));
+ sprintf(buf, "%4f", NAN);
+ assert(!strcmp(buf, " nan"));
+ sprintf(buf, "%4F", INFINITY);
+ assert(!strcmp(buf, " INF") || !strcmp(buf, "INFINITY"));
+ sprintf(buf, "%4F", NAN);
+ assert(!strcmp(buf, " NAN"));
+ sprintf(buf, "%05.2f", 1.0);
+ assert(!strcmp(buf, "01.00"));
+ sprintf(buf, "%09f", INFINITY); // 0 ignored when padding infs
+ assert(!strcmp(buf, " inf") || !strcmp(buf, " infinity"));
+ // TODO: We don't yet round properly
+ // sprintf(buf, "%5.2f", 1.2);
+ // assert(!strcmp(buf, " 1.20"));
+ // sprintf(buf, "%5.2f", 1.23);
+ // assert(!strcmp(buf, " 1.23"));
+ // sprintf(buf, "%5.2f", 1.234);
+ // assert(!strcmp(buf, " 1.23"));
+ // sprintf(buf, "%5.2f", 12.345);
+ // assert(!strcmp(buf, "12.35"));
+ // sprintf(buf, "%-5.2f", 1.2);
+ // assert(!strcmp(buf, "1.20 "));
+
+ // Test '+' and ' ' flags - mlibc issue #229.
+ // Disable -Wformat here since we deliberately induce some warnings.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+ sprintf(buf, "%+d", 12);
+ assert(!strcmp(buf, "+12"));
+ sprintf(buf, "% d", 12);
+ assert(!strcmp(buf, " 12"));
+ sprintf(buf, "% +d", 12);
+ assert(!strcmp(buf, "+12"));
+ sprintf(buf, "%+ d", 12);
+ assert(!strcmp(buf, "+12"));
+ sprintf(buf, "%+d", -12);
+ assert(!strcmp(buf, "-12"));
+ sprintf(buf, "% d", -12);
+ assert(!strcmp(buf, "-12"));
+ sprintf(buf, "% +d", -12);
+ assert(!strcmp(buf, "-12"));
+ sprintf(buf, "%+ d", -12);
+ assert(!strcmp(buf, "-12"));
+#pragma GCC diagnostic pop
+
+ // Test '#' flag.
+ // TODO: Test with a, A, e, E, f, F, g, G conversions.
+ sprintf(buf, "%#x", 12);
+ assert(!strcmp(buf, "0xc"));
+ sprintf(buf, "%#X", 12);
+ assert(!strcmp(buf, "0XC"));
+ sprintf(buf, "%#o", 12);
+ assert(!strcmp(buf, "014"));
+ sprintf(buf, "%#x", 0);
+ assert(!strcmp(buf, "0"));
+ sprintf(buf, "%#X", 0);
+ assert(!strcmp(buf, "0"));
+ sprintf(buf, "%#o", 0);
+ assert(!strcmp(buf, "0"));
+
+ // Test 'd' with different size mods to see
+ // if they work
+ sprintf(buf, "%d", 12);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%ld", 12L);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%lld", 12LL);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%zd", (size_t)12);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%hd", 12);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%hhd", 12);
+ assert(!strcmp(buf, "12"));
+
+ // Test 'x' with different size mods to see
+ // if they work
+ sprintf(buf, "%x", 12);
+ assert(!strcmp(buf, "c"));
+ sprintf(buf, "%lx", 12L);
+ assert(!strcmp(buf, "c"));
+ sprintf(buf, "%llx", 12LL);
+ assert(!strcmp(buf, "c"));
+ sprintf(buf, "%zx", (size_t)12);
+ assert(!strcmp(buf, "c"));
+ sprintf(buf, "%hx", 12);
+ assert(!strcmp(buf, "c"));
+ sprintf(buf, "%hhx", 12);
+ assert(!strcmp(buf, "c"));
+
+ // Test 'X' with different size mods to see
+ // if they work
+ sprintf(buf, "%X", 12);
+ assert(!strcmp(buf, "C"));
+ sprintf(buf, "%lX", 12L);
+ assert(!strcmp(buf, "C"));
+ sprintf(buf, "%llX", 12LL);
+ assert(!strcmp(buf, "C"));
+ sprintf(buf, "%zX", (size_t)12);
+ assert(!strcmp(buf, "C"));
+ sprintf(buf, "%hX", 12);
+ assert(!strcmp(buf, "C"));
+ sprintf(buf, "%hhX", 12);
+ assert(!strcmp(buf, "C"));
+
+ // Test 'o' with different size mods to see
+ // if they work
+ sprintf(buf, "%o", 12);
+ assert(!strcmp(buf, "14"));
+ sprintf(buf, "%lo", 12L);
+ assert(!strcmp(buf, "14"));
+ sprintf(buf, "%llo", 12LL);
+ assert(!strcmp(buf, "14"));
+ sprintf(buf, "%zo", (size_t)12);
+ assert(!strcmp(buf, "14"));
+ sprintf(buf, "%ho", 12);
+ assert(!strcmp(buf, "14"));
+ sprintf(buf, "%hho", 12);
+ assert(!strcmp(buf, "14"));
+
+ // Test %n$ syntax.
+ sprintf(buf, "%1$d", 12);
+ assert(!strcmp(buf, "12"));
+ sprintf(buf, "%1$d %1$d", 12);
+ assert(!strcmp(buf, "12 12"));
+ sprintf(buf, "%1$d %2$d %1$d", 12, 14);
+ assert(!strcmp(buf, "12 14 12"));
+ sprintf(buf, "%1$d %2$s %2$s", 12, "foo");
+ assert(!strcmp(buf, "12 foo foo"));
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/sscanf.c b/lib/mlibc/tests/ansi/sscanf.c
new file mode 100644
index 0000000..f3a881f
--- /dev/null
+++ b/lib/mlibc/tests/ansi/sscanf.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+struct format_test_cases {
+ const char *format;
+ const char *data;
+ int expected_int;
+ enum {
+ T_INT,
+ T_UINT,
+ T_CHAR,
+ T_NONE,
+ } type;
+ int ret;
+} formats[] = {
+ {"%i", "0x420", 0x420, T_INT, 1},
+ {"%i", "0420", 0420, T_INT, 1},
+ {"%i", "420", 420, T_INT, 1},
+ {"%i", "-420", -420, T_INT, 1},
+ {"%d", "-12345", -12345, T_INT, 1},
+ {"%u", "69", 69, T_UINT, 1},
+ {"%u", "0420", 420, T_UINT, 1},
+ {"%o", "0420", 0420, T_UINT, 1},
+ {"%x", "0xCB7", 0xCB7, T_UINT, 1},
+ {"%%", "%", 0, T_NONE, 0},
+ {"%c", " I am not a fan of this solution.", ' ', T_CHAR, 1},
+ {" %c", " CBT (capybara therapy)", 'C', T_CHAR, 1},
+};
+
+#pragma GCC diagnostic ignored "-Wformat-security"
+
+static void test_matrix() {
+ for(size_t i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) {
+ struct format_test_cases *f = &formats[i];
+ int ret = -1;
+ int data_int;
+ unsigned int data_uint;
+ char data_char;
+
+ switch(f->type) {
+ case T_INT: {
+ ret = sscanf(f->data, f->format, &data_int);
+ assert(data_int == f->expected_int);
+ break;
+ }
+ case T_UINT: {
+ ret = sscanf(f->data, f->format, &data_uint);
+ assert(data_uint == (unsigned int) f->expected_int);
+ break;
+ }
+ case T_CHAR: {
+ ret = sscanf(f->data, f->format, &data_char);
+ assert(data_char == (unsigned char) f->expected_int);
+ break;
+ }
+ case T_NONE: {
+ ret = sscanf(f->data, f->format);
+ break;
+ }
+
+ }
+
+ assert(ret == f->ret);
+ }
+}
+
+int main() {
+ {
+ int x = 0;
+ char buf[] = "12345";
+ sscanf(buf, "%d", &x);
+ assert(x == 12345);
+ }
+
+ {
+ char c;
+ int n1;
+ int n2;
+ char buf[] = "z$ 7 5 440";;
+ int count = sscanf(buf, "%*c%c %d %*d %d", &c, &n1, &n2);
+ assert(count == 3);
+ assert(c == '$');
+ assert(n1 == 7);
+ assert(n2 == 440);
+ }
+
+ {
+ // From dsda-doom
+ char buf[] = "process_priority 0\n";
+ char def[80], strparm[128];
+ memset(def, '!', 80);
+ memset(strparm, '!', 128);
+ sscanf(buf, "%s %[^\n]\n", def, strparm);
+ assert(!strcmp(def, "process_priority"));
+ assert(!strcmp(strparm, "0"));
+ }
+
+ {
+ char buf[] = "fffff100";
+ unsigned long y = 0;
+ sscanf(buf, "%lx", &y);
+ assert(y == 0xfffff100);
+ }
+
+#if !defined(__i386__)
+ {
+ char buf[] = "fffffffff100";
+ unsigned long y = 0;
+ sscanf(buf, "%lx", &y);
+ assert(y == 0xfffffffff100);
+ }
+#endif
+
+ {
+ char buf[] = "410dc000";
+ unsigned long y = 0;
+ sscanf(buf, "%lx", &y);
+ assert(y == 0x410dc000);
+ }
+
+ {
+ // From webkitgtk
+ char buf[] = "MemTotal: 16299664 kB\n";
+ char token[51] = {0};
+ size_t amount = 0;
+ int ret = sscanf(buf, "%50s%zukB", token, &amount);
+ assert(ret == 2);
+ assert(!strcmp(token, "MemTotal:"));
+ assert(amount == 16299664);
+ }
+
+ {
+ char buf[] = "SIGINT";
+ int sig;
+ int ret = sscanf(buf, "%d", &sig);
+ assert(!ret);
+ }
+
+ test_matrix();
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/strchr.c b/lib/mlibc/tests/ansi/strchr.c
new file mode 100644
index 0000000..a80a1f9
--- /dev/null
+++ b/lib/mlibc/tests/ansi/strchr.c
@@ -0,0 +1,20 @@
+#include <assert.h>
+#include <string.h>
+#include <stddef.h>
+
+int main() {
+ char str[] = "This is a sample string";
+ char *pch;
+ // The character 's' is at position 4, 7, 11 and 18
+ pch = strchr(str, 's');
+ assert(pch - str + 1 == 4);
+ pch = strchr(pch + 1, 's');
+ assert(pch - str + 1 == 7);
+ pch = strchr(pch + 1, 's');
+ assert(pch - str + 1 == 11);
+ pch = strchr(pch + 1, 's');
+ assert(pch - str + 1 == 18);
+ pch = strchr(pch + 1, 's');
+ assert(pch == NULL);
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/strftime.c b/lib/mlibc/tests/ansi/strftime.c
new file mode 100644
index 0000000..69ec642
--- /dev/null
+++ b/lib/mlibc/tests/ansi/strftime.c
@@ -0,0 +1,48 @@
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <locale.h>
+#include <stdio.h>
+
+int main() {
+ // Date representation depends on locale, here only C is tested.
+ // Maybe consider testing more locales?
+ if (setlocale (LC_ALL, "C") == NULL) {
+ fputs("strftime testcase could not set locale, errors may be expected!", stderr);
+ }
+
+ char timebuf[16];
+ char result[16] = " 8";
+ struct tm tm;
+ tm.tm_sec = 0;
+ tm.tm_min = 17;
+ tm.tm_hour = 17;
+ tm.tm_mday = 8;
+ tm.tm_mon = 2;
+ tm.tm_year = 121;
+ tm.tm_wday = 2;
+ tm.tm_yday = 39;
+ strftime(timebuf, sizeof(timebuf), "%e", &tm);
+ assert(!strcmp(timebuf, result));
+
+ memset(timebuf, 0, sizeof(timebuf));
+ strftime(timebuf, sizeof(timebuf), "%x", &tm);
+ assert(!strcmp(timebuf, "03/08/21"));
+
+ memset(timebuf, 0, sizeof(timebuf));
+ strftime(timebuf, sizeof(timebuf), "%X", &tm);
+ assert(!strcmp(timebuf, "17:17:00"));
+
+ memset(timebuf, 0, sizeof(timebuf));
+ strftime(timebuf, sizeof(timebuf), "%a %A", &tm);
+ assert(!strcmp(timebuf, "Tue Tuesday"));
+
+ memset(timebuf, 0, sizeof(timebuf));
+ strftime(timebuf, sizeof(timebuf), "%b %B %h", &tm);
+ assert(!strcmp(timebuf, "Mar March Mar"));
+
+ memset(timebuf, 0, sizeof(timebuf));
+ assert(!strftime(timebuf, sizeof(timebuf), "%a %A %a %A %b %B %h", &tm));
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/strrchr.c b/lib/mlibc/tests/ansi/strrchr.c
new file mode 100644
index 0000000..2de9821
--- /dev/null
+++ b/lib/mlibc/tests/ansi/strrchr.c
@@ -0,0 +1,11 @@
+#include <string.h>
+#include <assert.h>
+
+int main() {
+ char str[] = "This is a sample string";
+ char *pch;
+ pch = strrchr(str, 's');
+ // The last occurence of 's' is at position 18
+ assert(pch - str + 1 == 18);
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/strtof.c b/lib/mlibc/tests/ansi/strtof.c
new file mode 100644
index 0000000..a13af90
--- /dev/null
+++ b/lib/mlibc/tests/ansi/strtof.c
@@ -0,0 +1,83 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+#define FLT_RANGE 0.000001f
+#define DBL_RANGE 0.000001
+#define LDBL_RANGE 0.000001
+
+#define DO_TEST(str, value, off, func, range) ({ \
+ char s[] = (str); \
+ char *pEnd = NULL; \
+ __typeof(func(s, &pEnd)) result = func(s, &pEnd); \
+ assert(result >= (value) - (range)); \
+ assert(result <= (value) + (range)); \
+ assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); })
+
+#define DO_TEST_SUCCESS_FUNC(str, success_func, off, func) ({ \
+ char s[] = (str); \
+ char *pEnd = NULL; \
+ assert(success_func(func(s, &pEnd))); \
+ assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); })
+
+int main () {
+ DO_TEST("0", 0.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("0.12", 0.12f, -1, strtof, FLT_RANGE);
+ DO_TEST("12", 12.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("12.13", 12.13f, -1, strtof, FLT_RANGE);
+ DO_TEST("10.0e1", 100.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("10.0e10", 100000000000.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("100.0e-1", 10.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("0x0", 0.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("0x0.12", 0.0703125f, -1, strtof, FLT_RANGE);
+ DO_TEST("0x12", 18.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("0x12.13", 18.07421875f, -1, strtof, FLT_RANGE);
+ DO_TEST("0x10.0p1", 32.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("0x10.0p10", 16384.0f, -1, strtof, FLT_RANGE);
+ DO_TEST("0x100.0p-1", 128.0f, -1, strtof, FLT_RANGE);
+ DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtof);
+ DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtof);
+ DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtof);
+ DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtof);
+
+ DO_TEST("0", 0.0, -1, strtod, DBL_RANGE);
+ DO_TEST("0.12", 0.12, -1, strtod, DBL_RANGE);
+ DO_TEST("12", 12.0, -1, strtod, DBL_RANGE);
+ DO_TEST("12.13", 12.13, -1, strtod, DBL_RANGE);
+ DO_TEST("10.0e1", 100.0, -1, strtod, DBL_RANGE);
+ DO_TEST("10.0e10", 100000000000.0, -1, strtod, DBL_RANGE);
+ DO_TEST("100.0e-1", 10.0, -1, strtod, DBL_RANGE);
+ DO_TEST("0x0", 0.0, -1, strtod, DBL_RANGE);
+ DO_TEST("0x0.12", 0.0703125, -1, strtod, DBL_RANGE);
+ DO_TEST("0x12", 18.0, -1, strtod, DBL_RANGE);
+ DO_TEST("0x12.13", 18.07421875, -1, strtod, DBL_RANGE);
+ DO_TEST("0x10.0p1", 32.0, -1, strtod, DBL_RANGE);
+ DO_TEST("0x10.0p10", 16384.0, -1, strtod, DBL_RANGE);
+ DO_TEST("0x100.0p-1", 128.0, -1, strtod, DBL_RANGE);
+ DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtod);
+ DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtod);
+ DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtod);
+ DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtod);
+
+ DO_TEST("0", 0.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("0.12", 0.12, -1, strtold, LDBL_RANGE);
+ DO_TEST("12", 12.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("12.13", 12.13, -1, strtold, LDBL_RANGE);
+ DO_TEST("10.0e1", 100.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("10.0e10", 100000000000.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("100.0e-1", 10.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("0x0", 0.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("0x0.12", 0.0703125, -1, strtold, LDBL_RANGE);
+ DO_TEST("0x12", 18.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("0x12.13", 18.07421875, -1, strtold, LDBL_RANGE);
+ DO_TEST("0x10.0p1", 32.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("0x10.0p10", 16384.0, -1, strtold, LDBL_RANGE);
+ DO_TEST("0x100.0p-1", 128.0, -1, strtold, LDBL_RANGE);
+ DO_TEST_SUCCESS_FUNC("NAN", isnan, -1, strtold);
+ DO_TEST_SUCCESS_FUNC("nan", isnan, -1, strtold);
+ DO_TEST_SUCCESS_FUNC("INF", isinf, -1, strtold);
+ DO_TEST_SUCCESS_FUNC("INFINITY", isinf, -1, strtold);
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/strtol.c b/lib/mlibc/tests/ansi/strtol.c
new file mode 100644
index 0000000..823cb4a
--- /dev/null
+++ b/lib/mlibc/tests/ansi/strtol.c
@@ -0,0 +1,140 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <wchar.h>
+
+#define DO_TEST(str, value, off, func, base) ({ \
+ char s[] = (str); \
+ char *pEnd = NULL; \
+ errno = 0; \
+ assert(func(s, &pEnd, base) == (value)); \
+ assert(errno == 0); \
+ assert(pEnd == (off == -1 ? s + strlen(s) : s + off)); })
+
+#define DO_ERR_TEST(str, value, err, func, base) ({ \
+ char s[] = (str); \
+ char *pEnd = NULL; \
+ errno = 0; \
+ assert(func(s, &pEnd, base) == (value)); \
+ assert(errno == err); \
+ assert(pEnd == (err == ERANGE ? s + strlen(s) : s)); })
+
+#define DO_TESTL(str, value, off, func, base) ({ \
+ wchar_t s[] = (str); \
+ wchar_t *pEnd = NULL; \
+ errno = 0; \
+ assert(func(s, &pEnd, base) == (value)); \
+ assert(errno == 0); \
+ assert(pEnd == (off == -1 ? s + wcslen(s) : s + off)); })
+
+#define DO_ERR_TESTL(str, value, err, func, base) ({ \
+ wchar_t s[] = (str); \
+ wchar_t *pEnd = NULL; \
+ errno = 0; \
+ assert(func(s, &pEnd, base) == (value)); \
+ assert(errno == err); \
+ assert(pEnd == (err == ERANGE ? s + wcslen(s) : s)); })
+
+int main () {
+ // A few generic checks.
+ DO_TEST("0", 0, -1, strtol, 0);
+ DO_TEST("0", 0, -1, strtol, 10);
+ DO_TEST("2001", 2001, -1, strtol, 10);
+ DO_TEST("+2001", 2001, -1, strtol, 10);
+ DO_TEST("60c0c0", 0x60c0c0, -1, strtol, 16);
+ DO_TEST("-1101110100110100100000", -3624224, -1, strtol, 2);
+ DO_TEST("0x6fffff", 0x6fffff, -1, strtol, 0);
+ DO_TEST("0666", 0666, -1, strtol, 0);
+ DO_TEST("0xzzz", 0, 1, strtol, 0);
+ DO_TEST("0yzzz", 0, 1, strtol, 0);
+ DO_TEST("00xzz", 0, 2, strtol, 0);
+ DO_ERR_TEST("", 0, 0, strtol, 10);
+ DO_ERR_TEST("asd", 0, 0, strtol, 10);
+ DO_ERR_TEST("999999999999999999999999999", LONG_MAX, ERANGE, strtol, 10);
+ DO_ERR_TEST("-999999999999999999999999999", LONG_MIN, ERANGE, strtol, 10);
+
+ // strtol
+#if defined(__i386__)
+ DO_TEST("-2147483648", LONG_MIN, -1, strtol, 10);
+ DO_TEST("2147483647", LONG_MAX, -1, strtol, 10);
+ DO_ERR_TEST("-2147483649", LONG_MIN, ERANGE, strtol, 10);
+ DO_ERR_TEST("2147483648", LONG_MAX, ERANGE, strtol, 10);
+#else
+ DO_TEST("-9223372036854775808", LONG_MIN, -1, strtol, 10);
+ DO_TEST("9223372036854775807", LONG_MAX, -1, strtol, 10);
+ DO_ERR_TEST("9223372036854775808", LONG_MAX, ERANGE, strtol, 10);
+ DO_ERR_TEST("-9223372036854775809", LONG_MIN, ERANGE, strtol, 10);
+#endif
+
+ // wcstol
+#if defined(__i386__)
+ DO_TESTL(L"-2147483648", LONG_MIN, -1, wcstol, 10);
+ DO_TESTL(L"2147483647", LONG_MAX, -1, wcstol, 10);
+ DO_ERR_TESTL(L"2147483648", LONG_MAX, ERANGE, wcstol, 10);
+ DO_ERR_TESTL(L"-2147483649", LONG_MIN, ERANGE, wcstol, 10);
+#else
+ DO_TESTL(L"-9223372036854775808", LONG_MIN, -1, wcstol, 10);
+ DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstol, 10);
+ DO_ERR_TESTL(L"9223372036854775808", LONG_MAX, ERANGE, wcstol, 10);
+ DO_ERR_TESTL(L"-9223372036854775809", LONG_MIN, ERANGE, wcstol, 10);
+#endif
+
+ // strtoll
+ DO_TEST("-9223372036854775808", LLONG_MIN, -1, strtoll, 10);
+ DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoll, 10);
+ DO_ERR_TEST("9223372036854775808", LLONG_MAX, ERANGE, strtoll, 10);
+ DO_ERR_TEST("-9223372036854775809", LLONG_MIN, ERANGE, strtoll, 10);
+ // wcstoll
+ DO_TESTL(L"-9223372036854775808", LLONG_MIN, -1, wcstoll, 10);
+ DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoll, 10);
+ DO_ERR_TESTL(L"9223372036854775808", LLONG_MAX, ERANGE, wcstoll, 10);
+ DO_ERR_TESTL(L"-9223372036854775809", LLONG_MIN, ERANGE, wcstoll, 10);
+
+ // strtoul
+#if defined(__i386__)
+ DO_TEST("-1", -(1UL), -1, strtoul, 10);
+ DO_TEST("2147483647", LONG_MAX, -1, strtoul, 10);
+ DO_TEST("4294967295", ULONG_MAX, -1, strtoul, 10);
+ DO_TEST("-4294967295", 1UL, -1, strtoul, 10);
+ DO_ERR_TEST("4294967296", ULONG_MAX, ERANGE, strtoul, 10);
+#else
+ DO_TEST("-1", -(1UL), -1, strtoul, 10);
+ DO_TEST("9223372036854775807", LONG_MAX, -1, strtoul, 10);
+ DO_TEST("18446744073709551615", ULONG_MAX, -1, strtoul, 10);
+ DO_TEST("-18446744073709551615", 1UL, -1, strtoul, 10);
+ DO_ERR_TEST("18446744073709551616", ULONG_MAX, ERANGE, strtoul, 10);
+#endif
+
+ // wcstoul
+#if defined(__i386__)
+ DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10);
+ DO_TESTL(L"2147483647", LONG_MAX, -1, wcstoul, 10);
+ DO_TESTL(L"4294967295", ULONG_MAX, -1, wcstoul, 10);
+ DO_TESTL(L"-4294967295", 1UL, -1, wcstoul, 10);
+ DO_ERR_TESTL(L"4294967296", ULONG_MAX, ERANGE, wcstoul, 10);
+#else
+ DO_TESTL(L"-1", -(1UL), -1, wcstoul, 10);
+ DO_TESTL(L"9223372036854775807", LONG_MAX, -1, wcstoul, 10);
+ DO_TESTL(L"18446744073709551615", ULONG_MAX, -1, wcstoul, 10);
+ DO_TESTL(L"-18446744073709551615", 1UL, -1, wcstoul, 10);
+ DO_ERR_TESTL(L"18446744073709551616", ULONG_MAX, ERANGE, wcstoul, 10);
+#endif
+
+ // strtoull
+ DO_TEST("-1", -(1ULL), -1, strtoull, 10);
+ DO_TEST("9223372036854775807", LLONG_MAX, -1, strtoull, 10);
+ DO_TEST("18446744073709551615", ULLONG_MAX, -1, strtoull, 10);
+ DO_TEST("-18446744073709551615", 1ULL, -1, strtoull, 10);
+ DO_ERR_TEST("18446744073709551616", ULLONG_MAX, ERANGE, strtoull, 10);
+ // wcstoull
+ DO_TESTL(L"-1", -(1ULL), -1, wcstoull, 10);
+ DO_TESTL(L"9223372036854775807", LLONG_MAX, -1, wcstoull, 10);
+ DO_TESTL(L"18446744073709551615", ULLONG_MAX, -1, wcstoull, 10);
+ DO_TESTL(L"-18446744073709551615", 1ULL, -1, wcstoull, 10);
+ DO_ERR_TESTL(L"18446744073709551616", ULLONG_MAX, ERANGE, wcstoull, 10);
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/strverscmp.c b/lib/mlibc/tests/ansi/strverscmp.c
new file mode 100644
index 0000000..d6501a1
--- /dev/null
+++ b/lib/mlibc/tests/ansi/strverscmp.c
@@ -0,0 +1,16 @@
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+int main() {
+ int res;
+
+ res = strverscmp("jan1", "jan10");
+ assert(res < 0);
+
+ res = strverscmp("jan11", "jan10");
+ assert(res > 0);
+
+ res = strverscmp("jan1", "jan1");
+ assert(res == 0);
+}
diff --git a/lib/mlibc/tests/ansi/strxfrm.c b/lib/mlibc/tests/ansi/strxfrm.c
new file mode 100644
index 0000000..07a4082
--- /dev/null
+++ b/lib/mlibc/tests/ansi/strxfrm.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <locale.h>
+#include <string.h>
+
+int main() {
+ setlocale(LC_ALL, "C");
+
+ const char *buf = "cbtteststring";
+ char dest[14];
+ size_t ret = strxfrm(dest, buf, strlen(buf) + 1);
+ assert(ret == 13);
+ int cmp = strncmp(dest, buf, 13);
+ assert(!cmp);
+}
diff --git a/lib/mlibc/tests/ansi/timegm.c b/lib/mlibc/tests/ansi/timegm.c
new file mode 100644
index 0000000..f5af03e
--- /dev/null
+++ b/lib/mlibc/tests/ansi/timegm.c
@@ -0,0 +1,45 @@
+#include <time.h>
+#include <stdio.h>
+#include <assert.h>
+
+int main() {
+ struct tm soon = {};
+ soon.tm_sec = 0;
+ soon.tm_min = 0;
+ soon.tm_hour = 0;
+ soon.tm_mday = 1;
+ soon.tm_mon = 0;
+ soon.tm_year = 70;
+ time_t result;
+ time_t expected_result = 0;
+ // This should be epoch.
+ result = timegm(&soon);
+ printf("epoch: %ld\n", result);
+ assert(result == expected_result);
+
+ soon.tm_sec = 12;
+ soon.tm_min = 8;
+ soon.tm_hour = 16;
+ soon.tm_mday = 17;
+ soon.tm_mon = 4;
+ soon.tm_year = 122;
+ expected_result = 1652803692;
+ result = timegm(&soon);
+ // On my host, this returned 1652803692, verify this.
+ printf("epoch: %ld\n", result);
+ assert(result == expected_result);
+
+ soon.tm_sec = 45;
+ soon.tm_min = 42;
+ soon.tm_hour = 17;
+ soon.tm_mday = 16;
+ soon.tm_mon = 8;
+ soon.tm_year = 69;
+ expected_result = -9181035;
+ result = timegm(&soon);
+ // On my host, this returned -9181035, verify this.
+ printf("epoch: %ld\n", result);
+ assert(result == expected_result);
+
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/ungetc.c b/lib/mlibc/tests/ansi/ungetc.c
new file mode 100644
index 0000000..8773c6d
--- /dev/null
+++ b/lib/mlibc/tests/ansi/ungetc.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <assert.h>
+
+#ifdef USE_HOST_LIBC
+#define TEST_FILE "ungetc-host-libc.tmp"
+#else
+#define TEST_FILE "ungetc.tmp"
+#endif
+
+void test(int buffering) {
+ FILE *f = fopen(TEST_FILE, "w");
+ for(int c = '0'; c <= '9'; c++) {
+ fputc(c, f);
+ }
+ fclose(f);
+
+ f = fopen(TEST_FILE, "r");
+ if (!buffering) {
+ setbuf(f, NULL);
+ }
+
+ assert(ungetc('x', f) == 'x');
+ assert(fgetc(f) == 'x');
+
+ // Test pushing back the same character
+ for (int c = '0'; c <= '9'; c++) {
+ assert(fgetc(f) == c);
+ assert(ungetc(c, f) == c);
+ assert(fgetc(f) == c);
+ }
+ assert(fgetc(f) == EOF);
+ assert(ungetc(EOF, f) == EOF);
+
+ // Even though the spec does not guarantee it, we should be able to
+ // ungetc more than one character.
+ assert(ungetc('x', f) == 'x');
+ assert(ungetc('y', f) == 'y');
+ assert(fgetc(f) == 'y');
+ assert(fgetc(f) == 'x');
+
+ // Seeking should discard the effects of ungetc.
+ assert(ungetc('x', f) == 'x');
+ rewind(f);
+
+ // Test pushing back a different character
+ for (int c = '0'; c <= '9'; c++) {
+ assert(fgetc(f) == c);
+ assert(ungetc(c - '0' + 'a', f) == c - '0' + 'a');
+ assert(fgetc(f) == c - '0' + 'a');
+ }
+
+#ifndef USE_HOST_LIBC
+ // Too many ungetcs should fail.
+ int eof = 0;
+ for (int i = 0; i < 100; i++) {
+ if (ungetc('x', f) == EOF) {
+ eof = 1;
+ break;
+ }
+ }
+ assert(eof);
+#endif
+
+ fclose(f);
+
+ // TODO: Test with other operations, like fread.
+}
+
+int main() {
+ fprintf(stderr, "with buffering...\n");
+ test(1);
+ fprintf(stderr, "without buffering...\n");
+ test(0);
+}
diff --git a/lib/mlibc/tests/ansi/utf8.c b/lib/mlibc/tests/ansi/utf8.c
new file mode 100644
index 0000000..18b0d5a
--- /dev/null
+++ b/lib/mlibc/tests/ansi/utf8.c
@@ -0,0 +1,63 @@
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <locale.h>
+
+#if UINTPTR_MAX == UINT64_MAX
+#define WCHAR_SPEC ""
+#else
+#define WCHAR_SPEC "l"
+#endif
+
+#define EXPECT(func) ({ \
+ if(res != expected_ret) { \
+ printf(#func " decoded %d bytes (expected %d bytes), at %s:%d\n", \
+ res, expected_ret, __FILE__, line); \
+ fflush(stdout); \
+ abort(); \
+ } \
+ if(wc != expected) { \
+ printf(#func " output cp %" WCHAR_SPEC "x (expected cp %" WCHAR_SPEC "x), at %s:%d\n", wc, \
+ expected, __FILE__, line); \
+ fflush(stdout); \
+ abort(); \
+ } \
+ })
+
+void verify_decode(const char *input, wchar_t expected, int line) {
+ wchar_t wc;
+ int bytes = *input ? strlen(input) : 1;
+ int expected_ret = *input ? strlen(input) : 0;
+
+ // Check mbrtowc().
+ mbstate_t state;
+ memset(&state, 0, sizeof(state));
+ assert(mbrtowc(NULL, NULL, -1, &state) == 0);
+ int res = mbrtowc(&wc, input, bytes, &state);
+ EXPECT("mbrtowc");
+ res = mbrtowc(NULL, input, bytes, &state);
+ EXPECT("mbrtowc (pwc == NULL)");
+
+ // Check mbtowc().
+ assert(mbtowc(NULL, NULL, -1) == 0);
+ res = mbtowc(&wc, input, bytes);
+ EXPECT("mbtowc");
+ res = mbtowc(NULL, input, bytes);
+ EXPECT("mbtowc (pwc == NULL)");
+}
+
+int main() {
+ setlocale(LC_ALL, "C.UTF-8");
+
+#define verify_decode(in, out) verify_decode(in, out, __LINE__)
+ verify_decode("\x24", 0x24);
+ verify_decode("\xC2\xA2", 0xA2);
+ verify_decode("\xE0\xA4\xB9", 0x939);
+ verify_decode("\xE2\x82\xAC", 0x20AC);
+ verify_decode("\xED\x95\x9C", 0xD55C);
+ verify_decode("\xF0\x90\x8D\x88", 0x10348);
+ verify_decode("", L'\0');
+}
diff --git a/lib/mlibc/tests/ansi/wcsdup.c b/lib/mlibc/tests/ansi/wcsdup.c
new file mode 100644
index 0000000..564b77e
--- /dev/null
+++ b/lib/mlibc/tests/ansi/wcsdup.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+int main() {
+ wchar_t *wide_string = L"test string\n";
+ wchar_t *dup_string = wcsdup(wide_string);
+ assert(!memcmp(wide_string, dup_string, (wcslen(wide_string) + 1) * sizeof(wchar_t)));
+ free(dup_string);
+}
diff --git a/lib/mlibc/tests/ansi/wcsncasecmp.c b/lib/mlibc/tests/ansi/wcsncasecmp.c
new file mode 100644
index 0000000..fcbe98f
--- /dev/null
+++ b/lib/mlibc/tests/ansi/wcsncasecmp.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include <wchar.h>
+
+int main() {
+ assert(!wcsncasecmp(L"foo", L"foo", 3));
+ assert(!wcsncasecmp(L"foo", L"FOO", 3));
+ assert(!wcsncasecmp(L"fooa", L"FOOB", 3));
+ assert(wcsncasecmp(L"foo", L"bar", 3));
+ assert(!wcsncasecmp(L"fooa", L"FOOA", 4));
+ assert(!wcsncasecmp(L"123abc", L"123AbC", 6));
+}
diff --git a/lib/mlibc/tests/ansi/wcsrtombs.c b/lib/mlibc/tests/ansi/wcsrtombs.c
new file mode 100644
index 0000000..80df257
--- /dev/null
+++ b/lib/mlibc/tests/ansi/wcsrtombs.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <wchar.h>
+#include <assert.h>
+#include <string.h>
+
+int main() {
+ const wchar_t str[] = L"wcsrtombs";
+ const wchar_t *p = str;
+ int ret = wcsrtombs(NULL, &p, 343245234, NULL);
+ assert(ret == 9);
+ return 0;
+}
diff --git a/lib/mlibc/tests/ansi/wmemcmp.c b/lib/mlibc/tests/ansi/wmemcmp.c
new file mode 100644
index 0000000..74de9bd
--- /dev/null
+++ b/lib/mlibc/tests/ansi/wmemcmp.c
@@ -0,0 +1,19 @@
+#include <assert.h>
+#include <wchar.h>
+#include <stdlib.h>
+
+int main(void){
+ wchar_t *ws1 = calloc(10, sizeof(wchar_t));
+ wchar_t *ws2 = calloc(10, sizeof(wchar_t));
+
+ mbstowcs(ws1, "Test 1", 10);
+ mbstowcs(ws2, "Tester 2", 10);
+
+ assert(wmemcmp(ws1, ws2, 10) < 0);
+ assert(wmemcmp(ws2, ws1, 10) > 0);
+ assert(wmemcmp(ws2, ws2, 10) == 0);
+
+ free(ws1);
+ free(ws2);
+ return 0;
+}