diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b8b274..024f37c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ set(CMAKE_EXE_LINKER_FLAGS set(malloc_impl dlmalloc) set(photon_libc_sources "") -set(generic_dirs string stdio stdlib errno internal) +set(generic_dirs string stdio stdlib errno internal ctype) message(STATUS "Memory allocator: ${malloc_impl}") diff --git a/photon/libc/ctype/ctype.c b/photon/libc/ctype/ctype.c new file mode 100644 index 0000000..1aaba3e --- /dev/null +++ b/photon/libc/ctype/ctype.c @@ -0,0 +1,46 @@ +#include + +static unsigned int random_seed = 53455346; + +int isupper(int c) { return (c >= 65 && c <= 90); } + +int islower(int c) { return (c >= 97 && c <= 122); } + +int toupper(int c) { + if (!islower(c)) { + return c; + } + + return c - 32; +} + +int tolower(int c) { + if (!isupper(c)) { + return c; + } + + return c + 32; +} + +int isdigit(int c) { return (c >= 48 && c <= 57); } + +int isalpha(int c) { return (c >= 65 && c <= 90) || (c >= 97 && c <= 122); } + +int isalnum(int c) { return isalpha(c) | isdigit(c); } + +int iscntrl(int c) { return (c <= 31) || (c == 127); } + +int isprint(int c) { return (c >= 32 && c <= 126) || (c >= 128 && c <= 254); } + +int isgraph(int c) { return isprint(c) && c != 32; } + +int ispunct(int c) { return isgraph(c) && !isalnum(c); } + +int isspace(int c) { + return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\v') || + (c == '\f') || (c == '\r'); +} + +int isxdigit(int c) { + return isdigit(c) || (c >= 65 && c <= 70) || (c >= 97 && c <= 102); +} diff --git a/photon/libc/include/ctype.h b/photon/libc/include/ctype.h new file mode 100644 index 0000000..ef78c6f --- /dev/null +++ b/photon/libc/include/ctype.h @@ -0,0 +1,27 @@ +#ifndef TYPES_H_ +#define TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int isalnum(int c); +extern int isalpha(int c); +extern int iscntrl(int c); +extern int isdigit(int c); +extern int isgraph(int c); +extern int islower(int c); +extern int isprint(int c); +extern int ispunct(int c); +extern int isspace(int c); +extern int isupper(int c); +extern int isxdigit(int c); +extern int tolower(int c); +extern int toupper(int c); +extern int fill_random(unsigned char *buffer, unsigned int size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/photon/libc/include/limits.h b/photon/libc/include/limits.h new file mode 100644 index 0000000..1defa10 --- /dev/null +++ b/photon/libc/include/limits.h @@ -0,0 +1,24 @@ +#ifndef LIMITS_H_ +#define LIMITS_H_ + +#define CHAR_BIT 8 +#define SCHAR_MIN -127 +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#define CHAR_MIN SCHAR_MIN +#define CHAR_MAX SCHAR_MAX +#define MB_LEN_MAX 1 +#define SHRT_MIN -32767 +#define SHRT_MAX 32767 +#define USHRT_MAX 65535 +#define INT_MIN -2147483648 +#define INT_MAX 2147483648 +#define UINT_MAX 4294967295 +#define LONG_MIN -2147483648 +#define LONG_MAX 2147483648 +#define ULONG_MAX 4294967295 +#define _I64_MIN -9223372036854775808 +#define _I64_MAX 9223372036854775808 +#define _UI64_MAX 18446744073709551615 + +#endif /* LIMITS_H_ */ diff --git a/photon/libc/include/stddef.h b/photon/libc/include/stddef.h index 73c6622..a2525fc 100644 --- a/photon/libc/include/stddef.h +++ b/photon/libc/include/stddef.h @@ -4,7 +4,7 @@ #include "machine/_stdint.h" #define NULL ((void *)0) -#define offsetof(t, m) ((size_t)(&(t *)0)->m) +#define offsetof(t, m) ((size_t)&(((t *)0)->m)) #if defined(__cplusplus) extern "C" { diff --git a/photon/libc/include/stdio.h b/photon/libc/include/stdio.h index ef062c0..de4e4a8 100644 --- a/photon/libc/include/stdio.h +++ b/photon/libc/include/stdio.h @@ -29,13 +29,22 @@ extern FILE *stderr; extern FILE *fopen(const char *path, const char *mode); extern FILE *freopen(const char *path, const char *mode, FILE *fp); +#ifdef __magenta__ +extern FILE *fdopen(mx_handle_t fd, const char *mode); +#else extern FILE *fdopen(int fd, const char *mode); +#endif extern int fclose(FILE *fp); extern int fflush(FILE *fp); +extern size_t fread(void *ptr, size_t size, size_t count, FILE *fp); +extern size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp); extern int fileno(FILE *fp); extern int fputs(const char *str, FILE *fp); extern int fputc(int c, FILE *fp); +extern int fgetc(FILE *fp); + +extern int ungetc(int c, FILE *fp); extern int printf(const char *restrict format, ...); extern int fprintf(FILE *fp, const char *restrict format, ...); diff --git a/photon/libc/include/stdlib.h b/photon/libc/include/stdlib.h index 93b033f..a0d4ac7 100644 --- a/photon/libc/include/stdlib.h +++ b/photon/libc/include/stdlib.h @@ -12,6 +12,11 @@ extern _Noreturn void exit(int code); extern void *malloc(size_t sz); extern void free(void *ptr); +extern int atoi(const char *str); +extern double atof(const char *str); +extern long int strtol(const char *str, char **endptr, int base); +extern double strtod(const char *str, char **endptr); + #if defined(__cplusplus) } /* extern "C" */ #endif diff --git a/photon/libc/include/string.h b/photon/libc/include/string.h index b123a81..a0be36a 100644 --- a/photon/libc/include/string.h +++ b/photon/libc/include/string.h @@ -16,6 +16,11 @@ extern size_t strlen(const char *str); extern int strcmp(const char *a, const char *b); extern int strncmp(const char *a, const char *b, size_t sz); +extern char *strcpy(char *dest, const char *src); +extern char *strncpy(char *dest, const char *src, size_t sz); + +extern char *strdup(const char *s); + #if defined(__cplusplus) } /* extern "C" */ #endif diff --git a/photon/libc/stdio/fdopen.c b/photon/libc/stdio/fdopen.c index d379308..45bc696 100644 --- a/photon/libc/stdio/fdopen.c +++ b/photon/libc/stdio/fdopen.c @@ -1,10 +1,17 @@ #include +#include #include #include <__fio.h> +#ifdef __magenta__ +FILE *fdopen(mx_handle_t fd, const char *mode) +#else FILE *fdopen(int fd, const char *mode) +#endif { struct __io_file *fp = malloc(sizeof(*fp)); + memset(fp, 0x0, sizeof(*fp)); + int res = __fio_fdopen(fd, mode, fp); if (res != 0) { free(fp); diff --git a/photon/libc/stdio/fgetc.c b/photon/libc/stdio/fgetc.c new file mode 100644 index 0000000..7f37fb8 --- /dev/null +++ b/photon/libc/stdio/fgetc.c @@ -0,0 +1,13 @@ +#include +#include <__fio.h> + +int fgetc(FILE *fp) +{ + char ch = 0; + __fio_read(fp, &ch, 1); + if (__fio_error(fp)) { + return EOF; + } + + return ch; +} diff --git a/photon/libc/stdio/fopen.c b/photon/libc/stdio/fopen.c index e671015..0afe20c 100644 --- a/photon/libc/stdio/fopen.c +++ b/photon/libc/stdio/fopen.c @@ -1,10 +1,13 @@ #include #include +#include #include <__fio.h> FILE *fopen(const char *path, const char *mode) { struct __io_file *fp = malloc(sizeof(*fp)); + memset(fp, 0x0, sizeof(*fp)); + int res = __fio_fopen(path, mode, fp); if (res != 0) { free(fp); diff --git a/photon/libc/stdio/fwrite.c b/photon/libc/stdio/fwrite.c new file mode 100644 index 0000000..1afc42e --- /dev/null +++ b/photon/libc/stdio/fwrite.c @@ -0,0 +1,12 @@ +#include +#include <__fio.h> + +size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp) +{ + if (!size || !count) { + return 0; + } + + unsigned int written = __fio_write(fp, ptr, size * count); + return written / size; +} diff --git a/photon/libc/stdio/ungetc.c b/photon/libc/stdio/ungetc.c new file mode 100644 index 0000000..b8fdea0 --- /dev/null +++ b/photon/libc/stdio/ungetc.c @@ -0,0 +1,8 @@ +#include +#include <__fio.h> + +int ungetc(int c, FILE *fp) +{ + int res = __fio_ungetc(fp, c); + return res == -1 ? EOF : c; +} diff --git a/photon/libc/stdlib/atof.c b/photon/libc/stdlib/atof.c new file mode 100644 index 0000000..1c909b1 --- /dev/null +++ b/photon/libc/stdlib/atof.c @@ -0,0 +1,42 @@ +#include + +double atof(const char *s) +{ + double a = 0.0; + int e = 0; + int c; + while ((c = *s++) != '\0' && isdigit(c)) { + a = a*10.0 + (c - '0'); + } + if (c == '.') { + while ((c = *s++) != '\0' && isdigit(c)) { + a = a*10.0 + (c - '0'); + e = e-1; + } + } + if (c == 'e' || c == 'E') { + int sign = 1; + int i = 0; + c = *s++; + if (c == '+') + c = *s++; + else if (c == '-') { + c = *s++; + sign = -1; + } + while (isdigit(c)) { + i = i*10 + (c - '0'); + c = *s++; + } + e += i*sign; + } + while (e > 0) { + a *= 10.0; + e--; + } + while (e < 0) { + a *= 0.1; + e++; + } + return a; +} diff --git a/photon/libc/stdlib/atoi.c b/photon/libc/stdlib/atoi.c new file mode 100644 index 0000000..e69de29 diff --git a/photon/libc/stdlib/strtod.c b/photon/libc/stdlib/strtod.c new file mode 100644 index 0000000..a88b4ec --- /dev/null +++ b/photon/libc/stdlib/strtod.c @@ -0,0 +1,91 @@ +#include +#include +#include + +double strtod(const char *str, char **ptr) +{ + if (ptr == (char **)0) { + return atof(str); + } + + size_t len = strlen(str); + char rstr[len + 1]; + strcpy(rstr, str); + + char *p = rstr; + + while (isspace(*p)) { + ++p; + } + + if (*p == '+' || *p == '-') { + ++p; + } + + if ((p[0] == 'i' || p[0] == 'I') + && (p[1] == 'n' || p[1] == 'N') + && (p[2] == 'f' || p[2] == 'F')) { + if ((p[3] == 'i' || p[3] == 'I') + && (p[4] == 'n' || p[4] == 'N') + && (p[5] == 'i' || p[5] == 'I') + && (p[6] == 't' || p[6] == 'T') + && (p[7] == 'y' || p[7] == 'Y')) { + *ptr = p + 8; + return atof(str); + } else { + *ptr = p + 3; + return atof(str); + } + } + + if ((p[0] == 'n' || p[0] == 'N') + && (p[1] == 'a' || p[1] == 'A') + && (p[2] == 'n' || p[2] == 'N')) { + p += 3; + if (*p == '(') { + ++p; + while (*p != '\0' && *p != ')') { + ++p; + } + + if (*p == ')') { + ++p; + } + } + + *ptr = p; + return atof(str); + } + + if (isdigit(*p) || *p == '.') { + int got_dot = 0; + while (isdigit(*p) || (!got_dot && *p == '.')) { + if (*p == '.') + got_dot = 1; + ++p; + } + + if (*p == 'e' || *p == 'E') { + int i; + i = 1; + if (p[i] == '+' || p[i] == '-') { + ++i; + } + + if (isdigit (p[i])) { + while (isdigit (p[i])) { + ++i; + } + + *ptr = p + i; + return atof(str); + } + } + + *ptr = p; + return atof(str); + } + + *ptr = (char *)str; + return 0.0; +} diff --git a/photon/libc/stdlib/strtol.c b/photon/libc/stdlib/strtol.c new file mode 100644 index 0000000..40f5cc2 --- /dev/null +++ b/photon/libc/stdlib/strtol.c @@ -0,0 +1,85 @@ +#include +#include +#include + +long strtol(const char *nptr, char **endptr, int base) +{ + const char *s = nptr; + unsigned long acc; + int c; + unsigned long cutoff; + int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } else if ((base == 0 || base == 2) && + c == '0' && (*s == 'b' || *s == 'B')) { + c = s[1]; + s += 2; + base = 2; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/photon/libc/string/fread.c b/photon/libc/string/fread.c new file mode 100644 index 0000000..5fe5e52 --- /dev/null +++ b/photon/libc/string/fread.c @@ -0,0 +1,12 @@ +#include +#include <__fio.h> + +size_t fread(void *ptr, size_t size, size_t count, FILE *fp) +{ + if (!size || !count) { + return 0; + } + + unsigned int written = __fio_read(fp, ptr, size * count); + return written / size; +} diff --git a/photon/libc/string/fwrite.c b/photon/libc/string/fwrite.c new file mode 100644 index 0000000..e69de29 diff --git a/photon/libc/string/strcmp.c b/photon/libc/string/strcmp.c new file mode 100644 index 0000000..42aea66 --- /dev/null +++ b/photon/libc/string/strcmp.c @@ -0,0 +1,19 @@ +int strcmp(const char *s1, const char *s2) +{ + int i; + for (i = 0; s1[i] == s2[i]; i++) + if (s1[i] == '\0') + return 0; + + return s1[i] - s2[i]; +} + +int strncmp(const char *s1, const char *s2, unsigned int n) +{ + for (; n > 0; s1++, s2++, --n) + if (*s1 != *s2) + return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : 1); + else if (*s1 == '\0') + return 0; + return 0; +} diff --git a/photon/libc/string/strcpy.c b/photon/libc/string/strcpy.c new file mode 100644 index 0000000..6e85814 --- /dev/null +++ b/photon/libc/string/strcpy.c @@ -0,0 +1,26 @@ +char *strcpy(char *output, const char *input) +{ + unsigned int i; + for (i = 0; input[i] != 0; i++) { + output[i] = input[i]; + } + + output[i] = '\0'; + return output; +} + +char *strncpy(char *output, const char *input, unsigned int count) +{ + unsigned int size = count; + unsigned int i; + for (i = 0; i < size; i++) { + output[i] = input[i]; + + if (input[i] == 0) { + break; + } + } + + output[i] = '\0'; + return output; +} diff --git a/photon/libc/string/strdup.c b/photon/libc/string/strdup.c new file mode 100644 index 0000000..5b706ad --- /dev/null +++ b/photon/libc/string/strdup.c @@ -0,0 +1,11 @@ +#include +#include + +char *strdup(const char *str) +{ + size_t len = strlen(str); + char *out = malloc(len + 1); + memcpy(out, str, len); + out[len] = 0; + return out; +} diff --git a/photon/libc/sys/magenta/__fio.h b/photon/libc/sys/magenta/__fio.h index aa7c3b2..2c8287e 100644 --- a/photon/libc/sys/magenta/__fio.h +++ b/photon/libc/sys/magenta/__fio.h @@ -14,17 +14,20 @@ struct __io_file { unsigned long buf_idx; mx_handle_t handle; char err; + char unget; }; extern int __fileno(struct __io_file *f); extern void __fio_init(mx_handle_t in, mx_handle_t out, mx_handle_t err); +extern unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz); extern unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz); extern unsigned int __fio_flush(struct __io_file *f); extern int __fio_error(struct __io_file *f); +extern int __fio_ungetc(struct __io_file *f, char c); extern int __fio_fopen(const char *path, const char *mode, struct __io_file *out); extern int __fio_fclose(struct __io_file *in); -extern int __fio_fdopen(int fd, const char *mode, struct __io_file *out); +extern int __fio_fdopen(mx_handle_t fd, const char *mode, struct __io_file *out); #if defined(__cplusplus) } diff --git a/photon/libc/sys/magenta/fio.c b/photon/libc/sys/magenta/fio.c index f1feb6f..8c2cbc8 100644 --- a/photon/libc/sys/magenta/fio.c +++ b/photon/libc/sys/magenta/fio.c @@ -9,6 +9,38 @@ struct __io_file *stdin = &__stdin; struct __io_file *stdout = &__stdout; struct __io_file *stderr = &__stderr; +static mx_flags_t flags_from_mode(const char *r) +{ + mx_flags_t out = 0; + + while (*r) { + switch (*r) { + case 'r': + out |= MX_FILE_READ; + break; + case 'w': + out |= MX_FILE_WRITE; + break; + case '+': + out |= (MX_FILE_READ | MX_FILE_WRITE); + break; + case 'a': + out |= MX_FILE_APPEND; + break; + case 'b': + /* TODO */ + break; + default: + out = 0; + return out; + } + + r++; + } + + return out; +} + void __fio_init(mx_handle_t in, mx_handle_t out, mx_handle_t err) { __stdin.handle = in; @@ -16,11 +48,59 @@ void __fio_init(mx_handle_t in, mx_handle_t out, mx_handle_t err) __stderr.handle = err; } +int __fio_fopen(const char *path, const char *mode, struct __io_file *fp) +{ + mx_handle_t h = MX_NULL_HANDLE; + mx_status_t stat = mx_open(MX_NULL_HANDLE, path, 0, &h); + + if (stat != MX_OK) { + return -1; + } + + fp->handle = h; + return 0; +} + +int __fio_fdopen(mx_handle_t fd, const char *mode, struct __io_file *fp) +{ + /* TODO validate handle and mode */ + fp->handle = fd; + return 0; +} + int __fileno(struct __io_file *f) { return (int)f->handle; } +unsigned int __fio_read(struct __io_file *f, char *buf, unsigned int sz) +{ + if (!sz) { + return 0; + } + + size_t i = 0; + unsigned long real_sz = 0; + + if (f->unget) { + buf[i++] = f->unget; + f->unget = 0; + sz--; + } + + if (!sz) { + return real_sz; + } + + mx_status_t err = mx_read(f->handle, sz, buf + i, &real_sz); + + if (err != MX_OK || real_sz != sz) { + f->err = 1; + } + + return real_sz + i; +} + unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz) { for (unsigned int i = 0; i < sz; i++) { @@ -37,6 +117,16 @@ unsigned int __fio_write(struct __io_file *f, const char *buf, unsigned int sz) return sz; } +int __fio_ungetc(struct __io_file *f, char c) +{ + if (f->unget) { + return -1; + } + + f->unget = c; + return 0; +} + unsigned int __fio_flush(struct __io_file *f) { unsigned long written = 0;