123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- #ifndef _GNU_SOURCE
- #define _GNU_SOURCE /* But only when HAVE_ASPRINTF */
- #endif
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <limits.h>
- #include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */
- #include "bool.h"
- #include "casprintf.h"
- static __inline__ void
- newVsnprintf(char * const buffer,
- size_t const bufferSize,
- const char * const fmt,
- va_list varargs,
- size_t * const formattedSizeP) {
- /*----------------------------------------------------------------------------
- This is vsnprintf() with the new behavior, where not fitting in the buffer
- is not a failure.
- Unfortunately, we can't practically return the size of the formatted string
- if the C library has old vsnprintf() and the formatted string doesn't fit
- in the buffer, so in that case we just return something larger than the
- buffer.
- -----------------------------------------------------------------------------*/
- if (bufferSize > INT_MAX/2) {
- /* There's a danger we won't be able to coerce the return value
- of XMLRPC_VSNPRINTF to an integer (which we have to do because,
- while for POSIX its return value is ssize_t, on Windows it is int),
- or return double the buffer size.
- */
- *formattedSizeP = 0;
- } else {
- int rc;
- rc = XMLRPC_VSNPRINTF(buffer, bufferSize, fmt, varargs);
- if (rc < 0) {
- /* We have old vsnprintf() (or Windows) and the formatted value
- doesn't fit in the buffer, but we don't know how big a buffer it
- needs.
- */
- *formattedSizeP = bufferSize * 2;
- } else {
- /* Either the string fits in the buffer or we have new vsnprintf()
- which tells us how big the string is regardless.
- */
- *formattedSizeP = rc;
- }
- }
- }
- static __inline__ void
- simpleVasprintf(char ** const retvalP,
- const char * const fmt,
- va_list varargs) {
- /*----------------------------------------------------------------------------
- This is a poor man's implementation of vasprintf(), of GNU fame.
- -----------------------------------------------------------------------------*/
- char * result;
- size_t bufferSize;
- bool outOfMemory;
- for (result = NULL, bufferSize = 4096, outOfMemory = false;
- !result && !outOfMemory;
- ) {
- result = malloc(bufferSize);
- if (!result)
- outOfMemory = true;
- else {
- size_t bytesNeeded;
- newVsnprintf(result, bufferSize, fmt, varargs, &bytesNeeded);
- if (bytesNeeded > bufferSize) {
- free(result);
- result = NULL;
- bufferSize = bytesNeeded;
- }
- }
- }
- *retvalP = result;
- }
- const char * const strsol = "[Insufficient memory to build string]";
- void
- cvasprintf(const char ** const retvalP,
- const char * const fmt,
- va_list varargs) {
- char * string;
- #if HAVE_ASPRINTF
- vasprintf(&string, fmt, varargs);
- #else
- simpleVasprintf(&string, fmt, varargs);
- #endif
- if (string == NULL)
- *retvalP = strsol;
- else
- *retvalP = string;
- }
- void GNU_PRINTF_ATTR(2,3)
- casprintf(const char ** const retvalP, const char * const fmt, ...) {
- va_list varargs; /* mysterious structure used by variable arg facility */
- va_start(varargs, fmt); /* start up the mysterious variable arg facility */
- cvasprintf(retvalP, fmt, varargs);
- va_end(varargs);
- }
- void
- strfree(const char * const string) {
- if (string != strsol)
- free((void *)string);
- }
|