diff --git a/Makefile b/Makefile index 34a89f0..4770193 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,8 @@ SHARED_LIBS= # Build CFLAGS=-I include \ + -ggdb \ + -Og \ -ffreestanding \ -Wall \ -Wextra \ diff --git a/include/math.h b/include/math.h index fbffb58..8e71686 100644 --- a/include/math.h +++ b/include/math.h @@ -3,4 +3,23 @@ #define HUGE_VAL (__builtin_huge_val()) double log10(double f); +double log2(double f); double log(double f); +double sqrt(double f); +double floor(double f); +double ceil(double f); +double fmod(double x, double y); +double atan2(double x, double y); +double asin(double x); +double acos(double x); +double fabs(double x); +double pow(double x, double y); +double tanh(double f); +double cosh(double f); +double sinh(double f); +double sin(double f); +double cos(double f); +double tan(double f); +double frexp(double x, int *exp); +double ldexp(double x, int exp); +double exp(double f); diff --git a/include/setjmp.h b/include/setjmp.h index ab18099..a3d8446 100644 --- a/include/setjmp.h +++ b/include/setjmp.h @@ -4,5 +4,7 @@ typedef struct { unsigned long _v[8]; } jmp_buf[1]; +int _setjmp(jmp_buf env); int setjmp(jmp_buf env); +void _longjmp(jmp_buf env, int val); void longjmp(jmp_buf env, int val); diff --git a/include/stdio.h b/include/stdio.h index 818b5ce..f341d3c 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -34,6 +34,12 @@ int renameat(int olddfd, const char *oldpath, int newdfd, const char *newpath char *ctermid(char *s); int setvbuf(FILE *fp, char *buf, int mode, size_t size); void setbuf(FILE *fp, char *buf); +int ungetc(int ch, FILE *fp); + +FILE *tmpfile(void); + +FILE *popen(const char *command, const char *type); +int pclose(FILE *fp); void flockfile(FILE *fp); void funlockfile(FILE *fp); diff --git a/include/stdlib.h b/include/stdlib.h index d5ce6c1..b8ff1c0 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -11,12 +11,15 @@ __Malloc void *calloc(size_t size, size_t nmemb); __Malloc void *malloc(size_t size); void *realloc(void *p, size_t newsz); void free(void *ptr); +_Noreturn void abort(void); +int abs(int d); + +int system(const char *command); int atoi(const char *str); char *getenv(const char *name); int setenv(const char *name, const char *value, int overwrite); -// XXX: POSIX doesn't define _Noreturn attribute on those? -void _Exit(int status); -void exit(int status); +_Noreturn void _Exit(int status); +_Noreturn void exit(int status); diff --git a/include/time.h b/include/time.h index c28c435..cf541e3 100644 --- a/include/time.h +++ b/include/time.h @@ -23,4 +23,6 @@ time_t time(time_t *t); double difftime(time_t t1, time_t t0); struct tm *gmtime_r(const time_t *restrict timep, struct tm *restrict res); +struct tm *localtime_r(const time_t *restrict timep, struct tm *restrict res); +time_t mktime(struct tm *tm); size_t strftime(char *restrict buf, size_t lim, const char *restrict fmt, const struct tm *restrict tm); diff --git a/src/malloc/calloc.c b/src/malloc/calloc.c new file mode 100644 index 0000000..d1e616f --- /dev/null +++ b/src/malloc/calloc.c @@ -0,0 +1,10 @@ +#include +#include + +void *calloc(size_t size, size_t nmemb) { + void *blk = malloc(size * nmemb); + if (blk) { + memset(blk, 0, size * nmemb); + } + return blk; +} diff --git a/src/stdio/fflush.c b/src/stdio/fflush.c index a47b1f6..82e9e97 100644 --- a/src/stdio/fflush.c +++ b/src/stdio/fflush.c @@ -2,6 +2,10 @@ #include int fflush(FILE *fp) { + if (!fp) { + // TODO: flush all open files + return 0; + } if (fp->buf_mode != _IONBF) { if (__libc_file_flush_read(fp) != 0) { return -1; diff --git a/src/stdio/file.c b/src/stdio/file.c index 6d19b1f..4709aa8 100644 --- a/src/stdio/file.c +++ b/src/stdio/file.c @@ -20,6 +20,7 @@ FILE *__libc_file_create(void) { res->free = file_default_free; res->buf = ((void *) res) + sizeof(FILE); + res->buf_mode = _IOLBF; res->ungetc = -1; return res; diff --git a/src/stdio/getdelim.c b/src/stdio/getdelim.c index 6875228..d373dc1 100644 --- a/src/stdio/getdelim.c +++ b/src/stdio/getdelim.c @@ -23,6 +23,7 @@ ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *fp) { } p = *lineptr; + rem = *n; while (1) { if (!rem) { diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c index 04d6d8f..c9b08c1 100644 --- a/src/stdio/pclose.c +++ b/src/stdio/pclose.c @@ -1,6 +1,5 @@ #include int pclose(FILE *fp) { - (void) fp; - return 0; + return fclose(fp); } diff --git a/src/stdio/popen.c b/src/stdio/popen.c index ba4762b..08af0b0 100644 --- a/src/stdio/popen.c +++ b/src/stdio/popen.c @@ -1,9 +1,113 @@ +#include <_libc/stdio.h> +#include +#include +#include #include #include +// Internal pipe state +struct pipe { + int fd; + pid_t pid; +}; + +static ssize_t pipe_read(void *ctx, void *buf, size_t lim) { + return read(((struct pipe *) ctx)->fd, buf, lim); +} + +static ssize_t pipe_write(void *ctx, const void *buf, size_t lim) { + return write(((struct pipe *) ctx)->fd, buf, lim); +} + +static off_t pipe_seek(void *ctx, off_t offset, int whence) { + (void) ctx; + (void) offset; + (void) whence; + errno = ESPIPE; + return -1; +} + +static int pipe_close(void *_ctx) { + struct pipe *ctx = _ctx; + close(ctx->fd); + int r; + if (waitpid(ctx->pid, &r, 0) < 0) { + return -1; + } + free(ctx); + return r; +} + FILE *popen(const char *command, const char *mode) { - (void) command; - (void) mode; - errno = EINVAL; + int fds[2]; + struct pipe *ctx; + FILE *fp = NULL; + int flags = __libc_file_mode(mode); + if (flags < 0) { + errno = EINVAL; + return NULL; + } + if ((flags & (FILE_MODE_WRITE | FILE_MODE_READ)) == (FILE_MODE_READ | FILE_MODE_WRITE)) { + errno = EINVAL; + return NULL; + } + + if (!(ctx = calloc(1, sizeof(struct pipe)))) { + goto err; + } + if (!(fp = __libc_file_create())) { + goto err_ctx; + } + if (pipe(fds) != 0) { + goto err_file; + } + if ((ctx->pid = fork()) == -1) { + goto err_pipe; + } + + if (ctx->pid == 0) { + // In child + if (flags & FILE_MODE_WRITE) { + if (dup2(fds[0], STDIN_FILENO) < 0) { + _exit(-1); + } + } else { + if (dup2(fds[1], STDOUT_FILENO) < 0) { + _exit(-1); + } + } + close(fds[0]); + close(fds[1]); + + _exit(execl("/bin/sh", "sh", "-c", command, NULL)); + } + + if (flags & FILE_MODE_WRITE) { + close(fds[0]); + ctx->fd = fds[1]; + fp->flags = FILE_MODE_WRITE; + } else { + close(fds[1]); + ctx->fd = fds[0]; + fp->flags = FILE_MODE_READ; + } + + fp->ctx = ctx; + fp->read = pipe_read; + fp->write = pipe_write; + fp->seek = pipe_seek; + fp->close = pipe_close; + + return fp; + + // TODO: preserve errno here +err_pipe: + close(fds[0]); + close(fds[1]); +err_file: + fclose(fp); +err_ctx: + free(ctx); +err: return NULL; } diff --git a/src/time/time.c b/src/time/time.c index 71013c0..9e73c53 100644 --- a/src/time/time.c +++ b/src/time/time.c @@ -6,5 +6,5 @@ time_t time(time_t *t) { if (gettimeofday(&now, NULL) != 0) { return -1; } - return t ? *t = now.tv_sec : now.tv_sec; + return t ? *t = (time_t) now.tv_sec : (time_t) now.tv_sec; }