summaryrefslogtreecommitdiff
path: root/src/cmd/dist/buf.c
blob: 2ddc6be7520243a51faf689de810caa48b24c806 (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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Byte buffers and string vectors.

#include "a.h"

// binit prepares an uninitialized buffer for use.
void
binit(Buf *b)
{
	b->p = nil;
	b->len = 0;
	b->cap = 0;
}

// breset truncates the buffer back to zero length.
void
breset(Buf *b)
{
	b->len = 0;
}

// bfree frees the storage associated with a buffer.
void
bfree(Buf *b)
{
	xfree(b->p);
	binit(b);
}

// bgrow ensures that the buffer has at least n more bytes
// between its len and cap.
void
bgrow(Buf *b, int n)
{
	int want;
	
	want = b->len+n;
	if(want > b->cap) {
		b->cap = 2*want;
		if(b->cap < 64)
			b->cap = 64;
		b->p = xrealloc(b->p, b->cap);
	}
}

// bwrite appends the n bytes at v to the buffer.
void
bwrite(Buf *b, void *v, int n)
{
	bgrow(b, n);
	xmemmove(b->p+b->len, v, n);
	b->len += n;
}

// bwritestr appends the string p to the buffer.
void
bwritestr(Buf *b, char *p)
{
	bwrite(b, p, xstrlen(p));
}

// bstr returns a pointer to a NUL-terminated string of the
// buffer contents.  The pointer points into the buffer.
char*
bstr(Buf *b)
{
	bgrow(b, 1);
	b->p[b->len] = '\0';
	return b->p;
}

// btake takes ownership of the string form of the buffer.
// After this call, the buffer has zero length and does not
// refer to the memory that btake returned.
char*
btake(Buf *b)
{
	char *p;
	
	p = bstr(b);
	binit(b);
	return p;
}

// bwriteb appends the src buffer to the dst buffer.
void
bwriteb(Buf *dst, Buf *src)
{
	bwrite(dst, src->p, src->len);
}

// bequal reports whether the buffers have the same content.
bool
bequal(Buf *s, Buf *t)
{
	return s->len == t->len && xmemcmp(s->p, t->p, s->len) == 0;
}

// bsubst rewites b to replace all occurrences of x with y.
void
bsubst(Buf *b, char *x, char *y)
{
	char *p;
	int nx, ny, pos;

	nx = xstrlen(x);
	ny = xstrlen(y);

	pos = 0;
	for(;;) {
		p = xstrstr(bstr(b)+pos, x);
		if(p == nil)
			break;
		if(nx != ny) {
			if(nx < ny) {
				pos = p - b->p;
				bgrow(b, ny-nx);
				p = b->p + pos;
			}
			xmemmove(p+ny, p+nx, (b->p+b->len)-(p+nx));
		}
		xmemmove(p, y, ny);
		pos = p+ny - b->p;
		b->len += ny - nx;
	}
}

// The invariant with the vectors is that v->p[0:v->len] is allocated
// strings that are owned by the vector.  The data beyond v->len may
// be garbage.

// vinit prepares an uninitialized vector for use.
void
vinit(Vec *v)
{
	v->p = nil;
	v->len = 0;
	v->cap = 0;
}

// vreset truncates the vector back to zero length.
void
vreset(Vec *v)
{
	int i;
	
	for(i=0; i<v->len; i++) {
		xfree(v->p[i]);
		v->p[i] = nil;
	}
	v->len = 0;
}

// vfree frees the storage associated with the vector.
void
vfree(Vec *v)
{
	vreset(v);
	xfree(v->p);
	vinit(v);
}


// vgrow ensures that the vector has room for at least 
// n more entries between len and cap.
void
vgrow(Vec *v, int n)
{
	int want;
	
	want = v->len+n;
	if(want > v->cap) {
		v->cap = 2*want;
		if(v->cap < 64)
			v->cap = 64;
		v->p = xrealloc(v->p, v->cap*sizeof v->p[0]);
	}
}

// vcopy copies the srclen strings at src into the vector.
void
vcopy(Vec *dst, char **src, int srclen)
{
	int i;
	
	// use vadd, to make copies of strings
	for(i=0; i<srclen; i++)
		vadd(dst, src[i]);
}

// vadd adds a copy of the string p to the vector.
void
vadd(Vec *v, char *p)
{
	vgrow(v, 1);
	if(p != nil)
		p = xstrdup(p);
	v->p[v->len++] = p;
}

// vaddn adds a string consisting of the n bytes at p to the vector.
static void
vaddn(Vec *v, char *p, int n)
{
	char *q;

	vgrow(v, 1);
	q = xmalloc(n+1);
	xmemmove(q, p, n);
	q[n] = '\0';
	v->p[v->len++] = q;
}

static int
strpcmp(const void *a, const void *b)
{
	return xstrcmp(*(char**)a, *(char**)b);
}

// vuniq sorts the vector and then discards duplicates,
// in the manner of sort | uniq.
void
vuniq(Vec *v)
{
	int i, n;

	xqsort(v->p, v->len, sizeof(v->p[0]), strpcmp);
	n = 0;
	for(i=0; i<v->len; i++) {
		if(n>0 && streq(v->p[i], v->p[n-1]))
			xfree(v->p[i]);
		else
			v->p[n++] = v->p[i];
	}
	v->len = n;
}

// splitlines replaces the vector v with the result of splitting
// the input p after each \n.
void
splitlines(Vec *v, char *p)
{
	int i;
	char *start;
	
	vreset(v);
	start = p;
	for(i=0; p[i]; i++) {
		if(p[i] == '\n') {
			vaddn(v, start, (p+i+1)-start);
			start = p+i+1;
		}
	}
	if(*start != '\0')
		vadd(v, start);
}

// splitfields replaces the vector v with the result of splitting
// the input p into non-empty fields containing no spaces.
void
splitfields(Vec *v, char *p)
{
	char *start;

	vreset(v);
	for(;;) {
		while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
			p++;
		if(*p == '\0')
			break;
		start = p;
		while(*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\0')
			p++;
		vaddn(v, start, p-start);
	}
}