Work around curl-gnutls not liking to be reinitialized
[git] / strbuf.c
1 #include "cache.h"
2
3 int prefixcmp(const char *str, const char *prefix)
4 {
5         for (; ; str++, prefix++)
6                 if (!*prefix)
7                         return 0;
8                 else if (*str != *prefix)
9                         return (unsigned char)*prefix - (unsigned char)*str;
10 }
11
12 /*
13  * Used as the default ->buf value, so that people can always assume
14  * buf is non NULL and ->buf is NUL terminated even for a freshly
15  * initialized strbuf.
16  */
17 char strbuf_slopbuf[1];
18
19 void strbuf_init(struct strbuf *sb, size_t hint)
20 {
21         sb->alloc = sb->len = 0;
22         sb->buf = strbuf_slopbuf;
23         if (hint)
24                 strbuf_grow(sb, hint);
25 }
26
27 void strbuf_release(struct strbuf *sb)
28 {
29         if (sb->alloc) {
30                 free(sb->buf);
31                 strbuf_init(sb, 0);
32         }
33 }
34
35 char *strbuf_detach(struct strbuf *sb, size_t *sz)
36 {
37         char *res = sb->alloc ? sb->buf : NULL;
38         if (sz)
39                 *sz = sb->len;
40         strbuf_init(sb, 0);
41         return res;
42 }
43
44 void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
45 {
46         strbuf_release(sb);
47         sb->buf   = buf;
48         sb->len   = len;
49         sb->alloc = alloc;
50         strbuf_grow(sb, 0);
51         sb->buf[sb->len] = '\0';
52 }
53
54 void strbuf_grow(struct strbuf *sb, size_t extra)
55 {
56         if (sb->len + extra + 1 <= sb->len)
57                 die("you want to use way too much memory");
58         if (!sb->alloc)
59                 sb->buf = NULL;
60         ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
61 }
62
63 void strbuf_rtrim(struct strbuf *sb)
64 {
65         while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
66                 sb->len--;
67         sb->buf[sb->len] = '\0';
68 }
69
70 int strbuf_cmp(struct strbuf *a, struct strbuf *b)
71 {
72         int cmp;
73         if (a->len < b->len) {
74                 cmp = memcmp(a->buf, b->buf, a->len);
75                 return cmp ? cmp : -1;
76         } else {
77                 cmp = memcmp(a->buf, b->buf, b->len);
78                 return cmp ? cmp : a->len != b->len;
79         }
80 }
81
82 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
83                                    const void *data, size_t dlen)
84 {
85         if (pos + len < pos)
86                 die("you want to use way too much memory");
87         if (pos > sb->len)
88                 die("`pos' is too far after the end of the buffer");
89         if (pos + len > sb->len)
90                 die("`pos + len' is too far after the end of the buffer");
91
92         if (dlen >= len)
93                 strbuf_grow(sb, dlen - len);
94         memmove(sb->buf + pos + dlen,
95                         sb->buf + pos + len,
96                         sb->len - pos - len);
97         memcpy(sb->buf + pos, data, dlen);
98         strbuf_setlen(sb, sb->len + dlen - len);
99 }
100
101 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
102 {
103         strbuf_splice(sb, pos, 0, data, len);
104 }
105
106 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
107 {
108         strbuf_splice(sb, pos, len, NULL, 0);
109 }
110
111 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
112 {
113         strbuf_grow(sb, len);
114         memcpy(sb->buf + sb->len, data, len);
115         strbuf_setlen(sb, sb->len + len);
116 }
117
118 void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
119 {
120         strbuf_grow(sb, len);
121         memcpy(sb->buf + sb->len, sb->buf + pos, len);
122         strbuf_setlen(sb, sb->len + len);
123 }
124
125 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
126 {
127         int len;
128         va_list ap;
129
130         if (!strbuf_avail(sb))
131                 strbuf_grow(sb, 64);
132         va_start(ap, fmt);
133         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
134         va_end(ap);
135         if (len < 0)
136                 die("your vsnprintf is broken");
137         if (len > strbuf_avail(sb)) {
138                 strbuf_grow(sb, len);
139                 va_start(ap, fmt);
140                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
141                 va_end(ap);
142                 if (len > strbuf_avail(sb)) {
143                         die("this should not happen, your snprintf is broken");
144                 }
145         }
146         strbuf_setlen(sb, sb->len + len);
147 }
148
149 void strbuf_expand(struct strbuf *sb, const char *format,
150                    const char **placeholders, expand_fn_t fn, void *context)
151 {
152         for (;;) {
153                 const char *percent, **p;
154
155                 percent = strchrnul(format, '%');
156                 strbuf_add(sb, format, percent - format);
157                 if (!*percent)
158                         break;
159                 format = percent + 1;
160
161                 for (p = placeholders; *p; p++) {
162                         if (!prefixcmp(format, *p))
163                                 break;
164                 }
165                 if (*p) {
166                         fn(sb, *p, context);
167                         format += strlen(*p);
168                 } else
169                         strbuf_addch(sb, '%');
170         }
171 }
172
173 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
174 {
175         size_t res;
176
177         strbuf_grow(sb, size);
178         res = fread(sb->buf + sb->len, 1, size, f);
179         if (res > 0) {
180                 strbuf_setlen(sb, sb->len + res);
181         }
182         return res;
183 }
184
185 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
186 {
187         size_t oldlen = sb->len;
188
189         strbuf_grow(sb, hint ? hint : 8192);
190         for (;;) {
191                 ssize_t cnt;
192
193                 cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
194                 if (cnt < 0) {
195                         strbuf_setlen(sb, oldlen);
196                         return -1;
197                 }
198                 if (!cnt)
199                         break;
200                 sb->len += cnt;
201                 strbuf_grow(sb, 8192);
202         }
203
204         sb->buf[sb->len] = '\0';
205         return sb->len - oldlen;
206 }
207
208 int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
209 {
210         int ch;
211
212         strbuf_grow(sb, 0);
213         if (feof(fp))
214                 return EOF;
215
216         strbuf_reset(sb);
217         while ((ch = fgetc(fp)) != EOF) {
218                 if (ch == term)
219                         break;
220                 strbuf_grow(sb, 1);
221                 sb->buf[sb->len++] = ch;
222         }
223         if (ch == EOF && sb->len == 0)
224                 return EOF;
225
226         sb->buf[sb->len] = '\0';
227         return 0;
228 }
229
230 int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
231 {
232         int fd, len;
233
234         fd = open(path, O_RDONLY);
235         if (fd < 0)
236                 return -1;
237         len = strbuf_read(sb, fd, hint);
238         close(fd);
239         if (len < 0)
240                 return -1;
241
242         return len;
243 }