From: Junio C Hamano Date: Mon, 13 Jun 2016 17:37:48 +0000 (-0700) Subject: Merge branch 'jk/parseopt-string-list' into jk/string-list-static-init X-Git-Tag: v2.10.0-rc0~166^2~1 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/7013220d2b3181d4ae55e21e0f18b9abfd6e011d?hp=-c Merge branch 'jk/parseopt-string-list' into jk/string-list-static-init * jk/parseopt-string-list: blame,shortlog: don't make local option variables static interpret-trailers: don't duplicate option strings parse_opt_string_list: stop allocating new strings --- 7013220d2b3181d4ae55e21e0f18b9abfd6e011d diff --combined builtin/blame.c index 21f42b0b62,9b1701d314..80d24315b3 --- a/builtin/blame.c +++ b/builtin/blame.c @@@ -28,7 -28,6 +28,7 @@@ #include "line-range.h" #include "line-log.h" #include "dir.h" +#include "progress.h" static char blame_usage[] = N_("git blame [] [] [] [--] "); @@@ -51,7 -50,6 +51,7 @@@ static int incremental static int xdl_opts; static int abbrev = -1; static int no_whole_file_rename; +static int show_progress; static struct date_mode blame_date_mode = { DATE_ISO8601 }; static size_t blame_date_width; @@@ -129,11 -127,6 +129,11 @@@ struct origin char path[FLEX_ARRAY]; }; +struct progress_info { + struct progress *progress; + int blamed_lines; +}; + static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen, xdl_emit_hunk_consume_func_t hunk_func, void *cb_data) { @@@ -466,11 -459,12 +466,11 @@@ static void queue_blames(struct scorebo static struct origin *make_origin(struct commit *commit, const char *path) { struct origin *o; - o = xcalloc(1, sizeof(*o) + strlen(path) + 1); + FLEX_ALLOC_STR(o, path, path); o->commit = commit; o->refcnt = 1; o->next = commit->util; commit->util = o; - strcpy(o->path, path); return o; } @@@ -511,7 -505,7 +511,7 @@@ static int fill_blob_sha1_and_mode(stru { if (!is_null_sha1(origin->blob_sha1)) return 0; - if (get_tree_entry(origin->commit->object.sha1, + if (get_tree_entry(origin->commit->object.oid.hash, origin->path, origin->blob_sha1, &origin->mode)) goto error_out; @@@ -562,11 -556,11 +562,11 @@@ static struct origin *find_origin(struc PATHSPEC_LITERAL_PATH, "", paths); diff_setup_done(&diff_opts); - if (is_null_sha1(origin->commit->object.sha1)) - do_diff_cache(parent->tree->object.sha1, &diff_opts); + if (is_null_oid(&origin->commit->object.oid)) + do_diff_cache(parent->tree->object.oid.hash, &diff_opts); else - diff_tree_sha1(parent->tree->object.sha1, - origin->commit->tree->object.sha1, + diff_tree_sha1(parent->tree->object.oid.hash, + origin->commit->tree->object.oid.hash, "", &diff_opts); diffcore_std(&diff_opts); @@@ -632,11 -626,11 +632,11 @@@ static struct origin *find_rename(struc diff_opts.single_follow = origin->path; diff_setup_done(&diff_opts); - if (is_null_sha1(origin->commit->object.sha1)) - do_diff_cache(parent->tree->object.sha1, &diff_opts); + if (is_null_oid(&origin->commit->object.oid)) + do_diff_cache(parent->tree->object.oid.hash, &diff_opts); else - diff_tree_sha1(parent->tree->object.sha1, - origin->commit->tree->object.sha1, + diff_tree_sha1(parent->tree->object.oid.hash, + origin->commit->tree->object.oid.hash, "", &diff_opts); diffcore_std(&diff_opts); @@@ -982,8 -976,8 +982,8 @@@ static void pass_blame_to_parent(struc if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d)) die("unable to generate diff (%s -> %s)", - sha1_to_hex(parent->commit->object.sha1), - sha1_to_hex(target->commit->object.sha1)); + oid_to_hex(&parent->commit->object.oid), + oid_to_hex(&target->commit->object.oid)); /* The rest are the same as the parent */ blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent); *d.dstq = NULL; @@@ -1131,7 -1125,7 +1131,7 @@@ static void find_copy_in_blob(struct sc memset(split, 0, sizeof(struct blame_entry [3])); if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d)) die("unable to generate diff (%s)", - sha1_to_hex(parent->commit->object.sha1)); + oid_to_hex(&parent->commit->object.oid)); /* remainder, if any, all match the preimage */ handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split); } @@@ -1280,11 -1274,11 +1280,11 @@@ static void find_copy_in_parent(struct && (!porigin || strcmp(target->path, porigin->path)))) DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); - if (is_null_sha1(target->commit->object.sha1)) - do_diff_cache(parent->tree->object.sha1, &diff_opts); + if (is_null_oid(&target->commit->object.oid)) + do_diff_cache(parent->tree->object.oid.hash, &diff_opts); else - diff_tree_sha1(parent->tree->object.sha1, - target->commit->tree->object.sha1, + diff_tree_sha1(parent->tree->object.oid.hash, + target->commit->tree->object.oid.hash, "", &diff_opts); if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER)) @@@ -1695,7 -1689,7 +1695,7 @@@ static void get_commit_info(struct comm if (len) strbuf_add(&ret->summary, subject, len); else - strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1)); + strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid)); unuse_commit_buffer(commit, message); } @@@ -1738,7 -1732,7 +1738,7 @@@ static int emit_one_suspect_detail(stru printf("boundary\n"); if (suspect->previous) { struct origin *prev = suspect->previous; - printf("previous %s ", sha1_to_hex(prev->commit->object.sha1)); + printf("previous %s ", oid_to_hex(&prev->commit->object.oid)); write_name_quoted(prev->path, stdout, '\n'); } @@@ -1751,21 -1745,18 +1751,21 @@@ * The blame_entry is found to be guilty for the range. * Show it in incremental output. */ -static void found_guilty_entry(struct blame_entry *ent) +static void found_guilty_entry(struct blame_entry *ent, + struct progress_info *pi) { if (incremental) { struct origin *suspect = ent->suspect; printf("%s %d %d %d\n", - sha1_to_hex(suspect->commit->object.sha1), + oid_to_hex(&suspect->commit->object.oid), ent->s_lno + 1, ent->lno + 1, ent->num_lines); emit_one_suspect_detail(suspect, 0); write_filename_info(suspect->path); maybe_flush_or_die(stdout, "stdout"); } + pi->blamed_lines += ent->num_lines; + display_progress(pi->progress, pi->blamed_lines); } /* @@@ -1776,11 -1767,6 +1776,11 @@@ static void assign_blame(struct scorebo { struct rev_info *revs = sb->revs; struct commit *commit = prio_queue_get(&sb->commits); + struct progress_info pi = { NULL, 0 }; + + if (show_progress) + pi.progress = start_progress_delay(_("Blaming lines"), + sb->num_lines, 50, 1); while (commit) { struct blame_entry *ent; @@@ -1822,7 -1808,7 +1822,7 @@@ suspect->guilty = 1; for (;;) { struct blame_entry *next = ent->next; - found_guilty_entry(ent); + found_guilty_entry(ent, &pi); if (next) { ent = next; continue; @@@ -1838,8 -1824,6 +1838,8 @@@ if (DEBUG) /* sanity */ sanity_check_refcnt(sb); } + + stop_progress(&pi.progress); } static const char *format_time(unsigned long time, const char *tz_str, @@@ -1895,9 -1879,9 +1895,9 @@@ static void emit_porcelain(struct score int cnt; const char *cp; struct origin *suspect = ent->suspect; - char hex[41]; + char hex[GIT_SHA1_HEXSZ + 1]; - strcpy(hex, sha1_to_hex(suspect->commit->object.sha1)); + sha1_to_hex_r(hex, suspect->commit->object.oid.hash); printf("%s %d %d %d\n", hex, ent->s_lno + 1, @@@ -1933,11 -1917,11 +1933,11 @@@ static void emit_other(struct scoreboar const char *cp; struct origin *suspect = ent->suspect; struct commit_info ci; - char hex[41]; + char hex[GIT_SHA1_HEXSZ + 1]; int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP); get_commit_info(suspect->commit, &ci, 1); - strcpy(hex, sha1_to_hex(suspect->commit->object.sha1)); + sha1_to_hex_r(hex, suspect->commit->object.oid.hash); cp = nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { @@@ -2057,8 -2041,7 +2057,8 @@@ static int prepare_lines(struct scorebo for (p = buf; p < end; p = get_next_line(p, end)) num++; - sb->lineno = lineno = xmalloc(sizeof(*sb->lineno) * (num + 1)); + ALLOC_ARRAY(sb->lineno, num + 1); + lineno = sb->lineno; for (p = buf; p < end; p = get_next_line(p, end)) *lineno++ = p - buf; @@@ -2093,7 -2076,7 +2093,7 @@@ static int read_ancestry(const char *gr static int update_auto_abbrev(int auto_abbrev, struct origin *suspect) { - const char *uniq = find_unique_abbrev(suspect->commit->object.sha1, + const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash, auto_abbrev); int len = strlen(uniq); if (auto_abbrev < len) @@@ -2169,7 -2152,7 +2169,7 @@@ static void sanity_check_refcnt(struct if (ent->suspect->refcnt <= 0) { fprintf(stderr, "%s in %s has negative refcnt %d\n", ent->suspect->path, - sha1_to_hex(ent->suspect->commit->object.sha1), + oid_to_hex(&ent->suspect->commit->object.oid), ent->suspect->refcnt); baa = 1; } @@@ -2232,7 -2215,7 +2232,7 @@@ static void verify_working_tree_path(st struct commit_list *parents; for (parents = work_tree->parents; parents; parents = parents->next) { - const unsigned char *commit_sha1 = parents->item->object.sha1; + const unsigned char *commit_sha1 = parents->item->object.oid.hash; unsigned char blob_sha1[20]; unsigned mode; @@@ -2307,7 -2290,6 +2307,7 @@@ static struct commit *fake_working_tree unsigned mode; struct strbuf msg = STRBUF_INIT; + read_cache(); time(&now); commit = alloc_commit_node(); commit->object.parsed = 1; @@@ -2327,7 -2309,7 +2327,7 @@@ strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n"); for (parent = commit->parents; parent; parent = parent->next) strbuf_addf(&msg, "parent %s\n", - sha1_to_hex(parent->item->object.sha1)); + oid_to_hex(&parent->item->object.oid)); strbuf_addf(&msg, "author %s\n" "committer %s\n\n" @@@ -2409,18 -2391,26 +2409,18 @@@ ce->ce_mode = create_ce_mode(mode); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); - /* - * We are not going to write this out, so this does not matter - * right now, but someday we might optimize diff-index --cached - * with cache-tree information. - */ cache_tree_invalidate_path(&the_index, path); return commit; } -static char *prepare_final(struct scoreboard *sb) +static struct commit *find_single_final(struct rev_info *revs, + const char **name_p) { int i; - const char *final_commit_name = NULL; - struct rev_info *revs = sb->revs; + struct commit *found = NULL; + const char *name = NULL; - /* - * There must be one and only one positive commit in the - * revs->pending array. - */ for (i = 0; i < revs->pending.nr; i++) { struct object *obj = revs->pending.objects[i].item; if (obj->flags & UNINTERESTING) @@@ -2429,22 -2419,14 +2429,22 @@@ obj = deref_tag(obj, NULL, 0); if (obj->type != OBJ_COMMIT) die("Non commit %s?", revs->pending.objects[i].name); - if (sb->final) + if (found) die("More than one commit to dig from %s and %s?", - revs->pending.objects[i].name, - final_commit_name); - sb->final = (struct commit *) obj; - final_commit_name = revs->pending.objects[i].name; + revs->pending.objects[i].name, name); + found = (struct commit *)obj; + name = revs->pending.objects[i].name; } - return xstrdup_or_null(final_commit_name); + if (name_p) + *name_p = name; + return found; +} + +static char *prepare_final(struct scoreboard *sb) +{ + const char *name; + sb->final = find_single_final(sb->revs, &name); + return xstrdup_or_null(name); } static char *prepare_initial(struct scoreboard *sb) @@@ -2520,19 -2502,17 +2520,19 @@@ int cmd_blame(int argc, const char **ar long dashdash_pos, lno; char *final_commit_name = NULL; enum object_type type; + struct commit *final_commit = NULL; - static struct string_list range_list; - static int output_option = 0, opt = 0; - static int show_stats = 0; - static const char *revs_file = NULL; - static const char *contents_from = NULL; - static const struct option options[] = { + struct string_list range_list = STRING_LIST_INIT_NODUP; + int output_option = 0, opt = 0; + int show_stats = 0; + const char *revs_file = NULL; + const char *contents_from = NULL; + const struct option options[] = { OPT_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")), OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")), OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")), OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")), + OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")), OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE), OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME), OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER), @@@ -2568,7 -2548,6 +2568,7 @@@ save_commit_buffer = 0; dashdash_pos = 0; + show_progress = -1; parse_options_start(&ctx, argc, argv, prefix, options, PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0); @@@ -2593,13 -2572,6 +2593,13 @@@ parse_done DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES); argc = parse_options_end(&ctx); + if (incremental || (output_option & OUTPUT_PORCELAIN)) { + if (show_progress > 0) + die("--progress can't be used with --incremental or porcelain formats"); + show_progress = 0; + } else if (show_progress < 0) + show_progress = isatty(2); + if (0 < abbrev) /* one more abbrev length is needed for the boundary commit */ abbrev++; @@@ -2640,6 -2612,7 +2640,6 @@@ fewer display columns. */ blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */ break; - case DATE_LOCAL: case DATE_NORMAL: blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700"); break; @@@ -2719,11 -2692,11 +2719,11 @@@ } else if (contents_from) die("--contents and --reverse do not blend well."); - else if (revs.first_parent_only) - die("combining --first-parent and --reverse is not supported"); else { final_commit_name = prepare_initial(&sb); sb.commits.compare = compare_commits_by_reverse_commit_date; + if (revs.first_parent_only) + revs.children.name = NULL; } if (!sb.final) { @@@ -2740,12 -2713,6 +2740,12 @@@ else if (contents_from) die("Cannot use --contents with final commit object name"); + if (reverse && revs.first_parent_only) { + final_commit = find_single_final(sb.revs, NULL); + if (!final_commit) + die("--reverse and --first-parent together require specified latest commit"); + } + /* * If we have bottom, this will mark the ancestors of the * bottom commits we would reach while traversing as @@@ -2754,26 -2721,7 +2754,26 @@@ if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); - if (is_null_sha1(sb.final->object.sha1)) { + if (reverse && revs.first_parent_only) { + struct commit *c = final_commit; + + sb.revs->children.name = "children"; + while (c->parents && + oidcmp(&c->object.oid, &sb.final->object.oid)) { + struct commit_list *l = xcalloc(1, sizeof(*l)); + + l->item = c; + if (add_decoration(&sb.revs->children, + &c->parents->item->object, l)) + die("BUG: not unique item in first-parent chain"); + c = c->parents->item; + } + + if (oidcmp(&c->object.oid, &sb.final->object.oid)) + die("--reverse --first-parent together require range along first-parent chain"); + } + + if (is_null_oid(&sb.final->object.oid)) { o = sb.final->util; sb.final_buf = xmemdupz(o->file.ptr, o->file.size); sb.final_buf_size = o->file.size; @@@ -2849,11 -2797,11 +2849,11 @@@ read_mailmap(&mailmap, NULL); + assign_blame(&sb, opt); + if (!incremental) setup_pager(); - assign_blame(&sb, opt); - free(final_commit_name); if (incremental) diff --combined builtin/interpret-trailers.c index b99ae4be88,b75e953111..175f14797b --- a/builtin/interpret-trailers.c +++ b/builtin/interpret-trailers.c @@@ -12,18 -12,16 +12,18 @@@ #include "trailer.h" static const char * const git_interpret_trailers_usage[] = { - N_("git interpret-trailers [--trim-empty] [(--trailer [(=|:)])...] [...]"), + N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer [(=|:)])...] [...]"), NULL }; int cmd_interpret_trailers(int argc, const char **argv, const char *prefix) { + int in_place = 0; int trim_empty = 0; - struct string_list trailers = STRING_LIST_INIT_DUP; + struct string_list trailers = STRING_LIST_INIT_NODUP; struct option options[] = { + OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")), OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")), OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"), N_("trailer(s) to add")), @@@ -36,12 -34,9 +36,12 @@@ if (argc) { int i; for (i = 0; i < argc; i++) - process_trailers(argv[i], trim_empty, &trailers); - } else - process_trailers(NULL, trim_empty, &trailers); + process_trailers(argv[i], in_place, trim_empty, &trailers); + } else { + if (in_place) + die(_("no input file given for in-place editing")); + process_trailers(NULL, in_place, trim_empty, &trailers); + } string_list_clear(&trailers, 0); diff --combined builtin/shortlog.c index bfc082e584,cb3e89cf1d..f83984e8a1 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@@ -14,26 -14,7 +14,26 @@@ static char const * const shortlog_usag NULL }; -static int compare_by_number(const void *a1, const void *a2) +/* + * The util field of our string_list_items will contain one of two things: + * + * - if --summary is not in use, it will point to a string list of the + * oneline subjects assigned to this author + * + * - if --summary is in use, we don't need that list; we only need to know + * its size. So we abuse the pointer slot to store our integer counter. + * + * This macro accesses the latter. + */ +#define UTIL_TO_INT(x) ((intptr_t)(x)->util) + +static int compare_by_counter(const void *a1, const void *a2) +{ + const struct string_list_item *i1 = a1, *i2 = a2; + return UTIL_TO_INT(i2) - UTIL_TO_INT(i1); +} + +static int compare_by_list(const void *a1, const void *a2) { const struct string_list_item *i1 = a1, *i2 = a2; const struct string_list *l1 = i1->util, *l2 = i2->util; @@@ -50,9 -31,13 +50,9 @@@ static void insert_one_record(struct sh const char *author, const char *oneline) { - const char *dot3 = log->common_repo_prefix; - char *buffer, *p; struct string_list_item *item; const char *mailbuf, *namebuf; size_t namelen, maillen; - const char *eol; - struct strbuf subject = STRBUF_INIT; struct strbuf namemailbuf = STRBUF_INIT; struct ident_split ident; @@@ -71,95 -56,98 +71,95 @@@ strbuf_addf(&namemailbuf, " <%.*s>", (int)maillen, mailbuf); item = string_list_insert(&log->list, namemailbuf.buf); - if (item->util == NULL) - item->util = xcalloc(1, sizeof(struct string_list)); - - /* Skip any leading whitespace, including any blank lines. */ - while (*oneline && isspace(*oneline)) - oneline++; - eol = strchr(oneline, '\n'); - if (!eol) - eol = oneline + strlen(oneline); - if (starts_with(oneline, "[PATCH")) { - char *eob = strchr(oneline, ']'); - if (eob && (!eol || eob < eol)) - oneline = eob + 1; - } - while (*oneline && isspace(*oneline) && *oneline != '\n') - oneline++; - format_subject(&subject, oneline, " "); - buffer = strbuf_detach(&subject, NULL); - - if (dot3) { - int dot3len = strlen(dot3); - if (dot3len > 5) { - while ((p = strstr(buffer, dot3)) != NULL) { - int taillen = strlen(p) - dot3len; - memcpy(p, "/.../", 5); - memmove(p + 5, p + dot3len, taillen + 1); + + if (log->summary) + item->util = (void *)(UTIL_TO_INT(item) + 1); + else { + const char *dot3 = log->common_repo_prefix; + char *buffer, *p; + struct strbuf subject = STRBUF_INIT; + const char *eol; + + /* Skip any leading whitespace, including any blank lines. */ + while (*oneline && isspace(*oneline)) + oneline++; + eol = strchr(oneline, '\n'); + if (!eol) + eol = oneline + strlen(oneline); + if (starts_with(oneline, "[PATCH")) { + char *eob = strchr(oneline, ']'); + if (eob && (!eol || eob < eol)) + oneline = eob + 1; + } + while (*oneline && isspace(*oneline) && *oneline != '\n') + oneline++; + format_subject(&subject, oneline, " "); + buffer = strbuf_detach(&subject, NULL); + + if (dot3) { + int dot3len = strlen(dot3); + if (dot3len > 5) { + while ((p = strstr(buffer, dot3)) != NULL) { + int taillen = strlen(p) - dot3len; + memcpy(p, "/.../", 5); + memmove(p + 5, p + dot3len, taillen + 1); + } } } - } - string_list_append(item->util, buffer); + if (item->util == NULL) + item->util = xcalloc(1, sizeof(struct string_list)); + string_list_append(item->util, buffer); + } } static void read_from_stdin(struct shortlog *log) { - char author[1024], oneline[1024]; + struct strbuf author = STRBUF_INIT; + struct strbuf oneline = STRBUF_INIT; - while (fgets(author, sizeof(author), stdin) != NULL) { - if (!(author[0] == 'A' || author[0] == 'a') || - !starts_with(author + 1, "uthor: ")) + while (strbuf_getline_lf(&author, stdin) != EOF) { + const char *v; + if (!skip_prefix(author.buf, "Author: ", &v) && + !skip_prefix(author.buf, "author ", &v)) continue; - while (fgets(oneline, sizeof(oneline), stdin) && - oneline[0] != '\n') + while (strbuf_getline_lf(&oneline, stdin) != EOF && + oneline.len) ; /* discard headers */ - while (fgets(oneline, sizeof(oneline), stdin) && - oneline[0] == '\n') + while (strbuf_getline_lf(&oneline, stdin) != EOF && + !oneline.len) ; /* discard blanks */ - insert_one_record(log, author + 8, oneline); + insert_one_record(log, v, oneline.buf); } + strbuf_release(&author); + strbuf_release(&oneline); } void shortlog_add_commit(struct shortlog *log, struct commit *commit) { - const char *author = NULL, *buffer; - struct strbuf buf = STRBUF_INIT; - struct strbuf ufbuf = STRBUF_INIT; - - pp_commit_easy(CMIT_FMT_RAW, commit, &buf); - buffer = buf.buf; - while (*buffer && *buffer != '\n') { - const char *eol = strchr(buffer, '\n'); - - if (eol == NULL) - eol = buffer + strlen(buffer); + struct strbuf author = STRBUF_INIT; + struct strbuf oneline = STRBUF_INIT; + struct pretty_print_context ctx = {0}; + + ctx.fmt = CMIT_FMT_USERFORMAT; + ctx.abbrev = log->abbrev; + ctx.subject = ""; + ctx.after_subject = ""; + ctx.date_mode.type = DATE_NORMAL; + ctx.output_encoding = get_log_output_encoding(); + + format_commit_message(commit, "%an <%ae>", &author, &ctx); + if (!log->summary) { + if (log->user_format) + pretty_print_commit(&ctx, commit, &oneline); else - eol++; - - if (starts_with(buffer, "author ")) - author = buffer + 7; - buffer = eol; - } - if (!author) { - warning(_("Missing author: %s"), - sha1_to_hex(commit->object.sha1)); - return; + format_commit_message(commit, "%s", &oneline, &ctx); } - if (log->user_format) { - struct pretty_print_context ctx = {0}; - ctx.fmt = CMIT_FMT_USERFORMAT; - ctx.abbrev = log->abbrev; - ctx.subject = ""; - ctx.after_subject = ""; - ctx.date_mode.type = DATE_NORMAL; - ctx.output_encoding = get_log_output_encoding(); - pretty_print_commit(&ctx, commit, &ufbuf); - buffer = ufbuf.buf; - } else if (*buffer) { - buffer++; - } - insert_one_record(log, author, !*buffer ? "" : buffer); - strbuf_release(&ufbuf); - strbuf_release(&buf); + + insert_one_record(log, author.buf, oneline.len ? oneline.buf : ""); + + strbuf_release(&author); + strbuf_release(&oneline); } static void get_from_rev(struct rev_info *rev, struct shortlog *log) @@@ -233,11 -221,11 +233,11 @@@ void shortlog_init(struct shortlog *log int cmd_shortlog(int argc, const char **argv, const char *prefix) { - static struct shortlog log; - static struct rev_info rev; + struct shortlog log = { STRING_LIST_INIT_NODUP }; + struct rev_info rev; int nongit = !startup_info->have_repository; - static const struct option options[] = { + const struct option options[] = { OPT_BOOL('n', "numbered", &log.sort_by_number, N_("sort output according to the number of commits per author")), OPT_BOOL('s', "summary", &log.summary, @@@ -306,14 -294,14 +306,14 @@@ void shortlog_output(struct shortlog *l if (log->sort_by_number) qsort(log->list.items, log->list.nr, sizeof(struct string_list_item), - compare_by_number); + log->summary ? compare_by_counter : compare_by_list); for (i = 0; i < log->list.nr; i++) { - struct string_list *onelines = log->list.items[i].util; - + const struct string_list_item *item = &log->list.items[i]; if (log->summary) { - printf("%6d\t%s\n", onelines->nr, log->list.items[i].string); + printf("%6d\t%s\n", (int)UTIL_TO_INT(item), item->string); } else { - printf("%s (%d):\n", log->list.items[i].string, onelines->nr); + struct string_list *onelines = item->util; + printf("%s (%d):\n", item->string, onelines->nr); for (j = onelines->nr - 1; j >= 0; j--) { const char *msg = onelines->items[j].string; @@@ -326,11 -314,11 +326,11 @@@ printf(" %s\n", msg); } putchar('\n'); + onelines->strdup_strings = 1; + string_list_clear(onelines, 0); + free(onelines); } - onelines->strdup_strings = 1; - string_list_clear(onelines, 0); - free(onelines); log->list.items[i].util = NULL; } diff --combined parse-options-cb.c index 239898d946,4e8290181f..ba5acf3111 --- a/parse-options-cb.c +++ b/parse-options-cb.c @@@ -5,7 -5,6 +5,7 @@@ #include "color.h" #include "string-list.h" #include "argv-array.h" +#include "sha1-array.h" /*----- some often used options -----*/ @@@ -78,7 -77,7 +78,7 @@@ int parse_opt_verbosity_cb(const struc return 0; } -int parse_opt_with_commit(const struct option *opt, const char *arg, int unset) +int parse_opt_commits(const struct option *opt, const char *arg, int unset) { unsigned char sha1[20]; struct commit *commit; @@@ -94,22 -93,6 +94,22 @@@ return 0; } +int parse_opt_object_name(const struct option *opt, const char *arg, int unset) +{ + unsigned char sha1[20]; + + if (unset) { + sha1_array_clear(opt->value); + return 0; + } + if (!arg) + return -1; + if (get_sha1(arg, sha1)) + return error(_("malformed object name '%s'"), arg); + sha1_array_append(opt->value, sha1); + return 0; +} + int parse_opt_tertiary(const struct option *opt, const char *arg, int unset) { int *target = opt->value; @@@ -144,7 -127,7 +144,7 @@@ int parse_opt_string_list(const struct if (!arg) return -1; - string_list_append(v, xstrdup(arg)); + string_list_append(v, arg); return 0; }