aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/error.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/error.c')
-rw-r--r--src/common/error.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/common/error.c b/src/common/error.c
new file mode 100644
index 0000000..dbc1d81
--- /dev/null
+++ b/src/common/error.c
@@ -0,0 +1,111 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "error.h"
+#include "utils.h"
+
+
+bc_error_t*
+bc_error_new(int type, const char *msg)
+{
+ bc_error_t *err = bc_malloc(sizeof(bc_error_t));
+ err->type = type;
+ err->msg = bc_strdup(msg);
+ return err;
+}
+
+
+bc_error_t*
+bc_error_new_printf(int type, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *tmp = bc_strdup_vprintf(format, ap);
+ va_end(ap);
+ bc_error_t *rv = bc_error_new(type, tmp);
+ free(tmp);
+ return rv;
+}
+
+
+bc_error_t*
+bc_error_parser(int type, const char *src, size_t src_len,
+ size_t current, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char *msg = bc_strdup_vprintf(format, ap);
+ va_end(ap);
+
+ size_t lineno = 1;
+ size_t linestart = 0;
+ size_t lineend = 0;
+ size_t pos = 1;
+
+ for (size_t i = 0; i < src_len; i++) {
+ char c = src[i];
+ if (i < current) {
+ if ((i + 1) < src_len) {
+ if ((c == '\n' && src[i + 1] == '\r') ||
+ (c == '\r' && src[i + 1] == '\n'))
+ {
+ lineno++;
+ i++;
+ pos = 1;
+ if ((i + 1) < src_len)
+ linestart = i + 1;
+ continue;
+ }
+ }
+ if (c == '\n' || c == '\r') {
+ lineno++;
+ pos = 1;
+ if ((i + 1) < src_len)
+ linestart = i + 1;
+ continue;
+ }
+ pos++;
+ }
+ else if (c == '\n' || c == '\r') {
+ lineend = i;
+ break;
+ }
+ }
+
+ if (lineend <= linestart && src_len >= linestart)
+ lineend = src_len;
+
+ char *line = bc_strndup(src + linestart, lineend - linestart);
+
+ bc_error_t *rv = NULL;
+
+ if (line[0] == '\0') // "near" message isn't useful if line is empty
+ rv = bc_error_new(type, msg);
+ else
+ rv = bc_error_new_printf(type,
+ "%s\nError occurred near line %d, position %d: %s", msg, lineno,
+ pos, line);
+
+ free(msg);
+ free(line);
+
+ return rv;
+}
+
+
+void
+bc_error_free(bc_error_t *err)
+{
+ if (err == NULL)
+ return;
+ free(err->msg);
+ free(err);
+}