Coverage Report

Created: 2026-10-17 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/strbuf.c
Line
Count
Source
1
#define DISABLE_SIGN_COMPARE_WARNINGS
2
3
#include "git-compat-util.h"
4
#include "gettext.h"
5
#include "hex-ll.h"
6
#include "strbuf.h"
7
#include "string-list.h"
8
#include "utf8.h"
9
#include "date.h"
10
11
bool starts_with(const char *str, const char *prefix)
12
0
{
13
0
  for (; ; str++, prefix++)
14
0
    if (!*prefix)
15
0
      return true;
16
0
    else if (*str != *prefix)
17
0
      return false;
18
0
}
19
20
bool istarts_with(const char *str, const char *prefix)
21
0
{
22
0
  for (; ; str++, prefix++)
23
0
    if (!*prefix)
24
0
      return true;
25
0
    else if (tolower(*str) != tolower(*prefix))
26
0
      return false;
27
0
}
28
29
bool starts_with_mem(const char *str, size_t len, const char *prefix)
30
0
{
31
0
  const char *end = str + len;
32
0
  for (; ; str++, prefix++) {
33
0
    if (!*prefix)
34
0
      return true;
35
0
    else if (str == end || *str != *prefix)
36
0
      return false;
37
0
  }
38
0
}
39
40
bool skip_to_optional_arg_default(const char *str, const char *prefix,
41
         const char **arg, const char *def)
42
0
{
43
0
  const char *p;
44
45
0
  if (!skip_prefix(str, prefix, &p))
46
0
    return false;
47
48
0
  if (!*p) {
49
0
    if (arg)
50
0
      *arg = def;
51
0
    return true;
52
0
  }
53
54
0
  if (*p != '=')
55
0
    return false;
56
57
0
  if (arg)
58
0
    *arg = p + 1;
59
0
  return true;
60
0
}
61
62
/*
63
 * Used as the default ->buf value, so that people can always assume
64
 * buf is non NULL and ->buf is NUL terminated even for a freshly
65
 * initialized strbuf.
66
 */
67
char strbuf_slopbuf[1];
68
69
void strbuf_init(struct strbuf *sb, size_t hint)
70
1.60k
{
71
1.60k
  struct strbuf blank = STRBUF_INIT;
72
1.60k
  memcpy(sb, &blank, sizeof(*sb));
73
1.60k
  if (hint)
74
0
    strbuf_grow(sb, hint);
75
1.60k
}
76
77
void strbuf_release(struct strbuf *sb)
78
0
{
79
0
  if (sb->alloc) {
80
0
    free(sb->buf);
81
0
    strbuf_init(sb, 0);
82
0
  }
83
0
}
84
85
char *strbuf_detach(struct strbuf *sb, size_t *sz)
86
1.60k
{
87
1.60k
  char *res;
88
1.60k
  strbuf_grow(sb, 0);
89
1.60k
  res = sb->buf;
90
1.60k
  if (sz)
91
0
    *sz = sb->len;
92
1.60k
  strbuf_init(sb, 0);
93
1.60k
  return res;
94
1.60k
}
95
96
void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
97
0
{
98
0
  strbuf_release(sb);
99
0
  sb->buf   = buf;
100
0
  sb->len   = len;
101
0
  sb->alloc = alloc;
102
0
  strbuf_grow(sb, 0);
103
0
  sb->buf[sb->len] = '\0';
104
0
}
105
106
void strbuf_grow(struct strbuf *sb, size_t extra)
107
11.7k
{
108
11.7k
  int new_buf = !sb->alloc;
109
11.7k
  size_t new_len = st_add3(sb->len, extra, 1);
110
11.7k
  if (new_buf)
111
1.60k
    sb->buf = NULL;
112
11.7k
  ALLOC_GROW(sb->buf, new_len, sb->alloc);
113
11.7k
  if (new_buf)
114
1.60k
    sb->buf[0] = '\0';
115
11.7k
}
116
117
void strbuf_trim(struct strbuf *sb)
118
0
{
119
0
  strbuf_rtrim(sb);
120
0
  strbuf_ltrim(sb);
121
0
}
122
123
void strbuf_rtrim(struct strbuf *sb)
124
0
{
125
0
  while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
126
0
    sb->len--;
127
0
  sb->buf[sb->len] = '\0';
128
0
}
129
130
void strbuf_trim_trailing_dir_sep(struct strbuf *sb)
131
0
{
132
0
  while (sb->len > 0 && is_dir_sep((unsigned char)sb->buf[sb->len - 1]))
133
0
    sb->len--;
134
0
  sb->buf[sb->len] = '\0';
135
0
}
136
137
void strbuf_trim_trailing_newline(struct strbuf *sb)
138
0
{
139
0
  if (sb->len > 0 && sb->buf[sb->len - 1] == '\n') {
140
0
    if (--sb->len > 0 && sb->buf[sb->len - 1] == '\r')
141
0
      --sb->len;
142
0
    sb->buf[sb->len] = '\0';
143
0
  }
144
0
}
145
146
void strbuf_ltrim(struct strbuf *sb)
147
0
{
148
0
  char *b = sb->buf;
149
0
  while (sb->len > 0 && isspace(*b)) {
150
0
    b++;
151
0
    sb->len--;
152
0
  }
153
0
  memmove(sb->buf, b, sb->len);
154
0
  sb->buf[sb->len] = '\0';
155
0
}
156
157
int strbuf_reencode(struct strbuf *sb, const char *from, const char *to)
158
0
{
159
0
  char *out;
160
0
  size_t len;
161
162
0
  if (same_encoding(from, to))
163
0
    return 0;
164
165
0
  out = reencode_string_len(sb->buf, sb->len, to, from, &len);
166
0
  if (!out)
167
0
    return -1;
168
169
0
  strbuf_attach(sb, out, len, len + 1);
170
0
  return 0;
171
0
}
172
173
void strbuf_tolower(struct strbuf *sb)
174
0
{
175
0
  char *p = sb->buf, *end = sb->buf + sb->len;
176
0
  for (; p < end; p++)
177
0
    *p = tolower(*p);
178
0
}
179
180
struct strbuf **strbuf_split_buf(const char *str, size_t slen,
181
         int terminator, int max)
