usage.con commit Merge branch 'po/read-graft-line' into next (1e3fe0d)
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "git-compat-util.h"
   7#include "cache.h"
   8
   9void vreportf(const char *prefix, const char *err, va_list params)
  10{
  11        char msg[4096];
  12        char *p;
  13
  14        vsnprintf(msg, sizeof(msg), err, params);
  15        for (p = msg; *p; p++) {
  16                if (iscntrl(*p) && *p != '\t' && *p != '\n')
  17                        *p = '?';
  18        }
  19        fprintf(stderr, "%s%s\n", prefix, msg);
  20}
  21
  22static NORETURN void usage_builtin(const char *err, va_list params)
  23{
  24        vreportf("usage: ", err, params);
  25        exit(129);
  26}
  27
  28static NORETURN void die_builtin(const char *err, va_list params)
  29{
  30        vreportf("fatal: ", err, params);
  31        exit(128);
  32}
  33
  34static void error_builtin(const char *err, va_list params)
  35{
  36        vreportf("error: ", err, params);
  37}
  38
  39static void warn_builtin(const char *warn, va_list params)
  40{
  41        vreportf("warning: ", warn, params);
  42}
  43
  44static int die_is_recursing_builtin(void)
  45{
  46        static int dying;
  47        /*
  48         * Just an arbitrary number X where "a < x < b" where "a" is
  49         * "maximum number of pthreads we'll ever plausibly spawn" and
  50         * "b" is "something less than Inf", since the point is to
  51         * prevent infinite recursion.
  52         */
  53        static const int recursion_limit = 1024;
  54
  55        dying++;
  56        if (dying > recursion_limit) {
  57                return 1;
  58        } else if (dying == 2) {
  59                warning("die() called many times. Recursion error or racy threaded death!");
  60                return 0;
  61        } else {
  62                return 0;
  63        }
  64}
  65
  66/* If we are in a dlopen()ed .so write to a global variable would segfault
  67 * (ugh), so keep things static. */
  68static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;
  69static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;
  70static void (*error_routine)(const char *err, va_list params) = error_builtin;
  71static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
  72static int (*die_is_recursing)(void) = die_is_recursing_builtin;
  73
  74void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))
  75{
  76        die_routine = routine;
  77}
  78
  79void set_error_routine(void (*routine)(const char *err, va_list params))
  80{
  81        error_routine = routine;
  82}
  83
  84void (*get_error_routine(void))(const char *err, va_list params)
  85{
  86        return error_routine;
  87}
  88
  89void set_warn_routine(void (*routine)(const char *warn, va_list params))
  90{
  91        warn_routine = routine;
  92}
  93
  94void (*get_warn_routine(void))(const char *warn, va_list params)
  95{
  96        return warn_routine;
  97}
  98
  99void set_die_is_recursing_routine(int (*routine)(void))
 100{
 101        die_is_recursing = routine;
 102}
 103
 104void NORETURN usagef(const char *err, ...)
 105{
 106        va_list params;
 107
 108        va_start(params, err);
 109        usage_routine(err, params);
 110        va_end(params);
 111}
 112
 113void NORETURN usage(const char *err)
 114{
 115        usagef("%s", err);
 116}
 117
 118void NORETURN die(const char *err, ...)
 119{
 120        va_list params;
 121
 122        if (die_is_recursing()) {
 123                fputs("fatal: recursion detected in die handler\n", stderr);
 124                exit(128);
 125        }
 126
 127        va_start(params, err);
 128        die_routine(err, params);
 129        va_end(params);
 130}
 131
 132static const char *fmt_with_err(char *buf, int n, const char *fmt)
 133{
 134        char str_error[256], *err;
 135        int i, j;
 136
 137        err = strerror(errno);
 138        for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) {
 139                if ((str_error[j++] = err[i++]) != '%')
 140                        continue;
 141                if (j < sizeof(str_error) - 1) {
 142                        str_error[j++] = '%';
 143                } else {
 144                        /* No room to double the '%', so we overwrite it with
 145                         * '\0' below */
 146                        j--;
 147                        break;
 148                }
 149        }
 150        str_error[j] = 0;
 151        snprintf(buf, n, "%s: %s", fmt, str_error);
 152        return buf;
 153}
 154
 155void NORETURN die_errno(const char *fmt, ...)
 156{
 157        char buf[1024];
 158        va_list params;
 159
 160        if (die_is_recursing()) {
 161                fputs("fatal: recursion detected in die_errno handler\n",
 162                        stderr);
 163                exit(128);
 164        }
 165
 166        va_start(params, fmt);
 167        die_routine(fmt_with_err(buf, sizeof(buf), fmt), params);
 168        va_end(params);
 169}
 170
 171#undef error_errno
 172int error_errno(const char *fmt, ...)
 173{
 174        char buf[1024];
 175        va_list params;
 176
 177        va_start(params, fmt);
 178        error_routine(fmt_with_err(buf, sizeof(buf), fmt), params);
 179        va_end(params);
 180        return -1;
 181}
 182
 183#undef error
 184int error(const char *err, ...)
 185{
 186        va_list params;
 187
 188        va_start(params, err);
 189        error_routine(err, params);
 190        va_end(params);
 191        return -1;
 192}
 193
 194void warning_errno(const char *warn, ...)
 195{
 196        char buf[1024];
 197        va_list params;
 198
 199        va_start(params, warn);
 200        warn_routine(fmt_with_err(buf, sizeof(buf), warn), params);
 201        va_end(params);
 202}
 203
 204void warning(const char *warn, ...)
 205{
 206        va_list params;
 207
 208        va_start(params, warn);
 209        warn_routine(warn, params);
 210        va_end(params);
 211}
 212
 213static NORETURN void BUG_vfl(const char *file, int line, const char *fmt, va_list params)
 214{
 215        char prefix[256];
 216
 217        /* truncation via snprintf is OK here */
 218        if (file)
 219                snprintf(prefix, sizeof(prefix), "BUG: %s:%d: ", file, line);
 220        else
 221                snprintf(prefix, sizeof(prefix), "BUG: ");
 222
 223        vreportf(prefix, fmt, params);
 224        abort();
 225}
 226
 227#ifdef HAVE_VARIADIC_MACROS
 228NORETURN void BUG_fl(const char *file, int line, const char *fmt, ...)
 229{
 230        va_list ap;
 231        va_start(ap, fmt);
 232        BUG_vfl(file, line, fmt, ap);
 233        va_end(ap);
 234}
 235#else
 236NORETURN void BUG(const char *fmt, ...)
 237{
 238        va_list ap;
 239        va_start(ap, fmt);
 240        BUG_vfl(NULL, 0, fmt, ap);
 241        va_end(ap);
 242}
 243#endif