Coverage Report

Created: 2026-01-09 07:10

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