Merge branch 'ph/strbuf'

* ph/strbuf: (44 commits)
  Make read_patch_file work on a strbuf.
  strbuf_read_file enhancement, and use it.
  strbuf change: be sure ->buf is never ever NULL.
  double free in builtin-update-index.c
  Clean up stripspace a bit, use strbuf even more.
  Add strbuf_read_file().
  rerere: Fix use of an empty strbuf.buf
  Small cache_tree_write refactor.
  Make builtin-rerere use of strbuf nicer and more efficient.
  Add strbuf_cmp.
  strbuf_setlen(): do not barf on setting length of an empty buffer to 0
  sq_quote_argv and add_to_string rework with strbuf's.
  Full rework of quote_c_style and write_name_quoted.
  Rework unquote_c_style to work on a strbuf.
  strbuf API additions and enhancements.
  nfv?asprintf are broken without va_copy, workaround them.
  Fix the expansion pattern of the pseudo-static path buffer.
  builtin-for-each-ref.c::copy_name() - do not overstep the buffer.
  builtin-apply.c: fix a tiny leak introduced during xmemdupz() conversion.
  Use xmemdupz() in many places.
  ...
This commit is contained in:
Junio C Hamano 2007-10-03 03:06:02 -07:00
commit 66d4035e10
59 changed files with 1799 additions and 2501 deletions

View File

@ -3,7 +3,6 @@
*/ */
#include "cache.h" #include "cache.h"
#include "commit.h" #include "commit.h"
#include "strbuf.h"
#include "tar.h" #include "tar.h"
#include "builtin.h" #include "builtin.h"
#include "archive.h" #include "archive.h"
@ -79,19 +78,6 @@ static void write_trailer(void)
} }
} }
static void strbuf_append_string(struct strbuf *sb, const char *s)
{
int slen = strlen(s);
int total = sb->len + slen;
if (total + 1 > sb->alloc) {
sb->buf = xrealloc(sb->buf, total + 1);
sb->alloc = total + 1;
}
memcpy(sb->buf + sb->len, s, slen);
sb->len = total;
sb->buf[total] = '\0';
}
/* /*
* pax extended header records have the format "%u %s=%s\n". %u contains * pax extended header records have the format "%u %s=%s\n". %u contains
* the size of the whole string (including the %u), the first %s is the * the size of the whole string (including the %u), the first %s is the
@ -101,26 +87,17 @@ static void strbuf_append_string(struct strbuf *sb, const char *s)
static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword, static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
const char *value, unsigned int valuelen) const char *value, unsigned int valuelen)
{ {
char *p; int len, tmp;
int len, total, tmp;
/* "%u %s=%s\n" */ /* "%u %s=%s\n" */
len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1; len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
for (tmp = len; tmp > 9; tmp /= 10) for (tmp = len; tmp > 9; tmp /= 10)
len++; len++;
total = sb->len + len; strbuf_grow(sb, len);
if (total > sb->alloc) { strbuf_addf(sb, "%u %s=", len, keyword);
sb->buf = xrealloc(sb->buf, total); strbuf_add(sb, value, valuelen);
sb->alloc = total; strbuf_addch(sb, '\n');
}
p = sb->buf;
p += sprintf(p, "%u %s=", len, keyword);
memcpy(p, value, valuelen);
p += valuelen;
*p = '\n';
sb->len = total;
} }
static unsigned int ustar_header_chksum(const struct ustar_header *header) static unsigned int ustar_header_chksum(const struct ustar_header *header)
@ -154,8 +131,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
struct strbuf ext_header; struct strbuf ext_header;
memset(&header, 0, sizeof(header)); memset(&header, 0, sizeof(header));
ext_header.buf = NULL; strbuf_init(&ext_header, 0);
ext_header.len = ext_header.alloc = 0;
if (!sha1) { if (!sha1) {
*header.typeflag = TYPEFLAG_GLOBAL_HEADER; *header.typeflag = TYPEFLAG_GLOBAL_HEADER;
@ -167,7 +143,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1)); sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
} else { } else {
if (verbose) if (verbose)
fprintf(stderr, "%.*s\n", path->len, path->buf); fprintf(stderr, "%.*s\n", (int)path->len, path->buf);
if (S_ISDIR(mode) || S_ISGITLINK(mode)) { if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
*header.typeflag = TYPEFLAG_DIR; *header.typeflag = TYPEFLAG_DIR;
mode = (mode | 0777) & ~tar_umask; mode = (mode | 0777) & ~tar_umask;
@ -226,8 +202,8 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
if (ext_header.len > 0) { if (ext_header.len > 0) {
write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len); write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
free(ext_header.buf);
} }
strbuf_release(&ext_header);
write_blocked(&header, sizeof(header)); write_blocked(&header, sizeof(header));
if (S_ISREG(mode) && buffer && size > 0) if (S_ISREG(mode) && buffer && size > 0)
write_blocked(buffer, size); write_blocked(buffer, size);
@ -236,11 +212,11 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
static void write_global_extended_header(const unsigned char *sha1) static void write_global_extended_header(const unsigned char *sha1)
{ {
struct strbuf ext_header; struct strbuf ext_header;
ext_header.buf = NULL;
ext_header.len = ext_header.alloc = 0; strbuf_init(&ext_header, 0);
strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40); strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len); write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
free(ext_header.buf); strbuf_release(&ext_header);
} }
static int git_tar_config(const char *var, const char *value) static int git_tar_config(const char *var, const char *value)
@ -261,28 +237,17 @@ static int write_tar_entry(const unsigned char *sha1,
const char *base, int baselen, const char *base, int baselen,
const char *filename, unsigned mode, int stage) const char *filename, unsigned mode, int stage)
{ {
static struct strbuf path; static struct strbuf path = STRBUF_INIT;
int filenamelen = strlen(filename);
void *buffer; void *buffer;
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
if (!path.alloc) { strbuf_reset(&path);
path.buf = xmalloc(PATH_MAX); strbuf_grow(&path, PATH_MAX);
path.alloc = PATH_MAX; strbuf_add(&path, base, baselen);
path.len = path.eof = 0; strbuf_addstr(&path, filename);
}
if (path.alloc < baselen + filenamelen + 1) {
free(path.buf);
path.buf = xmalloc(baselen + filenamelen + 1);
path.alloc = baselen + filenamelen + 1;
}
memcpy(path.buf, base, baselen);
memcpy(path.buf + baselen, filename, filenamelen);
path.len = baselen + filenamelen;
path.buf[path.len] = '\0';
if (S_ISDIR(mode) || S_ISGITLINK(mode)) { if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
strbuf_append_string(&path, "/"); strbuf_addch(&path, '/');
buffer = NULL; buffer = NULL;
size = 0; size = 0;
} else { } else {

7
attr.c
View File

@ -160,12 +160,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
else if (!equals) else if (!equals)
e->setto = ATTR__TRUE; e->setto = ATTR__TRUE;
else { else {
char *value; e->setto = xmemdupz(equals + 1, ep - equals - 1);
int vallen = ep - equals;
value = xmalloc(vallen);
memcpy(value, equals+1, vallen-1);
value[vallen-1] = 0;
e->setto = value;
} }
e->attr = git_attr(cp, len); e->attr = git_attr(cp, len);
} }

View File

@ -71,12 +71,8 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
baselen = common_prefix(pathspec); baselen = common_prefix(pathspec);
path = "."; path = ".";
base = ""; base = "";
if (baselen) { if (baselen)
char *common = xmalloc(baselen + 1); path = base = xmemdupz(*pathspec, baselen);
memcpy(common, *pathspec, baselen);
common[baselen] = 0;
path = base = common;
}
/* Read the directory and prune it */ /* Read the directory and prune it */
read_directory(dir, path, base, baselen, pathspec); read_directory(dir, path, base, baselen, pathspec);

View File

@ -163,15 +163,14 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c
fputs(pre, output); fputs(pre, output);
if (patch->old_name && patch->new_name && if (patch->old_name && patch->new_name &&
strcmp(patch->old_name, patch->new_name)) { strcmp(patch->old_name, patch->new_name)) {
write_name_quoted(NULL, 0, patch->old_name, 1, output); quote_c_style(patch->old_name, NULL, output, 0);
fputs(" => ", output); fputs(" => ", output);
write_name_quoted(NULL, 0, patch->new_name, 1, output); quote_c_style(patch->new_name, NULL, output, 0);
} } else {
else {
const char *n = patch->new_name; const char *n = patch->new_name;
if (!n) if (!n)
n = patch->old_name; n = patch->old_name;
write_name_quoted(NULL, 0, n, 1, output); quote_c_style(n, NULL, output, 0);
} }
fputs(post, output); fputs(post, output);
} }
@ -179,36 +178,18 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c
#define CHUNKSIZE (8192) #define CHUNKSIZE (8192)
#define SLOP (16) #define SLOP (16)
static void *read_patch_file(int fd, unsigned long *sizep) static void read_patch_file(struct strbuf *sb, int fd)
{ {
unsigned long size = 0, alloc = CHUNKSIZE; if (strbuf_read(sb, fd, 0) < 0)
void *buffer = xmalloc(alloc);
for (;;) {
ssize_t nr = alloc - size;
if (nr < 1024) {
alloc += CHUNKSIZE;
buffer = xrealloc(buffer, alloc);
nr = alloc - size;
}
nr = xread(fd, (char *) buffer + size, nr);
if (!nr)
break;
if (nr < 0)
die("git-apply: read returned %s", strerror(errno)); die("git-apply: read returned %s", strerror(errno));
size += nr;
}
*sizep = size;
/* /*
* Make sure that we have some slop in the buffer * Make sure that we have some slop in the buffer
* so that we can do speculative "memcmp" etc, and * so that we can do speculative "memcmp" etc, and
* see to it that it is NUL-filled. * see to it that it is NUL-filled.
*/ */
if (alloc < size + SLOP) strbuf_grow(sb, SLOP);
buffer = xrealloc(buffer, size + SLOP); memset(sb->buf + sb->len, 0, SLOP);
memset((char *) buffer + size, 0, SLOP);
return buffer;
} }
static unsigned long linelen(const char *buffer, unsigned long size) static unsigned long linelen(const char *buffer, unsigned long size)
@ -244,35 +225,33 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
{ {
int len; int len;
const char *start = line; const char *start = line;
char *name;
if (*line == '"') { if (*line == '"') {
struct strbuf name;
/* Proposed "new-style" GNU patch/diff format; see /* Proposed "new-style" GNU patch/diff format; see
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
*/ */
name = unquote_c_style(line, NULL); strbuf_init(&name, 0);
if (name) { if (!unquote_c_style(&name, line, NULL)) {
char *cp = name; char *cp;
while (p_value) {
for (cp = name.buf; p_value; p_value--) {
cp = strchr(cp, '/'); cp = strchr(cp, '/');
if (!cp) if (!cp)
break; break;
cp++; cp++;
p_value--;
} }
if (cp) { if (cp) {
/* name can later be freed, so we need /* name can later be freed, so we need
* to memmove, not just return cp * to memmove, not just return cp
*/ */
memmove(name, cp, strlen(cp) + 1); strbuf_remove(&name, 0, cp - name.buf);
free(def); free(def);
return name; return strbuf_detach(&name, NULL);
}
else {
free(name);
name = NULL;
} }
} }
strbuf_release(&name);
} }
for (;;) { for (;;) {
@ -304,13 +283,10 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
int deflen = strlen(def); int deflen = strlen(def);
if (deflen < len && !strncmp(start, def, deflen)) if (deflen < len && !strncmp(start, def, deflen))
return def; return def;
free(def);
} }
name = xmalloc(len + 1); return xmemdupz(start, len);
memcpy(name, start, len);
name[len] = 0;
free(def);
return name;
} }
static int count_slashes(const char *cp) static int count_slashes(const char *cp)
@ -583,29 +559,30 @@ static const char *stop_at_slash(const char *line, int llen)
*/ */
static char *git_header_name(char *line, int llen) static char *git_header_name(char *line, int llen)
{ {
int len;
const char *name; const char *name;
const char *second = NULL; const char *second = NULL;
size_t len;
line += strlen("diff --git "); line += strlen("diff --git ");
llen -= strlen("diff --git "); llen -= strlen("diff --git ");
if (*line == '"') { if (*line == '"') {
const char *cp; const char *cp;
char *first = unquote_c_style(line, &second); struct strbuf first;
if (!first) struct strbuf sp;
return NULL;
strbuf_init(&first, 0);
strbuf_init(&sp, 0);
if (unquote_c_style(&first, line, &second))
goto free_and_fail1;
/* advance to the first slash */ /* advance to the first slash */
cp = stop_at_slash(first, strlen(first)); cp = stop_at_slash(first.buf, first.len);
if (!cp || cp == first) {
/* we do not accept absolute paths */ /* we do not accept absolute paths */
free_first_and_fail: if (!cp || cp == first.buf)
free(first); goto free_and_fail1;
return NULL; strbuf_remove(&first, 0, cp + 1 - first.buf);
}
len = strlen(cp+1);
memmove(first, cp+1, len+1); /* including NUL */
/* second points at one past closing dq of name. /* second points at one past closing dq of name.
* find the second name. * find the second name.
@ -614,40 +591,40 @@ static char *git_header_name(char *line, int llen)
second++; second++;
if (line + llen <= second) if (line + llen <= second)
goto free_first_and_fail; goto free_and_fail1;
if (*second == '"') { if (*second == '"') {
char *sp = unquote_c_style(second, NULL); if (unquote_c_style(&sp, second, NULL))
if (!sp) goto free_and_fail1;
goto free_first_and_fail; cp = stop_at_slash(sp.buf, sp.len);
cp = stop_at_slash(sp, strlen(sp)); if (!cp || cp == sp.buf)
if (!cp || cp == sp) { goto free_and_fail1;
free_both_and_fail:
free(sp);
goto free_first_and_fail;
}
/* They must match, otherwise ignore */ /* They must match, otherwise ignore */
if (strcmp(cp+1, first)) if (strcmp(cp + 1, first.buf))
goto free_both_and_fail; goto free_and_fail1;
free(sp); strbuf_release(&sp);
return first; return strbuf_detach(&first, NULL);
} }
/* unquoted second */ /* unquoted second */
cp = stop_at_slash(second, line + llen - second); cp = stop_at_slash(second, line + llen - second);
if (!cp || cp == second) if (!cp || cp == second)
goto free_first_and_fail; goto free_and_fail1;
cp++; cp++;
if (line + llen - cp != len + 1 || if (line + llen - cp != first.len + 1 ||
memcmp(first, cp, len)) memcmp(first.buf, cp, first.len))
goto free_first_and_fail; goto free_and_fail1;
return first; return strbuf_detach(&first, NULL);
free_and_fail1:
strbuf_release(&first);
strbuf_release(&sp);
return NULL;
} }
/* unquoted first name */ /* unquoted first name */
name = stop_at_slash(line, llen); name = stop_at_slash(line, llen);
if (!name || name == line) if (!name || name == line)
return NULL; return NULL;
name++; name++;
/* since the first name is unquoted, a dq if exists must be /* since the first name is unquoted, a dq if exists must be
@ -655,28 +632,30 @@ static char *git_header_name(char *line, int llen)
*/ */
for (second = name; second < line + llen; second++) { for (second = name; second < line + llen; second++) {
if (*second == '"') { if (*second == '"') {
const char *cp = second; struct strbuf sp;
const char *np; const char *np;
char *sp = unquote_c_style(second, NULL);
if (!sp) strbuf_init(&sp, 0);
return NULL; if (unquote_c_style(&sp, second, NULL))
np = stop_at_slash(sp, strlen(sp)); goto free_and_fail2;
if (!np || np == sp) {
free_second_and_fail: np = stop_at_slash(sp.buf, sp.len);
free(sp); if (!np || np == sp.buf)
return NULL; goto free_and_fail2;
}
np++; np++;
len = strlen(np);
if (len < cp - name && len = sp.buf + sp.len - np;
if (len < second - name &&
!strncmp(np, name, len) && !strncmp(np, name, len) &&
isspace(name[len])) { isspace(name[len])) {
/* Good */ /* Good */
memmove(sp, np, len + 1); strbuf_remove(&sp, 0, np - sp.buf);
return sp; return strbuf_detach(&sp, NULL);
} }
goto free_second_and_fail;
free_and_fail2:
strbuf_release(&sp);
return NULL;
} }
} }
@ -700,10 +679,7 @@ static char *git_header_name(char *line, int llen)
break; break;
} }
if (second[len] == '\n' && !memcmp(name, second, len)) { if (second[len] == '\n' && !memcmp(name, second, len)) {
char *ret = xmalloc(len + 1); return xmemdupz(name, len);
memcpy(ret, name, len);
ret[len] = 0;
return ret;
} }
} }
} }
@ -1397,96 +1373,66 @@ static const char minuses[]= "--------------------------------------------------
static void show_stats(struct patch *patch) static void show_stats(struct patch *patch)
{ {
const char *prefix = ""; struct strbuf qname;
char *name = patch->new_name; char *cp = patch->new_name ? patch->new_name : patch->old_name;
char *qname = NULL; int max, add, del;
int len, max, add, del, total;
if (!name) strbuf_init(&qname, 0);
name = patch->old_name; quote_c_style(cp, &qname, NULL, 0);
if (0 < (len = quote_c_style(name, NULL, NULL, 0))) {
qname = xmalloc(len + 1);
quote_c_style(name, qname, NULL, 0);
name = qname;
}
/* /*
* "scale" the filename * "scale" the filename
*/ */
len = strlen(name);
max = max_len; max = max_len;
if (max > 50) if (max > 50)
max = 50; max = 50;
if (len > max) {
char *slash; if (qname.len > max) {
prefix = "..."; cp = strchr(qname.buf + qname.len + 3 - max, '/');
max -= 3; if (!cp)
name += len - max; cp = qname.buf + qname.len + 3 - max;
slash = strchr(name, '/'); strbuf_splice(&qname, 0, cp - qname.buf, "...", 3);
if (slash)
name = slash;
} }
len = max;
if (patch->is_binary) {
printf(" %-*s | Bin\n", max, qname.buf);
strbuf_release(&qname);
return;
}
printf(" %-*s |", max, qname.buf);
strbuf_release(&qname);
/* /*
* scale the add/delete * scale the add/delete
*/ */
max = max_change; max = max + max_change > 70 ? 70 - max : max_change;
if (max + len > 70)
max = 70 - len;
add = patch->lines_added; add = patch->lines_added;
del = patch->lines_deleted; del = patch->lines_deleted;
total = add + del;
if (max_change > 0) { if (max_change > 0) {
total = (total * max + max_change / 2) / max_change; int total = ((add + del) * max + max_change / 2) / max_change;
add = (add * max + max_change / 2) / max_change; add = (add * max + max_change / 2) / max_change;
del = total - add; del = total - add;
} }
if (patch->is_binary) printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
printf(" %s%-*s | Bin\n", prefix, len, name);
else
printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
len, name, patch->lines_added + patch->lines_deleted,
add, pluses, del, minuses); add, pluses, del, minuses);
free(qname);
} }
static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p) static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
{ {
int fd;
unsigned long got;
unsigned long nsize;
char *nbuf;
unsigned long size = *size_p;
char *buf = *buf_p;
switch (st->st_mode & S_IFMT) { switch (st->st_mode & S_IFMT) {
case S_IFLNK: case S_IFLNK:
return readlink(path, buf, size) != size; strbuf_grow(buf, st->st_size);
if (readlink(path, buf->buf, st->st_size) != st->st_size)
return -1;
strbuf_setlen(buf, st->st_size);
return 0;
case S_IFREG: case S_IFREG:
fd = open(path, O_RDONLY); if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
if (fd < 0) return error("unable to open or read %s", path);
return error("unable to open %s", path); convert_to_git(path, buf->buf, buf->len, buf);
got = 0; return 0;
for (;;) {
ssize_t ret = xread(fd, buf + got, size - got);
if (ret <= 0)
break;
got += ret;
}
close(fd);
nsize = got;
nbuf = convert_to_git(path, buf, &nsize);
if (nbuf) {
free(buf);
*buf_p = nbuf;
*alloc_p = nsize;
*size_p = nsize;
}
return got != size;
default: default:
return -1; return -1;
} }
@ -1591,12 +1537,6 @@ static void remove_last_line(const char **rbuf, int *rsize)
*rsize = offset + 1; *rsize = offset + 1;
} }
struct buffer_desc {
char *buffer;
unsigned long size;
unsigned long alloc;
};
static int apply_line(char *output, const char *patch, int plen) static int apply_line(char *output, const char *patch, int plen)
{ {
/* plen is number of bytes to be copied from patch, /* plen is number of bytes to be copied from patch,
@ -1673,10 +1613,9 @@ static int apply_line(char *output, const char *patch, int plen)
return output + plen - buf; return output + plen - buf;
} }
static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof) static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int inaccurate_eof)
{ {
int match_beginning, match_end; int match_beginning, match_end;
char *buf = desc->buffer;
const char *patch = frag->patch; const char *patch = frag->patch;
int offset, size = frag->size; int offset, size = frag->size;
char *old = xmalloc(size); char *old = xmalloc(size);
@ -1787,24 +1726,17 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
lines = 0; lines = 0;
pos = frag->newpos; pos = frag->newpos;
for (;;) { for (;;) {
offset = find_offset(buf, desc->size, offset = find_offset(buf->buf, buf->len,
oldlines, oldsize, pos, &lines); oldlines, oldsize, pos, &lines);
if (match_end && offset + oldsize != desc->size) if (match_end && offset + oldsize != buf->len)
offset = -1; offset = -1;
if (match_beginning && offset) if (match_beginning && offset)
offset = -1; offset = -1;
if (offset >= 0) { if (offset >= 0) {
int diff;
unsigned long size, alloc;
if (new_whitespace == strip_whitespace && if (new_whitespace == strip_whitespace &&
(desc->size - oldsize - offset == 0)) /* end of file? */ (buf->len - oldsize - offset == 0)) /* end of file? */
newsize -= new_blank_lines_at_end; newsize -= new_blank_lines_at_end;
diff = newsize - oldsize;
size = desc->size + diff;
alloc = desc->alloc;
/* Warn if it was necessary to reduce the number /* Warn if it was necessary to reduce the number
* of context lines. * of context lines.
*/ */
@ -1814,19 +1746,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
" to apply fragment at %d\n", " to apply fragment at %d\n",
leading, trailing, pos + lines); leading, trailing, pos + lines);
if (size > alloc) { strbuf_splice(buf, offset, oldsize, newlines, newsize);
alloc = size + 8192;
desc->alloc = alloc;
buf = xrealloc(buf, alloc);
desc->buffer = buf;
}
desc->size = size;
memmove(buf + offset + newsize,
buf + offset + oldsize,
size - offset - newsize);
memcpy(buf + offset, newlines, newsize);
offset = 0; offset = 0;
break; break;
} }
@ -1862,12 +1783,11 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
return offset; return offset;
} }
static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch) static int apply_binary_fragment(struct strbuf *buf, struct patch *patch)
{ {
unsigned long dst_size;
struct fragment *fragment = patch->fragments; struct fragment *fragment = patch->fragments;
void *data; unsigned long len;
void *result; void *dst;
/* Binary patch is irreversible without the optional second hunk */ /* Binary patch is irreversible without the optional second hunk */
if (apply_in_reverse) { if (apply_in_reverse) {
@ -1878,29 +1798,24 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
? patch->new_name : patch->old_name); ? patch->new_name : patch->old_name);
fragment = fragment->next; fragment = fragment->next;
} }
data = (void*) fragment->patch;
switch (fragment->binary_patch_method) { switch (fragment->binary_patch_method) {
case BINARY_DELTA_DEFLATED: case BINARY_DELTA_DEFLATED:
result = patch_delta(desc->buffer, desc->size, dst = patch_delta(buf->buf, buf->len, fragment->patch,
data, fragment->size, &len);
fragment->size, if (!dst)
&dst_size);
free(desc->buffer);
desc->buffer = result;
break;
case BINARY_LITERAL_DEFLATED:
free(desc->buffer);
desc->buffer = data;
dst_size = fragment->size;
break;
}
if (!desc->buffer)
return -1; return -1;
desc->size = desc->alloc = dst_size; /* XXX patch_delta NUL-terminates */
strbuf_attach(buf, dst, len, len + 1);
return 0;
case BINARY_LITERAL_DEFLATED:
strbuf_reset(buf);
strbuf_add(buf, fragment->patch, fragment->size);
return 0; return 0;
} }
return -1;
}
static int apply_binary(struct buffer_desc *desc, struct patch *patch) static int apply_binary(struct strbuf *buf, struct patch *patch)
{ {
const char *name = patch->old_name ? patch->old_name : patch->new_name; const char *name = patch->old_name ? patch->old_name : patch->new_name;
unsigned char sha1[20]; unsigned char sha1[20];
@ -1919,7 +1834,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
/* See if the old one matches what the patch /* See if the old one matches what the patch
* applies to. * applies to.
*/ */
hash_sha1_file(desc->buffer, desc->size, blob_type, sha1); hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix)) if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
return error("the patch applies to '%s' (%s), " return error("the patch applies to '%s' (%s), "
"which does not match the " "which does not match the "
@ -1928,16 +1843,14 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
} }
else { else {
/* Otherwise, the old one must be empty. */ /* Otherwise, the old one must be empty. */
if (desc->size) if (buf->len)
return error("the patch applies to an empty " return error("the patch applies to an empty "
"'%s' but it is not empty", name); "'%s' but it is not empty", name);
} }
get_sha1_hex(patch->new_sha1_prefix, sha1); get_sha1_hex(patch->new_sha1_prefix, sha1);
if (is_null_sha1(sha1)) { if (is_null_sha1(sha1)) {
free(desc->buffer); strbuf_release(buf);
desc->alloc = desc->size = 0;
desc->buffer = NULL;
return 0; /* deletion patch */ return 0; /* deletion patch */
} }
@ -1945,43 +1858,44 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
/* We already have the postimage */ /* We already have the postimage */
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
char *result;
free(desc->buffer); result = read_sha1_file(sha1, &type, &size);
desc->buffer = read_sha1_file(sha1, &type, &size); if (!result)
if (!desc->buffer)
return error("the necessary postimage %s for " return error("the necessary postimage %s for "
"'%s' cannot be read", "'%s' cannot be read",
patch->new_sha1_prefix, name); patch->new_sha1_prefix, name);
desc->alloc = desc->size = size; /* XXX read_sha1_file NUL-terminates */
} strbuf_attach(buf, result, size, size + 1);
else { } else {
/* We have verified desc matches the preimage; /* We have verified buf matches the preimage;
* apply the patch data to it, which is stored * apply the patch data to it, which is stored
* in the patch->fragments->{patch,size}. * in the patch->fragments->{patch,size}.
*/ */
if (apply_binary_fragment(desc, patch)) if (apply_binary_fragment(buf, patch))
return error("binary patch does not apply to '%s'", return error("binary patch does not apply to '%s'",
name); name);
/* verify that the result matches */ /* verify that the result matches */
hash_sha1_file(desc->buffer, desc->size, blob_type, sha1); hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix)) if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1)); return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)",
name, patch->new_sha1_prefix, sha1_to_hex(sha1));
} }
return 0; return 0;
} }
static int apply_fragments(struct buffer_desc *desc, struct patch *patch) static int apply_fragments(struct strbuf *buf, struct patch *patch)
{ {
struct fragment *frag = patch->fragments; struct fragment *frag = patch->fragments;
const char *name = patch->old_name ? patch->old_name : patch->new_name; const char *name = patch->old_name ? patch->old_name : patch->new_name;
if (patch->is_binary) if (patch->is_binary)
return apply_binary(desc, patch); return apply_binary(buf, patch);
while (frag) { while (frag) {
if (apply_one_fragment(desc, frag, patch->inaccurate_eof)) { if (apply_one_fragment(buf, frag, patch->inaccurate_eof)) {
error("patch failed: %s:%ld", name, frag->oldpos); error("patch failed: %s:%ld", name, frag->oldpos);
if (!apply_with_reject) if (!apply_with_reject)
return -1; return -1;
@ -1992,76 +1906,56 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
return 0; return 0;
} }
static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p, static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
unsigned long *size_p)
{ {
if (!ce) if (!ce)
return 0; return 0;
if (S_ISGITLINK(ntohl(ce->ce_mode))) { if (S_ISGITLINK(ntohl(ce->ce_mode))) {
*buf_p = xmalloc(100); strbuf_grow(buf, 100);
*size_p = snprintf(*buf_p, 100, strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
"Subproject commit %s\n", sha1_to_hex(ce->sha1));
} else { } else {
enum object_type type; enum object_type type;
*buf_p = read_sha1_file(ce->sha1, &type, size_p); unsigned long sz;
if (!*buf_p) char *result;
result = read_sha1_file(ce->sha1, &type, &sz);
if (!result)
return -1; return -1;
/* XXX read_sha1_file NUL-terminates */
strbuf_attach(buf, result, sz, sz + 1);
} }
return 0; return 0;
} }
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{ {
char *buf; struct strbuf buf;
unsigned long size, alloc;
struct buffer_desc desc;
size = 0; strbuf_init(&buf, 0);
alloc = 0;
buf = NULL;
if (cached) { if (cached) {
if (read_file_or_gitlink(ce, &buf, &size)) if (read_file_or_gitlink(ce, &buf))
return error("read of %s failed", patch->old_name); return error("read of %s failed", patch->old_name);
alloc = size;
} else if (patch->old_name) { } else if (patch->old_name) {
if (S_ISGITLINK(patch->old_mode)) { if (S_ISGITLINK(patch->old_mode)) {
if (ce) if (ce) {
read_file_or_gitlink(ce, &buf, &size); read_file_or_gitlink(ce, &buf);
else { } else {
/* /*
* There is no way to apply subproject * There is no way to apply subproject
* patch without looking at the index. * patch without looking at the index.
*/ */
patch->fragments = NULL; patch->fragments = NULL;
size = 0;
} }
} } else {
else { if (read_old_data(st, patch->old_name, &buf))
size = xsize_t(st->st_size); return error("read of %s failed", patch->old_name);
alloc = size + 8192;
buf = xmalloc(alloc);
if (read_old_data(st, patch->old_name,
&buf, &alloc, &size))
return error("read of %s failed",
patch->old_name);
} }
} }
desc.size = size; if (apply_fragments(&buf, patch) < 0)
desc.alloc = alloc;
desc.buffer = buf;
if (apply_fragments(&desc, patch) < 0)
return -1; /* note with --reject this succeeds. */ return -1; /* note with --reject this succeeds. */
patch->result = strbuf_detach(&buf, &patch->resultsize);
/* NUL terminate the result */
if (desc.alloc <= desc.size)
desc.buffer = xrealloc(desc.buffer, desc.size + 1);
desc.buffer[desc.size] = 0;
patch->result = desc.buffer;
patch->resultsize = desc.size;
if (0 < patch->is_delete && patch->resultsize) if (0 < patch->is_delete && patch->resultsize)
return error("removal patch leaves file contents"); return error("removal patch leaves file contents");
@ -2315,13 +2209,8 @@ static void numstat_patch_list(struct patch *patch)
if (patch->is_binary) if (patch->is_binary)
printf("-\t-\t"); printf("-\t-\t");
else else
printf("%d\t%d\t", printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
patch->lines_added, patch->lines_deleted); write_name_quoted(name, stdout, line_termination);
if (line_termination && quote_c_style(name, NULL, NULL, 0))
quote_c_style(name, NULL, stdout, 0);
else
fputs(name, stdout);
putchar(line_termination);
} }
} }
@ -2486,7 +2375,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size) static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
{ {
int fd; int fd;
char *nbuf; struct strbuf nbuf;
if (S_ISGITLINK(mode)) { if (S_ISGITLINK(mode)) {
struct stat st; struct stat st;
@ -2505,23 +2394,16 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
if (fd < 0) if (fd < 0)
return -1; return -1;
nbuf = convert_to_working_tree(path, buf, &size); strbuf_init(&nbuf, 0);
if (nbuf) if (convert_to_working_tree(path, buf, size, &nbuf)) {
buf = nbuf; size = nbuf.len;
buf = nbuf.buf;
while (size) {
int written = xwrite(fd, buf, size);
if (written < 0)
die("writing file %s: %s", path, strerror(errno));
if (!written)
die("out of space writing file %s", path);
buf += written;
size -= written;
} }
write_or_die(fd, buf, size);
strbuf_release(&nbuf);
if (close(fd) < 0) if (close(fd) < 0)
die("closing file %s: %s", path, strerror(errno)); die("closing file %s: %s", path, strerror(errno));
if (nbuf)
free(nbuf);
return 0; return 0;
} }
@ -2754,22 +2636,22 @@ static void prefix_patches(struct patch *p)
static int apply_patch(int fd, const char *filename, int inaccurate_eof) static int apply_patch(int fd, const char *filename, int inaccurate_eof)
{ {
unsigned long offset, size; size_t offset;
char *buffer = read_patch_file(fd, &size); struct strbuf buf;
struct patch *list = NULL, **listp = &list; struct patch *list = NULL, **listp = &list;
int skipped_patch = 0; int skipped_patch = 0;
strbuf_init(&buf, 0);
patch_input_file = filename; patch_input_file = filename;
if (!buffer) read_patch_file(&buf, fd);
return -1;
offset = 0; offset = 0;
while (size > 0) { while (offset < buf.len) {
struct patch *patch; struct patch *patch;
int nr; int nr;
patch = xcalloc(1, sizeof(*patch)); patch = xcalloc(1, sizeof(*patch));
patch->inaccurate_eof = inaccurate_eof; patch->inaccurate_eof = inaccurate_eof;
nr = parse_chunk(buffer + offset, size, patch); nr = parse_chunk(buf.buf + offset, buf.len, patch);
if (nr < 0) if (nr < 0)
break; break;
if (apply_in_reverse) if (apply_in_reverse)
@ -2787,7 +2669,6 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
skipped_patch++; skipped_patch++;
} }
offset += nr; offset += nr;
size -= nr;
} }
if (whitespace_error && (new_whitespace == error_on_whitespace)) if (whitespace_error && (new_whitespace == error_on_whitespace))
@ -2822,7 +2703,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
if (summary) if (summary)
summary_patch_list(list); summary_patch_list(list);
free(buffer); strbuf_release(&buf);
return 0; return 0;
} }

