replace has_extension with ends_with
[git.git] / strbuf.c
blob63356ccd1b60bfddbff3dcb1d816d3e0f0d16ce4
1 #include "cache.h"
2 #include "refs.h"
4 int starts_with(const char *str, const char *prefix)
6 for (; ; str++, prefix++)
7 if (!*prefix)
8 return 1;
9 else if (*str != *prefix)
10 return 0;
14 * Used as the default ->buf value, so that people can always assume
15 * buf is non NULL and ->buf is NUL terminated even for a freshly
16 * initialized strbuf.
18 char strbuf_slopbuf[1];
20 void strbuf_init(struct strbuf *sb, size_t hint)
22 sb->alloc = sb->len = 0;
23 sb->buf = strbuf_slopbuf;
24 if (hint)
25 strbuf_grow(sb, hint);
28 void strbuf_release(struct strbuf *sb)
30 if (sb->alloc) {
31 free(sb->buf);
32 strbuf_init(sb, 0);
36 char *strbuf_detach(struct strbuf *sb, size_t *sz)
38 char *res;
39 strbuf_grow(sb, 0);
40 res = sb->buf;
41 if (sz)
42 *sz = sb->len;
43 strbuf_init(sb, 0);
44 return res;
47 void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
49 strbuf_release(sb);
50 sb->buf = buf;
51 sb->len = len;
52 sb->alloc = alloc;
53 strbuf_grow(sb, 0);
54 sb->buf[sb->len] = '\0';
57 void strbuf_grow(struct strbuf *sb, size_t extra)
59 int new_buf = !sb->alloc;
60 if (unsigned_add_overflows(extra, 1) ||
61 unsigned_add_overflows(sb->len, extra + 1))
62 die("you want to use way too much memory");
63 if (new_buf)
64 sb->buf = NULL;
65 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
66 if (new_buf)
67 sb->buf[0] = '\0';
70 void strbuf_trim(struct strbuf *sb)
72 char *b = sb->buf;
73 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
74 sb->len--;
75 while (sb->len > 0 && isspace(*b)) {
76 b++;
77 sb->len--;
79 memmove(sb->buf, b, sb->len);
80 sb->buf[sb->len] = '\0';
82 void strbuf_rtrim(struct strbuf *sb)
84 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
85 sb->len--;
86 sb->buf[sb->len] = '\0';
89 void strbuf_ltrim(struct strbuf *sb)
91 char *b = sb->buf;
92 while (sb->len > 0 && isspace(*b)) {
93 b++;
94 sb->len--;
96 memmove(sb->buf, b, sb->len);
97 sb->buf[sb->len] = '\0';
100 struct strbuf **strbuf_split_buf(const char *str, size_t slen,
101 int terminator, int max)
103 struct strbuf **ret = NULL;
104 size_t nr = 0, alloc = 0;
105 struct strbuf *t;
107 while (slen) {
108 int len = slen;
109 if (max <= 0 || nr + 1 < max) {
110 const char *end = memchr(str, terminator, slen);
111 if (end)
112 len = end - str + 1;
114 t = xmalloc(sizeof(struct strbuf));
115 strbuf_init(t, len);
116 strbuf_add(t, str, len);
117 ALLOC_GROW(ret, nr + 2, alloc);
118 ret[nr++] = t;
119 str += len;
120 slen -= len;
122 ALLOC_GROW(ret, nr + 1, alloc); /* In case string was empty */
123 ret[nr] = NULL;
124 return ret;
127 void strbuf_list_free(struct strbuf **sbs)
129 struct strbuf **s = sbs;
131 while (*s) {
132 strbuf_release(*s);
133 free(*s++);
135 free(sbs);
138 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
140 int len = a->len < b->len ? a->len: b->len;
141 int cmp = memcmp(a->buf, b->buf, len);
142 if (cmp)
143 return cmp;
144 return a->len < b->len ? -1: a->len != b->len;
147 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
148 const void *data, size_t dlen)
150 if (unsigned_add_overflows(pos, len))
151 die("you want to use way too much memory");
152 if (pos > sb->len)
153 die("`pos' is too far after the end of the buffer");
154 if (pos + len > sb->len)
155 die("`pos + len' is too far after the end of the buffer");
157 if (dlen >= len)
158 strbuf_grow(sb, dlen - len);
159 memmove(sb->buf + pos + dlen,
160 sb->buf + pos + len,
161 sb->len - pos - len);
162 memcpy(sb->buf + pos, data, dlen);
163 strbuf_setlen(sb, sb->len + dlen - len);
166 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
168 strbuf_splice(sb, pos, 0, data, len);
171 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
173 strbuf_splice(sb, pos, len, NULL, 0);
176 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
178 strbuf_grow(sb, len);
179 memcpy(sb->buf + sb->len, data, len);
180 strbuf_setlen(sb, sb->len + len);
183 void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
185 strbuf_grow(sb, len);
186 memcpy(sb->buf + sb->len, sb->buf + pos, len);
187 strbuf_setlen(sb, sb->len + len);
190 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
192 va_list ap;
193 va_start(ap, fmt);
194 strbuf_vaddf(sb, fmt, ap);
195 va_end(ap);
198 static void add_lines(struct strbuf *out,
199 const char *prefix1,
200 const char *prefix2,
201 const char *buf, size_t size)
203 while (size) {
204 const char *prefix;
205 const char *next = memchr(buf, '\n', size);
206 next = next ? (next + 1) : (buf + size);
208 prefix = (prefix2 && buf[0] == '\n') ? prefix2 : prefix1;
209 strbuf_addstr(out, prefix);
210 strbuf_add(out, buf, next - buf);
211 size -= next - buf;
212 buf = next;
214 strbuf_complete_line(out);
217 void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)
219 static char prefix1[3];
220 static char prefix2[2];
222 if (prefix1[0] != comment_line_char) {
223 sprintf(prefix1, "%c ", comment_line_char);
224 sprintf(prefix2, "%c", comment_line_char);
226 add_lines(out, prefix1, prefix2, buf, size);
229 void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)
231 va_list params;
232 struct strbuf buf = STRBUF_INIT;
233 int incomplete_line = sb->len && sb->buf[sb->len - 1] != '\n';
235 va_start(params, fmt);
236 strbuf_vaddf(&buf, fmt, params);
237 va_end(params);
239 strbuf_add_commented_lines(sb, buf.buf, buf.len);
240 if (incomplete_line)
241 sb->buf[--sb->len] = '\0';
243 strbuf_release(&buf);
246 void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
248 int len;
249 va_list cp;
251 if (!strbuf_avail(sb))
252 strbuf_grow(sb, 64);
253 va_copy(cp, ap);
254 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
255 va_end(cp);
256 if (len < 0)
257 die("BUG: your vsnprintf is broken (returned %d)", len);
258 if (len > strbuf_avail(sb)) {
259 strbuf_grow(sb, len);
260 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
261 if (len > strbuf_avail(sb))
262 die("BUG: your vsnprintf is broken (insatiable)");
264 strbuf_setlen(sb, sb->len + len);
267 void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
268 void *context)
270 for (;;) {
271 const char *percent;
272 size_t consumed;
274 percent = strchrnul(format, '%');
275 strbuf_add(sb, format, percent - format);
276 if (!*percent)
277 break;
278 format = percent + 1;
280 if (*format == '%') {
281 strbuf_addch(sb, '%');
282 format++;
283 continue;
286 consumed = fn(sb, format, context);
287 if (consumed)
288 format += consumed;
289 else
290 strbuf_addch(sb, '%');
294 size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
295 void *context)
297 struct strbuf_expand_dict_entry *e = context;
298 size_t len;
300 for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
301 if (!strncmp(placeholder, e->placeholder, len)) {
302 if (e->value)
303 strbuf_addstr(sb, e->value);
304 return len;
307 return 0;
310 void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
312 int i, len = src->len;
314 for (i = 0; i < len; i++) {
315 if (src->buf[i] == '%')
316 strbuf_addch(dst, '%');
317 strbuf_addch(dst, src->buf[i]);
321 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
323 size_t res;
324 size_t oldalloc = sb->alloc;
326 strbuf_grow(sb, size);
327 res = fread(sb->buf + sb->len, 1, size, f);
328 if (res > 0)
329 strbuf_setlen(sb, sb->len + res);
330 else if (oldalloc == 0)
331 strbuf_release(sb);
332 return res;
335 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
337 size_t oldlen = sb->len;
338 size_t oldalloc = sb->alloc;
340 strbuf_grow(sb, hint ? hint : 8192);
341 for (;;) {
342 ssize_t cnt;
344 cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
345 if (cnt < 0) {
346 if (oldalloc == 0)
347 strbuf_release(sb);
348 else
349 strbuf_setlen(sb, oldlen);
350 return -1;
352 if (!cnt)
353 break;
354 sb->len += cnt;
355 strbuf_grow(sb, 8192);
358 sb->buf[sb->len] = '\0';
359 return sb->len - oldlen;
362 #define STRBUF_MAXLINK (2*PATH_MAX)
364 int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
366 size_t oldalloc = sb->alloc;
368 if (hint < 32)
369 hint = 32;
371 while (hint < STRBUF_MAXLINK) {
372 int len;
374 strbuf_grow(sb, hint);
375 len = readlink(path, sb->buf, hint);
376 if (len < 0) {
377 if (errno != ERANGE)
378 break;
379 } else if (len < hint) {
380 strbuf_setlen(sb, len);
381 return 0;
384 /* .. the buffer was too small - try again */
385 hint *= 2;
387 if (oldalloc == 0)
388 strbuf_release(sb);
389 return -1;
392 int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
394 int ch;
396 if (feof(fp))
397 return EOF;
399 strbuf_reset(sb);
400 while ((ch = fgetc(fp)) != EOF) {
401 strbuf_grow(sb, 1);
402 sb->buf[sb->len++] = ch;
403 if (ch == term)
404 break;
406 if (ch == EOF && sb->len == 0)
407 return EOF;
409 sb->buf[sb->len] = '\0';
410 return 0;
413 int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
415 if (strbuf_getwholeline(sb, fp, term))
416 return EOF;
417 if (sb->buf[sb->len-1] == term)
418 strbuf_setlen(sb, sb->len-1);
419 return 0;
422 int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
424 strbuf_reset(sb);
426 while (1) {
427 char ch;
428 ssize_t len = xread(fd, &ch, 1);
429 if (len <= 0)
430 return EOF;
431 strbuf_addch(sb, ch);
432 if (ch == term)
433 break;
435 return 0;
438 int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
440 int fd, len;
442 fd = open(path, O_RDONLY);
443 if (fd < 0)
444 return -1;
445 len = strbuf_read(sb, fd, hint);
446 close(fd);
447 if (len < 0)
448 return -1;
450 return len;
453 void strbuf_add_lines(struct strbuf *out, const char *prefix,
454 const char *buf, size_t size)
456 add_lines(out, prefix, NULL, buf, size);
459 void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
461 while (*s) {
462 size_t len = strcspn(s, "\"<>&");
463 strbuf_add(buf, s, len);
464 s += len;
465 switch (*s) {
466 case '"':
467 strbuf_addstr(buf, "&quot;");
468 break;
469 case '<':
470 strbuf_addstr(buf, "&lt;");
471 break;
472 case '>':
473 strbuf_addstr(buf, "&gt;");
474 break;
475 case '&':
476 strbuf_addstr(buf, "&amp;");
477 break;
478 case 0:
479 return;
481 s++;
485 static int is_rfc3986_reserved(char ch)
487 switch (ch) {
488 case '!': case '*': case '\'': case '(': case ')': case ';':
489 case ':': case '@': case '&': case '=': case '+': case '$':
490 case ',': case '/': case '?': case '#': case '[': case ']':
491 return 1;
493 return 0;
496 static int is_rfc3986_unreserved(char ch)
498 return isalnum(ch) ||
499 ch == '-' || ch == '_' || ch == '.' || ch == '~';
502 static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
503 int reserved)
505 strbuf_grow(sb, len);
506 while (len--) {
507 char ch = *s++;
508 if (is_rfc3986_unreserved(ch) ||
509 (!reserved && is_rfc3986_reserved(ch)))
510 strbuf_addch(sb, ch);
511 else
512 strbuf_addf(sb, "%%%02x", ch);
516 void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
517 int reserved)
519 strbuf_add_urlencode(sb, s, strlen(s), reserved);
522 void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
524 if (bytes > 1 << 30) {
525 strbuf_addf(buf, "%u.%2.2u GiB",
526 (int)(bytes >> 30),
527 (int)(bytes & ((1 << 30) - 1)) / 10737419);
528 } else if (bytes > 1 << 20) {
529 int x = bytes + 5243; /* for rounding */
530 strbuf_addf(buf, "%u.%2.2u MiB",
531 x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
532 } else if (bytes > 1 << 10) {
533 int x = bytes + 5; /* for rounding */
534 strbuf_addf(buf, "%u.%2.2u KiB",
535 x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
536 } else {
537 strbuf_addf(buf, "%u bytes", (int)bytes);
541 int printf_ln(const char *fmt, ...)
543 int ret;
544 va_list ap;
545 va_start(ap, fmt);
546 ret = vprintf(fmt, ap);
547 va_end(ap);
548 if (ret < 0 || putchar('\n') == EOF)
549 return -1;
550 return ret + 1;
553 int fprintf_ln(FILE *fp, const char *fmt, ...)
555 int ret;
556 va_list ap;
557 va_start(ap, fmt);
558 ret = vfprintf(fp, fmt, ap);
559 va_end(ap);
560 if (ret < 0 || putc('\n', fp) == EOF)
561 return -1;
562 return ret + 1;