summaryrefslogtreecommitdiff
path: root/src/user/knob/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/knob/format.c')
-rw-r--r--src/user/knob/format.c257
1 files changed, 220 insertions, 37 deletions
diff --git a/src/user/knob/format.c b/src/user/knob/format.c
index 593b20c..54d50ef 100644
--- a/src/user/knob/format.c
+++ b/src/user/knob/format.c
@@ -1,48 +1,231 @@
-#include <stdbool.h>
-#include <stdint.h>
-
-bool try_sntoi(const char *s, uint32_t n, uint32_t *out) {
- uint32_t calc = 0;
- for (uint32_t i = 0; i < n; ++i) {
- if ((s[i] < '0') || (s[i] > '9'))
- return false;
- calc = calc * 10 + s[i] - '0';
- }
- *out = calc;
- return true;
-}
+#include <knob/block.h>
+#include <knob/panic.h>
+#include <knob/heap.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
+
+#include <stdarg.h>
+
+#define FORMAT_BUF_INIT_SIZE 200
+#define FORMAT_BUF_CHUNK_SIZE 50
-__attribute__ ((access (write_only, 2)))
-void itosz(uint32_t i, char *out) {
- if (!i) {
- *(uint16_t *)out = (uint16_t)'0';
+#define BAD_SPEC "%%UNKNOWN FORMAT SPEC%%"
+#define BAD_SPEC_LEN 23
+
+static char *buf;
+static uint32_t buf_s;
+static char *buf_i;
+
+static const char *const hextab = "0123456789abcdef";
+
+static void ensure(uint32_t extra) {
+ const uint32_t total_len = buf_i - buf + extra;
+ if (total_len < buf_s)
return;
+
+ buf_s = (total_len / FORMAT_BUF_CHUNK_SIZE + 1) * FORMAT_BUF_CHUNK_SIZE;
+
+ char *const new_buf = get_block(buf_s);
+ if (!new_buf)
+ PANIC("out of memory in knob format");
+ blockcpy(new_buf, buf, buf_i - buf);
+ free_block(buf);
+ buf_i += new_buf - buf;
+ buf = new_buf;
+}
+
+struct format_spec {
+ uint32_t len;
+ enum {
+ UNKNOWN,
+ CHAR,
+ STRING,
+ UNSIGNED_DECIMAL,
+ HEXADECIMAL
+ //TODO: signed decimal
+ } kind;
+};
+
+static const char *get_format(const char *from, struct format_spec *format_out) {
+ if (*from == 'n') {
+ ++from;
+ format_out->len = -1;
}
- bool zero = false;
- for (uint32_t m = 1000000000; m; m /= 10) {
- uint8_t d = (i / m) % 10;
- if (zero)
- *(out++) = d + '0';
- else if (d) {
- zero = true;
- *(out++) = d + '0';
+ else {
+ uint32_t len = 0;
+ while ((*from >= '0') && (*from <= '9'))
+ len = len * 10 + *(from++) - '0';
+ format_out->len = len;
+ }
+
+ switch (*from) {
+ case 'c':
+ format_out->kind = CHAR;
+ break;
+ case 's':
+ format_out->kind = STRING;
+ break;
+ case 'u':
+ format_out->kind = UNSIGNED_DECIMAL;
+ break;
+ case 'h':
+ case 'x':
+ format_out->kind = HEXADECIMAL;
+ break;
+ default:
+ format_out->kind = UNKNOWN;
+ break;
+ }
+
+ return from + 1;
+}
+
+//allocates new memory
+char *format_v(const char *fmt, va_list args) {
+ buf = get_block(FORMAT_BUF_INIT_SIZE);
+ if (!buf)
+ PANIC("out of memory in knob format");
+ buf_s = FORMAT_BUF_INIT_SIZE;
+ buf_i = buf;
+
+ while (*fmt) {
+ if (*fmt != '%') {
+ ensure(1);
+ *(buf_i++) = *(fmt++);
+ }
+ else if (fmt[1] == '%') {
+ ensure(1);
+ *(buf_i++) = '%';
+ fmt += 2;
+ }
+ else {
+ struct format_spec form;
+ fmt = get_format(fmt + 1, &form);
+ if (form.len == -1)
+ //should passing zero still have the special meaning?
+ form.len = va_arg(args, uint32_t);
+ switch (form.kind) {
+ case UNKNOWN:
+ ensure(BAD_SPEC_LEN);
+ blockcpy(buf_i, BAD_SPEC, BAD_SPEC_LEN);
+ buf_i += BAD_SPEC_LEN;
+ continue;
+
+ uint32_t ch;
+ case CHAR:
+ ch = va_arg(args, uint32_t);
+ ensure(1);
+ *(buf_i++) = (char)ch;
+ continue;
+
+ const char *str;
+ case STRING:
+ str = va_arg(args, const char *);
+ if (!form.len)
+ form.len = strlen(str);
+ ensure(form.len);
+ blockcpy(buf_i, str, form.len);
+ buf_i += form.len;
+ continue;
+
+ uint32_t k;
+ case UNSIGNED_DECIMAL:
+ k = va_arg(args, uint32_t);
+ if (!form.len) {
+ uint32_t n = 10;
+ ++form.len;
+ while (k >= n) {
+ ++form.len;
+ n *= 10;
+ }
+ }
+ ensure(form.len);
+ const uint32_t len_backup = form.len;
+ while (form.len--) {
+ buf_i[form.len] = (k % 10) + '0';
+ k /= 10;
+ }
+ buf_i += len_backup;
+ continue;
+
+ case HEXADECIMAL:
+ k = va_arg(args, uint32_t);
+ if (!form.len)
+ form.len = 8;
+ ensure(form.len);
+ const uint32_t hlen_backup = form.len;
+ while (form.len--) {
+ buf_i[form.len] = hextab[k % 16];
+ k >>= 4;
+ }
+ buf_i += hlen_backup;
+ continue;
+ }
}
}
- *out = '\0';
+
+ *buf_i = '\0';
+ return buf;
+}
+
+//allocates new memory
+char *format(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ char *const res = format_v(fmt, args);
+ va_end(args);
+ return res;
+}
+
+void syslogf_v(const char *fmt, va_list args) {
+ char *const msg = format_v(fmt, args);
+ _system_log(msg);
+ free_block(msg);
}
-const char *const hex_digits = "0123456789abcdef";
+void syslogf(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ syslogf_v(fmt, args);
+ va_end(args);
+}
-__attribute__ ((access (write_only, 2)))
-void itosz_h8(uint8_t i, char *out) {
- out[0] = hex_digits[i >> 4];
- out[1] = hex_digits[i & 0xf];
- out[2] = '\0';
+//reads a unsigned decimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtou(const char *from, uint32_t *i_out) {
+ const char *const old_from = from;
+ uint32_t v = 0;
+ while (*from && (*from != '\n') && (*from != ' ')) {
+ if ((*from < '0') || (*from > '9'))
+ return 0;
+ v = v * 10 + *(from++) - '0';
+ }
+ *i_out = v;
+ while ((*from == '\n') || (*from == ' '))
+ ++from;
+ return from - old_from;
}
-__attribute__ ((access (write_only, 2)))
-void itosz_h32(uint32_t i, char *out) {
- for (uint8_t digit = 0; digit < 8; ++digit)
- out[digit] = hex_digits[(i >> (28 - digit * 4)) & 0xf];
- out[8] = '\0';
+//reads a hexadecimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtoh(const char *from, uint32_t *i_out) {
+ const char *const old_from = from;
+ uint32_t v = 0;
+ while (*from && (*from != '\n') && (*from != ' ')) {
+ if ((*from >= '0') && (*from <= '9'))
+ v = v * 16 + *(from++) - '0';
+ else if ((*from >= 'a') && (*from <= 'f'))
+ v = v * 16 + *(from++) - 'a' + 10;
+ else if ((*from >= 'A') && (*from <= 'F'))
+ v = v * 16 + *(from++) - 'A' + 10;
+ else
+ return 0;
+ }
+ *i_out = v;
+ while ((*from == '\n') || (*from == ' '))
+ ++from;
+ return from - old_from;
} \ No newline at end of file