freeswitch/libs/xmlrpc-c/lib/libutil/asprintf.c

196 lines
4.8 KiB
C

#define _XOPEN_SOURCE 600 /* Make sure strdup() is in <string.h> */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* But only when HAVE_ASPRINTF */
#endif
#include <stdarg.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#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);
}