182
0
{
183
0
  struct strbuf **ret = NULL;
184
0
  size_t nr = 0, alloc = 0;
185
0
  struct strbuf *t;
186
187
0
  while (slen) {
188
0
    int len = slen;
189
0
    if (max <= 0 || nr + 1 < max) {
190
0
      const char *end = memchr(str, terminator, slen);
191
0
      if (end)
192
0
        len = end - str + 1;
193
0
    }
194
0
    t = xmalloc(sizeof(struct strbuf));
195
0
    strbuf_init(t, len);
196
0
    strbuf_add(t, str, len);
197
0
    ALLOC_GROW(ret, nr + 2, alloc);
198
0
    ret[nr++] = t;
199
0
    str += len;
200
0
    slen -= len;
201
0
  }
202
0
  ALLOC_GROW(ret, nr + 1, alloc); /* In case string was empty */
203
0
  ret[nr] = NULL;
204
0
  return ret;
205
0
}
206
207
void strbuf_add_separated_string_list(struct strbuf *str,
208
              const char *sep,
209
              struct string_list *slist)
210
0
{
211
0
  struct string_list_item *item;
212
0
  int sep_needed = 0;
213
214
0
  for_each_string_list_item(item, slist) {
215
0
    if (sep_needed)
216
0
      strbuf_addstr(str, sep);
217
0
    strbuf_addstr(str, item->string);
218
0
    sep_needed = 1;
219
0
  }
220
0
}
221
222
void strbuf_list_free(struct strbuf **sbs)
223
0
{
224
0
  struct strbuf **s = sbs;
225
226
0
  if (!s)
227
0
    return;
228
0
  while (*s) {
229
0
    strbuf_release(*s);
230
0
    free(*s++);
231
0
  }
232
0
  free(sbs);
233
0
}
234
235
int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
236
0
{
237
0
  size_t len = a->len < b->len ? a->len: b->len;
238
0
  int cmp = memcmp(a->buf, b->buf, len);
239
0
  if (cmp)
240
0
    return cmp;
241
0
  return a->len < b->len ? -1: a->len != b->len;
242
0
}
243
244
void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
245
           const void *data, size_t dlen)
246
0
{
247
0
  if (unsigned_add_overflows(pos, len))
248
0
    die("you want to use way too much memory");
249
0
  if (pos > sb->len)
250
0
    die("`pos' is too far after the end of the buffer");
251
0
  if (pos + len > sb->len)
252
0
    die("`pos + len' is too far after the end of the buffer");
253
254
0
  if (dlen >= len)
255
0
    strbuf_grow(sb, dlen - len);
256
0
  memmove(sb->buf + pos + dlen,
257
0
      sb->buf + pos + len,
258
0
      sb->len - pos - len);
259
0
  memcpy(sb->buf + pos, data, dlen);
260
0
  strbuf_setlen(sb, sb->len + dlen - len);
261
0
}
262
263
void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
264
0
{
265
0
  strbuf_splice(sb, pos, 0, data, len);
266
0
}
267
268
void strbuf_vinsertf(struct strbuf *sb, size_t pos, const char *fmt, va_list ap)
269
0
{
270
0
  int len, len2;
271
0
  char save;
272
0
  va_list cp;
273
274
0
  if (pos > sb->len)
275
0
    die("`pos' is too far after the end of the buffer");
276
0
  va_copy(cp, ap);
277
0
  len = vsnprintf(sb->buf + sb->len, 0, fmt, cp);
278
0
  va_end(cp);
279
0
  if (len < 0)
280
0
    die(_("unable to format message: %s"), fmt);
281
0
  if (!len)
282
0
    return; /* nothing to do */
283
0
  if (unsigned_add_overflows(sb->len, len))
284
0
    die("you want to use way too much memory");
285
0
  strbuf_grow(sb, len);
286
0
  memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos);
287
  /* vsnprintf() will append a NUL, overwriting one of our characters */
288
0
  save = sb->buf[pos + len];
289
0
  len2 = vsnprintf(sb->buf + pos, len + 1, fmt, ap);