View File

@ -81,95 +81,79 @@ static int run_remote_archiver(const char *remote, int argc,
return !!rv; return !!rv;
} }
static void *format_subst(const struct commit *commit, const char *format, static void format_subst(const struct commit *commit,
unsigned long *sizep) const char *src, size_t len,
struct strbuf *buf)
{ {
unsigned long len = *sizep, result_len = 0; char *to_free = NULL;
const char *a = format; struct strbuf fmt;
char *result = NULL;
if (src == buf->buf)
to_free = strbuf_detach(buf, NULL);
strbuf_init(&fmt, 0);
for (;;) { for (;;) {
const char *b, *c; const char *b, *c;
char *fmt, *formatted = NULL;
unsigned long a_len, fmt_len, formatted_len, allocated = 0;
b = memmem(a, len, "$Format:", 8); b = memmem(src, len, "$Format:", 8);
if (!b || a + len < b + 9) if (!b || src + len < b + 9)
break; break;
c = memchr(b + 8, '$', len - 8); c = memchr(b + 8, '$', len - 8);
if (!c) if (!c)
break; break;
a_len = b - a; strbuf_reset(&fmt);
fmt_len = c - b - 8; strbuf_add(&fmt, b + 8, c - b - 8);
fmt = xmalloc(fmt_len + 1);
memcpy(fmt, b + 8, fmt_len);
fmt[fmt_len] = '\0';
formatted_len = format_commit_message(commit, fmt, &formatted, strbuf_add(buf, src, b - src);
&allocated); format_commit_message(commit, fmt.buf, buf);
free(fmt); len -= c + 1 - src;
result = xrealloc(result, result_len + a_len + formatted_len); src = c + 1;
memcpy(result + result_len, a, a_len); }
memcpy(result + result_len + a_len, formatted, formatted_len); strbuf_add(buf, src, len);
result_len += a_len + formatted_len; strbuf_release(&fmt);
len -= c + 1 - a; free(to_free);
a = c + 1;
} }
if (result && len) { static int convert_to_archive(const char *path,
result = xrealloc(result, result_len + len); const void *src, size_t len,
memcpy(result + result_len, a, len); struct strbuf *buf,
result_len += len;
}
*sizep = result_len;
return result;
}
static void *convert_to_archive(const char *path,
const void *src, unsigned long *sizep,
const struct commit *commit) const struct commit *commit)
{ {
static struct git_attr *attr_export_subst; static struct git_attr *attr_export_subst;
struct git_attr_check check[1]; struct git_attr_check check[1];
if (!commit) if (!commit)
return NULL; return 0;
if (!attr_export_subst) if (!attr_export_subst)
attr_export_subst = git_attr("export-subst", 12); attr_export_subst = git_attr("export-subst", 12);
check[0].attr = attr_export_subst; check[0].attr = attr_export_subst;
if (git_checkattr(path, ARRAY_SIZE(check), check)) if (git_checkattr(path, ARRAY_SIZE(check), check))
return NULL; return 0;
if (!ATTR_TRUE(check[0].value)) if (!ATTR_TRUE(check[0].value))
return NULL; return 0;
return format_subst(commit, src, sizep); format_subst(commit, src, len, buf);
return 1;
} }
void *sha1_file_to_archive(const char *path, const unsigned char *sha1, void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
unsigned int mode, enum object_type *type, unsigned int mode, enum object_type *type,
unsigned long *size, unsigned long *sizep,
const struct commit *commit) const struct commit *commit)
{ {
void *buffer, *converted; void *buffer;
buffer = read_sha1_file(sha1, type, size); buffer = read_sha1_file(sha1, type, sizep);
if (buffer && S_ISREG(mode)) { if (buffer && S_ISREG(mode)) {
converted = convert_to_working_tree(path, buffer, size); struct strbuf buf;
if (converted) {
free(buffer);
buffer = converted;
}
converted = convert_to_archive(path, buffer, size, commit); strbuf_init(&buf, 0);
if (converted) { strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
free(buffer); convert_to_working_tree(path, buf.buf, buf.len, &buf);
buffer = converted; convert_to_archive(path, buf.buf, buf.len, &buf, commit);
} buffer = strbuf_detach(&buf, sizep);
} }
return buffer; return buffer;

View File

@ -1430,8 +1430,7 @@ static void get_commit_info(struct commit *commit,
static void write_filename_info(const char *path) static void write_filename_info(const char *path)
{ {
printf("filename "); printf("filename ");
write_name_quoted(NULL, 0, path, 1, stdout); write_name_quoted(path, stdout, '\n');
putchar('\n');
} }
/* /*
@ -2001,11 +2000,9 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
struct commit *commit; struct commit *commit;
struct origin *origin; struct origin *origin;
unsigned char head_sha1[20]; unsigned char head_sha1[20];
char *buf; struct strbuf buf;
const char *ident; const char *ident;
int fd;
time_t now; time_t now;
unsigned long fin_size;
int size, len; int size, len;
struct cache_entry *ce; struct cache_entry *ce;
unsigned mode; unsigned mode;
@ -2023,9 +2020,11 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
origin = make_origin(commit, path); origin = make_origin(commit, path);
strbuf_init(&buf, 0);
if (!contents_from || strcmp("-", contents_from)) { if (!contents_from || strcmp("-", contents_from)) {
struct stat st; struct stat st;
const char *read_from; const char *read_from;
unsigned long fin_size;
if (contents_from) { if (contents_from) {
if (stat(contents_from, &st) < 0) if (stat(contents_from, &st) < 0)
@ -2038,19 +2037,16 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
read_from = path; read_from = path;
} }
fin_size = xsize_t(st.st_size); fin_size = xsize_t(st.st_size);
buf = xmalloc(fin_size+1);
mode = canon_mode(st.st_mode); mode = canon_mode(st.st_mode);
switch (st.st_mode & S_IFMT) { switch (st.st_mode & S_IFMT) {
case S_IFREG: case S_IFREG:
fd = open(read_from, O_RDONLY); if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
if (fd < 0) die("cannot open or read %s", read_from);
die("cannot open %s", read_from);
if (read_in_full(fd, buf, fin_size) != fin_size)
die("cannot read %s", read_from);
break; break;
case S_IFLNK: case S_IFLNK:
if (readlink(read_from, buf, fin_size+1) != fin_size) if (readlink(read_from, buf.buf, buf.alloc) != fin_size)
die("cannot readlink %s", read_from); die("cannot readlink %s", read_from);
buf.len = fin_size;
break; break;
default: default:
die("unsupported file type %s", read_from); die("unsupported file type %s", read_from);
@ -2059,26 +2055,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
else { else {
/* Reading from stdin */ /* Reading from stdin */
contents_from = "standard input"; contents_from = "standard input";
buf = NULL;
fin_size = 0;
mode = 0; mode = 0;
while (1) { if (strbuf_read(&buf, 0, 0) < 0)
ssize_t cnt = 8192; die("read error %s from stdin", strerror(errno));
buf = xrealloc(buf, fin_size + cnt);
cnt = xread(0, buf + fin_size, cnt);
if (cnt < 0)
die("read error %s from stdin",
strerror(errno));
if (!cnt)
break;
fin_size += cnt;
} }
buf = xrealloc(buf, fin_size + 1); origin->file.ptr = buf.buf;
} origin->file.size = buf.len;
buf[fin_size] = 0; pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
origin->file.ptr = buf;
origin->file.size = fin_size;
pretend_sha1_file(buf, fin_size, OBJ_BLOB, origin->blob_sha1);
commit->util = origin; commit->util = origin;
/* /*

View File

@ -268,23 +268,22 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
} }
if (verbose) { if (verbose) {
char *subject = NULL; struct strbuf subject;
unsigned long subject_len = 0;
const char *sub = " **** invalid ref ****"; const char *sub = " **** invalid ref ****";
strbuf_init(&subject, 0);
commit = lookup_commit(item->sha1); commit = lookup_commit(item->sha1);
if (commit && !parse_commit(commit)) { if (commit && !parse_commit(commit)) {
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, pretty_print_commit(CMIT_FMT_ONELINE, commit,
&subject, &subject_len, 0, &subject, 0, NULL, NULL, 0);
NULL, NULL, 0); sub = subject.buf;
sub = subject;
} }
printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color), printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
maxwidth, item->name, maxwidth, item->name,
branch_get_color(COLOR_BRANCH_RESET), branch_get_color(COLOR_BRANCH_RESET),
find_unique_abbrev(item->sha1, abbrev), sub); find_unique_abbrev(item->sha1, abbrev), sub);
if (subject) strbuf_release(&subject);
free(subject);
} else { } else {
printf("%c %s%s%s\n", c, branch_get_color(color), item->name, printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
branch_get_color(COLOR_BRANCH_RESET)); branch_get_color(COLOR_BRANCH_RESET));

View File

@ -56,7 +56,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
else if (ATTR_UNSET(value)) else if (ATTR_UNSET(value))
value = "unspecified"; value = "unspecified";
write_name_quoted("", 0, argv[i], 1, stdout); quote_c_style(argv[i], NULL, stdout, 0);
printf(": %s: %s\n", argv[j+1], value); printf(": %s: %s\n", argv[j+1], value);
} }
} }

View File

@ -38,7 +38,6 @@
*/ */
#include "builtin.h" #include "builtin.h"
#include "cache.h" #include "cache.h"
#include "strbuf.h"
#include "quote.h" #include "quote.h"
#include "cache-tree.h" #include "cache-tree.h"
@ -67,9 +66,7 @@ static void write_tempfile_record(const char *name, int prefix_length)
fputs(topath[checkout_stage], stdout); fputs(topath[checkout_stage], stdout);
putchar('\t'); putchar('\t');
write_name_quoted("", 0, name + prefix_length, write_name_quoted(name + prefix_length, stdout, line_termination);
line_termination, stdout);
putchar(line_termination);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
topath[i][0] = 0; topath[i][0] = 0;
@ -271,28 +268,28 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
} }
if (read_from_stdin) { if (read_from_stdin) {
struct strbuf buf; struct strbuf buf, nbuf;
if (all) if (all)
die("git-checkout-index: don't mix '--all' and '--stdin'"); die("git-checkout-index: don't mix '--all' and '--stdin'");
strbuf_init(&buf);
while (1) {
char *path_name;
const char *p;
read_line(&buf, stdin, line_termination); strbuf_init(&buf, 0);
if (buf.eof) strbuf_init(&nbuf, 0);
break; while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
if (line_termination && buf.buf[0] == '"') const char *p;
path_name = unquote_c_style(buf.buf, NULL); if (line_termination && buf.buf[0] == '"') {
else strbuf_reset(&nbuf);
path_name = buf.buf; if (unquote_c_style(&nbuf, buf.buf, NULL))
p = prefix_path(prefix, prefix_length, path_name); die("line is badly quoted");
checkout_file(p, prefix_length); strbuf_swap(&buf, &nbuf);
if (p < path_name || p > path_name + strlen(path_name))
free((char *)p);
if (path_name != buf.buf)
free(path_name);
} }
p = prefix_path(prefix, prefix_length, buf.buf);
checkout_file(p, prefix_length);
if (p < buf.buf || p > buf.buf + buf.len)
free((char *)p);
}
strbuf_release(&nbuf);
strbuf_release(&buf);
} }
if (all) if (all)

View File

@ -14,36 +14,6 @@
/* /*
* FIXME! Share the code with "write-tree.c" * FIXME! Share the code with "write-tree.c"
*/ */
static void init_buffer(char **bufp, unsigned int *sizep)
{
*bufp = xmalloc(BLOCKING);
*sizep = 0;
}
static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
{
char one_line[2048];
va_list args;
int len;
unsigned long alloc, size, newsize;
char *buf;
va_start(args, fmt);
len = vsnprintf(one_line, sizeof(one_line), fmt, args);
va_end(args);
size = *sizep;
newsize = size + len + 1;
alloc = (size + 32767) & ~32767;
buf = *bufp;
if (newsize > alloc) {
alloc = (newsize + 32767) & ~32767;
buf = xrealloc(buf, alloc);
*bufp = buf;
}
*sizep = newsize - 1;
memcpy(buf + size, one_line, len);
}
static void check_valid(unsigned char *sha1, enum object_type expect) static void check_valid(unsigned char *sha1, enum object_type expect)
{ {
enum object_type type = sha1_object_info(sha1, NULL); enum object_type type = sha1_object_info(sha1, NULL);
@ -87,9 +57,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
int parents = 0; int parents = 0;
unsigned char tree_sha1[20]; unsigned char tree_sha1[20];
unsigned char commit_sha1[20]; unsigned char commit_sha1[20];
char comment[1000]; struct strbuf buffer;
char *buffer;
unsigned int size;
int encoding_is_utf8; int encoding_is_utf8;
git_config(git_default_config); git_config(git_default_config);
@ -118,8 +86,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
/* Not having i18n.commitencoding is the same as having utf-8 */ /* Not having i18n.commitencoding is the same as having utf-8 */
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding); encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
init_buffer(&buffer, &size); strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1)); strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree_sha1));
/* /*
* NOTE! This ordering means that the same exact tree merged with a * NOTE! This ordering means that the same exact tree merged with a
@ -127,26 +95,24 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
* if everything else stays the same. * if everything else stays the same.
*/ */
for (i = 0; i < parents; i++) for (i = 0; i < parents; i++)
add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i])); strbuf_addf(&buffer, "parent %s\n", sha1_to_hex(parent_sha1[i]));
/* Person/date information */ /* Person/date information */
add_buffer(&buffer, &size, "author %s\n", git_author_info(1)); strbuf_addf(&buffer, "author %s\n", git_author_info(1));
add_buffer(&buffer, &size, "committer %s\n", git_committer_info(1)); strbuf_addf(&buffer, "committer %s\n", git_committer_info(1));
if (!encoding_is_utf8) if (!encoding_is_utf8)
add_buffer(&buffer, &size, strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
"encoding %s\n", git_commit_encoding); strbuf_addch(&buffer, '\n');
add_buffer(&buffer, &size, "\n");
/* And add the comment */ /* And add the comment */
while (fgets(comment, sizeof(comment), stdin) != NULL) if (strbuf_read(&buffer, 0, 0) < 0)
add_buffer(&buffer, &size, "%s", comment); die("git-commit-tree: read returned %s", strerror(errno));
/* And check the encoding */ /* And check the encoding */
buffer[size] = '\0'; if (encoding_is_utf8 && !is_utf8(buffer.buf))
if (encoding_is_utf8 && !is_utf8(buffer))
fprintf(stderr, commit_utf8_warn); fprintf(stderr, commit_utf8_warn);
if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) { if (!write_sha1_file(buffer.buf, buffer.len, commit_type, commit_sha1)) {
printf("%s\n", sha1_to_hex(commit_sha1)); printf("%s\n", sha1_to_hex(commit_sha1));
return 0; return 0;
} }

View File

@ -3,26 +3,14 @@
#include "refs.h" #include "refs.h"
#include "commit.h" #include "commit.h"
#define CHUNK_SIZE 1024
static char *get_stdin(void) static char *get_stdin(void)
{ {
size_t offset = 0; struct strbuf buf;
char *data = xmalloc(CHUNK_SIZE); strbuf_init(&buf, 0);
if (strbuf_read(&buf, 0, 1024) < 0) {
while (1) { die("error reading standard input: %s", strerror(errno));
ssize_t cnt = xread(0, data + offset, CHUNK_SIZE);
if (cnt < 0)
die("error reading standard input: %s",
strerror(errno));
if (cnt == 0) {
data[offset] = 0;
break;
} }
offset += cnt; return strbuf_detach(&buf, NULL);
data = xrealloc(data, offset + CHUNK_SIZE);
}
return data;
} }
static void show_new(enum object_type type, unsigned char *sha1_new) static void show_new(enum object_type type, unsigned char *sha1_new)
@ -234,19 +222,15 @@ static char *find_local_name(const char *remote_name, const char *refs,
} }
if (!strncmp(remote_name, ref, len) && ref[len] == ':') { if (!strncmp(remote_name, ref, len) && ref[len] == ':') {
const char *local_part = ref + len + 1; const char *local_part = ref + len + 1;
char *ret;
int retlen; int retlen;
if (!next) if (!next)
retlen = strlen(local_part); retlen = strlen(local_part);
else else
retlen = next - local_part; retlen = next - local_part;
ret = xmalloc(retlen + 1);
memcpy(ret, local_part, retlen);
ret[retlen] = 0;
*force_p = single_force; *force_p = single_force;
*not_for_merge_p = not_for_merge; *not_for_merge_p = not_for_merge;
return ret; return xmemdupz(local_part, retlen);
} }
ref = next; ref = next;
} }

View File

@ -140,12 +140,10 @@ static int handle_line(char *line)
if (!strcmp(".", src) || !strcmp(src, origin)) { if (!strcmp(".", src) || !strcmp(src, origin)) {
int len = strlen(origin); int len = strlen(origin);
if (origin[0] == '\'' && origin[len - 1] == '\'') { if (origin[0] == '\'' && origin[len - 1] == '\'') {
char *new_origin = xmalloc(len - 1); origin = xmemdupz(origin + 1, len - 2);
memcpy(new_origin, origin + 1, len - 2); } else {
new_origin[len - 2] = 0;
origin = new_origin;
} else
origin = xstrdup(origin); origin = xstrdup(origin);
}
} else { } else {
char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5); char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
sprintf(new_origin, "%s of %s", origin, src); sprintf(new_origin, "%s of %s", origin, src);
@ -211,14 +209,11 @@ static void shortlog(const char *name, unsigned char *sha1,
bol += 2; bol += 2;
eol = strchr(bol, '\n'); eol = strchr(bol, '\n');
if (eol) { if (eol) {
int len = eol - bol; oneline = xmemdupz(bol, eol - bol);
oneline = xmalloc(len + 1); } else {
memcpy(oneline, bol, len);
oneline[len] = 0;
} else
oneline = xstrdup(bol); oneline = xstrdup(bol);
}
append_to_list(&subjects, oneline, NULL); append_to_list(&subjects, oneline, NULL);
} }

View File

@ -87,7 +87,6 @@ static int used_atom_cnt, sort_atom_limit, need_tagged;
static int parse_atom(const char *atom, const char *ep) static int parse_atom(const char *atom, const char *ep)
{ {
const char *sp; const char *sp;
char *n;
int i, at; int i, at;
sp = atom; sp = atom;
@ -129,10 +128,7 @@ static int parse_atom(const char *atom, const char *ep)
(sizeof *used_atom) * used_atom_cnt); (sizeof *used_atom) * used_atom_cnt);
used_atom_type = xrealloc(used_atom_type, used_atom_type = xrealloc(used_atom_type,
(sizeof(*used_atom_type) * used_atom_cnt)); (sizeof(*used_atom_type) * used_atom_cnt));
n = xmalloc(ep - atom + 1); used_atom[at] = xmemdupz(atom, ep - atom);
memcpy(n, atom, ep - atom);
n[ep-atom] = 0;
used_atom[at] = n;
used_atom_type[at] = valid_atom[i].cmp_type; used_atom_type[at] = valid_atom[i].cmp_type;
return at; return at;
} }
@ -316,46 +312,28 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un
static const char *copy_line(const char *buf) static const char *copy_line(const char *buf)
{ {
const char *eol = strchr(buf, '\n'); const char *eol = strchr(buf, '\n');
char *line;
int len;
if (!eol) if (!eol)
return ""; return "";
len = eol - buf; return xmemdupz(buf, eol - buf);
line = xmalloc(len + 1);
memcpy(line, buf, len);
line[len] = 0;
return line;
} }
static const char *copy_name(const char *buf) static const char *copy_name(const char *buf)
{ {
const char *eol = strchr(buf, '\n'); const char *cp;
const char *eoname = strstr(buf, " <"); for (cp = buf; *cp && *cp != '\n'; cp++) {
char *line; if (!strncmp(cp, " <", 2))
int len; return xmemdupz(buf, cp - buf);
if (!(eoname && eol && eoname < eol)) }
return ""; return "";
len = eoname - buf;
line = xmalloc(len + 1);
memcpy(line, buf, len);
line[len] = 0;
return line;
} }
static const char *copy_email(const char *buf) static const char *copy_email(const char *buf)
{ {
const char *email = strchr(buf, '<'); const char *email = strchr(buf, '<');
const char *eoemail = strchr(email, '>'); const char *eoemail = strchr(email, '>');
char *line;
int len;
if (!email || !eoemail) if (!email || !eoemail)
return ""; return "";
eoemail++; return xmemdupz(email, eoemail + 1 - email);
len = eoemail - email;
line = xmalloc(len + 1);
memcpy(line, email, len);
line[len] = 0;
return line;
} }
static void grab_date(const char *buf, struct atom_value *v, const char *atomname) static void grab_date(const char *buf, struct atom_value *v, const char *atomname)

View File

