diff options
author | Vladimir Azarov <avm@intermediate-node.net> | 2024-10-13 20:54:32 +0200 |
---|---|---|
committer | Vladimir Azarov <avm@intermediate-node.net> | 2024-10-13 20:54:32 +0200 |
commit | 3972268b97b789a8212ea9bc7d1b9ce9905a68d8 (patch) | |
tree | b0cbf5012266da4702afb640f6bb1cdb2f097153 /tools/common.c | |
parent | 47a781f03119d360ef2b2936234d381fd2f4c85d (diff) |
Base library for tools and sed utility
Diffstat (limited to 'tools/common.c')
-rw-r--r-- | tools/common.c | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/tools/common.c b/tools/common.c new file mode 100644 index 0000000..00f7d3c --- /dev/null +++ b/tools/common.c @@ -0,0 +1,427 @@ +#define START "_start" +#include <crt_arch.h> +#include <bits/syscall.h.in> +#include <syscall_arch.h> + +#include <stdarg.h> + +#include "common.h" + +enum { + flush_on_newline = 1 +}; + +int errno = 0; +char *progname; + +static long sysret(unsigned long r) +{ + if (r > -4096UL) { + errno = -r; + return -1; + } + return r; +} + +void exit(int code) +{ + __syscall1(__NR_exit, code); +} + +static void *brk(void *addr) +{ + return (void *)__syscall1(__NR_brk, (long)addr); +} + +int write(int fd, char *buf, int len) +{ + return sysret(__syscall3(__NR_write, fd, (long)buf, len)); +} + +int read(int fd, char *buf, int len) +{ + return sysret(__syscall3(__NR_read, fd, (long)buf, len)); +} + +int open(char *fname, int flags, int mode) +{ + int o_largefile = 0100000; + return sysret(__syscall3(__NR_open, (long)fname, + flags|o_largefile, mode)); +} + +int stat(char *fname, struct stat *st) +{ + return sysret(__syscall2(__NR_stat, (long)fname, (long)st)); +} + +int fstat(int fd, struct stat *st) +{ + return sysret(__syscall2(__NR_fstat, (long)fd, (long)st)); +} + +int close(int fd) +{ + return sysret(__syscall1(__NR_close, fd)); +} + +void *mmap(char *addr, unsigned long length, int prot, int flags, int fd, + unsigned long offset) +{ + return (void*)sysret(__syscall6(__NR_mmap, (long)addr, length, + prot, flags, fd, offset)); +} + +int munmap(char *addr, int length) +{ + return sysret(__syscall2(__NR_munmap, (long)addr, length)); +} + +#define MREMAP_MAYMOVE 1 + +int mremap(void *old_addr, unsigned long old_size, unsigned long new_size, + int flags, void *new_addr) +{ + return sysret(__syscall5(__NR_mremap, (long)old_addr, old_size, + new_size, flags, (long)new_addr)); +} + +int strzlen(char *s) +{ + char *sc = s; + for (; *s; ++s) + ; + return s - sc; +} + +int strzeq(char *s1, char *s2) +{ + for (; *s1 && *s1 == *s2; ++s1, ++s2) + ; + return *s1 == 0 && *s2 == 0; +} + +int streq(struct str *s1, struct str *s2) +{ + int i; + if (s1->end - s1->start != s2->end - s2->start) + return 0; + for (i = 0; s1->start + i < s1->end; ++i) { + if (s1->start[i] != s2->start[i]) + return 0; + } + return 1; +} + +void memmove(char *dest, char *src, int len) +{ + int i; + if (dest < src) { + for (i = 0; i < len; ++i) + dest[i] = src[i]; + } else { + for (i = len - 1; i >= 0; --i) + dest[i] = src[i]; + } +} + +void memcpy(void *dest, void *src, int len) +{ + int i; + char *d = dest; + char *s = src; + for (i = 0; i < len; ++i) + d[i] = s[i]; +} + +void memset(void *dest, char c, int len) +{ + char *tmp = dest; + for (; tmp < (char*)dest + len; ++tmp) + *tmp = c; +} + +#define E(e, s) [e] = s, + +char *estrings[256] = { +#include "../src/errno/__strerror.h" +}; +#undef E + +void perror(char *s) +{ + int idx = errno; + if (errno > 256 || estrings[errno] == NULL) + idx = 0; + eprintf("%s: %s\n", s, estrings[idx]); +} + +void syscall_error(char *fname) +{ + perror(fname); + hexit(1); +} + +enum { + buflen = 32 * 1024 +}; + +struct iobuf { + int fd; + char buf[buflen]; + int len; +}; + +struct iobuf stdout = { 1 }; +struct iobuf stderr = { 2 }; + +static void flush(struct iobuf *buf) +{ + int ret = write(buf->fd, buf->buf, buf->len); + if (ret != buf->len) { + write(2, _S("some stdout/stderr error\n")); + exit(3); + } + buf->len = 0; +} + +static void putchar(struct iobuf *buf, char c) +{ + if (buf->len == buflen) + flush(buf); + buf->buf[buf->len] = c; + ++buf->len; + + if (flush_on_newline && c == '\n') + flush(buf); +} + +void hexit(int code) +{ + flush(&stdout); + flush(&stderr); + exit(code); +} + +static void print_int(struct iobuf *buf, int nsigned, int byte4, + unsigned long n) +{ + char tmpbuf[64]; + char *p = tmpbuf; + unsigned long k; + + if (nsigned) { + if (byte4) { + int tmp = n; + if (tmp < 0) { + putchar(buf, '-'); + tmp = -tmp; + } + k = tmp; + } else { + if ((signed long)n < 0) { + putchar(buf, '-'); + n = -n; + } + k = n; + } + } else { + k = n; + } + + if (k == 0) { + putchar(buf, '0'); + return; + } + + for (; k > 0; k /= 10) { + *p = k % 10 + '0'; + ++p; + } + for (--p;; --p) { + putchar(buf, *p); + if (p == tmpbuf) + break; + } +} + +void print_strz(struct iobuf *buf, char *s) +{ + for (; *s; ++s) + putchar(buf, *s); +} + +void print_str(struct iobuf *buf, struct str *s) +{ + char *tmp = s->start; + for (; tmp != s->end; ++tmp) + putchar(buf, *tmp); +} + +static void format(struct iobuf *buf, char c, va_list vl) +{ + switch(c) { + unsigned long arg; + case '%': + putchar(buf, '%'); + break; + case 'd': + case 'u': + arg = va_arg(vl, unsigned int); + print_int(buf, c == 'd', 1, arg); + break; + case 'D': + case 'U': + arg = va_arg(vl, unsigned long); + print_int(buf, c == 'D', 0, arg); + break; + case 's': + print_strz(buf, va_arg(vl, char*)); + break; + case 'S': + print_str(buf, va_arg(vl, struct str *)); + break; + case 'c': + arg = va_arg(vl, int); + putchar(buf, arg); + break; + default: + write(2, _S("printf: unexpected format option \n")); + hexit(2); + } +} + +static void __printf(struct iobuf *buf, char *s, va_list vl) +{ + for (; *s; ++s) { + if (*s == '%') { + if (s[1] == 0) { + write(2, _S("printf: nothing comes after '%'")); + hexit(2); + } + format(buf, s[1], vl); + ++s; + } else { + putchar(buf, *s); + } + } + return; +} + +void printf(char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + __printf(&stdout, fmt, vl); + va_end(vl); +} + +void evprintf(char *fmt, va_list vl) +{ + print_strz(&stderr, progname); + print_strz(&stderr, ": "); + __printf(&stderr, fmt, vl); +} + +void eprintf(char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + evprintf(fmt, vl); + va_end(vl); +} + +/* Memory management */ + +struct mem_buffer { + char *cur, *end; + char *saved; +}; + +static struct mem_buffer mem_buf; + +static void mem_buffer_init() +{ + mem_buf.cur = mem_buf.end = brk(NULL); + mem_buf.saved = NULL; +} + +void save_heap_offset() +{ + if (mem_buf.saved != NULL) { + eprintf("mem_buffer: offset already saved\n"); + hexit(2); + } + mem_buf.saved = mem_buf.cur; +} + +void restore_heap_offset() +{ + if (mem_buf.saved == NULL) { + eprintf("mem_buffer: no offset was saved\n"); + hexit(2); + } + mem_buf.cur = mem_buf.saved; + mem_buf.saved = NULL; +} + +static int get_alignment(int n) +{ + if (n >= 16) + return 16; + if (n >= 8) + return 8; + if (n >= 4) + return 4; + if (n >= 2) + return 2; + return 1; +} + +static void mem_buf_grow(int size) +{ + char *tmp; + if (size < 128*1024) { + size = 128*1024; + } else { + size *= 2; + size &= -4096; + } + /*printf("Growing (%d)\n", size);*/ + tmp = brk(mem_buf.end + size); + if (tmp == mem_buf.end) { + eprintf("mem_buf: unable to allocate memory\n"); + hexit(1); + } + mem_buf.end = tmp; +} + +#define ALIGN(v, align) \ + (void*)(((unsigned long)(v) + (align) - 1ul) & -(align)) + +void *malloc(int size) +{ + int align = get_alignment(size); + char *tmp = ALIGN(mem_buf.cur, align); + int diff = tmp + size - mem_buf.end; + + if (diff > 0) + mem_buf_grow(diff); + + mem_buf.cur = tmp + size; + return tmp; +} + +int main(int argc, char **argv, char **envp); + +void _start_c(unsigned long *p) +{ + int argc = p[0]; + char **argv = (void *)(p + 1); + char **envp = argv + argc + 1; + + progname = argv[0]; + mem_buffer_init(); + + hexit(main(argc, argv, envp)); +} |