/* * Minimal bootstrap RTL (runtime library) - Message reporting. * * Copyright © 2025 Samuel Lidén Borell * * SPDX-License-Identifier: EUPL-1.2+ OR LGPL-2.1-or-later */ #include #include #include #include #include "rtl.h" #include "internal.h" enum MessageArgKind { MAK_INT }; struct MessageArg { enum MessageArgKind kind; union { SlulInt i; } u; }; struct MessageReporter { const struct String *format; int num_args, args_left; struct MessageArg *args, *nextarg; }; void MessageReporter__giveme(struct MessageReporter **mr_ptr) { struct MessageReporter *mr = malloc(sizeof(struct MessageReporter)); OOM_CHECK(mr); mr->format = NULL; *mr_ptr = mr; } void MessageReporter_begin_message( struct MessageReporter *mr, const struct String *format) { const unsigned char *fmt; SlulInt fmtlen; int num_args; struct MessageArg *args; mr->format = format; /* Silly parsing of format string. Placeholders have {} syntax */ fmt = SLUL__decode_string(format, &fmtlen); num_args = 0; while (fmtlen) { if (*fmt == '{') num_args++; fmt++; fmtlen--; } mr->num_args = mr->args_left = num_args; args = calloc((size_t)num_args, sizeof(struct MessageArg)); OOM_CHECK(args); mr->args = mr->nextarg = args; } void MessageReporter_add_int( struct MessageReporter *mr, SlulInt number) { CHECK(mr->args_left > 0, "more arguments than {}'s"); mr->nextarg->kind = MAK_INT; mr->nextarg->u.i = number; mr->nextarg++; mr->args_left--; } void MessageReporter_report(struct MessageReporter *mr) { const struct MessageArg *arg; int argsleft; SlulInt max_size, charsleft; const unsigned char *fmt; unsigned char *buff, *bp; assert(mr->format != NULL); assert(mr->args_left == 0); fmt = SLUL__decode_string(mr->format, &charsleft); CHECK(charsleft < SLUL_INT_MAX, "integer overflow"); max_size = charsleft + 1; /* Determine max size */ argsleft = mr->num_args; arg = mr->args; while (argsleft) { switch (arg->kind) { case MAK_INT: CHECK(max_size <= SLUL_INT_MAX-11, "integer overflow"); max_size += 11; break; default: assert(0); } arg++; argsleft--; } /* Format */ buff = malloc(max_size); OOM_CHECK(buff); bp = buff; arg = mr->args; while (charsleft) { unsigned char c = *fmt; if (c != '{') { *(bp++) = c; } else if (charsleft > 0) { switch (arg->kind) { case MAK_INT: { SlulInt num = arg->u.i; if (num == 0) { *(bp++) = '0'; } else { unsigned char *start = bp, *end; while (num != 0) { *(bp++) = '0' + (unsigned char)(num % 10); num /= 10; } end = bp-1; while (start < end) { unsigned char tmp = *start; *(start++) = *end; *(end--) = tmp; } } break; } } fmt++; charsleft--; } else { FAIL("no character after `{`"); } fmt++; charsleft--; } *bp = '\0'; /* Print */ /* TODO errors/warnings should go to stderr */ puts((const char *)buff); free(buff); }