Coverage Report

Created: 2024-09-08 06:23

/src/git/strbuf.c
Line
Count
Source (jump to first uncovered line)
1
#include "git-compat-util.h"
2
#include "gettext.h"
3
#include "hex-ll.h"
4
#include "strbuf.h"
5
#include "string-list.h"
6
#include "utf8.h"
7
#include "date.h"
8
9
int starts_with(const char *str, const char *prefix)
10
0
{
11
0
  for (; ; str++, prefix++)
12
0
    if (!*prefix)
13
0
      return 1;
14
0
    else if (*str != *prefix)
15
0
      return 0;
16
0
}
17
18
int istarts_with(const char *str, const char *prefix)
19
0
{
20
0
  for (; ; str++, prefix++)
21
0
    if (!*prefix)
22
0
      return 1;
23
0
    else if (tolower(*str) != tolower(*prefix))
24
0
      return 0;
25
0
}
26
27
int starts_with_mem(const char *str, size_t len, const char *prefix)
28
0
{
29
0
  const char *end = str + len;
30
0
  for (; ; str++, prefix++) {
31
0
    if (!*prefix)
32
0
      return 1;
33
0
    else if (str == end || *str != *prefix)
34
0
      return 0;
35
0
  }
36
0
}
37
38
int skip_to_optional_arg_default(const char *str, const char *prefix,
39
         const char **arg, const char *def)
40
0
{
41
0
  const char *p;
42
43
0
  if (!skip_prefix(str, prefix, &p))
44
0
    return 0;
45
46
0
  if (!*p) {
47
0
    if (arg)
48
0
      *arg = def;
49
0
    return 1;
50
0
  }
51
52
0
  if (*p != '=')
53
0
    return 0;
54
55
0
  if (arg)
56
0
    *arg = p + 1;
57
0
  return 1;
58
0
}
59
60
/*
61
 * Used as the default ->buf value, so that people can always assume
62
 * buf is non NULL and ->buf is NUL terminated even for a freshly
63
 * initialized strbuf.
64
 */
65
char strbuf_slopbuf[1];
66
67
void strbuf_init(struct strbuf *sb, size_t hint)
68
0
{
69
0
  struct strbuf blank = STRBUF_INIT;
70
0
  memcpy(sb, &blank, sizeof(*sb));
71
0
  if (hint)
72
0
    strbuf_grow(sb, hint);
73
0
}
74
75
void strbuf_release(struct strbuf *sb)
76
0
{
77
0
  if (sb->alloc) {
78
0
    free(sb->buf);
79
0
    strbuf_init(sb, 0);
80
0
  }
81
0
}
82
83
char *strbuf_detach(struct strbuf *sb, size_t *sz)
84
0
{
85
0
  char *res;
86
0
  strbuf_grow(sb, 0);
87
0
  res = sb->buf;
88
0
  if (sz)
89
0
    *sz = sb->len;
90
0
  strbuf_init(sb, 0);
91
0
  return res;
92
0
}
93
94
void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
95
0
{
96
0
  strbuf_release(sb);
97
0
  sb->buf   = buf;
98
0
  sb->len   = len;
99
0
  sb->alloc = alloc;
100
0
  strbuf_grow(sb, 0);
101
0
  sb->buf[sb->len] = '\0';
102
0
}
103
104
void strbuf_grow(struct strbuf *sb, size_t extra)
105
0
{
106
0
  int new_buf = !sb->alloc;
107
0
  if (unsigned_add_overflows(extra, 1) ||
108
0
      unsigned_add_overflows(sb->len, extra + 1))
109
0
    die("you want to use way too much memory");
110
0
  if (new_buf)
111
0
    sb->buf = NULL;
112
0
  ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
113
0
  if (new_buf)
114
0
    sb->buf[0] = '\0';
115
0
}
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);
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
0
{
311
0
  strbuf_grow(sb, len);
312
0
  memcpy(sb->buf + sb->len, data, len);
313
0
  strbuf_setlen(sb, sb->len + len);
314
0
}
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
static void add_lines(struct strbuf *out,
363
      const char *prefix,
364
      const char *buf, size_t size,
365
      int space_after_prefix)