290
0
  sb->buf[pos + len] = save;
291
0
  if (len2 != len)
292
0
    BUG("your vsnprintf is broken (returns inconsistent lengths)");
293
0
  strbuf_setlen(sb, sb->len + len);
294
0
}
295
296
void strbuf_insertf(struct strbuf *sb, size_t pos, const char *fmt, ...)
297
0
{
298
0
  va_list ap;
299
0
  va_start(ap, fmt);
300
0
  strbuf_vinsertf(sb, pos, fmt, ap);
301
0
  va_end(ap);
302
0
}
303
304
void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
305
0
{
306
0
  strbuf_splice(sb, pos, len, "", 0);
307
0
}
308
309
void strbuf_add(struct strbuf *sb, const void *data, size_t len)
310
261
{
311
261
  strbuf_grow(sb, len);
312
261
  memcpy(sb->buf + sb->len, data, len);
313
261
  strbuf_setlen(sb, sb->len + len);
314
261
}
315
316
void strbuf_addstrings(struct strbuf *sb, const char *s, size_t n)
317
0
{
318
0
  size_t len = strlen(s);
319
320
0
  strbuf_grow(sb, st_mult(len, n));
321
0
  for (size_t i = 0; i < n; i++)
322
0
    strbuf_add(sb, s, len);
323
0
}
324
325
void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
326
0
{
327
0
  strbuf_grow(sb, sb2->len);
328
0
  memcpy(sb->buf + sb->len, sb2->buf, sb2->len);
329
0
  strbuf_setlen(sb, sb->len + sb2->len);
330
0
}
331
332
const char *strbuf_join_argv(struct strbuf *buf,
333
           int argc, const char **argv, char delim)
334
0
{
335
0
  if (!argc)
336
0
    return buf->buf;
337
338
0
  strbuf_addstr(buf, *argv);
339
0
  while (--argc) {
340
0
    strbuf_addch(buf, delim);
341
0
    strbuf_addstr(buf, *(++argv));
342
0
  }
343
344
0
  return buf->buf;
345
0
}
346
347
void strbuf_addchars(struct strbuf *sb, int c, size_t n)
348
0
{
349
0
  strbuf_grow(sb, n);
350
0
  memset(sb->buf + sb->len, c, n);
351
0
  strbuf_setlen(sb, sb->len + n);
352
0
}
353
354
void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
355
0
{
356
0
  va_list ap;
357
0
  va_start(ap, fmt);
358
0
  strbuf_vaddf(sb, fmt, ap);
359
0
  va_end(ap);
360
0
}
361
362
void strbuf_add_uint(struct strbuf *sb, uintmax_t value)
363
0
{
364
0
  char buf[DIV_ROUND_UP(bitsizeof(value) * 10, 33)];
365
0
  char *end = buf + sizeof(buf);
366
0
  char *p = end;
367
368
0
  do
369
0
    *--p = "0123456789"[value % 10];
370
0
  while (value /= 10);
371
0
  strbuf_add(sb, p, end - p);
372
0
}
373
374
static void add_lines(struct strbuf *out,
375
      const char *prefix,
376
      const char *buf, size_t size,
377
      int space_after_prefix)
378
0
{
379
0
  while (size) {
380
0
    const char *next = memchr(buf, '\n', size);
381
0
    next = next ? (next + 1) : (buf + size);
382
383
0
    strbuf_addstr(out, prefix);
384
0
    if (space_after_prefix && buf[0] != '\n' && buf[0] != '\t')
385
0
      strbuf_addch(out, ' ');
386
0
    strbuf_add(out, buf, next - buf);
387
0
    size -= next - buf;
388
0
    buf = next;
389
0
  }
390
0
  strbuf_complete_line(out);
391
0
}
392
393
void strbuf_add_commented_lines(struct strbuf *out, const char *buf,
394
        size_t size, const char *comment_prefix)
395
0
{
396
0
  add_lines(out, comment_prefix, buf, size, 1);
397
0
}
398
399
void strbuf_commented_addf(struct strbuf *sb, const char *comment_prefix,
400
         const char *fmt, ...)
