aboutsummaryrefslogtreecommitdiff
path: root/src/backend/lib/stringinfo.c
blob: d5e44ba0f107ae0fc85202c31257ba54642529c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*-------------------------------------------------------------------------
 *
 * stringinfo.c
 *
 * StringInfo 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 palloc().
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *	  $Id: stringinfo.c,v 1.17 1999/05/26 12:55:14 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#include <stdio.h>
#include <string.h>

#include "postgres.h"
#include "lib/stringinfo.h"

#ifdef NOT_USED
/*
 * makeStringInfo
 *
 * Create an empty 'StringInfoData' & return a pointer to it.
 */
StringInfo
makeStringInfo(void)
{
	StringInfo	res;

	res = (StringInfo) palloc(sizeof(StringInfoData));
	if (res == NULL)
		elog(ERROR, "makeStringInfo: Out of memory");

	initStringInfo(res);

	return res;
}
#endif

/*
 * initStringInfo
 *
 * Initialize a StringInfoData struct (with previously undefined contents)
 * to describe an empty string.
 */
void
initStringInfo(StringInfo str)
{
	int			size = 256;		/* initial default buffer size */

	str->data = palloc(size);
	if (str->data == NULL)
		elog(ERROR,
			 "initStringInfo: Out of memory (%d bytes requested)", size);
	str->maxlen = size;
	str->len = 0;
	str->data[0] = '\0';
}

/*
 * enlargeStringInfo
 *
 * Internal routine: make sure there is enough space for 'needed' more bytes
 * ('needed' does not include the terminating null).
 */
static void
enlargeStringInfo(StringInfo str, int needed)
{
	int			newlen;
	char	   *newdata;

	needed += str->len + 1;		/* total space required now */
	if (needed <= str->maxlen)
		return;					/* 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 = 2 * str->maxlen;
	while (needed > newlen)
		newlen = 2 * newlen;

	newdata = palloc(newlen);
	if (newdata == NULL)
		elog(ERROR,
		"enlargeStringInfo: Out of memory (%d bytes requested)", newlen);

	/* OK, transfer data into new buffer, and release old buffer */
	memcpy(newdata, str->data, str->len + 1);
	pfree(str->data);
	str->data = newdata;
	str->maxlen = newlen;
}

/*
 * appendStringInfo
 *
 * 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.
 *
 * CAUTION: the current implementation has a 1K limit on the amount of text
 * generated in a single call (not on the total string length).
 */
void
appendStringInfo(StringInfo str, const char *fmt,...)
{
	va_list		args;
	char		buffer[1024];
	int			buflen;

	Assert(str != NULL);

	va_start(args, fmt);
	buflen = vsnprintf(buffer, sizeof(buffer), fmt, args);
	va_end(args);

	/* Make more room if needed */
	enlargeStringInfo(str, buflen);

	/* OK, append the data, including the trailing null */
	memcpy(str->data + str->len, buffer, buflen + 1);
	str->len += buflen;
}

/*------------------------
 * appendStringInfoChar
 * Append a single byte to str.
 * Like appendStringInfo(str, "%c", ch) but much faster.
 */
void
appendStringInfoChar(StringInfo str, char ch)
{
	Assert(str != NULL);

	/* Make more room if needed */
	enlargeStringInfo(str, 1);

	/* OK, append the character */
	str->data[str->len] = ch;
	str->len++;
	str->data[str->len] = '\0';
}

/*
 * appendBinaryStringInfo
 *
 * Append arbitrary binary data to a StringInfo, allocating more space
 * if necessary.
 */
void
appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
{
	Assert(str != NULL);

	/* Make more room if needed */
	enlargeStringInfo(str, datalen);

	/* 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';
}