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