1#include "Python.h"
2
3/* snprintf() and vsnprintf() wrappers.
4
5 If the platform has vsnprintf, we use it, else we
6 emulate it in a half-hearted way. Even if the platform has it, we wrap
7 it because platforms differ in what vsnprintf does in case the buffer
8 is too small: C99 behavior is to return the number of characters that
9 would have been written had the buffer not been too small, and to set
10 the last byte of the buffer to \0. At least MS _vsnprintf returns a
11 negative value instead, and fills the entire buffer with non-\0 data.
12
13 The wrappers ensure that str[size-1] is always \0 upon return.
14
15 PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
16 (including the trailing '\0') into str.
17
18 Return value (rv):
19
20 When 0 <= rv < size, the output conversion was unexceptional, and
21 rv characters were written to str (excluding a trailing \0 byte at
22 str[rv]).
23
24 When rv >= size, output conversion was truncated, and a buffer of
25 size rv+1 would have been needed to avoid truncation. str[size-1]
26 is \0 in this case.
27
28 When rv < 0, "something bad happened". str[size-1] is \0 in this
29 case too, but the rest of str is unreliable. It could be that
30 an error in format codes was detected by libc, or on platforms
31 with a non-C99 vsnprintf simply that the buffer wasn't big enough
32 to avoid truncation, or on platforms without any vsnprintf that
33 PyMem_Malloc couldn't obtain space for a temp buffer.
34
35 CAUTION: Unlike C99, str != NULL and size > 0 are required.
36 Also, size must be smaller than INT_MAX.
37*/
38
39int
40PyOS_snprintf(char *str, size_t size, const char *format, ...)
41{
42 int rc;
43 va_list va;
44
45 va_start(va, format);
46 rc = PyOS_vsnprintf(str, size, format, va);
47 va_end(va);
48 return rc;
49}
50
51int
52PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
53{
54 assert(str != NULL);
55 assert(size > 0);
56 assert(size <= (INT_MAX - 1));
57 assert(format != NULL);
58
59 int len; /* # bytes written, excluding \0 */
60 /* We take a size_t as input but return an int. Sanity check
61 * our input so that it won't cause an overflow in the
62 * vsnprintf return value. */
63 if (size > INT_MAX - 1) {
64 len = -666;
65 goto Done;
66 }
67
68#if defined(_MSC_VER)
69 len = _vsnprintf(str, size, format, va);
70#else
71 len = vsnprintf(str, size, format, va);
72#endif
73
74Done:
75 if (size > 0) {
76 str[size-1] = '\0';
77 }
78 return len;
79}
80