Git fork

Merge branch 'jc/strbuf-split'

Arrays of strbuf is often a wrong data structure to use, and
strbuf_split*() family of functions that create them often have
better alternatives.

Update several code paths and replace strbuf_split*().

* jc/strbuf-split:
trace2: do not use strbuf_split*()
trace2: trim_trailing_newline followed by trim is a no-op
sub-process: do not use strbuf_split*()
environment: do not use strbuf_split*()
config: do not use strbuf_split()
notes: do not use strbuf_split*()
merge-tree: do not use strbuf_split*()
clean: do not use strbuf_split*() [part 2]
clean: do not pass the whole structure when it is not necessary
clean: do not use strbuf_split*() [part 1]
clean: do not pass strbuf by value
wt-status: avoid strbuf_split*()

+129 -166
+36 -38
builtin/clean.c
··· 478 478 */ 479 479 static int parse_choice(struct menu_stuff *menu_stuff, 480 480 int is_single, 481 - struct strbuf input, 481 + char *input, 482 482 int **chosen) 483 483 { 484 - struct strbuf **choice_list, **ptr; 484 + struct string_list choice = STRING_LIST_INIT_NODUP; 485 + struct string_list_item *item; 485 486 int nr = 0; 486 487 int i; 487 488 488 - if (is_single) { 489 - choice_list = strbuf_split_max(&input, '\n', 0); 490 - } else { 491 - char *p = input.buf; 492 - do { 493 - if (*p == ',') 494 - *p = ' '; 495 - } while (*p++); 496 - choice_list = strbuf_split_max(&input, ' ', 0); 497 - } 489 + string_list_split_in_place_f(&choice, input, 490 + is_single ? "\n" : ", ", -1, 491 + STRING_LIST_SPLIT_TRIM); 498 492 499 - for (ptr = choice_list; *ptr; ptr++) { 500 - char *p; 501 - int choose = 1; 493 + for_each_string_list_item(item, &choice) { 494 + const char *string; 495 + int choose; 502 496 int bottom = 0, top = 0; 503 497 int is_range, is_number; 504 498 505 - strbuf_trim(*ptr); 506 - if (!(*ptr)->len) 499 + string = item->string; 500 + if (!*string) 507 501 continue; 508 502 509 503 /* Input that begins with '-'; unchoose */ 510 - if (*(*ptr)->buf == '-') { 504 + if (string[0] == '-') { 511 505 choose = 0; 512 - strbuf_remove((*ptr), 0, 1); 506 + string++; 507 + } else { 508 + choose = 1; 513 509 } 514 510 515 511 is_range = 0; 516 512 is_number = 1; 517 - for (p = (*ptr)->buf; *p; p++) { 513 + for (const char *p = string; *p; p++) { 518 514 if ('-' == *p) { 519 515 if (!is_range) { 520 516 is_range = 1; ··· 532 528 } 533 529 534 530 if (is_number) { 535 - bottom = atoi((*ptr)->buf); 531 + bottom = atoi(string); 536 532 top = bottom; 537 533 } else if (is_range) { 538 - bottom = atoi((*ptr)->buf); 534 + bottom = atoi(string); 539 535 /* a range can be specified like 5-7 or 5- */ 540 - if (!*(strchr((*ptr)->buf, '-') + 1)) 536 + if (!*(strchr(string, '-') + 1)) 541 537 top = menu_stuff->nr; 542 538 else 543 - top = atoi(strchr((*ptr)->buf, '-') + 1); 544 - } else if (!strcmp((*ptr)->buf, "*")) { 539 + top = atoi(strchr(string, '-') + 1); 540 + } else if (!strcmp(string, "*")) { 545 541 bottom = 1; 546 542 top = menu_stuff->nr; 547 543 } else { 548 - bottom = find_unique((*ptr)->buf, menu_stuff); 544 + bottom = find_unique(string, menu_stuff); 549 545 top = bottom; 550 546 } 551 547 552 548 if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top || 553 549 (is_single && bottom != top)) { 554 550 clean_print_color(CLEAN_COLOR_ERROR); 555 - printf(_("Huh (%s)?\n"), (*ptr)->buf); 551 + printf(_("Huh (%s)?\n"), string); 556 552 clean_print_color(CLEAN_COLOR_RESET); 557 553 continue; 558 554 } ··· 561 557 (*chosen)[i-1] = choose; 562 558 } 563 559 564 - strbuf_list_free(choice_list); 560 + string_list_clear(&choice, 0); 565 561 566 562 for (i = 0; i < menu_stuff->nr; i++) 567 563 nr += (*chosen)[i]; ··· 631 627 632 628 nr = parse_choice(stuff, 633 629 opts->flags & MENU_OPTS_SINGLETON, 634 - choice, 630 + choice.buf, 635 631 &chosen); 636 632 637 633 if (opts->flags & MENU_OPTS_SINGLETON) { ··· 679 675 { 680 676 struct dir_struct dir = DIR_INIT; 681 677 struct strbuf confirm = STRBUF_INIT; 682 - struct strbuf **ignore_list; 683 - struct string_list_item *item; 684 678 struct pattern_list *pl; 685 679 int changed = -1, i; 686 680 687 681 for (;;) { 682 + struct string_list ignore_list = STRING_LIST_INIT_NODUP; 683 + struct string_list_item *item; 684 + 688 685 if (!del_list.nr) 689 686 break; 690 687 ··· 702 699 break; 703 700 704 701 pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude"); 705 - ignore_list = strbuf_split_max(&confirm, ' ', 0); 706 702 707 - for (i = 0; ignore_list[i]; i++) { 708 - strbuf_trim(ignore_list[i]); 709 - if (!ignore_list[i]->len) 710 - continue; 703 + string_list_split_in_place_f(&ignore_list, confirm.buf, " ", -1, 704 + STRING_LIST_SPLIT_TRIM); 711 705 712 - add_pattern(ignore_list[i]->buf, "", 0, pl, -(i+1)); 706 + for (i = 0; i < ignore_list.nr; i++) { 707 + item = &ignore_list.items[i]; 708 + if (!*item->string) 709 + continue; 710 + add_pattern(item->string, "", 0, pl, -(i+1)); 713 711 } 714 712 715 713 changed = 0; ··· 730 728 clean_print_color(CLEAN_COLOR_RESET); 731 729 } 732 730 733 - strbuf_list_free(ignore_list); 731 + string_list_clear(&ignore_list, 0); 734 732 dir_clear(&dir); 735 733 } 736 734
+16 -14
builtin/merge-tree.c
··· 619 619 "--merge-base", "--stdin"); 620 620 line_termination = '\0'; 621 621 while (strbuf_getline_lf(&buf, stdin) != EOF) { 622 - struct strbuf **split; 622 + struct string_list split = STRING_LIST_INIT_NODUP; 623 623 const char *input_merge_base = NULL; 624 624 625 - split = strbuf_split(&buf, ' '); 626 - if (!split[0] || !split[1]) 625 + string_list_split_in_place_f(&split, buf.buf, " ", -1, 626 + STRING_LIST_SPLIT_TRIM); 627 + 628 + if (split.nr < 2) 627 629 die(_("malformed input line: '%s'."), buf.buf); 628 - strbuf_rtrim(split[0]); 629 - strbuf_rtrim(split[1]); 630 630 631 631 /* parse the merge-base */ 632 - if (!strcmp(split[1]->buf, "--")) { 633 - input_merge_base = split[0]->buf; 632 + if (!strcmp(split.items[1].string, "--")) { 633 + input_merge_base = split.items[0].string; 634 634 } 635 635 636 - if (input_merge_base && split[2] && split[3] && !split[4]) { 637 - strbuf_rtrim(split[2]); 638 - strbuf_rtrim(split[3]); 639 - real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix); 640 - } else if (!input_merge_base && !split[2]) { 641 - real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix); 636 + if (input_merge_base && split.nr == 4) { 637 + real_merge(&o, input_merge_base, 638 + split.items[2].string, split.items[3].string, 639 + prefix); 640 + } else if (!input_merge_base && split.nr == 2) { 641 + real_merge(&o, NULL, 642 + split.items[0].string, split.items[1].string, 643 + prefix); 642 644 } else { 643 645 die(_("malformed input line: '%s'."), buf.buf); 644 646 } 645 647 maybe_flush_or_die(stdout, "stdout"); 646 648 647 - strbuf_list_free(split); 649 + string_list_clear(&split, 0); 648 650 } 649 651 strbuf_release(&buf); 650 652
+12 -11
builtin/notes.c
··· 376 376 377 377 while (strbuf_getline_lf(&buf, stdin) != EOF) { 378 378 struct object_id from_obj, to_obj; 379 - struct strbuf **split; 379 + struct string_list split = STRING_LIST_INIT_NODUP; 380 380 int err; 381 381 382 - split = strbuf_split(&buf, ' '); 383 - if (!split[0] || !split[1]) 382 + string_list_split_in_place_f(&split, buf.buf, " ", -1, 383 + STRING_LIST_SPLIT_TRIM); 384 + if (split.nr < 2) 384 385 die(_("malformed input line: '%s'."), buf.buf); 385 - strbuf_rtrim(split[0]); 386 - strbuf_rtrim(split[1]); 387 - if (repo_get_oid(the_repository, split[0]->buf, &from_obj)) 388 - die(_("failed to resolve '%s' as a valid ref."), split[0]->buf); 389 - if (repo_get_oid(the_repository, split[1]->buf, &to_obj)) 390 - die(_("failed to resolve '%s' as a valid ref."), split[1]->buf); 386 + if (repo_get_oid(the_repository, split.items[0].string, &from_obj)) 387 + die(_("failed to resolve '%s' as a valid ref."), 388 + split.items[0].string); 389 + if (repo_get_oid(the_repository, split.items[1].string, &to_obj)) 390 + die(_("failed to resolve '%s' as a valid ref."), 391 + split.items[1].string); 391 392 392 393 if (rewrite_cmd) 393 394 err = copy_note_for_rewrite(c, &from_obj, &to_obj); ··· 397 398 398 399 if (err) { 399 400 error(_("failed to copy notes from '%s' to '%s'"), 400 - split[0]->buf, split[1]->buf); 401 + split.items[0].string, split.items[1].string); 401 402 ret = 1; 402 403 } 403 404 404 - strbuf_list_free(split); 405 + string_list_clear(&split, 0); 405 406 } 406 407 407 408 if (!rewrite_cmd) {
+10 -13
config.c
··· 629 629 config_fn_t fn, void *data) 630 630 { 631 631 const char *value; 632 - struct strbuf **pair; 632 + struct string_list pair = STRING_LIST_INIT_DUP; 633 633 int ret; 634 634 struct key_value_info kvi = KVI_INIT; 635 635 636 636 kvi_from_param(&kvi); 637 637 638 - pair = strbuf_split_str(text, '=', 2); 639 - if (!pair[0]) 638 + string_list_split(&pair, text, "=", 1); 639 + if (!pair.nr) 640 640 return error(_("bogus config parameter: %s"), text); 641 641 642 - if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') { 643 - strbuf_setlen(pair[0], pair[0]->len - 1); 644 - value = pair[1] ? pair[1]->buf : ""; 645 - } else { 642 + if (pair.nr == 1) 646 643 value = NULL; 647 - } 644 + else 645 + value = pair.items[1].string; 648 646 649 - strbuf_trim(pair[0]); 650 - if (!pair[0]->len) { 651 - strbuf_list_free(pair); 647 + if (!*pair.items[0].string) { 648 + string_list_clear(&pair, 0); 652 649 return error(_("bogus config parameter: %s"), text); 653 650 } 654 651 655 - ret = config_parse_pair(pair[0]->buf, value, &kvi, fn, data); 656 - strbuf_list_free(pair); 652 + ret = config_parse_pair(pair.items[0].string, value, &kvi, fn, data); 653 + string_list_clear(&pair, 0); 657 654 return ret; 658 655 } 659 656
+12 -7
environment.c
··· 175 175 const char *get_git_namespace(void) 176 176 { 177 177 static const char *namespace; 178 - 179 178 struct strbuf buf = STRBUF_INIT; 180 - struct strbuf **components, **c; 181 179 const char *raw_namespace; 180 + struct string_list components = STRING_LIST_INIT_DUP; 181 + struct string_list_item *item; 182 182 183 183 if (namespace) 184 184 return namespace; ··· 190 190 } 191 191 192 192 strbuf_addstr(&buf, raw_namespace); 193 - components = strbuf_split(&buf, '/'); 193 + 194 + string_list_split(&components, buf.buf, "/", -1); 194 195 strbuf_reset(&buf); 195 - for (c = components; *c; c++) 196 - if (strcmp((*c)->buf, "/") != 0) 197 - strbuf_addf(&buf, "refs/namespaces/%s", (*c)->buf); 198 - strbuf_list_free(components); 196 + 197 + for_each_string_list_item(item, &components) { 198 + if (item->string[0]) 199 + strbuf_addf(&buf, "refs/namespaces/%s/", item->string); 200 + } 201 + string_list_clear(&components, 0); 202 + 203 + strbuf_trim_trailing_dir_sep(&buf); 199 204 if (check_refname_format(buf.buf, 0)) 200 205 die(_("bad git namespace path \"%s\""), raw_namespace); 201 206 strbuf_addch(&buf, '/');
+6 -9
sub-process.c
··· 30 30 31 31 int subprocess_read_status(int fd, struct strbuf *status) 32 32 { 33 - struct strbuf **pair; 34 - char *line; 35 33 int len; 36 34 37 35 for (;;) { 36 + char *line; 37 + const char *value; 38 + 38 39 len = packet_read_line_gently(fd, NULL, &line); 39 40 if ((len < 0) || !line) 40 41 break; 41 - pair = strbuf_split_str(line, '=', 2); 42 - if (pair[0] && pair[0]->len && pair[1]) { 42 + if (skip_prefix(line, "status=", &value)) { 43 43 /* the last "status=<foo>" line wins */ 44 - if (!strcmp(pair[0]->buf, "status=")) { 45 - strbuf_reset(status); 46 - strbuf_addbuf(status, pair[1]); 47 - } 44 + strbuf_reset(status); 45 + strbuf_addstr(status, value); 48 46 } 49 - strbuf_list_free(pair); 50 47 } 51 48 52 49 return (len < 0) ? len : 0;
+27 -53
trace2/tr2_cfg.c
··· 8 8 #include "trace2/tr2_sysenv.h" 9 9 #include "wildmatch.h" 10 10 11 - static struct strbuf **tr2_cfg_patterns; 12 - static int tr2_cfg_count_patterns; 11 + static struct string_list tr2_cfg_patterns = STRING_LIST_INIT_DUP; 13 12 static int tr2_cfg_loaded; 14 13 15 - static struct strbuf **tr2_cfg_env_vars; 16 - static int tr2_cfg_env_vars_count; 14 + static struct string_list tr2_cfg_env_vars = STRING_LIST_INIT_DUP; 17 15 static int tr2_cfg_env_vars_loaded; 18 16 19 17 /* 20 18 * Parse a string containing a comma-delimited list of config keys 21 - * or wildcard patterns into a list of strbufs. 19 + * or wildcard patterns into a string list. 22 20 */ 23 - static int tr2_cfg_load_patterns(void) 21 + static size_t tr2_cfg_load_patterns(void) 24 22 { 25 - struct strbuf **s; 26 23 const char *envvar; 27 24 28 25 if (tr2_cfg_loaded) 29 - return tr2_cfg_count_patterns; 26 + return tr2_cfg_patterns.nr; 30 27 tr2_cfg_loaded = 1; 31 28 32 29 envvar = tr2_sysenv_get(TR2_SYSENV_CFG_PARAM); 33 30 if (!envvar || !*envvar) 34 - return tr2_cfg_count_patterns; 35 - 36 - tr2_cfg_patterns = strbuf_split_buf(envvar, strlen(envvar), ',', -1); 37 - for (s = tr2_cfg_patterns; *s; s++) { 38 - struct strbuf *buf = *s; 39 - 40 - if (buf->len && buf->buf[buf->len - 1] == ',') 41 - strbuf_setlen(buf, buf->len - 1); 42 - strbuf_trim_trailing_newline(*s); 43 - strbuf_trim(*s); 44 - } 31 + return tr2_cfg_patterns.nr; 45 32 46 - tr2_cfg_count_patterns = s - tr2_cfg_patterns; 47 - return tr2_cfg_count_patterns; 33 + string_list_split_f(&tr2_cfg_patterns, envvar, ",", -1, 34 + STRING_LIST_SPLIT_TRIM); 35 + return tr2_cfg_patterns.nr; 48 36 } 49 37 50 38 void tr2_cfg_free_patterns(void) 51 39 { 52 - if (tr2_cfg_patterns) 53 - strbuf_list_free(tr2_cfg_patterns); 54 - tr2_cfg_count_patterns = 0; 40 + if (tr2_cfg_patterns.nr) 41 + string_list_clear(&tr2_cfg_patterns, 0); 55 42 tr2_cfg_loaded = 0; 56 43 } 57 44 58 45 /* 59 46 * Parse a string containing a comma-delimited list of environment variable 60 - * names into a list of strbufs. 47 + * names into a string list. 61 48 */ 62 - static int tr2_load_env_vars(void) 49 + static size_t tr2_load_env_vars(void) 63 50 { 64 - struct strbuf **s; 65 51 const char *varlist; 66 52 67 53 if (tr2_cfg_env_vars_loaded) 68 - return tr2_cfg_env_vars_count; 54 + return tr2_cfg_env_vars.nr; 69 55 tr2_cfg_env_vars_loaded = 1; 70 56 71 57 varlist = tr2_sysenv_get(TR2_SYSENV_ENV_VARS); 72 58 if (!varlist || !*varlist) 73 - return tr2_cfg_env_vars_count; 74 - 75 - tr2_cfg_env_vars = strbuf_split_buf(varlist, strlen(varlist), ',', -1); 76 - for (s = tr2_cfg_env_vars; *s; s++) { 77 - struct strbuf *buf = *s; 78 - 79 - if (buf->len && buf->buf[buf->len - 1] == ',') 80 - strbuf_setlen(buf, buf->len - 1); 81 - strbuf_trim_trailing_newline(*s); 82 - strbuf_trim(*s); 83 - } 59 + return tr2_cfg_env_vars.nr; 84 60 85 - tr2_cfg_env_vars_count = s - tr2_cfg_env_vars; 86 - return tr2_cfg_env_vars_count; 61 + string_list_split_f(&tr2_cfg_env_vars, varlist, ",", -1, 62 + STRING_LIST_SPLIT_TRIM); 63 + return tr2_cfg_env_vars.nr; 87 64 } 88 65 89 66 void tr2_cfg_free_env_vars(void) 90 67 { 91 - if (tr2_cfg_env_vars) 92 - strbuf_list_free(tr2_cfg_env_vars); 93 - tr2_cfg_env_vars_count = 0; 68 + if (tr2_cfg_env_vars.nr) 69 + string_list_clear(&tr2_cfg_env_vars, 0); 94 70 tr2_cfg_env_vars_loaded = 0; 95 71 } 96 72 ··· 105 81 static int tr2_cfg_cb(const char *key, const char *value, 106 82 const struct config_context *ctx, void *d) 107 83 { 108 - struct strbuf **s; 84 + struct string_list_item *item; 109 85 struct tr2_cfg_data *data = (struct tr2_cfg_data *)d; 110 86 111 - for (s = tr2_cfg_patterns; *s; s++) { 112 - struct strbuf *buf = *s; 113 - int wm = wildmatch(buf->buf, key, WM_CASEFOLD); 87 + for_each_string_list_item(item, &tr2_cfg_patterns) { 88 + int wm = wildmatch(item->string, key, WM_CASEFOLD); 114 89 if (wm == WM_MATCH) { 115 90 trace2_def_param_fl(data->file, data->line, key, value, 116 91 ctx->kvi); ··· 132 107 void tr2_list_env_vars_fl(const char *file, int line) 133 108 { 134 109 struct key_value_info kvi = KVI_INIT; 135 - struct strbuf **s; 110 + struct string_list_item *item; 136 111 137 112 kvi_from_param(&kvi); 138 113 if (tr2_load_env_vars() <= 0) 139 114 return; 140 115 141 - for (s = tr2_cfg_env_vars; *s; s++) { 142 - struct strbuf *buf = *s; 143 - const char *val = getenv(buf->buf); 116 + for_each_string_list_item(item, &tr2_cfg_env_vars) { 117 + const char *val = getenv(item->string); 144 118 if (val && *val) 145 - trace2_def_param_fl(file, line, buf->buf, val, &kvi); 119 + trace2_def_param_fl(file, line, item->string, val, &kvi); 146 120 } 147 121 } 148 122
+10 -21
wt-status.c
··· 1352 1352 */ 1353 1353 static void abbrev_oid_in_line(struct strbuf *line) 1354 1354 { 1355 - struct strbuf **split; 1356 - int i; 1355 + struct string_list split = STRING_LIST_INIT_DUP; 1356 + struct object_id oid; 1357 1357 1358 1358 if (starts_with(line->buf, "exec ") || 1359 1359 starts_with(line->buf, "x ") || ··· 1361 1361 starts_with(line->buf, "l ")) 1362 1362 return; 1363 1363 1364 - split = strbuf_split_max(line, ' ', 3); 1365 - if (split[0] && split[1]) { 1366 - struct object_id oid; 1367 - 1368 - /* 1369 - * strbuf_split_max left a space. Trim it and re-add 1370 - * it after abbreviation. 1371 - */ 1372 - strbuf_trim(split[1]); 1373 - if (!repo_get_oid(the_repository, split[1]->buf, &oid)) { 1374 - strbuf_reset(split[1]); 1375 - strbuf_add_unique_abbrev(split[1], &oid, 1376 - DEFAULT_ABBREV); 1377 - strbuf_addch(split[1], ' '); 1378 - strbuf_reset(line); 1379 - for (i = 0; split[i]; i++) 1380 - strbuf_addbuf(line, split[i]); 1381 - } 1364 + if ((2 <= string_list_split(&split, line->buf, " ", 2)) && 1365 + !repo_get_oid(the_repository, split.items[1].string, &oid)) { 1366 + strbuf_reset(line); 1367 + strbuf_addf(line, "%s ", split.items[0].string); 1368 + strbuf_add_unique_abbrev(line, &oid, DEFAULT_ABBREV); 1369 + for (size_t i = 2; i < split.nr; i++) 1370 + strbuf_addf(line, " %s", split.items[i].string); 1382 1371 } 1383 - strbuf_list_free(split); 1372 + string_list_clear(&split, 0); 1384 1373 } 1385 1374 1386 1375 static int read_rebase_todolist(const char *fname, struct string_list *lines)