diff options
author | pommicket <pommicket@gmail.com> | 2022-02-14 16:52:33 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2022-02-14 16:52:33 -0500 |
commit | c15db88951d7c5d1903fb3e5f42ca9f966f27d21 (patch) | |
tree | d5b6bae3a1458b519efbbfd762be61f645a1b4f0 /05 | |
parent | d0d868433eb8e737fd581c1eb6f2734f293e6267 (diff) |
almost all of stdio.h
Diffstat (limited to '05')
-rw-r--r-- | 05/Makefile | 4 | ||||
-rw-r--r-- | 05/codegen.b | 4 | ||||
-rw-r--r-- | 05/constants.b | 4 | ||||
-rw-r--r-- | 05/main.c | 6 | ||||
-rw-r--r-- | 05/stdc_common.h | 94 | ||||
-rw-r--r-- | 05/stdio.h | 352 | ||||
-rw-r--r-- | 05/string.h | 1 |
7 files changed, 403 insertions, 62 deletions
diff --git a/05/Makefile b/05/Makefile index 69fd54c..0a2fcb5 100644 --- a/05/Makefile +++ b/05/Makefile @@ -5,9 +5,9 @@ out04: in04 ../04/out03 ../04/out03 in04 out04 %.html: %.md ../markdown ../markdown $< -%.out: %.c +%.out: %.c *.h out04 ./out04 $< $@ -a.out: main.c +a.out: main.c *.h out04 ./out04 clean: rm -f out* README.html *.out diff --git a/05/codegen.b b/05/codegen.b index 0220450..8e06318 100644 --- a/05/codegen.b +++ b/05/codegen.b @@ -3030,7 +3030,7 @@ function generate_code generate_functions() ; generate code at the entry point of the executable local main_addr - main_addr = ident_list_lookup(functions_addresses, .str_main) + main_addr = ident_list_lookup(functions_addresses, .str__main) if main_addr == 0 goto no_main_function ; on entry, we will have: @@ -3066,7 +3066,7 @@ function generate_code :no_main_function die(.str_no_main_function) :str_no_main_function - string Error: No main function. + string Error: No _main function. byte 0 :too_much_code die(.str_too_much_code) diff --git a/05/constants.b b/05/constants.b index fd8a382..5027198 100644 --- a/05/constants.b +++ b/05/constants.b @@ -789,6 +789,6 @@ :str_default string default byte 0 -:str_main - string main +:str__main + string _main byte 0 @@ -1,8 +1,10 @@ #include <stdio.h> #include <string.h> -int main(int argc, char **argv) { - printf("%s\n",remove("test_file")?"failure":"success"); +int main(void) { + char nam[L_tmpnam]; + printf("%s\n", tmpnam(nam)); + return 0; } diff --git a/05/stdc_common.h b/05/stdc_common.h index db50cd9..e4527b8 100644 --- a/05/stdc_common.h +++ b/05/stdc_common.h @@ -59,15 +59,107 @@ static unsigned char __syscall_data[] = { (((unsigned long (*)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long))__syscall_data)\ (no, arg1, arg2, arg3, arg4, arg5, arg6)) +long read(int fd, void *buf, size_t count) { + return __syscall(0, fd, buf, count, 0, 0, 0); +} long write(int fd, void *buf, size_t count) { - __syscall(1, fd, buf, count, 0, 0, 0); + return __syscall(1, fd, buf, count, 0, 0, 0); +} + +void _Exit(int status) { + return __syscall(60, status, 0, 0, 0, 0, 0); +} + +typedef long time_t; + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +int clock_gettime(int clock, struct timespec *tp) { + return __syscall(228, clock, tp, 0, 0, 0, 0); } +#define F_OK 0 +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +int access(const char *pathname, int mode) { + return __syscall(21, pathname, mode, 0, 0, 0, 0); +} + + +int errno; + +#define EIO 5 +#define EDOM 33 +#define ERANGE 34 + +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define MAP_SHARED 0x01 +#define MAP_ANONYMOUS 0x20 +#define MAP_PRIVATE 0x02 +void *mmap(void *addr, size_t length, int prot, int flags, int fd, long offset) { + return __syscall(9, addr, length, prot, flags, fd, offset); +} + +int munmap(void *addr, size_t length) { + return __syscall(11, addr, length, 0, 0, 0, 0); +} + +void *malloc(size_t n) { + void *memory; + size_t bytes = n + 16; + memory = mmap(0, bytes, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if ((uint64_t)memory > 0xffffffffffff0000) return NULL; + *(uint64_t *)memory = bytes; + return (char *)memory + 16; +} + +void free(void *ptr) { + uint64_t *memory = (char *)ptr - 16; + uint64_t size = *memory; + munmap(memory, size); +} + +void *calloc(size_t nmemb, size_t size) { + if (nmemb > 0xffffffffffffffff / size) + return NULL; + return malloc(nmemb * size); +} + + size_t strlen(char *s) { char *t = s; while (*t) ++t; return t - s; } + +typedef struct { + int fd; + unsigned char eof; + unsigned char err; +} FILE; + +FILE _stdin = {0}, *stdin; +FILE _stdout = {1}, *stdout; +FILE _stderr = {2}, *stderr; + +int main(); + +int _main(int argc, char **argv) { + stdin = &_stdin; + stdout = &_stdout; + stderr = &_stderr; + return main(argc, argv); +} + + #endif // _STDC_COMMON_H @@ -1541,16 +1541,6 @@ static int32_t _stbsp__real_to_str(char const **start, uint32_t *len, char *out, #undef STBSP__SPECIAL #undef STBSP__COPYFP -typedef void FILE; - -FILE *stdin = 0; -FILE *stdout = 1; -FILE *stderr = 2; - -int __fd_puts(int fd, const char *s) { - return write(fd, s, strlen(s)); -} - // these are the constants that gnu uses, but they don't really matter for us #define _IOFBF 0 #define _IOLBF 1 @@ -1566,10 +1556,52 @@ typedef long fpos_t; #define SEEK_CUR 1 #define SEEK_END 2 #define SEEK_SET 0 -#define TMP_MAX 10000 +#define TMP_MAX 500 + +long lseek(int fd, long offset, int whence) { + return __syscall(8, fd, offset, whence, 0, 0, 0); +} + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t count; + if (nmemb > 0xffffffffffffffff / size) { + stream->err = 1; + return 0; + } + count = size * nmemb; + while (count > 0) { + long n = write(stream->fd, ptr, count); + if (n <= 0) break; + count -= n; + ptr = (char *)ptr + n; + } + if (count > 0) stream->err = 1; + return nmemb - count / size; +} + +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t count; + long n = 1; + if (stream->eof) return 0; + if (nmemb > 0xffffffffffffffff / size) { + stream->err = 1; + return 0; + } + count = size * nmemb; + while (count > 0) { + n = read(stream->fd, ptr, count); + if (n <= 0) break; + count -= n; + ptr = (char *)ptr + n; + } + if (n == 0) stream->eof = 1; + if (n < 0) stream->err = 1; + return nmemb - count / size; +} static char *__fprintf_callback(const char *buf, void *user, int len) { - write((int)user, buf, len); + FILE *fp = user; + fwrite(buf, 1, len, fp); return buf; } @@ -1600,6 +1632,82 @@ int printf(const char *fmt, ...) { return ret; } +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 0100 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_DIRECTORY 0200000 +#define __O_TMPFILE 020000000 +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) +int open(const char *path, int flags, int mode) { + return __syscall(2, path, flags, mode, 0, 0, 0); +} + +int close(int fd) { + return __syscall(3, fd, 0, 0, 0, 0, 0); +} + + +int _fopen_flags_from_mode(const char *mode) { + int flags; + if (mode[1] == '+' || (mode[1] && mode[2] == '+')) { + // open for updating + flags = O_RDWR; + switch (mode[0]) { + case 'r': break; + case 'w': flags |= O_TRUNC | O_CREAT; break; + case 'a': flags |= O_APPEND | O_CREAT; break; + default: return -1; + } + } else { + switch (mode[0]) { + case 'r': flags = O_RDONLY; break; + case 'w': flags = O_WRONLY | O_TRUNC | O_CREAT; break; + case 'a': flags = O_WRONLY | O_APPEND | O_CREAT; break; + default: return -1; + } + } + return flags; +} + +FILE *_FILE_from_fd(int fd) { + FILE *fp = calloc(1, sizeof(FILE)); + fp->fd = fd; + return fp; +} + +FILE *fopen(const char *filename, const char *mode) { + int flags = _fopen_flags_from_mode(mode); + if (flags < 0) return NULL; + int fd; + + fd = open(filename, flags, 0644); + if (fd < 0) return NULL; + return _FILE_from_fd(fd); +} + +int fclose(FILE *stream) { + int ret = close(stream->fd); + free(stream); + return ret; +} + +int fflush(FILE *stream) { + // we don't buffer anything + return 0; +} + +FILE *freopen(const char *filename, const char *mode, FILE *stream) { + int flags = _fopen_flags_from_mode(mode); + close(stream->fd); + if (flags < 0) return NULL; + stream->eof = stream->err = 0; + stream->fd = open(filename, flags, 0644); + return stream; +} + int unlink(const char *pathname) { return __syscall(87, pathname, 0, 0, 0, 0, 0); } @@ -1614,49 +1722,187 @@ int remove(const char *filename) { : 0; } -int rename(const char *old, const char *new); -FILE *tmpfile(void); -char *tmpnam(char *s); -int fclose(FILE *stream); -int fflush(FILE *stream); -FILE *fopen(const char *filename, const char *mode); -FILE *freopen(const char *filename, const char *mode, -FILE *stream); -void setbuf(FILE *stream, char *buf); -int setvbuf(FILE *stream, char *buf, int mode, size_t size); -int fprintf(FILE *stream, const char *format, ...); +int rename(const char *old, const char *new) { + return __syscall(82, old, new, 0, 0, 0, 0); +} + +char *tmpnam(char *s) { + struct timespec t = {0}; + do { + clock_gettime(CLOCK_MONOTONIC, &t); // use clock as a source of randomness + sprintf(s, "/tmp/C_%06u", t.tv_nsec % 1000000); + } while (access(s, F_OK) == 0); // if file exists, generate a new name + return s; +} + +FILE *tmpfile(void) { + int fd = open("/tmp", O_TMPFILE | O_RDWR, 0600); + if (fd < 0) return NULL; + return _FILE_from_fd(fd); +} + +// we don't buffer anything +// we're allowed to do this: "The contents of the array at any time are indeterminate." C89 ยง 4.9.5.6 +void setbuf(FILE *stream, char *buf) { +} + +int setvbuf(FILE *stream, char *buf, int mode, size_t size) { + return 0; +} + +// @TODO int fscanf(FILE *stream, const char *format, ...); -int printf(const char *format, ...); -int scanf(const char *format, ...); -int sprintf(char *s, const char *format, ...); int sscanf(const char *s, const char *format, ...); -int vfprintf(FILE *stream, const char *format, va_list arg); -int vprintf(const char *format, va_list arg); -int vsprintf(char *s, const char *format, va_list arg); -int fgetc(FILE *stream); -char *fgets(char *s, int n, FILE *stream); -int fputc(int c, FILE *stream); -int fputs(const char *s, FILE *stream); -int getc(FILE *stream); -int getchar(void); -char *gets(char *s); -int putc(int c, FILE *stream); -int putchar(int c); -int puts(const char *s); -int ungetc(int c, FILE *stream); -size_t fread(void *ptr, size_t size, size_t nmemb, -FILE *stream); -size_t fwrite(const void *ptr, size_t size, size_t nmemb, -FILE *stream); -int fgetpos(FILE *stream, fpos_t *pos); -int fseek(FILE *stream, long int offset, int whence); -int fsetpos(FILE *stream, const fpos_t *pos); -long int ftell(FILE *stream); -void rewind(FILE *stream); -void clearerr(FILE *stream); -int feof(FILE *stream); -int ferror(FILE *stream); -void perror(const char *s); +int scanf(const char *format, ...); + +int fgetc(FILE *stream) { + unsigned char c; + long n; + if (stream->eof) return EOF; + n = read(stream->fd, &c, 1); + if (n > 0) return c; + if (n < 0) { + stream->err = 1; + return EOF; + } + // n == 0 + stream->eof = 1; + return EOF; +} + +#define getc(fp) fgetc(fp) + +char *fgets(char *s, int n, FILE *stream) { + char *p = s, *end = p + (n-1); + + if (stream->eof) return NULL; + + while (p < end) { + long n = read(stream->fd, p, 1); + if (n < 0) { + stream->err = 1; + return NULL; + } + if (n == 0) { + stream->eof = 1; + if (p == s) { + // end of file reached, and no characters were read + return NULL; + } + break; + } + if (*p == '\n') { + ++p; + break; + } + ++p; + } + *p = '\0'; + return s; +} + +int fputc(int c, FILE *stream) { + size_t n = fwrite(&c, 1, 1, stream); + if (n == 1) return c; + return EOF; +} +#define putc(c, fp) fputc(c, fp) + +int fputs(const char *s, FILE *stream) { + size_t n = strlen(s); + if (fwrite(s, 1, n, stream) == n) + return n; + return EOF; +} + +int getchar(void) { + return getc(stdin); +} + +char *gets(char *s) { + char *p; + fgets(s, 1l<<20, stdin); + if (*s) { + p = s + strlen(s) - 1; + // remove newline + if (*p == '\n') + *p = '\0'; + } + return s; +} + +int putchar(int c) { + return putc(c, stdout); +} + +int puts(const char *s) { + fputs(s, stdout); + putchar('\n'); +} + +int ungetc(int c, FILE *stream) { + /* @NONSTANDARD */ + fprintf(stderr, "ERROR: ungetc is not supported.\n"); + _Exit(-1); +} + + +int fgetpos(FILE *stream, fpos_t *pos) { + long off = lseek(stream->fd, 0, SEEK_CUR); + if (off < 0) { + errno = EIO; + return EIO; + } + *pos = off; + return 0; +} + +int fsetpos(FILE *stream, const fpos_t *pos) { + long off = lseek(stream->fd, *pos, SEEK_SET); + if (off < 0) { + errno = EIO; + return EIO; + } + stream->eof = 0; + return 0; +} + +int fseek(FILE *stream, long int offset, int whence) { + long off = lseek(stream->fd, offset, whence); + if (off < 0) { + return EIO; + } + stream->eof = 0; + return 0; +} + +long int ftell(FILE *stream) { + long off = lseek(stream->fd, 0, SEEK_CUR); + if (off < 0) { + errno = EIO; + return -1L; + } + return off; +} + +void rewind(FILE *stream) { + fseek(stream, 0, SEEK_SET); + stream->err = 0; +} + +void clearerr(FILE *stream) { + stream->err = 0; +} + +int feof(FILE *stream) { + return stream->eof; +} + +int ferror(FILE *stream) { + return stream->err; +} + +void perror(const char *s); // @TODO #undef STB_SPRINTF_MIN diff --git a/05/string.h b/05/string.h index 44a25e6..1ea2a91 100644 --- a/05/string.h +++ b/05/string.h @@ -11,4 +11,5 @@ void *memset(void *s, int c, size_t n) { } + #endif // _STRING_H |