@ -441,8 +441,6 @@ static const char *clean_message_id(const char *msg_id)
{ {
char ch; char ch;
const char *a, *z, *m; const char *a, *z, *m;
char *n;
size_t len;
m = msg_id; m = msg_id;
while ((ch = *m) && (isspace(ch) || (ch == '<'))) while ((ch = *m) && (isspace(ch) || (ch == '<')))
@ -458,11 +456,7 @@ static const char *clean_message_id(const char *msg_id)
die("insane in-reply-to: %s", msg_id); die("insane in-reply-to: %s", msg_id);
if (++z == m) if (++z == m)
return a; return a;
len = z - a; return xmemdupz(a, z - a);
n = xmalloc(len + 1);
memcpy(n, a, len);
n[len] = 0;
return n;
} }
int cmd_format_patch(int argc, const char **argv, const char *prefix) int cmd_format_patch(int argc, const char **argv, const char *prefix)
@ -541,9 +535,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
endpos = strchr(committer, '>'); endpos = strchr(committer, '>');
if (!endpos) if (!endpos)
die("bogos committer info %s\n", committer); die("bogos committer info %s\n", committer);
add_signoff = xmalloc(endpos - committer + 2); add_signoff = xmemdupz(committer, endpos - committer + 1);
memcpy(add_signoff, committer, endpos - committer + 1);
add_signoff[endpos - committer + 1] = 0;
} }
else if (!strcmp(argv[i], "--attach")) { else if (!strcmp(argv[i], "--attach")) {
rev.mime_boundary = git_version_string; rev.mime_boundary = git_version_string;
@ -792,13 +784,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
sign = '-'; sign = '-';
if (verbose) { if (verbose) {
char *buf = NULL; struct strbuf buf;
unsigned long buflen = 0; strbuf_init(&buf, 0);
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, pretty_print_commit(CMIT_FMT_ONELINE, commit,
&buf, &buflen, 0, NULL, NULL, 0); &buf, 0, NULL, NULL, 0);
printf("%c %s %s\n", sign, printf("%c %s %s\n", sign,
sha1_to_hex(commit->object.sha1), buf); sha1_to_hex(commit->object.sha1), buf.buf);
free(buf); strbuf_release(&buf);
} }
else { else {
printf("%c %s\n", sign, printf("%c %s\n", sign,

View File

@ -84,8 +84,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
return; return;
fputs(tag, stdout); fputs(tag, stdout);
write_name_quoted("", 0, ent->name + offset, line_terminator, stdout); write_name_quoted(ent->name + offset, stdout, line_terminator);
putchar(line_terminator);
} }
static void show_other_files(struct dir_struct *dir) static void show_other_files(struct dir_struct *dir)
@ -208,21 +207,15 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
if (!show_stage) { if (!show_stage) {
fputs(tag, stdout); fputs(tag, stdout);
write_name_quoted("", 0, ce->name + offset, } else {
line_terminator, stdout);
putchar(line_terminator);
}
else {
printf("%s%06o %s %d\t", printf("%s%06o %s %d\t",
tag, tag,
ntohl(ce->ce_mode), ntohl(ce->ce_mode),
abbrev ? find_unique_abbrev(ce->sha1,abbrev) abbrev ? find_unique_abbrev(ce->sha1,abbrev)
: sha1_to_hex(ce->sha1), : sha1_to_hex(ce->sha1),
ce_stage(ce)); ce_stage(ce));
write_name_quoted("", 0, ce->name + offset,
line_terminator, stdout);
putchar(line_terminator);
} }
write_name_quoted(ce->name + offset, stdout, line_terminator);
} }
static void show_files(struct dir_struct *dir, const char *prefix) static void show_files(struct dir_struct *dir, const char *prefix)
@ -300,7 +293,6 @@ static void prune_cache(const char *prefix)
static const char *verify_pathspec(const char *prefix) static const char *verify_pathspec(const char *prefix)
{ {
const char **p, *n, *prev; const char **p, *n, *prev;
char *real_prefix;
unsigned long max; unsigned long max;
prev = NULL; prev = NULL;
@ -327,14 +319,8 @@ static const char *verify_pathspec(const char *prefix)
if (prefix_offset > max || memcmp(prev, prefix, prefix_offset)) if (prefix_offset > max || memcmp(prev, prefix, prefix_offset))
die("git-ls-files: cannot generate relative filenames containing '..'"); die("git-ls-files: cannot generate relative filenames containing '..'");
real_prefix = NULL;
prefix_len = max; prefix_len = max;
if (max) { return max ? xmemdupz(prev, max) : NULL;
real_prefix = xmalloc(max + 1);
memcpy(real_prefix, prev, max);
real_prefix[max] = 0;
}
return real_prefix;
} }
/* /*

View File

@ -112,10 +112,8 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
abbrev ? find_unique_abbrev(sha1, abbrev) abbrev ? find_unique_abbrev(sha1, abbrev)
: sha1_to_hex(sha1)); : sha1_to_hex(sha1));
} }
write_name_quoted(base + chomp_prefix, baselen - chomp_prefix, write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
pathname, pathname, stdout, line_termination);
line_termination, stdout);
putchar(line_termination);
return retval; return retval;
} }

View File

@ -22,10 +22,7 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
int length = strlen(result[i]); int length = strlen(result[i]);
if (length > 0 && result[i][length - 1] == '/') { if (length > 0 && result[i][length - 1] == '/') {
char *without_slash = xmalloc(length); result[i] = xmemdupz(result[i], length - 1);
memcpy(without_slash, result[i], length - 1);
without_slash[length - 1] = '\0';
result[i] = without_slash;
} }
if (base_name) { if (base_name) {
const char *last_slash = strrchr(result[i], '/'); const char *last_slash = strrchr(result[i], '/');

View File

@ -66,40 +66,15 @@ static int write_rr(struct path_list *rr, int out_fd)
return commit_lock_file(&write_lock); return commit_lock_file(&write_lock);
} }
struct buffer {
char *ptr;
int nr, alloc;
};
static void append_line(struct buffer *buffer, const char *line)
{
int len = strlen(line);
if (buffer->nr + len > buffer->alloc) {
buffer->alloc = alloc_nr(buffer->nr + len);
buffer->ptr = xrealloc(buffer->ptr, buffer->alloc);
}
memcpy(buffer->ptr + buffer->nr, line, len);
buffer->nr += len;
}
static void clear_buffer(struct buffer *buffer)
{
free(buffer->ptr);
buffer->ptr = NULL;
buffer->nr = buffer->alloc = 0;
}
static int handle_file(const char *path, static int handle_file(const char *path,
unsigned char *sha1, const char *output) unsigned char *sha1, const char *output)
{ {
SHA_CTX ctx; SHA_CTX ctx;
char buf[1024]; char buf[1024];
int hunk = 0, hunk_no = 0; int hunk = 0, hunk_no = 0;
struct buffer minus = { NULL, 0, 0 }, plus = { NULL, 0, 0 }; struct strbuf one, two;
struct buffer *one = &minus, *two = &plus;
FILE *f = fopen(path, "r"); FILE *f = fopen(path, "r");
FILE *out; FILE *out = NULL;
if (!f) if (!f)
return error("Could not open %s", path); return error("Could not open %s", path);
@ -110,51 +85,50 @@ static int handle_file(const char *path,
fclose(f); fclose(f);
return error("Could not write %s", output); return error("Could not write %s", output);
} }
} else }
out = NULL;
if (sha1) if (sha1)
SHA1_Init(&ctx); SHA1_Init(&ctx);
strbuf_init(&one, 0);
strbuf_init(&two, 0);
while (fgets(buf, sizeof(buf), f)) { while (fgets(buf, sizeof(buf), f)) {
if (!prefixcmp(buf, "<<<<<<< ")) if (!prefixcmp(buf, "<<<<<<< "))
hunk = 1; hunk = 1;
else if (!prefixcmp(buf, "=======")) else if (!prefixcmp(buf, "======="))
hunk = 2; hunk = 2;
else if (!prefixcmp(buf, ">>>>>>> ")) { else if (!prefixcmp(buf, ">>>>>>> ")) {
int one_is_longer = (one->nr > two->nr); int cmp = strbuf_cmp(&one, &two);
int common_len = one_is_longer ? two->nr : one->nr;
int cmp = memcmp(one->ptr, two->ptr, common_len);
hunk_no++; hunk_no++;
hunk = 0; hunk = 0;
if ((cmp > 0) || ((cmp == 0) && one_is_longer)) { if (cmp > 0) {
struct buffer *swap = one; strbuf_swap(&one, &two);
one = two;
two = swap;
} }
if (out) { if (out) {
fputs("<<<<<<<\n", out); fputs("<<<<<<<\n", out);
fwrite(one->ptr, one->nr, 1, out); fwrite(one.buf, one.len, 1, out);
fputs("=======\n", out); fputs("=======\n", out);
fwrite(two->ptr, two->nr, 1, out); fwrite(two.buf, two.len, 1, out);
fputs(">>>>>>>\n", out); fputs(">>>>>>>\n", out);
} }
if (sha1) { if (sha1) {
SHA1_Update(&ctx, one->ptr, one->nr); SHA1_Update(&ctx, one.buf ? one.buf : "",
SHA1_Update(&ctx, "\0", 1); one.len + 1);
SHA1_Update(&ctx, two->ptr, two->nr); SHA1_Update(&ctx, two.buf ? two.buf : "",
SHA1_Update(&ctx, "\0", 1); two.len + 1);
} }
clear_buffer(one); strbuf_reset(&one);
clear_buffer(two); strbuf_reset(&two);
} else if (hunk == 1) } else if (hunk == 1)
append_line(one, buf); strbuf_addstr(&one, buf);
else if (hunk == 2) else if (hunk == 2)
append_line(two, buf); strbuf_addstr(&two, buf);
else if (out) else if (out)
fputs(buf, out); fputs(buf, out);
} }
strbuf_release(&one);
strbuf_release(&two);
fclose(f); fclose(f);
if (out) if (out)

View File

@ -80,13 +80,12 @@ static void show_commit(struct commit *commit)
putchar('\n'); putchar('\n');
if (revs.verbose_header) { if (revs.verbose_header) {
char *buf = NULL; struct strbuf buf;
unsigned long buflen = 0; strbuf_init(&buf, 0);
pretty_print_commit(revs.commit_format, commit, ~0, pretty_print_commit(revs.commit_format, commit,
&buf, &buflen, &buf, revs.abbrev, NULL, NULL, revs.date_mode);
revs.abbrev, NULL, NULL, revs.date_mode); printf("%s%c", buf.buf, hdr_termination);
printf("%s%c", buf, hdr_termination); strbuf_release(&buf);
free(buf);
} }
maybe_flush_or_die(stdout, "stdout"); maybe_flush_or_die(stdout, "stdout");
if (commit->parents) { if (commit->parents) {

View File

@ -168,9 +168,7 @@ static void set_author_ident_env(const char *message)
char *line, *pend, *email, *timestamp; char *line, *pend, *email, *timestamp;
p += 7; p += 7;
line = xmalloc(eol + 1 - p); line = xmemdupz(p, eol - p);
memcpy(line, p, eol - p);
line[eol - p] = '\0';
email = strchr(line, '<'); email = strchr(line, '<');
if (!email) if (!email)
die ("Could not extract author email from %s", die ("Could not extract author email from %s",

View File

@ -39,10 +39,7 @@ static void insert_author_oneline(struct path_list *list,
while (authorlen > 0 && isspace(author[authorlen - 1])) while (authorlen > 0 && isspace(author[authorlen - 1]))
authorlen--; authorlen--;
buffer = xmalloc(authorlen + 1); buffer = xmemdupz(author, authorlen);
memcpy(buffer, author, authorlen);
buffer[authorlen] = '\0';
item = path_list_insert(buffer, list); item = path_list_insert(buffer, list);
if (item->util == NULL) if (item->util == NULL)
item->util = xcalloc(1, sizeof(struct path_list)); item->util = xcalloc(1, sizeof(struct path_list));
@ -66,13 +63,9 @@ static void insert_author_oneline(struct path_list *list,
oneline++; oneline++;
onelinelen--; onelinelen--;
} }
while (onelinelen > 0 && isspace(oneline[onelinelen - 1])) while (onelinelen > 0 && isspace(oneline[onelinelen - 1]))
onelinelen--; onelinelen--;
buffer = xmemdupz(oneline, onelinelen);
buffer = xmalloc(onelinelen + 1);
memcpy(buffer, oneline, onelinelen);
buffer[onelinelen] = '\0';
if (dot3) { if (dot3) {
int dot3len = strlen(dot3); int dot3len = strlen(dot3);

View File

@ -259,16 +259,15 @@ static void join_revs(struct commit_list **list_p,
static void show_one_commit(struct commit *commit, int no_name) static void show_one_commit(struct commit *commit, int no_name)
{ {
char *pretty = NULL; struct strbuf pretty;
const char *pretty_str = "(unavailable)"; const char *pretty_str = "(unavailable)";
unsigned long pretty_len = 0;
struct commit_name *name = commit->util; struct commit_name *name = commit->util;
strbuf_init(&pretty, 0);
if (commit->object.parsed) { if (commit->object.parsed) {
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0, pretty_print_commit(CMIT_FMT_ONELINE, commit,
&pretty, &pretty_len, &pretty, 0, NULL, NULL, 0);
0, NULL, NULL, 0); pretty_str = pretty.buf;
pretty_str = pretty;
} }
if (!prefixcmp(pretty_str, "[PATCH] ")) if (!prefixcmp(pretty_str, "[PATCH] "))
pretty_str += 8; pretty_str += 8;
@ -289,7 +288,7 @@ static void show_one_commit(struct commit *commit, int no_name)
find_unique_abbrev(commit->object.sha1, 7)); find_unique_abbrev(commit->object.sha1, 7));
} }
puts(pretty_str); puts(pretty_str);
free(pretty); strbuf_release(&pretty);
} }
static char *ref_name[MAX_REVS + 1]; static char *ref_name[MAX_REVS + 1];

View File

@ -8,17 +8,13 @@
*/ */
static size_t cleanup(char *line, size_t len) static size_t cleanup(char *line, size_t len)
{ {
if (len) {
if (line[len - 1] == '\n')
len--;
while (len) { while (len) {
unsigned char c = line[len - 1]; unsigned char c = line[len - 1];
if (!isspace(c)) if (!isspace(c))
break; break;
len--; len--;
} }
}
return len; return len;
} }
@ -34,66 +30,60 @@ static size_t cleanup(char *line, size_t len)
* If the input has only empty lines and spaces, * If the input has only empty lines and spaces,
* no output will be produced. * no output will be produced.
* *
* If last line has a newline at the end, it will be removed. * If last line does not have a newline at the end, one is added.
* *
* Enable skip_comments to skip every line starting with "#". * Enable skip_comments to skip every line starting with "#".
*/ */
size_t stripspace(char *buffer, size_t length, int skip_comments) void stripspace(struct strbuf *sb, int skip_comments)
{ {
int empties = -1; int empties = 0;
size_t i, j, len, newlen; size_t i, j, len, newlen;
char *eol; char *eol;
for (i = j = 0; i < length; i += len, j += newlen) { /* We may have to add a newline. */
eol = memchr(buffer + i, '\n', length - i); strbuf_grow(sb, 1);
len = eol ? eol - (buffer + i) + 1 : length - i;
if (skip_comments && len && buffer[i] == '#') { for (i = j = 0; i < sb->len; i += len, j += newlen) {
eol = memchr(sb->buf + i, '\n', sb->len - i);
len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
if (skip_comments && len && sb->buf[i] == '#') {
newlen = 0; newlen = 0;
continue; continue;
} }
newlen = cleanup(buffer + i, len); newlen = cleanup(sb->buf + i, len);
/* Not just an empty line? */ /* Not just an empty line? */
if (newlen) { if (newlen) {
if (empties != -1) if (empties > 0 && j > 0)
buffer[j++] = '\n'; sb->buf[j++] = '\n';
if (empties > 0)
buffer[j++] = '\n';
empties = 0; empties = 0;
memmove(buffer + j, buffer + i, newlen); memmove(sb->buf + j, sb->buf + i, newlen);
continue; sb->buf[newlen + j++] = '\n';
} } else {
if (empties < 0)
continue;
empties++; empties++;
} }
}
return j; strbuf_setlen(sb, j);
} }
int cmd_stripspace(int argc, const char **argv, const char *prefix) int cmd_stripspace(int argc, const char **argv, const char *prefix)
{ {
char *buffer; struct strbuf buf;
unsigned long size;
int strip_comments = 0; int strip_comments = 0;
if (argc > 1 && (!strcmp(argv[1], "-s") || if (argc > 1 && (!strcmp(argv[1], "-s") ||
!strcmp(argv[1], "--strip-comments"))) !strcmp(argv[1], "--strip-comments")))
strip_comments = 1; strip_comments = 1;
size = 1024; strbuf_init(&buf, 0);
buffer = xmalloc(size); if (strbuf_read(&buf, 0, 1024) < 0)
if (read_fd(0, &buffer, &size)) {
free(buffer);
die("could not read the input"); die("could not read the input");
}
size = stripspace(buffer, size, strip_comments); stripspace(&buf, strip_comments);
write_or_die(1, buffer, size);
if (size)
putc('\n', stdout);
free(buffer); write_or_die(1, buf.buf, buf.len);
strbuf_release(&buf);
return 0; return 0;
} }

View File

@ -17,12 +17,11 @@ static const char builtin_tag_usage[] =
static char signingkey[1000]; static char signingkey[1000];
static void launch_editor(const char *path, char **buffer, unsigned long *len) static void launch_editor(const char *path, struct strbuf *buffer)
{ {
const char *editor, *terminal; const char *editor, *terminal;
struct child_process child; struct child_process child;
const char *args[3]; const char *args[3];
int fd;
editor = getenv("GIT_EDITOR"); editor = getenv("GIT_EDITOR");
if (!editor && editor_program) if (!editor && editor_program)
@ -52,16 +51,10 @@ static void launch_editor(const char *path, char **buffer, unsigned long *len)
if (run_command(&child)) if (run_command(&child))
die("There was a problem with the editor %s.", editor); die("There was a problem with the editor %s.", editor);
fd = open(path, O_RDONLY); if (strbuf_read_file(buffer, path, 0) < 0)
if (fd < 0)
die("could not open '%s': %s", path, strerror(errno));
if (read_fd(fd, buffer, len)) {
free(*buffer);
die("could not read message file '%s': %s", die("could not read message file '%s': %s",
path, strerror(errno)); path, strerror(errno));
} }
close(fd);
}
struct tag_filter { struct tag_filter {
const char *pattern; const char *pattern;
@ -184,7 +177,7 @@ static int verify_tag(const char *name, const char *ref,
return 0; return 0;
} }
static ssize_t do_sign(char *buffer, size_t size, size_t max) static int do_sign(struct strbuf *buffer)
{ {
struct child_process gpg; struct child_process gpg;
const char *args[4]; const char *args[4];
@ -216,22 +209,22 @@ static ssize_t do_sign(char *buffer, size_t size, size_t max)
if (start_command(&gpg)) if (start_command(&gpg))
return error("could not run gpg."); return error("could not run gpg.");
if (write_in_full(gpg.in, buffer, size) != size) { if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
close(gpg.in); close(gpg.in);
finish_command(&gpg); finish_command(&gpg);
return error("gpg did not accept the tag data"); return error("gpg did not accept the tag data");
} }
close(gpg.in); close(gpg.in);
gpg.close_in = 0; gpg.close_in = 0;
len = read_in_full(gpg.out, buffer + size, max - size); len = strbuf_read(buffer, gpg.out, 1024);
if (finish_command(&gpg) || !len || len < 0) if (finish_command(&gpg) || !len || len < 0)
return error("gpg failed to sign the tag"); return error("gpg failed to sign the tag");
if (len == max - size) if (len < 0)
return error("could not read the entire signature from gpg."); return error("could not read the entire signature from gpg.");
return size + len; return 0;
} }
static const char tag_template[] = static const char tag_template[] =
@ -254,15 +247,13 @@ static int git_tag_config(const char *var, const char *value)
return git_default_config(var, value); return git_default_config(var, value);
} }
#define MAX_SIGNATURE_LENGTH 1024
/* message must be NULL or allocated, it will be reallocated and freed */
static void create_tag(const unsigned char *object, const char *tag, static void create_tag(const unsigned char *object, const char *tag,
char *message, int sign, unsigned char *result) struct strbuf *buf, int message, int sign,
unsigned char *result)
{ {
enum object_type type; enum object_type type;
char header_buf[1024], *buffer = NULL; char header_buf[1024];
int header_len, max_size; int header_len;
unsigned long size = 0;
type = sha1_object_info(object, NULL); type = sha1_object_info(object, NULL);
if (type <= OBJ_NONE) if (type <= OBJ_NONE)
@ -294,53 +285,37 @@ static void create_tag(const unsigned char *object, const char *tag,
write_or_die(fd, tag_template, strlen(tag_template)); write_or_die(fd, tag_template, strlen(tag_template));
close(fd); close(fd);
launch_editor(path, &buffer, &size); launch_editor(path, buf);
unlink(path); unlink(path);
free(path); free(path);
} }
else {
buffer = message;
size = strlen(message);
}
size = stripspace(buffer, size, 1); stripspace(buf, 1);
if (!message && !size) if (!message && !buf->len)
die("no tag message?"); die("no tag message?");
/* insert the header and add the '\n' if needed: */ strbuf_insert(buf, 0, header_buf, header_len);
max_size = header_len + size + (sign ? MAX_SIGNATURE_LENGTH : 0) + 1;
buffer = xrealloc(buffer, max_size);
if (size)
buffer[size++] = '\n';
memmove(buffer + header_len, buffer, size);
memcpy(buffer, header_buf, header_len);
size += header_len;
if (sign) { if (sign && do_sign(buf) < 0)
ssize_t r = do_sign(buffer, size, max_size);
if (r < 0)
die("unable to sign the tag"); die("unable to sign the tag");
size = r; if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
}
if (write_sha1_file(buffer, size, tag_type, result) < 0)
die("unable to write tag file"); die("unable to write tag file");
free(buffer);
} }
int cmd_tag(int argc, const char **argv, const char *prefix) int cmd_tag(int argc, const char **argv, const char *prefix)
{ {
struct strbuf buf;
unsigned char object[20], prev[20]; unsigned char object[20], prev[20];
int annotate = 0, sign = 0, force = 0, lines = 0; int annotate = 0, sign = 0, force = 0, lines = 0, message = 0;
char *message = NULL;
char ref[PATH_MAX]; char ref[PATH_MAX];
const char *object_ref, *tag; const char *object_ref, *tag;
int i; int i;
struct ref_lock *lock; struct ref_lock *lock;
git_config(git_tag_config); git_config(git_tag_config);
strbuf_init(&buf, 0);
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
const char *arg = argv[i]; const char *arg = argv[i];
@ -376,13 +351,11 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die("option -m needs an argument."); die("option -m needs an argument.");
if (message) if (message)
die("only one -F or -m option is allowed."); die("only one -F or -m option is allowed.");
message = xstrdup(argv[i]); strbuf_addstr(&buf, argv[i]);
message = 1;
continue; continue;
} }
if (!strcmp(arg, "-F")) { if (!strcmp(arg, "-F")) {
unsigned long len;
int fd;
annotate = 1; annotate = 1;
i++; i++;
if (i == argc) if (i == argc)
@ -390,20 +363,15 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (message) if (message)
die("only one -F or -m option is allowed."); die("only one -F or -m option is allowed.");
if (!strcmp(argv[i], "-")) if (!strcmp(argv[i], "-")) {
fd = 0; if (strbuf_read(&buf, 0, 1024) < 0)
else { die("cannot read %s", argv[i]);
fd = open(argv[i], O_RDONLY); } else {
if (fd < 0) if (strbuf_read_file(&buf, argv[i], 1024) < 0)
die("could not open '%s': %s", die("could not open or read '%s': %s",
argv[i], strerror(errno)); argv[i], strerror(errno));
} }
len = 1024; message = 1;
message = xmalloc(len);
if (read_fd(fd, &message, &len)) {
free(message);
die("cannot read %s", argv[i]);
}
continue; continue;
} }
if (!strcmp(arg, "-u")) { if (!strcmp(arg, "-u")) {
@ -451,7 +419,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die("tag '%s' already exists", tag); die("tag '%s' already exists", tag);
if (annotate) if (annotate)
create_tag(object, tag, message, sign, object); create_tag(object, tag, &buf, message, sign, object);
lock = lock_any_ref_for_update(ref, prev, 0); lock = lock_any_ref_for_update(ref, prev, 0);
if (!lock) if (!lock)
@ -459,5 +427,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (write_ref_sha1(lock, object, NULL) < 0) if (write_ref_sha1(lock, object, NULL) < 0)
die("%s: cannot update the ref", ref); die("%s: cannot update the ref", ref);
strbuf_release(&buf);
return 0; return 0;
} }

View File

@ -4,7 +4,6 @@
* Copyright (C) Linus Torvalds, 2005 * Copyright (C) Linus Torvalds, 2005
*/ */
#include "cache.h" #include "cache.h"
#include "strbuf.h"
#include "quote.h" #include "quote.h"
#include "cache-tree.h" #include "cache-tree.h"
#include "tree-walk.h" #include "tree-walk.h"
@ -296,8 +295,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
static void read_index_info(int line_termination) static void read_index_info(int line_termination)
{ {
struct strbuf buf; struct strbuf buf;
strbuf_init(&buf); struct strbuf uq;
while (1) {
strbuf_init(&buf, 0);
strbuf_init(&uq, 0);
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
char *ptr, *tab; char *ptr, *tab;
char *path_name; char *path_name;
unsigned char sha1[20]; unsigned char sha1[20];
@ -321,10 +323,6 @@ static void read_index_info(int line_termination)
* This format is to put higher order stages into the * This format is to put higher order stages into the
* index file and matches git-ls-files --stage output. * index file and matches git-ls-files --stage output.
*/ */
read_line(&buf, stdin, line_termination);
if (buf.eof)
break;
errno = 0; errno = 0;
ul = strtoul(buf.buf, &ptr, 8); ul = strtoul(buf.buf, &ptr, 8);
if (ptr == buf.buf || *ptr != ' ' if (ptr == buf.buf || *ptr != ' '
@ -349,15 +347,17 @@ static void read_index_info(int line_termination)
if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ') if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
goto bad_line; goto bad_line;
if (line_termination && ptr[0] == '"')
path_name = unquote_c_style(ptr, NULL);
else
path_name = ptr; path_name = ptr;
if (line_termination && path_name[0] == '"') {
strbuf_reset(&uq);
if (unquote_c_style(&uq, path_name, NULL)) {
die("git-update-index: bad quoting of path name");
}
path_name = uq.buf;
}
if (!verify_path(path_name)) { if (!verify_path(path_name)) {
fprintf(stderr, "Ignoring path %s\n", path_name); fprintf(stderr, "Ignoring path %s\n", path_name);
if (path_name != ptr)
free(path_name);
continue; continue;
} }
@ -377,13 +377,13 @@ static void read_index_info(int line_termination)
die("git-update-index: unable to update %s", die("git-update-index: unable to update %s",
path_name); path_name);
} }
if (path_name != ptr)
free(path_name);
continue; continue;
bad_line: bad_line:
die("malformed index info %s", buf.buf); die("malformed index info %s", buf.buf);
} }
strbuf_release(&buf);
strbuf_release(&uq);
} }
static const char update_index_usage[] = static const char update_index_usage[] =
@ -706,27 +706,27 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
free((char*)p); free((char*)p);
} }
if (read_from_stdin) { if (read_from_stdin) {
struct strbuf buf; struct strbuf buf, nbuf;
strbuf_init(&buf);
while (1) { strbuf_init(&buf, 0);
char *path_name; strbuf_init(&nbuf, 0);
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
const char *p; const char *p;
read_line(&buf, stdin, line_termination); if (line_termination && buf.buf[0] == '"') {
if (buf.eof) strbuf_reset(&nbuf);
break; if (unquote_c_style(&nbuf, buf.buf, NULL))
if (line_termination && buf.buf[0] == '"') die("line is badly quoted");
path_name = unquote_c_style(buf.buf, NULL); strbuf_swap(&buf, &nbuf);
else }
path_name = buf.buf; p = prefix_path(prefix, prefix_length, buf.buf);
p = prefix_path(prefix, prefix_length, path_name);
update_one(p, NULL, 0); update_one(p, NULL, 0);
if (set_executable_bit) if (set_executable_bit)
chmod_path(set_executable_bit, p); chmod_path(set_executable_bit, p);
if (p < path_name || p > path_name + strlen(path_name)) if (p < buf.buf || p > buf.buf + buf.len)
free((char *)p); free((char *)p);
if (path_name != buf.buf)
free(path_name);
} }
strbuf_release(&nbuf);
strbuf_release(&buf);
} }
finish: finish:

View File

@ -7,7 +7,6 @@ extern const char git_version_string[];
extern const char git_usage_string[]; extern const char git_usage_string[];
extern void help_unknown_cmd(const char *cmd); extern void help_unknown_cmd(const char *cmd);
extern size_t stripspace(char *buffer, size_t length, int skip_comments);
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix); extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
extern void prune_packed_objects(int); extern void prune_packed_objects(int);

View File

@ -235,8 +235,7 @@ static int update_one(struct cache_tree *it,
int missing_ok, int missing_ok,
int dryrun) int dryrun)
{ {
unsigned long size, offset; struct strbuf buffer;
char *buffer;
int i; int i;
if (0 <= it->entry_count && has_sha1_file(it->sha1)) if (0 <= it->entry_count && has_sha1_file(it->sha1))
@ -293,9 +292,7 @@ static int update_one(struct cache_tree *it,
/* /*
* Then write out the tree object for this level. * Then write out the tree object for this level.
*/ */
size = 8192; strbuf_init(&buffer, 8192);
buffer = xmalloc(size);
offset = 0;
for (i = 0; i < entries; i++) { for (i = 0; i < entries; i++) {
struct cache_entry *ce = cache[i]; struct cache_entry *ce = cache[i];
@ -332,15 +329,9 @@ static int update_one(struct cache_tree *it,
if (!ce->ce_mode) if (!ce->ce_mode)
continue; /* entry being removed */ continue; /* entry being removed */
if (size < offset + entlen + 100) { strbuf_grow(&buffer, entlen + 100);
size = alloc_nr(offset + entlen + 100); strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
buffer = xrealloc(buffer, size); strbuf_add(&buffer, sha1, 20);
}
offset += sprintf(buffer + offset,
"%o %.*s", mode, entlen, path + baselen);
buffer[offset++] = 0;
hashcpy((unsigned char*)buffer + offset, sha1);
offset += 20;
#if DEBUG #if DEBUG
fprintf(stderr, "cache-tree update-one %o %.*s\n", fprintf(stderr, "cache-tree update-one %o %.*s\n",
@ -349,10 +340,10 @@ static int update_one(struct cache_tree *it,
} }
if (dryrun) if (dryrun)
hash_sha1_file(buffer, offset, tree_type, it->sha1); hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
else else
write_sha1_file(buffer, offset, tree_type, it->sha1); write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
free(buffer); strbuf_release(&buffer);
it->entry_count = i; it->entry_count = i;
#if DEBUG #if DEBUG
fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
@ -378,12 +369,8 @@ int cache_tree_update(struct cache_tree *it,
return 0; return 0;
} }
static void *write_one(struct cache_tree *it, static void write_one(struct strbuf *buffer, struct cache_tree *it,
char *path, const char *path, int pathlen)
int pathlen,
char *buffer,
unsigned long *size,
unsigned long *offset)
{ {
int i; int i;
@ -393,13 +380,9 @@ static void *write_one(struct cache_tree *it,
* tree-sha1 (missing if invalid) * tree-sha1 (missing if invalid)
* subtree_nr "cache-tree" entries for subtrees. * subtree_nr "cache-tree" entries for subtrees.
*/ */
if (*size < *offset + pathlen + 100) { strbuf_grow(buffer, pathlen + 100);
*size = alloc_nr(*offset + pathlen + 100); strbuf_add(buffer, path, pathlen);
buffer = xrealloc(buffer, *size); strbuf_addf(buffer, "%c%d %d\n", 0, it->entry_count, it->subtree_nr);
}
*offset += sprintf(buffer + *offset, "%.*s%c%d %d\n",
pathlen, path, 0,
it->entry_count, it->subtree_nr);
#if DEBUG #if DEBUG
if (0 <= it->entry_count) if (0 <= it->entry_count)
@ -412,8 +395,7 @@ static void *write_one(struct cache_tree *it,
#endif #endif
if (0 <= it->entry_count) { if (0 <= it->entry_count) {
hashcpy((unsigned char*)buffer + *offset, it->sha1); strbuf_add(buffer, it->sha1, 20);
*offset += 20;
} }
for (i = 0; i < it->subtree_nr; i++) { for (i = 0; i < it->subtree_nr; i++) {
struct cache_tree_sub *down = it->down[i]; struct cache_tree_sub *down = it->down[i];
@ -423,21 +405,13 @@ static void *write_one(struct cache_tree *it,
prev->name, prev->namelen) <= 0) prev->name, prev->namelen) <= 0)
die("fatal - unsorted cache subtree"); die("fatal - unsorted cache subtree");
} }
buffer = write_one(down->cache_tree, down->name, down->namelen, write_one(buffer, down->cache_tree, down->name, down->namelen);
buffer, size, offset);
} }
return buffer;
} }
void *cache_tree_write(struct cache_tree *root, unsigned long *size_p) void cache_tree_write(struct strbuf *sb, struct cache_tree *root)
{ {
char path[PATH_MAX]; write_one(sb, root, "", 0);
unsigned long size = 8192;
char *buffer = xmalloc(size);
*size_p = 0;
path[0] = 0;
return write_one(root, path, 0, buffer, &size, size_p);
} }
static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)

View File

@ -22,7 +22,7 @@ void cache_tree_free(struct cache_tree **);
void cache_tree_invalidate_path(struct cache_tree *, const char *); void cache_tree_invalidate_path(struct cache_tree *, const char *);
struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *); struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *);
void *cache_tree_write(struct cache_tree *root, unsigned long *size_p); void cache_tree_write(struct strbuf *, struct cache_tree *root);
struct cache_tree *cache_tree_read(const char *buffer, unsigned long size); struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
int cache_tree_fully_valid(struct cache_tree *); int cache_tree_fully_valid(struct cache_tree *);

View File

@ -2,6 +2,7 @@
#define CACHE_H #define CACHE_H
#include "git-compat-util.h" #include "git-compat-util.h"
#include "strbuf.h"
#include SHA1_HEADER #include SHA1_HEADER
#include <zlib.h> #include <zlib.h>
@ -270,7 +271,6 @@ extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat
extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int); extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
extern int read_fd(int fd, char **return_buf, unsigned long *return_size);
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object); extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
@ -587,14 +587,13 @@ extern void *alloc_object_node(void);
extern void alloc_report(void); extern void alloc_report(void);
/* trace.c */ /* trace.c */
extern int nfasprintf(char **str, const char *fmt, ...);
extern int nfvasprintf(char **str, const char *fmt, va_list va);
extern void trace_printf(const char *format, ...); extern void trace_printf(const char *format, ...);
extern void trace_argv_printf(const char **argv, int count, const char *format, ...); extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
/* convert.c */ /* convert.c */
extern char *convert_to_git(const char *path, const char *src, unsigned long *sizep); /* returns 1 if *dst was used */
extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep); extern int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst);
extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
/* diff.c */ /* diff.c */
extern int diff_auto_refresh_index; extern int diff_auto_refresh_index;

View File