401
0
{
402
0
  va_list params;
403
0
  struct strbuf buf = STRBUF_INIT;
404
0
  int incomplete_line = sb->len && sb->buf[sb->len - 1] != '\n';
405
406
0
  va_start(params, fmt);
407
0
  strbuf_vaddf(&buf, fmt, params);
408
0
  va_end(params);
409
410
0
  strbuf_add_commented_lines(sb, buf.buf, buf.len, comment_prefix);
411
0
  if (incomplete_line)
412
0
    sb->buf[--sb->len] = '\0';
413
414
0
  strbuf_release(&buf);
415
0
}
416
417
void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
418
0
{
419
0
  int len;
420
0
  va_list cp;
421
422
0
  if (!strbuf_avail(sb))
423
0
    strbuf_grow(sb, 64);
424
0
  va_copy(cp, ap);
425
0
  len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
426
0
  va_end(cp);
427
0
  if (len < 0)
428
0
    die(_("unable to format message: %s"), fmt);
429
0
  if (len > strbuf_avail(sb)) {
430
0
    strbuf_grow(sb, len);
431
0
    len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
432
0
    if (len > strbuf_avail(sb))
433
0
      BUG("your vsnprintf is broken (insatiable)");
434
0
  }
435
0
  strbuf_setlen(sb, sb->len + len);
436
0
}
437
438
int strbuf_expand_step(struct strbuf *sb, const char **formatp)
439
0
{
440
0
  const char *format = *formatp;
441
0
  const char *percent = strchrnul(format, '%');
442
443
0
  strbuf_add(sb, format, percent - format);
444
0
  if (!*percent)
445
0
    return 0;
446
0
  *formatp = percent + 1;
447
0
  return 1;
448
0
}
449
450
size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder)
451
0
{
452
0
  int ch;
453
454
0
  switch (placeholder[0]) {
455
0
  case 'n':   /* newline */
456
0
    strbuf_addch(sb, '\n');
457
0
    return 1;
458
0
  case 'x':
459
    /* %x00 == NUL, %x0a == LF, etc. */
460
0
    ch = hex2chr(placeholder + 1);
461
0
    if (ch < 0)
462
0
      return 0;
463
0
    strbuf_addch(sb, ch);
464
0
    return 3;
465
0
  }
466
0
  return 0;
467
0
}
468
469
void strbuf_expand_bad_format(const char *format, const char *command)
470
0
{
471
0
  const char *end;
472
473
0
  if (*format != '(')
474
    /* TRANSLATORS: The first %s is a command like "ls-tree". */
475
0
    die(_("bad %s format: element '%s' does not start with '('"),
476
0
        command, format);
477
478
0
  end = strchr(format + 1, ')');
479
0
  if (!end)
480
    /* TRANSLATORS: The first %s is a command like "ls-tree". */
481
0
    die(_("bad %s format: element '%s' does not end in ')'"),
482
0
        command, format);
483
484
  /* TRANSLATORS: %s is a command like "ls-tree". */
485
0
  die(_("bad %s format: %%%.*s"),
486
0
      command, (int)(end - format + 1), format);
487
0
}
488
489
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
490
0
{
491
0
  size_t i, len = src->len;
492
493
0
  for (i = 0; i < len; i++) {
494
0
    if (src->buf[i] == '%')
495
0
      strbuf_addch(dst, '%');
496
0
    strbuf_addch(dst, src->buf[i]);
497
0
  }
498
0
}
499
500
0
#define URL_UNSAFE_CHARS " <>\"%{}|\\^`:?#[]@!$&'()*+,;="
501
502
void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
503
0
{
504
0
  size_t i, len = strlen(src);
505
506
0
  for (i = 0; i < len; i++) {
507
0
    unsigned char ch = src[i];
508
0
    if (ch <= 0x1F || ch >= 0x7F ||
509
0
        (ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
510
0
        ((flags & STRBUF_ENCODE_HOST_AND_PORT) ?
511
0
         !isalnum(ch) && !strchr("-.:[]", ch) :
512
0
         !!strchr(URL_UNSAFE_CHARS, ch)))
513
0
      strbuf_addf(dst, "%%%02X", (unsigned char)ch);
514
0
    else
515
0
      strbuf_addch(dst, ch);
516
0
  }
517
0
}
518
519
size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
520
0
{
521
0
  size_t res;
522
0
  size_t oldalloc = sb->alloc;
523
524
0
  strbuf_grow(sb, size);
525
0
  res = fread(sb->buf + sb->len, 1, size, f);
526
0
  if (res > 0)
527
0
    strbuf_setlen(sb, sb->len + res);
528
0
  else if (oldalloc == 0)
529
0
    strbuf_release(sb);
530
0
  return res;
531
0
}
532
533
ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
534
0
{
535
0
  size_t oldlen = sb->len;
536
0
  size_t oldalloc = sb->alloc;
537
538
0
  strbuf_grow(sb, hint ? hint : 8192);
539
0
  for (;;) {
540
0
    ssize_t want = sb->alloc - sb->len - 1;
541
0
    ssize_t got = read_in_full(fd, sb->buf + sb->len, want);
542
543
0
    if (got < 0) {
544
0
      if (oldalloc == 0)
545
0
        strbuf_release(sb);
546
0
      else
547
0
        strbuf_setlen(sb, oldlen);
548
0
      return -1;
549
0
    }
550
0
    sb->len += got;
551
0
    if (got < want)
552
0
      break;
553
0
    strbuf_grow(sb, 8192);
554
0
  }
555
556
0
  sb->buf[sb->len] = '\0';
557
0
  return sb->len - oldlen;
558
0
}
559
560
ssize_t strbuf_read_once(struct strbuf *sb, int fd, size_t hint)
561
0
{
562
0
  size_t oldalloc = sb->alloc;
563
0
  ssize_t cnt;
564
565
0
  strbuf_grow(sb, hint ? hint : 8192);
566
0
  cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
567
0
  if (cnt > 0)
568
0
    strbuf_setlen(sb, sb->len + cnt);
569
0
  else if (oldalloc == 0)
570
0
    strbuf_release(sb);
571
0
  return cnt;
572
0
}
573
574
ssize_t strbuf_write(struct strbuf *sb, FILE *f)
575
0
{
576
0
  return sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;
577
0
}
578
579
0
#define STRBUF_MAXLINK (32767)
580
581
int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
582
0
{
583
0
  size_t oldalloc = sb->alloc;
584
585
0
  if (hint < 32)
586
0
    hint = 32;
587
588
0
  while (hint < STRBUF_MAXLINK) {
589
0
    ssize_t len;
590
591
0
    strbuf_grow(sb, hint + 1);
592
0
    len = readlink(path, sb->buf, hint + 1);
593
0
    if (len < 0) {
594
0
      if (errno != ERANGE)
595
0
        break;
596
0
    } else if (len <= hint) {
597
0
      strbuf_setlen(sb, len);
598
0
      return 0;
599
0
    }
600
601
    /* .. the buffer was too small - try again */
602
0
    hint *= 2;
603
0
  }
604
0
  if (oldalloc == 0)
605
0
    strbuf_release(sb);
606
0
  return -1;
607
0
}
608
609
int strbuf_getcwd(struct strbuf *sb)
610
0
{
611
0
  size_t oldalloc = sb->alloc;
612
0
  size_t guessed_len = 128;
613
614
0
  for (;; guessed_len *= 2) {
615
0
    strbuf_grow(sb, guessed_len);
616
0
    if (getcwd(sb->buf, sb->alloc)) {
617
0
      strbuf_setlen(sb, strlen(sb->buf));
618
0
      return 0;
619
0
    }
620
621
    /*
622
     * If getcwd(3) is implemented as a syscall that falls
623
     * back to a regular lookup using readdir(3) etc. then
624
     * we may be able to avoid EACCES by providing enough
625
     * space to the syscall as it's not necessarily bound
626
     * to the same restrictions as the fallback.
627
     */
628
0
    if (errno == EACCES && guessed_len < PATH_MAX)
629
0
      continue;
630
631
0
    if (errno != ERANGE)
632
0
      break;
633
0
  }
634
0
  if (oldalloc == 0)
635
0
    strbuf_release(sb);
636
0
  else
637
0
    strbuf_reset(sb);
638
0
  return -1;
639
0
}
640
641
#ifdef HAVE_GETDELIM
642
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
643
0
{
644
0
  ssize_t r;
645
646
0
  if (feof(fp))
647
0
    return EOF;
648
649
  /* Translate slopbuf to NULL, as we cannot call realloc on it */
650
0
  if (!sb->alloc)
651
0
    sb->buf = NULL;
652
0
  errno = 0;
653
0
  r = getdelim(&sb->buf, &sb->alloc, term, fp);
654
655
0
  if (r > 0) {
656
0
    sb->len = r;
657
0
    return 0;
658
0
  }
659
0
  assert(r == -1);
660
661
  /*
662
   * Normally we would have called xrealloc, which will try to free
663
   * memory and recover. But we have no way to tell getdelim() to do so.
664
   * Worse, we cannot try to recover ENOMEM ourselves, because we have
665
   * no idea how many bytes were read by getdelim.
666
   *
667
   * Dying here is reasonable. It mirrors what xrealloc would do on
668
   * catastrophic memory failure. We skip the opportunity to free pack
669
   * memory and retry, but that's unlikely to help for a malloc small
670
   * enough to hold a single line of input, anyway.
671
   */
672
0
  if (errno == ENOMEM)
673
0
    die("Out of memory, getdelim failed");
674
675
  /*
676
   * Restore strbuf invariants; if getdelim left us with a NULL pointer,
677
   * we can just re-init, but otherwise we should make sure that our
678
   * length is empty, and that the result is NUL-terminated.
679
   */
680
0
  if (!sb->buf)
681
0
    strbuf_init(sb, 0);
682
0
  else
683
0
    strbuf_reset(sb);
684
0
  return EOF;
685
0
}
686
#else
687
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
688
{
689
  int ch;
690
691
  if (feof(fp))
692
    return EOF;
693
694
  strbuf_reset(sb);
695
  flockfile(fp);
696
  while ((ch = getc_unlocked(fp)) != EOF) {
697
    if (!strbuf_avail(sb))
698
      strbuf_grow(sb, 1);
699
    sb->buf[sb->len++] = ch;
700
    if (ch == term)
701
      break;
702
  }
703
  funlockfile(fp);
704
  if (ch == EOF && sb->len == 0)
705
    return EOF;
706
707
  sb->buf[sb->len] = '\0';
708
  return 0;
709
}
710
#endif
711
712
int strbuf_appendwholeline(struct strbuf *sb, FILE *fp, int term)
713
0
{
714
0
  struct strbuf line = STRBUF_INIT;
715
0
  if (strbuf_getwholeline(&line, fp, term)) {
716
0
    strbuf_release(&line);
717
0
    return EOF;
718
0
  }
719
0
  strbuf_addbuf(sb, &line);
720
0
  strbuf_release(&line);
721
0
  return 0;
722
0
}
723
724
static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)
725
0
{
726
0
  if (strbuf_getwholeline(sb, fp, term))
727
0
    return EOF;
728
0
  if (sb->buf[sb->len - 1] == term)
729
0
    strbuf_setlen(sb, sb->len - 1);
730
0
  return 0;
731
0
}
732
733
int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term)
734
0
{
735
0
  if (strbuf_getwholeline(sb, fp, term))
736
0
    return EOF;
737
0
  if (term == '\n' && sb->buf[sb->len - 1] == '\n') {
738
0
    strbuf_setlen(sb, sb->len - 1);
739
0
    if (sb->len && sb->buf[sb->len - 1] == '\r')
740
0
      strbuf_setlen(sb, sb->len - 1);
741
0
  }
742
0
  return 0;
743
0
}
744
745
int strbuf_getline(struct strbuf *sb, FILE *fp)
746
0
{
747
0
  return strbuf_getdelim_strip_crlf(sb, fp, '\n');
748
0
}
749
750
int strbuf_getline_lf(struct strbuf *sb, FILE *fp)
751
0
{
752
0
  return strbuf_getdelim(sb, fp, '\n');
753
0
}
754
755
int strbuf_getline_nul(struct strbuf *sb, FILE *fp)
756
0
{
757
0
  return strbuf_getdelim(sb, fp, '\0');
758
0
}
759
760
int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
761
0
{
762
0
  strbuf_reset(sb);
763
764
0
  while (1) {
765
0
    char ch;
766
0
    ssize_t len = xread(fd, &ch, 1);
767
0
    if (len <= 0)
768
0
      return EOF;
769
0
    strbuf_addch(sb, ch);
770
0
    if (ch == term)
771
0
      break;
772
0
  }
773
0
  return 0;
774
0
}
775
776
ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
777
0
{
778
0
  int fd;
779
0
  ssize_t len;
780
0
  int saved_errno;
781
782
0
  fd = open(path, O_RDONLY);
783
0
  if (fd < 0)
784
0
    return -1;
785
0
  len = strbuf_read(sb, fd, hint);
786
0
  saved_errno = errno;
787
0
  close(fd);
788
0
  if (len < 0) {
789
0
    errno = saved_errno;
790
0
    return -1;
791
0
  }
792
793
0
  return len;
794
0
}
795
796
void strbuf_add_lines(struct strbuf *out, const char *prefix,
797
          const char *buf, size_t size)