366
0
{
367
0
  while (size) {
368
0
    const char *next = memchr(buf, '\n', size);
369
0
    next = next ? (next + 1) : (buf + size);
370
371
0
    strbuf_addstr(out, prefix);
372
0
    if (space_after_prefix && buf[0] != '\n' && buf[0] != '\t')
373
0
      strbuf_addch(out, ' ');
374
0
    strbuf_add(out, buf, next - buf);
375
0
    size -= next - buf;
376
0
    buf = next;
377
0
  }
378
0
  strbuf_complete_line(out);
379
0
}
380
381
void strbuf_add_commented_lines(struct strbuf *out, const char *buf,
382
        size_t size, const char *comment_prefix)
383
0
{
384
0
  add_lines(out, comment_prefix, buf, size, 1);
385
0
}
386
387
void strbuf_commented_addf(struct strbuf *sb, const char *comment_prefix,
388
         const char *fmt, ...)
389
0
{
390
0
  va_list params;
391
0
  struct strbuf buf = STRBUF_INIT;
392
0
  int incomplete_line = sb->len && sb->buf[sb->len - 1] != '\n';
393
394
0
  va_start(params, fmt);
395
0
  strbuf_vaddf(&buf, fmt, params);
396
0
  va_end(params);
397
398
0
  strbuf_add_commented_lines(sb, buf.buf, buf.len, comment_prefix);
399
0
  if (incomplete_line)
400
0
    sb->buf[--sb->len] = '\0';
401
402
0
  strbuf_release(&buf);
403
0
}
404
405
void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
406
0
{
407
0
  int len;
408
0
  va_list cp;
409
410
0
  if (!strbuf_avail(sb))
411
0
    strbuf_grow(sb, 64);
412
0
  va_copy(cp, ap);
413
0
  len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
414
0
  va_end(cp);
415
0
  if (len < 0)
416
0
    die(_("unable to format message: %s"), fmt);
417
0
  if (len > strbuf_avail(sb)) {
418
0
    strbuf_grow(sb, len);
419
0
    len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
420
0
    if (len > strbuf_avail(sb))
421
0
      BUG("your vsnprintf is broken (insatiable)");
422
0
  }
423
0
  strbuf_setlen(sb, sb->len + len);
424
0
}
425
426
int strbuf_expand_step(struct strbuf *sb, const char **formatp)
427
0
{
428
0
  const char *format = *formatp;
429
0
  const char *percent = strchrnul(format, '%');
430
431
0
  strbuf_add(sb, format, percent - format);
432
0
  if (!*percent)
433
0
    return 0;
434
0
  *formatp = percent + 1;
435
0
  return 1;
436
0
}
437
438
size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder)
439
0
{
440
0
  int ch;
441
442
0
  switch (placeholder[0]) {
443
0
  case 'n':   /* newline */
444
0
    strbuf_addch(sb, '\n');
445
0
    return 1;
446
0
  case 'x':
447
    /* %x00 == NUL, %x0a == LF, etc. */
448
0
    ch = hex2chr(placeholder + 1);
449
0
    if (ch < 0)
450
0
      return 0;
451
0
    strbuf_addch(sb, ch);
452
0
    return 3;
453
0
  }
454
0
  return 0;
455
0
}
456
457
void strbuf_expand_bad_format(const char *format, const char *command)
458
0
{
459
0
  const char *end;
460
461
0
  if (*format != '(')
462
    /* TRANSLATORS: The first %s is a command like "ls-tree". */
463
0
    die(_("bad %s format: element '%s' does not start with '('"),
464
0
        command, format);
465
466
0
  end = strchr(format + 1, ')');
467
0
  if (!end)
468
    /* TRANSLATORS: The first %s is a command like "ls-tree". */
469
0
    die(_("bad %s format: element '%s' does not end in ')'"),
470
0
        command, format);
471
472
  /* TRANSLATORS: %s is a command like "ls-tree". */
473
0
  die(_("bad %s format: %%%.*s"),
474
0
      command, (int)(end - format + 1), format);
475
0
}
476
477
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
478
0
{
479
0
  size_t i, len = src->len;
480
481
0
  for (i = 0; i < len; i++) {
482
0
    if (src->buf[i] == '%')
483
0
      strbuf_addch(dst, '%');
484
0
    strbuf_addch(dst, src->buf[i]);
485
0
  }
486
0
}
487
488
0
#define URL_UNSAFE_CHARS " <>\"%{}|\\^`:?#[]@!$&'()*+,;="
489
490
void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
491
0
{
492
0
  size_t i, len = strlen(src);
493
494
0
  for (i = 0; i < len; i++) {
495
0
    unsigned char ch = src[i];
496
0
    if (ch <= 0x1F || ch >= 0x7F ||
497
0
        (ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
498
0
        strchr(URL_UNSAFE_CHARS, ch))
499
0
      strbuf_addf(dst, "%%%02X", (unsigned char)ch);
500
0
    else
501
0
      strbuf_addch(dst, ch);
502
0
  }
503
0
}
504
505
size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
506
0
{
507
0
  size_t res;
508
0
  size_t oldalloc = sb->alloc;
509
510
0
  strbuf_grow(sb, size);
511
0
  res = fread(sb->buf + sb->len, 1, size, f);
512
0
  if (res > 0)
513
0
    strbuf_setlen(sb, sb->len + res);
514
0
  else if (oldalloc == 0)
515
0
    strbuf_release(sb);
516
0
  return res;
517
0
}
518
519
ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
520
0
{
521
0
  size_t oldlen = sb->len;
522
0
  size_t oldalloc = sb->alloc;
523
524
0
  strbuf_grow(sb, hint ? hint : 8192);
525
0
  for (;;) {
526
0
    ssize_t want = sb->alloc - sb->len - 1;
527
0
    ssize_t got = read_in_full(fd, sb->buf + sb->len, want);
528
529
0
    if (got < 0) {
530
0
      if (oldalloc == 0)
531
0
        strbuf_release(sb);
532
0
      else
533
0
        strbuf_setlen(sb, oldlen);
534
0
      return -1;
535
0
    }
536
0
    sb->len += got;
537
0
    if (got < want)
538
0
      break;
539
0
    strbuf_grow(sb, 8192);
540
0
  }
541
542
0
  sb->buf[sb->len] = '\0';
543
0
  return sb->len - oldlen;
544
0
}
545
546
ssize_t strbuf_read_once(struct strbuf *sb, int fd, size_t hint)
547
0
{
548
0
  size_t oldalloc = sb->alloc;
549
0
  ssize_t cnt;
550
551
0
  strbuf_grow(sb, hint ? hint : 8192);
552
0
  cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
553
0
  if (cnt > 0)
554
0
    strbuf_setlen(sb, sb->len + cnt);
555
0
  else if (oldalloc == 0)
556
0
    strbuf_release(sb);
557
0
  return cnt;
558
0
}
559
560
ssize_t strbuf_write(struct strbuf *sb, FILE *f)
561
0
{
562
0
  return sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;
563
0
}
564
565
0
#define STRBUF_MAXLINK (2*PATH_MAX)
566
567
int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
568
0
{
569
0
  size_t oldalloc = sb->alloc;
570
571
0
  if (hint < 32)
572
0
    hint = 32;
573
574
0
  while (hint < STRBUF_MAXLINK) {
575
0
    ssize_t len;
576
577
0
    strbuf_grow(sb, hint);
578
0
    len = readlink(path, sb->buf, hint);
579
0
    if (len < 0) {
580
0
      if (errno != ERANGE)
581
0
        break;
582
0
    } else if (len < hint) {
583
0
      strbuf_setlen(sb, len);
584
0
      return 0;
585
0
    }
586
587
    /* .. the buffer was too small - try again */
588
0
    hint *= 2;
589
0
  }
590
0
  if (oldalloc == 0)
591
0
    strbuf_release(sb);
592
0
  return -1;
593
0
}
594
595
int strbuf_getcwd(struct strbuf *sb)
596
0
{
597
0
  size_t oldalloc = sb->alloc;
598
0
  size_t guessed_len = 128;
599
600
0
  for (;; guessed_len *= 2) {
601
0
    strbuf_grow(sb, guessed_len);
602
0
    if (getcwd(sb->buf, sb->alloc)) {
603
0
      strbuf_setlen(sb, strlen(sb->buf));
604
0
      return 0;
605
0
    }
606
607
    /*
608
     * If getcwd(3) is implemented as a syscall that falls
609
     * back to a regular lookup using readdir(3) etc. then
610
     * we may be able to avoid EACCES by providing enough
611
     * space to the syscall as it's not necessarily bound
612
     * to the same restrictions as the fallback.
613
     */
614
0
    if (errno == EACCES && guessed_len < PATH_MAX)
615
0
      continue;
616
617
0
    if (errno != ERANGE)
618
0
      break;
619
0
  }
620
0
  if (oldalloc == 0)
621
0
    strbuf_release(sb);
622
0
  else
623
0
    strbuf_reset(sb);
624
0
  return -1;
625
0
}
626
627
#ifdef HAVE_GETDELIM
628
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
629
0
{
630
0
  ssize_t r;
631
632
0
  if (feof(fp))
633
0
    return EOF;
634
635
0
  strbuf_reset(sb);
636
637
  /* Translate slopbuf to NULL, as we cannot call realloc on it */
638
0
  if (!sb->alloc)
639
0
    sb->buf = NULL;
640
0
  errno = 0;
641
0
  r = getdelim(&sb->buf, &sb->alloc, term, fp);
642
643
0
  if (r > 0) {
644
0
    sb->len = r;
645
0
    return 0;
646
0
  }
647
0
  assert(r == -1);
648
649
  /*
650
   * Normally we would have called xrealloc, which will try to free
651
   * memory and recover. But we have no way to tell getdelim() to do so.
652
   * Worse, we cannot try to recover ENOMEM ourselves, because we have
653
   * no idea how many bytes were read by getdelim.
654
   *
655
   * Dying here is reasonable. It mirrors what xrealloc would do on
656
   * catastrophic memory failure. We skip the opportunity to free pack
657
   * memory and retry, but that's unlikely to help for a malloc small
658
   * enough to hold a single line of input, anyway.
659
   */
660
0
  if (errno == ENOMEM)
661
0
    die("Out of memory, getdelim failed");
662
663
  /*
664
   * Restore strbuf invariants; if getdelim left us with a NULL pointer,
665
   * we can just re-init, but otherwise we should make sure that our
666
   * length is empty, and that the result is NUL-terminated.
667
   */
668
0
  if (!sb->buf)
669
0
    strbuf_init(sb, 0);
670
0
  else
671
0
    strbuf_reset(sb);
672
0
  return EOF;
673
0
}
674
#else
675
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
676
{
677
  int ch;
678
679
  if (feof(fp))
680
    return EOF;
681
682
  strbuf_reset(sb);
683
  flockfile(fp);
684
  while ((ch = getc_unlocked(fp)) != EOF) {
685
    if (!strbuf_avail(sb))
686
      strbuf_grow(sb, 1);
687
    sb->buf[sb->len++] = ch;
688
    if (ch == term)
689
      break;
690
  }
691
  funlockfile(fp);
692
  if (ch == EOF && sb->len == 0)
693
    return EOF;
694
695
  sb->buf[sb->len] = '\0';
696
  return 0;
697
}
698
#endif
699
700
int strbuf_appendwholeline(struct strbuf *sb, FILE *fp, int term)
701
0
{
702
0
  struct strbuf line = STRBUF_INIT;
703
0
  if (strbuf_getwholeline(&line, fp, term)) {
704
0
    strbuf_release(&line);
705
0
    return EOF;
706
0
  }
707
0
  strbuf_addbuf(sb, &line);
708
0
  strbuf_release(&line);
709
0
  return 0;
710
0
}
711
712
static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)
713
0
{
714
0
  if (strbuf_getwholeline(sb, fp, term))
715
0
    return EOF;
716
0
  if (sb->buf[sb->len - 1] == term)
717
0
    strbuf_setlen(sb, sb->len - 1);
718
0
  return 0;
719
0
}
720
721
int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term)
722
0
{
723
0
  if (strbuf_getwholeline(sb, fp, term))
724
0
    return EOF;
725
0
  if (term == '\n' && sb->buf[sb->len - 1] == '\n') {
726
0
    strbuf_setlen(sb, sb->len - 1);
727
0
    if (sb->len && sb->buf[sb->len - 1] == '\r')
728
0
      strbuf_setlen(sb, sb->len - 1);
729
0
  }
730
0
  return 0;
731
0
}
732
733
int strbuf_getline(struct strbuf *sb, FILE *fp)
734
0
{
735
0
  return strbuf_getdelim_strip_crlf(sb, fp, '\n');
736
0
}
737
738
int strbuf_getline_lf(struct strbuf *sb, FILE *fp)
739
0
{
740
0
  return strbuf_getdelim(sb, fp, '\n');
741
0
}
742
743
int strbuf_getline_nul(struct strbuf *sb, FILE *fp)
744
0
{
745
0
  return strbuf_getdelim(sb, fp, '\0');
746
0
}
747
748
int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
749
0
{
750
0
  strbuf_reset(sb);
751
752
0
  while (1) {
753
0
    char ch;
754
0
    ssize_t len = xread(fd, &ch, 1);
755
0
    if (len <= 0)
756
0
      return EOF;
757
0
    strbuf_addch(sb, ch);
758
0
    if (ch == term)
759
0
      break;
760
0
  }
761
0
  return 0;
762
0
}
763
764
ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
765
0
{
766
0
  int fd;
767
0
  ssize_t len;
768
0
  int saved_errno;
769
770
0
  fd = open(path, O_RDONLY);
771
0
  if (fd < 0)
772
0
    return -1;
773
0
  len = strbuf_read(sb, fd, hint);
774
0
  saved_errno = errno;
775
0
  close(fd);
776
0
  if (len < 0) {
777
0
    errno = saved_errno;
778
0
    return -1;
779
0
  }
780
781
0
  return len;
782
0
}
783
784
void strbuf_add_lines(struct strbuf *out, const char *prefix,
785
          const char *buf, size_t size)
