summaryrefslogtreecommitdiff
path: root/libpq/pqexpbuffer.c
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-11-30 22:37:25 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-12-06 15:11:04 +0300
commitf1f39911e0d2d88c98eae96a3eb14a53c664206f (patch)
tree4cf4e3a84d895f59323d3b6ab4bfab38b3cab489 /libpq/pqexpbuffer.c
parentfc9499b8a7b7a3e350bfabf2cd6ae0bc13f04bea (diff)
Upgrade to 12.1
Diffstat (limited to 'libpq/pqexpbuffer.c')
-rw-r--r--libpq/pqexpbuffer.c430
1 files changed, 0 insertions, 430 deletions
diff --git a/libpq/pqexpbuffer.c b/libpq/pqexpbuffer.c
deleted file mode 100644
index 8d82d5c..0000000
--- a/libpq/pqexpbuffer.c
+++ /dev/null
@@ -1,430 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pqexpbuffer.c
- *
- * PQExpBuffer provides an indefinitely-extensible string data type.
- * It can be used to buffer either ordinary C strings (null-terminated text)
- * or arbitrary binary data. All storage is allocated with malloc().
- *
- * 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() nor elog(), nor psprintf.c which
- * will exit() on error.
- *
- * 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.
- *
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/interfaces/libpq/pqexpbuffer.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres_fe.h"
-
-#include <limits.h>
-
-#include "pqexpbuffer.h"
-
-#ifdef WIN32
-#include "win32.h"
-#endif
-
-
-/* All "broken" PQExpBuffers point to this string. */
-static const char oom_buffer[1] = "";
-
-static bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args) pg_attribute_printf(2, 0);
-
-
-/*
- * markPQExpBufferBroken
- *
- * Put a PQExpBuffer in "broken" state if it isn't already.
- */
-static void
-markPQExpBufferBroken(PQExpBuffer str)
-{
- if (str->data != oom_buffer)
- free(str->data);
-
- /*
- * Casting away const here is a bit ugly, but it seems preferable to not
- * marking oom_buffer const. We want to do that to encourage the compiler
- * to put oom_buffer in read-only storage, so that anyone who tries to
- * scribble on a broken PQExpBuffer will get a failure.
- */
- str->data = (char *) oom_buffer;
- str->len = 0;
- str->maxlen = 0;
-}
-
-/*
- * createPQExpBuffer
- *
- * Create an empty 'PQExpBufferData' & return a pointer to it.
- */
-PQExpBuffer
-createPQExpBuffer(void)
-{
- PQExpBuffer res;
-
- res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
- if (res != NULL)
- initPQExpBuffer(res);
-
- return res;
-}
-
-/*
- * initPQExpBuffer
- *
- * Initialize a PQExpBufferData struct (with previously undefined contents)
- * to describe an empty string.
- */
-void
-initPQExpBuffer(PQExpBuffer str)
-{
- str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
- if (str->data == NULL)
- {
- str->data = (char *) oom_buffer; /* see comment above */
- str->maxlen = 0;
- str->len = 0;
- }
- else
- {
- str->maxlen = INITIAL_EXPBUFFER_SIZE;
- str->len = 0;
- str->data[0] = '\0';
- }
-}
-
-/*
- * destroyPQExpBuffer(str);
- *
- * free()s both the data buffer and the PQExpBufferData.
- * This is the inverse of createPQExpBuffer().
- */
-void
-destroyPQExpBuffer(PQExpBuffer str)
-{
- if (str)
- {
- termPQExpBuffer(str);
- free(str);
- }
-}
-
-/*
- * termPQExpBuffer(str)
- * free()s the data buffer but not the PQExpBufferData itself.
- * This is the inverse of initPQExpBuffer().
- */
-void
-termPQExpBuffer(PQExpBuffer str)
-{
- if (str->data != oom_buffer)
- free(str->data);
- /* just for luck, make the buffer validly empty. */
- str->data = (char *) oom_buffer; /* see comment above */
- str->maxlen = 0;
- str->len = 0;
-}
-
-/*
- * resetPQExpBuffer
- * Reset a PQExpBuffer to empty
- *
- * Note: if possible, a "broken" PQExpBuffer is returned to normal.
- */
-void
-resetPQExpBuffer(PQExpBuffer str)
-{
- if (str)
- {
- if (str->data != oom_buffer)
- {
- str->len = 0;
- str->data[0] = '\0';
- }
- else
- {
- /* try to reinitialize to valid state */
- initPQExpBuffer(str);
- }
- }
-}
-
-/*
- * enlargePQExpBuffer
- * Make sure there is enough space for 'needed' more bytes in the buffer
- * ('needed' does not include the terminating null).
- *
- * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
- * the buffer is left in "broken" state.)
- */
-int
-enlargePQExpBuffer(PQExpBuffer str, size_t needed)
-{
- size_t newlen;
- char *newdata;
-
- if (PQExpBufferBroken(str))
- return 0; /* already failed */
-
- /*
- * Guard against ridiculous "needed" values, which can occur if we're fed
- * bogus data. Without this, we can get an overflow or infinite loop in
- * the following.
- */
- if (needed >= ((size_t) INT_MAX - str->len))
- {
- markPQExpBufferBroken(str);
- return 0;
- }
-
- needed += str->len + 1; /* total space required now */
-
- /* Because of the above test, we now have needed <= INT_MAX */
-
- if (needed <= str->maxlen)
- return 1; /* got enough space already */
-
- /*
- * We don't want to allocate just a little more space with each append;
- * for efficiency, double the buffer size each time it overflows.
- * Actually, we might need to more than double it if 'needed' is big...
- */
- newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
- while (needed > newlen)
- newlen = 2 * newlen;
-
- /*
- * Clamp to INT_MAX in case we went past it. Note we are assuming here
- * that INT_MAX <= UINT_MAX/2, else the above loop could overflow. We
- * will still have newlen >= needed.
- */
- if (newlen > (size_t) INT_MAX)
- newlen = (size_t) INT_MAX;
-
- newdata = (char *) realloc(str->data, newlen);
- if (newdata != NULL)
- {
- str->data = newdata;
- str->maxlen = newlen;
- return 1;
- }
-
- markPQExpBufferBroken(str);
- return 0;
-}
-
-/*
- * printfPQExpBuffer
- * Format text data under the control of fmt (an sprintf-like format string)
- * 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().
- */
-void
-printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
-{
- va_list args;
- bool done;
-
- resetPQExpBuffer(str);
-
- if (PQExpBufferBroken(str))
- return; /* already failed */
-
- /* Loop in case we have to retry after enlarging the buffer. */
- do
- {
- va_start(args, fmt);
- done = appendPQExpBufferVA(str, fmt, args);
- va_end(args);
- } while (!done);
-}
-
-/*
- * appendPQExpBuffer
- *
- * Format text data under the control of fmt (an sprintf-like format string)
- * 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.
- */
-void
-appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
-{
- va_list args;
- bool done;
-
- if (PQExpBufferBroken(str))
- return; /* already failed */
-
- /* Loop in case we have to retry after enlarging the buffer. */
- do
- {
- va_start(args, fmt);
- done = appendPQExpBufferVA(str, fmt, args);
- va_end(args);
- } while (!done);
-}
-
-/*
- * appendPQExpBufferVA
- * Shared guts of printfPQExpBuffer/appendPQExpBuffer.
- * Attempt to format data and append it to str. Returns true if done
- * (either successful or hard failure), false if need to retry.
- */
-static bool
-appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args)
-{
- size_t avail;
- size_t needed;
- int nprinted;
-
- /*
- * Try to format the given string into the available space; but if there's
- * hardly any space, don't bother trying, just enlarge the buffer first.
- */
- if (str->maxlen > str->len + 16)
- {
- /*
- * Note: we intentionally leave one byte unused, as a guard against
- * old broken versions of vsnprintf.
- */
- avail = str->maxlen - str->len - 1;
-
- errno = 0;
-
- nprinted = vsnprintf(str->data + str->len, avail, fmt, args);
-
- /*
- * If vsnprintf reports an error other than ENOMEM, fail.
- */
- if (nprinted < 0 && errno != 0 && errno != ENOMEM)
- {
- markPQExpBufferBroken(str);
- return true;
- }
-
- /*
- * Note: some versions of vsnprintf return the number of chars
- * actually stored, not the total space needed as C99 specifies. And
- * at least one returns -1 on failure. Be conservative about
- * believing whether the print worked.
- */
- if (nprinted >= 0 && (size_t) nprinted < avail - 1)
- {
- /* Success. Note nprinted does not include trailing null. */
- str->len += nprinted;
- return true;
- }
-
- if (nprinted >= 0 && (size_t) nprinted > avail)
- {
- /*
- * This appears to be a C99-compliant vsnprintf, so believe its
- * estimate of the required space. (If it's wrong, the logic will
- * still work, but we may loop multiple times.) Note that the
- * space needed should be only nprinted+1 bytes, but we'd better
- * allocate one more than that so that the test above will succeed
- * next time.
- *
- * In the corner case where the required space just barely
- * overflows, fail.
- */
- if (nprinted > INT_MAX - 2)
- {
- markPQExpBufferBroken(str);
- return true;
- }
- needed = nprinted + 2;
- }
- else
- {
- /*
- * Buffer overrun, and we don't know how much space is needed.
- * Estimate twice the previous buffer size, but not more than
- * INT_MAX.
- */
- if (avail >= INT_MAX / 2)
- needed = INT_MAX;
- else
- needed = avail * 2;
- }
- }
- else
- {
- /*
- * We have to guess at how much to enlarge, since we're skipping the
- * formatting work.
- */
- needed = 32;
- }
-
- /* Increase the buffer size and try again. */
- if (!enlargePQExpBuffer(str, needed))
- return true; /* oops, out of memory */
-
- return false;
-}
-
-/*
- * appendPQExpBufferStr
- * Append the given string to a PQExpBuffer, allocating more space
- * if necessary.
- */
-void
-appendPQExpBufferStr(PQExpBuffer str, const char *data)
-{
- appendBinaryPQExpBuffer(str, data, strlen(data));
-}
-
-/*
- * appendPQExpBufferChar
- * Append a single byte to str.
- * Like appendPQExpBuffer(str, "%c", ch) but much faster.
- */
-void
-appendPQExpBufferChar(PQExpBuffer str, char ch)
-{
- /* Make more room if needed */
- if (!enlargePQExpBuffer(str, 1))
- return;
-
- /* OK, append the character */
- str->data[str->len] = ch;
- str->len++;
- str->data[str->len] = '\0';
-}
-
-/*
- * appendBinaryPQExpBuffer
- *
- * Append arbitrary binary data to a PQExpBuffer, allocating more space
- * if necessary.
- */
-void
-appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
-{
- /* Make more room if needed */
- if (!enlargePQExpBuffer(str, datalen))
- return;
-
- /* OK, append the data */
- memcpy(str->data + str->len, data, datalen);
- str->len += datalen;
-
- /*
- * Keep a trailing null in place, even though it's probably useless for
- * binary data...
- */
- str->data[str->len] = '\0';
-}