summaryrefslogtreecommitdiff
path: root/src/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils.c')
-rw-r--r--src/utils.c137
1 files changed, 106 insertions, 31 deletions
diff --git a/src/utils.c b/src/utils.c
index 5f9d49e..7f2831b 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,41 +1,116 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
#include <lcq/pit/utils.h>
-void pit_panic(const char *format, ...) {
- va_list vargs;
- va_start(vargs, format);
- vfprintf(stderr, format, vargs);
- va_end(vargs);
- exit(1);
-}
-
-void pit_debug(const char *format, ...) {
- va_list vargs;
- va_start(vargs, format);
- vfprintf(stderr, format, vargs);
- va_end(vargs);
+enum vsnprintf_mode {
+ VSNPRINTF_MODE_NORMAL,
+ VSNPRINTF_MODE_FLAGS,
+ VSNPRINTF_MODE_WIDTH,
+ VSNPRINTF_MODE_PRECISION,
+ VSNPRINTF_MODE_LENGTH_MOD,
+ VSNPRINTF_MODE_CONVERSION_SPEC
+};
+#define SCRATCH_LEN 256
+#define WRITE(c) { buf[idx++] = c; if (idx >= len - 1) goto done; }
+#define WRITE_SCRATCH(c) { scratch[sidx++] = c; if (sidx >= SCRATCH_LEN) goto error; }
+int pit_string_vsnprintf(char *buf, size_t len, char *format, va_list ap) {
+ // vsnprintf
+ size_t idx = 0;
+ size_t flen = pit_string_strlen(format);
+ size_t fidx = 0;
+ enum vsnprintf_mode mode = VSNPRINTF_MODE_NORMAL;
+ size_t sidx = 0;
+ char scratch[SCRATCH_LEN] = {0};
+ char length_mod = 0;
+ for (; fidx < flen && idx < len - 1; ++fidx) {
+ char c = format[fidx];
+ sidx = 0;
+ switch (mode) {
+ case VSNPRINTF_MODE_NORMAL:
+ if (c == '%') {
+ mode = VSNPRINTF_MODE_FLAGS;
+ } else WRITE(c);
+ break;
+ case VSNPRINTF_MODE_FLAGS:
+ case VSNPRINTF_MODE_WIDTH:
+ case VSNPRINTF_MODE_PRECISION:
+ case VSNPRINTF_MODE_LENGTH_MOD:
+ switch (c) {
+ case 'l': length_mod = 'l'; mode = VSNPRINTF_MODE_CONVERSION_SPEC; continue;
+ }
+ // fallthrough
+ case VSNPRINTF_MODE_CONVERSION_SPEC:
+ switch (c) {
+ case '%': WRITE('%'); mode = VSNPRINTF_MODE_NORMAL; break;
+ case 'd': {
+ long arg = 0;
+ if (length_mod == 'l') arg = va_arg(ap, long); else arg = va_arg(ap, int);
+ if (arg == 0) { WRITE('0') }
+ else {
+ while (arg != 0) { WRITE_SCRATCH('0' + (char) (arg % 10)); arg /= 10; }
+ while (sidx > 0) { WRITE(scratch[sidx - 1]); sidx -= 1; }
+ }
+ mode = VSNPRINTF_MODE_NORMAL;
+ break;
+ }
+ case 'f': {
+ double arg = 0.0;
+ if (length_mod == 'l')
+ arg = va_arg(ap, double);
+ else
+ arg = va_arg(ap, double);
+ long wholepart = (long) arg;
+ double fracpart = arg - (double) wholepart;
+ if (wholepart == 0) { WRITE('0') }
+ else {
+ while (wholepart != 0) { WRITE_SCRATCH('0' + (char) (wholepart % 10)); wholepart /= 10; }
+ while (sidx > 0) { WRITE(scratch[sidx - 1]); sidx -= 1; }
+ }
+ WRITE('.');
+ for (int i = 0; i < 6; ++i) {
+ fracpart *= 10.0;
+ wholepart = (long) fracpart;
+ fracpart -= (double) wholepart;
+ WRITE('0' + (char) wholepart);
+ }
+ mode = VSNPRINTF_MODE_NORMAL;
+ break;
+ }
+ case 's': {
+ char *arg = va_arg(ap, char *);
+ while (*arg != 0) { WRITE(*arg); arg += 1; }
+ mode = VSNPRINTF_MODE_NORMAL;
+ break;
+ }
+ default: goto error;
+ }
+ break;
+ }
+ }
+done:
+ buf[idx] = 0;
+ return (int) idx;
+error:
+ return -1;
}
-
-static uintptr_t pit_align_down(uintptr_t addr, uintptr_t align) {
- return addr & ~(align - 1); /* easy! just zero the low bits */
-}
-static uintptr_t pit_align_up(uintptr_t addr, uintptr_t align) {
- return (addr + align - 1) /* increment past the next aligned address... */
- & ~(align - 1); /* ...and then zero the low bits */
+int pit_string_snprintf(char *buf, size_t len, char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ int ret = pit_string_vsnprintf(buf, len, format, ap);
+ va_end(ap);
+ return ret;
}
-pit_arena *pit_arena_new(i64 capacity, i64 elem_size) {
- i64 byte_len = 0;
- pit_mul(&byte_len, elem_size, capacity);
- pit_arena *a = (pit_arena *) malloc(sizeof(pit_arena) + (size_t) byte_len);
- if (!a || byte_len <= 0) return NULL;
+pit_arena *pit_arena_new(u8 *buf, i64 buf_len, i64 elem_size) {
+ uintptr_t base = (uintptr_t) buf;
+ uintptr_t aligned = pit_align_up(base, sizeof(void *));
+ pit_arena *a = (pit_arena *) aligned;
+ uintptr_t data = aligned + sizeof(pit_arena);
+ i64 offset = (i64) data - (i64) base;
+ i64 remaining = (i64) pit_align_down((uintptr_t) (buf_len - offset), sizeof(void *));
+ if (!a || remaining <= 0) return NULL;
a->elem_size = elem_size;
- a->capacity = byte_len / elem_size;
+ a->capacity = remaining / elem_size;
a->next = 0;
- a->back = byte_len;
+ a->back = remaining;
return a;
}
void pit_arena_reset(pit_arena *a) {