almost all of stdio.h
This commit is contained in:
parent
d0d868433e
commit
c15db88951
7 changed files with 403 additions and 62 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
352
05/stdio.h
352
05/stdio.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
|
||||
|
||||
|
|
|
@ -11,4 +11,5 @@ void *memset(void *s, int c, size_t n) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
#endif // _STRING_H
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue