You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.7 KiB
93 lines
2.7 KiB
#include "Python.h" |
|
#include <ctype.h> |
|
|
|
/* snprintf() wrappers. If the platform has vsnprintf, we use it, else we |
|
emulate it in a half-hearted way. Even if the platform has it, we wrap |
|
it because platforms differ in what vsnprintf does in case the buffer |
|
is too small: C99 behavior is to return the number of characters that |
|
would have been written had the buffer not been too small, and to set |
|
the last byte of the buffer to \0. At least MS _vsnprintf returns a |
|
negative value instead, and fills the entire buffer with non-\0 data. |
|
|
|
The wrappers ensure that str[size-1] is always \0 upon return. |
|
|
|
PyOS_snprintf and PyOS_vsnprintf never write more than size bytes |
|
(including the trailing '\0') into str. |
|
|
|
If the platform doesn't have vsnprintf, and the buffer size needed to |
|
avoid truncation exceeds size by more than 512, Python aborts with a |
|
Py_FatalError. |
|
|
|
Return value (rv): |
|
|
|
When 0 <= rv < size, the output conversion was unexceptional, and |
|
rv characters were written to str (excluding a trailing \0 byte at |
|
str[rv]). |
|
|
|
When rv >= size, output conversion was truncated, and a buffer of |
|
size rv+1 would have been needed to avoid truncation. str[size-1] |
|
is \0 in this case. |
|
|
|
When rv < 0, "something bad happened". str[size-1] is \0 in this |
|
case too, but the rest of str is unreliable. It could be that |
|
an error in format codes was detected by libc, or on platforms |
|
with a non-C99 vsnprintf simply that the buffer wasn't big enough |
|
to avoid truncation, or on platforms without any vsnprintf that |
|
PyMem_Malloc couldn't obtain space for a temp buffer. |
|
|
|
CAUTION: Unlike C99, str != NULL and size > 0 are required. |
|
*/ |
|
|
|
int |
|
PyOS_snprintf(char *str, size_t size, const char *format, ...) |
|
{ |
|
int rc; |
|
va_list va; |
|
|
|
va_start(va, format); |
|
rc = PyOS_vsnprintf(str, size, format, va); |
|
va_end(va); |
|
return rc; |
|
} |
|
|
|
int |
|
PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) |
|
{ |
|
int len; /* # bytes written, excluding \0 */ |
|
#ifndef HAVE_SNPRINTF |
|
char *buffer; |
|
#endif |
|
assert(str != NULL); |
|
assert(size > 0); |
|
assert(format != NULL); |
|
|
|
#ifdef HAVE_SNPRINTF |
|
len = vsnprintf(str, size, format, va); |
|
#else |
|
/* Emulate it. */ |
|
buffer = PyMem_MALLOC(size + 512); |
|
if (buffer == NULL) { |
|
len = -666; |
|
goto Done; |
|
} |
|
|
|
len = vsprintf(buffer, format, va); |
|
if (len < 0) |
|
/* ignore the error */; |
|
|
|
else if ((size_t)len >= size + 512) |
|
Py_FatalError("Buffer overflow in PyOS_snprintf/PyOS_vsnprintf"); |
|
|
|
else { |
|
const size_t to_copy = (size_t)len < size ? |
|
(size_t)len : size - 1; |
|
assert(to_copy < size); |
|
memcpy(str, buffer, to_copy); |
|
str[to_copy] = '\0'; |
|
} |
|
PyMem_FREE(buffer); |
|
Done: |
|
#endif |
|
str[size-1] = '\0'; |
|
return len; |
|
}
|
|
|