diff options
Diffstat (limited to 'src/interfaces/libpq/pqexpbuffer.c')
-rw-r--r-- | src/interfaces/libpq/pqexpbuffer.c | 103 |
1 files changed, 73 insertions, 30 deletions
diff --git a/src/interfaces/libpq/pqexpbuffer.c b/src/interfaces/libpq/pqexpbuffer.c index ddaca7e67b5..bedf456b3ce 100644 --- a/src/interfaces/libpq/pqexpbuffer.c +++ b/src/interfaces/libpq/pqexpbuffer.c @@ -8,11 +8,15 @@ * * This module is essentially the same as the backend's StringInfo data type, * but it is intended for use in frontend libpq and client applications. - * Thus, it does not rely on palloc(), elog(), nor vsnprintf(). + * Thus, it does not rely on palloc() nor elog(). + * + * It does rely on vsnprintf(); if configure finds that libc doesn't provide + * a usable vsnprintf(), then a copy of our own implementation of it will + * be linked into libpq. * * Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.1 1999/08/31 01:37:37 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.2 2000/01/17 02:59:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -148,27 +152,47 @@ enlargePQExpBuffer(PQExpBuffer str, int needed) * and insert it into str. More space is allocated to str if necessary. * This is a convenience routine that does the same thing as * resetPQExpBuffer() followed by appendPQExpBuffer(). - * - * CAUTION: the frontend version of this routine WILL FAIL if the result of - * the sprintf formatting operation exceeds 1KB of data (but the size of the - * pre-existing string in the buffer doesn't matter). We could make it - * support larger strings, but that requires vsnprintf() which is not - * universally available. Currently there is no need for long strings to be - * formatted in the frontend. We could support it, if necessary, by - * conditionally including a vsnprintf emulation. */ void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) { va_list args; - char buffer[1024]; - - va_start(args, fmt); - vsprintf(buffer, fmt, args); - va_end(args); + int avail, + nprinted; resetPQExpBuffer(str); - appendPQExpBufferStr(str, buffer); + + for (;;) + { + /*---------- + * Try to format the given string into the available space; + * but if there's hardly any space, don't bother trying, + * just fall through to enlarge the buffer first. + *---------- + */ + avail = str->maxlen - str->len - 1; + if (avail > 16) + { + va_start(args, fmt); + nprinted = vsnprintf(str->data + str->len, avail, + fmt, args); + va_end(args); + /* + * Note: some versions of vsnprintf return the number of chars + * actually stored, but at least one returns -1 on failure. + * Be conservative about believing whether the print worked. + */ + if (nprinted >= 0 && nprinted < avail-1) + { + /* Success. Note nprinted does not include trailing null. */ + str->len += nprinted; + break; + } + } + /* Double the buffer size and try again. */ + if (! enlargePQExpBuffer(str, str->maxlen)) + return; /* oops, out of memory */ + } } /*------------------------ @@ -178,26 +202,45 @@ printfPQExpBuffer(PQExpBuffer str, const char *fmt,...) * and append it to whatever is already in str. More space is allocated * to str if necessary. This is sort of like a combination of sprintf and * strcat. - * - * CAUTION: the frontend version of this routine WILL FAIL if the result of - * the sprintf formatting operation exceeds 1KB of data (but the size of the - * pre-existing string in the buffer doesn't matter). We could make it - * support larger strings, but that requires vsnprintf() which is not - * universally available. Currently there is no need for long strings to be - * formatted in the frontend. We could support it, if necessary, by - * conditionally including a vsnprintf emulation. */ void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...) { va_list args; - char buffer[1024]; - - va_start(args, fmt); - vsprintf(buffer, fmt, args); - va_end(args); + int avail, + nprinted; - appendPQExpBufferStr(str, buffer); + for (;;) + { + /*---------- + * Try to format the given string into the available space; + * but if there's hardly any space, don't bother trying, + * just fall through to enlarge the buffer first. + *---------- + */ + avail = str->maxlen - str->len - 1; + if (avail > 16) + { + va_start(args, fmt); + nprinted = vsnprintf(str->data + str->len, avail, + fmt, args); + va_end(args); + /* + * Note: some versions of vsnprintf return the number of chars + * actually stored, but at least one returns -1 on failure. + * Be conservative about believing whether the print worked. + */ + if (nprinted >= 0 && nprinted < avail-1) + { + /* Success. Note nprinted does not include trailing null. */ + str->len += nprinted; + break; + } + } + /* Double the buffer size and try again. */ + if (! enlargePQExpBuffer(str, str->maxlen)) + return; /* oops, out of memory */ + } } /*------------------------ |