summaryrefslogtreecommitdiff
path: root/src/user/lib/stdlib.c
blob: c055d047166316f351f085d0cd6379ad2ee0f41c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <user/lib/stdlib.h>
#include <shared/printf.h>
#include <shared/syscalls.h>

// TODO oh god this garbage - malloc, actually open, [...]
static libc_file _stdin_null  = { .fd = 0 };
static libc_file _stdout_null = { .fd = 1 };

libc_file *stdin = &_stdin_null, *stdout = &_stdout_null;

static void backend_file(void *arg, const char *buf, size_t len) {
	file_write((libc_file*)arg, buf, len);
}

int printf(const char *fmt, ...) {
	int ret = 0;
	va_list argp;
	va_start(argp, fmt);
	ret = __printf_internal(fmt, argp, backend_file, (void*)stdout);
	va_end(argp);
	return ret;
}

static void backend_buf(void *arg, const char *buf, size_t len) {
	char **ptrs = arg;
	size_t space = ptrs[1] - ptrs[0];
	if (len > space) len = space;
	memcpy(ptrs[0], buf, len);
	ptrs[0] += len;
}

int snprintf(char *str, size_t len, const char *fmt, ...) {
	int ret = 0;
	char *ptrs[2] = {str, str + len};
	va_list argp;
	va_start(argp, fmt);
	ret = __printf_internal(fmt, argp, backend_buf, &ptrs);
	va_end(argp);
	if (ptrs[0] < ptrs[1]) *ptrs[0] = '\0';
	return ret;
}

int _klogf(const char *fmt, ...) {
	// idiotic. however, this hack won't matter anyways
	char buf[256];
	int ret = 0;
	char *ptrs[2] = {buf, buf + sizeof buf};
	va_list argp;
	va_start(argp, fmt);
	ret = __printf_internal(fmt, argp, backend_buf, &ptrs);
	va_end(argp);
	if (ptrs[0] < ptrs[1]) *ptrs[0] = '\0';
	_syscall_debug_klog(buf, ret);
	return ret;
}


libc_file *file_open(const char *path, int flags) {
	handle_t h = _syscall_open(path, strlen(path), flags);
	libc_file *f;
	if (h < 0) return NULL;

	f = malloc(sizeof *f);
	if (!f) {
		_syscall_close(h);
		return NULL;
	}
	f->pos = 0;
	f->eof = false;
	f->fd = h;
	return f;
}

libc_file *file_reopen(libc_file *f, const char *path, int flags) {
	/* partially based on the musl implementation of freopen */
	libc_file *f2;
	if (!path) goto fail;
	f2 = file_open(path, flags);
	if (!f2) goto fail;

	/* shouldn't happen, but if it happens, let's roll with it. */
	if (f->fd == f2->fd) f2->fd = -1;

	if (_syscall_dup(f2->fd, f->fd, 0) < 0) goto fail2;
	f->pos = f2->pos;
	f->eof = f2->eof;
	file_close(f2);
	return f;

fail2:
	file_close(f2);
fail:
	file_close(f);
	return NULL;
}

int file_read(libc_file *f, char *buf, size_t len) {
	if (f->fd < 0) return -1;

	int res = _syscall_read(f->fd, buf, len, f->pos);
	if (res < 0) return res;
	if (res == 0 && len > 0) f->eof = true;
	f->pos += res;
	return res;
}

int file_write(libc_file *f, const char *buf, size_t len) {
	if (f->fd < 0) return -1;

	int res = _syscall_write(f->fd, buf, len, f->pos);
	if (res < 0) return res;
	f->pos += res;
	return res;
}

void file_close(libc_file *f) {
	if (f->fd > 0) _syscall_close(f->fd);
	if (f != &_stdin_null && f != &_stdout_null)
		free(f);
}