summaryrefslogtreecommitdiff
path: root/userland/libc/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'userland/libc/stdlib')
-rw-r--r--userland/libc/stdlib/abort.c10
-rw-r--r--userland/libc/stdlib/abs.c3
-rw-r--r--userland/libc/stdlib/atexit.c6
-rw-r--r--userland/libc/stdlib/atof.c5
-rw-r--r--userland/libc/stdlib/atoi.c4
-rw-r--r--userland/libc/stdlib/getenv.c6
-rw-r--r--userland/libc/stdlib/mkstemp.c14
-rw-r--r--userland/libc/stdlib/qsort.c29
-rw-r--r--userland/libc/stdlib/rand.c17
-rw-r--r--userland/libc/stdlib/srand.c8
-rw-r--r--userland/libc/stdlib/strtod.c70
-rw-r--r--userland/libc/stdlib/strtol.c52
-rw-r--r--userland/libc/stdlib/strtold.c9
-rw-r--r--userland/libc/stdlib/strtoul.c72
-rw-r--r--userland/libc/stdlib/system.c17
15 files changed, 322 insertions, 0 deletions
diff --git a/userland/libc/stdlib/abort.c b/userland/libc/stdlib/abort.c
new file mode 100644
index 0000000..7fd747e
--- /dev/null
+++ b/userland/libc/stdlib/abort.c
@@ -0,0 +1,10 @@
+#include <assert.h>
+#include <stdlib.h>
+
+// https://pubs.opengroup.org/onlinepubs/9699919799/functions/abort.html
+void abort(void) {
+ printf("aborting!!!!\n");
+ assert(0);
+ for (;;)
+ ;
+}
diff --git a/userland/libc/stdlib/abs.c b/userland/libc/stdlib/abs.c
new file mode 100644
index 0000000..1079beb
--- /dev/null
+++ b/userland/libc/stdlib/abs.c
@@ -0,0 +1,3 @@
+#include <stdlib.h>
+
+int abs(int i) { return (i < 0) ? (-i) : (i); }
diff --git a/userland/libc/stdlib/atexit.c b/userland/libc/stdlib/atexit.c
new file mode 100644
index 0000000..0e401ff
--- /dev/null
+++ b/userland/libc/stdlib/atexit.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+int atexit(void (*func)(void)) {
+ //TODO
+ return 0;
+}
diff --git a/userland/libc/stdlib/atof.c b/userland/libc/stdlib/atof.c
new file mode 100644
index 0000000..8524f8b
--- /dev/null
+++ b/userland/libc/stdlib/atof.c
@@ -0,0 +1,5 @@
+#include <stdlib.h>
+
+double atof(const char *str) {
+ return strtod(str,(char **)NULL);
+}
diff --git a/userland/libc/stdlib/atoi.c b/userland/libc/stdlib/atoi.c
new file mode 100644
index 0000000..2183306
--- /dev/null
+++ b/userland/libc/stdlib/atoi.c
@@ -0,0 +1,4 @@
+#include <stdlib.h>
+
+// https://pubs.opengroup.org/onlinepubs/9699919799/
+int atoi(const char *str) { return (int)strtol(str, (char **)NULL, 10); }
diff --git a/userland/libc/stdlib/getenv.c b/userland/libc/stdlib/getenv.c
new file mode 100644
index 0000000..9a6a4e5
--- /dev/null
+++ b/userland/libc/stdlib/getenv.c
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+char *getenv(const char *name) {
+ // FIXME
+ return NULL;
+}
diff --git a/userland/libc/stdlib/mkstemp.c b/userland/libc/stdlib/mkstemp.c
new file mode 100644
index 0000000..1ea8790
--- /dev/null
+++ b/userland/libc/stdlib/mkstemp.c
@@ -0,0 +1,14 @@
+#include <fcntl.h>
+#include <stdlib.h>
+
+char rand_char(void) { return 'A' + (rand() % 10); }
+
+int mkstemp(char *template) {
+ // FIXME: Incomplete
+ const char *s = template;
+ for (; *template; template ++) {
+ if ('X' == *template)
+ *template = rand_char();
+ }
+ return open(s, O_RDWR, O_CREAT);
+}
diff --git a/userland/libc/stdlib/qsort.c b/userland/libc/stdlib/qsort.c
new file mode 100644
index 0000000..3f87db5
--- /dev/null
+++ b/userland/libc/stdlib/qsort.c
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+#include <string.h>
+
+// https://pubs.opengroup.org/onlinepubs/9699919799/functions/qsort.html
+void qsort(void *base, size_t nel, size_t width,
+ int (*compar)(const void *, const void *)) {
+ // If the nel argument has the value zero, the comparison function pointed to
+ // by compar shall not be called and no rearrangement shall take place.
+ if (0 == nel)
+ return;
+
+ // AB
+ // Results in negative
+ // BA
+ // Results in positive
+
+ // Using bubblesort
+ unsigned char *p = base;
+ for (size_t i = 1; i < nel; i++) {
+ for (size_t j = 0; j < nel; j++) {
+ if (compar((p + i * width), (p + j * width)) < 0) {
+ unsigned char tmp[width];
+ memcpy(tmp, (p + i * width), width);
+ memcpy((p + i * width), (p + j * width), width);
+ memcpy((p + j * width), tmp, width);
+ }
+ }
+ }
+}
diff --git a/userland/libc/stdlib/rand.c b/userland/libc/stdlib/rand.c
new file mode 100644
index 0000000..e186af7
--- /dev/null
+++ b/userland/libc/stdlib/rand.c
@@ -0,0 +1,17 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+uint32_t xorshift(uint32_t x) {
+ uint32_t f = x;
+ x ^= x << 13;
+ x ^= x >> 17;
+ x ^= x << 5;
+ return f + x;
+}
+
+extern uint32_t __INTERNAL_RNG_STATE;
+int rand(void) {
+ uint32_t x = xorshift(__INTERNAL_RNG_STATE);
+ __INTERNAL_RNG_STATE++;
+ return x;
+}
diff --git a/userland/libc/stdlib/srand.c b/userland/libc/stdlib/srand.c
new file mode 100644
index 0000000..a35185a
--- /dev/null
+++ b/userland/libc/stdlib/srand.c
@@ -0,0 +1,8 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+uint32_t __INTERNAL_RNG_STATE;
+void srand(unsigned int seed) {
+ __INTERNAL_RNG_STATE = seed;
+ __INTERNAL_RNG_STATE = rand(); // rand() used the internal rng state
+}
diff --git a/userland/libc/stdlib/strtod.c b/userland/libc/stdlib/strtod.c
new file mode 100644
index 0000000..2c83879
--- /dev/null
+++ b/userland/libc/stdlib/strtod.c
@@ -0,0 +1,70 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <assert.h>
+
+int ctoi(char c) { return c - '0'; }
+
+double strtod(const char *restrict nptr, char **restrict endptr) {
+ double r = 0;
+ // An initial, possibly empty, sequence of white-space characters (as
+ // specified by isspace())
+ for (; isspace(*nptr); nptr++)
+ ;
+
+ // A subject sequence interpreted as a floating-point constant or representing
+ // infinity or NaN
+
+ {
+ // The expected form of the subject sequence is an optional '+' or '-' sign
+ int sign = 0;
+ int exp_sign = 0;
+ if ('+' == *nptr) {
+ sign = 0;
+ nptr++;
+ } else if ('-' == *nptr) {
+ sign = 1;
+ nptr++;
+ }
+
+ // A non-empty sequence of decimal digits optionally containing a radix
+ // character
+ double exp = 0;
+ for (; isdigit(*nptr); nptr++) {
+ r *= 10;
+ r += ctoi(*nptr);
+ }
+ if ('.' == *nptr) {
+ double div = 10;
+ for (; isdigit(*nptr); nptr++) {
+ r += ctoi(*nptr) / div;
+ div *= 10;
+ }
+ }
+ r *= (sign) ? (-1) : (1);
+
+ // then an optional exponent part consisting of the character 'e' or
+ // the character 'E'
+ if ('e' == tolower(*nptr)) {
+ // optionally followed by a '+' or '-' character
+ if ('+' == *nptr) {
+ exp_sign = 0;
+ nptr++;
+ } else if ('-' == *nptr) {
+ exp_sign = 1;
+ nptr++;
+ }
+ // and then followed by one or more decimal digits
+ for (; isdigit(*nptr); nptr++) {
+ exp *= 10;
+ exp += ctoi(*nptr);
+ }
+ exp *= (exp_sign) ? (-1) : (1);
+ }
+ assert(0 == exp); // TODO
+ }
+
+ // A final string of one or more unrecognized characters, including the
+ // terminating NUL character of the input string
+ ;
+ return r;
+}
diff --git a/userland/libc/stdlib/strtol.c b/userland/libc/stdlib/strtol.c
new file mode 100644
index 0000000..7aa7760
--- /dev/null
+++ b/userland/libc/stdlib/strtol.c
@@ -0,0 +1,52 @@
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <assert.h>
+
+extern int errno;
+extern int get_value(char c, long base);
+
+// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html
+long strtol(const char *str, char **restrict endptr, int base) {
+ long ret_value = 0;
+ if (endptr)
+ *endptr = str;
+ // Ignore inital white-space sequence
+ for (; *str && isspace(*str); str++)
+ ;
+ if (!*str)
+ return ret_value;
+
+ int sign = 0;
+ if ('-' == *str) {
+ // FIXME
+ sign = 1;
+ str++;
+ assert(0);
+ } else if ('+' == *str) {
+ str++;
+ }
+
+ if (0 == base) {
+ // FIXME
+ assert(0);
+ }
+
+ if (2 <= base && 36 >= base) {
+ for (; *str; str++) {
+ ret_value *= base;
+ int val = get_value(*str, base);
+ if (ret_value > LONG_MAX - val) {
+ errno = ERANGE;
+ return 0;
+ }
+ ret_value += val;
+ }
+ } else {
+ errno = EINVAL;
+ return 0;
+ }
+ if (endptr)
+ *endptr = str;
+ return ret_value;
+}
diff --git a/userland/libc/stdlib/strtold.c b/userland/libc/stdlib/strtold.c
new file mode 100644
index 0000000..222464e
--- /dev/null
+++ b/userland/libc/stdlib/strtold.c
@@ -0,0 +1,9 @@
+#include <assert.h>
+#include <stdlib.h>
+
+long double strtold(const char *restrict nptr, char **restrict endptr) {
+ // TODO
+ // I will do this some other day
+ assert(NULL);
+ return 0;
+}
diff --git a/userland/libc/stdlib/strtoul.c b/userland/libc/stdlib/strtoul.c
new file mode 100644
index 0000000..4d9a51d
--- /dev/null
+++ b/userland/libc/stdlib/strtoul.c
@@ -0,0 +1,72 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+
+extern int errno;
+int get_value(char c, long base) {
+ int r;
+ if (c >= '0' && c <= '9')
+ r = c - '0';
+ else if (c >= 'A' && c <= 'Z')
+ r = c - 'A';
+ else if (c >= 'a' && c <= 'z')
+ r = c - 'a';
+ else
+ return -1;
+ if (r >= base)
+ return -1;
+ return r;
+}
+
+// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtoul.html
+unsigned long strtoul(const char *restrict str, char **restrict endptr,
+ int base) {
+ unsigned long ret_value = 0;
+ if (endptr)
+ *endptr = str;
+ // Ignore inital white-space sequence
+ for (; *str && isspace(*str); str++)
+ ;
+ if (!*str)
+ return ret_value;
+
+ int sign = 0;
+ if ('-' == *str) {
+ // FIXME
+ sign = 1;
+ str++;
+ assert(0);
+ } else if ('+' == *str) {
+ str++;
+ }
+
+ if (0 == base) {
+ // FIXME
+ assert(0);
+ }
+
+ if (2 <= base && 36 >= base) {
+ for (; *str; str++) {
+ ret_value *= base;
+ int val = get_value(*str, base);
+ /*
+ if (-1 == val) {
+ errno = ERANGE;
+ return 0;
+ }*/
+ if (ret_value > ULONG_MAX - val) {
+ errno = ERANGE;
+ return 0;
+ }
+
+ ret_value += val;
+ }
+ } else {
+ errno = EINVAL;
+ return 0;
+ }
+ if (endptr)
+ *endptr = str;
+ return ret_value;
+}
diff --git a/userland/libc/stdlib/system.c b/userland/libc/stdlib/system.c
new file mode 100644
index 0000000..d951c5c
--- /dev/null
+++ b/userland/libc/stdlib/system.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+
+int system(const char *command) {
+ if (!command)
+ return NULL;
+ int pid = fork();
+ if (0 == pid) {
+ char *argv[2];
+ argv[0] = "/sh";
+ argv[1] = command;
+ execv("/sh", argv);
+ }
+ // FIXME: Use waitpid
+ int rc;
+ (void)wait(&rc);
+ return rc;
+}