798
0
{
799
0
  add_lines(out, prefix, buf, size, 0);
800
0
}
801
802
void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
803
0
{
804
0
  while (*s) {
805
0
    size_t len = strcspn(s, "\"<>&");
806
0
    strbuf_add(buf, s, len);
807
0
    s += len;
808
0
    switch (*s) {
809
0
    case '"':
810
0
      strbuf_addstr(buf, "&quot;");
811
0
      break;
812
0
    case '<':
813
0
      strbuf_addstr(buf, "&lt;");
814
0
      break;
815
0
    case '>':
816
0
      strbuf_addstr(buf, "&gt;");
817
0
      break;
818
0
    case '&':
819
0
      strbuf_addstr(buf, "&amp;");
820
0
      break;
821
0
    case 0:
822
0
      return;
823
0
    }
824
0
    s++;
825
0
  }
826
0
}
827
828
static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
829
         char_predicate allow_unencoded_fn)
830
0
{
831
0
  strbuf_grow(sb, len);
832
0
  while (len--) {
833
0
    char ch = *s++;
834
0
    if (allow_unencoded_fn(ch))
835
0
      strbuf_addch(sb, ch);
836
0
    else
837
0
      strbuf_addf(sb, "%%%02x", (unsigned char)ch);
838
0
  }
839
0
}
840
841
void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
842
           char_predicate allow_unencoded_fn)