786
0
{
787
0
  add_lines(out, prefix, buf, size, 0);
788
0
}
789
790
void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
791
0
{
792
0
  while (*s) {
793
0
    size_t len = strcspn(s, "\"<>&");
794
0
    strbuf_add(buf, s, len);
795
0
    s += len;
796
0
    switch (*s) {
797
0
    case '"':
798
0
      strbuf_addstr(buf, "&quot;");
799
0
      break;
800
0
    case '<':
801
0
      strbuf_addstr(buf, "&lt;");
802
0
      break;
803
0
    case '>':
804
0
      strbuf_addstr(buf, "&gt;");
805
0
      break;
806
0
    case '&':
807
0
      strbuf_addstr(buf, "&amp;");
808
0
      break;
809
0
    case 0:
810
0
      return;
811
0
    }
812
0
    s++;
813
0
  }
814
0
}
815
816
static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
817
         char_predicate allow_unencoded_fn)
818
0
{
819
0
  strbuf_grow(sb, len);
820
0
  while (len--) {
821
0
    char ch = *s++;
822
0
    if (allow_unencoded_fn(ch))
823
0
      strbuf_addch(sb, ch);
824
0
    else
825
0
      strbuf_addf(sb, "%%%02x", (unsigned char)ch);
826
0
  }
827
0
}
828
829
void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
830
           char_predicate allow_unencoded_fn)
