| // 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); | |
| } | |
| } |