Fix library check in and search bug.
[mspang/pyceo.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_vaddf(struct strbuf *sb, const char *fmt, va_list args)
316 {
317         int len;
318         va_list ap;
319
320         va_copy(ap, args);
321         if (!strbuf_avail(sb))
322                 strbuf_grow(sb, 64);
323         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
324
325         va_copy(ap, args);
326         if (len < 0)
327                 die("your vsnprintf is broken");
328         if (len > strbuf_avail(sb)) {
329                 strbuf_grow(sb, len);
330                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
331                 if (len > strbuf_avail(sb)) {
332                         die("this should not happen, your snprintf is broken");
333                 }
334         }
335         strbuf_setlen(sb, sb->len + len);
336 }
337
338 void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
339                    void *context)
340 {
341         for (;;) {
342                 const char *percent;
343                 size_t consumed;
344
345                 percent = gitstrchrnul(format, '%');
346                 strbuf_add(sb, format, percent - format);
347                 if (!*percent)
348                         break;
349                 format = percent + 1;
350
351                 consumed = fn(sb, format, context);
352                 if (consumed)
353                         format += consumed;
354                 else
355                         strbuf_addch(sb, '%');
356         }
357 }
358
359 size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
360                 void *context)
361 {
362         struct strbuf_expand_dict_entry *e = context;
363         size_t len;
364
365         for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
366                 if (!strncmp(placeholder, e->placeholder, len)) {
367                         if (e->value)
368                                 strbuf_addstr(sb, e->value);
369                         return len;
370                 }
371         }
372         return 0;
373 }
374
375 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
376 {
377         size_t res;
378
379         strbuf_grow(sb, size);
380         res = fread(sb->buf + sb->len, 1, size, f);
381         if (res > 0) {
382                 strbuf_setlen(sb, sb->len + res);
383         }
384         return res;
385 }
386
387 ssize_t strbuf_write(struct strbuf *sb, int fd) {
388     ssize_t total = 0;
389
390     while (total < sb->len) {
391         ssize_t cnt = write(fd, sb->buf + total, sb->len - total);
392         if (cnt <= 0)
393             return -1;
394         total += cnt;
395     }
396
397     return total;
398 }
399
400 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
401 {
402         size_t oldlen = sb->len;
403
404         strbuf_grow(sb, hint ? hint : 8192);
405         for (;;) {
406                 ssize_t cnt;
407
408                 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
409                 if (cnt < 0) {
410                         strbuf_setlen(sb, oldlen);
411                         return -1;
412                 }
413                 if (!cnt)
414                         break;
415                 sb->len += cnt;
416                 strbuf_grow(sb, 8192);
417         }
418
419         sb->buf[sb->len] = '\0';
420         return sb->len - oldlen;
421 }
422
423 int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
424 {
425         int ch;
426
427         strbuf_grow(sb, 0);
428         if (feof(fp))
429                 return EOF;
430
431         strbuf_reset(sb);
432         while ((ch = fgetc(fp)) != EOF) {
433                 if (ch == term)
434                         break;
435                 strbuf_grow(sb, 1);
436                 sb->buf[sb->len++] = ch;
437         }
438         if (ch == EOF && sb->len == 0)
439                 return EOF;
440
441         sb->buf[sb->len] = '\0';
442         return 0;
443 }
444
445 int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
446 {
447         int fd, len;
448
449         fd = open(path, O_RDONLY);
450         if (fd < 0)
451                 return -1;
452         len = strbuf_read(sb, fd, hint);
453         close(fd);
454         if (len < 0)
455                 return -1;
456
457         return len;
458 }