|
6 | 6 | #include "git-compat-util.h"
|
7 | 7 | #include "cache.h"
|
8 | 8 |
|
| 9 | +static void replace_control_chars(char *str, size_t size) |
| 10 | +{ |
| 11 | + size_t i; |
| 12 | + |
| 13 | + for (i = 0; i < size; i++) { |
| 14 | + if (iscntrl(str[i]) && str[i] != '\t' && str[i] != '\n') |
| 15 | + str[i] = '?'; |
| 16 | + } |
| 17 | +} |
| 18 | + |
| 19 | +/* Atomically report (prefix + vsnprintf(err, params) + '\n') to stderr. */ |
9 | 20 | void vreportf(const char *prefix, const char *err, va_list params)
|
10 | 21 | {
|
11 | 22 | char msg[4096];
|
12 |
| - char *p; |
| 23 | + int ret; |
| 24 | + size_t prefix_size, total_size; |
13 | 25 |
|
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); |
| 26 | + prefix_size = strlen(prefix); |
| 27 | + if (prefix_size >= sizeof(msg)) |
| 28 | + BUG("vreportf: prefix is too long"); |
| 29 | + |
| 30 | + memcpy(msg, prefix, prefix_size); |
| 31 | + |
| 32 | + ret = vsnprintf(msg + prefix_size, sizeof(msg) - prefix_size, err, params); |
| 33 | + if (ret < 0) |
| 34 | + BUG("your vsnprintf is broken (returned %d)", ret); |
| 35 | + |
| 36 | + total_size = strlen(msg); /* vsnprintf() returns _desired_ size */ |
| 37 | + msg[total_size++] = '\n'; /* it's ok to overwrite terminating NULL */ |
| 38 | + |
| 39 | + replace_control_chars(msg, total_size); |
| 40 | + |
| 41 | + fflush(stderr); /* flush FILE* before writing lowlevel fd */ |
| 42 | + xwrite(2, msg, total_size); /* writing directly to fd is most atomic */ |
20 | 43 | }
|
21 | 44 |
|
22 | 45 | static NORETURN void usage_builtin(const char *err, va_list params)
|
|
0 commit comments