1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-05-28 23:34:49 -05:00

Add a 'strbuf' system, for building up a large string piece by piece.

I'm faintly surprised I haven't needed this before. Basically it's an
allocating string formatter, like dupprintf, except that it
concatenates on to the end of a previous string. You instantiate a
strbuf, then repeatedly call strbuf_catf to append pieces of formatted
output to it, and then you can extract the whole string and free it
(separately or both in one step).
This commit is contained in:
Simon Tatham 2017-01-21 14:55:53 +00:00
parent 23a9d5608c
commit 960ad594a3
2 changed files with 72 additions and 16 deletions

81
misc.c
View File

@ -394,22 +394,16 @@ int toint(unsigned u)
* directive we don't know about, we should panic and die rather
* than run any risk.
*/
char *dupprintf(const char *fmt, ...)
static char *dupvprintf_inner(char *buf, int oldlen, int oldsize,
const char *fmt, va_list ap)
{
char *ret;
va_list ap;
va_start(ap, fmt);
ret = dupvprintf(fmt, ap);
va_end(ap);
return ret;
}
char *dupvprintf(const char *fmt, va_list ap)
{
char *buf;
int len, size;
buf = snewn(512, char);
size = 512;
size = oldsize - oldlen;
if (size == 0) {
size = 512;
buf = sresize(buf, oldlen + size, char);
}
while (1) {
#if defined _WINDOWS && _MSC_VER < 1900 /* 1900 == VS2015 has real snprintf */
@ -420,7 +414,7 @@ char *dupvprintf(const char *fmt, va_list ap)
* XXX some environments may have this as __va_copy() */
va_list aq;
va_copy(aq, ap);
len = vsnprintf(buf, size, fmt, aq);
len = vsnprintf(buf + oldlen, size, fmt, aq);
va_end(aq);
#else
/* Ugh. No va_copy macro, so do something nasty.
@ -431,7 +425,7 @@ char *dupvprintf(const char *fmt, va_list ap)
* (indeed, it has been observed to).
* XXX the autoconf manual suggests that using memcpy() will give
* "maximum portability". */
len = vsnprintf(buf, size, fmt, ap);
len = vsnprintf(buf + oldlen, size, fmt, ap);
#endif
if (len >= 0 && len < size) {
/* This is the C99-specified criterion for snprintf to have
@ -446,10 +440,65 @@ char *dupvprintf(const char *fmt, va_list ap)
* buffer wasn't big enough, so we enlarge it a bit and hope. */
size += 512;
}
buf = sresize(buf, size, char);
buf = sresize(buf, oldlen + size, char);
}
}
char *dupvprintf(const char *fmt, va_list ap)
{
return dupvprintf_inner(NULL, 0, 0, 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;
}
struct strbuf {
char *s;
int len, size;
};
strbuf *strbuf_new(void)
{
strbuf *buf = snew(strbuf);
buf->len = 0;
buf->size = 512;
buf->s = snewn(buf->size, char);
*buf->s = '\0';
return buf;
}
void strbuf_free(strbuf *buf)
{
sfree(buf->s);
sfree(buf);
}
char *strbuf_str(strbuf *buf)
{
return buf->s;
}
char *strbuf_to_str(strbuf *buf)
{
char *ret = buf->s;
sfree(buf);
return ret;
}
void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap)
{
buf->s = dupvprintf_inner(buf->s, buf->len, buf->size, fmt, ap);
buf->len += strlen(buf->s + buf->len);
}
void strbuf_catf(strbuf *buf, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
strbuf_catfv(buf, fmt, ap);
va_end(ap);
}
/*
* Read an entire line of text from a file. Return a buffer
* malloced to be as big as necessary (caller must free).

7
misc.h
View File

@ -38,6 +38,13 @@ char *dupprintf(const char *fmt, ...)
;
char *dupvprintf(const char *fmt, va_list ap);
void burnstr(char *string);
typedef struct strbuf strbuf;
strbuf *strbuf_new(void);
void strbuf_free(strbuf *buf);
char *strbuf_str(strbuf *buf); /* does not free buf */
char *strbuf_to_str(strbuf *buf); /* does free buf, but you must free result */
void strbuf_catf(strbuf *buf, const char *fmt, ...);
void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap);
/* String-to-Unicode converters that auto-allocate the destination and
* work around the rather deficient interface of mb_to_wc.