📄 error.c
字号:
/* error.c: common exception handling for Subversion * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <stdarg.h>#include <assert.h>#include <apr_general.h>#include <apr_pools.h>#include <apr_strings.h>#include "svn_cmdline.h"#include "svn_error.h"#ifdef SVN_DEBUG/* file_line for the non-debug case. */static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>";#endif /* SVN_DEBUG */#include "svn_private_config.h"/*** Helpers for creating errors ***/#undef svn_error_create#undef svn_error_createf#undef svn_error_quick_wrap#undef svn_error_wrap_apr/* XXX FIXME: These should be protected by a thread mutex. svn_error__locate and make_error_internal should cooperate in locking and unlocking it. *//* XXX TODO: Define mutex here #if APR_HAS_THREADS */static const char *error_file = NULL;static long error_line = -1;voidsvn_error__locate(const char *file, long line){ /* XXX TODO: Lock mutex here */ error_file = file; error_line = line;}/* Cleanup function for errors. svn_error_clear () removes this so errors that are properly handled *don't* hit this code. */#if defined(SVN_DEBUG_ERROR)static apr_status_t err_abort(void *data){ svn_error_t *err = data; /* For easy viewing in a debugger */ abort(); err = err; /* Fake a use for the variable */}#endifstatic svn_error_t *make_error_internal(apr_status_t apr_err, svn_error_t *child){ apr_pool_t *pool; svn_error_t *new_error; /* Reuse the child's pool, or create our own. */ if (child) pool = child->pool; else { if (apr_pool_create(&pool, NULL)) abort(); } /* Create the new error structure */ new_error = apr_pcalloc(pool, sizeof(*new_error)); /* Fill 'er up. */ new_error->apr_err = apr_err; new_error->child = child; new_error->pool = pool; new_error->file = error_file; new_error->line = error_line; /* XXX TODO: Unlock mutex here */#if defined(SVN_DEBUG_ERROR) if (! child) apr_pool_cleanup_register(pool, new_error, err_abort, NULL);#endif return new_error;}/*** Creating and destroying errors. ***/svn_error_t *svn_error_create(apr_status_t apr_err, svn_error_t *child, const char *message){ svn_error_t *err; err = make_error_internal(apr_err, child); if (message) err->message = apr_pstrdup(err->pool, message); return err;}svn_error_t *svn_error_createf(apr_status_t apr_err, svn_error_t *child, const char *fmt, ...){ svn_error_t *err; va_list ap; err = make_error_internal(apr_err, child); va_start(ap, fmt); err->message = apr_pvsprintf(err->pool, fmt, ap); va_end(ap); return err;}svn_error_t *svn_error_wrap_apr(apr_status_t status, const char *fmt, ...){ svn_error_t *err, *utf8_err; va_list ap; char errbuf[255]; const char *msg_apr, *msg; err = make_error_internal(status, NULL); if (fmt) { /* Grab the APR error message. */ apr_strerror(status, errbuf, sizeof(errbuf)); utf8_err = svn_utf_cstring_to_utf8(&msg_apr, errbuf, err->pool); if (utf8_err) msg_apr = NULL; svn_error_clear(utf8_err); /* Append it to the formatted message. */ va_start(ap, fmt); msg = apr_pvsprintf(err->pool, fmt, ap); va_end(ap); err->message = apr_psprintf(err->pool, "%s%s%s", msg, (msg_apr) ? ": " : "", (msg_apr) ? msg_apr : ""); } return err;}svn_error_t *svn_error_quick_wrap(svn_error_t *child, const char *new_msg){ return svn_error_create(child->apr_err, child, new_msg);}voidsvn_error_compose(svn_error_t *chain, svn_error_t *new_err){ apr_pool_t *pool = chain->pool; apr_pool_t *oldpool = new_err->pool; while (chain->child) chain = chain->child;#if defined(SVN_DEBUG_ERROR) /* Kill existing handler since the end of the chain is going to change */ apr_pool_cleanup_kill(pool, chain, err_abort);#endif /* Copy the new error chain into the old chain's pool. */ while (new_err) { chain->child = apr_palloc(pool, sizeof(*chain->child)); chain = chain->child; *chain = *new_err; if (chain->message) chain->message = apr_pstrdup(pool, new_err->message); chain->pool = pool;#if defined(SVN_DEBUG_ERROR) if (! new_err->child) apr_pool_cleanup_kill(oldpool, new_err, err_abort);#endif new_err = new_err->child; }#if defined(SVN_DEBUG_ERROR) apr_pool_cleanup_register(pool, chain, err_abort, NULL);#endif /* Destroy the new error chain. */ apr_pool_destroy(oldpool);}svn_error_t *svn_error_dup(svn_error_t *err){ apr_pool_t *pool; svn_error_t *new_err = NULL, *tmp_err = NULL; if (apr_pool_create(&pool, NULL)) abort(); for (; err; err = err->child) { if (! new_err) { new_err = apr_palloc(pool, sizeof(*new_err)); tmp_err = new_err; } else { tmp_err->child = apr_palloc(pool, sizeof(*tmp_err->child)); tmp_err = tmp_err->child; } *tmp_err = *err; tmp_err->pool = pool; if (tmp_err->message) tmp_err->message = apr_pstrdup(pool, tmp_err->message); }#if defined(SVN_DEBUG_ERROR) apr_pool_cleanup_register(pool, tmp_err, err_abort, NULL);#endif return new_err;}voidsvn_error_clear(svn_error_t *err){ if (err) {#if defined(SVN_DEBUG_ERROR) while (err->child) err = err->child; apr_pool_cleanup_kill(err->pool, err, err_abort);#endif apr_pool_destroy(err->pool); }}static voidprint_error(svn_error_t *err, FILE *stream, const char *prefix){ char errbuf[256]; const char *err_string; svn_error_t *temp_err = NULL; /* ensure initialized even if err->file == NULL */ /* Pretty-print the error */ /* Note: we can also log errors here someday. */#ifdef SVN_DEBUG /* Note: err->file is _not_ in UTF-8, because it's expanded from the __FILE__ preprocessor macro. */ const char *file_utf8; if (err->file && !(temp_err = svn_utf_cstring_to_utf8(&file_utf8, err->file, err->pool))) svn_error_clear(svn_cmdline_fprintf(stream, err->pool, "%s:%ld", err->file, err->line)); else { svn_error_clear(svn_cmdline_fputs(SVN_FILE_LINE_UNDEFINED, stream, err->pool)); svn_error_clear(temp_err); } svn_error_clear(svn_cmdline_fprintf(stream, err->pool, ": (apr_err=%d)\n", err->apr_err));#endif /* SVN_DEBUG */ /* Only print the same APR error string once. */ if (err->message) { svn_error_clear(svn_cmdline_fprintf(stream, err->pool, "%s%s\n", prefix, err->message)); } else { /* Is this a Subversion-specific error code? */ if ((err->apr_err > APR_OS_START_USEERR) && (err->apr_err <= APR_OS_START_CANONERR)) err_string = svn_strerror(err->apr_err, errbuf, sizeof(errbuf)); /* Otherwise, this must be an APR error code. */ else if ((temp_err = svn_utf_cstring_to_utf8 (&err_string, apr_strerror(err->apr_err, errbuf, sizeof(errbuf)), err->pool))) { svn_error_clear(temp_err); err_string = _("Can't recode error string from APR"); } svn_error_clear(svn_cmdline_fprintf(stream, err->pool, "%s%s\n", prefix, err_string)); }}voidsvn_handle_error(svn_error_t *err, FILE *stream, svn_boolean_t fatal){ svn_handle_error2(err, stream, fatal, "svn: ");}voidsvn_handle_error2(svn_error_t *err, FILE *stream, svn_boolean_t fatal, const char *prefix){ /* In a long error chain, there may be multiple errors with the same error code and no custom message. We only want to print the default message for that code once; printing it multiple times would add no useful information. The 'empties' array below remembers the codes of empty errors already seen in the chain. We could allocate it in err->pool, but there's no telling how long err will live or how many times it will get handled. So we use a subpool. */ apr_pool_t *subpool; apr_array_header_t *empties; /* ### The rest of this file carefully avoids using svn_pool_*(), preferring apr_pool_*() instead. I can't remember why -- it may be an artifact of r3719, or it may be for some deeper reason -- but I'm playing it safe and using apr_pool_*() here too. */ apr_pool_create(&subpool, err->pool); empties = apr_array_make(subpool, 0, sizeof(apr_status_t)); while (err) { int i; svn_boolean_t printed_already = FALSE; if (! err->message) { for (i = 0; i < empties->nelts; i++) { if (err->apr_err == ((apr_status_t *)empties->elts)[i]) { printed_already = TRUE; break; } } } if (! printed_already) { print_error(err, stream, prefix); if (! err->message) { (*((apr_status_t *) apr_array_push(empties))) = err->apr_err; } } err = err->child; } apr_pool_destroy(subpool); fflush(stream); if (fatal) /* XXX Shouldn't we exit(1) here instead, so that atexit handlers get called? --xbc */ abort();}voidsvn_handle_warning(FILE *stream, svn_error_t *err){ svn_handle_warning2(stream, err, "svn: ");}voidsvn_handle_warning2(FILE *stream, svn_error_t *err, const char *prefix){ char buf[256]; svn_error_clear(svn_cmdline_fprintf (stream, err->pool, _("%swarning: %s\n"), prefix, svn_err_best_message(err, buf, sizeof(buf)))); fflush(stream);}const char *svn_err_best_message(svn_error_t *err, char *buf, apr_size_t bufsize){ if (err->message) return err->message; else return svn_strerror(err->apr_err, buf, bufsize);}/* svn_strerror() and helpers */typedef struct { svn_errno_t errcode; const char *errdesc;} err_defn;/* To understand what is going on here, read svn_error_codes.h. */#define SVN_ERROR_BUILD_ARRAY#include "svn_error_codes.h"char *svn_strerror(apr_status_t statcode, char *buf, apr_size_t bufsize){ const err_defn *defn; for (defn = error_table; defn->errdesc != NULL; ++defn) if (defn->errcode == (svn_errno_t)statcode) { apr_cpystrn(buf, _(defn->errdesc), bufsize); return buf; } return apr_strerror(statcode, buf, bufsize);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -