forked from Mirrors/freeswitch
196 lines
4.8 KiB
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);
|
|
}
|
|
|
|
|
|
|