Merge branch 'sa/send-email-dedup-some-headers'
[git] / compat / snprintf.c
1 #include "../git-compat-util.h"
2
3 /*
4  * The size parameter specifies the available space, i.e. includes
5  * the trailing NUL byte; but Windows's vsnprintf uses the entire
6  * buffer and avoids the trailing NUL, should the buffer be exactly
7  * big enough for the result. Defining SNPRINTF_SIZE_CORR to 1 will
8  * therefore remove 1 byte from the reported buffer size, so we
9  * always have room for a trailing NUL byte.
10  */
11 #ifndef SNPRINTF_SIZE_CORR
12 #if defined(WIN32) && (!defined(__GNUC__) || __GNUC__ < 4) && (!defined(_MSC_VER) || _MSC_VER < 1900)
13 #define SNPRINTF_SIZE_CORR 1
14 #else
15 #define SNPRINTF_SIZE_CORR 0
16 #endif
17 #endif
18
19 #undef vsnprintf
20 int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
21 {
22         va_list cp;
23         char *s;
24         int ret = -1;
25
26         if (maxsize > 0) {
27                 va_copy(cp, ap);
28                 ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
29                 va_end(cp);
30                 if (ret == maxsize-1)
31                         ret = -1;
32                 /* Windows does not NUL-terminate if result fills buffer */
33                 str[maxsize-1] = 0;
34         }
35         if (ret != -1)
36                 return ret;
37
38         s = NULL;
39         if (maxsize < 128)
40                 maxsize = 128;
41
42         while (ret == -1) {
43                 maxsize *= 4;
44                 str = realloc(s, maxsize);
45                 if (! str)
46                         break;
47                 s = str;
48                 va_copy(cp, ap);
49                 ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, cp);
50                 va_end(cp);
51                 if (ret == maxsize-1)
52                         ret = -1;
53         }
54         free(s);
55         return ret;
56 }
57
58 int git_snprintf(char *str, size_t maxsize, const char *format, ...)
59 {
60         va_list ap;
61         int ret;
62
63         va_start(ap, format);
64         ret = git_vsnprintf(str, maxsize, format, ap);
65         va_end(ap);
66
67         return ret;
68 }
69