fff3a4867908500e2be669582a8729859b426c34
[public/pyceo-broken.git] / src / strbuf.c
1 /*
2  Copyright (c) 2005-2008 Junio C. Hamano et al.
3
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License (version 2)
6  as published by the Free Software Foundation.
7
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  GNU General Public License for more details.
12
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24
25 #include "strbuf.h"
26 #include "util.h"
27
28 #define die fatal
29
30 #define alloc_nr(x) (((x)+16)*3/2)
31
32 /*
33  *  * Realloc the buffer pointed at by variable 'x' so that it can hold
34  *   * at least 'nr' entries; the number of entries currently allocated
35  *    * is 'alloc', using the standard growing factor alloc_nr() macro.
36  *     *
37  *      * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
38  *       */
39 #define ALLOC_GROW(x, nr, alloc) \
40         do { \
41                     if ((nr) > alloc) { \
42                                     if (alloc_nr(alloc) < (nr)) \
43                                         alloc = (nr); \
44                                     else \
45                                         alloc = alloc_nr(alloc); \
46                                     x = xrealloc((x), alloc * sizeof(*(x))); \
47                                 } \
48                 } while(0)
49
50
51 static inline char *gitstrchrnul(const char *s, int c)
52 {
53         while (*s && *s != c)
54                     s++;
55             return (char *)s;
56 }
57
58
59 int prefixcmp(const char *str, const char *prefix)
60 {
61         for (; ; str++, prefix++)
62                 if (!*prefix)
63                         return 0;
64                 else if (*str != *prefix)
65                         return (unsigned char)*prefix - (unsigned char)*str;
66 }
67
68 /*
69  * Used as the default ->buf value, so that people can always assume
70  * buf is non NULL and ->buf is NUL terminated even for a freshly
71  * initialized strbuf.
72  */
73 char strbuf_slopbuf[1];
74
75 void strbuf_init(struct strbuf *sb, size_t hint)
76 {
77         sb->alloc = sb->len = 0;
78         sb->buf = strbuf_slopbuf;
79         if (hint)
80                 strbuf_grow(sb, hint);
81 }
82
83 void strbuf_release(struct strbuf *sb)
84 {
85         if (sb->alloc) {
86                 free(sb->buf);
87                 strbuf_init(sb, 0);
88         }
89 }
90
91 char *strbuf_detach(struct strbuf *sb, size_t *sz)
92 {
93         char *res = sb->alloc ? sb->buf : NULL;
94         if (sz)
95                 *sz = sb->len;
96         strbuf_init(sb, 0);
97         return res;
98 }
99
100 void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
101 {
102         strbuf_release(sb);
103         sb->buf   = buf;
104         sb->len   = len;
105         sb->alloc = alloc;
106         strbuf_grow(sb, 0);
107         sb->buf[sb->len] = '\0';
108 }
109
110 void strbuf_grow(struct strbuf *sb, size_t extra)
111 {
112         if (sb->len + extra + 1 <= sb->len)
113                 die("you want to use way too much memory");
114         if (!sb->alloc)
115                 sb->buf = NULL;
116         ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
117 }
118
119 void strbuf_trim(struct strbuf *sb)
120 {
121         char *b = sb->buf;
122         while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
123                 sb->len--;
124         while (sb->len > 0 && isspace(*b)) {
125                 b++;
126                 sb->len--;
127         }
128         memmove(sb->buf, b, sb->len);
129         sb->buf[sb->len] = '\0';
130 }
131 void strbuf_rtrim(struct strbuf *sb)
132 {
133         while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
134                 sb->len--;
135         sb->buf[sb->len] = '\0';
136 }
137
138 void strbuf_ltrim(struct strbuf *sb)
139 {
140         char *b = sb->buf;
141         while (sb->len > 0 && isspace(*b)) {
142                 b++;
143                 sb->len--;
144         }
145         memmove(sb->buf, b, sb->len);
146         sb->buf[sb->len] = '\0';
147 }
148
149 void strbuf_tolower(struct strbuf *sb)
150 {
151         int i;
152         for (i = 0; i < sb->len; i++)
153                 sb->buf[i] = tolower(sb->buf[i]);
154 }
155
156 struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
157 {
158         int alloc = 2, pos = 0;
159         char *n, *p;
160         struct strbuf **ret;
161         struct strbuf *t;
162
163         ret = xcalloc(alloc, sizeof(struct strbuf *));
164         p = n = sb->buf;
165         while (n < sb->buf + sb->len) {
166                 int len;
167                 n = memchr(n, delim, sb->len - (n - sb->buf));
168                 if (pos + 1 >= alloc) {
169                         alloc = alloc * 2;
170                         ret = xrealloc(ret, sizeof(struct strbuf *) * alloc);
171                 }
172                 if (!n)
173                         n = sb->buf + sb->len - 1;
174                 len = n - p + 1;
175                 t = xmalloc(sizeof(struct strbuf));
176                 strbuf_init(t, len);
177                 strbuf_add(t, p, len);
178                 ret[pos] = t;
179                 ret[++pos] = NULL;
180                 p = ++n;
181         }
182         return ret;
183 }
184
185 struct strbuf **strbuf_splitws(const struct strbuf *sb)
186 {
187         int alloc = 2, pos = 0;
188         struct strbuf **ret;
189         int prev_ws = 1, ws;
190         int i, start = 0;
191
192         ret = xcalloc(alloc, sizeof(struct strbuf *));
193
194         for (i = 0; i <= sb->len; i++) {
195             ws = !sb->buf[i] || isspace(sb->buf[i]);
196             if (prev_ws == ws)
197                 continue;
198             if (!ws) {
199                 start = i;
200             } else {
201                 if (pos + 1 >= alloc) {
202                     alloc = alloc * 2;
203                     ret = xrealloc(ret, sizeof(struct strbuf *) * alloc);
204                 }
205                 ret[pos] = xmalloc(sizeof(struct strbuf));
206                 strbuf_init(ret[pos], i - start);
207                 strbuf_add(ret[pos], &sb->buf[start], i - start);
208                 pos++;
209             }
210             prev_ws = ws;
211         }
212
213         ret[pos] = NULL;
214         return ret;
215 }
216
217 void strbuf_list_free(struct strbuf **sbs)
218 {
219         struct strbuf **s = sbs;
220
221         while (*s) {
222                 strbuf_release(*s);
223                 free(*s++);
224         }
225         free(sbs);
226 }
227
228 size_t strbuf_list_len(struct strbuf **sbs)
229 {
230     size_t n = 0;
231     while (*sbs++)
232         n++;
233     return n;
234 }
235
236 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
237 {
238         int cmp;
239         if (a->len < b->len) {
240                 cmp = memcmp(a->buf, b->buf, a->len);
241                 return cmp ? cmp : -1;
242         } else {
243                 cmp = memcmp(a->buf, b->buf, b->len);
244                 return cmp ? cmp : a->len != b->len;
245         }
246 }
247
248 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
249                                    const void *data, size_t dlen)
250 {
251         if (pos + len < pos)
252                 die("you want to use way too much memory");
253         if (pos > sb->len)
254                 die("`pos' is too far after the end of the buffer");
255         if (pos + len > sb->len)
256                 die("`pos + len' is too far after the end of the buffer");
257
258         if (dlen >= len)
259                 strbuf_grow(sb, dlen - len);
260         memmove(sb->buf + pos + dlen,
261                         sb->buf + pos + len,
262                         sb->len - pos - len);
263         memcpy(sb->buf + pos, data, dlen);
264         strbuf_setlen(sb, sb->len + dlen - len);
265 }
266
267 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
268 {
269         strbuf_splice(sb, pos, 0, data, len);
270 }
271
272 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
273 {
274         strbuf_splice(sb, pos, len, NULL, 0);
275 }
276
277 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
278 {
279         strbuf_grow(sb, len);
280         memcpy(sb->buf + sb->len, data, len);
281         strbuf_setlen(sb, sb->len + len);
282 }
283
284 void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
285 {
286         strbuf_grow(sb, len);
287         memcpy(sb->buf + sb->len, sb->buf + pos, len);
288         strbuf_setlen(sb, sb->len + len);
289 }
290
291 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
292 {
293         int len;
294         va_list ap;
295
296         if (!strbuf_avail(sb))
297                 strbuf_grow(sb, 64);
298         va_start(ap, fmt);
299         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
300         va_end(ap);
301         if (len < 0)
302                 die("your vsnprintf is broken");
303         if (len > strbuf_avail(sb)) {
304                 strbuf_grow(sb, len);
305                 va_start(ap, fmt);
306                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
307                 va_end(ap);
308                 if (len > strbuf_avail(sb)) {
309                         die("this should not happen, your snprintf is broken");
310                 }
311         }
312         strbuf_setlen(sb, sb->len + len);
313 }
314
315 void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
316                    void *context)
317 {
318         for (;;) {
319                 const char *percent;
320                 size_t consumed;
321
322                 percent = gitstrchrnul(format, '%');
323                 strbuf_add(sb, format, percent - format);
324                 if (!*percent)
325                         break;
326                 format = percent + 1;
327
328                 consumed = fn(sb, format, context);
329                 if (consumed)
330                         format += consumed;
331                 else
332                         strbuf_addch(sb, '%');
333         }
334 }
335
336 size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
337                 void *context)
338 {
339         struct strbuf_expand_dict_entry *e = context;
340         size_t len;
341
342         for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
343                 if (!strncmp(placeholder, e->placeholder, len)) {
344                         if (e->value)
345                                 strbuf_addstr(sb, e->value);
346                         return len;
347                 }
348         }
349         return 0;
350 }
351
352 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
353 {
354         size_t res;
355
356         strbuf_grow(sb, size);
357         res = fread(sb->buf + sb->len, 1, size, f);
358         if (res > 0) {
359                 strbuf_setlen(sb, sb->len + res);
360         }
361         return res;
362 }
363
364 ssize_t strbuf_write(struct strbuf *sb, int fd) {
365     ssize_t total = 0;
366
367     while (total < sb->len) {
368         ssize_t cnt = write(fd, sb->buf + total, sb->len - total);
369         if (cnt <= 0)
370             return -1;
371         total += cnt;
372     }
373
374     return total;
375 }
376
377 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
378 {
379         size_t oldlen = sb->len;
380
381         strbuf_grow(sb, hint ? hint : 8192);
382         for (;;) {
383                 ssize_t cnt;
384
385                 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
386                 if (cnt < 0) {
387                         strbuf_setlen(sb, oldlen);
388                         return -1;
389                 }
390                 if (!cnt)
391                         break;
392                 sb->len += cnt;
393                 strbuf_grow(sb, 8192);
394         }
395
396         sb->buf[sb->len] = '\0';
397         return sb->len - oldlen;
398 }
399
400 int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
401 {
402         int ch;
403
404         strbuf_grow(sb, 0);
405         if (feof(fp))
406                 return EOF;
407
408         strbuf_reset(sb);
409         while ((ch = fgetc(fp)) != EOF) {
410                 if (ch == term)
411                         break;
412                 strbuf_grow(sb, 1);
413                 sb->buf[sb->len++] = ch;
414         }
415         if (ch == EOF && sb->len == 0)
416                 return EOF;
417
418         sb->buf[sb->len] = '\0';
419         return 0;
420 }
421
422 int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
423 {
424         int fd, len;
425
426         fd = open(path, O_RDONLY);
427         if (fd < 0)
428                 return -1;
429         len = strbuf_read(sb, fd, hint);
430         close(fd);
431         if (len < 0)
432                 return -1;
433
434         return len;
435 }