diff options
Diffstat (limited to 'util/errors.c')
-rw-r--r-- | util/errors.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/util/errors.c b/util/errors.c new file mode 100644 index 000000000..6cabb97ee --- /dev/null +++ b/util/errors.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * 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 "global.h" +#include "posix.h" +#include "buffer.h" + +/******************************************** + * New error handling + ********************************************/ + +static git_error g_git_oom_error = { + "Out of memory", + GIT_ERROR_NOMEMORY +}; + +static void set_error_from_buffer(int error_class) +{ + git_error *error = &GIT_GLOBAL->error_t; + git_buf *buf = &GIT_GLOBAL->error_buf; + + error->message = buf->ptr; + error->klass = error_class; + + GIT_GLOBAL->last_error = error; +} + +static void set_error(int error_class, char *string) +{ + git_buf *buf = &GIT_GLOBAL->error_buf; + + git_buf_clear(buf); + if (string) { + git_buf_puts(buf, string); + git__free(string); + } + + set_error_from_buffer(error_class); +} + +void git_error_set_oom(void) +{ + GIT_GLOBAL->last_error = &g_git_oom_error; +} + +void git_error_set(int error_class, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + git_error_vset(error_class, fmt, ap); + va_end(ap); +} + +void git_error_vset(int error_class, const char *fmt, va_list ap) +{ + git_buf *buf = &GIT_GLOBAL->error_buf; + + git_buf_clear(buf); + if (fmt) { + git_buf_vprintf(buf, fmt, ap); + if (error_class == GIT_ERROR_OS) + git_buf_PUTS(buf, ": "); + } + + if (error_class == GIT_ERROR_OS) + git__system_errmsg(buf); + + if (!git_buf_oom(buf)) + set_error_from_buffer(error_class); +} + +int git_error_set_str(int error_class, const char *string) +{ + git_buf *buf = &GIT_GLOBAL->error_buf; + + assert(string); + + if (!string) { + git_error_set(GIT_ERROR_INVALID, "unspecified caller error"); + return -1; + } + + git_buf_clear(buf); + git_buf_puts(buf, string); + + if (git_buf_oom(buf)) + return -1; + + set_error_from_buffer(error_class); + return 0; +} + +void git_error_clear(void) +{ + if (GIT_GLOBAL->last_error != NULL) { + set_error(0, NULL); + GIT_GLOBAL->last_error = NULL; + } + + errno = 0; +#ifdef GIT_WIN32 + SetLastError(0); +#endif +} + +const git_error *git_error_last(void) +{ + return GIT_GLOBAL->last_error; +} + +int git_error_state_capture(git_error_state *state, int error_code) +{ + git_error *error = GIT_GLOBAL->last_error; + git_buf *error_buf = &GIT_GLOBAL->error_buf; + + memset(state, 0, sizeof(git_error_state)); + + if (!error_code) + return 0; + + state->error_code = error_code; + state->oom = (error == &g_git_oom_error); + + if (error) { + state->error_msg.klass = error->klass; + + if (state->oom) + state->error_msg.message = g_git_oom_error.message; + else + state->error_msg.message = git_buf_detach(error_buf); + } + + git_error_clear(); + return error_code; +} + +int git_error_state_restore(git_error_state *state) +{ + int ret = 0; + + git_error_clear(); + + if (state && state->error_msg.message) { + if (state->oom) + git_error_set_oom(); + else + set_error(state->error_msg.klass, state->error_msg.message); + + ret = state->error_code; + memset(state, 0, sizeof(git_error_state)); + } + + return ret; +} + +void git_error_state_free(git_error_state *state) +{ + if (!state) + return; + + if (!state->oom) + git__free(state->error_msg.message); + + memset(state, 0, sizeof(git_error_state)); +} + +int git_error_system_last(void) +{ +#ifdef GIT_WIN32 + return GetLastError(); +#else + return errno; +#endif +} + +void git_error_system_set(int code) +{ +#ifdef GIT_WIN32 + SetLastError(code); +#else + errno = code; +#endif +} + +/* Deprecated error values and functions */ + +const git_error *giterr_last(void) +{ + return git_error_last(); +} + +void giterr_clear(void) +{ + git_error_clear(); +} + +void giterr_set_str(int error_class, const char *string) +{ + git_error_set_str(error_class, string); +} + +void giterr_set_oom(void) +{ + git_error_set_oom(); +} |