843
0
{
844
0
  strbuf_add_urlencode(sb, s, strlen(s), allow_unencoded_fn);
845
0
}
846
847
void humanise_count(size_t count, char **value, const char **unit)
848
0
{
849
0
  if (count >= 1000000000) {
850
0
    size_t x = count + 5000000; /* for rounding */
851
0
    *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000000),
852
0
         (unsigned)(x % 1000000000 / 10000000));
853
    /* TRANSLATORS: SI decimal prefix symbol for 10^9 */
854
0
    *unit = _("G");
855
0
  } else if (count >= 1000000) {
856
0
    size_t x = count + 5000; /* for rounding */
857
0
    *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000000),
858
0
         (unsigned)(x % 1000000 / 10000));
859
    /* TRANSLATORS: SI decimal prefix symbol for 10^6 */
860
0
    *unit = _("M");
861
0
  } else if (count >= 1000) {
862
0
    size_t x = count + 5; /* for rounding */
863
0
    *value = xstrfmt(_("%u.%2.2u"), (unsigned)(x / 1000),
864
0
         (unsigned)(x % 1000 / 10));
865
    /* TRANSLATORS: SI decimal prefix symbol for 10^3 */
866
0
    *unit = _("k");
867
0
  } else {
868
0
    *value = xstrfmt("%u", (unsigned)count);
869
0
    *unit = NULL;
870
0
  }
871
0
}
872
873
void humanise_bytes(off_t bytes, char **value, const char **unit,
874
        unsigned flags)
