1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
#include "compat.h"
#if ! HAVE_VSNPRINTF
#include <stdarg.h>
#include <stdio.h>
int
vsnprintf(char * string, size_t size, const char * format, va_list args)
{
char * buffer;
int length;
FILE * devnull = fopen("/dev/null", "w");
/* Apparently programs get mad and segfault if you try to use a va_list
* twice without re-initializing it, so make a copy: */
va_list copy;
#ifdef va_copy
va_copy(copy, args);
#else
# ifdef __va_copy
__va_copy(copy, args);
# else
copy = args;
# endif
#endif
/* There's no ANSI function to output the length of a printf-formatted
* string without actually creating such output, so this is a kludge. */
if (! devnull) {
fprintf(stderr, _("Sorry, you don't have /dev/null.\n\
I can't emulate snprintf() or vsnprintf() for you.\n"));
exit(EXIT_FAILURE);
}
length = vfprintf(devnull, format, args);
buffer = malloc(length + 1);
if (!buffer) {
fprintf(stderr, _("Sorry, ran out of memory.\n"));
exit(EXIT_FAILURE);
}
vsprintf(buffer, format, copy);
strncpy(string, buffer, size);
/* clean up */
va_end(copy); /* the calling function should call va_end(args) */
fclose(devnull);
free(buffer);
/* according to the Linux Programmer's Manual, the ISO C99 standard has
* vsnprintf returning the same number for a given format string as would
* any other member of the printf family, even if length > size. */
return length;
}
#endif
|