summaryrefslogtreecommitdiffhomepage
path: root/lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c162
1 files changed, 90 insertions, 72 deletions
diff --git a/lib.c b/lib.c
index 5cc5598..d6a6f7a 100644
--- a/lib.c
+++ b/lib.c
@@ -36,7 +36,7 @@
#include <sys/types.h>
-static void
+__attribute__((format(printf, 3, 5))) static void
snprintf_append(char **dptr, size_t *dlen, const char *fmt, ssize_t sz, ...)
{
va_list ap;
@@ -110,68 +110,88 @@ format_context_line(char **msg, size_t *msglen, const char *line, size_t off)
}
static void
-format_error_context(char **msg, size_t *msglen, const char *path, const char *expr, size_t off)
+format_error_context(char **msg, size_t *msglen, const char *path, FILE *fp, struct json_object *stacktrace, size_t off)
{
- const char *p, *nl;
- size_t len, rlen;
+ struct json_object *e, *fn, *file;
+ size_t len, rlen, idx;
bool truncated;
char buf[256];
int eline;
- FILE *f;
- if (path) {
- f = fopen(path, "rb");
+ if (stacktrace) {
+ for (idx = 0; idx < json_object_array_length(stacktrace); idx++) {
+ e = json_object_array_get_idx(stacktrace, idx);
+ fn = json_object_object_get(e, "function");
+ file = json_object_object_get(e, "filename");
+
+ if (idx == 0) {
+ path = (file && strcmp(json_object_get_string(file), "[stdin]"))
+ ? json_object_get_string(file) : NULL;
+
+ if (path && fn)
+ sprintf_append(msg, msglen, "In %s(), file %s, ",
+ json_object_get_string(fn), path);
+ else if (fn)
+ sprintf_append(msg, msglen, "In %s(), ",
+ json_object_get_string(fn));
+ else if (path)
+ sprintf_append(msg, msglen, "In %s, ", path);
+ else
+ sprintf_append(msg, msglen, "In ");
- if (f) {
- truncated = false;
- eline = 1;
- rlen = 0;
+ sprintf_append(msg, msglen, "line %" PRId64 ", byte %" PRId64 ":\n",
+ json_object_get_int64(json_object_object_get(e, "line")),
+ json_object_get_int64(json_object_object_get(e, "byte")));
+ }
+ else {
+ sprintf_append(msg, msglen, " at %s%s (%s:%" PRId64 ":%" PRId64 ")\n",
+ fn ? "function " : "main function",
+ fn ? json_object_get_string(fn) : "",
+ json_object_get_string(file),
+ json_object_get_int64(json_object_object_get(e, "line")),
+ json_object_get_int64(json_object_object_get(e, "byte")));
+ }
+ }
+ }
- while (fgets(buf, sizeof(buf), f)) {
- len = strlen(buf);
- rlen += len;
+ fseek(fp, 0, SEEK_SET);
- if (rlen > off) {
- sprintf_append(msg, msglen, "In %s, line %u, byte %d:\n\n `%s",
- path, eline, len - (rlen - off) + (truncated ? sizeof(buf) : 1),
- truncated ? "..." : "");
+ truncated = false;
+ eline = 1;
+ rlen = 0;
- format_context_line(msg, msglen, buf,
- len - (rlen - off) + (truncated ? 3 : 0));
+ while (fgets(buf, sizeof(buf), fp)) {
+ len = strlen(buf);
+ rlen += len;
- break;
- }
+ if (rlen > off) {
+ if (!stacktrace) {
+ if (path && strcmp(path, "[stdin]"))
+ sprintf_append(msg, msglen, "In %s, ", path);
+ else
+ sprintf_append(msg, msglen, "In ");
- truncated = (len > 0 && buf[len-1] != '\n');
- eline += !truncated;
+ sprintf_append(msg, msglen, "line %d, byte %zu:\n",
+ eline, len - (rlen - off) + (truncated ? sizeof(buf) : 0));
}
- }
- else {
- sprintf_append(msg, msglen, "In %s, byte offset %zu [Unable to read source context]\n",
- path, off);
- }
- fclose(f);
- }
- else if (expr) {
- /* skip lines until error line */
- for (p = nl = expr, eline = 1; *p && p < expr + off; p++) {
- if (*p == '\n') {
- nl = p + 1;
- eline++;
- }
+ sprintf_append(msg, msglen, "\n `%s", truncated ? "..." : "");
+ format_context_line(msg, msglen, buf, len - (rlen - off) + (truncated ? 3 : 0));
+
+ break;
}
- sprintf_append(msg, msglen, "In line %u, byte %d:\n\n `", eline, p - nl);
- format_context_line(msg, msglen, nl, p - nl);
+ truncated = (len > 0 && buf[len-1] != '\n');
+ eline += !truncated;
}
}
char *
-ut_format_error(struct ut_state *state, const char *expr)
+ut_format_error(struct ut_state *state, FILE *fp)
{
- char *msg = NULL, *filename = state->filename;
- size_t off = state ? state->lex.off : 0;
+ char *msg = NULL, *filename = state->source->filename;
+ struct json_object *stacktrace = NULL;
+ size_t off = state ? state->source->off : 0;
struct ut_op *tag;
bool first = true;
size_t msglen = 0;
@@ -253,12 +273,16 @@ ut_format_error(struct ut_state *state, const char *expr)
filename = tag->tag.data;
}
- sprintf_append(&msg, &msglen, "%s\n", json_object_get_string(state->error.info.exception));
+ stacktrace = json_object_object_get(state->error.info.exception, "stacktrace");
+
+ sprintf_append(&msg, &msglen, "%s\n",
+ json_object_get_string(json_object_object_get(state->error.info.exception, "message")));
+
break;
}
if (off)
- format_error_context(&msg, &msglen, filename, expr, off);
+ format_error_context(&msg, &msglen, filename, fp, stacktrace, off);
return msg;
}
@@ -1543,28 +1567,32 @@ static struct json_object *
ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct ut_scope *scope)
{
struct json_object *ex, *entry, *rv;
- char *source, *msg;
+ struct ut_source *src;
struct stat st;
- FILE *sfile;
+ char *msg;
if (stat(path, &st))
return NULL;
- sfile = fopen(path, "rb");
+ src = xalloc(sizeof(*src));
+ src->fp = fopen(path, "rb");
- if (!sfile)
- return ut_exception(s, off, "Unable to open file %s: %s", path, strerror(errno));
+ if (!src->fp) {
+ free(src);
- source = xalloc(st.st_size + 1);
+ return ut_exception(s, off, "Unable to open file %s: %s", path, strerror(errno));
+ }
- fread(source, 1, st.st_size, sfile);
- fclose(sfile);
+ src->next = s->sources;
+ s->sources = src;
+ s->source = src;
- if (ut_parse(s, source)) {
- msg = ut_format_error(s, source);
+ if (ut_parse(s, src->fp)) {
+ msg = ut_format_error(s, src->fp);
ex = ut_exception(s, off, "Module loading failed: %s", msg);
- free(source);
+ fclose(src->fp);
+ free(src);
free(msg);
return ex;
@@ -1575,16 +1603,16 @@ ut_require_utpl(struct ut_state *s, uint32_t off, const char *path, struct ut_sc
rv = ut_invoke(s, off, NULL, entry, NULL);
if (ut_is_type(rv, T_EXCEPTION)) {
- msg = ut_format_error(s, source);
+ msg = ut_format_error(s, src->fp);
json_object_put(rv);
rv = ut_exception(s, off, "%s", msg);
free(msg);
}
- free(source);
-
json_object_put(entry);
+ s->source = src->next;
+
return rv;
}
@@ -1592,8 +1620,8 @@ static struct json_object *
ut_require_path(struct ut_state *s, uint32_t off, const char *path_template, const char *name)
{
struct json_object *rv = NULL;
- char *path = NULL, *filename;
const char *p, *q, *last;
+ char *path = NULL;
size_t plen = 0;
p = strchr(path_template, '*');
@@ -1618,16 +1646,11 @@ ut_require_path(struct ut_state *s, uint32_t off, const char *path_template, con
}
}
- filename = s->filename;
- s->filename = path;
-
if (!strcmp(p, ".so"))
rv = ut_require_so(s, off, path);
else if (!strcmp(p, ".utpl"))
rv = ut_require_utpl(s, off, path, NULL);
- s->filename = filename;
-
invalid:
free(path);
@@ -2086,7 +2109,7 @@ ut_include(struct ut_state *s, uint32_t off, struct json_object *args)
struct json_object *rv, *path = json_object_array_get_idx(args, 0);
struct json_object *scope = json_object_array_get_idx(args, 1);
struct ut_scope *sc;
- char *p, *filename;
+ char *p;
if (!json_object_is_type(path, json_type_string))
return ut_exception(s, off, "Passed filename is not a string");
@@ -2094,7 +2117,7 @@ ut_include(struct ut_state *s, uint32_t off, struct json_object *args)
if (scope && !json_object_is_type(scope, json_type_object))
return ut_exception(s, off, "Passed scope value is not an object");
- p = include_path(s->filename, json_object_get_string(path));
+ p = include_path(s->source->filename, json_object_get_string(path));
if (!p)
return ut_exception(s, off, "Include file not found");
@@ -2109,13 +2132,8 @@ ut_include(struct ut_state *s, uint32_t off, struct json_object *args)
sc = s->scope;
}
- filename = s->filename;
- s->filename = p;
-
rv = ut_require_utpl(s, off, p, sc);
- s->filename = filename;
-
free(p);
if (scope)