diff options
Diffstat (limited to 'src/errors.c')
-rw-r--r-- | src/errors.c | 112 |
1 files changed, 87 insertions, 25 deletions
diff --git a/src/errors.c b/src/errors.c index 81770e786..22b8ae7bf 100644 --- a/src/errors.c +++ b/src/errors.c @@ -4,7 +4,10 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ + #include "common.h" +#include "errors.h" +#include "posix.h" #include "global.h" #include <stdarg.h> @@ -55,50 +58,109 @@ const char *git_strerror(int num) return "Unknown error"; } -#define ERROR_MAX_LEN 1024 +static git_error git_error_OOM = { + GIT_ENOMEM, + "out of memory", + NULL, + NULL, + -1 +}; + +git_error * git_error_oom(void) +{ + /* + * Throw an out-of-memory error: + * what we return is actually a static pointer, because on + * oom situations we cannot afford to allocate a new error + * object. + * + * The `git_error_free` function will take care of not + * freeing this special type of error. + * + */ + return &git_error_OOM; +} -void git___rethrow(const char *msg, ...) +git_error * git_error_createf(const char *file, unsigned int line, int code, + const char *fmt, ...) { - char new_error[ERROR_MAX_LEN]; - char *last_error; - char *old_error = NULL; + git_error *err; + va_list ap; + size_t size; - va_list va; + err = git__malloc(sizeof(git_error)); + if (err == NULL) + return git_error_oom(); - last_error = GIT_GLOBAL->error.last; + memset(err, 0x0, sizeof(git_error)); - va_start(va, msg); - vsnprintf(new_error, ERROR_MAX_LEN, msg, va); - va_end(va); + va_start(ap, fmt); + size = p_vsnprintf(err->msg, 0, fmt, ap); + va_end(ap); - old_error = git__strdup(last_error); + size++; - snprintf(last_error, ERROR_MAX_LEN, "%s \n - %s", new_error, old_error); + err->msg = git__malloc(size); + if (err->msg == NULL) { + free(err); + return git_error_oom(); + } - git__free(old_error); + va_start(ap, fmt); + size = p_vsnprintf(err->msg, size, fmt, ap); + va_end(ap); + + err->code = code; + err->child = GIT_GLOBAL->git_errno; + err->file = file; + err->line = line; + + GIT_GLOBAL->git_errno = err; + + return err; } -void git___throw(const char *msg, ...) +git_error * git_error__quick_wrap(const char *file, int line, + git_error_code error, const char *msg) { - va_list va; + if (error == GIT_SUCCESS) + return GIT_SUCCESS; - va_start(va, msg); - vsnprintf(GIT_GLOBAL->error.last, ERROR_MAX_LEN, msg, va); - va_end(va); + return git_error_createf(file, line, error, "%s", msg); } -const char *git_lasterror(void) +void git_error_free(git_error *err) { - char *last_error = GIT_GLOBAL->error.last; + if (err == NULL) + return; + + if (err->child) + git_error_free(err->child); - if (!last_error[0]) - return NULL; + if (err->msg) + free(err->msg); - return last_error; + free(err); } void git_clearerror(void) { - char *last_error = GIT_GLOBAL->error.last; - last_error[0] = '\0'; + git_error_free(GIT_GLOBAL->git_errno); + GIT_GLOBAL->git_errno = NULL; +} + +const char *git_lasterror(void) +{ + return GIT_GLOBAL->git_errno == NULL ? NULL : GIT_GLOBAL->git_errno->msg; +} + +void git_error_print_stack(git_error *error_in) +{ + git_error *error; + + if (error_in == NULL) + error_in = GIT_GLOBAL->git_errno; + + for (error = error_in; error; error = error->child) + fprintf(stderr, "%s:%u %s\n", error->file, error->line, error->msg); } |