aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/error.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/error.c')
-rw-r--r--src/error.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/error.c b/src/error.c
new file mode 100644
index 0000000..6a0e10f
--- /dev/null
+++ b/src/error.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2012-2021 Robin Haberkorn
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "sciteco.h"
+#include "string-utils.h"
+#include "interface.h"
+#include "list.h"
+#include "error.h"
+
+guint teco_error_return_args = 0;
+
+/*
+ * FIXME: Does this have to be stored in teco_machine_main_t?
+ * Probably becomes clear once we implement error handling by macros.
+ */
+guint teco_error_pos = 0, teco_error_line = 0, teco_error_column = 0;
+
+void
+teco_error_set_coord(const gchar *str, guint pos)
+{
+ teco_error_pos = pos;
+ teco_string_get_coord(str, pos, &teco_error_line, &teco_error_column);
+}
+
+typedef enum {
+ TECO_FRAME_QREG,
+ TECO_FRAME_FILE,
+ TECO_FRAME_EDHOOK,
+ TECO_FRAME_TOPLEVEL
+} teco_frame_type_t;
+
+typedef struct teco_frame_t {
+ teco_stailq_entry_t entry;
+
+ teco_frame_type_t type;
+
+ guint pos, line, column;
+
+ /*
+ * NOTE: This is currently sufficient to describe all
+ * frame types. Otherwise, add an union.
+ */
+ gchar name[];
+} teco_frame_t;
+
+/**
+ * List of teco_frame_t describing the stack frames.
+ *
+ * Stack frames are collected deliberately unformatted
+ * since there are future applications where displaying
+ * a stack frame will not be necessary (e.g. error handled
+ * by SciTECO macro).
+ * Preformatting all stack frames would be very costly.
+ */
+static teco_stailq_head_t teco_frames = TECO_STAILQ_HEAD_INITIALIZER(&teco_frames);
+
+void
+teco_error_display_short(const GError *error)
+{
+ teco_interface_msg(TECO_MSG_ERROR, "%s (at %d)",
+ error->message, teco_error_pos);
+}
+
+void
+teco_error_display_full(const GError *error)
+{
+ teco_interface_msg(TECO_MSG_ERROR, "%s", error->message);
+
+ guint nr = 0;
+
+ for (teco_stailq_entry_t *cur = teco_frames.first; cur != NULL; cur = cur->next) {
+ teco_frame_t *frame = (teco_frame_t *)cur;
+
+ switch (frame->type) {
+ case TECO_FRAME_QREG:
+ teco_interface_msg(TECO_MSG_INFO,
+ "#%d in Q-Register \"%s\" at %d (%d:%d)",
+ nr, frame->name, frame->pos, frame->line, frame->column);
+ break;
+ case TECO_FRAME_FILE:
+ teco_interface_msg(TECO_MSG_INFO,
+ "#%d in file \"%s\" at %d (%d:%d)",
+ nr, frame->name, frame->pos, frame->line, frame->column);
+ break;
+ case TECO_FRAME_EDHOOK:
+ teco_interface_msg(TECO_MSG_INFO,
+ "#%d in \"%s\" hook execution",
+ nr, frame->name);
+ break;
+ case TECO_FRAME_TOPLEVEL:
+ teco_interface_msg(TECO_MSG_INFO,
+ "#%d in toplevel macro at %d (%d:%d)",
+ nr, frame->pos, frame->line, frame->column);
+ break;
+ }
+
+ nr++;
+ }
+}
+
+static teco_frame_t *
+teco_error_add_frame(teco_frame_type_t type, gsize size)
+{
+ teco_frame_t *frame = g_malloc(sizeof(teco_frame_t) + size);
+ frame->type = type;
+ frame->pos = teco_error_pos;
+ frame->line = teco_error_line;
+ frame->column = teco_error_column;
+ teco_stailq_insert_tail(&teco_frames, &frame->entry);
+
+ return frame;
+}
+
+void
+teco_error_add_frame_qreg(const gchar *name, gsize len)
+{
+ g_autofree gchar *name_printable = teco_string_echo(name, len);
+ teco_frame_t *frame = teco_error_add_frame(TECO_FRAME_QREG, strlen(name_printable) + 1);
+ strcpy(frame->name, name_printable);
+}
+
+void
+teco_error_add_frame_file(const gchar *name)
+{
+ teco_frame_t *frame = teco_error_add_frame(TECO_FRAME_FILE, strlen(name) + 1);
+ strcpy(frame->name, name);
+}
+
+void
+teco_error_add_frame_edhook(const gchar *type)
+{
+ teco_frame_t *frame = teco_error_add_frame(TECO_FRAME_EDHOOK, strlen(type) + 1);
+ strcpy(frame->name, type);
+}
+
+void
+teco_error_add_frame_toplevel(void)
+{
+ teco_error_add_frame(TECO_FRAME_TOPLEVEL, 0);
+}
+
+#ifndef NDEBUG
+__attribute__((destructor))
+#endif
+void
+teco_error_clear_frames(void)
+{
+ teco_stailq_entry_t *entry;
+ while ((entry = teco_stailq_remove_head(&teco_frames)))
+ g_free(entry);
+}