LCOV - code coverage report
Current view: top level - src/backend/lib - stringinfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 71 74 95.9 %
Date: 2017-09-29 15:12:54 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * stringinfo.c
       4             :  *
       5             :  * StringInfo provides an indefinitely-extensible string data type.
       6             :  * It can be used to buffer either ordinary C strings (null-terminated text)
       7             :  * or arbitrary binary data.  All storage is allocated with palloc().
       8             :  *
       9             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      10             :  * Portions Copyright (c) 1994, Regents of the University of California
      11             :  *
      12             :  *    src/backend/lib/stringinfo.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #include "postgres.h"
      17             : 
      18             : #include "lib/stringinfo.h"
      19             : #include "utils/memutils.h"
      20             : 
      21             : 
      22             : /*
      23             :  * makeStringInfo
      24             :  *
      25             :  * Create an empty 'StringInfoData' & return a pointer to it.
      26             :  */
      27             : StringInfo
      28        4446 : makeStringInfo(void)
      29             : {
      30             :     StringInfo  res;
      31             : 
      32        4446 :     res = (StringInfo) palloc(sizeof(StringInfoData));
      33             : 
      34        4446 :     initStringInfo(res);
      35             : 
      36        4446 :     return res;
      37             : }
      38             : 
      39             : /*
      40             :  * initStringInfo
      41             :  *
      42             :  * Initialize a StringInfoData struct (with previously undefined contents)
      43             :  * to describe an empty string.
      44             :  */
      45             : void
      46      204156 : initStringInfo(StringInfo str)
      47             : {
      48      204156 :     int         size = 1024;    /* initial default buffer size */
      49             : 
      50      204156 :     str->data = (char *) palloc(size);
      51      204156 :     str->maxlen = size;
      52      204156 :     resetStringInfo(str);
      53      204156 : }
      54             : 
      55             : /*
      56             :  * resetStringInfo
      57             :  *
      58             :  * Reset the StringInfo: the data buffer remains valid, but its
      59             :  * previous content, if any, is cleared.
      60             :  */
      61             : void
      62      466202 : resetStringInfo(StringInfo str)
      63             : {
      64      466202 :     str->data[0] = '\0';
      65      466202 :     str->len = 0;
      66      466202 :     str->cursor = 0;
      67      466202 : }
      68             : 
      69             : /*
      70             :  * appendStringInfo
      71             :  *
      72             :  * Format text data under the control of fmt (an sprintf-style format string)
      73             :  * and append it to whatever is already in str.  More space is allocated
      74             :  * to str if necessary.  This is sort of like a combination of sprintf and
      75             :  * strcat.
      76             :  */
      77             : void
      78      264870 : appendStringInfo(StringInfo str, const char *fmt,...)
      79             : {
      80             :     for (;;)
      81             :     {
      82             :         va_list     args;
      83             :         int         needed;
      84             : 
      85             :         /* Try to format the data. */
      86      264870 :         va_start(args, fmt);
      87      264870 :         needed = appendStringInfoVA(str, fmt, args);
      88      264870 :         va_end(args);
      89             : 
      90      264870 :         if (needed == 0)
      91      263995 :             break;              /* success */
      92             : 
      93             :         /* Increase the buffer size and try again. */
      94         875 :         enlargeStringInfo(str, needed);
      95         875 :     }
      96      263995 : }
      97             : 
      98             : /*
      99             :  * appendStringInfoVA
     100             :  *
     101             :  * Attempt to format text data under the control of fmt (an sprintf-style
     102             :  * format string) and append it to whatever is already in str.  If successful
     103             :  * return zero; if not (because there's not enough space), return an estimate
     104             :  * of the space needed, without modifying str.  Typically the caller should
     105             :  * pass the return value to enlargeStringInfo() before trying again; see
     106             :  * appendStringInfo for standard usage pattern.
     107             :  *
     108             :  * XXX This API is ugly, but there seems no alternative given the C spec's
     109             :  * restrictions on what can portably be done with va_list arguments: you have
     110             :  * to redo va_start before you can rescan the argument list, and we can't do
     111             :  * that from here.
     112             :  */
     113             : int
     114      276092 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
     115             : {
     116             :     int         avail;
     117             :     size_t      nprinted;
     118             : 
     119      276092 :     Assert(str != NULL);
     120             : 
     121             :     /*
     122             :      * If there's hardly any space, don't bother trying, just fail to make the
     123             :      * caller enlarge the buffer first.  We have to guess at how much to
     124             :      * enlarge, since we're skipping the formatting work.
     125             :      */
     126      276092 :     avail = str->maxlen - str->len;
     127      276092 :     if (avail < 16)
     128         829 :         return 32;
     129             : 
     130      275263 :     nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
     131             : 
     132      275263 :     if (nprinted < (size_t) avail)
     133             :     {
     134             :         /* Success.  Note nprinted does not include trailing null. */
     135      275206 :         str->len += (int) nprinted;
     136      275206 :         return 0;
     137             :     }
     138             : 
     139             :     /* Restore the trailing null so that str is unmodified. */
     140          57 :     str->data[str->len] = '\0';
     141             : 
     142             :     /*
     143             :      * Return pvsnprintf's estimate of the space needed.  (Although this is
     144             :      * given as a size_t, we know it will fit in int because it's not more
     145             :      * than MaxAllocSize.)
     146             :      */
     147          57 :     return (int) nprinted;
     148             : }
     149             : 
     150             : /*
     151             :  * appendStringInfoString
     152             :  *
     153             :  * Append a null-terminated string to str.
     154             :  * Like appendStringInfo(str, "%s", s) but faster.
     155             :  */
     156             : void
     157      192892 : appendStringInfoString(StringInfo str, const char *s)
     158             : {
     159      192892 :     appendBinaryStringInfo(str, s, strlen(s));
     160      192892 : }
     161             : 
     162             : /*
     163             :  * appendStringInfoChar
     164             :  *
     165             :  * Append a single byte to str.
     166             :  * Like appendStringInfo(str, "%c", ch) but much faster.
     167             :  */
     168             : void
     169      818343 : appendStringInfoChar(StringInfo str, char ch)
     170             : {
     171             :     /* Make more room if needed */
     172      818343 :     if (str->len + 1 >= str->maxlen)
     173         587 :         enlargeStringInfo(str, 1);
     174             : 
     175             :     /* OK, append the character */
     176      818343 :     str->data[str->len] = ch;
     177      818343 :     str->len++;
     178      818343 :     str->data[str->len] = '\0';
     179      818343 : }
     180             : 
     181             : /*
     182             :  * appendStringInfoSpaces
     183             :  *
     184             :  * Append the specified number of spaces to a buffer.
     185             :  */
     186             : void
     187        6672 : appendStringInfoSpaces(StringInfo str, int count)
     188             : {
     189        6672 :     if (count > 0)
     190             :     {
     191             :         /* Make more room if needed */
     192        6621 :         enlargeStringInfo(str, count);
     193             : 
     194             :         /* OK, append the spaces */
     195       60410 :         while (--count >= 0)
     196       47168 :             str->data[str->len++] = ' ';
     197        6621 :         str->data[str->len] = '\0';
     198             :     }
     199        6672 : }
     200             : 
     201             : /*
     202             :  * appendBinaryStringInfo
     203             :  *
     204             :  * Append arbitrary binary data to a StringInfo, allocating more space
     205             :  * if necessary.
     206             :  */
     207             : void
     208      869840 : appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
     209             : {
     210      869840 :     Assert(str != NULL);
     211             : 
     212             :     /* Make more room if needed */
     213      869840 :     enlargeStringInfo(str, datalen);
     214             : 
     215             :     /* OK, append the data */
     216      869840 :     memcpy(str->data + str->len, data, datalen);
     217      869840 :     str->len += datalen;
     218             : 
     219             :     /*
     220             :      * Keep a trailing null in place, even though it's probably useless for
     221             :      * binary data.  (Some callers are dealing with text but call this because
     222             :      * their input isn't null-terminated.)
     223             :      */
     224      869840 :     str->data[str->len] = '\0';
     225      869840 : }
     226             : 
     227             : /*
     228             :  * enlargeStringInfo
     229             :  *
     230             :  * Make sure there is enough space for 'needed' more bytes
     231             :  * ('needed' does not include the terminating null).
     232             :  *
     233             :  * External callers usually need not concern themselves with this, since
     234             :  * all stringinfo.c routines do it automatically.  However, if a caller
     235             :  * knows that a StringInfo will eventually become X bytes large, it
     236             :  * can save some palloc overhead by enlarging the buffer before starting
     237             :  * to store data in it.
     238             :  *
     239             :  * NB: because we use repalloc() to enlarge the buffer, the string buffer
     240             :  * will remain allocated in the same memory context that was current when
     241             :  * initStringInfo was called, even if another context is now current.
     242             :  * This is the desired and indeed critical behavior!
     243             :  */
     244             : void
     245      981872 : enlargeStringInfo(StringInfo str, int needed)
     246             : {
     247             :     int         newlen;
     248             : 
     249             :     /*
     250             :      * Guard against out-of-range "needed" values.  Without this, we can get
     251             :      * an overflow or infinite loop in the following.
     252             :      */
     253      981872 :     if (needed < 0)              /* should not happen */
     254           0 :         elog(ERROR, "invalid string enlargement request size: %d", needed);
     255      981872 :     if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
     256           0 :         ereport(ERROR,
     257             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     258             :                  errmsg("out of memory"),
     259             :                  errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
     260             :                            str->len, needed)));
     261             : 
     262      981872 :     needed += str->len + 1;      /* total space required now */
     263             : 
     264             :     /* Because of the above test, we now have needed <= MaxAllocSize */
     265             : 
     266      981872 :     if (needed <= str->maxlen)
     267     1959186 :         return;                 /* got enough space already */
     268             : 
     269             :     /*
     270             :      * We don't want to allocate just a little more space with each append;
     271             :      * for efficiency, double the buffer size each time it overflows.
     272             :      * Actually, we might need to more than double it if 'needed' is big...
     273             :      */
     274        4558 :     newlen = 2 * str->maxlen;
     275       21192 :     while (needed > newlen)
     276       12076 :         newlen = 2 * newlen;
     277             : 
     278             :     /*
     279             :      * Clamp to MaxAllocSize in case we went past it.  Note we are assuming
     280             :      * here that MaxAllocSize <= INT_MAX/2, else the above loop could
     281             :      * overflow.  We will still have newlen >= needed.
     282             :      */
     283        4558 :     if (newlen > (int) MaxAllocSize)
     284           0 :         newlen = (int) MaxAllocSize;
     285             : 
     286        4558 :     str->data = (char *) repalloc(str->data, newlen);
     287             : 
     288        4558 :     str->maxlen = newlen;
     289             : }

Generated by: LCOV version 1.11