831
0
{
832
0
  strbuf_add_urlencode(sb, s, strlen(s), allow_unencoded_fn);
833
0
}
834
835
static void strbuf_humanise(struct strbuf *buf, off_t bytes,
836
         int humanise_rate)
837
0
{
838
0
  if (bytes > 1 << 30) {
839
0
    strbuf_addf(buf,
840
0
        humanise_rate == 0 ?
841
          /* TRANSLATORS: IEC 80000-13:2008 gibibyte */
842
0
          _("%u.%2.2u GiB") :
843
          /* TRANSLATORS: IEC 80000-13:2008 gibibyte/second */
844
0
          _("%u.%2.2u GiB/s"),
845
0
          (unsigned)(bytes >> 30),
846
0
          (unsigned)(bytes & ((1 << 30) - 1)) / 10737419);
847
0
  } else if (bytes > 1 << 20) {
848
0
    unsigned x = bytes + 5243;  /* for rounding */
849
0
    strbuf_addf(buf,
850
0
        humanise_rate == 0 ?
851
          /* TRANSLATORS: IEC 80000-13:2008 mebibyte */
852
0
          _("%u.%2.2u MiB") :
853
          /* TRANSLATORS: IEC 80000-13:2008 mebibyte/second */
854
0
          _("%u.%2.2u MiB/s"),
855
0
          x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
856
0
  } else if (bytes > 1 << 10) {
857
0
    unsigned x = bytes + 5;  /* for rounding */
858
0
    strbuf_addf(buf,
859
0
        humanise_rate == 0 ?
860
          /* TRANSLATORS: IEC 80000-13:2008 kibibyte */
861
0
          _("%u.%2.2u KiB") :
862
          /* TRANSLATORS: IEC 80000-13:2008 kibibyte/second */
863
0
          _("%u.%2.2u KiB/s"),
864
0
          x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
865
0
  } else {
866
0
    strbuf_addf(buf,
867
0
        humanise_rate == 0 ?
868
          /* TRANSLATORS: IEC 80000-13:2008 byte */
869
0
          Q_("%u byte", "%u bytes", bytes) :
870
          /* TRANSLATORS: IEC 80000-13:2008 byte/second */
871
0
          Q_("%u byte/s", "%u bytes/s", bytes),
872
0
        (unsigned)bytes);
873
0
  }
874
0
}
875
876
void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
877
0
{
878
0
  strbuf_humanise(buf, bytes, 0);
879
0
}
880
881
void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)
882
0
{
883
0
  strbuf_humanise(buf, bytes, 1);
884
0
}
885
886
int printf_ln(const char *fmt, ...)
887
0
{
888
0
  int ret;
889
0
  va_list ap;
890
0
  va_start(ap, fmt);
891
0
  ret = vprintf(fmt, ap);
892
0
  va_end(ap);
893
0
  if (ret < 0 || putchar('\n') == EOF)
894
0
    return -1;
895
0
  return ret + 1;
896
0
}
897
898
int fprintf_ln(FILE *fp, const char *fmt, ...)
899
0
{
900
0
  int ret;
901
0
  va_list ap;
902
0
  va_start(ap, fmt);
903
0
  ret = vfprintf(fp, fmt, ap);
904
0
  va_end(ap);
905
0
  if (ret < 0 || putc('\n', fp) == EOF)
906
0
    return -1;
907
0
  return ret + 1;
908
0
}
909
910
char *xstrdup_tolower(const char *string)
911
0
{
912
0
  char *result;
913
0
  size_t len, i;
914
915
0
  len = strlen(string);
916
0
  result = xmallocz(len);
917
0
  for (i = 0; i < len; i++)
918
0
    result[i] = tolower(string[i]);
919
0
  return result;
920
0
}
921
922
char *xstrdup_toupper(const char *string)
923
0
{
924
0
  char *result;
925
0
  size_t len, i;
926
927
0
  len = strlen(string);
928
0
  result = xmallocz(len);
929
0
  for (i = 0; i < len; i++)
930
0
    result[i] = toupper(string[i]);
931
0
  return result;
932
0
}
933
934
char *xstrvfmt(const char *fmt, va_list ap)
935
0
{
936
0
  struct strbuf buf = STRBUF_INIT;
937
0
  strbuf_vaddf(&buf, fmt, ap);
938
0
  return strbuf_detach(&buf, NULL);
939
0
}
940
941
char *xstrfmt(const char *fmt, ...)
942
0
{
943
0
  va_list ap;
944
0
  char *ret;
945
946
0
  va_start(ap, fmt);
947
0
  ret = xstrvfmt(fmt, ap);
948
0
  va_end(ap);
949
950
0
  return ret;
951
0
}
952
953
void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
954
         int tz_offset, int suppress_tz_name)
