summaryrefslogtreecommitdiff
path: root/05/util.b
diff options
context:
space:
mode:
Diffstat (limited to '05/util.b')
-rw-r--r--05/util.b357
1 files changed, 357 insertions, 0 deletions
diff --git a/05/util.b b/05/util.b
new file mode 100644
index 0000000..13fed4d
--- /dev/null
+++ b/05/util.b
@@ -0,0 +1,357 @@
+
+function file_error
+ argument name
+ fputs(2, .str_file_error)
+ fputs(2, name)
+ fputc(2, 10)
+ exit(1)
+
+:str_file_error
+ string Error opening file:
+ byte 32
+ byte 0
+
+function malloc
+ argument size
+ local total_size
+ local memory
+ total_size = size + 8
+ memory = syscall(9, 0, total_size, 3, 0x22, -1, 0)
+ if memory ] 0xffffffffffff0000 goto malloc_failed
+ *8memory = total_size
+ return memory + 8
+
+:malloc_failed
+ fputs(2, .str_out_of_memory)
+ exit(1)
+
+:str_out_of_memory
+ string Out of memory.
+ byte 10
+ byte 0
+
+function free
+ argument memory
+ local psize
+ local size
+ psize = memory - 8
+ size = *8psize
+ syscall(11, psize, size)
+ return
+
+; returns a pointer to a null-terminated string containing the number given
+function itos
+ global 32 itos_string
+ argument x
+ local c
+ local p
+ p = &itos_string
+ p += 30
+ :itos_loop
+ c = x % 10
+ c += '0
+ *1p = c
+ x /= 10
+ if x == 0 goto itos_loop_end
+ p -= 1
+ goto itos_loop
+ :itos_loop_end
+ return p
+
+
+; returns the number at the start of the given string
+function stoi
+ argument s
+ local p
+ local n
+ local c
+ n = 0
+ p = s
+ :stoi_loop
+ c = *1p
+ if c < '0 goto stoi_loop_end
+ if c > '9 goto stoi_loop_end
+ n *= 10
+ n += c - '0
+ p += 1
+ goto stoi_loop
+ :stoi_loop_end
+ return n
+
+function memchr
+ argument mem
+ argument c
+ local p
+ local a
+ p = mem
+ :memchr_loop
+ a = *1p
+ if a == c goto memchr_loop_end
+ p += 1
+ goto memchr_loop
+ :memchr_loop_end
+ return p
+
+function strlen
+ argument s
+ local c
+ local p
+ p = s
+ :strlen_loop
+ c = *1p
+ if c == 0 goto strlen_loop_end
+ p += 1
+ goto strlen_loop
+ :strlen_loop_end
+ return p - s
+
+function strcpy
+ argument dest
+ argument src
+ local p
+ local q
+ local c
+ p = dest
+ q = src
+ :strcpy_loop
+ c = *1q
+ *1p = c
+ if c == 0 goto strcpy_loop_end
+ p += 1
+ q += 1
+ goto strcpy_loop
+ :strcpy_loop_end
+ return p
+
+function str_startswith
+ argument s
+ argument prefix
+ local p
+ local q
+ local c1
+ local c2
+ p = s
+ q = prefix
+ :str_startswith_loop
+ c1 = *1p
+ c2 = *1q
+ if c2 == 0 goto return_1
+ if c1 != c2 goto return_0
+ p += 1
+ q += 1
+ goto str_startswith_loop
+
+function fputs
+ argument fd
+ argument s
+ local length
+ length = strlen(s)
+ syscall(1, fd, s, length)
+ return
+
+function puts
+ argument s
+ fputs(1, s)
+ return
+
+function fputn
+ argument fd
+ argument n
+ local s
+ s = itos(n)
+ fputs(fd, s)
+ return
+
+function fputc
+ argument fd
+ argument c
+ local p
+ p = &c
+ syscall(1, fd, p, 1)
+ return
+
+function putc
+ argument c
+ fputc(1, c)
+ return
+
+; returns 0 at end of file
+function fgetc
+ argument fd
+ local c
+ local p
+ c = 0
+ p = &c
+ syscall(0, fd, p, 1)
+ return c
+
+; read a line from fd as a null-terminated string
+; returns 0 at end of file, 1 otherwise
+function fgets
+ argument fd
+ argument buf
+ argument size
+ local p
+ local end
+ local c
+ p = buf
+ end = buf + size
+
+ :fgets_loop
+ c = fgetc(fd)
+ if c == 0 goto fgets_eof
+ if c == 10 goto fgets_eol
+ *1p = c
+ p += 1
+ if p == end goto fgets_eob
+ goto fgets_loop
+
+ :fgets_eol ; end of line
+ *1p = 0
+ return 1
+ :fgets_eof ; end of file
+ *1p = 0
+ return 0
+ :fgets_eob ; end of buffer
+ p -= 1
+ *1p = 0
+ return 1
+
+; open the given file for reading
+function open_r
+ argument filename
+ local fd
+ fd = syscall(2, filename, 0)
+ if fd < 0 goto open_r_error
+ return fd
+ :open_r_error
+ file_error(filename)
+ return -1
+
+; open the given file for writing with the given mode
+function open_w
+ argument filename
+ argument mode
+ local fd
+ fd = syscall(2, filename, 0x241, mode)
+ if fd < 0 goto open_w_error
+ return fd
+ :open_w_error
+ file_error(filename)
+ return -1
+
+function close
+ argument fd
+ syscall(3, fd)
+ return
+
+function isupper
+ argument c
+ if c < 'A goto return_0
+ if c <= 'Z goto return_1
+ goto return_0
+
+function exit
+ argument status_code
+ syscall(0x3c, status_code)
+
+:return_0
+ return 0
+:return_1
+ return 1
+
+function syscall
+ ; I've done some testing, and this should be okay even if
+ ; rbp-56 goes beyond the end of the stack.
+ ; mov rax, [rbp-16]
+ byte 0x48
+ byte 0x8b
+ byte 0x85
+ byte 0xf0
+ byte 0xff
+ byte 0xff
+ byte 0xff
+ ; mov rdi, rax
+ byte 0x48
+ byte 0x89
+ byte 0xc7
+
+ ; mov rax, [rbp-24]
+ byte 0x48
+ byte 0x8b
+ byte 0x85
+ byte 0xe8
+ byte 0xff
+ byte 0xff
+ byte 0xff
+ ; mov rsi, rax
+ byte 0x48
+ byte 0x89
+ byte 0xc6
+
+ ; mov rax, [rbp-32]
+ byte 0x48
+ byte 0x8b
+ byte 0x85
+ byte 0xe0
+ byte 0xff
+ byte 0xff
+ byte 0xff
+ ; mov rdx, rax
+ byte 0x48
+ byte 0x89
+ byte 0xc2
+
+ ; mov rax, [rbp-40]
+ byte 0x48
+ byte 0x8b
+ byte 0x85
+ byte 0xd8
+ byte 0xff
+ byte 0xff
+ byte 0xff
+ ; mov r10, rax
+ byte 0x49
+ byte 0x89
+ byte 0xc2
+
+ ; mov rax, [rbp-48]
+ byte 0x48
+ byte 0x8b
+ byte 0x85
+ byte 0xd0
+ byte 0xff
+ byte 0xff
+ byte 0xff
+ ; mov r8, rax
+ byte 0x49
+ byte 0x89
+ byte 0xc0
+
+ ; mov rax, [rbp-56]
+ byte 0x48
+ byte 0x8b
+ byte 0x85
+ byte 0xc8
+ byte 0xff
+ byte 0xff
+ byte 0xff
+ ; mov r9, rax
+ byte 0x49
+ byte 0x89
+ byte 0xc1
+
+ ; mov rax, [rbp-8]
+ byte 0x48
+ byte 0x8b
+ byte 0x85
+ byte 0xf8
+ byte 0xff
+ byte 0xff
+ byte 0xff
+
+ ; syscall
+ byte 0x0f
+ byte 0x05
+
+ return