diff options
-rw-r--r-- | builtin-add.c | 69 | ||||
-rw-r--r-- | builtin-branch.c | 17 | ||||
-rw-r--r-- | builtin-log.c | 6 | ||||
-rw-r--r-- | builtin-rev-list.c | 8 | ||||
-rw-r--r-- | builtin-show-branch.c | 23 | ||||
-rw-r--r-- | cache.h | 7 | ||||
-rw-r--r-- | commit.c | 393 | ||||
-rw-r--r-- | commit.h | 2 | ||||
-rw-r--r-- | dir.c | 28 | ||||
-rw-r--r-- | dir.h | 9 | ||||
-rw-r--r-- | interpolate.c | 46 | ||||
-rw-r--r-- | interpolate.h | 6 | ||||
-rw-r--r-- | log-tree.c | 35 |
13 files changed, 410 insertions, 239 deletions
diff --git a/builtin-add.c b/builtin-add.c index 159117106a..734547994f 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -40,42 +40,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p dir->nr = dst - dir->entries; for (i = 0; i < specs; i++) { - struct stat st; - const char *match; - if (seen[i]) - continue; - - match = pathspec[i]; - if (!match[0]) - continue; - - /* Existing file? We must have ignored it */ - if (!lstat(match, &st)) { - struct dir_entry *ent; - - ent = dir_add_name(dir, match, strlen(match)); - ent->ignored = 1; - if (S_ISDIR(st.st_mode)) - ent->ignored_dir = 1; - continue; - } - die("pathspec '%s' did not match any files", match); + if (!seen[i] && !file_exists(pathspec[i])) + die("pathspec '%s' did not match any files", + pathspec[i]); } } -static void fill_directory(struct dir_struct *dir, const char **pathspec) +static void fill_directory(struct dir_struct *dir, const char **pathspec, + int ignored_too) { const char *path, *base; int baselen; /* Set up the default git porcelain excludes */ memset(dir, 0, sizeof(*dir)); - dir->exclude_per_dir = ".gitignore"; - path = git_path("info/exclude"); - if (!access(path, R_OK)) - add_excludes_from_file(dir, path); - if (!access(excludes_file, R_OK)) - add_excludes_from_file(dir, excludes_file); + if (!ignored_too) { + dir->collect_ignored = 1; + dir->exclude_per_dir = ".gitignore"; + path = git_path("info/exclude"); + if (!access(path, R_OK)) + add_excludes_from_file(dir, path); + if (!access(excludes_file, R_OK)) + add_excludes_from_file(dir, excludes_file); + } /* * Calculate common prefix for the pathspec, and @@ -219,13 +206,11 @@ int cmd_add(int argc, const char **argv, const char *prefix) } pathspec = get_pathspec(prefix, argv + i); - fill_directory(&dir, pathspec); + fill_directory(&dir, pathspec, ignored_too); if (show_only) { const char *sep = "", *eof = ""; for (i = 0; i < dir.nr; i++) { - if (!ignored_too && dir.entries[i]->ignored) - continue; printf("%s%s", sep, dir.entries[i]->name); sep = " "; eof = "\n"; @@ -237,25 +222,13 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (read_cache() < 0) die("index file corrupt"); - if (!ignored_too) { - int has_ignored = 0; - for (i = 0; i < dir.nr; i++) - if (dir.entries[i]->ignored) - has_ignored = 1; - if (has_ignored) { - fprintf(stderr, ignore_warning); - for (i = 0; i < dir.nr; i++) { - if (!dir.entries[i]->ignored) - continue; - fprintf(stderr, "%s", dir.entries[i]->name); - if (dir.entries[i]->ignored_dir) - fprintf(stderr, " (directory)"); - fputc('\n', stderr); - } - fprintf(stderr, - "Use -f if you really want to add them.\n"); - exit(1); + if (dir.ignored_nr) { + fprintf(stderr, ignore_warning); + for (i = 0; i < dir.ignored_nr; i++) { + fprintf(stderr, "%s\n", dir.ignored[i]->name); } + fprintf(stderr, "Use -f if you really want to add them.\n"); + exit(1); } for (i = 0; i < dir.nr; i++) diff --git a/builtin-branch.c b/builtin-branch.c index bd4748f845..77b85dde1f 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -247,7 +247,6 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, char c; int color; struct commit *commit; - char subject[256]; switch (item->kind) { case REF_LOCAL_BRANCH: @@ -268,17 +267,23 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, } if (verbose) { + char *subject = NULL; + unsigned long subject_len = 0; + const char *sub = " **** invalid ref ****"; + commit = lookup_commit(item->sha1); - if (commit && !parse_commit(commit)) + if (commit && !parse_commit(commit)) { pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, - subject, sizeof(subject), 0, + &subject, &subject_len, 0, NULL, NULL, 0); - else - strcpy(subject, " **** invalid ref ****"); + sub = subject; + } printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color), maxwidth, item->name, branch_get_color(COLOR_BRANCH_RESET), - find_unique_abbrev(item->sha1, abbrev), subject); + find_unique_abbrev(item->sha1, abbrev), sub); + if (subject) + free(subject); } else { printf("%c %s%s%s\n", c, branch_get_color(color), item->name, branch_get_color(COLOR_BRANCH_RESET)); diff --git a/builtin-log.c b/builtin-log.c index 0aede76839..b9035ab799 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -742,11 +742,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) sign = '-'; if (verbose) { - static char buf[16384]; + char *buf = NULL; + unsigned long buflen = 0; pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, - buf, sizeof(buf), 0, NULL, NULL, 0); + &buf, &buflen, 0, NULL, NULL, 0); printf("%c %s %s\n", sign, sha1_to_hex(commit->object.sha1), buf); + free(buf); } else { printf("%c %s\n", sign, diff --git a/builtin-rev-list.c b/builtin-rev-list.c index ebf53f5944..813aadf596 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -92,11 +92,13 @@ static void show_commit(struct commit *commit) putchar('\n'); if (revs.verbose_header) { - static char pretty_header[16384]; + char *buf = NULL; + unsigned long buflen = 0; pretty_print_commit(revs.commit_format, commit, ~0, - pretty_header, sizeof(pretty_header), + &buf, &buflen, revs.abbrev, NULL, NULL, revs.date_mode); - printf("%s%c", pretty_header, hdr_termination); + printf("%s%c", buf, hdr_termination); + free(buf); } fflush(stdout); if (commit->parents) { diff --git a/builtin-show-branch.c b/builtin-show-branch.c index c892f1f7a6..4fa87f6081 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -259,17 +259,19 @@ static void join_revs(struct commit_list **list_p, static void show_one_commit(struct commit *commit, int no_name) { - char pretty[256], *cp; + char *pretty = NULL; + const char *pretty_str = "(unavailable)"; + unsigned long pretty_len = 0; struct commit_name *name = commit->util; - if (commit->object.parsed) + + if (commit->object.parsed) { pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, - pretty, sizeof(pretty), 0, NULL, NULL, 0); - else - strcpy(pretty, "(unavailable)"); - if (!prefixcmp(pretty, "[PATCH] ")) - cp = pretty + 8; - else - cp = pretty; + &pretty, &pretty_len, + 0, NULL, NULL, 0); + pretty_str = pretty; + } + if (!prefixcmp(pretty_str, "[PATCH] ")) + pretty_str += 8; if (!no_name) { if (name && name->head_name) { @@ -286,7 +288,8 @@ static void show_one_commit(struct commit *commit, int no_name) printf("[%s] ", find_unique_abbrev(commit->object.sha1, 7)); } - puts(cp); + puts(pretty_str); + free(pretty); } static char *ref_name[MAX_REVS + 1]; @@ -234,8 +234,11 @@ extern void verify_non_filename(const char *prefix, const char *name); */ #define ALLOC_GROW(x, nr, alloc) \ do { \ - if ((nr) >= alloc) { \ - alloc = alloc_nr(alloc); \ + if ((nr) > alloc) { \ + if (alloc_nr(alloc) < (nr)) \ + alloc = (nr); \ + else \ + alloc = alloc_nr(alloc); \ x = xrealloc((x), alloc * sizeof(*(x))); \ } \ } while(0) @@ -529,6 +529,14 @@ static int add_rfc2047(char *buf, const char *line, int len, return bp - buf; } +static unsigned long bound_rfc2047(unsigned long len, const char *encoding) +{ + /* upper bound of q encoded string of length 'len' */ + unsigned long elen = strlen(encoding); + + return len * 3 + elen + 100; +} + static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const char *line, enum date_mode dmode, const char *encoding) @@ -776,7 +784,7 @@ static void fill_person(struct interp *table, const char *msg, int len) } static long format_commit_message(const struct commit *commit, - const char *msg, char *buf, unsigned long space) + const char *msg, char **buf_p, unsigned long *space_p) { struct interp table[] = { { "%H" }, /* commit hash */ @@ -905,31 +913,252 @@ static long format_commit_message(const struct commit *commit, if (!table[i].value) interp_set_entry(table, i, "<unknown>"); - interpolate(buf, space, user_format, table, ARRAY_SIZE(table)); + do { + char *buf = *buf_p; + unsigned long space = *space_p; + + space = interpolate(buf, space, user_format, + table, ARRAY_SIZE(table)); + if (!space) + break; + buf = xrealloc(buf, space); + *buf_p = buf; + *space_p = space; + } while (1); interp_clear_table(table, ARRAY_SIZE(table)); - return strlen(buf); + return strlen(*buf_p); +} + +static void pp_header(enum cmit_fmt fmt, + int abbrev, + enum date_mode dmode, + const char *encoding, + const struct commit *commit, + const char **msg_p, + unsigned long *len_p, + unsigned long *ofs_p, + char **buf_p, + unsigned long *space_p) +{ + int parents_shown = 0; + + for (;;) { + const char *line = *msg_p; + char *dst; + int linelen = get_one_line(*msg_p, *len_p); + unsigned long len; + + if (!linelen) + return; + *msg_p += linelen; + *len_p -= linelen; + + if (linelen == 1) + /* End of header */ + return; + + ALLOC_GROW(*buf_p, linelen + *ofs_p + 20, *space_p); + dst = *buf_p + *ofs_p; + + if (fmt == CMIT_FMT_RAW) { + memcpy(dst, line, linelen); + *ofs_p += linelen; + continue; + } + + if (!memcmp(line, "parent ", 7)) { + if (linelen != 48) + die("bad parent line in commit"); + continue; + } + + if (!parents_shown) { + struct commit_list *parent; + int num; + for (parent = commit->parents, num = 0; + parent; + parent = parent->next, num++) + ; + /* with enough slop */ + num = *ofs_p + num * 50 + 20; + ALLOC_GROW(*buf_p, num, *space_p); + dst = *buf_p + *ofs_p; + *ofs_p += add_merge_info(fmt, dst, commit, abbrev); + parents_shown = 1; + } + + /* + * MEDIUM == DEFAULT shows only author with dates. + * FULL shows both authors but not dates. + * FULLER shows both authors and dates. + */ + if (!memcmp(line, "author ", 7)) { + len = linelen; + if (fmt == CMIT_FMT_EMAIL) + len = bound_rfc2047(linelen, encoding); + ALLOC_GROW(*buf_p, *ofs_p + len, *space_p); + dst = *buf_p + *ofs_p; + *ofs_p += add_user_info("Author", fmt, dst, + line + 7, dmode, encoding); + } + + if (!memcmp(line, "committer ", 10) && + (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) { + len = linelen; + if (fmt == CMIT_FMT_EMAIL) + len = bound_rfc2047(linelen, encoding); + ALLOC_GROW(*buf_p, *ofs_p + len, *space_p); + dst = *buf_p + *ofs_p; + *ofs_p += add_user_info("Commit", fmt, dst, + line + 10, dmode, encoding); + } + } +} + +static void pp_title_line(enum cmit_fmt fmt, + const char **msg_p, + unsigned long *len_p, + unsigned long *ofs_p, + char **buf_p, + unsigned long *space_p, + int indent, + const char *subject, + const char *after_subject, + const char *encoding, + int plain_non_ascii) +{ + char *title; + unsigned long title_alloc, title_len; + unsigned long len; + + title_len = 0; + title_alloc = 80; + title = xmalloc(title_alloc); + for (;;) { + const char *line = *msg_p; + int linelen = get_one_line(line, *len_p); + *msg_p += linelen; + *len_p -= linelen; + + if (!linelen || is_empty_line(line, &linelen)) + break; + + if (title_alloc <= title_len + linelen + 2) { + title_alloc = title_len + linelen + 80; + title = xrealloc(title, title_alloc); + } + len = 0; + if (title_len) { + if (fmt == CMIT_FMT_EMAIL) { + len++; + title[title_len++] = '\n'; + } + len++; + title[title_len++] = ' '; + } + memcpy(title + title_len, line, linelen); + title_len += linelen; + } + + /* Enough slop for the MIME header and rfc2047 */ + len = bound_rfc2047(title_len, encoding)+ 1000; + if (subject) + len += strlen(subject); + if (after_subject) + len += strlen(after_subject); + if (encoding) + len += strlen(encoding); + ALLOC_GROW(*buf_p, title_len + *ofs_p + len, *space_p); + + if (subject) { + len = strlen(subject); + memcpy(*buf_p + *ofs_p, subject, len); + *ofs_p += len; + *ofs_p += add_rfc2047(*buf_p + *ofs_p, + title, title_len, encoding); + } else { + memcpy(*buf_p + *ofs_p, title, title_len); + *ofs_p += title_len; + } + (*buf_p)[(*ofs_p)++] = '\n'; + if (plain_non_ascii) { + const char *header_fmt = + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=%s\n" + "Content-Transfer-Encoding: 8bit\n"; + *ofs_p += snprintf(*buf_p + *ofs_p, + *space_p - *ofs_p, + header_fmt, encoding); + } + if (after_subject) { + len = strlen(after_subject); + memcpy(*buf_p + *ofs_p, after_subject, len); + *ofs_p += len; + } + free(title); + if (fmt == CMIT_FMT_EMAIL) { + ALLOC_GROW(*buf_p, *ofs_p + 20, *space_p); + (*buf_p)[(*ofs_p)++] = '\n'; + } +} + +static void pp_remainder(enum cmit_fmt fmt, + const char **msg_p, + unsigned long *len_p, + unsigned long *ofs_p, + char **buf_p, + unsigned long *space_p, + int indent) +{ + int first = 1; + for (;;) { + const char *line = *msg_p; + int linelen = get_one_line(line, *len_p); + *msg_p += linelen; + *len_p -= linelen; + + if (!linelen) + break; + + if (is_empty_line(line, &linelen)) { + if (first) + continue; + if (fmt == CMIT_FMT_SHORT) + break; + } + first = 0; + + ALLOC_GROW(*buf_p, *ofs_p + linelen + indent + 20, *space_p); + if (indent) { + memset(*buf_p + *ofs_p, ' ', indent); + *ofs_p += indent; + } + memcpy(*buf_p + *ofs_p, line, linelen); + *ofs_p += linelen; + (*buf_p)[(*ofs_p)++] = '\n'; + } } unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, - char *buf, unsigned long space, + char **buf_p, unsigned long *space_p, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode) { - int hdr = 1, body = 0, seen_title = 0; unsigned long offset = 0; + unsigned long beginning_of_body; int indent = 4; - int parents_shown = 0; const char *msg = commit->buffer; int plain_non_ascii = 0; char *reencoded; const char *encoding; + char *buf; if (fmt == CMIT_FMT_USERFORMAT) - return format_commit_message(commit, msg, buf, space); + return format_commit_message(commit, msg, buf_p, space_p); encoding = (git_log_output_encoding ? git_log_output_encoding @@ -937,8 +1166,10 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, if (!encoding) encoding = "utf-8"; reencoded = logmsg_reencode(commit, encoding); - if (reencoded) + if (reencoded) { msg = reencoded; + len = strlen(reencoded); + } if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; @@ -969,137 +1200,57 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, } } + pp_header(fmt, abbrev, dmode, encoding, + commit, &msg, &len, + &offset, buf_p, space_p); + if (fmt != CMIT_FMT_ONELINE && !subject) { + ALLOC_GROW(*buf_p, offset + 20, *space_p); + (*buf_p)[offset++] = '\n'; + } + + /* Skip excess blank lines at the beginning of body, if any... */ for (;;) { - const char *line = msg; int linelen = get_one_line(msg, len); - + int ll = linelen; if (!linelen) break; - - /* - * We want some slop for indentation and a possible - * final "...". Thus the "+ 20". - */ - if (offset + linelen + 20 > space) { - memcpy(buf + offset, " ...\n", 8); - offset += 8; + if (!is_empty_line(msg, &ll)) break; - } - msg += linelen; len -= linelen; - if (hdr) { - if (linelen == 1) { - hdr = 0; - if ((fmt != CMIT_FMT_ONELINE) && !subject) - buf[offset++] = '\n'; - continue; - } - if (fmt == CMIT_FMT_RAW) { - memcpy(buf + offset, line, linelen); - offset += linelen; - continue; - } - if (!memcmp(line, "parent ", 7)) { - if (linelen != 48) - die("bad parent line in commit"); - continue; - } - - if (!parents_shown) { - offset += add_merge_info(fmt, buf + offset, - commit, abbrev); - parents_shown = 1; - continue; - } - /* - * MEDIUM == DEFAULT shows only author with dates. - * FULL shows both authors but not dates. - * FULLER shows both authors and dates. - */ - if (!memcmp(line, "author ", 7)) - offset += add_user_info("Author", fmt, - buf + offset, - line + 7, - dmode, - encoding); - if (!memcmp(line, "committer ", 10) && - (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) - offset += add_user_info("Commit", fmt, - buf + offset, - line + 10, - dmode, - encoding); - continue; - } + } - if (!subject) - body = 1; + /* These formats treat the title line specially. */ + if (fmt == CMIT_FMT_ONELINE + || fmt == CMIT_FMT_EMAIL) + pp_title_line(fmt, &msg, &len, &offset, + buf_p, space_p, indent, + subject, after_subject, encoding, + plain_non_ascii); - if (is_empty_line(line, &linelen)) { - if (!seen_title) - continue; - if (!body) - continue; - if (subject) - continue; - if (fmt == CMIT_FMT_SHORT) - break; - } + beginning_of_body = offset; + if (fmt != CMIT_FMT_ONELINE) + pp_remainder(fmt, &msg, &len, &offset, + buf_p, space_p, indent); - seen_title = 1; - if (subject) { - int slen = strlen(subject); - memcpy(buf + offset, subject, slen); - offset += slen; - offset += add_rfc2047(buf + offset, line, linelen, - encoding); - } - else { - memset(buf + offset, ' ', indent); - memcpy(buf + offset + indent, line, linelen); - offset += linelen + indent; - } - buf[offset++] = '\n'; - if (fmt == CMIT_FMT_ONELINE) - break; - if (subject && plain_non_ascii) { - int sz; - char header[512]; - const char *header_fmt = - "MIME-Version: 1.0\n" - "Content-Type: text/plain; charset=%s\n" - "Content-Transfer-Encoding: 8bit\n"; - sz = snprintf(header, sizeof(header), header_fmt, - encoding); - if (sizeof(header) < sz) - die("Encoding name %s too long", encoding); - memcpy(buf + offset, header, sz); - offset += sz; - } - if (after_subject) { - int slen = strlen(after_subject); - if (slen > space - offset - 1) - slen = space - offset - 1; - memcpy(buf + offset, after_subject, slen); - offset += slen; - after_subject = NULL; - } - subject = NULL; - } - while (offset && isspace(buf[offset-1])) + while (offset && isspace((*buf_p)[offset-1])) offset--; + + ALLOC_GROW(*buf_p, offset + 20, *space_p); + buf = *buf_p; + /* Make sure there is an EOLN for the non-oneline case */ if (fmt != CMIT_FMT_ONELINE) buf[offset++] = '\n'; + /* - * make sure there is another EOLN to separate the headers from whatever - * body the caller appends if we haven't already written a body + * The caller may append additional body text in e-mail + * format. Make sure we did not strip the blank line + * between the header and the body. */ - if (fmt == CMIT_FMT_EMAIL && !body) + if (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body) buf[offset++] = '\n'; buf[offset] = '\0'; - free(reencoded); return offset; } @@ -61,7 +61,7 @@ enum cmit_fmt { }; extern enum cmit_fmt get_commit_format(const char *arg); -extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode); +extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char **buf_p, unsigned long *space_p, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode); /** Removes the first commit from a list sorted by date, and adds all * of its parents. @@ -275,7 +275,6 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len) { struct dir_entry *ent; ent = xmalloc(sizeof(*ent) + len + 1); - ent->ignored = ent->ignored_dir = 0; ent->len = len; memcpy(ent->name, pathname, len); ent->name[len] = 0; @@ -287,10 +286,19 @@ struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int if (cache_name_pos(pathname, len) >= 0) return NULL; - ALLOC_GROW(dir->entries, dir->nr, dir->alloc); + ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc); return dir->entries[dir->nr++] = dir_entry_new(pathname, len); } +struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len) +{ + if (cache_name_pos(pathname, len) >= 0) + return NULL; + + ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc); + return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len); +} + enum exist_status { index_nonexistent = 0, index_directory, @@ -423,6 +431,18 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli return 0; } +static int in_pathspec(const char *path, int len, const struct path_simplify *simplify) +{ + if (simplify) { + for (; simplify->path; simplify++) { + if (len == simplify->len + && !memcmp(path, simplify->path, len)) + return 1; + } + } + return 0; +} + /* * Read a directory tree. We currently ignore anything but * directories, regular files and symlinks. That's because git @@ -463,6 +483,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co continue; exclude = excluded(dir, fullname); + if (exclude && dir->collect_ignored + && in_pathspec(fullname, baselen + len, simplify)) + dir_add_ignored(dir, fullname, baselen + len); if (exclude != dir->show_ignored) { if (!dir->show_ignored || DTYPE(de) != DT_DIR) { continue; @@ -609,6 +632,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i read_directory_recursive(dir, path, base, baselen, 0, simplify); free_simplify(simplify); qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name); + qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name); return dir->nr; } @@ -13,9 +13,7 @@ struct dir_entry { - unsigned int ignored : 1; - unsigned int ignored_dir : 1; - unsigned int len : 30; + unsigned int len; char name[FLEX_ARRAY]; /* more */ }; @@ -31,11 +29,14 @@ struct exclude_list { struct dir_struct { int nr, alloc; + int ignored_nr, ignored_alloc; unsigned int show_ignored:1, show_other_directories:1, hide_empty_directories:1, - no_gitlinks:1; + no_gitlinks:1, + collect_ignored:1; struct dir_entry **entries; + struct dir_entry **ignored; /* Exclude info */ const char *exclude_per_dir; diff --git a/interpolate.c b/interpolate.c index fb30694f47..00826778fc 100644 --- a/interpolate.c +++ b/interpolate.c @@ -44,33 +44,33 @@ void interp_clear_table(struct interp *table, int ninterps) * { "%%", "%"}, * } * - * Returns 1 on a successful substitution pass that fits in result, - * Returns 0 on a failed or overflowing substitution pass. + * Returns 0 on a successful substitution pass that fits in result, + * Returns a number of bytes needed to hold the full substituted + * string otherwise. */ -int interpolate(char *result, int reslen, +unsigned long interpolate(char *result, unsigned long reslen, const char *orig, const struct interp *interps, int ninterps) { const char *src = orig; char *dest = result; - int newlen = 0; + unsigned long newlen = 0; const char *name, *value; - int namelen, valuelen; + unsigned long namelen, valuelen; int i; char c; memset(result, 0, reslen); - while ((c = *src) && newlen < reslen - 1) { + while ((c = *src)) { if (c == '%') { /* Try to match an interpolation string. */ for (i = 0; i < ninterps; i++) { name = interps[i].name; namelen = strlen(name); - if (strncmp(src, name, namelen) == 0) { + if (strncmp(src, name, namelen) == 0) break; - } } /* Check for valid interpolation. */ @@ -78,29 +78,25 @@ int interpolate(char *result, int reslen, value = interps[i].value; valuelen = strlen(value); - if (newlen + valuelen < reslen - 1) { + if (newlen + valuelen + 1 < reslen) { /* Substitute. */ strncpy(dest, value, valuelen); - newlen += valuelen; dest += valuelen; - src += namelen; - } else { - /* Something's not fitting. */ - return 0; } - - } else { - /* Skip bogus interpolation. */ - *dest++ = *src++; - newlen++; + newlen += valuelen; + src += namelen; + continue; } - - } else { - /* Straight copy one non-interpolation character. */ - *dest++ = *src++; - newlen++; } + /* Straight copy one non-interpolation character. */ + if (newlen + 1 < reslen) + *dest++ = *src; + src++; + newlen++; } - return newlen < reslen - 1; + if (newlen + 1 < reslen) + return 0; + else + return newlen + 2; } diff --git a/interpolate.h b/interpolate.h index 16a26b9986..77407e67dc 100644 --- a/interpolate.h +++ b/interpolate.h @@ -19,8 +19,8 @@ struct interp { extern void interp_set_entry(struct interp *table, int slot, const char *value); extern void interp_clear_table(struct interp *table, int ninterps); -extern int interpolate(char *result, int reslen, - const char *orig, - const struct interp *interps, int ninterps); +extern unsigned long interpolate(char *result, unsigned long reslen, + const char *orig, + const struct interp *interps, int ninterps); #endif /* INTERPOLATE_H */ diff --git a/log-tree.c b/log-tree.c index 4bef909144..0cf21bc051 100644 --- a/log-tree.c +++ b/log-tree.c @@ -79,16 +79,25 @@ static int detect_any_signoff(char *letter, int size) return seen_head && seen_name; } -static int append_signoff(char *buf, int buf_sz, int at, const char *signoff) +static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p, + unsigned long at, const char *signoff) { static const char signed_off_by[] = "Signed-off-by: "; - int signoff_len = strlen(signoff); + size_t signoff_len = strlen(signoff); int has_signoff = 0; - char *cp = buf; - - /* Do we have enough space to add it? */ - if (buf_sz - at <= strlen(signed_off_by) + signoff_len + 3) - return at; + char *cp; + char *buf; + unsigned long buf_sz; + + buf = *buf_p; + buf_sz = *buf_sz_p; + if (buf_sz <= at + strlen(signed_off_by) + signoff_len + 3) { + buf_sz += strlen(signed_off_by) + signoff_len + 3; + buf = xrealloc(buf, buf_sz); + *buf_p = buf; + *buf_sz_p = buf_sz; + } + cp = buf; /* First see if we already have the sign-off by the signer */ while ((cp = strstr(cp, signed_off_by))) { @@ -133,7 +142,8 @@ static unsigned int digits_in_number(unsigned int number) void show_log(struct rev_info *opt, const char *sep) { - static char this_header[16384]; + char *msgbuf = NULL; + unsigned long msgbuf_len = 0; struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; int abbrev = opt->diffopt.abbrev; @@ -278,14 +288,15 @@ void show_log(struct rev_info *opt, const char *sep) /* * And then the pretty-printed message itself */ - len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, - sizeof(this_header), abbrev, subject, + len = pretty_print_commit(opt->commit_format, commit, ~0u, + &msgbuf, &msgbuf_len, abbrev, subject, extra_headers, opt->date_mode); if (opt->add_signoff) - len = append_signoff(this_header, sizeof(this_header), len, + len = append_signoff(&msgbuf, &msgbuf_len, len, opt->add_signoff); - printf("%s%s%s", this_header, extra, sep); + printf("%s%s%s", msgbuf, extra, sep); + free(msgbuf); } int log_tree_diff_flush(struct rev_info *opt) |