Merge branch 'fc/completion-test-simplification'
[git] / usage.c
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
9 static int dying;
10
11 void vreportf(const char *prefix, const char *err, va_list params)
12 {
13         char msg[4096];
14         vsnprintf(msg, sizeof(msg), err, params);
15         fprintf(stderr, "%s%s\n", prefix, msg);
16 }
17
18 void vwritef(int fd, const char *prefix, const char *err, va_list params)
19 {
20         char msg[4096];
21         int len = vsnprintf(msg, sizeof(msg), err, params);
22         if (len > sizeof(msg))
23                 len = sizeof(msg);
24
25         write_in_full(fd, prefix, strlen(prefix));
26         write_in_full(fd, msg, len);
27         write_in_full(fd, "\n", 1);
28 }
29
30 static NORETURN void usage_builtin(const char *err, va_list params)
31 {
32         vreportf("usage: ", err, params);
33         exit(129);
34 }
35
36 static NORETURN void die_builtin(const char *err, va_list params)
37 {
38         vreportf("fatal: ", err, params);
39         exit(128);
40 }
41
42 static void error_builtin(const char *err, va_list params)
43 {
44         vreportf("error: ", err, params);
45 }
46
47 static void warn_builtin(const char *warn, va_list params)
48 {
49         vreportf("warning: ", warn, params);
50 }
51
52 /* If we are in a dlopen()ed .so write to a global variable would segfault
53  * (ugh), so keep things static. */
54 static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;
55 static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;
56 static void (*error_routine)(const char *err, va_list params) = error_builtin;
57 static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
58
59 void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))
60 {
61         die_routine = routine;
62 }
63
64 void set_error_routine(void (*routine)(const char *err, va_list params))
65 {
66         error_routine = routine;
67 }
68
69 void NORETURN usagef(const char *err, ...)
70 {
71         va_list params;
72
73         va_start(params, err);
74         usage_routine(err, params);
75         va_end(params);
76 }
77
78 void NORETURN usage(const char *err)
79 {
80         usagef("%s", err);
81 }
82
83 void NORETURN die(const char *err, ...)
84 {
85         va_list params;
86
87         if (dying) {
88                 fputs("fatal: recursion detected in die handler\n", stderr);
89                 exit(128);
90         }
91         dying = 1;
92
93         va_start(params, err);
94         die_routine(err, params);
95         va_end(params);
96 }
97
98 void NORETURN die_errno(const char *fmt, ...)
99 {
100         va_list params;
101         char fmt_with_err[1024];
102         char str_error[256], *err;
103         int i, j;
104
105         if (dying) {
106                 fputs("fatal: recursion detected in die_errno handler\n",
107                         stderr);
108                 exit(128);
109         }
110         dying = 1;
111
112         err = strerror(errno);
113         for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) {
114                 if ((str_error[j++] = err[i++]) != '%')
115                         continue;
116                 if (j < sizeof(str_error) - 1) {
117                         str_error[j++] = '%';
118                 } else {
119                         /* No room to double the '%', so we overwrite it with
120                          * '\0' below */
121                         j--;
122                         break;
123                 }
124         }
125         str_error[j] = 0;
126         snprintf(fmt_with_err, sizeof(fmt_with_err), "%s: %s", fmt, str_error);
127
128         va_start(params, fmt);
129         die_routine(fmt_with_err, params);
130         va_end(params);
131 }
132
133 int error(const char *err, ...)
134 {
135         va_list params;
136
137         va_start(params, err);
138         error_routine(err, params);
139         va_end(params);
140         return -1;
141 }
142
143 void warning(const char *warn, ...)
144 {
145         va_list params;
146
147         va_start(params, warn);
148         warn_routine(warn, params);
149         va_end(params);
150 }