@ -650,10 +650,7 @@ static void dump_quoted_path(const char *prefix, const char *path,
const char *c_meta, const char *c_reset) const char *c_meta, const char *c_reset)
{ {
printf("%s%s", c_meta, prefix); printf("%s%s", c_meta, prefix);
if (quote_c_style(path, NULL, NULL, 0))
quote_c_style(path, NULL, stdout, 0); quote_c_style(path, NULL, stdout, 0);
else
printf("%s", path);
printf("%s\n", c_reset); printf("%s\n", c_reset);
} }
@ -900,16 +897,7 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
putchar(inter_name_termination); putchar(inter_name_termination);
} }
if (line_termination) { write_name_quoted(p->path, stdout, line_termination);
if (quote_c_style(p->path, NULL, NULL, 0))
quote_c_style(p->path, NULL, stdout, 0);
else
printf("%s", p->path);
putchar(line_termination);
}
else {
printf("%s%c", p->path, line_termination);
}
} }
void show_combined_diff(struct combine_diff_path *p, void show_combined_diff(struct combine_diff_path *p,

400
commit.c
View File

@ -458,11 +458,11 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
/* /*
* Generic support for pretty-printing the header * Generic support for pretty-printing the header
*/ */
static int get_one_line(const char *msg, unsigned long len) static int get_one_line(const char *msg)
{ {
int ret = 0; int ret = 0;
while (len--) { for (;;) {
char c = *msg++; char c = *msg++;
if (!c) if (!c)
break; break;
@ -485,31 +485,25 @@ static int is_rfc2047_special(char ch)
return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_')); return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
} }
static int add_rfc2047(char *buf, const char *line, int len, static void add_rfc2047(struct strbuf *sb, const char *line, int len,
const char *encoding) const char *encoding)
{ {
char *bp = buf; int i, last;
int i, needquote;
char q_encoding[128];
const char *q_encoding_fmt = "=?%s?q?";
for (i = needquote = 0; !needquote && i < len; i++) { for (i = 0; i < len; i++) {
int ch = line[i]; int ch = line[i];
if (non_ascii(ch)) if (non_ascii(ch))
needquote++; goto needquote;
if ((i + 1 < len) && if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
(ch == '=' && line[i+1] == '?')) goto needquote;
needquote++;
} }
if (!needquote) strbuf_add(sb, line, len);
return sprintf(buf, "%.*s", len, line); return;
i = snprintf(q_encoding, sizeof(q_encoding), q_encoding_fmt, encoding); needquote:
if (sizeof(q_encoding) < i) strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
die("Insanely long encoding name %s", encoding); strbuf_addf(sb, "=?%s?q?", encoding);
memcpy(bp, q_encoding, i); for (i = last = 0; i < len; i++) {
bp += i;
for (i = 0; i < len; i++) {
unsigned ch = line[i] & 0xFF; unsigned ch = line[i] & 0xFF;
/* /*
* We encode ' ' using '=20' even though rfc2047 * We encode ' ' using '=20' even though rfc2047
@ -518,40 +512,30 @@ static int add_rfc2047(char *buf, const char *line, int len,
* leave the underscore in place. * leave the underscore in place.
*/ */
if (is_rfc2047_special(ch) || ch == ' ') { if (is_rfc2047_special(ch) || ch == ' ') {
sprintf(bp, "=%02X", ch); strbuf_add(sb, line + last, i - last);
bp += 3; strbuf_addf(sb, "=%02X", ch);
last = i + 1;
} }
else
*bp++ = ch;
} }
memcpy(bp, "?=", 2); strbuf_add(sb, line + last, len - last);
bp += 2; strbuf_addstr(sb, "?=");
return bp - buf;
} }
static unsigned long bound_rfc2047(unsigned long len, const char *encoding) static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
{
/* 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 *line, enum date_mode dmode,
const char *encoding) const char *encoding)
{ {
char *date; char *date;
int namelen; int namelen;
unsigned long time; unsigned long time;
int tz, ret; int tz;
const char *filler = " "; const char *filler = " ";
if (fmt == CMIT_FMT_ONELINE) if (fmt == CMIT_FMT_ONELINE)
return 0; return;
date = strchr(line, '>'); date = strchr(line, '>');
if (!date) if (!date)
return 0; return;
namelen = ++date - line; namelen = ++date - line;
time = strtoul(date, &date, 10); time = strtoul(date, &date, 10);
tz = strtol(date, NULL, 10); tz = strtol(date, NULL, 10);
@ -560,42 +544,34 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
char *name_tail = strchr(line, '<'); char *name_tail = strchr(line, '<');
int display_name_length; int display_name_length;
if (!name_tail) if (!name_tail)
return 0; return;
while (line < name_tail && isspace(name_tail[-1])) while (line < name_tail && isspace(name_tail[-1]))
name_tail--; name_tail--;
display_name_length = name_tail - line; display_name_length = name_tail - line;
filler = ""; filler = "";
strcpy(buf, "From: "); strbuf_addstr(sb, "From: ");
ret = strlen(buf); add_rfc2047(sb, line, display_name_length, encoding);
ret += add_rfc2047(buf + ret, line, display_name_length, strbuf_add(sb, name_tail, namelen - display_name_length);
encoding); strbuf_addch(sb, '\n');
memcpy(buf + ret, name_tail, namelen - display_name_length); } else {
ret += namelen - display_name_length; strbuf_addf(sb, "%s: %.*s%.*s\n", what,
buf[ret++] = '\n';
}
else {
ret = sprintf(buf, "%s: %.*s%.*s\n", what,
(fmt == CMIT_FMT_FULLER) ? 4 : 0, (fmt == CMIT_FMT_FULLER) ? 4 : 0,
filler, namelen, line); filler, namelen, line);
} }
switch (fmt) { switch (fmt) {
case CMIT_FMT_MEDIUM: case CMIT_FMT_MEDIUM:
ret += sprintf(buf + ret, "Date: %s\n", strbuf_addf(sb, "Date: %s\n", show_date(time, tz, dmode));
show_date(time, tz, dmode));
break; break;
case CMIT_FMT_EMAIL: case CMIT_FMT_EMAIL:
ret += sprintf(buf + ret, "Date: %s\n", strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
show_date(time, tz, DATE_RFC2822));
break; break;
case CMIT_FMT_FULLER: case CMIT_FMT_FULLER:
ret += sprintf(buf + ret, "%sDate: %s\n", what, strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
show_date(time, tz, dmode));
break; break;
default: default:
/* notin' */ /* notin' */
break; break;
} }
return ret;
} }
static int is_empty_line(const char *line, int *len_p) static int is_empty_line(const char *line, int *len_p)
@ -607,16 +583,16 @@ static int is_empty_line(const char *line, int *len_p)
return !len; return !len;
} }
static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *commit, int abbrev) static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
const struct commit *commit, int abbrev)
{ {
struct commit_list *parent = commit->parents; struct commit_list *parent = commit->parents;
int offset;
if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) || if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
!parent || !parent->next) !parent || !parent->next)
return 0; return;
offset = sprintf(buf, "Merge:"); strbuf_addstr(sb, "Merge:");
while (parent) { while (parent) {
struct commit *p = parent->item; struct commit *p = parent->item;
@ -629,10 +605,9 @@ static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *com
dots = (abbrev && strlen(hex) != 40) ? "..." : ""; dots = (abbrev && strlen(hex) != 40) ? "..." : "";
parent = parent->next; parent = parent->next;
offset += sprintf(buf + offset, " %s%s", hex, dots); strbuf_addf(sb, " %s%s", hex, dots);
} }
buf[offset++] = '\n'; strbuf_addch(sb, '\n');
return offset;
} }
static char *get_header(const struct commit *commit, const char *key) static char *get_header(const struct commit *commit, const char *key)
@ -653,11 +628,7 @@ static char *get_header(const struct commit *commit, const char *key)
if (eol - line > key_len && if (eol - line > key_len &&
!strncmp(line, key, key_len) && !strncmp(line, key, key_len) &&
line[key_len] == ' ') { line[key_len] == ' ') {
int len = eol - line - key_len; return xmemdupz(line + key_len + 1, eol - line - key_len - 1);
char *ret = xmalloc(len);
memcpy(ret, line + key_len + 1, len - 1);
ret[len - 1] = '\0';
return ret;
} }
line = next; line = next;
} }
@ -665,47 +636,34 @@ static char *get_header(const struct commit *commit, const char *key)
static char *replace_encoding_header(char *buf, const char *encoding) static char *replace_encoding_header(char *buf, const char *encoding)
{ {
char *encoding_header = strstr(buf, "\nencoding "); struct strbuf tmp;
char *header_end = strstr(buf, "\n\n"); size_t start, len;
char *end_of_encoding_header; char *cp = buf;
int encoding_header_pos;
int encoding_header_len;
int new_len;
int need_len;
int buflen = strlen(buf) + 1;
if (!header_end) /* guess if there is an encoding header before a \n\n */
header_end = buf + buflen; while (strncmp(cp, "encoding ", strlen("encoding "))) {
if (!encoding_header || encoding_header >= header_end) cp = strchr(cp, '\n');
if (!cp || *++cp == '\n')
return buf; return buf;
encoding_header++; }
end_of_encoding_header = strchr(encoding_header, '\n'); start = cp - buf;
if (!end_of_encoding_header) cp = strchr(cp, '\n');
if (!cp)
return buf; /* should not happen but be defensive */ return buf; /* should not happen but be defensive */
end_of_encoding_header++; len = cp + 1 - (buf + start);
encoding_header_len = end_of_encoding_header - encoding_header;
encoding_header_pos = encoding_header - buf;
strbuf_init(&tmp, 0);
strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
if (is_encoding_utf8(encoding)) { if (is_encoding_utf8(encoding)) {
/* we have re-coded to UTF-8; drop the header */ /* we have re-coded to UTF-8; drop the header */
memmove(encoding_header, end_of_encoding_header, strbuf_remove(&tmp, start, len);
buflen - (encoding_header_pos + encoding_header_len)); } else {
return buf; /* just replaces XXXX in 'encoding XXXX\n' */
strbuf_splice(&tmp, start + strlen("encoding "),
len - strlen("encoding \n"),
encoding, strlen(encoding));
} }
new_len = strlen(encoding); return strbuf_detach(&tmp, NULL);
need_len = new_len + strlen("encoding \n");
if (encoding_header_len < need_len) {
buf = xrealloc(buf, buflen + (need_len - encoding_header_len));
encoding_header = buf + encoding_header_pos;
end_of_encoding_header = encoding_header + encoding_header_len;
}
memmove(end_of_encoding_header + (need_len - encoding_header_len),
end_of_encoding_header,
buflen - (encoding_header_pos + encoding_header_len));
memcpy(encoding_header + 9, encoding, strlen(encoding));
encoding_header[9 + new_len] = '\n';
return buf;
} }
static char *logmsg_reencode(const struct commit *commit, static char *logmsg_reencode(const struct commit *commit,
@ -747,7 +705,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
start = end + 1; start = end + 1;
while (end > 0 && isspace(msg[end - 1])) while (end > 0 && isspace(msg[end - 1]))
end--; end--;
table[0].value = xstrndup(msg, end); table[0].value = xmemdupz(msg, end);
if (start >= len) if (start >= len)
return; return;
@ -759,7 +717,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
if (end >= len) if (end >= len)
return; return;
table[1].value = xstrndup(msg + start, end - start); table[1].value = xmemdupz(msg + start, end - start);
/* parse date */ /* parse date */
for (start = end + 1; start < len && isspace(msg[start]); start++) for (start = end + 1; start < len && isspace(msg[start]); start++)
@ -770,7 +728,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
if (msg + start == ep) if (msg + start == ep)
return; return;
table[5].value = xstrndup(msg + start, ep - (msg + start)); table[5].value = xmemdupz(msg + start, ep - (msg + start));
/* parse tz */ /* parse tz */
for (start = ep - msg + 1; start < len && isspace(msg[start]); start++) for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
@ -787,8 +745,8 @@ static void fill_person(struct interp *table, const char *msg, int len)
interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601)); interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
} }
long format_commit_message(const struct commit *commit, const void *format, void format_commit_message(const struct commit *commit,
char **buf_p, unsigned long *space_p) const void *format, struct strbuf *sb)
{ {
struct interp table[] = { struct interp table[] = {
{ "%H" }, /* commit hash */ { "%H" }, /* commit hash */
@ -841,6 +799,7 @@ long format_commit_message(const struct commit *commit, const void *format,
}; };
struct commit_list *p; struct commit_list *p;
char parents[1024]; char parents[1024];
unsigned long len;
int i; int i;
enum { HEADER, SUBJECT, BODY } state; enum { HEADER, SUBJECT, BODY } state;
const char *msg = commit->buffer; const char *msg = commit->buffer;
@ -896,7 +855,7 @@ long format_commit_message(const struct commit *commit, const void *format,
; /* do nothing */ ; /* do nothing */
if (state == SUBJECT) { if (state == SUBJECT) {
table[ISUBJECT].value = xstrndup(msg + i, eol - i); table[ISUBJECT].value = xmemdupz(msg + i, eol - i);
i = eol; i = eol;
} }
if (i == eol) { if (i == eol) {
@ -912,7 +871,7 @@ long format_commit_message(const struct commit *commit, const void *format,
msg + i + 10, eol - i - 10); msg + i + 10, eol - i - 10);
else if (!prefixcmp(msg + i, "encoding ")) else if (!prefixcmp(msg + i, "encoding "))
table[IENCODING].value = table[IENCODING].value =
xstrndup(msg + i + 9, eol - i - 9); xmemdupz(msg + i + 9, eol - i - 9);
i = eol; i = eol;
} }
if (msg[i]) if (msg[i])
@ -921,21 +880,15 @@ long format_commit_message(const struct commit *commit, const void *format,
if (!table[i].value) if (!table[i].value)
interp_set_entry(table, i, "<unknown>"); interp_set_entry(table, i, "<unknown>");
do { len = interpolate(sb->buf + sb->len, strbuf_avail(sb),
char *buf = *buf_p; format, table, ARRAY_SIZE(table));
unsigned long space = *space_p; if (len > strbuf_avail(sb)) {
strbuf_grow(sb, len);
space = interpolate(buf, space, format, interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,
table, ARRAY_SIZE(table)); format, table, ARRAY_SIZE(table));
if (!space) }
break; strbuf_setlen(sb, sb->len + len);
buf = xrealloc(buf, space);
*buf_p = buf;
*space_p = space;
} while (1);
interp_clear_table(table, ARRAY_SIZE(table)); interp_clear_table(table, ARRAY_SIZE(table));
return strlen(*buf_p);
} }
static void pp_header(enum cmit_fmt fmt, static void pp_header(enum cmit_fmt fmt,
@ -944,34 +897,24 @@ static void pp_header(enum cmit_fmt fmt,
const char *encoding, const char *encoding,
const struct commit *commit, const struct commit *commit,
const char **msg_p, const char **msg_p,
unsigned long *len_p, struct strbuf *sb)
unsigned long *ofs_p,
char **buf_p,
unsigned long *space_p)
{ {
int parents_shown = 0; int parents_shown = 0;
for (;;) { for (;;) {
const char *line = *msg_p; const char *line = *msg_p;
char *dst; int linelen = get_one_line(*msg_p);
int linelen = get_one_line(*msg_p, *len_p);
unsigned long len;
if (!linelen) if (!linelen)
return; return;
*msg_p += linelen; *msg_p += linelen;
*len_p -= linelen;
if (linelen == 1) if (linelen == 1)
/* End of header */ /* End of header */
return; return;
ALLOC_GROW(*buf_p, linelen + *ofs_p + 20, *space_p);
dst = *buf_p + *ofs_p;
if (fmt == CMIT_FMT_RAW) { if (fmt == CMIT_FMT_RAW) {
memcpy(dst, line, linelen); strbuf_add(sb, line, linelen);
*ofs_p += linelen;
continue; continue;
} }
@ -989,10 +932,8 @@ static void pp_header(enum cmit_fmt fmt,
parent = parent->next, num++) parent = parent->next, num++)
; ;
/* with enough slop */ /* with enough slop */
num = *ofs_p + num * 50 + 20; strbuf_grow(sb, num * 50 + 20);
ALLOC_GROW(*buf_p, num, *space_p); add_merge_info(fmt, sb, commit, abbrev);
dst = *buf_p + *ofs_p;
*ofs_p += add_merge_info(fmt, dst, commit, abbrev);
parents_shown = 1; parents_shown = 1;
} }
@ -1002,129 +943,82 @@ static void pp_header(enum cmit_fmt fmt,
* FULLER shows both authors and dates. * FULLER shows both authors and dates.
*/ */
if (!memcmp(line, "author ", 7)) { if (!memcmp(line, "author ", 7)) {
len = linelen; strbuf_grow(sb, linelen + 80);
if (fmt == CMIT_FMT_EMAIL) add_user_info("Author", fmt, sb, line + 7, dmode, encoding);
len = bound_rfc2047(linelen, encoding);
ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);
dst = *buf_p + *ofs_p;
*ofs_p += add_user_info("Author", fmt, dst,
line + 7, dmode, encoding);
} }
if (!memcmp(line, "committer ", 10) && if (!memcmp(line, "committer ", 10) &&
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) { (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
len = linelen; strbuf_grow(sb, linelen + 80);
if (fmt == CMIT_FMT_EMAIL) add_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
len = bound_rfc2047(linelen, encoding);
ALLOC_GROW(*buf_p, *ofs_p + len + 80, *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, static void pp_title_line(enum cmit_fmt fmt,
const char **msg_p, const char **msg_p,
unsigned long *len_p, struct strbuf *sb,
unsigned long *ofs_p,
char **buf_p,
unsigned long *space_p,
int indent,
const char *subject, const char *subject,
const char *after_subject, const char *after_subject,
const char *encoding, const char *encoding,
int plain_non_ascii) int plain_non_ascii)
{ {
char *title; struct strbuf title;
unsigned long title_alloc, title_len;
unsigned long len; strbuf_init(&title, 80);
title_len = 0;
title_alloc = 80;
title = xmalloc(title_alloc);
for (;;) { for (;;) {
const char *line = *msg_p; const char *line = *msg_p;
int linelen = get_one_line(line, *len_p); int linelen = get_one_line(line);
*msg_p += linelen;
*len_p -= linelen;
*msg_p += linelen;
if (!linelen || is_empty_line(line, &linelen)) if (!linelen || is_empty_line(line, &linelen))
break; break;
if (title_alloc <= title_len + linelen + 2) { strbuf_grow(&title, linelen + 2);
title_alloc = title_len + linelen + 80; if (title.len) {
title = xrealloc(title, title_alloc);
}
len = 0;
if (title_len) {
if (fmt == CMIT_FMT_EMAIL) { if (fmt == CMIT_FMT_EMAIL) {
len++; strbuf_addch(&title, '\n');
title[title_len++] = '\n';
} }
len++; strbuf_addch(&title, ' ');
title[title_len++] = ' ';
} }
memcpy(title + title_len, line, linelen); strbuf_add(&title, line, linelen);
title_len += linelen;
} }
/* Enough slop for the MIME header and rfc2047 */ strbuf_grow(sb, title.len + 1024);
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) { if (subject) {
len = strlen(subject); strbuf_addstr(sb, subject);
memcpy(*buf_p + *ofs_p, subject, len); add_rfc2047(sb, title.buf, title.len, encoding);
*ofs_p += len;
*ofs_p += add_rfc2047(*buf_p + *ofs_p,
title, title_len, encoding);
} else { } else {
memcpy(*buf_p + *ofs_p, title, title_len); strbuf_addbuf(sb, &title);
*ofs_p += title_len;
} }
(*buf_p)[(*ofs_p)++] = '\n'; strbuf_addch(sb, '\n');
if (plain_non_ascii) { if (plain_non_ascii) {
const char *header_fmt = const char *header_fmt =
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=%s\n" "Content-Type: text/plain; charset=%s\n"
"Content-Transfer-Encoding: 8bit\n"; "Content-Transfer-Encoding: 8bit\n";
*ofs_p += snprintf(*buf_p + *ofs_p, strbuf_addf(sb, header_fmt, encoding);
*space_p - *ofs_p,
header_fmt, encoding);
} }
if (after_subject) { if (after_subject) {
len = strlen(after_subject); strbuf_addstr(sb, after_subject);
memcpy(*buf_p + *ofs_p, after_subject, len);
*ofs_p += len;
} }
free(title);
if (fmt == CMIT_FMT_EMAIL) { if (fmt == CMIT_FMT_EMAIL) {
ALLOC_GROW(*buf_p, *ofs_p + 20, *space_p); strbuf_addch(sb, '\n');
(*buf_p)[(*ofs_p)++] = '\n';
} }
strbuf_release(&title);
} }
static void pp_remainder(enum cmit_fmt fmt, static void pp_remainder(enum cmit_fmt fmt,
const char **msg_p, const char **msg_p,
unsigned long *len_p, struct strbuf *sb,
unsigned long *ofs_p,
char **buf_p,
unsigned long *space_p,
int indent) int indent)
{ {
int first = 1; int first = 1;
for (;;) { for (;;) {
const char *line = *msg_p; const char *line = *msg_p;
int linelen = get_one_line(line, *len_p); int linelen = get_one_line(line);
*msg_p += linelen; *msg_p += linelen;
*len_p -= linelen;
if (!linelen) if (!linelen)
break; break;
@ -1137,36 +1031,32 @@ static void pp_remainder(enum cmit_fmt fmt,
} }
first = 0; first = 0;
ALLOC_GROW(*buf_p, *ofs_p + linelen + indent + 20, *space_p); strbuf_grow(sb, linelen + indent + 20);
if (indent) { if (indent) {
memset(*buf_p + *ofs_p, ' ', indent); memset(sb->buf + sb->len, ' ', indent);
*ofs_p += indent; strbuf_setlen(sb, sb->len + indent);
} }
memcpy(*buf_p + *ofs_p, line, linelen); strbuf_add(sb, line, linelen);
*ofs_p += linelen; strbuf_addch(sb, '\n');
(*buf_p)[(*ofs_p)++] = '\n';
} }
} }
unsigned long pretty_print_commit(enum cmit_fmt fmt, void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
const struct commit *commit, struct strbuf *sb, int abbrev,
unsigned long len, const char *subject, const char *after_subject,
char **buf_p, unsigned long *space_p,
int abbrev, const char *subject,
const char *after_subject,
enum date_mode dmode) enum date_mode dmode)
{ {
unsigned long offset = 0;
unsigned long beginning_of_body; unsigned long beginning_of_body;
int indent = 4; int indent = 4;
const char *msg = commit->buffer; const char *msg = commit->buffer;
int plain_non_ascii = 0; int plain_non_ascii = 0;
char *reencoded; char *reencoded;
const char *encoding; const char *encoding;
char *buf;
if (fmt == CMIT_FMT_USERFORMAT) if (fmt == CMIT_FMT_USERFORMAT) {
return format_commit_message(commit, user_format, buf_p, space_p); format_commit_message(commit, user_format, sb);
return;
}
encoding = (git_log_output_encoding encoding = (git_log_output_encoding
? git_log_output_encoding ? git_log_output_encoding
@ -1176,7 +1066,6 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
reencoded = logmsg_reencode(commit, encoding); reencoded = logmsg_reencode(commit, encoding);
if (reencoded) { if (reencoded) {
msg = reencoded; msg = reencoded;
len = strlen(reencoded);
} }
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
@ -1191,14 +1080,13 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
if (fmt == CMIT_FMT_EMAIL && !after_subject) { if (fmt == CMIT_FMT_EMAIL && !after_subject) {
int i, ch, in_body; int i, ch, in_body;
for (in_body = i = 0; (ch = msg[i]) && i < len; i++) { for (in_body = i = 0; (ch = msg[i]); i++) {
if (!in_body) { if (!in_body) {
/* author could be non 7-bit ASCII but /* author could be non 7-bit ASCII but
* the log may be so; skip over the * the log may be so; skip over the
* header part first. * header part first.
*/ */
if (ch == '\n' && if (ch == '\n' && msg[i+1] == '\n')
i + 1 < len && msg[i+1] == '\n')
in_body = 1; in_body = 1;
} }
else if (non_ascii(ch)) { else if (non_ascii(ch)) {
@ -1208,59 +1096,44 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
} }
} }
pp_header(fmt, abbrev, dmode, encoding, pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
commit, &msg, &len,
&offset, buf_p, space_p);
if (fmt != CMIT_FMT_ONELINE && !subject) { if (fmt != CMIT_FMT_ONELINE && !subject) {
ALLOC_GROW(*buf_p, offset + 20, *space_p); strbuf_addch(sb, '\n');
(*buf_p)[offset++] = '\n';
} }
/* Skip excess blank lines at the beginning of body, if any... */ /* Skip excess blank lines at the beginning of body, if any... */
for (;;) { for (;;) {
int linelen = get_one_line(msg, len); int linelen = get_one_line(msg);
int ll = linelen; int ll = linelen;
if (!linelen) if (!linelen)
break; break;
if (!is_empty_line(msg, &ll)) if (!is_empty_line(msg, &ll))
break; break;
msg += linelen; msg += linelen;
len -= linelen;
} }
/* These formats treat the title line specially. */ /* These formats treat the title line specially. */
if (fmt == CMIT_FMT_ONELINE if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
|| fmt == CMIT_FMT_EMAIL) pp_title_line(fmt, &msg, sb, subject,
pp_title_line(fmt, &msg, &len, &offset, after_subject, encoding, plain_non_ascii);
buf_p, space_p, indent,
subject, after_subject, encoding,
plain_non_ascii);
beginning_of_body = offset; beginning_of_body = sb->len;
if (fmt != CMIT_FMT_ONELINE) if (fmt != CMIT_FMT_ONELINE)
pp_remainder(fmt, &msg, &len, &offset, pp_remainder(fmt, &msg, sb, indent);
buf_p, space_p, indent); strbuf_rtrim(sb);
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 */ /* Make sure there is an EOLN for the non-oneline case */
if (fmt != CMIT_FMT_ONELINE) if (fmt != CMIT_FMT_ONELINE)
buf[offset++] = '\n'; strbuf_addch(sb, '\n');
/* /*
* The caller may append additional body text in e-mail * The caller may append additional body text in e-mail
* format. Make sure we did not strip the blank line * format. Make sure we did not strip the blank line
* between the header and the body. * between the header and the body.
*/ */
if (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body) if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
buf[offset++] = '\n'; strbuf_addch(sb, '\n');
buf[offset] = '\0';
free(reencoded); free(reencoded);
return offset;
} }
struct commit *pop_commit(struct commit_list **stack) struct commit *pop_commit(struct commit_list **stack)
@ -1483,8 +1356,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)
} }
struct commit_list *get_merge_bases(struct commit *one, struct commit_list *get_merge_bases(struct commit *one,
struct commit *two, struct commit *two, int cleanup)
int cleanup)
{ {
struct commit_list *list; struct commit_list *list;
struct commit **rslt; struct commit **rslt;

View File

@ -3,6 +3,7 @@
#include "object.h" #include "object.h"
#include "tree.h" #include "tree.h"
#include "strbuf.h"
#include "decorate.h" #include "decorate.h"
struct commit_list { struct commit_list {
@ -61,8 +62,12 @@ enum cmit_fmt {
}; };
extern enum cmit_fmt get_commit_format(const char *arg); extern enum cmit_fmt get_commit_format(const char *arg);
extern long format_commit_message(const struct commit *commit, const void *template, char **buf_p, unsigned long *space_p); extern void format_commit_message(const struct commit *commit,
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); const void *format, struct strbuf *sb);
extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
struct strbuf *,
int abbrev, const char *subject,
const char *after_subject, enum date_mode);
/** Removes the first commit from a list sorted by date, and adds all /** Removes the first commit from a list sorted by date, and adds all
* of its parents. * of its parents.

View File

@ -393,9 +393,7 @@ static int git_proxy_command_options(const char *var, const char *value)
if (matchlen == 4 && if (matchlen == 4 &&
!memcmp(value, "none", 4)) !memcmp(value, "none", 4))
matchlen = 0; matchlen = 0;
git_proxy_command = xmalloc(matchlen + 1); git_proxy_command = xmemdupz(value, matchlen);
memcpy(git_proxy_command, value, matchlen);
git_proxy_command[matchlen] = 0;
} }
return 0; return 0;
} }
@ -579,16 +577,13 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
if (pid < 0) if (pid < 0)
die("unable to fork"); die("unable to fork");
if (!pid) { if (!pid) {
char command[MAX_CMD_LEN]; struct strbuf cmd;
char *posn = command;
int size = MAX_CMD_LEN;
int of = 0;
of |= add_to_string(&posn, &size, prog, 0); strbuf_init(&cmd, MAX_CMD_LEN);
of |= add_to_string(&posn, &size, " ", 0); strbuf_addstr(&cmd, prog);
of |= add_to_string(&posn, &size, path, 1); strbuf_addch(&cmd, ' ');
sq_quote_buf(&cmd, path);
if (of) if (cmd.len >= MAX_CMD_LEN)
die("command line too long"); die("command line too long");
dup2(pipefd[1][0], 0); dup2(pipefd[1][0], 0);
@ -608,10 +603,10 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
ssh_basename++; ssh_basename++;
if (!port) if (!port)
execlp(ssh, ssh_basename, host, command, NULL); execlp(ssh, ssh_basename, host, cmd.buf, NULL);
else else
execlp(ssh, ssh_basename, "-p", port, host, execlp(ssh, ssh_basename, "-p", port, host,
command, NULL); cmd.buf, NULL);
} }
else { else {
unsetenv(ALTERNATE_DB_ENVIRONMENT); unsetenv(ALTERNATE_DB_ENVIRONMENT);
@ -620,7 +615,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
unsetenv(GIT_WORK_TREE_ENVIRONMENT); unsetenv(GIT_WORK_TREE_ENVIRONMENT);
unsetenv(GRAFT_ENVIRONMENT); unsetenv(GRAFT_ENVIRONMENT);
unsetenv(INDEX_ENVIRONMENT); unsetenv(INDEX_ENVIRONMENT);
execlp("sh", "sh", "-c", command, NULL); execlp("sh", "sh", "-c", cmd.buf, NULL);
} }
die("exec failed"); die("exec failed");
} }

414
convert.c
View File

@ -80,24 +80,19 @@ static int is_binary(unsigned long size, struct text_stat *stats)
return 0; return 0;
} }
static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep, int action) static int crlf_to_git(const char *path, const char *src, size_t len,
struct strbuf *buf, int action)
{ {
char *buffer, *dst;
unsigned long size, nsize;
struct text_stat stats; struct text_stat stats;
char *dst;
if ((action == CRLF_BINARY) || !auto_crlf) if ((action == CRLF_BINARY) || !auto_crlf || !len)
return NULL; return 0;
size = *sizep;
if (!size)
return NULL;
gather_stats(src, size, &stats);
gather_stats(src, len, &stats);
/* No CR? Nothing to convert, regardless. */ /* No CR? Nothing to convert, regardless. */
if (!stats.cr) if (!stats.cr)
return NULL; return 0;
if (action == CRLF_GUESS) { if (action == CRLF_GUESS) {
/* /*
@ -106,24 +101,17 @@ static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep
* stuff? * stuff?
*/ */
if (stats.cr != stats.crlf) if (stats.cr != stats.crlf)
return NULL; return 0;
/* /*
* And add some heuristics for binary vs text, of course... * And add some heuristics for binary vs text, of course...
*/ */
if (is_binary(size, &stats)) if (is_binary(len, &stats))
return NULL; return 0;
} }
/* strbuf_grow(buf, len);
* Ok, allocate a new buffer, fill it in, and return it dst = buf->buf;
* to let the caller know that we switched buffers.
*/
nsize = size - stats.crlf;
buffer = xmalloc(nsize);
*sizep = nsize;
dst = buffer;
if (action == CRLF_GUESS) { if (action == CRLF_GUESS) {
/* /*
* If we guessed, we already know we rejected a file with * If we guessed, we already know we rejected a file with
@ -134,71 +122,72 @@ static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep
unsigned char c = *src++; unsigned char c = *src++;
if (c != '\r') if (c != '\r')
*dst++ = c; *dst++ = c;
} while (--size); } while (--len);
} else { } else {
do { do {
unsigned char c = *src++; unsigned char c = *src++;
if (! (c == '\r' && (1 < size && *src == '\n'))) if (! (c == '\r' && (1 < len && *src == '\n')))
*dst++ = c; *dst++ = c;
} while (--size); } while (--len);
}
strbuf_setlen(buf, dst - buf->buf);
return 1;
} }
return buffer; static int crlf_to_worktree(const char *path, const char *src, size_t len,
} struct strbuf *buf, int action)
static char *crlf_to_worktree(const char *path, const char *src, unsigned long *sizep, int action)
{ {
char *buffer, *dst; char *to_free = NULL;
unsigned long size, nsize;
struct text_stat stats; struct text_stat stats;
unsigned char last;
if ((action == CRLF_BINARY) || (action == CRLF_INPUT) || if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
auto_crlf <= 0) auto_crlf <= 0)
return NULL; return 0;
size = *sizep; if (!len)
if (!size) return 0;
return NULL;
gather_stats(src, size, &stats); gather_stats(src, len, &stats);
/* No LF? Nothing to convert, regardless. */ /* No LF? Nothing to convert, regardless. */
if (!stats.lf) if (!stats.lf)
return NULL; return 0;
/* Was it already in CRLF format? */ /* Was it already in CRLF format? */
if (stats.lf == stats.crlf) if (stats.lf == stats.crlf)
return NULL; return 0;
if (action == CRLF_GUESS) { if (action == CRLF_GUESS) {
/* If we have any bare CR characters, we're not going to touch it */ /* If we have any bare CR characters, we're not going to touch it */
if (stats.cr != stats.crlf) if (stats.cr != stats.crlf)
return NULL; return 0;
if (is_binary(size, &stats)) if (is_binary(len, &stats))
return NULL; return 0;
} }
/* /* are we "faking" in place editing ? */
* Ok, allocate a new buffer, fill it in, and return it if (src == buf->buf)
* to let the caller know that we switched buffers. to_free = strbuf_detach(buf, NULL);
*/
nsize = size + stats.lf - stats.crlf;
buffer = xmalloc(nsize);
*sizep = nsize;
last = 0;
dst = buffer; strbuf_grow(buf, len + stats.lf - stats.crlf);
do { for (;;) {
unsigned char c = *src++; const char *nl = memchr(src, '\n', len);
if (c == '\n' && last != '\r') if (!nl)
*dst++ = '\r'; break;
*dst++ = c; if (nl > src && nl[-1] == '\r') {
last = c; strbuf_add(buf, src, nl + 1 - src);
} while (--size); } else {
strbuf_add(buf, src, nl - src);
strbuf_addstr(buf, "\r\n");
}
len -= nl + 1 - src;
src = nl + 1;
}
strbuf_add(buf, src, len);
return buffer; free(to_free);
return 1;
} }
static int filter_buffer(const char *path, const char *src, static int filter_buffer(const char *path, const char *src,
@ -246,8 +235,8 @@ static int filter_buffer(const char *path, const char *src,
return (write_err || status); return (write_err || status);
} }
static char *apply_filter(const char *path, const char *src, static int apply_filter(const char *path, const char *src, size_t len,
unsigned long *sizep, const char *cmd) struct strbuf *dst, const char *cmd)
{ {
/* /*
* Create a pipeline to have the command filter the buffer's * Create a pipeline to have the command filter the buffer's
@ -255,21 +244,19 @@ static char *apply_filter(const char *path, const char *src,
* *
* (child --> cmd) --> us * (child --> cmd) --> us
*/ */
const int SLOP = 4096;
int pipe_feed[2]; int pipe_feed[2];
int status; int status, ret = 1;
char *dst;
unsigned long dstsize, dstalloc;
struct child_process child_process; struct child_process child_process;
struct strbuf nbuf;
if (!cmd) if (!cmd)
return NULL; return 0;
memset(&child_process, 0, sizeof(child_process)); memset(&child_process, 0, sizeof(child_process));
if (pipe(pipe_feed) < 0) { if (pipe(pipe_feed) < 0) {
error("cannot create pipe to run external filter %s", cmd); error("cannot create pipe to run external filter %s", cmd);
return NULL; return 0;
} }
fflush(NULL); fflush(NULL);
@ -278,54 +265,37 @@ static char *apply_filter(const char *path, const char *src,
error("cannot fork to run external filter %s", cmd); error("cannot fork to run external filter %s", cmd);
close(pipe_feed[0]); close(pipe_feed[0]);
close(pipe_feed[1]); close(pipe_feed[1]);
return NULL; return 0;
} }
if (!child_process.pid) { if (!child_process.pid) {
dup2(pipe_feed[1], 1); dup2(pipe_feed[1], 1);
close(pipe_feed[0]); close(pipe_feed[0]);
close(pipe_feed[1]); close(pipe_feed[1]);
exit(filter_buffer(path, src, *sizep, cmd)); exit(filter_buffer(path, src, len, cmd));
} }
close(pipe_feed[1]); close(pipe_feed[1]);
dstalloc = *sizep; strbuf_init(&nbuf, 0);
dst = xmalloc(dstalloc); if (strbuf_read(&nbuf, pipe_feed[0], len) < 0) {
dstsize = 0;
while (1) {
ssize_t numread = xread(pipe_feed[0], dst + dstsize,
dstalloc - dstsize);
if (numread <= 0) {
if (!numread)
break;
error("read from external filter %s failed", cmd); error("read from external filter %s failed", cmd);
free(dst); ret = 0;
dst = NULL;
break;
}
dstsize += numread;
if (dstalloc <= dstsize + SLOP) {
dstalloc = dstsize + SLOP;
dst = xrealloc(dst, dstalloc);
}
} }
if (close(pipe_feed[0])) { if (close(pipe_feed[0])) {
error("read from external filter %s failed", cmd); ret = error("read from external filter %s failed", cmd);
free(dst); ret = 0;
dst = NULL;
} }
status = finish_command(&child_process); status = finish_command(&child_process);
if (status) { if (status) {
error("external filter %s failed %d", cmd, -status); ret = error("external filter %s failed %d", cmd, -status);
free(dst); ret = 0;
dst = NULL;
} }
if (dst) if (ret) {
*sizep = dstsize; *dst = nbuf;
return dst; } else {
strbuf_release(&nbuf);
}
return ret;
} }
static struct convert_driver { static struct convert_driver {
@ -353,13 +323,8 @@ static int read_convert_config(const char *var, const char *value)
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen]) if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
break; break;
if (!drv) { if (!drv) {
char *namebuf;
drv = xcalloc(1, sizeof(struct convert_driver)); drv = xcalloc(1, sizeof(struct convert_driver));
namebuf = xmalloc(namelen + 1); drv->name = xmemdupz(name, namelen);
memcpy(namebuf, name, namelen);
namebuf[namelen] = 0;
drv->name = namebuf;
drv->next = NULL;
*user_convert_tail = drv; *user_convert_tail = drv;
user_convert_tail = &(drv->next); user_convert_tail = &(drv->next);
} }
@ -449,137 +414,104 @@ static int count_ident(const char *cp, unsigned long size)
return cnt; return cnt;
} }
static char *ident_to_git(const char *path, const char *src, unsigned long *sizep, int ident) static int ident_to_git(const char *path, const char *src, size_t len,
struct strbuf *buf, int ident)
{ {
int cnt; char *dst, *dollar;
unsigned long size;
char *dst, *buf;
if (!ident) if (!ident || !count_ident(src, len))
return NULL; return 0;
size = *sizep;
cnt = count_ident(src, size);
if (!cnt)
return NULL;
buf = xmalloc(size);
for (dst = buf; size; size--) { strbuf_grow(buf, len);
char ch = *src++; dst = buf->buf;
*dst++ = ch; for (;;) {
if ((ch == '$') && (3 <= size) && dollar = memchr(src, '$', len);
!memcmp("Id:", src, 3)) { if (!dollar)
unsigned long rem = size - 3; break;
const char *cp = src + 3; memcpy(dst, src, dollar + 1 - src);
do { dst += dollar + 1 - src;
ch = *cp++; len -= dollar + 1 - src;
if (ch == '$') src = dollar + 1;
if (len > 3 && !memcmp(src, "Id:", 3)) {
dollar = memchr(src + 3, '$', len - 3);
if (!dollar)
break; break;
rem--;
} while (rem);
if (!rem)
continue;
memcpy(dst, "Id$", 3); memcpy(dst, "Id$", 3);
dst += 3; dst += 3;
size -= (cp - src); len -= dollar + 1 - src;
src = cp; src = dollar + 1;
} }
} }
memcpy(dst, src, len);
strbuf_setlen(buf, dst + len - buf->buf);
return 1;
}
*sizep = dst - buf; static int ident_to_worktree(const char *path, const char *src, size_t len,
return buf; struct strbuf *buf, int ident)
}
static char *ident_to_worktree(const char *path, const char *src, unsigned long *sizep, int ident)
{ {
int cnt;
unsigned long size;
char *dst, *buf;
unsigned char sha1[20]; unsigned char sha1[20];
char *to_free = NULL, *dollar;
int cnt;
if (!ident) if (!ident)
return NULL; return 0;
size = *sizep; cnt = count_ident(src, len);
cnt = count_ident(src, size);
if (!cnt) if (!cnt)
return NULL; return 0;
hash_sha1_file(src, size, "blob", sha1); /* are we "faking" in place editing ? */
buf = xmalloc(size + cnt * 43); if (src == buf->buf)
to_free = strbuf_detach(buf, NULL);
hash_sha1_file(src, len, "blob", sha1);
for (dst = buf; size; size--) { strbuf_grow(buf, len + cnt * 43);
const char *cp; for (;;) {
/* Fetch next source character, move the pointer on */ /* step 1: run to the next '$' */
char ch = *src++; dollar = memchr(src, '$', len);
/* Copy the current character to the destination */ if (!dollar)
*dst++ = ch; break;
/* If the current character is "$" or there are less than three strbuf_add(buf, src, dollar + 1 - src);
* remaining bytes or the two bytes following this one are not len -= dollar + 1 - src;
* "Id", then simply read the next character */ src = dollar + 1;
if ((ch != '$') || (size < 3) || memcmp("Id", src, 2))
/* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
if (len < 3 || memcmp("Id", src, 2))
continue; continue;
/*
* Here when
* - There are more than 2 bytes remaining
* - The current three bytes are "$Id"
* with
* - ch == "$"
* - src[0] == "I"
*/
/* step 3: skip over Id$ or Id:xxxxx$ */
if (src[2] == '$') {
src += 3;
len -= 3;
} else if (src[2] == ':') {
/* /*
* It's possible that an expanded Id has crept its way into the * It's possible that an expanded Id has crept its way into the
* repository, we cope with that by stripping the expansion out * repository, we cope with that by stripping the expansion out
*/ */
if (src[2] == ':') { dollar = memchr(src + 3, '$', len - 3);
/* Expanded keywords have "$Id:" at the front */ if (!dollar) {
/* incomplete keyword, no more '$', so just quit the loop */
/* discard up to but not including the closing $ */
unsigned long rem = size - 3;
/* Point at first byte after the ":" */
cp = src + 3;
/*
* Throw away characters until either
* - we reach a "$"
* - we run out of bytes (rem == 0)
*/
do {
ch = *cp;
if (ch == '$')
break; break;
cp++;
rem--;
} while (rem);
/* If the above finished because it ran out of characters, then
* this is an incomplete keyword, so don't run the expansion */
if (!rem)
continue;
} else if (src[2] == '$')
cp = src + 2;
else
/* Anything other than "$Id:XXX$" or $Id$ and we skip the
* expansion */
continue;
/* cp is now pointing at the last $ of the keyword */
memcpy(dst, "Id: ", 4);
dst += 4;
memcpy(dst, sha1_to_hex(sha1), 40);
dst += 40;
*dst++ = ' ';
/* Adjust for the characters we've discarded */
size -= (cp - src);
src = cp;
/* Copy the final "$" */
*dst++ = *src++;
size--;
} }
*sizep = dst - buf; len -= dollar + 1 - src;
return buf; src = dollar + 1;
} else {
/* it wasn't a "Id$" or "Id:xxxx$" */
continue;
}
/* step 4: substitute */
strbuf_addstr(buf, "Id: ");
strbuf_add(buf, sha1_to_hex(sha1), 40);
strbuf_addstr(buf, " $");
}
strbuf_add(buf, src, len);
free(to_free);
return 1;
} }
static int git_path_check_crlf(const char *path, struct git_attr_check *check) static int git_path_check_crlf(const char *path, struct git_attr_check *check)
@ -618,13 +550,12 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
return !!ATTR_TRUE(value); return !!ATTR_TRUE(value);
} }
char *convert_to_git(const char *path, const char *src, unsigned long *sizep) int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst)
{ {
struct git_attr_check check[3]; struct git_attr_check check[3];
int crlf = CRLF_GUESS; int crlf = CRLF_GUESS;
int ident = 0; int ident = 0, ret = 0;
char *filter = NULL; char *filter = NULL;
char *buf, *buf2;
setup_convert_check(check); setup_convert_check(check);
if (!git_checkattr(path, ARRAY_SIZE(check), check)) { if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
@ -636,30 +567,25 @@ char *convert_to_git(const char *path, const char *src, unsigned long *sizep)
filter = drv->clean; filter = drv->clean;
} }
buf = apply_filter(path, src, sizep, filter); ret |= apply_filter(path, src, len, dst, filter);
if (ret) {
buf2 = crlf_to_git(path, buf ? buf : src, sizep, crlf); src = dst->buf;
if (buf2) { len = dst->len;
free(buf); }
buf = buf2; ret |= crlf_to_git(path, src, len, dst, crlf);
if (ret) {
src = dst->buf;
len = dst->len;
}
return ret | ident_to_git(path, src, len, dst, ident);
} }
buf2 = ident_to_git(path, buf ? buf : src, sizep, ident); int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
if (buf2) {
free(buf);
buf = buf2;
}
return buf;
}
char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep)
{ {
struct git_attr_check check[3]; struct git_attr_check check[3];
int crlf = CRLF_GUESS; int crlf = CRLF_GUESS;
int ident = 0; int ident = 0, ret = 0;
char *filter = NULL; char *filter = NULL;
char *buf, *buf2;
setup_convert_check(check); setup_convert_check(check);
if (!git_checkattr(path, ARRAY_SIZE(check), check)) { if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
@ -671,19 +597,15 @@ char *convert_to_working_tree(const char *path, const char *src, unsigned long *
filter = drv->smudge; filter = drv->smudge;
} }
buf = ident_to_worktree(path, src, sizep, ident); ret |= ident_to_worktree(path, src, len, dst, ident);
if (ret) {
buf2 = crlf_to_worktree(path, buf ? buf : src, sizep, crlf); src = dst->buf;
if (buf2) { len = dst->len;
free(buf);
buf = buf2;
} }
ret |= crlf_to_worktree(path, src, len, dst, crlf);
buf2 = apply_filter(path, buf ? buf : src, sizep, filter); if (ret) {
if (buf2) { src = dst->buf;
free(buf); len = dst->len;
buf = buf2;
} }
return ret | apply_filter(path, src, len, dst, filter);
return buf;
} }

