summaryrefslogtreecommitdiffhomepage
path: root/lib.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-08-24 12:37:54 +0200
committerJo-Philipp Wich <jo@mein.io>2020-08-25 20:38:10 +0200
commitd86c9ab4c1c7b25cd942c4656626e2feca318857 (patch)
tree280f238450de50e58fe40675b88754f9b2f71eab /lib.c
parent765b2f9298d8030b459f53f21d03d00b87ef7310 (diff)
main.c, lib.c: move error formatting logic to lib.c
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/lib.c b/lib.c
index 30b7574..39238ed 100644
--- a/lib.c
+++ b/lib.c
@@ -31,6 +31,186 @@
#include <sys/time.h>
+static bool
+snprintf_append(char **dptr, size_t *dlen, const char *fmt, ssize_t sz, ...)
+{
+ va_list ap;
+ char *tmp;
+ int n;
+
+ va_start(ap, sz);
+ n = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ if (n < 0)
+ return false;
+ else if (sz >= 0 && n > sz)
+ n = sz;
+
+ tmp = realloc(*dptr, *dlen + n + 1);
+
+ if (!tmp)
+ return false;
+
+ va_start(ap, sz);
+ vsnprintf(tmp + *dlen, n + 1, fmt, ap);
+ va_end(ap);
+
+ *dptr = tmp;
+ *dlen += n;
+
+ return true;
+}
+
+#define sprintf_append(dptr, dlen, fmt, ...) \
+ snprintf_append(dptr, dlen, fmt, -1, ##__VA_ARGS__)
+
+static void
+format_error_context(char **msg, size_t *msglen, const char *expr, size_t off)
+{
+ int eoff, eline, padlen;
+ const char *p, *nl;
+ int i;
+
+ /* skip lines until error line */
+ for (p = nl = expr, eline = 0; *p && p < expr + off; p++) {
+ if (*p == '\n') {
+ nl = p + 1;
+ eline++;
+ }
+ }
+
+ eoff = p - nl;
+
+ sprintf_append(msg, msglen, "In line %u, byte %d:\n\n `", eline + 1, eoff);
+
+ for (p = nl, padlen = 0; *p != '\n' && *p != '\0'; p++) {
+ switch (*p) {
+ case '\t':
+ sprintf_append(msg, msglen, " ");
+ if (p < nl + eoff)
+ padlen += 4;
+ break;
+
+ case '\r':
+ case '\v':
+ sprintf_append(msg, msglen, " ");
+ if (p < nl + eoff)
+ padlen++;
+ break;
+
+ default:
+ sprintf_append(msg, msglen, "%c", *p);
+ if (p < nl + eoff)
+ padlen++;
+ }
+ }
+
+ sprintf_append(msg, msglen, "`\n ");
+
+ if (padlen < strlen("Near here ^")) {
+ for (i = 0; i < padlen; i++)
+ sprintf_append(msg, msglen, " ");
+
+ sprintf_append(msg, msglen, "^-- Near here\n");
+ }
+ else {
+ sprintf_append(msg, msglen, "Near here ");
+
+ for (i = strlen("Near here "); i < padlen; i++)
+ sprintf_append(msg, msglen, "-");
+
+ sprintf_append(msg, msglen, "^\n");
+ }
+
+ sprintf_append(msg, msglen, "\n");
+}
+
+char *
+ut_format_error(struct ut_state *state, const char *expr)
+{
+ size_t off = state ? state->off : 0;
+ struct ut_opcode *tag;
+ bool first = true;
+ size_t msglen = 0;
+ char *msg = NULL;
+ int i, max_i;
+
+ switch (state ? state->error.code : UT_ERROR_OUT_OF_MEMORY) {
+ case UT_ERROR_NO_ERROR:
+ return NULL;
+
+ case UT_ERROR_OUT_OF_MEMORY:
+ sprintf_append(&msg, &msglen, "Runtime error: Out of memory\n");
+ break;
+
+ case UT_ERROR_UNTERMINATED_COMMENT:
+ sprintf_append(&msg, &msglen, "Syntax error: Unterminated comment\n");
+ break;
+
+ case UT_ERROR_UNTERMINATED_STRING:
+ sprintf_append(&msg, &msglen, "Syntax error: Unterminated string\n");
+ break;
+
+ case UT_ERROR_UNTERMINATED_BLOCK:
+ sprintf_append(&msg, &msglen, "Syntax error: Unterminated template block\n");
+ break;
+
+ case UT_ERROR_UNEXPECTED_CHAR:
+ sprintf_append(&msg, &msglen, "Syntax error: Unexpected character\n");
+ break;
+
+ case UT_ERROR_OVERLONG_STRING:
+ sprintf_append(&msg, &msglen, "Syntax error: String or label literal too long\n");
+ break;
+
+ case UT_ERROR_INVALID_ESCAPE:
+ sprintf_append(&msg, &msglen, "Syntax error: Invalid escape sequence\n");
+ break;
+
+ case UT_ERROR_NESTED_BLOCKS:
+ sprintf_append(&msg, &msglen, "Syntax error: Template blocks may not be nested\n");
+ break;
+
+ case UT_ERROR_UNEXPECTED_TOKEN:
+ sprintf_append(&msg, &msglen, "Syntax error: Unexpected token\n");
+
+ for (i = 0, max_i = 0; i < sizeof(state->error.info.tokens) * 8; i++)
+ if ((state->error.info.tokens[i / 64] & ((unsigned)1 << (i % 64))) && tokennames[i])
+ max_i = i;
+
+ for (i = 0; i < sizeof(state->error.info.tokens) * 8; i++) {
+ if ((state->error.info.tokens[i / 64] & ((unsigned)1 << (i % 64))) && tokennames[i]) {
+ if (first) {
+ sprintf_append(&msg, &msglen, "Expecting %s", tokennames[i]);
+ first = false;
+ }
+ else if (i < max_i) {
+ sprintf_append(&msg, &msglen, ", %s", tokennames[i]);
+ }
+ else {
+ sprintf_append(&msg, &msglen, " or %s", tokennames[i]);
+ }
+ }
+ }
+
+ sprintf_append(&msg, &msglen, "\n");
+ break;
+
+ case UT_ERROR_EXCEPTION:
+ tag = json_object_get_userdata(state->error.info.exception);
+ off = (tag && tag->operand[0]) ? tag->operand[0]->off : 0;
+
+ sprintf_append(&msg, &msglen, "%s\n", json_object_get_string(state->error.info.exception));
+ break;
+ }
+
+ if (off)
+ format_error_context(&msg, &msglen, expr, off);
+
+ return msg;
+}
+
static double
ut_cast_double(struct json_object *v)
{