955
0
{
956
0
  struct strbuf munged_fmt = STRBUF_INIT;
957
0
  size_t hint = 128;
958
0
  size_t len;
959
960
0
  if (!*fmt)
961
0
    return;
962
963
  /*
964
   * There is no portable way to pass timezone information to
965
   * strftime, so we handle %z and %Z here. Likewise '%s', because
966
   * going back to an epoch time requires knowing the zone.
967
   *
968
   * Note that tz_offset is in the "[-+]HHMM" decimal form; this is what
969
   * we want for %z, but the computation for %s has to convert to number
970
   * of seconds.
971
   */
972
0
  while (strbuf_expand_step(&munged_fmt, &fmt)) {
973
0
    if (skip_prefix(fmt, "%", &fmt))
974
0
      strbuf_addstr(&munged_fmt, "%%");
975
0
    else if (skip_prefix(fmt, "s", &fmt))
976
0
      strbuf_addf(&munged_fmt, "%"PRItime,
977
0
            (timestamp_t)tm_to_time_t(tm) -
978
0
            3600 * (tz_offset / 100) -
979
0
            60 * (tz_offset % 100));
980
0
    else if (skip_prefix(fmt, "z", &fmt))
981
0
      strbuf_addf(&munged_fmt, "%+05d", tz_offset);
982
0
    else if (suppress_tz_name && skip_prefix(fmt, "Z", &fmt))
983
0
      ; /* nothing */
984
0
    else
985
0
      strbuf_addch(&munged_fmt, '%');
986
0
  }
987
0
  fmt = munged_fmt.buf;
988
989
0
  strbuf_grow(sb, hint);
990
0
  len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
991
992
0
  if (!len) {
993
    /*
994
     * strftime reports "0" if it could not fit the result in the buffer.
995
     * Unfortunately, it also reports "0" if the requested time string
996
     * takes 0 bytes. So our strategy is to munge the format so that the
997
     * output contains at least one character, and then drop the extra
998
     * character before returning.
999
     */
1000
0
    strbuf_addch(&munged_fmt, ' ');
1001
0
    while (!len) {
1002
0
      hint *= 2;
1003
0
      strbuf_grow(sb, hint);
1004
0
      len = strftime(sb->buf + sb->len, sb->alloc - sb->len,
1005
0
               munged_fmt.buf, tm);
1006
0
    }
1007
0
    len--; /* drop munged space */
1008
0
  }
1009
0
  strbuf_release(&munged_fmt);
1010
0
  strbuf_setlen(sb, sb->len + len);
1011
0
}
1012
1013
/*
1014
 * Returns the length of a line, without trailing spaces.
1015
 *
1016
 * If the line ends with newline, it will be removed too.
1017
 */