332
diff.c
View File

@ -83,13 +83,8 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen]) if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
break; break;
if (!drv) { if (!drv) {
char *namebuf;
drv = xcalloc(1, sizeof(struct ll_diff_driver)); drv = xcalloc(1, sizeof(struct ll_diff_driver));
namebuf = xmalloc(namelen + 1); drv->name = xmemdupz(name, namelen);
memcpy(namebuf, name, namelen);
namebuf[namelen] = 0;
drv->name = namebuf;
drv->next = NULL;
if (!user_diff_tail) if (!user_diff_tail)
user_diff_tail = &user_diff; user_diff_tail = &user_diff;
*user_diff_tail = drv; *user_diff_tail = drv;
@ -126,12 +121,8 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen]) if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
break; break;
if (!pp) { if (!pp) {
char *namebuf;
pp = xcalloc(1, sizeof(*pp)); pp = xcalloc(1, sizeof(*pp));
namebuf = xmalloc(namelen + 1); pp->name = xmemdupz(name, namelen);
memcpy(namebuf, name, namelen);
namebuf[namelen] = 0;
pp->name = namebuf;
pp->next = funcname_pattern_list; pp->next = funcname_pattern_list;
funcname_pattern_list = pp; funcname_pattern_list = pp;
} }
@ -190,44 +181,23 @@ int git_diff_ui_config(const char *var, const char *value)
return git_default_config(var, value); return git_default_config(var, value);
} }
static char *quote_one(const char *str)
{
int needlen;
char *xp;
if (!str)
return NULL;
needlen = quote_c_style(str, NULL, NULL, 0);
if (!needlen)
return xstrdup(str);
xp = xmalloc(needlen + 1);
quote_c_style(str, xp, NULL, 0);
return xp;
}
static char *quote_two(const char *one, const char *two) static char *quote_two(const char *one, const char *two)
{ {
int need_one = quote_c_style(one, NULL, NULL, 1); int need_one = quote_c_style(one, NULL, NULL, 1);
int need_two = quote_c_style(two, NULL, NULL, 1); int need_two = quote_c_style(two, NULL, NULL, 1);
char *xp; struct strbuf res;
strbuf_init(&res, 0);
if (need_one + need_two) { if (need_one + need_two) {
if (!need_one) need_one = strlen(one); strbuf_addch(&res, '"');
if (!need_two) need_one = strlen(two); quote_c_style(one, &res, NULL, 1);
quote_c_style(two, &res, NULL, 1);
xp = xmalloc(need_one + need_two + 3); strbuf_addch(&res, '"');
xp[0] = '"'; } else {
quote_c_style(one, xp + 1, NULL, 1); strbuf_addstr(&res, one);
quote_c_style(two, xp + need_one + 1, NULL, 1); strbuf_addstr(&res, two);
strcpy(xp + need_one + need_two + 1, "\"");
return xp;
} }
need_one = strlen(one); return strbuf_detach(&res, NULL);
need_two = strlen(two);
xp = xmalloc(need_one + need_two + 1);
strcpy(xp, one);
strcpy(xp + need_one, two);
return xp;
} }
static const char *external_diff(void) static const char *external_diff(void)
@ -679,27 +649,20 @@ static char *pprint_rename(const char *a, const char *b)
{ {
const char *old = a; const char *old = a;
const char *new = b; const char *new = b;
char *name = NULL; struct strbuf name;
int pfx_length, sfx_length; int pfx_length, sfx_length;
int len_a = strlen(a); int len_a = strlen(a);
int len_b = strlen(b); int len_b = strlen(b);
int a_midlen, b_midlen;
int qlen_a = quote_c_style(a, NULL, NULL, 0); int qlen_a = quote_c_style(a, NULL, NULL, 0);
int qlen_b = quote_c_style(b, NULL, NULL, 0); int qlen_b = quote_c_style(b, NULL, NULL, 0);
strbuf_init(&name, 0);
if (qlen_a || qlen_b) { if (qlen_a || qlen_b) {
if (qlen_a) len_a = qlen_a; quote_c_style(a, &name, NULL, 0);
if (qlen_b) len_b = qlen_b; strbuf_addstr(&name, " => ");
name = xmalloc( len_a + len_b + 5 ); quote_c_style(b, &name, NULL, 0);
if (qlen_a) return strbuf_detach(&name, NULL);
quote_c_style(a, name, NULL, 0);
else
memcpy(name, a, len_a);
memcpy(name + len_a, " => ", 4);
if (qlen_b)
quote_c_style(b, name + len_a + 4, NULL, 0);
else
memcpy(name + len_a + 4, b, len_b + 1);
return name;
} }
/* Find common prefix */ /* Find common prefix */
@ -728,24 +691,26 @@ static char *pprint_rename(const char *a, const char *b)
* pfx{sfx-a => sfx-b} * pfx{sfx-a => sfx-b}
* name-a => name-b * name-a => name-b
*/ */
if (pfx_length + sfx_length) { a_midlen = len_a - pfx_length - sfx_length;
int a_midlen = len_a - pfx_length - sfx_length; b_midlen = len_b - pfx_length - sfx_length;
int b_midlen = len_b - pfx_length - sfx_length; if (a_midlen < 0)
if (a_midlen < 0) a_midlen = 0; a_midlen = 0;
if (b_midlen < 0) b_midlen = 0; if (b_midlen < 0)
b_midlen = 0;
name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7); strbuf_grow(&name, pfx_length + a_midlen + b_midlen + sfx_length + 7);
sprintf(name, "%.*s{%.*s => %.*s}%s", if (pfx_length + sfx_length) {
pfx_length, a, strbuf_add(&name, a, pfx_length);
a_midlen, a + pfx_length, strbuf_addch(&name, '{');
b_midlen, b + pfx_length,
a + len_a - sfx_length);
} }
else { strbuf_add(&name, a + pfx_length, a_midlen);
name = xmalloc(len_a + len_b + 5); strbuf_addstr(&name, " => ");
sprintf(name, "%s => %s", a, b); strbuf_add(&name, b + pfx_length, b_midlen);
if (pfx_length + sfx_length) {
strbuf_addch(&name, '}');
strbuf_add(&name, a + len_a - sfx_length, sfx_length);
} }
return name; return strbuf_detach(&name, NULL);
} }
struct diffstat_t { struct diffstat_t {
@ -858,12 +823,13 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
int change = file->added + file->deleted; int change = file->added + file->deleted;
if (!file->is_renamed) { /* renames are already quoted by pprint_rename */ if (!file->is_renamed) { /* renames are already quoted by pprint_rename */
len = quote_c_style(file->name, NULL, NULL, 0); struct strbuf buf;
if (len) { strbuf_init(&buf, 0);
char *qname = xmalloc(len + 1); if (quote_c_style(file->name, &buf, NULL, 0)) {
quote_c_style(file->name, qname, NULL, 0);
free(file->name); free(file->name);
file->name = qname; file->name = strbuf_detach(&buf, NULL);
} else {
strbuf_release(&buf);
} }
} }
@ -1001,14 +967,14 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
printf("-\t-\t"); printf("-\t-\t");
else else
printf("%d\t%d\t", file->added, file->deleted); printf("%d\t%d\t", file->added, file->deleted);
if (options->line_termination && !file->is_renamed && if (!file->is_renamed) {
quote_c_style(file->name, NULL, NULL, 0)) write_name_quoted(file->name, stdout, options->line_termination);
quote_c_style(file->name, NULL, stdout, 0); } else {
else
fputs(file->name, stdout); fputs(file->name, stdout);
putchar(options->line_termination); putchar(options->line_termination);
} }
} }
}
struct checkdiff_t { struct checkdiff_t {
struct xdiff_emit_state xm; struct xdiff_emit_state xm;
@ -1545,26 +1511,15 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
static int populate_from_stdin(struct diff_filespec *s) static int populate_from_stdin(struct diff_filespec *s)
{ {
#define INCREMENT 1024 struct strbuf buf;
char *buf;
unsigned long size;
ssize_t got;
size = 0; strbuf_init(&buf, 0);
buf = NULL; if (strbuf_read(&buf, 0, 0) < 0)
while (1) {
buf = xrealloc(buf, size + INCREMENT);
got = xread(0, buf + size, INCREMENT);
if (!got)
break; /* EOF */
if (got < 0)
return error("error while reading from stdin %s", return error("error while reading from stdin %s",
strerror(errno)); strerror(errno));
size += got;
}
s->should_munmap = 0; s->should_munmap = 0;
s->data = buf; s->data = strbuf_detach(&buf, &s->size);
s->size = size;
s->should_free = 1; s->should_free = 1;
return 0; return 0;
} }
@ -1609,10 +1564,9 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
if (!s->sha1_valid || if (!s->sha1_valid ||
reuse_worktree_file(s->path, s->sha1, 0)) { reuse_worktree_file(s->path, s->sha1, 0)) {
struct strbuf buf;
struct stat st; struct stat st;
int fd; int fd;
char *buf;
unsigned long size;
if (!strcmp(s->path, "-")) if (!strcmp(s->path, "-"))
return populate_from_stdin(s); return populate_from_stdin(s);
@ -1653,13 +1607,11 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
/* /*
* Convert from working tree format to canonical git format * Convert from working tree format to canonical git format
*/ */
size = s->size; strbuf_init(&buf, 0);
buf = convert_to_git(s->path, s->data, &size); if (convert_to_git(s->path, s->data, s->size, &buf)) {
if (buf) {
munmap(s->data, s->size); munmap(s->data, s->size);
s->should_munmap = 0; s->should_munmap = 0;
s->data = buf; s->data = strbuf_detach(&buf, &s->size);
s->size = size;
s->should_free = 1; s->should_free = 1;
} }
} }
@ -1967,50 +1919,46 @@ static int similarity_index(struct diff_filepair *p)
static void run_diff(struct diff_filepair *p, struct diff_options *o) static void run_diff(struct diff_filepair *p, struct diff_options *o)
{ {
const char *pgm = external_diff(); const char *pgm = external_diff();
char msg[PATH_MAX*2+300], *xfrm_msg; struct strbuf msg;
struct diff_filespec *one; char *xfrm_msg;
struct diff_filespec *two; struct diff_filespec *one = p->one;
struct diff_filespec *two = p->two;
const char *name; const char *name;
const char *other; const char *other;
char *name_munged, *other_munged;
int complete_rewrite = 0; int complete_rewrite = 0;
int len;
if (DIFF_PAIR_UNMERGED(p)) { if (DIFF_PAIR_UNMERGED(p)) {
/* unmerged */
run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0); run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
return; return;
} }
name = p->one->path; name = p->one->path;
other = (strcmp(name, p->two->path) ? p->two->path : NULL); other = (strcmp(name, p->two->path) ? p->two->path : NULL);
name_munged = quote_one(name);
other_munged = quote_one(other);
one = p->one; two = p->two;
diff_fill_sha1_info(one); diff_fill_sha1_info(one);
diff_fill_sha1_info(two); diff_fill_sha1_info(two);
len = 0; strbuf_init(&msg, PATH_MAX * 2 + 300);
switch (p->status) { switch (p->status) {
case DIFF_STATUS_COPIED: case DIFF_STATUS_COPIED:
len += snprintf(msg + len, sizeof(msg) - len, strbuf_addf(&msg, "similarity index %d%%", similarity_index(p));
"similarity index %d%%\n" strbuf_addstr(&msg, "\ncopy from ");
"copy from %s\n" quote_c_style(name, &msg, NULL, 0);
"copy to %s\n", strbuf_addstr(&msg, "\ncopy to ");
similarity_index(p), name_munged, other_munged); quote_c_style(other, &msg, NULL, 0);
strbuf_addch(&msg, '\n');
break; break;
case DIFF_STATUS_RENAMED: case DIFF_STATUS_RENAMED:
len += snprintf(msg + len, sizeof(msg) - len, strbuf_addf(&msg, "similarity index %d%%", similarity_index(p));
"similarity index %d%%\n" strbuf_addstr(&msg, "\nrename from ");
"rename from %s\n" quote_c_style(name, &msg, NULL, 0);
"rename to %s\n", strbuf_addstr(&msg, "\nrename to ");
similarity_index(p), name_munged, other_munged); quote_c_style(other, &msg, NULL, 0);
strbuf_addch(&msg, '\n');
break; break;
case DIFF_STATUS_MODIFIED: case DIFF_STATUS_MODIFIED:
if (p->score) { if (p->score) {
len += snprintf(msg + len, sizeof(msg) - len, strbuf_addf(&msg, "dissimilarity index %d%%\n",
"dissimilarity index %d%%\n",
similarity_index(p)); similarity_index(p));
complete_rewrite = 1; complete_rewrite = 1;
break; break;
@ -2030,19 +1978,17 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
abbrev = 40; abbrev = 40;
} }
len += snprintf(msg + len, sizeof(msg) - len, strbuf_addf(&msg, "index %.*s..%.*s",
"index %.*s..%.*s",
abbrev, sha1_to_hex(one->sha1), abbrev, sha1_to_hex(one->sha1),
abbrev, sha1_to_hex(two->sha1)); abbrev, sha1_to_hex(two->sha1));
if (one->mode == two->mode) if (one->mode == two->mode)
len += snprintf(msg + len, sizeof(msg) - len, strbuf_addf(&msg, " %06o", one->mode);
" %06o", one->mode); strbuf_addch(&msg, '\n');
len += snprintf(msg + len, sizeof(msg) - len, "\n");
} }
if (len) if (msg.len)
msg[--len] = 0; strbuf_setlen(&msg, msg.len - 1);
xfrm_msg = len ? msg : NULL; xfrm_msg = msg.len ? msg.buf : NULL;
if (!pgm && if (!pgm &&
DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
@ -2061,8 +2007,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o, run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
complete_rewrite); complete_rewrite);
free(name_munged); strbuf_release(&msg);
free(other_munged);
} }
static void run_diffstat(struct diff_filepair *p, struct diff_options *o, static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
@ -2518,72 +2463,30 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len)
return sha1_to_hex(sha1); return sha1_to_hex(sha1);
} }
static void diff_flush_raw(struct diff_filepair *p, static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt)
struct diff_options *options)
{ {
int two_paths; int line_termination = opt->line_termination;
char status[10]; int inter_name_termination = line_termination ? '\t' : '\0';
int abbrev = options->abbrev;
const char *path_one, *path_two;
int inter_name_termination = '\t';
int line_termination = options->line_termination;
if (!line_termination) if (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) {
inter_name_termination = 0; printf(":%06o %06o %s ", p->one->mode, p->two->mode,
diff_unique_abbrev(p->one->sha1, opt->abbrev));
path_one = p->one->path; printf("%s ", diff_unique_abbrev(p->two->sha1, opt->abbrev));
path_two = p->two->path; }
if (line_termination) { if (p->score) {
path_one = quote_one(path_one); printf("%c%03d%c", p->status, similarity_index(p),
path_two = quote_one(path_two); inter_name_termination);
} else {
printf("%c%c", p->status, inter_name_termination);
} }
if (p->score) if (p->status == DIFF_STATUS_COPIED || p->status == DIFF_STATUS_RENAMED) {
sprintf(status, "%c%03d", p->status, similarity_index(p)); write_name_quoted(p->one->path, stdout, inter_name_termination);
else { write_name_quoted(p->two->path, stdout, line_termination);
status[0] = p->status; } else {
status[1] = 0; const char *path = p->one->mode ? p->one->path : p->two->path;
write_name_quoted(path, stdout, line_termination);
} }
switch (p->status) {
case DIFF_STATUS_COPIED:
case DIFF_STATUS_RENAMED:
two_paths = 1;
break;
case DIFF_STATUS_ADDED:
case DIFF_STATUS_DELETED:
two_paths = 0;
break;
default:
two_paths = 0;
break;
}
if (!(options->output_format & DIFF_FORMAT_NAME_STATUS)) {
printf(":%06o %06o %s ",
p->one->mode, p->two->mode,
diff_unique_abbrev(p->one->sha1, abbrev));
printf("%s ",
diff_unique_abbrev(p->two->sha1, abbrev));
}
printf("%s%c%s", status, inter_name_termination,
two_paths || p->one->mode ? path_one : path_two);
if (two_paths)
printf("%c%s", inter_name_termination, path_two);
putchar(line_termination);
if (path_one != p->one->path)
free((void*)path_one);
if (path_two != p->two->path)
free((void*)path_two);
}
static void diff_flush_name(struct diff_filepair *p, struct diff_options *opt)
{
char *path = p->two->path;
if (opt->line_termination)
path = quote_one(p->two->path);
printf("%s%c", path, opt->line_termination);
if (p->two->path != path)
free(path);
} }
int diff_unmodified_pair(struct diff_filepair *p) int diff_unmodified_pair(struct diff_filepair *p)
@ -2593,14 +2496,11 @@ int diff_unmodified_pair(struct diff_filepair *p)
* let transformers to produce diff_filepairs any way they want, * let transformers to produce diff_filepairs any way they want,
* and filter and clean them up here before producing the output. * and filter and clean them up here before producing the output.
*/ */
struct diff_filespec *one, *two; struct diff_filespec *one = p->one, *two = p->two;
if (DIFF_PAIR_UNMERGED(p)) if (DIFF_PAIR_UNMERGED(p))
return 0; /* unmerged is interesting */ return 0; /* unmerged is interesting */
one = p->one;
two = p->two;
/* deletion, addition, mode or type change /* deletion, addition, mode or type change
* and rename are all interesting. * and rename are all interesting.
*/ */
@ -2789,32 +2689,27 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS))
diff_flush_raw(p, opt); diff_flush_raw(p, opt);
else if (fmt & DIFF_FORMAT_NAME) else if (fmt & DIFF_FORMAT_NAME)
diff_flush_name(p, opt); write_name_quoted(p->two->path, stdout, opt->line_termination);
} }
static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs) static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
{ {
char *name = quote_one(fs->path);
if (fs->mode) if (fs->mode)
printf(" %s mode %06o %s\n", newdelete, fs->mode, name); printf(" %s mode %06o ", newdelete, fs->mode);
else else
printf(" %s %s\n", newdelete, name); printf(" %s ", newdelete);
free(name); write_name_quoted(fs->path, stdout, '\n');
} }
static void show_mode_change(struct diff_filepair *p, int show_name) static void show_mode_change(struct diff_filepair *p, int show_name)
{ {
if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) { if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
printf(" mode change %06o => %06o%c", p->one->mode, p->two->mode,
show_name ? ' ' : '\n');
if (show_name) { if (show_name) {
char *name = quote_one(p->two->path); write_name_quoted(p->two->path, stdout, '\n');
printf(" mode change %06o => %06o %s\n",
p->one->mode, p->two->mode, name);
free(name);
} }
else
printf(" mode change %06o => %06o\n",
p->one->mode, p->two->mode);
} }
} }
@ -2844,12 +2739,11 @@ static void diff_summary(struct diff_filepair *p)
break; break;
default: default:
if (p->score) { if (p->score) {
char *name = quote_one(p->two->path); puts(" rewrite ");
printf(" rewrite %s (%d%%)\n", name, write_name_quoted(p->two->path, stdout, ' ');
similarity_index(p)); printf("(%d%%)\n", similarity_index(p));
free(name); }
show_mode_change(p, 0); show_mode_change(p, !p->score);
} else show_mode_change(p, 1);
break; break;
} }
} }

