]> git.ipfire.org Git - thirdparty/git.git/blobdiff - usage.c
t1415: set REFFILES for test specific to storage format
[thirdparty/git.git] / usage.c
diff --git a/usage.c b/usage.c
index cc803336bd5e6761b7fd50c33dba5aa9f734c4ba..1b206de36d6e1cb7799fce728c2a37e310479223 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -9,35 +9,84 @@
 void vreportf(const char *prefix, const char *err, va_list params)
 {
        char msg[4096];
-       char *p;
+       char *p, *pend = msg + sizeof(msg);
+       size_t prefix_len = strlen(prefix);
 
-       vsnprintf(msg, sizeof(msg), err, params);
-       for (p = msg; *p; p++) {
+       if (sizeof(msg) <= prefix_len) {
+               fprintf(stderr, "BUG!!! too long a prefix '%s'\n", prefix);
+               abort();
+       }
+       memcpy(msg, prefix, prefix_len);
+       p = msg + prefix_len;
+       if (vsnprintf(p, pend - p, err, params) < 0)
+               *p = '\0'; /* vsnprintf() failed, clip at prefix */
+
+       for (; p != pend - 1 && *p; p++) {
                if (iscntrl(*p) && *p != '\t' && *p != '\n')
                        *p = '?';
        }
-       fprintf(stderr, "%s%s\n", prefix, msg);
+
+       *(p++) = '\n'; /* we no longer need a NUL */
+       fflush(stderr);
+       write_in_full(2, msg, p - msg);
 }
 
 static NORETURN void usage_builtin(const char *err, va_list params)
 {
        vreportf("usage: ", err, params);
+
+       /*
+        * When we detect a usage error *before* the command dispatch in
+        * cmd_main(), we don't know what verb to report.  Force it to this
+        * to facilitate post-processing.
+        */
+       trace2_cmd_name("_usage_");
+
+       /*
+        * Currently, the (err, params) are usually just the static usage
+        * string which isn't very useful here.  Usually, the call site
+        * manually calls fprintf(stderr,...) with the actual detailed
+        * syntax error before calling usage().
+        *
+        * TODO It would be nice to update the call sites to pass both
+        * the static usage string and the detailed error message.
+        */
+
        exit(129);
 }
 
 static NORETURN void die_builtin(const char *err, va_list params)
 {
+       /*
+        * We call this trace2 function first and expect it to va_copy 'params'
+        * before using it (because an 'ap' can only be walked once).
+        */
+       trace2_cmd_error_va(err, params);
+
        vreportf("fatal: ", err, params);
+
        exit(128);
 }
 
 static void error_builtin(const char *err, va_list params)
 {
+       /*
+        * We call this trace2 function first and expect it to va_copy 'params'
+        * before using it (because an 'ap' can only be walked once).
+        */
+       trace2_cmd_error_va(err, params);
+
        vreportf("error: ", err, params);
 }
 
 static void warn_builtin(const char *warn, va_list params)
 {
+       /*
+        * We call this trace2 function first and expect it to va_copy 'params'
+        * before using it (because an 'ap' can only be walked once).
+        */
+       trace2_cmd_error_va(warn, params);
+
        vreportf("warning: ", warn, params);
 }
 
@@ -65,33 +114,33 @@ static int die_is_recursing_builtin(void)
 
 /* If we are in a dlopen()ed .so write to a global variable would segfault
  * (ugh), so keep things static. */
-static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;
-static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;
-static void (*error_routine)(const char *err, va_list params) = error_builtin;
-static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
+static NORETURN_PTR report_fn usage_routine = usage_builtin;
+static NORETURN_PTR report_fn die_routine = die_builtin;
+static report_fn error_routine = error_builtin;
+static report_fn warn_routine = warn_builtin;
 static int (*die_is_recursing)(void) = die_is_recursing_builtin;
 
-void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))
+void set_die_routine(NORETURN_PTR report_fn routine)
 {
        die_routine = routine;
 }
 
-void set_error_routine(void (*routine)(const char *err, va_list params))
+void set_error_routine(report_fn routine)
 {
        error_routine = routine;
 }
 
-void (*get_error_routine(void))(const char *err, va_list params)
+report_fn get_error_routine(void)
 {
        return error_routine;
 }
 
-void set_warn_routine(void (*routine)(const char *warn, va_list params))
+void set_warn_routine(report_fn routine)
 {
        warn_routine = routine;
 }
 
-void (*get_warn_routine(void))(const char *warn, va_list params)
+report_fn get_warn_routine(void)
 {
        return warn_routine;
 }
@@ -217,6 +266,10 @@ int BUG_exit_code;
 static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
 {
        char prefix[256];
+       va_list params_copy;
+       static int in_bug;
+
+       va_copy(params_copy, params);
 
        /* truncation via snprintf is OK here */
        if (file)
@@ -225,6 +278,13 @@ static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_lis
                snprintf(prefix, sizeof(prefix), "BUG: ");
 
        vreportf(prefix, fmt, params);
+
+       if (in_bug)
+               abort();
+       in_bug = 1;
+
+       trace2_cmd_error_va(fmt, params_copy);
+
        if (BUG_exit_code)
                exit(BUG_exit_code);
        abort();