875
0
{
876
0
  int humanise_rate = flags & HUMANISE_RATE;
877
878
0
  if (bytes > 1 << 30) {
879
0
    *value = xstrfmt(_("%u.%2.2u"), (unsigned)(bytes >> 30),
880
0
         (unsigned)(bytes & ((1 << 30) - 1)) / 10737419);
881
    /* TRANSLATORS: IEC 80000-13:2008 gibibyte/second and gibibyte */
882
0
    *unit = humanise_rate ? _("GiB/s") : _("GiB");
883
0
  } else if (bytes > 1 << 20) {
884
0
    unsigned x = bytes + 5243; /* for rounding */
885
0
    *value = xstrfmt(_("%u.%2.2u"), x >> 20,
886
0
         ((x & ((1 << 20) - 1)) * 100) >> 20);
887
    /* TRANSLATORS: IEC 80000-13:2008 mebibyte/second and mebibyte */
888
0
    *unit = humanise_rate ? _("MiB/s") : _("MiB");
889
0
  } else if (bytes > 1 << 10) {
890
0
    unsigned x = bytes + 5; /* for rounding */
891
0
    *value = xstrfmt(_("%u.%2.2u"), x >> 10,
892
0
         ((x & ((1 << 10) - 1)) * 100) >> 10);
893
    /* TRANSLATORS: IEC 80000-13:2008 kibibyte/second and kibibyte */
894
0
    *unit = humanise_rate ? _("KiB/s") : _("KiB");
895
0
  } else {
896
0
    *value = xstrfmt("%u", (unsigned)bytes);
897
0
    if (flags & HUMANISE_COMPACT)
898
      /* TRANSLATORS: IEC 80000-13:2008 byte/second and byte */
899
0
      *unit = humanise_rate ? _("B/s") : _("B");
900
0
    else
901
0
      *unit = humanise_rate ?
902
          /* TRANSLATORS: IEC 80000-13:2008 byte/second */
903
0
          Q_("byte/s", "bytes/s", bytes) :
904
          /* TRANSLATORS: IEC 80000-13:2008 byte */
905
0
          Q_("byte", "bytes", bytes);
906
0
  }
907
0
}
908
909
static void strbuf_humanise(struct strbuf *buf, off_t bytes, unsigned flags)
910
0
{
911
0
  char *value;
912
0
  const char *unit;
913
914
0
  humanise_bytes(bytes, &value, &unit, flags);
915
916
  /*
917
   * TRANSLATORS: The first argument is the number string. The second
918
   * argument is the unit string (i.e. "12.34 MiB/s").
919
   */
920
0
  strbuf_addf(buf, _("%s %s"), value, unit);
921
0
  free(value);
922
0
}
923
924
void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
925
0
{
926
0
  strbuf_humanise(buf, bytes, 0);
927
0
}
928
929
void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)
930
0
{
931
0
  strbuf_humanise(buf, bytes, HUMANISE_RATE);
932
0
}
933
934
int printf_ln(const char *fmt, ...)
935
0
{
936
0
  int ret;
937
0
  va_list ap;
938
0
  va_start(ap, fmt);
939
0
  ret = vprintf(fmt, ap);
940
0
  va_end(ap);
941
0
  if (ret < 0 || putchar('\n') == EOF)
942
0
    return -1;
943
0
  return ret + 1;
944
0
}
945
946
int fprintf_ln(FILE *fp, const char *fmt, ...)
947
0
{
948
0
  int ret;
949
0
  va_list ap;
950
0
  va_start(ap, fmt);
951
0
  ret = vfprintf(fp, fmt, ap);
952
0
  va_end(ap);
953
0
  if (ret < 0 || putc('\n', fp) == EOF)
954
0
    return -1;
955
0
  return ret + 1;
956
0
}
957
958
char *xstrdup_tolower(const char *string)
959
0
{
960
0
  char *result;
961
0
  size_t len, i;
962
963
0
  len = strlen(string);
964
0
  result = xmallocz(len);
965
0
  for (i = 0; i < len; i++)
966
0
    result[i] = tolower(string[i]);
967
0
  return result;
968
0
}
969
970
char *xstrdup_toupper(const char *string)
971
0
{
972
0
  char *result;
973
0
  size_t len, i;
974
975
0
  len = strlen(string);
976
0
  result = xmallocz(len);
977
0
  for (i = 0; i < len; i++)
978
0
    result[i] = toupper(string[i]);
979
0
  return result;
980
0
}
981
982
char *xstrvfmt(const char *fmt, va_list ap)
983
0
{
984
0
  struct strbuf buf = STRBUF_INIT;
985
0
  strbuf_vaddf(&buf, fmt, ap);
986
0
  return strbuf_detach(&buf, NULL);
987
0
}
988
989
char *xstrfmt(const char *fmt, ...)
990
0
{
991
0
  va_list ap;
992
0
  char *ret;
993
994
0
  va_start(ap, fmt);
995
0
  ret = xstrvfmt(fmt, ap);
996
0
  va_end(ap);
997
998
0
  return ret;
999
0
}
1000
1001
void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
1002
         int tz_offset, int suppress_tz_name)