View File

@ -48,11 +48,8 @@ static void prepare_order(const char *orderfile)
if (*ep == '\n') { if (*ep == '\n') {
*ep = 0; *ep = 0;
order[cnt] = cp; order[cnt] = cp;
} } else {
else { order[cnt] = xmemdupz(cp, ep - cp);
order[cnt] = xmalloc(ep-cp+1);
memcpy(order[cnt], cp, ep-cp);
order[cnt][ep-cp] = 0;
} }
cnt++; cnt++;
} }

View File

@ -104,7 +104,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
long wrote; long wrote;
switch (ntohl(ce->ce_mode) & S_IFMT) { switch (ntohl(ce->ce_mode) & S_IFMT) {
char *buf, *new; char *new;
struct strbuf buf;
unsigned long size; unsigned long size;
case S_IFREG: case S_IFREG:
@ -116,10 +117,10 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
/* /*
* Convert from git internal format to working tree format * Convert from git internal format to working tree format
*/ */
buf = convert_to_working_tree(ce->name, new, &size); strbuf_init(&buf, 0);
if (buf) { if (convert_to_working_tree(ce->name, new, size, &buf)) {
free(new); free(new);
new = buf; new = strbuf_detach(&buf, &size);
} }
if (to_tempfile) { if (to_tempfile) {

View File

@ -149,7 +149,6 @@ Format of STDIN stream:
#include "pack.h" #include "pack.h"
#include "refs.h" #include "refs.h"
#include "csum-file.h" #include "csum-file.h"
#include "strbuf.h"
#include "quote.h" #include "quote.h"
#define PACK_ID_BITS 16 #define PACK_ID_BITS 16
@ -183,11 +182,10 @@ struct mark_set
struct last_object struct last_object
{ {
void *data; struct strbuf data;
unsigned long len;
uint32_t offset; uint32_t offset;
unsigned int depth; unsigned int depth;
unsigned no_free:1; unsigned no_swap : 1;
}; };
struct mem_pool struct mem_pool
@ -251,12 +249,6 @@ struct tag
unsigned char sha1[20]; unsigned char sha1[20];
}; };
struct dbuf
{
void *buffer;
size_t capacity;
};
struct hash_list struct hash_list
{ {
struct hash_list *next; struct hash_list *next;
@ -317,15 +309,15 @@ static struct mark_set *marks;
static const char* mark_file; static const char* mark_file;
/* Our last blob */ /* Our last blob */
static struct last_object last_blob; static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 };
/* Tree management */ /* Tree management */
static unsigned int tree_entry_alloc = 1000; static unsigned int tree_entry_alloc = 1000;
static void *avail_tree_entry; static void *avail_tree_entry;
static unsigned int avail_tree_table_sz = 100; static unsigned int avail_tree_table_sz = 100;
static struct avail_tree_content **avail_tree_table; static struct avail_tree_content **avail_tree_table;
static struct dbuf old_tree; static struct strbuf old_tree = STRBUF_INIT;
static struct dbuf new_tree; static struct strbuf new_tree = STRBUF_INIT;
/* Branch data */ /* Branch data */
static unsigned long max_active_branches = 5; static unsigned long max_active_branches = 5;
@ -340,14 +332,14 @@ static struct tag *last_tag;
/* Input stream parsing */ /* Input stream parsing */
static whenspec_type whenspec = WHENSPEC_RAW; static whenspec_type whenspec = WHENSPEC_RAW;
static struct strbuf command_buf; static struct strbuf command_buf = STRBUF_INIT;
static int unread_command_buf; static int unread_command_buf;
static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL}; static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
static struct recent_command *cmd_tail = &cmd_hist; static struct recent_command *cmd_tail = &cmd_hist;
static struct recent_command *rc_free; static struct recent_command *rc_free;
static unsigned int cmd_save = 100; static unsigned int cmd_save = 100;
static uintmax_t next_mark; static uintmax_t next_mark;
static struct dbuf new_data; static struct strbuf new_data = STRBUF_INIT;
static void write_branch_report(FILE *rpt, struct branch *b) static void write_branch_report(FILE *rpt, struct branch *b)
{ {
@ -567,17 +559,6 @@ static char *pool_strdup(const char *s)
return r; return r;
} }
static void size_dbuf(struct dbuf *b, size_t maxlen)
{
if (b->buffer) {
if (b->capacity >= maxlen)
return;
free(b->buffer);
}
b->capacity = ((maxlen / 1024) + 1) * 1024;
b->buffer = xmalloc(b->capacity);
}
static void insert_mark(uintmax_t idnum, struct object_entry *oe) static void insert_mark(uintmax_t idnum, struct object_entry *oe)
{ {
struct mark_set *s = marks; struct mark_set *s = marks;
@ -968,9 +949,7 @@ static void end_packfile(void)
free(old_p); free(old_p);
/* We can't carry a delta across packfiles. */ /* We can't carry a delta across packfiles. */
free(last_blob.data); strbuf_release(&last_blob.data);
last_blob.data = NULL;
last_blob.len = 0;
last_blob.offset = 0; last_blob.offset = 0;
last_blob.depth = 0; last_blob.depth = 0;
} }
@ -1006,8 +985,7 @@ static size_t encode_header(
static int store_object( static int store_object(
enum object_type type, enum object_type type,
void *dat, struct strbuf *dat,
size_t datlen,
struct last_object *last, struct last_object *last,
unsigned char *sha1out, unsigned char *sha1out,
uintmax_t mark) uintmax_t mark)
@ -1021,10 +999,10 @@ static int store_object(
z_stream s; z_stream s;
hdrlen = sprintf((char*)hdr,"%s %lu", typename(type), hdrlen = sprintf((char*)hdr,"%s %lu", typename(type),
(unsigned long)datlen) + 1; (unsigned long)dat->len) + 1;
SHA1_Init(&c); SHA1_Init(&c);
SHA1_Update(&c, hdr, hdrlen); SHA1_Update(&c, hdr, hdrlen);
SHA1_Update(&c, dat, datlen); SHA1_Update(&c, dat->buf, dat->len);
SHA1_Final(sha1, &c); SHA1_Final(sha1, &c);
if (sha1out) if (sha1out)
hashcpy(sha1out, sha1); hashcpy(sha1out, sha1);
@ -1043,11 +1021,11 @@ static int store_object(
return 1; return 1;
} }
if (last && last->data && last->depth < max_depth) { if (last && last->data.buf && last->depth < max_depth) {
delta = diff_delta(last->data, last->len, delta = diff_delta(last->data.buf, last->data.len,
dat, datlen, dat->buf, dat->len,
&deltalen, 0); &deltalen, 0);
if (delta && deltalen >= datlen) { if (delta && deltalen >= dat->len) {
free(delta); free(delta);
delta = NULL; delta = NULL;
} }
@ -1060,8 +1038,8 @@ static int store_object(
s.next_in = delta; s.next_in = delta;
s.avail_in = deltalen; s.avail_in = deltalen;
} else { } else {
s.next_in = dat; s.next_in = (void *)dat->buf;
s.avail_in = datlen; s.avail_in = dat->len;
} }
s.avail_out = deflateBound(&s, s.avail_in); s.avail_out = deflateBound(&s, s.avail_in);
s.next_out = out = xmalloc(s.avail_out); s.next_out = out = xmalloc(s.avail_out);
@ -1084,8 +1062,8 @@ static int store_object(
memset(&s, 0, sizeof(s)); memset(&s, 0, sizeof(s));
deflateInit(&s, zlib_compression_level); deflateInit(&s, zlib_compression_level);
s.next_in = dat; s.next_in = (void *)dat->buf;
s.avail_in = datlen; s.avail_in = dat->len;
s.avail_out = deflateBound(&s, s.avail_in); s.avail_out = deflateBound(&s, s.avail_in);
s.next_out = out = xrealloc(out, s.avail_out); s.next_out = out = xrealloc(out, s.avail_out);
while (deflate(&s, Z_FINISH) == Z_OK) while (deflate(&s, Z_FINISH) == Z_OK)
@ -1119,7 +1097,7 @@ static int store_object(
} else { } else {
if (last) if (last)
last->depth = 0; last->depth = 0;
hdrlen = encode_header(type, datlen, hdr); hdrlen = encode_header(type, dat->len, hdr);
write_or_die(pack_data->pack_fd, hdr, hdrlen); write_or_die(pack_data->pack_fd, hdr, hdrlen);
pack_size += hdrlen; pack_size += hdrlen;
} }
@ -1130,11 +1108,12 @@ static int store_object(
free(out); free(out);
free(delta); free(delta);
if (last) { if (last) {
if (!last->no_free) if (last->no_swap) {
free(last->data); last->data = *dat;
last->data = dat; } else {
strbuf_swap(&last->data, dat);
}
last->offset = e->offset; last->offset = e->offset;
last->len = datlen;
} }
return 0; return 0;
} }
@ -1230,14 +1209,10 @@ static int tecmp1 (const void *_a, const void *_b)
b->name->str_dat, b->name->str_len, b->versions[1].mode); b->name->str_dat, b->name->str_len, b->versions[1].mode);
} }
static void mktree(struct tree_content *t, static void mktree(struct tree_content *t, int v, struct strbuf *b)
int v,
unsigned long *szp,
struct dbuf *b)
{ {
size_t maxlen = 0; size_t maxlen = 0;
unsigned int i; unsigned int i;
char *c;
if (!v) if (!v)
qsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp0); qsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp0);
@ -1249,28 +1224,23 @@ static void mktree(struct tree_content *t,
maxlen += t->entries[i]->name->str_len + 34; maxlen += t->entries[i]->name->str_len + 34;
} }
size_dbuf(b, maxlen); strbuf_reset(b);
c = b->buffer; strbuf_grow(b, maxlen);
for (i = 0; i < t->entry_count; i++) { for (i = 0; i < t->entry_count; i++) {
struct tree_entry *e = t->entries[i]; struct tree_entry *e = t->entries[i];
if (!e->versions[v].mode) if (!e->versions[v].mode)
continue; continue;
c += sprintf(c, "%o", (unsigned int)e->versions[v].mode); strbuf_addf(b, "%o %s%c", (unsigned int)e->versions[v].mode,
*c++ = ' '; e->name->str_dat, '\0');
strcpy(c, e->name->str_dat); strbuf_add(b, e->versions[v].sha1, 20);
c += e->name->str_len + 1;
hashcpy((unsigned char*)c, e->versions[v].sha1);
c += 20;
} }
*szp = c - (char*)b->buffer;
} }
static void store_tree(struct tree_entry *root) static void store_tree(struct tree_entry *root)
{ {
struct tree_content *t = root->tree; struct tree_content *t = root->tree;
unsigned int i, j, del; unsigned int i, j, del;
unsigned long new_len; struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };
struct last_object lo;
struct object_entry *le; struct object_entry *le;
if (!is_null_sha1(root->versions[1].sha1)) if (!is_null_sha1(root->versions[1].sha1))
@ -1282,23 +1252,15 @@ static void store_tree(struct tree_entry *root)
} }
le = find_object(root->versions[0].sha1); le = find_object(root->versions[0].sha1);
if (!S_ISDIR(root->versions[0].mode) if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
|| !le mktree(t, 0, &old_tree);
|| le->pack_id != pack_id) { lo.data = old_tree;
lo.data = NULL;
lo.depth = 0;
lo.no_free = 0;
} else {
mktree(t, 0, &lo.len, &old_tree);
lo.data = old_tree.buffer;
lo.offset = le->offset; lo.offset = le->offset;
lo.depth = t->delta_depth; lo.depth = t->delta_depth;
lo.no_free = 1;
} }
mktree(t, 1, &new_len, &new_tree); mktree(t, 1, &new_tree);
store_object(OBJ_TREE, new_tree.buffer, new_len, store_object(OBJ_TREE, &new_tree, &lo, root->versions[1].sha1, 0);
&lo, root->versions[1].sha1, 0);
t->delta_depth = lo.depth; t->delta_depth = lo.depth;
for (i = 0, j = 0, del = 0; i < t->entry_count; i++) { for (i = 0, j = 0, del = 0; i < t->entry_count; i++) {
@ -1585,20 +1547,25 @@ static void dump_marks(void)
mark_file, strerror(errno)); mark_file, strerror(errno));
} }
static void read_next_command(void) static int read_next_command(void)
{ {
static int stdin_eof = 0;
if (stdin_eof) {
unread_command_buf = 0;
return EOF;
}
do { do {
if (unread_command_buf) { if (unread_command_buf) {
unread_command_buf = 0; unread_command_buf = 0;
if (command_buf.eof)
return;
} else { } else {
struct recent_command *rc; struct recent_command *rc;
command_buf.buf = NULL; strbuf_detach(&command_buf, NULL);
read_line(&command_buf, stdin, '\n'); stdin_eof = strbuf_getline(&command_buf, stdin, '\n');
if (command_buf.eof) if (stdin_eof)
return; return EOF;
rc = rc_free; rc = rc_free;
if (rc) if (rc)
@ -1617,6 +1584,8 @@ static void read_next_command(void)
cmd_tail = rc; cmd_tail = rc;
} }
} while (command_buf.buf[0] == '#'); } while (command_buf.buf[0] == '#');
return 0;
} }
static void skip_optional_lf(void) static void skip_optional_lf(void)
@ -1636,42 +1605,35 @@ static void cmd_mark(void)
next_mark = 0; next_mark = 0;
} }
static void *cmd_data (size_t *size) static void cmd_data(struct strbuf *sb)
{ {
size_t length; strbuf_reset(sb);
char *buffer;
if (prefixcmp(command_buf.buf, "data ")) if (prefixcmp(command_buf.buf, "data "))
die("Expected 'data n' command, found: %s", command_buf.buf); die("Expected 'data n' command, found: %s", command_buf.buf);
if (!prefixcmp(command_buf.buf + 5, "<<")) { if (!prefixcmp(command_buf.buf + 5, "<<")) {
char *term = xstrdup(command_buf.buf + 5 + 2); char *term = xstrdup(command_buf.buf + 5 + 2);
size_t sz = 8192, term_len = command_buf.len - 5 - 2; size_t term_len = command_buf.len - 5 - 2;
length = 0;
buffer = xmalloc(sz);
command_buf.buf = NULL;
for (;;) { for (;;) {
read_line(&command_buf, stdin, '\n'); if (strbuf_getline(&command_buf, stdin, '\n') == EOF)
if (command_buf.eof)
die("EOF in data (terminator '%s' not found)", term); die("EOF in data (terminator '%s' not found)", term);
if (term_len == command_buf.len if (term_len == command_buf.len
&& !strcmp(term, command_buf.buf)) && !strcmp(term, command_buf.buf))
break; break;
ALLOC_GROW(buffer, length + command_buf.len, sz); strbuf_addbuf(sb, &command_buf);
memcpy(buffer + length, strbuf_addch(sb, '\n');
command_buf.buf,
command_buf.len - 1);
length += command_buf.len - 1;
buffer[length++] = '\n';
} }
free(term); free(term);
} }
else { else {
size_t n = 0; size_t n = 0, length;
length = strtoul(command_buf.buf + 5, NULL, 10); length = strtoul(command_buf.buf + 5, NULL, 10);
buffer = xmalloc(length);
while (n < length) { while (n < length) {
size_t s = fread(buffer + n, 1, length - n, stdin); size_t s = strbuf_fread(sb, length - n, stdin);
if (!s && feof(stdin)) if (!s && feof(stdin))
die("EOF in data (%lu bytes remaining)", die("EOF in data (%lu bytes remaining)",
(unsigned long)(length - n)); (unsigned long)(length - n));
@ -1680,8 +1642,6 @@ static void *cmd_data (size_t *size)
} }
skip_optional_lf(); skip_optional_lf();
*size = length;
return buffer;
} }
static int validate_raw_date(const char *src, char *result, int maxlen) static int validate_raw_date(const char *src, char *result, int maxlen)
@ -1744,15 +1704,12 @@ static char *parse_ident(const char *buf)
static void cmd_new_blob(void) static void cmd_new_blob(void)
{ {
size_t l; static struct strbuf buf = STRBUF_INIT;
void *d;
read_next_command(); read_next_command();
cmd_mark(); cmd_mark();
d = cmd_data(&l); cmd_data(&buf);
store_object(OBJ_BLOB, &buf, &last_blob, NULL, next_mark);
if (store_object(OBJ_BLOB, d, l, &last_blob, NULL, next_mark))
free(d);
} }
static void unload_one_branch(void) static void unload_one_branch(void)
@ -1802,7 +1759,7 @@ static void load_branch(struct branch *b)
static void file_change_m(struct branch *b) static void file_change_m(struct branch *b)
{ {
const char *p = command_buf.buf + 2; const char *p = command_buf.buf + 2;
char *p_uq; static struct strbuf uq = STRBUF_INIT;
const char *endp; const char *endp;
struct object_entry *oe = oe; struct object_entry *oe = oe;
unsigned char sha1[20]; unsigned char sha1[20];
@ -1840,22 +1797,23 @@ static void file_change_m(struct branch *b)
if (*p++ != ' ') if (*p++ != ' ')
die("Missing space after SHA1: %s", command_buf.buf); die("Missing space after SHA1: %s", command_buf.buf);
p_uq = unquote_c_style(p, &endp); strbuf_reset(&uq);
if (p_uq) { if (!unquote_c_style(&uq, p, &endp)) {
if (*endp) if (*endp)
die("Garbage after path in: %s", command_buf.buf); die("Garbage after path in: %s", command_buf.buf);
p = p_uq; p = uq.buf;
} }
if (inline_data) { if (inline_data) {
size_t l; static struct strbuf buf = STRBUF_INIT;
void *d;
if (!p_uq) if (p != uq.buf) {
p = p_uq = xstrdup(p); strbuf_addstr(&uq, p);
p = uq.buf;
}
read_next_command(); read_next_command();
d = cmd_data(&l); cmd_data(&buf);
if (store_object(OBJ_BLOB, d, l, &last_blob, sha1, 0)) store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0);
free(d);
} else if (oe) { } else if (oe) {
if (oe->type != OBJ_BLOB) if (oe->type != OBJ_BLOB)
die("Not a blob (actually a %s): %s", die("Not a blob (actually a %s): %s",
@ -1870,58 +1828,54 @@ static void file_change_m(struct branch *b)
} }
tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode, NULL); tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode, NULL);
free(p_uq);
} }
static void file_change_d(struct branch *b) static void file_change_d(struct branch *b)
{ {
const char *p = command_buf.buf + 2; const char *p = command_buf.buf + 2;
char *p_uq; static struct strbuf uq = STRBUF_INIT;
const char *endp; const char *endp;
p_uq = unquote_c_style(p, &endp); strbuf_reset(&uq);
if (p_uq) { if (!unquote_c_style(&uq, p, &endp)) {
if (*endp) if (*endp)
die("Garbage after path in: %s", command_buf.buf); die("Garbage after path in: %s", command_buf.buf);
p = p_uq; p = uq.buf;
} }
tree_content_remove(&b->branch_tree, p, NULL); tree_content_remove(&b->branch_tree, p, NULL);
free(p_uq);
} }
static void file_change_cr(struct branch *b, int rename) static void file_change_cr(struct branch *b, int rename)
{ {
const char *s, *d; const char *s, *d;
char *s_uq, *d_uq; static struct strbuf s_uq = STRBUF_INIT;
static struct strbuf d_uq = STRBUF_INIT;
const char *endp; const char *endp;
struct tree_entry leaf; struct tree_entry leaf;
s = command_buf.buf + 2; s = command_buf.buf + 2;
s_uq = unquote_c_style(s, &endp); strbuf_reset(&s_uq);
if (s_uq) { if (!unquote_c_style(&s_uq, s, &endp)) {
if (*endp != ' ') if (*endp != ' ')
die("Missing space after source: %s", command_buf.buf); die("Missing space after source: %s", command_buf.buf);
} } else {
else {
endp = strchr(s, ' '); endp = strchr(s, ' ');
if (!endp) if (!endp)
die("Missing space after source: %s", command_buf.buf); die("Missing space after source: %s", command_buf.buf);
s_uq = xmalloc(endp - s + 1); strbuf_add(&s_uq, s, endp - s);
memcpy(s_uq, s, endp - s);
s_uq[endp - s] = 0;
} }
s = s_uq; s = s_uq.buf;
endp++; endp++;
if (!*endp) if (!*endp)
die("Missing dest: %s", command_buf.buf); die("Missing dest: %s", command_buf.buf);
d = endp; d = endp;
d_uq = unquote_c_style(d, &endp); strbuf_reset(&d_uq);
if (d_uq) { if (!unquote_c_style(&d_uq, d, &endp)) {
if (*endp) if (*endp)
die("Garbage after dest in: %s", command_buf.buf); die("Garbage after dest in: %s", command_buf.buf);
d = d_uq; d = d_uq.buf;
} }
memset(&leaf, 0, sizeof(leaf)); memset(&leaf, 0, sizeof(leaf));
@ -1935,9 +1889,6 @@ static void file_change_cr(struct branch *b, int rename)
leaf.versions[1].sha1, leaf.versions[1].sha1,
leaf.versions[1].mode, leaf.versions[1].mode,
leaf.tree); leaf.tree);
free(s_uq);
free(d_uq);
} }
static void file_change_deleteall(struct branch *b) static void file_change_deleteall(struct branch *b)
@ -2062,9 +2013,8 @@ static struct hash_list *cmd_merge(unsigned int *count)
static void cmd_new_commit(void) static void cmd_new_commit(void)
{ {
static struct strbuf msg = STRBUF_INIT;
struct branch *b; struct branch *b;
void *msg;
size_t msglen;
char *sp; char *sp;
char *author = NULL; char *author = NULL;
char *committer = NULL; char *committer = NULL;
@ -2089,7 +2039,7 @@ static void cmd_new_commit(void)
} }
if (!committer) if (!committer)
die("Expected committer but didn't get one"); die("Expected committer but didn't get one");
msg = cmd_data(&msglen); cmd_data(&msg);
read_next_command(); read_next_command();
cmd_from(b); cmd_from(b);
merge_list = cmd_merge(&merge_count); merge_list = cmd_merge(&merge_count);
@ -2101,7 +2051,7 @@ static void cmd_new_commit(void)
} }
/* file_change* */ /* file_change* */
while (!command_buf.eof && command_buf.len > 1) { while (command_buf.len > 0) {
if (!prefixcmp(command_buf.buf, "M ")) if (!prefixcmp(command_buf.buf, "M "))
file_change_m(b); file_change_m(b);
else if (!prefixcmp(command_buf.buf, "D ")) else if (!prefixcmp(command_buf.buf, "D "))
@ -2116,53 +2066,47 @@ static void cmd_new_commit(void)
unread_command_buf = 1; unread_command_buf = 1;
break; break;
} }
read_next_command(); if (read_next_command() == EOF)
break;
} }
/* build the tree and the commit */ /* build the tree and the commit */
store_tree(&b->branch_tree); store_tree(&b->branch_tree);
hashcpy(b->branch_tree.versions[0].sha1, hashcpy(b->branch_tree.versions[0].sha1,
b->branch_tree.versions[1].sha1); b->branch_tree.versions[1].sha1);
size_dbuf(&new_data, 114 + msglen
+ merge_count * 49 strbuf_reset(&new_data);
+ (author strbuf_addf(&new_data, "tree %s\n",
? strlen(author) + strlen(committer)
: 2 * strlen(committer)));
sp = new_data.buffer;
sp += sprintf(sp, "tree %s\n",
sha1_to_hex(b->branch_tree.versions[1].sha1)); sha1_to_hex(b->branch_tree.versions[1].sha1));
if (!is_null_sha1(b->sha1)) if (!is_null_sha1(b->sha1))
sp += sprintf(sp, "parent %s\n", sha1_to_hex(b->sha1)); strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(b->sha1));
while (merge_list) { while (merge_list) {
struct hash_list *next = merge_list->next; struct hash_list *next = merge_list->next;
sp += sprintf(sp, "parent %s\n", sha1_to_hex(merge_list->sha1)); strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(merge_list->sha1));
free(merge_list); free(merge_list);
merge_list = next; merge_list = next;
} }
sp += sprintf(sp, "author %s\n", author ? author : committer); strbuf_addf(&new_data,
sp += sprintf(sp, "committer %s\n", committer); "author %s\n"
*sp++ = '\n'; "committer %s\n"
memcpy(sp, msg, msglen); "\n",
sp += msglen; author ? author : committer, committer);
strbuf_addbuf(&new_data, &msg);
free(author); free(author);
free(committer); free(committer);
free(msg);
if (!store_object(OBJ_COMMIT, if (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark))
new_data.buffer, sp - (char*)new_data.buffer,
NULL, b->sha1, next_mark))
b->pack_id = pack_id; b->pack_id = pack_id;
b->last_commit = object_count_by_type[OBJ_COMMIT]; b->last_commit = object_count_by_type[OBJ_COMMIT];
} }
static void cmd_new_tag(void) static void cmd_new_tag(void)
{ {
static struct strbuf msg = STRBUF_INIT;
char *sp; char *sp;
const char *from; const char *from;
char *tagger; char *tagger;
struct branch *s; struct branch *s;
void *msg;
size_t msglen;
struct tag *t; struct tag *t;
uintmax_t from_mark = 0; uintmax_t from_mark = 0;
unsigned char sha1[20]; unsigned char sha1[20];
@ -2213,24 +2157,21 @@ static void cmd_new_tag(void)
/* tag payload/message */ /* tag payload/message */
read_next_command(); read_next_command();
msg = cmd_data(&msglen); cmd_data(&msg);
/* build the tag object */ /* build the tag object */
size_dbuf(&new_data, 67+strlen(t->name)+strlen(tagger)+msglen); strbuf_reset(&new_data);
sp = new_data.buffer; strbuf_addf(&new_data,
sp += sprintf(sp, "object %s\n", sha1_to_hex(sha1)); "object %s\n"
sp += sprintf(sp, "type %s\n", commit_type); "type %s\n"
sp += sprintf(sp, "tag %s\n", t->name); "tag %s\n"
sp += sprintf(sp, "tagger %s\n", tagger); "tagger %s\n"
*sp++ = '\n'; "\n",
memcpy(sp, msg, msglen); sha1_to_hex(sha1), commit_type, t->name, tagger);
sp += msglen; strbuf_addbuf(&new_data, &msg);
free(tagger); free(tagger);
free(msg);
if (store_object(OBJ_TAG, new_data.buffer, if (store_object(OBJ_TAG, &new_data, NULL, t->sha1, 0))
sp - (char*)new_data.buffer,
NULL, t->sha1, 0))
t->pack_id = MAX_PACK_ID; t->pack_id = MAX_PACK_ID;
else else
t->pack_id = pack_id; t->pack_id = pack_id;
@ -2256,7 +2197,7 @@ static void cmd_reset_branch(void)
else else
b = new_branch(sp); b = new_branch(sp);
read_next_command(); read_next_command();
if (!cmd_from(b) && command_buf.len > 1) if (!cmd_from(b) && command_buf.len > 0)
unread_command_buf = 1; unread_command_buf = 1;
} }
@ -2273,7 +2214,7 @@ static void cmd_checkpoint(void)
static void cmd_progress(void) static void cmd_progress(void)
{ {
fwrite(command_buf.buf, 1, command_buf.len - 1, stdout); fwrite(command_buf.buf, 1, command_buf.len, stdout);
fputc('\n', stdout); fputc('\n', stdout);
fflush(stdout); fflush(stdout);
skip_optional_lf(); skip_optional_lf();
@ -2323,7 +2264,7 @@ int main(int argc, const char **argv)
git_config(git_default_config); git_config(git_default_config);
alloc_objects(object_entry_alloc); alloc_objects(object_entry_alloc);
strbuf_init(&command_buf); strbuf_init(&command_buf, 0);
atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*)); atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*));
branch_table = xcalloc(branch_table_sz, sizeof(struct branch*)); branch_table = xcalloc(branch_table_sz, sizeof(struct branch*));
avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*)); avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*));
@ -2381,11 +2322,8 @@ int main(int argc, const char **argv)
prepare_packed_git(); prepare_packed_git();
start_packfile(); start_packfile();
set_die_routine(die_nicely); set_die_routine(die_nicely);
for (;;) { while (read_next_command() != EOF) {
read_next_command(); if (!strcmp("blob", command_buf.buf))
if (command_buf.eof)
break;
else if (!strcmp("blob", command_buf.buf))
cmd_new_blob(); cmd_new_blob();
else if (!prefixcmp(command_buf.buf, "commit ")) else if (!prefixcmp(command_buf.buf, "commit "))
cmd_new_commit(); cmd_new_commit();

View File

@ -6,7 +6,6 @@
#include "tag.h" #include "tag.h"
#include "blob.h" #include "blob.h"
#include "refs.h" #include "refs.h"
#include "strbuf.h"
int get_tree = 0; int get_tree = 0;
int get_history = 0; int get_history = 0;
@ -218,13 +217,12 @@ int pull_targets_stdin(char ***target, const char ***write_ref)
int targets = 0, targets_alloc = 0; int targets = 0, targets_alloc = 0;
struct strbuf buf; struct strbuf buf;
*target = NULL; *write_ref = NULL; *target = NULL; *write_ref = NULL;
strbuf_init(&buf); strbuf_init(&buf, 0);
while (1) { while (1) {
char *rf_one = NULL; char *rf_one = NULL;
char *tg_one; char *tg_one;
read_line(&buf, stdin, '\n'); if (strbuf_getline(&buf, stdin, '\n') == EOF)
if (buf.eof)
break; break;
tg_one = buf.buf; tg_one = buf.buf;
rf_one = strchr(tg_one, '\t'); rf_one = strchr(tg_one, '\t');
@ -240,6 +238,7 @@ int pull_targets_stdin(char ***target, const char ***write_ref)
(*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL; (*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL;
targets++; targets++;
} }
strbuf_release(&buf);
return targets; return targets;
} }

View File

@ -211,19 +211,20 @@ static inline void *xmalloc(size_t size)
return ret; return ret;
} }
static inline char *xstrndup(const char *str, size_t len) static inline void *xmemdupz(const void *data, size_t len)
{ {
char *p; char *p = xmalloc(len + 1);
memcpy(p, data, len);
p = memchr(str, '\0', len);
if (p)
len = p - str;
p = xmalloc(len + 1);
memcpy(p, str, len);
p[len] = '\0'; p[len] = '\0';
return p; return p;
} }
static inline char *xstrndup(const char *str, size_t len)
{
char *p = memchr(str, '\0', len);
return xmemdupz(str, p ? p - str : len);
}
static inline void *xrealloc(void *ptr, size_t size) static inline void *xrealloc(void *ptr, size_t size)
{ {
void *ret = realloc(ptr, size); void *ret = realloc(ptr, size);

16
git.c
View File

@ -187,19 +187,13 @@ static int handle_alias(int *argcp, const char ***argv)
if (alias_string) { if (alias_string) {
if (alias_string[0] == '!') { if (alias_string[0] == '!') {
if (*argcp > 1) { if (*argcp > 1) {
int i, sz = PATH_MAX; struct strbuf buf;
char *s = xmalloc(sz), *new_alias = s;
add_to_string(&s, &sz, alias_string, 0); strbuf_init(&buf, PATH_MAX);
strbuf_addstr(&buf, alias_string);
sq_quote_argv(&buf, (*argv) + 1, *argcp - 1, PATH_MAX);
free(alias_string); free(alias_string);
alias_string = new_alias; alias_string = buf.buf;
for (i = 1; i < *argcp &&
!add_to_string(&s, &sz, " ", 0) &&
!add_to_string(&s, &sz, (*argv)[i], 1)
; i++)
; /* do nothing */
if (!sz)
die("Too many or long arguments");
} }
trace_printf("trace: alias to shell cmd: %s => %s\n", trace_printf("trace: alias to shell cmd: %s => %s\n",
alias_command, alias_string + 1); alias_command, alias_string + 1);

View File

@ -1271,10 +1271,7 @@ xml_cdata(void *userData, const XML_Char *s, int len)
{ {
struct xml_ctx *ctx = (struct xml_ctx *)userData; struct xml_ctx *ctx = (struct xml_ctx *)userData;
free(ctx->cdata); free(ctx->cdata);
ctx->cdata = xmalloc(len + 1); ctx->cdata = xmemdupz(s, len);
/* NB: 's' is not null-terminated, can not use strlcpy here */
memcpy(ctx->cdata, s, len);
ctx->cdata[len] = '\0';
} }
static struct remote_lock *lock_remote(const char *path, long timeout) static struct remote_lock *lock_remote(const char *path, long timeout)
@ -2172,9 +2169,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
/* If it's a symref, set the refname; otherwise try for a sha1 */ /* If it's a symref, set the refname; otherwise try for a sha1 */
if (!prefixcmp((char *)buffer.buffer, "ref: ")) { if (!prefixcmp((char *)buffer.buffer, "ref: ")) {
*symref = xmalloc(buffer.posn - 5); *symref = xmemdupz((char *)buffer.buffer + 5, buffer.posn - 6);
memcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 6);
(*symref)[buffer.posn - 6] = '\0';
} else { } else {
get_sha1_hex(buffer.buffer, sha1); get_sha1_hex(buffer.buffer, sha1);
} }

View File

@ -105,6 +105,19 @@ static void free_generic_messages( message_t * );
static int nfsnprintf( char *buf, int blen, const char *fmt, ... ); static int nfsnprintf( char *buf, int blen, const char *fmt, ... );
static int nfvasprintf(char **strp, const char *fmt, va_list ap)
{
int len;
char tmp[8192];
len = vsnprintf(tmp, sizeof(tmp), fmt, ap);
if (len < 0)
die("Fatal: Out of memory\n");
if (len >= sizeof(tmp))
die("imap command overflow !\n");
*strp = xmemdupz(tmp, len);
return len;
}
static void arc4_init( void ); static void arc4_init( void );
static unsigned char arc4_getbyte( void ); static unsigned char arc4_getbyte( void );
@ -623,9 +636,7 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level )
goto bail; goto bail;
cur->len = s - p; cur->len = s - p;
s++; s++;
cur->val = xmalloc( cur->len + 1 ); cur->val = xmemdupz(p, cur->len);
memcpy( cur->val, p, cur->len );
cur->val[cur->len] = 0;
} else { } else {
/* atom */ /* atom */
p = s; p = s;
@ -633,12 +644,10 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level )
if (level && *s == ')') if (level && *s == ')')
break; break;
cur->len = s - p; cur->len = s - p;
if (cur->len == 3 && !memcmp ("NIL", p, 3)) if (cur->len == 3 && !memcmp ("NIL", p, 3)) {
cur->val = NIL; cur->val = NIL;
else { } else {
cur->val = xmalloc( cur->len + 1 ); cur->val = xmemdupz(p, cur->len);
memcpy( cur->val, p, cur->len );
cur->val[cur->len] = 0;
} }
} }
@ -1160,28 +1169,18 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
static int static int
read_message( FILE *f, msg_data_t *msg ) read_message( FILE *f, msg_data_t *msg )
{ {
int len, r; struct strbuf buf;
memset( msg, 0, sizeof *msg ); memset(msg, 0, sizeof(*msg));
len = CHUNKSIZE; strbuf_init(&buf, 0);
msg->data = xmalloc( len+1 );
msg->data[0] = 0;
while(!feof( f )) { do {
if (msg->len >= len) { if (strbuf_fread(&buf, CHUNKSIZE, f) <= 0)
void *p;
len += CHUNKSIZE;
p = xrealloc(msg->data, len+1);
if (!p)
break; break;
msg->data = p; } while (!feof(f));
}
r = fread( &msg->data[msg->len], 1, len - msg->len, f ); msg->len = buf.len;
if (r <= 0) msg->data = strbuf_detach(&buf, NULL);
break;
msg->len += r;
}
msg->data[msg->len] = 0;
return msg->len; return msg->len;
} }
@ -1231,13 +1230,7 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs )
if (p) if (p)
msg->len = &p[1] - data; msg->len = &p[1] - data;
msg->data = xmalloc( msg->len + 1 ); msg->data = xmemdupz(data, msg->len);
if (!msg->data)
return 0;
memcpy( msg->data, data, msg->len );
msg->data[ msg->len ] = 0;
*ofs += msg->len; *ofs += msg->len;
return 1; return 1;
} }

