提交 9bee7aab 编写于 作者: J Junio C Hamano

Merge branch 'ei/oneline+add-empty'

* ei/oneline+add-empty:
  Fix ALLOC_GROW calls with obsolete semantics
  Fix ALLOC_GROW off-by-one
  builtin-add: simplify (and increase accuracy of) exclude handling
  dir_struct: add collect_ignored option
  Extend --pretty=oneline to cover the first paragraph,
  Lift 16kB limit of log message output
......@@ -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++)
......
......@@ -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));
......
......@@ -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,
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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;
}
......@@ -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 */
......@@ -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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册