1018
static size_t cleanup(char *line, size_t len)
1019
0
{
1020
0
  while (len) {
1021
0
    unsigned char c = line[len - 1];
1022
0
    if (!isspace(c))
1023
0
      break;
1024
0
    len--;
1025
0
  }
1026
1027
0
  return len;
1028
0
}
1029
1030
/*
1031
 * Remove empty lines from the beginning and end
1032
 * and also trailing spaces from every line.
1033
 *
1034
 * Turn multiple consecutive empty lines between paragraphs
1035
 * into just one empty line.
1036
 *
1037
 * If the input has only empty lines and spaces,
1038
 * no output will be produced.
1039
 *
1040
 * If last line does not have a newline at the end, one is added.
1041
 *
1042
 * Pass a non-NULL comment_prefix to skip every line starting
1043
 * with it.
1044
 */
1045
void strbuf_stripspace(struct strbuf *sb, const char *comment_prefix)
1046
0
{
1047
0
  size_t empties = 0;
1048
0
  size_t i, j, len, newlen;
1049
0
  char *eol;
1050
1051
  /* We may have to add a newline. */
1052
0
  strbuf_grow(sb, 1);
1053
1054
0
  for (i = j = 0; i < sb->len; i += len, j += newlen) {
1055
0
    eol = memchr(sb->buf + i, '\n', sb->len - i);
1056
0
    len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
1057
1058
0
    if (comment_prefix && len &&
1059
0
        starts_with(sb->buf + i, comment_prefix)) {
1060
0
      newlen = 0;
1061
0
      continue;
1062
0
    }
1063
0
    newlen = cleanup(sb->buf + i, len);
1064
1065
    /* Not just an empty line? */
1066
0
    if (newlen) {
1067
0
      if (empties > 0 && j > 0)
1068
0
        sb->buf[j++] = '\n';
1069
0
      empties = 0;
1070
0
      memmove(sb->buf + j, sb->buf + i, newlen);
1071
0
      sb->buf[newlen + j++] = '\n';
1072
0
    } else {
1073
0
      empties++;
1074
0
    }
1075
0
  }
1076
1077
0
  strbuf_setlen(sb, j);
1078
0
}
1079
1080
void strbuf_strip_file_from_path(struct strbuf *sb)
1081
0
{
1082
0
  char *path_sep = find_last_dir_sep(sb->buf);
1083
0
  strbuf_setlen(sb, path_sep ? path_sep - sb->buf + 1 : 0);
1084
0
}