aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'libctf/ctf-subr.c')
-rw-r--r--libctf/ctf-subr.c87
1 files changed, 72 insertions, 15 deletions
diff --git a/libctf/ctf-subr.c b/libctf/ctf-subr.c
index 1586570..431b6d8 100644
--- a/libctf/ctf-subr.c
+++ b/libctf/ctf-subr.c
@@ -193,10 +193,16 @@ void ctf_dprintf (const char *format, ...)
}
}
-/* Errors and warnings. */
-_libctf_printflike_ (3, 4)
+/* This needs more attention to thread-safety later on. */
+static ctf_list_t open_errors;
+
+/* Errors and warnings. Report the warning or error to the list in FP (or the
+ open errors list if NULL): if ERR is nonzero it is the errno to report to the
+ debug stream instead of that recorded on fp. */
+_libctf_printflike_ (4, 5)
extern void
-ctf_err_warn (ctf_file_t *fp, int is_warning, const char *format, ...)
+ctf_err_warn (ctf_file_t *fp, int is_warning, int err,
+ const char *format, ...)
{
va_list alist;
ctf_err_warning_t *cew;
@@ -219,26 +225,68 @@ ctf_err_warn (ctf_file_t *fp, int is_warning, const char *format, ...)
}
va_end (alist);
- ctf_dprintf ("%s: %s\n", is_warning ? "error" : "warning", cew->cew_text);
+ /* Include the error code only if there is one, and if this is not a warning.
+ (Warnings may not have a meaningful error code, since the warning may not
+ lead to unwinding up to the user.) */
+ if (!is_warning && (err != 0 || (fp && ctf_errno (fp) != 0)))
+ ctf_dprintf ("%s: %s (%s)\n", is_warning ? _("error") : _("warning"),
+ cew->cew_text, err != 0 ? ctf_errmsg (err)
+ : ctf_errmsg (ctf_errno (fp)));
+ else
+ ctf_dprintf ("%s: %s\n", is_warning ? _("error") : _("warning"),
+ cew->cew_text);
+
+ if (fp != NULL)
+ ctf_list_append (&fp->ctf_errs_warnings, cew);
+ else
+ ctf_list_append (&open_errors, cew);
+}
- ctf_list_append (&fp->ctf_errs_warnings, cew);
+/* Move all the errors/warnings from an fp into the open_errors. */
+void
+ctf_err_warn_to_open (ctf_file_t *fp)
+{
+ ctf_list_splice (&open_errors, &fp->ctf_errs_warnings);
}
/* Error-warning reporting: an 'iterator' that returns errors and warnings from
the error/warning list, in order of emission. Errors and warnings are popped
- after return: the caller must free the returned error-text pointer. */
+ after return: the caller must free the returned error-text pointer.
+
+ An fp of NULL returns CTF-open-time errors from the open_errors variable
+ above.
+
+ The treatment of errors from this function itself is somewhat unusual: it
+ will often be called on an error path, so we don't want to overwrite the
+ ctf_errno unless we have no choice. So, like ctf_bufopen et al, this
+ function takes an errp pointer where errors are reported. The pointer is
+ optional: if not set, errors are reported via the fp (if non-NULL). Calls
+ with neither fp nor errp set are mildly problematic because there is no clear
+ way to report end-of-iteration: you just have to assume that a NULL return
+ means the end, and not an iterator error. */
+
char *
-ctf_errwarning_next (ctf_file_t *fp, ctf_next_t **it, int *is_warning)
+ctf_errwarning_next (ctf_file_t *fp, ctf_next_t **it, int *is_warning,
+ int *errp)
{
ctf_next_t *i = *it;
char *ret;
+ ctf_list_t *errlist;
ctf_err_warning_t *cew;
+ if (fp)
+ errlist = &fp->ctf_errs_warnings;
+ else
+ errlist = &open_errors;
+
if (!i)
{
if ((i = ctf_next_create ()) == NULL)
{
- ctf_set_errno (fp, ENOMEM);
+ if (errp)
+ *errp = ENOMEM;
+ else if (fp)
+ ctf_set_errno (fp, ENOMEM);
return NULL;
}
@@ -249,30 +297,39 @@ ctf_errwarning_next (ctf_file_t *fp, ctf_next_t **it, int *is_warning)
if ((void (*) (void)) ctf_errwarning_next != i->ctn_iter_fun)
{
- ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
+ if (errp)
+ *errp = ECTF_NEXT_WRONGFUN;
+ else if (fp)
+ ctf_set_errno (fp, ECTF_NEXT_WRONGFUN);
return NULL;
}
if (fp != i->cu.ctn_fp)
{
- ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
+ if (errp)
+ *errp = ECTF_NEXT_WRONGFP;
+ else if (fp)
+ ctf_set_errno (fp, ECTF_NEXT_WRONGFP);
return NULL;
}
- cew = ctf_list_next (&fp->ctf_errs_warnings);
+ cew = ctf_list_next (errlist);
if (!cew)
{
ctf_next_destroy (i);
*it = NULL;
- ctf_set_errno (fp, ECTF_NEXT_END);
+ if (errp)
+ *errp = ECTF_NEXT_END;
+ else if (fp)
+ ctf_set_errno (fp, ECTF_NEXT_END);
return NULL;
}
if (is_warning)
*is_warning = cew->cew_is_warning;
ret = cew->cew_text;
- ctf_list_delete (&fp->ctf_errs_warnings, cew);
+ ctf_list_delete (errlist, cew);
free (cew);
return ret;
}
@@ -281,7 +338,7 @@ void
ctf_assert_fail_internal (ctf_file_t *fp, const char *file, size_t line,
const char *exprstr)
{
- ctf_err_warn (fp, 0, "%s: %lu: libctf assertion failed: %s", file,
- (long unsigned int) line, exprstr);
+ ctf_err_warn (fp, 0, ECTF_INTERNAL, _("%s: %lu: libctf assertion failed: %s"),
+ file, (long unsigned int) line, exprstr);
ctf_set_errno (fp, ECTF_INTERNAL);
}