#define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #ifndef _GNU_SOURCE #define _GNU_SOURCE /* But only when HAVE_ASPRINTF */ #endif #include #include #include #include #include #include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */ #include "xmlrpc-c/string_int.h" #include "bool.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; } static const char * const xmlrpc_strsol = "[insufficient memory to build string]"; bool xmlrpc_strnomem(const char * const string) { /*---------------------------------------------------------------------------- The string 'string' was generated by a function in this file because it couldn't get enough memory to generate the string that it was supposed to generate. I.e. a preceding call to a string function failed. -----------------------------------------------------------------------------*/ return string == xmlrpc_strsol; } const char * xmlrpc_strnomemval() { return xmlrpc_strsol; } void xmlrpc_vasprintf(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 = xmlrpc_strsol; else *retvalP = string; } void XMLRPC_PRINTF_ATTR(2,3) xmlrpc_asprintf(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 */ xmlrpc_vasprintf(retvalP, fmt, varargs); va_end(varargs); } const char * xmlrpc_strdupsol(const char * const string) { const char * retvalOrNull; retvalOrNull = strdup(string); return retvalOrNull ? retvalOrNull : xmlrpc_strsol; } void xmlrpc_strfree(const char * const string) { if (string != xmlrpc_strsol) free((void *)string); } const char * xmlrpc_strdupnull(const char * const string) { if (string) return strdup(string); else return NULL; } void xmlrpc_strfreenull(const char * const string) { if (string) xmlrpc_strfree(string); }