]> Pileus Git - ~andy/git/blob - strbuf.c
Makefile: Fix compilation of Windows resource file
[~andy/git] / strbuf.c
1 #include "cache.h"
2 #include "refs.h"
3
4 int starts_with(const char *str, const char *prefix)
5 {
6         for (; ; str++, prefix++)
7                 if (!*prefix)
8                         return 1;
9                 else if (*str != *prefix)
10                         return 0;
11 }
12
13 int prefixcmp(const char *str, const char *prefix)
14 {
15         for (; ; str++, prefix++)
16                 if (!*prefix)
17                         return 0;
18                 else if (*str != *prefix)
19                         return (unsigned char)*prefix - (unsigned char)*str;
20 }
21
22 int ends_with(const char *str, const char *suffix)
23 {
24         int len = strlen(str), suflen = strlen(suffix);
25         if (len < suflen)
26                 return 0;
27         else
28                 return !strcmp(str + len - suflen, suffix);
29 }
30
31 int suffixcmp(const char *str, const char *suffix)
32 {
33         int len = strlen(str), suflen = strlen(suffix);
34         if (len < suflen)
35                 return -1;
36         else
37                 return strcmp(str + len - suflen, suffix);
38 }
39
40 /*
41  * Used as the default ->buf value, so that people can always assume
42  * buf is non NULL and ->buf is NUL terminated even for a freshly
43  * initialized strbuf.
44  */
45 char strbuf_slopbuf[1];
46
47 void strbuf_init(struct strbuf *sb, size_t hint)
48 {
49         sb->alloc = sb->len = 0;
50         sb->buf = strbuf_slopbuf;
51         if (hint)
52                 strbuf_grow(sb, hint);
53 }
54
55 void strbuf_release(struct strbuf *sb)
56 {
57         if (sb->alloc) {
58                 free(sb->buf);
59                 strbuf_init(sb, 0);
60         }
61 }
62
63 char *strbuf_detach(struct strbuf *sb, size_t *sz)
64 {
65         char *res;
66         strbuf_grow(sb, 0);
67         res = sb->buf;
68         if (sz)
69                 *sz = sb->len;
70         strbuf_init(sb, 0);
71         return res;
72 }
73
74 void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
75 {
76         strbuf_release(sb);
77         sb->buf   = buf;
78         sb->len   = len;
79         sb->alloc = alloc;
80         strbuf_grow(sb, 0);
81         sb->buf[sb->len] = '\0';
82 }
83
84 void strbuf_grow(struct strbuf *sb, size_t extra)
85 {
86         int new_buf = !sb->alloc;
87         if (unsigned_add_overflows(extra, 1) ||
88             unsigned_add_overflows(sb->len, extra + 1))
89                 die("you want to use way too much memory");
90         if (new_buf)
91                 sb->buf = NULL;
92         ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
93         if (new_buf)
94                 sb->buf[0] = '\0';
95 }
96
97 void strbuf_trim(struct strbuf *sb)
98 {
99         char *b = sb->buf;
100         while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
101                 sb->len--;
102         while (sb->len > 0 && isspace(*b)) {
103                 b++;
104                 sb->len--;
105         }
106         memmove(sb->buf, b, sb->len);
107         sb->buf[sb->len] = '\0';
108 }
109 void strbuf_rtrim(struct strbuf *sb)
110 {
111         while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
112                 sb->len--;
113         sb->buf[sb->len] = '\0';
114 }
115
116 void strbuf_ltrim(struct strbuf *sb)
117 {
118         char *b = sb->buf;
119         while (sb->len > 0 && isspace(*b)) {
120                 b++;
121                 sb->len--;
122         }
123         memmove(sb->buf, b, sb->len);
124         sb->buf[sb->len] = '\0';
125 }
126
127 struct strbuf **strbuf_split_buf(const char *str, size_t slen,
128                                  int terminator, int max)
129 {
130         struct strbuf **ret = NULL;
131         size_t nr = 0, alloc = 0;
132         struct strbuf *t;
133
134         while (slen) {
135                 int len = slen;
136                 if (max <= 0 || nr + 1 < max) {
137                         const char *end = memchr(str, terminator, slen);
138                         if (end)
139                                 len = end - str + 1;
140                 }
141                 t = xmalloc(sizeof(struct strbuf));
142                 strbuf_init(t, len);
143                 strbuf_add(t, str, len);
144                 ALLOC_GROW(ret, nr + 2, alloc);
145                 ret[nr++] = t;
146                 str += len;
147                 slen -= len;
148         }
149         ALLOC_GROW(ret, nr + 1, alloc); /* In case string was empty */
150         ret[nr] = NULL;
151         return ret;
152 }
153
154 void strbuf_list_free(struct strbuf **sbs)
155 {
156         struct strbuf **s = sbs;
157
158         while (*s) {
159                 strbuf_release(*s);
160                 free(*s++);
161         }
162         free(sbs);
163 }
164
165 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
166 {
167         int len = a->len < b->len ? a->len: b->len;
168         int cmp = memcmp(a->buf, b->buf, len);
169         if (cmp)
170                 return cmp;
171         return a->len < b->len ? -1: a->len != b->len;
172 }
173
174 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
175                                    const void *data, size_t dlen)
176 {
177         if (unsigned_add_overflows(pos, len))
178                 die("you want to use way too much memory");
179         if (pos > sb->len)
180                 die("`pos' is too far after the end of the buffer");
181         if (pos + len > sb->len)
182                 die("`pos + len' is too far after the end of the buffer");
183
184         if (dlen >= len)
185                 strbuf_grow(sb, dlen - len);
186         memmove(sb->buf + pos + dlen,
187                         sb->buf + pos + len,
188                         sb->len - pos - len);
189         memcpy(sb->buf + pos, data, dlen);
190         strbuf_setlen(sb, sb->len + dlen - len);
191 }
192
193 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
194 {
195         strbuf_splice(sb, pos, 0, data, len);
196 }
197
198 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
199 {
200         strbuf_splice(sb, pos, len, NULL, 0);
201 }
202
203 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
204 {
205         strbuf_grow(sb, len);
206         memcpy(sb->buf + sb->len, data, len);
207         strbuf_setlen(sb, sb->len + len);
208 }
209
210 void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
211 {
212         strbuf_grow(sb, len);
213         memcpy(sb->buf + sb->len, sb->buf + pos, len);
214         strbuf_setlen(sb, sb->len + len);
215 }
216
217 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
218 {
219         va_list ap;
220         va_start(ap, fmt);
221         strbuf_vaddf(sb, fmt, ap);
222         va_end(ap);
223 }
224
225 static void add_lines(struct strbuf *out,
226                         const char *prefix1,
227                         const char *prefix2,
228                         const char *buf, size_t size)
229 {
230         while (size) {
231                 const char *prefix;
232                 const char *next = memchr(buf, '\n', size);
233                 next = next ? (next + 1) : (buf + size);
234
235                 prefix = (prefix2 && buf[0] == '\n') ? prefix2 : prefix1;
236                 strbuf_addstr(out, prefix);
237                 strbuf_add(out, buf, next - buf);
238                 size -= next - buf;
239                 buf = next;
240         }
241         strbuf_complete_line(out);
242 }
243
244 void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)
245 {
246         static char prefix1[3];
247         static char prefix2[2];
248
249         if (prefix1[0] != comment_line_char) {
250                 sprintf(prefix1, "%c ", comment_line_char);
251                 sprintf(prefix2, "%c", comment_line_char);
252         }
253         add_lines(out, prefix1, prefix2, buf, size);
254 }
255
256 void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
257 {
258         va_list params;
259         struct strbuf buf = STRBUF_INIT;
260         int incomplete_line = sb->len && sb->buf[sb->len - 1] != '\n';
261
262         va_start(params, fmt);
263         strbuf_vaddf(&buf, fmt, params);
264         va_end(params);
265
266         strbuf_add_commented_lines(sb, buf.buf, buf.len);
267         if (incomplete_line)
268                 sb->buf[--sb->len] = '\0';
269
270         strbuf_release(&buf);
271 }
272
273 void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
274 {
275         int len;
276         va_list cp;
277
278         if (!strbuf_avail(sb))
279                 strbuf_grow(sb, 64);
280         va_copy(cp, ap);
281         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
282         va_end(cp);
283         if (len < 0)
284                 die("BUG: your vsnprintf is broken (returned %d)", len);
285         if (len > strbuf_avail(sb)) {
286                 strbuf_grow(sb, len);
287                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
288                 if (len > strbuf_avail(sb))
289                         die("BUG: your vsnprintf is broken (insatiable)");
290         }
291         strbuf_setlen(sb, sb->len + len);
292 }
293
294 void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
295                    void *context)
296 {
297         for (;;) {
298                 const char *percent;
299                 size_t consumed;
300
301                 percent = strchrnul(format, '%');
302                 strbuf_add(sb, format, percent - format);
303                 if (!*percent)
304                         break;
305                 format = percent + 1;
306
307                 if (*format == '%') {
308                         strbuf_addch(sb, '%');
309                         format++;
310                         continue;
311                 }
312
313                 consumed = fn(sb, format, context);
314                 if (consumed)
315                         format += consumed;
316                 else
317                         strbuf_addch(sb, '%');
318         }
319 }
320
321 size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
322                 void *context)
323 {
324         struct strbuf_expand_dict_entry *e = context;
325         size_t len;
326
327         for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
328                 if (!strncmp(placeholder, e->placeholder, len)) {
329                         if (e->value)
330                                 strbuf_addstr(sb, e->value);
331                         return len;
332                 }
333         }
334         return 0;
335 }
336
337 void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
338 {
339         int i, len = src->len;
340
341         for (i = 0; i < len; i++) {
342                 if (src->buf[i] == '%')
343                         strbuf_addch(dst, '%');
344                 strbuf_addch(dst, src->buf[i]);
345         }
346 }
347
348 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
349 {
350         size_t res;
351         size_t oldalloc = sb->alloc;
352
353         strbuf_grow(sb, size);
354         res = fread(sb->buf + sb->len, 1, size, f);
355         if (res > 0)
356                 strbuf_setlen(sb, sb->len + res);
357         else if (oldalloc == 0)
358                 strbuf_release(sb);
359         return res;
360 }
361
362 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
363 {
364         size_t oldlen = sb->len;
365         size_t oldalloc = sb->alloc;
366
367         strbuf_grow(sb, hint ? hint : 8192);
368         for (;;) {
369                 ssize_t cnt;
370
371                 cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
372                 if (cnt < 0) {
373                         if (oldalloc == 0)
374                                 strbuf_release(sb);
375                         else
376                                 strbuf_setlen(sb, oldlen);
377                         return -1;
378                 }
379                 if (!cnt)
380                         break;
381                 sb->len += cnt;
382                 strbuf_grow(sb, 8192);
383         }
384
385         sb->buf[sb->len] = '\0';
386         return sb->len - oldlen;
387 }
388
389 #define STRBUF_MAXLINK (2*PATH_MAX)
390
391 int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
392 {
393         size_t oldalloc = sb->alloc;
394
395         if (hint < 32)
396                 hint = 32;
397
398         while (hint < STRBUF_MAXLINK) {
399                 int len;
400
401                 strbuf_grow(sb, hint);
402                 len = readlink(path, sb->buf, hint);
403                 if (len < 0) {
404                         if (errno != ERANGE)
405                                 break;
406                 } else if (len < hint) {
407                         strbuf_setlen(sb, len);
408                         return 0;
409                 }
410
411                 /* .. the buffer was too small - try again */
412                 hint *= 2;
413         }
414         if (oldalloc == 0)
415                 strbuf_release(sb);
416         return -1;
417 }
418
419 int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
420 {
421         int ch;
422
423         if (feof(fp))
424                 return EOF;
425
426         strbuf_reset(sb);
427         while ((ch = fgetc(fp)) != EOF) {
428                 strbuf_grow(sb, 1);
429                 sb->buf[sb->len++] = ch;
430                 if (ch == term)
431                         break;
432         }
433         if (ch == EOF && sb->len == 0)
434                 return EOF;
435
436         sb->buf[sb->len] = '\0';
437         return 0;
438 }
439
440 int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
441 {
442         if (strbuf_getwholeline(sb, fp, term))
443                 return EOF;
444         if (sb->buf[sb->len-1] == term)
445                 strbuf_setlen(sb, sb->len-1);
446         return 0;
447 }
448
449 int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
450 {
451         strbuf_reset(sb);
452
453         while (1) {
454                 char ch;
455                 ssize_t len = xread(fd, &ch, 1);
456                 if (len <= 0)
457                         return EOF;
458                 strbuf_addch(sb, ch);
459                 if (ch == term)
460                         break;
461         }
462         return 0;
463 }
464
465 int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
466 {
467         int fd, len;
468
469         fd = open(path, O_RDONLY);
470         if (fd < 0)
471                 return -1;
472         len = strbuf_read(sb, fd, hint);
473         close(fd);
474         if (len < 0)
475                 return -1;
476
477         return len;
478 }
479
480 void strbuf_add_lines(struct strbuf *out, const char *prefix,
481                       const char *buf, size_t size)
482 {
483         add_lines(out, prefix, NULL, buf, size);
484 }
485
486 void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
487 {
488         while (*s) {
489                 size_t len = strcspn(s, "\"<>&");
490                 strbuf_add(buf, s, len);
491                 s += len;
492                 switch (*s) {
493                 case '"':
494                         strbuf_addstr(buf, "&quot;");
495                         break;
496                 case '<':
497                         strbuf_addstr(buf, "&lt;");
498                         break;
499                 case '>':
500                         strbuf_addstr(buf, "&gt;");
501                         break;
502                 case '&':
503                         strbuf_addstr(buf, "&amp;");
504                         break;
505                 case 0:
506                         return;
507                 }
508                 s++;
509         }
510 }
511
512 static int is_rfc3986_reserved(char ch)
513 {
514         switch (ch) {
515                 case '!': case '*': case '\'': case '(': case ')': case ';':
516                 case ':': case '@': case '&': case '=': case '+': case '$':
517                 case ',': case '/': case '?': case '#': case '[': case ']':
518                         return 1;
519         }
520         return 0;
521 }
522
523 static int is_rfc3986_unreserved(char ch)
524 {
525         return isalnum(ch) ||
526                 ch == '-' || ch == '_' || ch == '.' || ch == '~';
527 }
528
529 static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
530                                  int reserved)
531 {
532         strbuf_grow(sb, len);
533         while (len--) {
534                 char ch = *s++;
535                 if (is_rfc3986_unreserved(ch) ||
536                     (!reserved && is_rfc3986_reserved(ch)))
537                         strbuf_addch(sb, ch);
538                 else
539                         strbuf_addf(sb, "%%%02x", ch);
540         }
541 }
542
543 void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
544                              int reserved)
545 {
546         strbuf_add_urlencode(sb, s, strlen(s), reserved);
547 }
548
549 void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
550 {
551         if (bytes > 1 << 30) {
552                 strbuf_addf(buf, "%u.%2.2u GiB",
553                             (int)(bytes >> 30),
554                             (int)(bytes & ((1 << 30) - 1)) / 10737419);
555         } else if (bytes > 1 << 20) {
556                 int x = bytes + 5243;  /* for rounding */
557                 strbuf_addf(buf, "%u.%2.2u MiB",
558                             x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
559         } else if (bytes > 1 << 10) {
560                 int x = bytes + 5;  /* for rounding */
561                 strbuf_addf(buf, "%u.%2.2u KiB",
562                             x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
563         } else {
564                 strbuf_addf(buf, "%u bytes", (int)bytes);
565         }
566 }
567
568 int printf_ln(const char *fmt, ...)
569 {
570         int ret;
571         va_list ap;
572         va_start(ap, fmt);
573         ret = vprintf(fmt, ap);
574         va_end(ap);
575         if (ret < 0 || putchar('\n') == EOF)
576                 return -1;
577         return ret + 1;
578 }
579
580 int fprintf_ln(FILE *fp, const char *fmt, ...)
581 {
582         int ret;
583         va_list ap;
584         va_start(ap, fmt);
585         ret = vfprintf(fp, fmt, ap);
586         va_end(ap);
587         if (ret < 0 || putc('\n', fp) == EOF)
588                 return -1;
589         return ret + 1;
590 }