diff options
author | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
commit | 4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch) | |
tree | 80f156b7940d9d19971395f335530170c69516c7 /userland/libc/stdio |
Move everything into a new repo.
Diffstat (limited to 'userland/libc/stdio')
39 files changed, 901 insertions, 0 deletions
diff --git a/userland/libc/stdio/dprintf.c b/userland/libc/stdio/dprintf.c new file mode 100644 index 0000000..2f2aadb --- /dev/null +++ b/userland/libc/stdio/dprintf.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int dprintf(int fd, const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vdprintf(fd, format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/fclose.c b/userland/libc/stdio/fclose.c new file mode 100644 index 0000000..02d93ae --- /dev/null +++ b/userland/libc/stdio/fclose.c @@ -0,0 +1,10 @@ +#include <stdio.h> +#include <stdlib.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fclose.html +// FIXME: Do some actual error checking. +int fclose(FILE *stream) { + free(stream->cookie); + free(stream); + return 0; +} diff --git a/userland/libc/stdio/feof.c b/userland/libc/stdio/feof.c new file mode 100644 index 0000000..7f46301 --- /dev/null +++ b/userland/libc/stdio/feof.c @@ -0,0 +1,5 @@ +#include <stdio.h> + +int feof(FILE *stream) { + return stream->is_eof; +} diff --git a/userland/libc/stdio/ferror.c b/userland/libc/stdio/ferror.c new file mode 100644 index 0000000..8cb46cf --- /dev/null +++ b/userland/libc/stdio/ferror.c @@ -0,0 +1,5 @@ +#include <stdio.h> + +int ferror(FILE *stream) { + return stream->has_error; +} diff --git a/userland/libc/stdio/fflush.c b/userland/libc/stdio/fflush.c new file mode 100644 index 0000000..7a37c79 --- /dev/null +++ b/userland/libc/stdio/fflush.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fflush.html +int fflush(FILE *stream) { + // FIXME: Implement + return 0; +} diff --git a/userland/libc/stdio/fgetc.c b/userland/libc/stdio/fgetc.c new file mode 100644 index 0000000..c69211f --- /dev/null +++ b/userland/libc/stdio/fgetc.c @@ -0,0 +1,20 @@ +#include <assert.h> +#include <stdio.h> + +int fgetc(FILE *stream) { + if (stream->has_buffered_char) { + stream->has_buffered_char = 0; + return stream->buffered_char; + } + char c; + if (1 == fread(&c, 1, 1, stream)) + return (int)c; + // FIXME: Should use feof and ferror + if (stream->has_error) + return EOF; + if (stream->is_eof) + return EOF; + // How did we get here? + assert(0); + return EOF; +} diff --git a/userland/libc/stdio/fgetpos.c b/userland/libc/stdio/fgetpos.c new file mode 100644 index 0000000..7f34d6a --- /dev/null +++ b/userland/libc/stdio/fgetpos.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +// FIXME: Error handling +int fgetpos(FILE *restrict stream, fpos_t *restrict pos) { + *pos = (fpos_t)stream->offset_in_file; + return 0; +} diff --git a/userland/libc/stdio/fgets.c b/userland/libc/stdio/fgets.c new file mode 100644 index 0000000..8e21501 --- /dev/null +++ b/userland/libc/stdio/fgets.c @@ -0,0 +1,16 @@ +#include <stdio.h> + +char *fgets(char *s, int n, FILE *stream) { + for (int i = 0; i < n; i++) { + char c; + fread(&c, 1, 1, stream); + if (stream->has_error) + return NULL; + if (stream->is_eof) + return NULL; + s[i] = c; + if (c == '\n') + break; + } + return s; +} diff --git a/userland/libc/stdio/fileno.c b/userland/libc/stdio/fileno.c new file mode 100644 index 0000000..246cc51 --- /dev/null +++ b/userland/libc/stdio/fileno.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <errno.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fileno.html +// The fileno() function shall return the integer file descriptor associated +// with the stream pointed to by stream. +int fileno(FILE *stream) { + if (-1 == stream->fd) { + errno = EBADF; + return -1; + } + return stream->fd; +} diff --git a/userland/libc/stdio/fopen.c b/userland/libc/stdio/fopen.c new file mode 100644 index 0000000..a29c7ef --- /dev/null +++ b/userland/libc/stdio/fopen.c @@ -0,0 +1,57 @@ +#include <fcntl.h> +#include <sys/stat.h> +#include <stdint.h> +#include <stdio.h> + +// FIXME: All modes not implemented +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html +FILE *fopen(const char *pathname, const char *mode) { + uint8_t read = 0; + uint8_t write = 0; + uint8_t append = 0; + // FIXME: Not parsed correctly + for (; *mode; mode++) { + // r or rb + // Open file for reading. + // w or wb + // Truncate to zero length or create file for writing. + // a or ab + // Append; open or create file for writing at + // end-of-file. + switch (*mode) { + case 'r': + read = 1; + break; + case 'w': + write = 1; + break; + case 'a': + append = 1; + break; + } + } + int flag = 0; + if (read) + flag |= O_READ; + if (write) + flag |= O_WRITE; + + int fd = open(pathname, flag, 0); + if (-1 == fd) + return NULL; + + struct stat s; + stat(pathname, &s); + + FILE *r = malloc(sizeof(FILE)); + r->read = read_fd; + r->write = write_fd; + r->seek = seek_fd; + r->has_error = 0; + r->is_eof = 0; + r->offset_in_file = 0; + r->file_size = s.st_size; + r->cookie = NULL; + r->fd = fd; + return r; +} diff --git a/userland/libc/stdio/fprintf.c b/userland/libc/stdio/fprintf.c new file mode 100644 index 0000000..f983065 --- /dev/null +++ b/userland/libc/stdio/fprintf.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int fprintf(FILE *f, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int rc = vfprintf(f, fmt, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/fputc.c b/userland/libc/stdio/fputc.c new file mode 100644 index 0000000..7c8fa7c --- /dev/null +++ b/userland/libc/stdio/fputc.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int fputc(int c, FILE *stream) { + if (fwrite(&c, 1, 1, stream) > 0) + return c; + return EOF; +} diff --git a/userland/libc/stdio/fputs.c b/userland/libc/stdio/fputs.c new file mode 100644 index 0000000..1b70c66 --- /dev/null +++ b/userland/libc/stdio/fputs.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int fputs(const char *s, FILE *stream) { + const char *b = s; + for (; *s; s++) + if (0 == fwrite(s, 1, 1, stream)) + return EOF; + return s - b; +} diff --git a/userland/libc/stdio/fread.c b/userland/libc/stdio/fread.c new file mode 100644 index 0000000..1a27afa --- /dev/null +++ b/userland/libc/stdio/fread.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <sys/types.h> + +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + // FIXME: Check for overflow + ssize_t bytes_to_read = nmemb * size; + size_t rc = stream->read(stream, ptr, bytes_to_read); + // On success, fread() return the number of items read + rc /= size; + return rc; +} diff --git a/userland/libc/stdio/fscanf.c b/userland/libc/stdio/fscanf.c new file mode 100644 index 0000000..785ce4b --- /dev/null +++ b/userland/libc/stdio/fscanf.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <assert.h> + +int fscanf(FILE *stream, const char *format, ...) { + // FIXME + assert(0); +} diff --git a/userland/libc/stdio/fseek.c b/userland/libc/stdio/fseek.c new file mode 100644 index 0000000..fb891ec --- /dev/null +++ b/userland/libc/stdio/fseek.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <assert.h> + +int fseek(FILE *stream, long offset, int whence) { + return stream->seek(stream, offset, whence); + /* + switch (whence) { + case SEEK_SET: + stream->offset_in_file = offset; + break; + case SEEK_CUR: + stream->offset_in_file += offset; + break; + case SEEK_END: + // FIXME + assert(0); + break; + } + // FIXME: Error checking + return 0;*/ +} diff --git a/userland/libc/stdio/fsetpos.c b/userland/libc/stdio/fsetpos.c new file mode 100644 index 0000000..c39c545 --- /dev/null +++ b/userland/libc/stdio/fsetpos.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +// FIXME: Error handling +int fsetpos(FILE *stream, const fpos_t *pos) { + stream->offset_in_file = (long)(*pos); + return 0; +} diff --git a/userland/libc/stdio/ftell.c b/userland/libc/stdio/ftell.c new file mode 100644 index 0000000..35076d0 --- /dev/null +++ b/userland/libc/stdio/ftell.c @@ -0,0 +1,5 @@ +#include <stdio.h> + +long ftell(FILE *stream) { + return stream->offset_in_file; +} diff --git a/userland/libc/stdio/fwrite.c b/userland/libc/stdio/fwrite.c new file mode 100644 index 0000000..552bbd6 --- /dev/null +++ b/userland/libc/stdio/fwrite.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <sys/types.h> + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { + // FIXME: Check for overflow + ssize_t bytes_to_write = nmemb * size; + size_t rc = stream->write(stream, ptr, bytes_to_write); + // On success, fwrite() return the number of items + // written. + rc /= size; + return rc; +} diff --git a/userland/libc/stdio/getchar.c b/userland/libc/stdio/getchar.c new file mode 100644 index 0000000..dad2263 --- /dev/null +++ b/userland/libc/stdio/getchar.c @@ -0,0 +1,4 @@ +#include <stdio.h> + +// The getchar() function shall be equivalent to getc(stdin). +int getchar(void) { return fgetc(stdin); } diff --git a/userland/libc/stdio/open_memstream.c b/userland/libc/stdio/open_memstream.c new file mode 100644 index 0000000..8f359b9 --- /dev/null +++ b/userland/libc/stdio/open_memstream.c @@ -0,0 +1,108 @@ +#include <assert.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +/* +struct __IO_FILE { + size_t (*write)(FILE *, const unsigned char *, size_t); + size_t (*read)(FILE *, unsigned char *, size_t); + int (*seek)(FILE *, long, int); + long offset_in_file; + int buffered_char; + int has_buffered_char; + int fd; + uint8_t is_eof; + uint8_t has_error; + uint64_t file_size; + void *cookie; +}; +*/ + +struct Memstream { + size_t buffer_usage; + char *buffer; +}; + +#define MEMSTREAM_DEF_SIZE 4096 + +size_t memstream_write(FILE *fp, const unsigned char *buf, size_t n) { + struct Memstream *c = fp->cookie; + // FIXME: Do a reallocation + if (c->buffer_usage + n >= fp->file_size) { + n = fp->file_size - c->buffer_usage; + } + + memcpy(c->buffer + fp->offset_in_file, buf, n); + fp->offset_in_file += n; + if (fp->offset_in_file > c->buffer_usage) + c->buffer_usage = fp->offset_in_file; + return n; +} + +size_t memstream_read(FILE *fp, unsigned char *buf, size_t n) { + struct Memstream *c = fp->cookie; + size_t length_left = c->buffer_usage - fp->offset_in_file; + n = min(length_left, n); + memcpy(buf, c->buffer + fp->offset_in_file, n); + fp->offset_in_file += n; + if (0 == n) + fp->is_eof = 1; + return n; +} + +int memstream_seek(FILE *stream, long offset, int whence) { + switch (whence) { + case SEEK_SET: + stream->offset_in_file = offset; + break; + case SEEK_CUR: + stream->offset_in_file += offset; + break; + case SEEK_END: + stream->offset_in_file = stream->file_size + offset; + break; + default: + assert(0); + break; + } + // FIXME: Error checking + return 0; +} + +FILE *open_memstream(char **bufp, size_t *sizep) { + struct Memstream *c = NULL; + FILE *fp = malloc(sizeof(FILE)); + if (!fp) + return NULL; + + fp->offset_in_file = 0; + fp->buffered_char = 0; + fp->has_buffered_char = 0; + fp->seek = memstream_seek; + fp->fd = -1; + fp->is_eof = 0; + fp->has_error = 0; + fp->file_size = MEMSTREAM_DEF_SIZE; + + fp->write = memstream_write; + fp->read = memstream_read; + + c = malloc(sizeof(struct Memstream)); + if (!c) { + goto _exit_memstream_fail; + } + + fp->cookie = (void *)c; + + c->buffer = *bufp = malloc(MEMSTREAM_DEF_SIZE); + if (!bufp) { + goto _exit_memstream_fail; + } + c->buffer_usage = 0; + + return fp; +_exit_memstream_fail: + free(c); + free(fp); + return NULL; +} diff --git a/userland/libc/stdio/printf.c b/userland/libc/stdio/printf.c new file mode 100644 index 0000000..d26568a --- /dev/null +++ b/userland/libc/stdio/printf.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int printf(const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vprintf(format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/putc.c b/userland/libc/stdio/putc.c new file mode 100644 index 0000000..a468a95 --- /dev/null +++ b/userland/libc/stdio/putc.c @@ -0,0 +1,3 @@ +#include <stdio.h> + +int putc(int c, FILE *stream) { return fputc(c, stream);} diff --git a/userland/libc/stdio/putchar.c b/userland/libc/stdio/putchar.c new file mode 100644 index 0000000..3fcf7ca --- /dev/null +++ b/userland/libc/stdio/putchar.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <unistd.h> + +int putchar(int c) { + printf("%c", (char)c); + return c; +} diff --git a/userland/libc/stdio/puts.c b/userland/libc/stdio/puts.c new file mode 100644 index 0000000..4a72e66 --- /dev/null +++ b/userland/libc/stdio/puts.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int puts(const char *s) { + int rc = printf("%s\n", s); + return rc; +} diff --git a/userland/libc/stdio/remove.c b/userland/libc/stdio/remove.c new file mode 100644 index 0000000..35b41ad --- /dev/null +++ b/userland/libc/stdio/remove.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <errno.h> + +extern int errno; +int remove(const char *path) { + // FIXME + errno = ENAMETOOLONG; + return -1; +} diff --git a/userland/libc/stdio/rename.c b/userland/libc/stdio/rename.c new file mode 100644 index 0000000..15d4bf5 --- /dev/null +++ b/userland/libc/stdio/rename.c @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <assert.h> + +int rename(const char *old, const char *new) { + (void)old; + (void)new; + assert(0); // TODO: Implement + } diff --git a/userland/libc/stdio/setvbuf.c b/userland/libc/stdio/setvbuf.c new file mode 100644 index 0000000..7f91518 --- /dev/null +++ b/userland/libc/stdio/setvbuf.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size) { + // TODO + return 0; +} diff --git a/userland/libc/stdio/snprintf.c b/userland/libc/stdio/snprintf.c new file mode 100644 index 0000000..328442a --- /dev/null +++ b/userland/libc/stdio/snprintf.c @@ -0,0 +1,42 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +struct sn_cookie { + char *s; + size_t n; +}; + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +size_t sn_write(FILE *f, const unsigned char *s, const size_t l) { + struct sn_cookie *c = f->cookie; + size_t k = MIN(l, c->n); + memcpy(c->s, s, k); + c->s += k; + c->n -= k; + *(c->s) = '\0'; + // Upon successful completion, the snprintf() function shall return the number + // of bytes that would be written to s had n been sufficiently large excluding + // the terminating null byte. + return l; +} + +int vsnprintf(char *str, size_t size, const char *format, va_list ap) { + char dummy[1]; + struct sn_cookie c = {.s = (size ? str : dummy), .n = (size ? size - 1 : 0)}; + FILE f = { + .write = sn_write, + .cookie = &c, + }; + return vfprintf(&f, format, ap); +} + +int snprintf(char *str, size_t size, const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vsnprintf(str, size, format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/sprintf.c b/userland/libc/stdio/sprintf.c new file mode 100644 index 0000000..deffbbe --- /dev/null +++ b/userland/libc/stdio/sprintf.c @@ -0,0 +1,33 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +struct s_cookie { + char *s; +}; + +size_t s_write(FILE *f, const unsigned char *s, size_t l) { + struct s_cookie *c = f->cookie; + memcpy(c->s, s, l); + c->s += l; + *(c->s) = '\0'; + return l; +} + +int vsprintf(char *str, const char *format, va_list ap) { + struct s_cookie c = {.s = str}; + FILE f = { + .write = s_write, + .cookie = &c, + }; + return vfprintf(&f, format, ap); +} + +int sprintf(char *str, const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vsprintf(str, format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/stderr.c b/userland/libc/stdio/stderr.c new file mode 100644 index 0000000..76597e2 --- /dev/null +++ b/userland/libc/stdio/stderr.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <unistd.h> + +FILE __stderr_FILE = { + .write = write_fd, + .read = read_fd, + .is_eof = 0, + .has_error = 0, + .cookie = NULL, + .fd = 2, +}; diff --git a/userland/libc/stdio/stdin.c b/userland/libc/stdio/stdin.c new file mode 100644 index 0000000..ae3ab8d --- /dev/null +++ b/userland/libc/stdio/stdin.c @@ -0,0 +1,54 @@ +#include <assert.h> +#include <stdio.h> +#include <unistd.h> + +size_t write_fd(FILE *f, const unsigned char *s, size_t l) { + int rc = pwrite(f->fd, s, l, f->offset_in_file); + if (rc == -1) { + f->has_error = 1; + return 0; + } + f->offset_in_file += rc; + return rc; +} + +size_t read_fd(FILE *f, unsigned char *s, size_t l) { + int rc = pread(f->fd, s, l, f->offset_in_file); + if (rc == 0) + f->is_eof = 1; + if (rc == -1) { + f->has_error = 1; + return 0; + } + f->offset_in_file += rc; + return rc; +} + +int seek_fd(FILE *stream, long offset, int whence) { + switch (whence) { + case SEEK_SET: + stream->offset_in_file = offset; + break; + case SEEK_CUR: + stream->offset_in_file += offset; + break; + case SEEK_END: + stream->offset_in_file = stream->file_size + offset; + break; + default: + assert(0); + break; + } + // FIXME: Error checking + return 0; +} + +FILE __stdin_FILE = { + .write = write_fd, + .read = read_fd, + .seek = NULL, + .is_eof = 0, + .has_error = 0, + .cookie = NULL, + .fd = 0, +}; diff --git a/userland/libc/stdio/stdout.c b/userland/libc/stdio/stdout.c new file mode 100644 index 0000000..7f4edf0 --- /dev/null +++ b/userland/libc/stdio/stdout.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <unistd.h> + +FILE __stdout_FILE = { + .write = write_fd, + .read = read_fd, + .is_eof = 0, + .has_error = 0, + .seek = NULL, + .cookie = NULL, + .fd = 1, +}; +FILE __stderr_FILE; diff --git a/userland/libc/stdio/tmpfile.c b/userland/libc/stdio/tmpfile.c new file mode 100644 index 0000000..cee6e0a --- /dev/null +++ b/userland/libc/stdio/tmpfile.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <assert.h> + +FILE *tmpfile(void) { + // TODO + printf("TODO: Implement tmpfile()\n"); + assert(0); + return NULL; +} diff --git a/userland/libc/stdio/tmpnam.c b/userland/libc/stdio/tmpnam.c new file mode 100644 index 0000000..aafe67d --- /dev/null +++ b/userland/libc/stdio/tmpnam.c @@ -0,0 +1,10 @@ +#include <assert.h> +#include <stdio.h> + +char *tmpnam(char *s) { + assert(!s); + s = malloc(100); + strcpy(s, "/tmp.XXXXXX"); + mkstemp(s); + return s; +} diff --git a/userland/libc/stdio/ungetc.c b/userland/libc/stdio/ungetc.c new file mode 100644 index 0000000..8d649bc --- /dev/null +++ b/userland/libc/stdio/ungetc.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int ungetc(int c, FILE *stream) { + if (stream->has_buffered_char) + return EOF; + stream->buffered_char = c; + stream->has_buffered_char = 1; + return c; +} diff --git a/userland/libc/stdio/vdprintf.c b/userland/libc/stdio/vdprintf.c new file mode 100644 index 0000000..b3fa065 --- /dev/null +++ b/userland/libc/stdio/vdprintf.c @@ -0,0 +1,77 @@ +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +struct vd_cookie { + int fd; + char *buffer; + uint8_t buf_len; + uint8_t buf_used; + int sent_bytes; +}; + +size_t min(size_t a, size_t b) { return (a < b) ? a : b; } + +size_t vd_write(FILE *f, const unsigned char *s, size_t l) { + struct vd_cookie *c = f->cookie; + + int clear_buffer = 0; + size_t b_copy = min(l, c->buf_len - (c->buf_used)); + for (int i = 0; i < b_copy; i++) { + c->buffer[c->buf_used + i] = s[i]; + if (s[i] == '\n') + clear_buffer = 1; + } + c->buf_used += b_copy; + + if (clear_buffer) { + int rc = write(c->fd, c->buffer, c->buf_used); + c->buf_used = 0; + if (-1 == rc) { + return (size_t)-1; + } + c->sent_bytes += rc; + } + return l; +} + +int vdprintf(int fd, const char *format, va_list ap) { + FILE f = { + .write = write_fd, + .fd = fd, + }; + return vfprintf(&f, format, ap); + // return -1; + /* +char buffer[32]; +struct vd_cookie c = {.fd = fd, + .buffer = buffer, + .buf_len = 32, + .buf_used = 0, + .sent_bytes = 0}; +FILE f = { +.write = vd_write, +.cookie = &c, +}; + +// If an output error was encountered, these functions shall return a +// negative value and set errno to indicate the error. +if (-1 == vfprintf(&f, format, ap)) +return -1; + +// Upon successful completion, the dprintf(), +// fprintf(), and printf() functions shall return the number of bytes +// transmitted. + +if(0 == c.buf_used) +return c.sent_bytes; + +// First the current buffer needs to be cleared +int rc = write(fd, buffer, c.buf_used); +if (-1 == rc) { +return -1; +} +c.sent_bytes += rc; +return c.sent_bytes;*/ +} diff --git a/userland/libc/stdio/vfprintf.c b/userland/libc/stdio/vfprintf.c new file mode 100644 index 0000000..79a22fb --- /dev/null +++ b/userland/libc/stdio/vfprintf.c @@ -0,0 +1,243 @@ +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +const char HEX_SET[0x10] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +#define FILE_WRITE(_f, _s, _l, _r) \ + { \ + size_t _rc = _f->write(_f, (const unsigned char *)_s, _l); \ + if ((size_t)-1 == _rc) \ + assert(0); \ + *(int *)(_r) += _rc; \ + } +// if ((size_t)0 == _rc) \ +// assert(0); \ + +int fprint_num(FILE *f, int n, int base, char *char_set, int prefix, + int zero_padding, int right_padding) { + int c = 0; + if (0 == n) { + zero_padding = 1; + prefix = 1; + } + char str[32]; + int i = 0; + for (; n != 0 && i < 32; i++, n /= base) + // str[i] = (n % base) + '0'; + str[i] = char_set[(n % base)]; + + char t = (zero_padding) ? '0' : ' '; + int orig_i = i; + + if (!right_padding) { + for (; prefix - orig_i > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + + for (i--; i >= 0; i--) + FILE_WRITE(f, &(str[i]), 1, &c); + + if (right_padding) { + for (; prefix - orig_i > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + return c; +} + +int fprint_int(FILE *f, int n, int prefix, int zero_padding, + int right_padding) { + return fprint_num(f, n, 10, "0123456789", prefix, zero_padding, + right_padding); +} + +int fprint_hex(FILE *f, int n, int prefix, int zero_padding, + int right_padding) { + return fprint_num(f, n, 16, "0123456789abcdef", prefix, zero_padding, + right_padding); +} + +int fprint_octal(FILE *f, int n, int prefix, int zero_padding, + int right_padding) { + return fprint_num(f, n, 8, "012345678", prefix, zero_padding, right_padding); +} + +int print_string(FILE *f, const char *s, int *rc, int prefix, int right_padding, + int precision) { + int l = strlen(s); + char t = ' '; + int c = 0; + if (!right_padding) { + if (prefix) + assert(-1 == precision); // FIXME: Is this correct? + for (; prefix - l > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + int bl = precision; + for (; *s; s++, (*rc)++) { + if (precision != -1) { + if (0 == bl) + break; + bl--; + } + int r; + FILE_WRITE(f, (const unsigned char *)s, 1, &r); + assert(r != 0); + } + if (right_padding) { + assert(-1 == precision); // FIXME: Is this correct? + for (; prefix - l > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + (*rc) += c; + return 0; +} + +int parse_precision(const char **fmt) { + const char *s = *fmt; + int rc = 0; + for (int i = 0;; i++, s++) { + if ('\0' == *s) + break; + const char c = *s; + if ('*' == c) { + assert(i == 0); + return -1; + } else if (!(c >= '0' && c <= '9')) { + s--; + break; + } + rc *= 10; + rc += c - '0'; + } + *fmt = s; + return rc; +} + +int vfprintf(FILE *f, const char *fmt, va_list ap) { + int rc = 0; + const char *s = fmt; + int prefix = 0; + + int zero_padding = 0; + int right_padding = 0; + + int cont = 0; + int precision = -1; + for (; *s; s++) { + if (!cont && '%' != *s) { + FILE_WRITE(f, (const unsigned char *)s, 1, &rc); + continue; + } + if (!cont) { + cont = 1; + continue; + } + + if ('\0' == *s) + break; + + switch (*s) { + case '.': + s++; + assert('\0' != *s); + precision = parse_precision(&s); + assert('\0' != *s); + if (-1 == precision) + precision = va_arg(ap, int); + cont = 1; + break; + case '0': + prefix *= 10; + if (0 == prefix) + zero_padding = 1; + cont = 1; + break; + case '-': + assert(0 == prefix); + right_padding = 1; + cont = 1; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + prefix *= 10; + prefix += (*s) - '0'; + cont = 1; + break; + case 'i': + case 'd': + if(-1 != precision) { + zero_padding = 1; + prefix = precision; + right_padding = 0; + } + rc += fprint_int(f, va_arg(ap, int), prefix, zero_padding, right_padding); + cont = 0; + break; + case 'u': + assert(-1 == precision); + rc += fprint_int(f, va_arg(ap, unsigned int), prefix, zero_padding, + right_padding); + cont = 0; + break; + case 's': { + assert(!zero_padding); // this is not supported to strings + char *a = va_arg(ap, char *); + if (!a) { + if (-1 == + print_string(f, "(NULL)", &rc, prefix, right_padding, precision)) + return -1; + cont = 0; + break; + } + if (-1 == print_string(f, a, &rc, prefix, right_padding, precision)) + return -1; + cont = 0; + break; + } + case 'p': // TODO: Print this out in a nicer way + case 'x': + assert(-1 == precision); + rc += fprint_hex(f, va_arg(ap, const uint32_t), prefix, zero_padding, + right_padding); + cont = 0; + break; + case 'o': + assert(-1 == precision); + rc += fprint_octal(f, va_arg(ap, const uint32_t), prefix, zero_padding, + right_padding); + cont = 0; + break; + case '%': { + FILE_WRITE(f, (const unsigned char *)"%", 1, &rc); + cont = 0; + break; + } + case 'c': { + char c = va_arg(ap, const int); + FILE_WRITE(f, (const unsigned char *)&c, 1, &rc); + cont = 0; + break; + } + default: + printf("got %c but that is not supported by printf\n", *s); + assert(0); + break; + } + if (!cont) { + prefix = 0; + zero_padding = right_padding = 0; + precision = -1; + } + } + return rc; +} diff --git a/userland/libc/stdio/vprintf.c b/userland/libc/stdio/vprintf.c new file mode 100644 index 0000000..8a8dc33 --- /dev/null +++ b/userland/libc/stdio/vprintf.c @@ -0,0 +1,3 @@ +#include <stdio.h> + +int vprintf(const char *format, va_list ap) { return vdprintf(1, format, ap); } |