summaryrefslogtreecommitdiff
path: root/src/cmd/dist/buf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/dist/buf.c')
-rw-r--r--src/cmd/dist/buf.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c
new file mode 100644
index 000000000..45fb1954d
--- /dev/null
+++ b/src/cmd/dist/buf.c
@@ -0,0 +1,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.
+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);
+ }
+}