1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/utils/dupprintf.c
Simon Tatham 3396c97da9 New library-style 'utils' subdirectories.
Now that the new CMake build system is encouraging us to lay out the
code like a set of libraries, it seems like a good idea to make them
look more _like_ libraries, by putting things into separate modules as
far as possible.

This fixes several previous annoyances in which you had to link
against some object in order to get a function you needed, but that
object also contained other functions you didn't need which included
link-time symbol references you didn't want to have to deal with. The
usual offender was subsidiary supporting programs including misc.c for
some innocuous function and then finding they had to deal with the
requirements of buildinfo().

This big reorganisation introduces three new subdirectories called
'utils', one at the top level and one in each platform subdir. In each
case, the directory contains basically the same files that were
previously placed in the 'utils' build-time library, except that the
ones that were extremely miscellaneous (misc.c, utils.c, uxmisc.c,
winmisc.c, winmiscs.c, winutils.c) have been split up into much
smaller pieces.
2021-04-18 08:18:27 +01:00

101 lines
3.4 KiB
C

/*
* Do an sprintf(), but into a custom-allocated buffer.
*
* Currently I'm doing this via vsnprintf. This has worked so far,
* but it's not good, because vsnprintf is not available on all
* platforms. There's an ifdef to use `_vsnprintf', which seems
* to be the local name for it on Windows. Other platforms may
* lack it completely, in which case it'll be time to rewrite
* this function in a totally different way.
*
* The only `properly' portable solution I can think of is to
* implement my own format string scanner, which figures out an
* upper bound for the length of each formatting directive,
* allocates the buffer as it goes along, and calls sprintf() to
* actually process each directive. If I ever need to actually do
* this, some caveats:
*
* - It's very hard to find a reliable upper bound for
* floating-point values. %f, in particular, when supplied with
* a number near to the upper or lower limit of representable
* numbers, could easily take several hundred characters. It's
* probably feasible to predict this statically using the
* constants in <float.h>, or even to predict it dynamically by
* looking at the exponent of the specific float provided, but
* it won't be fun.
*
* - Don't forget to _check_, after calling sprintf, that it's
* used at most the amount of space we had available.
*
* - Fault any formatting directive we don't fully understand. The
* aim here is to _guarantee_ that we never overflow the buffer,
* because this is a security-critical function. If we see a
* directive we don't know about, we should panic and die rather
* than run any risk.
*/
#include <stdio.h>
#include "defs.h"
#include "misc.h"
#include "utils/utils.h"
/* Work around lack of va_copy in old MSC */
#if defined _MSC_VER && !defined va_copy
#define va_copy(a, b) TYPECHECK( \
(va_list *)0 == &(a) && (va_list *)0 == &(b), \
memcpy(&a, &b, sizeof(va_list)))
#endif
/* Also lack of vsnprintf before VS2015 */
#if defined _WINDOWS && \
!defined __MINGW32__ && \
!defined __WINE__ && \
_MSC_VER < 1900
#define vsnprintf _vsnprintf
#endif
char *dupvprintf_inner(char *buf, size_t oldlen, size_t *sizeptr,
const char *fmt, va_list ap)
{
size_t size = *sizeptr;
sgrowarrayn_nm(buf, size, oldlen, 512);
while (1) {
va_list aq;
va_copy(aq, ap);
int len = vsnprintf(buf + oldlen, size - oldlen, fmt, aq);
va_end(aq);
if (len >= 0 && len < size) {
/* This is the C99-specified criterion for snprintf to have
* been completely successful. */
*sizeptr = size;
return buf;
} else if (len > 0) {
/* This is the C99 error condition: the returned length is
* the required buffer size not counting the NUL. */
sgrowarrayn_nm(buf, size, oldlen + 1, len);
} else {
/* This is the pre-C99 glibc error condition: <0 means the
* buffer wasn't big enough, so we enlarge it a bit and hope. */
sgrowarray_nm(buf, size, size);
}
}
}
char *dupvprintf(const char *fmt, va_list ap)
{
size_t size = 0;
return dupvprintf_inner(NULL, 0, &size, fmt, ap);
}
char *dupprintf(const char *fmt, ...)
{
char *ret;
va_list ap;
va_start(ap, fmt);
ret = dupvprintf(fmt, ap);
va_end(ap);
return ret;
}