Success build TortoiseMerge.
[TortoiseGit.git] / src / TortoiseMerge / libsvn_diff / error.c
blobc6273a6f654dd7d694536d96932aa1a97dddde5a
1 /* error.c: common exception handling for Subversion
3 * ====================================================================
4 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
6 * This software is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at http://subversion.tigris.org/license-1.html.
9 * If newer versions of this license are posted there, you may use a
10 * newer version instead, at your option.
12 * This software consists of voluntary contributions made by many
13 * individuals. For exact contribution history, see the revision
14 * history and logs, available at http://subversion.tigris.org/.
15 * ====================================================================
20 #include <stdarg.h>
22 #include <apr_general.h>
23 #include <apr_pools.h>
24 #include <apr_strings.h>
26 //#include "svn_cmdline.h"
27 #include "svn_error.h"
28 #include "svn_pools.h"
29 #include "svn_utf.h"
31 #ifdef SVN_DEBUG
32 /* file_line for the non-debug case. */
33 static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>";
34 #endif /* SVN_DEBUG */
36 //#include "svn_private_config.h"
39 /*** Helpers for creating errors ***/
40 #undef svn_error_create
41 #undef svn_error_createf
42 #undef svn_error_quick_wrap
43 #undef svn_error_wrap_apr
46 /* XXX FIXME: These should be protected by a thread mutex.
47 svn_error__locate and make_error_internal should cooperate
48 in locking and unlocking it. */
50 /* XXX TODO: Define mutex here #if APR_HAS_THREADS */
51 static const char *error_file = NULL;
52 static long error_line = -1;
54 void
55 svn_error__locate(const char *file, long line)
57 /* XXX TODO: Lock mutex here */
58 error_file = file;
59 error_line = line;
63 /* Cleanup function for errors. svn_error_clear () removes this so
64 errors that are properly handled *don't* hit this code. */
65 #if defined(SVN_DEBUG)
66 static apr_status_t err_abort(void *data)
68 svn_error_t *err = data; /* For easy viewing in a debugger */
69 err = err; /* Fake a use for the variable to avoid compiler warnings */
70 abort();
72 #endif
75 static svn_error_t *
76 make_error_internal(apr_status_t apr_err,
77 svn_error_t *child)
79 apr_pool_t *pool;
80 svn_error_t *new_error;
82 /* Reuse the child's pool, or create our own. */
83 if (child)
84 pool = child->pool;
85 else
87 if (apr_pool_create(&pool, NULL))
88 abort();
91 /* Create the new error structure */
92 new_error = apr_pcalloc(pool, sizeof(*new_error));
94 /* Fill 'er up. */
95 new_error->apr_err = apr_err;
96 new_error->child = child;
97 new_error->pool = pool;
98 new_error->file = error_file;
99 new_error->line = error_line;
100 /* XXX TODO: Unlock mutex here */
102 #if defined(SVN_DEBUG)
103 if (! child)
104 apr_pool_cleanup_register(pool, new_error,
105 err_abort,
106 apr_pool_cleanup_null);
107 #endif
109 return new_error;
114 /*** Creating and destroying errors. ***/
116 svn_error_t *
117 svn_error_create(apr_status_t apr_err,
118 svn_error_t *child,
119 const char *message)
121 svn_error_t *err;
123 err = make_error_internal(apr_err, child);
125 if (message)
126 err->message = apr_pstrdup(err->pool, message);
128 return err;
132 svn_error_t *
133 svn_error_createf(apr_status_t apr_err,
134 svn_error_t *child,
135 const char *fmt,
136 ...)
138 svn_error_t *err;
139 va_list ap;
141 err = make_error_internal(apr_err, child);
143 va_start(ap, fmt);
144 err->message = apr_pvsprintf(err->pool, fmt, ap);
145 va_end(ap);
147 return err;
151 svn_error_t *
152 svn_error_wrap_apr(apr_status_t status,
153 const char *fmt,
154 ...)
156 svn_error_t *err, *utf8_err;
157 va_list ap;
158 char errbuf[255];
159 const char *msg_apr, *msg;
161 err = make_error_internal(status, NULL);
163 if (fmt)
165 /* Grab the APR error message. */
166 apr_strerror(status, errbuf, sizeof(errbuf));
167 utf8_err = svn_utf_cstring_to_utf8(&msg_apr, errbuf, err->pool);
168 if (utf8_err)
169 msg_apr = NULL;
170 svn_error_clear(utf8_err);
172 /* Append it to the formatted message. */
173 va_start(ap, fmt);
174 msg = apr_pvsprintf(err->pool, fmt, ap);
175 va_end(ap);
176 err->message = apr_psprintf(err->pool, "%s%s%s", msg,
177 (msg_apr) ? ": " : "",
178 (msg_apr) ? msg_apr : "");
181 return err;
185 svn_error_t *
186 svn_error_quick_wrap(svn_error_t *child, const char *new_msg)
188 return svn_error_create(child->apr_err,
189 child,
190 new_msg);
194 svn_error_t *
195 svn_error_compose_create(svn_error_t *err1,
196 svn_error_t *err2)
198 if (err1 && err2)
200 svn_error_compose(err1, err2);
201 return err1;
203 return err1 ? err1 : err2;
207 void
208 svn_error_compose(svn_error_t *chain, svn_error_t *new_err)
210 apr_pool_t *pool = chain->pool;
211 apr_pool_t *oldpool = new_err->pool;
213 while (chain->child)
214 chain = chain->child;
216 #if defined(SVN_DEBUG)
217 /* Kill existing handler since the end of the chain is going to change */
218 apr_pool_cleanup_kill(pool, chain, err_abort);
219 #endif
221 /* Copy the new error chain into the old chain's pool. */
222 while (new_err)
224 chain->child = apr_palloc(pool, sizeof(*chain->child));
225 chain = chain->child;
226 *chain = *new_err;
227 if (chain->message)
228 chain->message = apr_pstrdup(pool, new_err->message);
229 chain->pool = pool;
230 #if defined(SVN_DEBUG)
231 if (! new_err->child)
232 apr_pool_cleanup_kill(oldpool, new_err, err_abort);
233 #endif
234 new_err = new_err->child;
237 #if defined(SVN_DEBUG)
238 apr_pool_cleanup_register(pool, chain,
239 err_abort,
240 apr_pool_cleanup_null);
241 #endif
243 /* Destroy the new error chain. */
244 svn_pool_destroy(oldpool);
247 svn_error_t *
248 svn_error_root_cause(svn_error_t *err)
250 while (err)
252 if (err->child)
253 err = err->child;
254 else
255 break;
258 return err;
261 svn_error_t *
262 svn_error_dup(svn_error_t *err)
264 apr_pool_t *pool;
265 svn_error_t *new_err = NULL, *tmp_err = NULL;
267 if (apr_pool_create(&pool, NULL))
268 abort();
270 for (; err; err = err->child)
272 if (! new_err)
274 new_err = apr_palloc(pool, sizeof(*new_err));
275 tmp_err = new_err;
277 else
279 tmp_err->child = apr_palloc(pool, sizeof(*tmp_err->child));
280 tmp_err = tmp_err->child;
282 *tmp_err = *err;
283 tmp_err->pool = pool;
284 if (tmp_err->message)
285 tmp_err->message = apr_pstrdup(pool, tmp_err->message);
288 #if defined(SVN_DEBUG)
289 apr_pool_cleanup_register(pool, tmp_err,
290 err_abort,
291 apr_pool_cleanup_null);
292 #endif
294 return new_err;
297 void
298 svn_error_clear(svn_error_t *err)
300 if (err)
302 #if defined(SVN_DEBUG)
303 while (err->child)
304 err = err->child;
305 apr_pool_cleanup_kill(err->pool, err, err_abort);
306 #endif
307 svn_pool_destroy(err->pool);
311 static void
312 print_error(svn_error_t *err, FILE *stream, const char *prefix)
314 char errbuf[256];
315 const char *err_string;
316 svn_error_t *temp_err = NULL; /* ensure initialized even if
317 err->file == NULL */
318 /* Pretty-print the error */
319 /* Note: we can also log errors here someday. */
321 #ifdef SVN_DEBUG
322 /* Note: err->file is _not_ in UTF-8, because it's expanded from
323 the __FILE__ preprocessor macro. */
324 const char *file_utf8;
326 if (err->file
327 && !(temp_err = svn_utf_cstring_to_utf8(&file_utf8, err->file,
328 err->pool)))
329 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
330 "%s:%ld", err->file, err->line));
331 else
333 svn_error_clear(svn_cmdline_fputs(SVN_FILE_LINE_UNDEFINED,
334 stream, err->pool));
335 svn_error_clear(temp_err);
338 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
339 ": (apr_err=%d)\n", err->apr_err));
340 #endif /* SVN_DEBUG */
342 /* Only print the same APR error string once. */
343 if (err->message)
345 svn_error_clear(svn_cmdline_fprintf(stream, err->pool, "%s%s\n",
346 prefix, err->message));
348 else
350 /* Is this a Subversion-specific error code? */
351 if ((err->apr_err > APR_OS_START_USEERR)
352 && (err->apr_err <= APR_OS_START_CANONERR))
353 err_string = svn_strerror(err->apr_err, errbuf, sizeof(errbuf));
354 /* Otherwise, this must be an APR error code. */
355 else if ((temp_err = svn_utf_cstring_to_utf8
356 (&err_string, apr_strerror(err->apr_err, errbuf,
357 sizeof(errbuf)), err->pool)))
359 svn_error_clear(temp_err);
360 err_string = _("Can't recode error string from APR");
363 svn_error_clear(svn_cmdline_fprintf(stream, err->pool,
364 "%s%s\n", prefix, err_string));
368 void
369 svn_handle_error(svn_error_t *err, FILE *stream, svn_boolean_t fatal)
371 svn_handle_error2(err, stream, fatal, "svn: ");
374 void
375 svn_handle_error2(svn_error_t *err,
376 FILE *stream,
377 svn_boolean_t fatal,
378 const char *prefix)
380 /* In a long error chain, there may be multiple errors with the same
381 error code and no custom message. We only want to print the
382 default message for that code once; printing it multiple times
383 would add no useful information. The 'empties' array below
384 remembers the codes of empty errors already seen in the chain.
386 We could allocate it in err->pool, but there's no telling how
387 long err will live or how many times it will get handled. So we
388 use a subpool. */
389 apr_pool_t *subpool;
390 apr_array_header_t *empties;
391 svn_error_t *tmp_err;
393 /* ### The rest of this file carefully avoids using svn_pool_*(),
394 preferring apr_pool_*() instead. I can't remember why -- it may
395 be an artifact of r3719, or it may be for some deeper reason --
396 but I'm playing it safe and using apr_pool_*() here too. */
397 apr_pool_create(&subpool, err->pool);
398 empties = apr_array_make(subpool, 0, sizeof(apr_status_t));
400 tmp_err = err;
401 while (tmp_err)
403 int i;
404 svn_boolean_t printed_already = FALSE;
406 if (! tmp_err->message)
408 for (i = 0; i < empties->nelts; i++)
410 if (tmp_err->apr_err == APR_ARRAY_IDX(empties, i, apr_status_t) )
412 printed_already = TRUE;
413 break;
418 if (! printed_already)
420 print_error(tmp_err, stream, prefix);
421 if (! tmp_err->message)
423 APR_ARRAY_PUSH(empties, apr_status_t) = tmp_err->apr_err;
427 tmp_err = tmp_err->child;
430 svn_pool_destroy(subpool);
432 fflush(stream);
433 if (fatal)
435 /* Avoid abort()s in maintainer mode. */
436 svn_error_clear(err);
438 /* We exit(1) here instead of abort()ing so that atexit handlers
439 get called. */
440 exit(EXIT_FAILURE);
445 void
446 svn_handle_warning(FILE *stream, svn_error_t *err)
448 svn_handle_warning2(stream, err, "svn: ");
451 void
452 svn_handle_warning2(FILE *stream, svn_error_t *err, const char *prefix)
454 char buf[256];
456 svn_error_clear(svn_cmdline_fprintf
457 (stream, err->pool,
458 _("%swarning: %s\n"),
459 prefix, svn_err_best_message(err, buf, sizeof(buf))));
460 fflush(stream);
463 const char *
464 svn_err_best_message(svn_error_t *err, char *buf, apr_size_t bufsize)
466 if (err->message)
467 return err->message;
468 else
469 return svn_strerror(err->apr_err, buf, bufsize);
473 /* svn_strerror() and helpers */
475 typedef struct {
476 svn_errno_t errcode;
477 const char *errdesc;
478 } err_defn;
480 /* To understand what is going on here, read svn_error_codes.h. */
481 #define SVN_ERROR_BUILD_ARRAY
482 #include "svn_error_codes.h"
484 char *
485 svn_strerror(apr_status_t statcode, char *buf, apr_size_t bufsize)
487 const err_defn *defn;
489 for (defn = error_table; defn->errdesc != NULL; ++defn)
490 if (defn->errcode == (svn_errno_t)statcode)
492 apr_cpystrn(buf, _(defn->errdesc), bufsize);
493 return buf;
496 return apr_strerror(statcode, buf, bufsize);
499 svn_error_t *
500 svn_error_raise_on_malfunction(svn_boolean_t can_return,
501 const char *file, int line,
502 const char *expr)
504 if (!can_return)
505 abort(); /* Nothing else we can do as a library */
507 if (expr)
508 return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
509 _("In file '%s' line %d: assertion failed (%s)"),
510 file, line, expr);
511 else
512 return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
513 _("In file '%s' line %d: internal malfunction"),
514 file, line);
517 svn_error_t *
518 svn_error_abort_on_malfunction(svn_boolean_t can_return,
519 const char *file, int line,
520 const char *expr)
522 svn_error_t *err = svn_error_raise_on_malfunction(TRUE, file, line, expr);
524 svn_handle_error2(err, stderr, FALSE, "svn: ");
525 abort();
526 return err; /* Not reached. */
529 /* The current handler for reporting malfunctions, and its default setting. */
530 static svn_error_malfunction_handler_t malfunction_handler
531 = svn_error_abort_on_malfunction;
533 svn_error_malfunction_handler_t
534 svn_error_set_malfunction_handler(svn_error_malfunction_handler_t func)
536 svn_error_malfunction_handler_t old_malfunction_handler
537 = malfunction_handler;
539 malfunction_handler = func;
540 return old_malfunction_handler;
543 svn_error_t *
544 svn_error__malfunction(svn_boolean_t can_return,
545 const char *file, int line,
546 const char *expr)
548 return malfunction_handler(can_return, file, line, expr);