usage.con commit strbuf: clear errno before calling getdelim(3) (642956c)
   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
   9static FILE *error_handle;
  10
  11void vreportf(const char *prefix, const char *err, va_list params)
  12{
  13        char msg[4096];
  14        FILE *fh = error_handle ? error_handle : stderr;
  15        char *p;
  16
  17        vsnprintf(msg, sizeof(msg), err, params);
  18        for (p = msg; *p; p++) {
  19                if (iscntrl(*p) && *p != '\t' && *p != '\n')
  20                        *p = '?';
  21        }
  22        fprintf(fh, "%s%s\n", prefix, msg);
  23}
  24
  25static NORETURN void usage_builtin(const char *err, va_list params)
  26{
  27        vreportf("usage: ", err, params);
  28        exit(129);
  29}
  30
  31static NORETURN void die_builtin(const char *err, va_list params)
  32{
  33        vreportf("fatal: ", err, params);
  34        exit(128);
  35}
  36
  37static void error_builtin(const char *err, va_list params)
  38{
  39        vreportf("error: ", err, params);
  40}
  41
  42static void warn_builtin(const char *warn, va_list params)
  43{
  44        vreportf("warning: ", warn, params);
  45}
  46
  47static int die_is_recursing_builtin(void)
  48{
  49        static int dying;
  50        return dying++;
  51}
  52
  53/* If we are in a dlopen()ed .so write to a global variable would segfault
  54 * (ugh), so keep things static. */
  55static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;
  56static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;
  57static void (*error_routine)(const char *err, va_list params) = error_builtin;
  58static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
  59static int (*die_is_recursing)(void) = die_is_recursing_builtin;
  60
  61void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))
  62{
  63        die_routine = routine;
  64}
  65
  66void set_error_routine(void (*routine)(const char *err, va_list params))
  67{
  68        error_routine = routine;
  69}
  70
  71void (*get_error_routine(void))(const char *err, va_list params)
  72{
  73        return error_routine;
  74}
  75
  76void set_warn_routine(void (*routine)(const char *warn, va_list params))
  77{
  78        warn_routine = routine;
  79}
  80
  81void (*get_warn_routine(void))(const char *warn, va_list params)
  82{
  83        return warn_routine;
  84}
  85
  86void set_die_is_recursing_routine(int (*routine)(void))
  87{
  88        die_is_recursing = routine;
  89}
  90
  91void set_error_handle(FILE *fh)
  92{
  93        error_handle = fh;
  94}
  95
  96void NORETURN usagef(const char *err, ...)
  97{
  98        va_list params;
  99
 100        va_start(params, err);
 101        usage_routine(err, params);
 102        va_end(params);
 103}
 104
 105void NORETURN usage(const char *err)
 106{
 107        usagef("%s", err);
 108}
 109
 110void NORETURN die(const char *err, ...)
 111{
 112        va_list params;
 113
 114        if (die_is_recursing()) {
 115                fputs("fatal: recursion detected in die handler\n", stderr);
 116                exit(128);
 117        }
 118
 119        va_start(params, err);
 120        die_routine(err, params);
 121        va_end(params);
 122}
 123
 124static const char *fmt_with_err(char *buf, int n, const char *fmt)
 125{
 126        char str_error[256], *err;
 127        int i, j;
 128
 129        err = strerror(errno);
 130        for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) {
 131                if ((str_error[j++] = err[i++]) != '%')
 132                        continue;
 133                if (j < sizeof(str_error) - 1) {
 134                        str_error[j++] = '%';
 135                } else {
 136                        /* No room to double the '%', so we overwrite it with
 137                         * '\0' below */
 138                        j--;
 139                        break;
 140                }
 141        }
 142        str_error[j] = 0;
 143        snprintf(buf, n, "%s: %s", fmt, str_error);
 144        return buf;
 145}
 146
 147void NORETURN die_errno(const char *fmt, ...)
 148{
 149        char buf[1024];
 150        va_list params;
 151
 152        if (die_is_recursing()) {
 153                fputs("fatal: recursion detected in die_errno handler\n",
 154                        stderr);
 155                exit(128);
 156        }
 157
 158        va_start(params, fmt);
 159        die_routine(fmt_with_err(buf, sizeof(buf), fmt), params);
 160        va_end(params);
 161}
 162
 163#undef error_errno
 164int error_errno(const char *fmt, ...)
 165{
 166        char buf[1024];
 167        va_list params;
 168
 169        va_start(params, fmt);
 170        error_routine(fmt_with_err(buf, sizeof(buf), fmt), params);
 171        va_end(params);
 172        return -1;
 173}
 174
 175#undef error
 176int error(const char *err, ...)
 177{
 178        va_list params;
 179
 180        va_start(params, err);
 181        error_routine(err, params);
 182        va_end(params);
 183        return -1;
 184}
 185
 186void warning_errno(const char *warn, ...)
 187{
 188        char buf[1024];
 189        va_list params;
 190
 191        va_start(params, warn);
 192        warn_routine(fmt_with_err(buf, sizeof(buf), warn), params);
 193        va_end(params);
 194}
 195
 196void warning(const char *warn, ...)
 197{
 198        va_list params;
 199
 200        va_start(params, warn);
 201        warn_routine(warn, params);
 202        va_end(params);
 203}