View File

@ -44,9 +44,8 @@ void interp_clear_table(struct interp *table, int ninterps)
* { "%%", "%"}, * { "%%", "%"},
* } * }
* *
* Returns 0 on a successful substitution pass that fits in result, * Returns the length of the substituted string (not including the final \0).
* Returns a number of bytes needed to hold the full substituted * Like with snprintf, if the result is >= reslen, then it overflowed.
* string otherwise.
*/ */
unsigned long interpolate(char *result, unsigned long reslen, unsigned long interpolate(char *result, unsigned long reslen,
@ -61,8 +60,6 @@ unsigned long interpolate(char *result, unsigned long reslen,
int i; int i;
char c; char c;
memset(result, 0, reslen);
while ((c = *src)) { while ((c = *src)) {
if (c == '%') { if (c == '%') {
/* Try to match an interpolation string. */ /* Try to match an interpolation string. */
@ -78,9 +75,9 @@ unsigned long interpolate(char *result, unsigned long reslen,
value = interps[i].value; value = interps[i].value;
valuelen = strlen(value); valuelen = strlen(value);
if (newlen + valuelen + 1 < reslen) { if (newlen + valuelen < reslen) {
/* Substitute. */ /* Substitute. */
strncpy(dest, value, valuelen); memcpy(dest, value, valuelen);
dest += valuelen; dest += valuelen;
} }
newlen += valuelen; newlen += valuelen;
@ -95,8 +92,9 @@ unsigned long interpolate(char *result, unsigned long reslen,
newlen++; newlen++;
} }
if (newlen + 1 < reslen) /* XXX: the previous loop always keep room for the ending NUL,
return 0; we just need to check if there was room for a NUL in the first place */
else if (reslen > 0)
return newlen + 2; *dest = '\0';
return newlen;
} }

View File

@ -79,25 +79,14 @@ static int detect_any_signoff(char *letter, int size)
return seen_head && seen_name; return seen_head && seen_name;
} }
static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p, static void append_signoff(struct strbuf *sb, const char *signoff)
unsigned long at, const char *signoff)
{ {
static const char signed_off_by[] = "Signed-off-by: "; static const char signed_off_by[] = "Signed-off-by: ";
size_t signoff_len = strlen(signoff); size_t signoff_len = strlen(signoff);
int has_signoff = 0; int has_signoff = 0;
char *cp; char *cp;
char *buf;
unsigned long buf_sz;
buf = *buf_p; cp = sb->buf;
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 */ /* First see if we already have the sign-off by the signer */
while ((cp = strstr(cp, signed_off_by))) { while ((cp = strstr(cp, signed_off_by))) {
@ -105,29 +94,25 @@ static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,
has_signoff = 1; has_signoff = 1;
cp += strlen(signed_off_by); cp += strlen(signed_off_by);
if (cp + signoff_len >= buf + at) if (cp + signoff_len >= sb->buf + sb->len)
break; break;
if (strncmp(cp, signoff, signoff_len)) if (strncmp(cp, signoff, signoff_len))
continue; continue;
if (!isspace(cp[signoff_len])) if (!isspace(cp[signoff_len]))
continue; continue;
/* we already have him */ /* we already have him */
return at; return;
} }
if (!has_signoff) if (!has_signoff)
has_signoff = detect_any_signoff(buf, at); has_signoff = detect_any_signoff(sb->buf, sb->len);
if (!has_signoff) if (!has_signoff)
buf[at++] = '\n'; strbuf_addch(sb, '\n');
strcpy(buf + at, signed_off_by); strbuf_addstr(sb, signed_off_by);
at += strlen(signed_off_by); strbuf_add(sb, signoff, signoff_len);
strcpy(buf + at, signoff); strbuf_addch(sb, '\n');
at += signoff_len;
buf[at++] = '\n';
buf[at] = 0;
return at;
} }
static unsigned int digits_in_number(unsigned int number) static unsigned int digits_in_number(unsigned int number)
@ -142,14 +127,12 @@ static unsigned int digits_in_number(unsigned int number)
void show_log(struct rev_info *opt, const char *sep) void show_log(struct rev_info *opt, const char *sep)
{ {
char *msgbuf = NULL; struct strbuf msgbuf;
unsigned long msgbuf_len = 0;
struct log_info *log = opt->loginfo; struct log_info *log = opt->loginfo;
struct commit *commit = log->commit, *parent = log->parent; struct commit *commit = log->commit, *parent = log->parent;
int abbrev = opt->diffopt.abbrev; int abbrev = opt->diffopt.abbrev;
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
const char *extra; const char *extra;
int len;
const char *subject = NULL, *extra_headers = opt->extra_headers; const char *subject = NULL, *extra_headers = opt->extra_headers;
opt->loginfo = NULL; opt->loginfo = NULL;
@ -288,18 +271,17 @@ void show_log(struct rev_info *opt, const char *sep)
/* /*
* And then the pretty-printed message itself * And then the pretty-printed message itself
*/ */
len = pretty_print_commit(opt->commit_format, commit, ~0u, strbuf_init(&msgbuf, 0);
&msgbuf, &msgbuf_len, abbrev, subject, pretty_print_commit(opt->commit_format, commit, &msgbuf,
extra_headers, opt->date_mode); abbrev, subject, extra_headers, opt->date_mode);
if (opt->add_signoff) if (opt->add_signoff)
len = append_signoff(&msgbuf, &msgbuf_len, len, append_signoff(&msgbuf, opt->add_signoff);
opt->add_signoff);
if (opt->show_log_size) if (opt->show_log_size)
printf("log size %i\n", len); printf("log size %i\n", (int)msgbuf.len);
printf("%s%s%s", msgbuf, extra, sep); printf("%s%s%s", msgbuf.buf, extra, sep);
free(msgbuf); strbuf_release(&msgbuf);
} }
int log_tree_diff_flush(struct rev_info *opt) int log_tree_diff_flush(struct rev_info *opt)

View File

@ -85,12 +85,6 @@ struct stage_data
unsigned processed:1; unsigned processed:1;
}; };
struct output_buffer
{
struct output_buffer *next;
char *str;
};
static struct path_list current_file_set = {NULL, 0, 0, 1}; static struct path_list current_file_set = {NULL, 0, 0, 1};
static struct path_list current_directory_set = {NULL, 0, 0, 1}; static struct path_list current_directory_set = {NULL, 0, 0, 1};
@ -98,51 +92,52 @@ static int call_depth = 0;
static int verbosity = 2; static int verbosity = 2;
static int rename_limit = -1; static int rename_limit = -1;
static int buffer_output = 1; static int buffer_output = 1;
static struct output_buffer *output_list, *output_end; static struct strbuf obuf = STRBUF_INIT;
static int show(int v) static int show(int v)
{ {
return (!call_depth && verbosity >= v) || verbosity >= 5; return (!call_depth && verbosity >= v) || verbosity >= 5;
} }
static void output(int v, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (buffer_output && show(v)) {
struct output_buffer *b = xmalloc(sizeof(*b));
nfvasprintf(&b->str, fmt, args);
b->next = NULL;
if (output_end)
output_end->next = b;
else
output_list = b;
output_end = b;
} else if (show(v)) {
int i;
for (i = call_depth; i--;)
fputs(" ", stdout);
vfprintf(stdout, fmt, args);
fputc('\n', stdout);
}
va_end(args);
}
static void flush_output(void) static void flush_output(void)
{ {
struct output_buffer *b, *n; if (obuf.len) {
for (b = output_list; b; b = n) { fputs(obuf.buf, stdout);
int i; strbuf_reset(&obuf);
for (i = call_depth; i--;)
fputs(" ", stdout);
fputs(b->str, stdout);
fputc('\n', stdout);
n = b->next;
free(b->str);
free(b);
} }
output_list = NULL; }
output_end = NULL;
static void output(int v, const char *fmt, ...)
{
int len;
va_list ap;
if (!show(v))
return;
strbuf_grow(&obuf, call_depth * 2 + 2);
memset(obuf.buf + obuf.len, ' ', call_depth * 2);
strbuf_setlen(&obuf, obuf.len + call_depth * 2);
va_start(ap, fmt);
len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap);
va_end(ap);
if (len < 0)
len = 0;
if (len >= strbuf_avail(&obuf)) {
strbuf_grow(&obuf, len + 2);
va_start(ap, fmt);
len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap);
va_end(ap);
if (len >= strbuf_avail(&obuf)) {
die("this should not happen, your snprintf is broken");
}
}
strbuf_setlen(&obuf, obuf.len + len);
strbuf_add(&obuf, "\n", 1);
if (!buffer_output)
flush_output();
} }
static void output_commit_title(struct commit *commit) static void output_commit_title(struct commit *commit)
@ -434,19 +429,15 @@ static int update_stages(const char *path, struct diff_filespec *o,
static int remove_path(const char *name) static int remove_path(const char *name)
{ {
int ret, len; int ret;
char *slash, *dirs; char *slash, *dirs;
ret = unlink(name); ret = unlink(name);
if (ret) if (ret)
return ret; return ret;
len = strlen(name); dirs = xstrdup(name);
dirs = xmalloc(len+1);
memcpy(dirs, name, len);
dirs[len] = '\0';
while ((slash = strrchr(name, '/'))) { while ((slash = strrchr(name, '/'))) {
*slash = '\0'; *slash = '\0';
len = slash - name;
if (rmdir(name) != 0) if (rmdir(name) != 0)
break; break;
} }
@ -580,9 +571,7 @@ static void update_file_flags(const unsigned char *sha,
flush_buffer(fd, buf, size); flush_buffer(fd, buf, size);
close(fd); close(fd);
} else if (S_ISLNK(mode)) { } else if (S_ISLNK(mode)) {
char *lnk = xmalloc(size + 1); char *lnk = xmemdupz(buf, size);
memcpy(lnk, buf, size);
lnk[size] = '\0';
mkdir_p(path, 0777); mkdir_p(path, 0777);
unlink(path); unlink(path);
symlink(lnk, path); symlink(lnk, path);
@ -874,14 +863,9 @@ static int read_merge_config(const char *var, const char *value)
if (!strncmp(fn->name, name, namelen) && !fn->name[namelen]) if (!strncmp(fn->name, name, namelen) && !fn->name[namelen])
break; break;
if (!fn) { if (!fn) {
char *namebuf;
fn = xcalloc(1, sizeof(struct ll_merge_driver)); fn = xcalloc(1, sizeof(struct ll_merge_driver));
namebuf = xmalloc(namelen + 1); fn->name = xmemdupz(name, namelen);
memcpy(namebuf, name, namelen);
namebuf[namelen] = 0;
fn->name = namebuf;
fn->fn = ll_ext_merge; fn->fn = ll_ext_merge;
fn->next = NULL;
*ll_user_merge_tail = fn; *ll_user_merge_tail = fn;
ll_user_merge_tail = &(fn->next); ll_user_merge_tail = &(fn->next);
} }

14
mktag.c
View File

@ -111,8 +111,7 @@ static int verify_tag(char *buffer, unsigned long size)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
unsigned long size = 4096; struct strbuf buf;
char *buffer = xmalloc(size);
unsigned char result_sha1[20]; unsigned char result_sha1[20];
if (argc != 1) if (argc != 1)
@ -120,21 +119,20 @@ int main(int argc, char **argv)
setup_git_directory(); setup_git_directory();
if (read_fd(0, &buffer, &size)) { strbuf_init(&buf, 0);
free(buffer); if (strbuf_read(&buf, 0, 4096) < 0) {
die("could not read from stdin"); die("could not read from stdin");
} }
/* Verify it for some basic sanity: it needs to start with /* Verify it for some basic sanity: it needs to start with
"object <sha1>\ntype\ntagger " */ "object <sha1>\ntype\ntagger " */
if (verify_tag(buffer, size) < 0) if (verify_tag(buf.buf, buf.len) < 0)
die("invalid tag signature file"); die("invalid tag signature file");
if (write_sha1_file(buffer, size, tag_type, result_sha1) < 0) if (write_sha1_file(buf.buf, buf.len, tag_type, result_sha1) < 0)
die("unable to write tag file"); die("unable to write tag file");
free(buffer); strbuf_release(&buf);
printf("%s\n", sha1_to_hex(result_sha1)); printf("%s\n", sha1_to_hex(result_sha1));
return 0; return 0;
} }

View File

@ -4,7 +4,6 @@
* Copyright (c) Junio C Hamano, 2006 * Copyright (c) Junio C Hamano, 2006
*/ */
#include "cache.h" #include "cache.h"
#include "strbuf.h"
#include "quote.h" #include "quote.h"
#include "tree.h" #include "tree.h"
@ -44,30 +43,22 @@ static int ent_compare(const void *a_, const void *b_)
static void write_tree(unsigned char *sha1) static void write_tree(unsigned char *sha1)
{ {
char *buffer; struct strbuf buf;
unsigned long size, offset; size_t size;
int i; int i;
qsort(entries, used, sizeof(*entries), ent_compare); qsort(entries, used, sizeof(*entries), ent_compare);
for (size = i = 0; i < used; i++) for (size = i = 0; i < used; i++)
size += 32 + entries[i]->len; size += 32 + entries[i]->len;
buffer = xmalloc(size);
offset = 0;
strbuf_init(&buf, size);
for (i = 0; i < used; i++) { for (i = 0; i < used; i++) {
struct treeent *ent = entries[i]; struct treeent *ent = entries[i];
strbuf_addf(&buf, "%o %s%c", ent->mode, ent->name, '\0');
strbuf_add(&buf, ent->sha1, 20);
}
if (offset + ent->len + 100 < size) { write_sha1_file(buf.buf, buf.len, tree_type, sha1);
size = alloc_nr(offset + ent->len + 100);
buffer = xrealloc(buffer, size);
}
offset += sprintf(buffer + offset, "%o ", ent->mode);
offset += sprintf(buffer + offset, "%s", ent->name);
buffer[offset++] = 0;
hashcpy((unsigned char*)buffer + offset, ent->sha1);
offset += 20;
}
write_sha1_file(buffer, offset, tree_type, sha1);
} }
static const char mktree_usage[] = "git-mktree [-z]"; static const char mktree_usage[] = "git-mktree [-z]";
@ -75,6 +66,7 @@ static const char mktree_usage[] = "git-mktree [-z]";
int main(int ac, char **av) int main(int ac, char **av)
{ {
struct strbuf sb; struct strbuf sb;
struct strbuf p_uq;
unsigned char sha1[20]; unsigned char sha1[20];
int line_termination = '\n'; int line_termination = '\n';
@ -90,18 +82,14 @@ int main(int ac, char **av)
av++; av++;
} }
strbuf_init(&sb); strbuf_init(&sb, 0);
while (1) { strbuf_init(&p_uq, 0);
int len; while (strbuf_getline(&sb, stdin, line_termination) != EOF) {
char *ptr, *ntr; char *ptr, *ntr;
unsigned mode; unsigned mode;
enum object_type type; enum object_type type;
char *path; char *path;
read_line(&sb, stdin, line_termination);
if (sb.eof)
break;
len = sb.len;
ptr = sb.buf; ptr = sb.buf;
/* Input is non-recursive ls-tree output format /* Input is non-recursive ls-tree output format
* mode SP type SP sha1 TAB name * mode SP type SP sha1 TAB name
@ -111,7 +99,7 @@ int main(int ac, char **av)
die("input format error: %s", sb.buf); die("input format error: %s", sb.buf);
ptr = ntr + 1; /* type */ ptr = ntr + 1; /* type */
ntr = strchr(ptr, ' '); ntr = strchr(ptr, ' ');
if (!ntr || sb.buf + len <= ntr + 41 || if (!ntr || sb.buf + sb.len <= ntr + 40 ||
ntr[41] != '\t' || ntr[41] != '\t' ||
get_sha1_hex(ntr + 1, sha1)) get_sha1_hex(ntr + 1, sha1))
die("input format error: %s", sb.buf); die("input format error: %s", sb.buf);
@ -121,17 +109,21 @@ int main(int ac, char **av)
*ntr++ = 0; /* now at the beginning of SHA1 */ *ntr++ = 0; /* now at the beginning of SHA1 */
if (type != type_from_string(ptr)) if (type != type_from_string(ptr))
die("object type %s mismatch (%s)", ptr, typename(type)); die("object type %s mismatch (%s)", ptr, typename(type));
ntr += 41; /* at the beginning of name */
if (line_termination && ntr[0] == '"') path = ntr + 41; /* at the beginning of name */
path = unquote_c_style(ntr, NULL); if (line_termination && path[0] == '"') {
else strbuf_reset(&p_uq);
path = ntr; if (unquote_c_style(&p_uq, path, NULL)) {
die("invalid quoting");
}
path = p_uq.buf;
}
append_to_tree(mode, sha1, path); append_to_tree(mode, sha1, path);
if (path != ntr)
free(path);
} }
strbuf_release(&p_uq);
strbuf_release(&sb);
write_tree(sha1); write_tree(sha1);
puts(sha1_to_hex(sha1)); puts(sha1_to_hex(sha1));
exit(0); exit(0);

375
quote.c
View File

@ -12,37 +12,31 @@
* a'b ==> a'\''b ==> 'a'\''b' * a'b ==> a'\''b ==> 'a'\''b'
* a!b ==> a'\!'b ==> 'a'\!'b' * a!b ==> a'\!'b ==> 'a'\!'b'
*/ */
#undef EMIT
#define EMIT(x) do { if (++len < n) *bp++ = (x); } while(0)
static inline int need_bs_quote(char c) static inline int need_bs_quote(char c)
{ {
return (c == '\'' || c == '!'); return (c == '\'' || c == '!');
} }
static size_t sq_quote_buf(char *dst, size_t n, const char *src) void sq_quote_buf(struct strbuf *dst, const char *src)
{ {
char c; char *to_free = NULL;
char *bp = dst;
size_t len = 0;
EMIT('\''); if (dst->buf == src)
while ((c = *src++)) { to_free = strbuf_detach(dst, NULL);
if (need_bs_quote(c)) {
EMIT('\''); strbuf_addch(dst, '\'');
EMIT('\\'); while (*src) {
EMIT(c); size_t len = strcspn(src, "'\\");
EMIT('\''); strbuf_add(dst, src, len);
} else { src += len;
EMIT(c); while (need_bs_quote(*src)) {
strbuf_addstr(dst, "'\\");
strbuf_addch(dst, *src++);
strbuf_addch(dst, '\'');
} }
} }
EMIT('\''); strbuf_addch(dst, '\'');
free(to_free);
if ( n )
*bp = 0;
return len;
} }
void sq_quote_print(FILE *stream, const char *src) void sq_quote_print(FILE *stream, const char *src)
@ -62,11 +56,10 @@ void sq_quote_print(FILE *stream, const char *src)
fputc('\'', stream); fputc('\'', stream);
} }
char *sq_quote_argv(const char** argv, int count) void sq_quote_argv(struct strbuf *dst, const char** argv, int count,
size_t maxlen)
{ {
char *buf, *to;
int i; int i;
size_t len = 0;
/* Count argv if needed. */ /* Count argv if needed. */
if (count < 0) { if (count < 0) {
@ -74,53 +67,14 @@ char *sq_quote_argv(const char** argv, int count)
; /* just counting */ ; /* just counting */
} }
/* Special case: no argv. */
if (!count)
return xcalloc(1,1);
/* Get destination buffer length. */
for (i = 0; i < count; i++)
len += sq_quote_buf(NULL, 0, argv[i]) + 1;
/* Alloc destination buffer. */
to = buf = xmalloc(len + 1);
/* Copy into destination buffer. */ /* Copy into destination buffer. */
strbuf_grow(dst, 32 * count);
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
*to++ = ' '; strbuf_addch(dst, ' ');
to += sq_quote_buf(to, len, argv[i]); sq_quote_buf(dst, argv[i]);
if (maxlen && dst->len > maxlen)
die("Too many or long arguments");
} }
return buf;
}
/*
* Append a string to a string buffer, with or without shell quoting.
* Return true if the buffer overflowed.
*/
int add_to_string(char **ptrp, int *sizep, const char *str, int quote)
{
char *p = *ptrp;
int size = *sizep;
int oc;
int err = 0;
if (quote)
oc = sq_quote_buf(p, size, str);
else {
oc = strlen(str);
memcpy(p, str, (size <= oc) ? size - 1 : oc);
}
if (size <= oc) {
err = 1;
oc = size - 1;
}
*ptrp += oc;
**ptrp = '\0';
*sizep -= oc;
return err;
} }
char *sq_dequote(char *arg) char *sq_dequote(char *arg)
@ -157,111 +111,182 @@ char *sq_dequote(char *arg)
} }
} }
/* 1 means: quote as octal
* 0 means: quote as octal if (quote_path_fully)
* -1 means: never quote
* c: quote as "\\c"
*/
#define X8(x) x, x, x, x, x, x, x, x
#define X16(x) X8(x), X8(x)
static signed char const sq_lookup[256] = {
/* 0 1 2 3 4 5 6 7 */
/* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a',
/* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1,
/* 0x10 */ X16(1),
/* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1,
/* 0x28 */ X16(-1), X16(-1), X16(-1),
/* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1,
/* 0x60 */ X16(-1), X8(-1),
/* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1,
/* 0x80 */ /* set to 0 */
};
static inline int sq_must_quote(char c) {
return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
}
/* returns the longest prefix not needing a quote up to maxlen if positive.
This stops at the first \0 because it's marked as a character needing an
escape */
static size_t next_quote_pos(const char *s, ssize_t maxlen)
{
size_t len;
if (maxlen < 0) {
for (len = 0; !sq_must_quote(s[len]); len++);
} else {
for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
}
return len;
}
/* /*
* C-style name quoting. * C-style name quoting.
* *
* Does one of three things: * (1) if sb and fp are both NULL, inspect the input name and counts the
* number of bytes that are needed to hold c_style quoted version of name,
* counting the double quotes around it but not terminating NUL, and
* returns it.
* However, if name does not need c_style quoting, it returns 0.
* *
* (1) if outbuf and outfp are both NULL, inspect the input name and * (2) if sb or fp are not NULL, it emits the c_style quoted version
* counts the number of bytes that are needed to hold c_style * of name, enclosed with double quotes if asked and needed only.
* quoted version of name, counting the double quotes around * Return value is the same as in (1).
* it but not terminating NUL, and returns it. However, if name
* does not need c_style quoting, it returns 0.
*
* (2) if outbuf is not NULL, it must point at a buffer large enough
* to hold the c_style quoted version of name, enclosing double
* quotes, and terminating NUL. Fills outbuf with c_style quoted
* version of name enclosed in double-quote pair. Return value
* is undefined.
*
* (3) if outfp is not NULL, outputs c_style quoted version of name,
* but not enclosed in double-quote pair. Return value is undefined.
*/ */
static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
static int quote_c_style_counted(const char *name, int namelen, struct strbuf *sb, FILE *fp, int no_dq)
char *outbuf, FILE *outfp, int no_dq)
{ {
#undef EMIT #undef EMIT
#define EMIT(c) \ #define EMIT(c) \
(outbuf ? (*outbuf++ = (c)) : outfp ? fputc(c, outfp) : (count++)) do { \
if (sb) strbuf_addch(sb, (c)); \
if (fp) fputc((c), fp); \
count++; \
} while (0)
#define EMITBUF(s, l) \
do { \
if (sb) strbuf_add(sb, (s), (l)); \
if (fp) fwrite((s), (l), 1, fp); \
count += (l); \
} while (0)
#define EMITQ() EMIT('\\') size_t len, count = 0;
const char *p = name;
const char *sp; for (;;) {
unsigned char ch; int ch;
int count = 0, needquote = 0;
if (!no_dq) len = next_quote_pos(p, maxlen);
EMIT('"'); if (len == maxlen || !p[len])
for (sp = name; sp < name + namelen; sp++) {
ch = *sp;
if (!ch)
break; break;
if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
(quote_path_fully && (ch >= 0177))) {
needquote = 1;
switch (ch) {
case '\a': EMITQ(); ch = 'a'; break;
case '\b': EMITQ(); ch = 'b'; break;
case '\f': EMITQ(); ch = 'f'; break;
case '\n': EMITQ(); ch = 'n'; break;
case '\r': EMITQ(); ch = 'r'; break;
case '\t': EMITQ(); ch = 't'; break;
case '\v': EMITQ(); ch = 'v'; break;
case '\\': /* fallthru */ if (!no_dq && p == name)
case '"': EMITQ(); break; EMIT('"');
default:
/* octal */ EMITBUF(p, len);
EMITQ(); EMIT('\\');
p += len;
ch = (unsigned char)*p++;
if (sq_lookup[ch] >= ' ') {
EMIT(sq_lookup[ch]);
} else {
EMIT(((ch >> 6) & 03) + '0'); EMIT(((ch >> 6) & 03) + '0');
EMIT(((ch >> 3) & 07) + '0'); EMIT(((ch >> 3) & 07) + '0');
ch = (ch & 07) + '0'; EMIT(((ch >> 0) & 07) + '0');
break;
} }
} }
EMIT(ch);
} EMITBUF(p, len);
if (p == name) /* no ending quote needed */
return 0;
if (!no_dq) if (!no_dq)
EMIT('"'); EMIT('"');
if (outbuf) return count;
*outbuf = 0;
return needquote ? count : 0;
} }
int quote_c_style(const char *name, char *outbuf, FILE *outfp, int no_dq) size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
{ {
int cnt = strlen(name); return quote_c_style_counted(name, -1, sb, fp, nodq);
return quote_c_style_counted(name, cnt, outbuf, outfp, no_dq); }
void write_name_quoted(const char *name, FILE *fp, int terminator)
{
if (terminator) {
quote_c_style(name, NULL, fp, 0);
} else {
fputs(name, fp);
}
fputc(terminator, fp);
}
extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
const char *name, FILE *fp, int terminator)
{
int needquote = 0;
if (terminator) {
needquote = next_quote_pos(pfx, pfxlen) < pfxlen
|| name[next_quote_pos(name, -1)];
}
if (needquote) {
fputc('"', fp);
quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
quote_c_style(name, NULL, fp, 1);
fputc('"', fp);
} else {
fwrite(pfx, pfxlen, 1, fp);
fputs(name, fp);
}
fputc(terminator, fp);
} }
/* /*
* C-style name unquoting. * C-style name unquoting.
* *
* Quoted should point at the opening double quote. Returns * Quoted should point at the opening double quote.
* an allocated memory that holds unquoted name, which the caller * + Returns 0 if it was able to unquote the string properly, and appends the
* should free when done. Updates endp pointer to point at * result in the strbuf `sb'.
* one past the ending double quote if given. * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
* that this function will allocate memory in the strbuf, so calling
* strbuf_release is mandatory whichever result unquote_c_style returns.
*
* Updates endp pointer to point at one past the ending double quote if given.
*/ */
int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
char *unquote_c_style(const char *quoted, const char **endp)
{ {
const char *sp; size_t oldlen = sb->len, len;
char *name = NULL, *outp = NULL; int ch, ac;
int count = 0, ch, ac;
#undef EMIT
#define EMIT(c) (outp ? (*outp++ = (c)) : (count++))
if (*quoted++ != '"') if (*quoted++ != '"')
return NULL; return -1;
while (1) { for (;;) {
/* first pass counts and allocates, second pass fills */ len = strcspn(quoted, "\"\\");
for (sp = quoted; (ch = *sp++) != '"'; ) { strbuf_add(sb, quoted, len);
if (ch == '\\') { quoted += len;
switch (ch = *sp++) {
switch (*quoted++) {
case '"':
if (endp)
*endp = quoted + 1;
return 0;
case '\\':
break;
default:
goto error;
}
switch ((ch = *quoted++)) {
case 'a': ch = '\a'; break; case 'a': ch = '\a'; break;
case 'b': ch = '\b'; break; case 'b': ch = '\b'; break;
case 'f': ch = '\f'; break; case 'f': ch = '\f'; break;
@ -273,70 +298,26 @@ char *unquote_c_style(const char *quoted, const char **endp)
case '\\': case '"': case '\\': case '"':
break; /* verbatim */ break; /* verbatim */
case '0': /* octal values with first digit over 4 overflow */
case '1': case '0': case '1': case '2': case '3':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
/* octal */
ac = ((ch - '0') << 6); ac = ((ch - '0') << 6);
if ((ch = *sp++) < '0' || '7' < ch) if ((ch = *quoted++) < '0' || '7' < ch)
return NULL; goto error;
ac |= ((ch - '0') << 3); ac |= ((ch - '0') << 3);
if ((ch = *sp++) < '0' || '7' < ch) if ((ch = *quoted++) < '0' || '7' < ch)
return NULL; goto error;
ac |= (ch - '0'); ac |= (ch - '0');
ch = ac; ch = ac;
break; break;
default: default:
return NULL; /* malformed */ goto error;
} }
} strbuf_addch(sb, ch);
EMIT(ch);
} }
if (name) { error:
*outp = 0; strbuf_setlen(sb, oldlen);
if (endp) return -1;
*endp = sp;
return name;
}
outp = name = xmalloc(count + 1);
}
}
void write_name_quoted(const char *prefix, int prefix_len,
const char *name, int quote, FILE *out)
{
int needquote;
if (!quote) {
no_quote:
if (prefix_len)
fprintf(out, "%.*s", prefix_len, prefix);
fputs(name, out);
return;
}
needquote = 0;
if (prefix_len)
needquote = quote_c_style_counted(prefix, prefix_len,
NULL, NULL, 0);
if (!needquote)
needquote = quote_c_style(name, NULL, NULL, 0);
if (needquote) {
fputc('"', out);
if (prefix_len)
quote_c_style_counted(prefix, prefix_len,
NULL, out, 1);
quote_c_style(name, NULL, out, 1);
fputc('"', out);
}
else
goto no_quote;
} }
/* quoting as a string literal for other languages */ /* quoting as a string literal for other languages */