1003
0
{
1004
0
  struct strbuf munged_fmt = STRBUF_INIT;
1005
0
  size_t hint = 128;
1006
0
  size_t len;
1007
1008
0
  if (!*fmt)
1009
0
    return;
1010
1011
  /*
1012
   * There is no portable way to pass timezone information to
1013
   * strftime, so we handle %z and %Z here. Likewise '%s', because
1014
   * going back to an epoch time requires knowing the zone.
1015
   *
1016
   * Note that tz_offset is in the "[-+]HHMM" decimal form; this is what
1017
   * we want for %z, but the computation for %s has to convert to number
1018
   * of seconds.
1019
   */
1020
0
  while (strbuf_expand_step(&munged_fmt, &fmt)) {
1021
0
    if (skip_prefix(fmt, "%", &fmt))
1022
0
      strbuf_addstr(&munged_fmt, "%%");
1023
0
    else if (skip_prefix(fmt, "s", &fmt))
1024
0
      strbuf_addf(&munged_fmt, "%"PRItime,
1025
0
            (timestamp_t)tm_to_time_t(tm) -
1026
0
            60 * tz_to_minutes(tz_offset));
1027
0
    else if (skip_prefix(fmt, "z", &fmt))
1028
0
      strbuf_addf(&munged_fmt, "%+05d", tz_offset);
1029
0
    else if (suppress_tz_name && skip_prefix(fmt, "Z", &fmt))
1030
0
      ; /* nothing */
1031
0
    else
1032
0
      strbuf_addch(&munged_fmt, '%');
1033
0
  }
1034
0
  fmt = munged_fmt.buf;
1035
1036
0
  strbuf_grow(sb, hint);
1037
0
  len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
1038
1039
0
  if (!len) {
1040
    /*
1041
     * strftime reports "0" if it could not fit the result in the buffer.
1042
     * Unfortunately, it also reports "0" if the requested time string
1043
     * takes 0 bytes. So our strategy is to munge the format so that the
1044
     * output contains at least one character, and then drop the extra
1045
     * character before returning.
1046
     */
1047
0
    strbuf_addch(&munged_fmt, ' ');
1048
0
    while (!len) {
1049
0
      hint *= 2;
1050
0
      strbuf_grow(sb, hint);
1051
0
      len = strftime(sb->buf + sb->len, sb->alloc - sb->len,
1052
0
               munged_fmt.buf, tm);
1053
0
    }
1054
0
    len--; /* drop munged space */
1055
0
  }
1056
0
  strbuf_release(&munged_fmt);
1057
0
  strbuf_setlen(sb, sb->len + len);
1058
0
}
1059
1060
/*
1061
 * Returns the length of a line, without trailing spaces.
1062
 *
1063
 * If the line ends with newline, it will be removed too.
1064
 */
1065
static size_t cleanup(char *line, size_t len)
1066
0
{
1067
0
  while (len) {
1068
0
    unsigned char c = line[len - 1];
1069
0
    if (!isspace(c))
1070
0
      break;
1071
0
    len--;
1072
0
  }
1073
1074
0
  return len;
1075
0
}
1076
1077
/*
1078
 * Remove empty lines from the beginning and end
1079
 * and also trailing spaces from every line.
1080
 *
1081
 * Turn multiple consecutive empty lines between paragraphs
1082
 * into just one empty line.
1083
 *
1084
 * If the input has only empty lines and spaces,
1085
 * no output will be produced.
1086
 *
1087
 * If last line does not have a newline at the end, one is added.
1088
 *
1089
 * Pass a non-NULL comment_prefix to skip every line starting
1090
 * with it.
1091
 */
1092
void strbuf_stripspace(struct strbuf *sb, const char *comment_prefix)
1093
0
{
1094
0
  size_t empties = 0;
1095
0
  size_t i, j, len, newlen;
1096
0
  char *eol;
1097
1098
  /* We may have to add a newline. */
1099
0
  strbuf_grow(sb, 1);
1100
1101
0
  for (i = j = 0; i < sb->len; i += len, j += newlen) {
1102
0
    eol = memchr(sb->buf + i, '\n', sb->len - i);
1103
0
    len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
1104
1105
0
    if (comment_prefix && len &&
1106
0
        starts_with(sb->buf + i, comment_prefix)) {
1107
0
      newlen = 0;
1108
0
      continue;
1109
0
    }
1110
0
    newlen = cleanup(sb->buf + i, len);
1111
1112
    /* Not just an empty line? */
1113
0
    if (newlen) {
1114
0
      if (empties > 0 && j > 0)
1115
0
        sb->buf[j++] = '\n';
1116
0
      empties = 0;
1117
0
      memmove(sb->buf + j, sb->buf + i, newlen);
1118
0
      sb->buf[newlen + j++] = '\n';
1119
0
    } else {
1120
0
      empties++;
1121
0
    }
1122
0
  }
1123
1124
0
  strbuf_setlen(sb, j);
1125
0
}
1126
1127
void strbuf_strip_file_from_path(struct strbuf *sb)
1128
0
{
1129
0
  const char *path_sep = find_last_dir_sep(sb->buf);
1130
0
  strbuf_setlen(sb, path_sep ? path_sep - sb->buf + 1 : 0);
1131
0
}