19
quote.h
View File

@ -29,13 +29,10 @@
*/ */
extern void sq_quote_print(FILE *stream, const char *src); extern void sq_quote_print(FILE *stream, const char *src);
extern char *sq_quote_argv(const char** argv, int count);
/* extern void sq_quote_buf(struct strbuf *, const char *src);
* Append a string to a string buffer, with or without shell quoting. extern void sq_quote_argv(struct strbuf *, const char **argv, int count,
* Return true if the buffer overflowed. size_t maxlen);
*/
extern int add_to_string(char **ptrp, int *sizep, const char *str, int quote);
/* This unwraps what sq_quote() produces in place, but returns /* This unwraps what sq_quote() produces in place, but returns
* NULL if the input does not look like what sq_quote would have * NULL if the input does not look like what sq_quote would have
@ -43,12 +40,12 @@ extern int add_to_string(char **ptrp, int *sizep, const char *str, int quote);
*/ */
extern char *sq_dequote(char *); extern char *sq_dequote(char *);
extern int quote_c_style(const char *name, char *outbuf, FILE *outfp, extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp);
int nodq); extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq);
extern char *unquote_c_style(const char *quoted, const char **endp);
extern void write_name_quoted(const char *prefix, int prefix_len, extern void write_name_quoted(const char *name, FILE *, int terminator);
const char *name, int quote, FILE *out); extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
const char *name, FILE *, int terminator);
/* quoting as a string literal for other languages */ /* quoting as a string literal for other languages */
extern void perl_quote_print(FILE *stream, const char *src); extern void perl_quote_print(FILE *stream, const char *src);

View File

@ -1136,7 +1136,7 @@ int write_index(struct index_state *istate, int newfd)
{ {
SHA_CTX c; SHA_CTX c;
struct cache_header hdr; struct cache_header hdr;
int i, removed; int i, err, removed;
struct cache_entry **cache = istate->cache; struct cache_entry **cache = istate->cache;
int entries = istate->cache_nr; int entries = istate->cache_nr;
@ -1165,16 +1165,15 @@ int write_index(struct index_state *istate, int newfd)
/* Write extension data here */ /* Write extension data here */
if (istate->cache_tree) { if (istate->cache_tree) {
unsigned long sz; struct strbuf sb;
void *data = cache_tree_write(istate->cache_tree, &sz);
if (data && strbuf_init(&sb, 0);
!write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) && cache_tree_write(&sb, istate->cache_tree);
!ce_write(&c, newfd, data, sz)) err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0
free(data); || ce_write(&c, newfd, sb.buf, sb.len) < 0;
else { strbuf_release(&sb);
free(data); if (err)
return -1; return -1;
} }
}
return ce_flush(&c, newfd); return ce_flush(&c, newfd);
} }

12
refs.c
View File

@ -1246,15 +1246,11 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
static char *ref_msg(const char *line, const char *endp) static char *ref_msg(const char *line, const char *endp)
{ {
const char *ep; const char *ep;
char *msg;
line += 82; line += 82;
for (ep = line; ep < endp && *ep != '\n'; ep++) ep = memchr(line, '\n', endp - line);
; if (!ep)
msg = xmalloc(ep - line + 1); ep = endp;
memcpy(msg, line, ep - line); return xmemdupz(line, ep - line);
msg[ep - line] = 0;
return msg;
} }
int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1, char **msg, unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt) int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1, char **msg, unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)

30
rsh.c
View File

@ -10,12 +10,9 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
char *host; char *host;
char *path; char *path;
int sv[2]; int sv[2];
char command[COMMAND_SIZE];
char *posn;
int sizen;
int of;
int i; int i;
pid_t pid; pid_t pid;
struct strbuf cmd;
if (!strcmp(url, "-")) { if (!strcmp(url, "-")) {
*fd_in = 0; *fd_in = 0;
@ -36,24 +33,23 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
if (!path) { if (!path) {
return error("Bad URL: %s", url); return error("Bad URL: %s", url);
} }
/* $GIT_RSH <host> "env GIT_DIR=<path> <remote_prog> <args...>" */ /* $GIT_RSH <host> "env GIT_DIR=<path> <remote_prog> <args...>" */
sizen = COMMAND_SIZE; strbuf_init(&cmd, COMMAND_SIZE);
posn = command; strbuf_addstr(&cmd, "env ");
of = 0; strbuf_addstr(&cmd, GIT_DIR_ENVIRONMENT "=");
of |= add_to_string(&posn, &sizen, "env ", 0); sq_quote_buf(&cmd, path);
of |= add_to_string(&posn, &sizen, GIT_DIR_ENVIRONMENT "=", 0); strbuf_addch(&cmd, ' ');
of |= add_to_string(&posn, &sizen, path, 1); sq_quote_buf(&cmd, remote_prog);
of |= add_to_string(&posn, &sizen, " ", 0);
of |= add_to_string(&posn, &sizen, remote_prog, 1);
for (i = 0 ; i < rmt_argc ; i++) { for (i = 0 ; i < rmt_argc ; i++) {
of |= add_to_string(&posn, &sizen, " ", 0); strbuf_addch(&cmd, ' ');
of |= add_to_string(&posn, &sizen, rmt_argv[i], 1); sq_quote_buf(&cmd, rmt_argv[i]);
} }
of |= add_to_string(&posn, &sizen, " -", 0); strbuf_addstr(&cmd, " -");
if ( of ) if (cmd.len >= COMMAND_SIZE)
return error("Command line too long"); return error("Command line too long");
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
@ -74,7 +70,7 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
close(sv[1]); close(sv[1]);
dup2(sv[0], 0); dup2(sv[0], 0);
dup2(sv[0], 1); dup2(sv[0], 1);
execlp(ssh, ssh_basename, host, command, NULL); execlp(ssh, ssh_basename, host, cmd.buf, NULL);
} }
close(sv[0]); close(sv[0]);
*fd_in = sv[1]; *fd_in = sv[1];

View File

@ -1491,11 +1491,8 @@ found_cache_entry:
ent->lru.next->prev = ent->lru.prev; ent->lru.next->prev = ent->lru.prev;
ent->lru.prev->next = ent->lru.next; ent->lru.prev->next = ent->lru.next;
delta_base_cached -= ent->size; delta_base_cached -= ent->size;
} } else {
else { ret = xmemdupz(ent->data, ent->size);
ret = xmalloc(ent->size + 1);
memcpy(ret, ent->data, ent->size);
((char *)ret)[ent->size] = 0;
} }
*type = ent->type; *type = ent->type;
*base_size = ent->size; *base_size = ent->size;
@ -1872,12 +1869,9 @@ void *read_sha1_file(const unsigned char *sha1, enum object_type *type,
co = find_cached_object(sha1); co = find_cached_object(sha1);
if (co) { if (co) {
buf = xmalloc(co->size + 1);
memcpy(buf, co->buf, co->size);
((char*)buf)[co->size] = 0;
*type = co->type; *type = co->type;
*size = co->size; *size = co->size;
return buf; return xmemdupz(co->buf, co->size);
} }
buf = read_packed_sha1(sha1, type, size); buf = read_packed_sha1(sha1, type, size);
@ -2302,68 +2296,25 @@ int has_sha1_file(const unsigned char *sha1)
return find_sha1_file(sha1, &st) ? 1 : 0; return find_sha1_file(sha1, &st) ? 1 : 0;
} }
/*
* reads from fd as long as possible into a supplied buffer of size bytes.
* If necessary the buffer's size is increased using realloc()
*
* returns 0 if anything went fine and -1 otherwise
*
* The buffer is always NUL-terminated, not including it in returned size.
*
* NOTE: both buf and size may change, but even when -1 is returned
* you still have to free() it yourself.
*/
int read_fd(int fd, char **return_buf, unsigned long *return_size)
{
char *buf = *return_buf;
unsigned long size = *return_size;
ssize_t iret;
unsigned long off = 0;
if (!buf || size <= 1) {
size = 1024;
buf = xrealloc(buf, size);
}
do {
iret = xread(fd, buf + off, (size - 1) - off);
if (iret > 0) {
off += iret;
if (off == size - 1) {
size = alloc_nr(size);
buf = xrealloc(buf, size);
}
}
} while (iret > 0);
buf[off] = '\0';
*return_buf = buf;
*return_size = off;
if (iret < 0)
return -1;
return 0;
}
int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object) int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
{ {
unsigned long size = 4096; struct strbuf buf;
char *buf = xmalloc(size);
int ret; int ret;
if (read_fd(fd, &buf, &size)) { strbuf_init(&buf, 0);
free(buf); if (strbuf_read(&buf, fd, 4096) < 0) {
strbuf_release(&buf);
return -1; return -1;
} }
if (!type) if (!type)
type = blob_type; type = blob_type;
if (write_object) if (write_object)
ret = write_sha1_file(buf, size, type, sha1); ret = write_sha1_file(buf.buf, buf.len, type, sha1);
else else
ret = hash_sha1_file(buf, size, type, sha1); ret = hash_sha1_file(buf.buf, buf.len, type, sha1);
free(buf); strbuf_release(&buf);
return ret; return ret;
} }
@ -2385,12 +2336,11 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
* Convert blobs to git internal format * Convert blobs to git internal format
*/ */
if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) { if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) {
unsigned long nsize = size; struct strbuf nbuf;
char *nbuf = convert_to_git(path, buf, &nsize); strbuf_init(&nbuf, 0);
if (nbuf) { if (convert_to_git(path, buf, size, &nbuf)) {
munmap(buf, size); munmap(buf, size);
size = nsize; buf = strbuf_detach(&nbuf, &size);
buf = nbuf;
re_allocated = 1; re_allocated = 1;
} }
} }

207
strbuf.c
View File

@ -1,41 +1,202 @@
#include "cache.h" #include "cache.h"
#include "strbuf.h"
void strbuf_init(struct strbuf *sb) { /*
sb->buf = NULL; * Used as the default ->buf value, so that people can always assume
sb->eof = sb->alloc = sb->len = 0; * buf is non NULL and ->buf is NUL terminated even for a freshly
* initialized strbuf.
*/
char strbuf_slopbuf[1];
void strbuf_init(struct strbuf *sb, size_t hint)
{
sb->alloc = sb->len = 0;
sb->buf = strbuf_slopbuf;
if (hint)
strbuf_grow(sb, hint);
} }
static void strbuf_begin(struct strbuf *sb) { void strbuf_release(struct strbuf *sb)
{
if (sb->alloc) {
free(sb->buf); free(sb->buf);
strbuf_init(sb); strbuf_init(sb, 0);
}
} }
static void inline strbuf_add(struct strbuf *sb, int ch) { char *strbuf_detach(struct strbuf *sb, size_t *sz)
if (sb->alloc <= sb->len) { {
sb->alloc = sb->alloc * 3 / 2 + 16; char *res = sb->alloc ? sb->buf : NULL;
sb->buf = xrealloc(sb->buf, sb->alloc); if (sz)
} *sz = sb->len;
sb->buf[sb->len++] = ch; strbuf_init(sb, 0);
return res;
} }
static void strbuf_end(struct strbuf *sb) { void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
strbuf_add(sb, 0); {
strbuf_release(sb);
sb->buf = buf;
sb->len = len;
sb->alloc = alloc;
strbuf_grow(sb, 0);
sb->buf[sb->len] = '\0';
} }
void read_line(struct strbuf *sb, FILE *fp, int term) { void strbuf_grow(struct strbuf *sb, size_t extra)
{
if (sb->len + extra + 1 <= sb->len)
die("you want to use way too much memory");
if (!sb->alloc)
sb->buf = NULL;
ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
}
void strbuf_rtrim(struct strbuf *sb)
{
while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
sb->len--;
sb->buf[sb->len] = '\0';
}
int strbuf_cmp(struct strbuf *a, struct strbuf *b)
{
int cmp;
if (a->len < b->len) {
cmp = memcmp(a->buf, b->buf, a->len);
return cmp ? cmp : -1;
} else {
cmp = memcmp(a->buf, b->buf, b->len);
return cmp ? cmp : a->len != b->len;
}
}
void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
const void *data, size_t dlen)
{
if (pos + len < pos)
die("you want to use way too much memory");
if (pos > sb->len)
die("`pos' is too far after the end of the buffer");
if (pos + len > sb->len)
die("`pos + len' is too far after the end of the buffer");
if (dlen >= len)
strbuf_grow(sb, dlen - len);
memmove(sb->buf + pos + dlen,
sb->buf + pos + len,
sb->len - pos - len);
memcpy(sb->buf + pos, data, dlen);
strbuf_setlen(sb, sb->len + dlen - len);
}
void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
{
strbuf_splice(sb, pos, 0, data, len);
}
void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
{
strbuf_splice(sb, pos, len, NULL, 0);
}
void strbuf_add(struct strbuf *sb, const void *data, size_t len)
{
strbuf_grow(sb, len);
memcpy(sb->buf + sb->len, data, len);
strbuf_setlen(sb, sb->len + len);
}
void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
{
int len;
va_list ap;
va_start(ap, fmt);
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len < 0) {
len = 0;
}
if (len > strbuf_avail(sb)) {
strbuf_grow(sb, len);
va_start(ap, fmt);
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len > strbuf_avail(sb)) {
die("this should not happen, your snprintf is broken");
}
}
strbuf_setlen(sb, sb->len + len);
}
size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
{
size_t res;
strbuf_grow(sb, size);
res = fread(sb->buf + sb->len, 1, size, f);
if (res > 0) {
strbuf_setlen(sb, sb->len + res);
}
return res;
}
ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
{
size_t oldlen = sb->len;
strbuf_grow(sb, hint ? hint : 8192);
for (;;) {
ssize_t cnt;
cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
if (cnt < 0) {
strbuf_setlen(sb, oldlen);
return -1;
}
if (!cnt)
break;
sb->len += cnt;
strbuf_grow(sb, 8192);
}
sb->buf[sb->len] = '\0';
return sb->len - oldlen;
}
int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
{
int ch; int ch;
strbuf_begin(sb);
if (feof(fp)) { strbuf_grow(sb, 0);
sb->eof = 1; if (feof(fp))
return; return EOF;
}
strbuf_reset(sb);
while ((ch = fgetc(fp)) != EOF) { while ((ch = fgetc(fp)) != EOF) {
if (ch == term) if (ch == term)
break; break;
strbuf_add(sb, ch); strbuf_grow(sb, 1);
sb->buf[sb->len++] = ch;
} }
if (ch == EOF && sb->len == 0) if (ch == EOF && sb->len == 0)
sb->eof = 1; return EOF;
strbuf_end(sb);
sb->buf[sb->len] = '\0';
return 0;
}
int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
{
int fd, len;
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
len = strbuf_read(sb, fd, hint);
close(fd);
if (len < 0)
return -1;
return len;
} }

114
strbuf.h
View File

@ -1,13 +1,117 @@
#ifndef STRBUF_H #ifndef STRBUF_H
#define STRBUF_H #define STRBUF_H
/*
* Strbuf's can be use in many ways: as a byte array, or to store arbitrary
* long, overflow safe strings.
*
* Strbufs has some invariants that are very important to keep in mind:
*
* 1. the ->buf member is always malloc-ed, hence strbuf's can be used to
* build complex strings/buffers whose final size isn't easily known.
*
* It is NOT legal to copy the ->buf pointer away.
* `strbuf_detach' is the operation that detachs a buffer from its shell
* while keeping the shell valid wrt its invariants.
*
* 2. the ->buf member is a byte array that has at least ->len + 1 bytes
* allocated. The extra byte is used to store a '\0', allowing the ->buf
* member to be a valid C-string. Every strbuf function ensure this
* invariant is preserved.
*
* Note that it is OK to "play" with the buffer directly if you work it
* that way:
*
* strbuf_grow(sb, SOME_SIZE);
* // ... here the memory areay starting at sb->buf, and of length
* // sb_avail(sb) is all yours, and you are sure that sb_avail(sb) is at
* // least SOME_SIZE
* strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
*
* Of course, SOME_OTHER_SIZE must be smaller or equal to sb_avail(sb).
*
* Doing so is safe, though if it has to be done in many places, adding the
* missing API to the strbuf module is the way to go.
*
* XXX: do _not_ assume that the area that is yours is of size ->alloc - 1
* even if it's true in the current implementation. Alloc is somehow a
* "private" member that should not be messed with.
*/
#include <assert.h>
extern char strbuf_slopbuf[];
struct strbuf { struct strbuf {
int alloc; size_t alloc;
int len; size_t len;
int eof;
char *buf; char *buf;
}; };
extern void strbuf_init(struct strbuf *); #define STRBUF_INIT { 0, 0, strbuf_slopbuf }
extern void read_line(struct strbuf *, FILE *, int);
/*----- strbuf life cycle -----*/
extern void strbuf_init(struct strbuf *, size_t);
extern void strbuf_release(struct strbuf *);
extern char *strbuf_detach(struct strbuf *, size_t *);
extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
struct strbuf tmp = *a;
*a = *b;
*b = tmp;
}
/*----- strbuf size related -----*/
static inline size_t strbuf_avail(struct strbuf *sb) {
return sb->alloc ? sb->alloc - sb->len - 1 : 0;
}
extern void strbuf_grow(struct strbuf *, size_t);
static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
if (!sb->alloc)
strbuf_grow(sb, 0);
assert(len < sb->alloc);
sb->len = len;
sb->buf[len] = '\0';
}
#define strbuf_reset(sb) strbuf_setlen(sb, 0)
/*----- content related -----*/
extern void strbuf_rtrim(struct strbuf *);
extern int strbuf_cmp(struct strbuf *, struct strbuf *);
/*----- add data in your buffer -----*/
static inline void strbuf_addch(struct strbuf *sb, int c) {
strbuf_grow(sb, 1);
sb->buf[sb->len++] = c;
sb->buf[sb->len] = '\0';
}
extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
/* splice pos..pos+len with given data */
extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
const void *, size_t);
extern void strbuf_add(struct strbuf *, const void *, size_t);
static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
strbuf_add(sb, s, strlen(s));
}
static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
strbuf_add(sb, sb2->buf, sb2->len);
}
__attribute__((format(printf,2,3)))
extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
/* XXX: if read fails, any partial read is undone */
extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
extern int strbuf_getline(struct strbuf *, FILE *, int);
extern void stripspace(struct strbuf *buf, int skip_comments);
#endif /* STRBUF_H */ #endif /* STRBUF_H */

View File

@ -36,7 +36,8 @@ test_expect_success \
echo simple textfile >a/a && echo simple textfile >a/a &&
mkdir a/bin && mkdir a/bin &&
cp /bin/sh a/bin && cp /bin/sh a/bin &&
printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile && printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
printf "A not substituted O" >a/substfile2 &&
ln -s a a/l1 && ln -s a a/l1 &&
(p=long_path_to_a_file && cd a && (p=long_path_to_a_file && cd a &&
for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done &&
@ -108,20 +109,22 @@ test_expect_success \
'diff -r a c/prefix/a' 'diff -r a c/prefix/a'
test_expect_success \ test_expect_success \
'create an archive with a substfile' \ 'create an archive with a substfiles' \
'echo substfile export-subst >a/.gitattributes && 'echo "substfile?" export-subst >a/.gitattributes &&
git archive HEAD >f.tar && git archive HEAD >f.tar &&
rm a/.gitattributes' rm a/.gitattributes'
test_expect_success \ test_expect_success \
'extract substfile' \ 'extract substfiles' \
'(mkdir f && cd f && $TAR xf -) <f.tar' '(mkdir f && cd f && $TAR xf -) <f.tar'
test_expect_success \ test_expect_success \
'validate substfile contents' \ 'validate substfile contents' \
'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \ 'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
>f/a/substfile.expected && >f/a/substfile1.expected &&
diff f/a/substfile.expected f/a/substfile' diff f/a/substfile1.expected f/a/substfile1 &&
diff a/substfile2 f/a/substfile2
'
test_expect_success \ test_expect_success \
'git archive --format=zip' \ 'git archive --format=zip' \

4
tag.c
View File

@ -68,9 +68,7 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
memcpy(type, type_line + 5, typelen); memcpy(type, type_line + 5, typelen);
type[typelen] = '\0'; type[typelen] = '\0';
taglen = sig_line - tag_line - strlen("tag \n"); taglen = sig_line - tag_line - strlen("tag \n");
item->tag = xmalloc(taglen + 1); item->tag = xmemdupz(tag_line + 4, taglen);
memcpy(item->tag, tag_line + 4, taglen);
item->tag[taglen] = '\0';
if (!strcmp(type, blob_type)) { if (!strcmp(type, blob_type)) {
item->tagged = &lookup_blob(sha1)->object; item->tagged = &lookup_blob(sha1)->object;

109
trace.c
View File

@ -25,33 +25,6 @@
#include "cache.h" #include "cache.h"
#include "quote.h" #include "quote.h"
/* Stolen from "imap-send.c". */
int nfvasprintf(char **strp, const char *fmt, va_list ap)
{
int len;
char tmp[1024];
if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 ||
!(*strp = xmalloc(len + 1)))
die("Fatal: Out of memory\n");
if (len >= (int)sizeof(tmp))
vsprintf(*strp, fmt, ap);
else
memcpy(*strp, tmp, len + 1);
return len;
}
int nfasprintf(char **str, const char *fmt, ...)
{
int rc;
va_list args;
va_start(args, fmt);
rc = nfvasprintf(str, fmt, args);
va_end(args);
return rc;
}
/* Get a trace file descriptor from GIT_TRACE env variable. */ /* Get a trace file descriptor from GIT_TRACE env variable. */
static int get_trace_fd(int *need_close) static int get_trace_fd(int *need_close)
{ {
@ -89,63 +62,65 @@ static int get_trace_fd(int *need_close)
static const char err_msg[] = "Could not trace into fd given by " static const char err_msg[] = "Could not trace into fd given by "
"GIT_TRACE environment variable"; "GIT_TRACE environment variable";
void trace_printf(const char *format, ...) void trace_printf(const char *fmt, ...)
{ {
char *trace_str; struct strbuf buf;
va_list rest; va_list ap;
int need_close = 0; int fd, len, need_close = 0;
int fd = get_trace_fd(&need_close);
fd = get_trace_fd(&need_close);
if (!fd) if (!fd)
return; return;
va_start(rest, format); strbuf_init(&buf, 0);
nfvasprintf(&trace_str, format, rest); va_start(ap, fmt);
va_end(rest); len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
va_end(ap);
if (len >= strbuf_avail(&buf)) {
strbuf_grow(&buf, len - strbuf_avail(&buf) + 128);
va_start(ap, fmt);
len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
va_end(ap);
if (len >= strbuf_avail(&buf))
die("broken vsnprintf");
}
strbuf_setlen(&buf, len);
write_or_whine_pipe(fd, trace_str, strlen(trace_str), err_msg); write_or_whine_pipe(fd, buf.buf, buf.len, err_msg);
strbuf_release(&buf);
free(trace_str);
if (need_close) if (need_close)
close(fd); close(fd);
} }
void trace_argv_printf(const char **argv, int count, const char *format, ...) void trace_argv_printf(const char **argv, int count, const char *fmt, ...)
{ {
char *argv_str, *format_str, *trace_str; struct strbuf buf;
size_t argv_len, format_len, trace_len; va_list ap;
va_list rest; int fd, len, need_close = 0;
int need_close = 0;
int fd = get_trace_fd(&need_close);
fd = get_trace_fd(&need_close);
if (!fd) if (!fd)
return; return;
/* Get the argv string. */ strbuf_init(&buf, 0);
argv_str = sq_quote_argv(argv, count); va_start(ap, fmt);
argv_len = strlen(argv_str); len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
va_end(ap);
if (len >= strbuf_avail(&buf)) {
strbuf_grow(&buf, len - strbuf_avail(&buf) + 128);
va_start(ap, fmt);
len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
va_end(ap);
if (len >= strbuf_avail(&buf))
die("broken vsnprintf");
}
strbuf_setlen(&buf, len);
/* Get the formated string. */ sq_quote_argv(&buf, argv, count, 0);
va_start(rest, format); strbuf_addch(&buf, '\n');
nfvasprintf(&format_str, format, rest); write_or_whine_pipe(fd, buf.buf, buf.len, err_msg);
va_end(rest); strbuf_release(&buf);
/* Allocate buffer for trace string. */
format_len = strlen(format_str);
trace_len = argv_len + format_len + 1; /* + 1 for \n */
trace_str = xmalloc(trace_len + 1);
/* Copy everything into the trace string. */
strncpy(trace_str, format_str, format_len);
strncpy(trace_str + format_len, argv_str, argv_len);
strcpy(trace_str + trace_len - 1, "\n");
write_or_whine_pipe(fd, trace_str, trace_len, err_msg);
free(argv_str);
free(format_str);
free(trace_str);
if (need_close) if (need_close)
close(fd); close(fd);