aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archive-tar.c68
-rw-r--r--builtin-apply.c254
-rw-r--r--builtin-archive.c97
-rw-r--r--builtin-blame.c34
-rw-r--r--builtin-branch.c15
-rw-r--r--builtin-checkout-index.c8
-rw-r--r--builtin-commit-tree.c58
-rw-r--r--builtin-fetch--tool.c22
-rw-r--r--builtin-log.c12
-rw-r--r--builtin-rerere.c55
-rw-r--r--builtin-rev-list.c13
-rw-r--r--builtin-show-branch.c13
-rw-r--r--builtin-stripspace.c20
-rw-r--r--builtin-tag.c78
-rw-r--r--builtin-update-index.c13
-rw-r--r--cache-tree.c57
-rw-r--r--cache.h7
-rw-r--r--commit.c416
-rw-r--r--commit.h9
-rw-r--r--convert.c413
-rw-r--r--diff.c38
-rw-r--r--entry.c10
-rw-r--r--fast-import.c265
-rw-r--r--fetch.c7
-rw-r--r--git-compat-util.h17
-rw-r--r--imap-send.c30
-rw-r--r--interpolate.c20
-rw-r--r--log-tree.c56
-rw-r--r--mktag.c14
-rw-r--r--mktree.c33
-rw-r--r--sha1_file.c69
-rw-r--r--strbuf.c170
-rw-r--r--strbuf.h102
-rwxr-xr-xt/t5000-tar-tree.sh15
34 files changed, 1066 insertions, 1442 deletions
diff --git a/archive-tar.c b/archive-tar.c
index c0d95dab0..a87bc4b83 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -3,7 +3,6 @@
*/
#include "cache.h"
#include "commit.h"
-#include "strbuf.h"
#include "tar.h"
#include "builtin.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
* 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,
const char *value, unsigned int valuelen)
{
- char *p;
- int len, total, tmp;
+ int len, tmp;
/* "%u %s=%s\n" */
len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
for (tmp = len; tmp > 9; tmp /= 10)
len++;
- total = sb->len + len;
- if (total > sb->alloc) {
- sb->buf = xrealloc(sb->buf, total);
- sb->alloc = total;
- }
-
- p = sb->buf;
- p += sprintf(p, "%u %s=", len, keyword);
- memcpy(p, value, valuelen);
- p += valuelen;
- *p = '\n';
- sb->len = total;
+ strbuf_grow(sb, len);
+ strbuf_addf(sb, "%u %s=", len, keyword);
+ strbuf_add(sb, value, valuelen);
+ strbuf_addch(sb, '\n');
}
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;
memset(&header, 0, sizeof(header));
- ext_header.buf = NULL;
- ext_header.len = ext_header.alloc = 0;
+ strbuf_init(&ext_header, 0);
if (!sha1) {
*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));
} else {
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)) {
*header.typeflag = TYPEFLAG_DIR;
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) {
write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
- free(ext_header.buf);
}
+ strbuf_release(&ext_header);
write_blocked(&header, sizeof(header));
if (S_ISREG(mode) && buffer && size > 0)
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)
{
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);
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)
@@ -261,28 +237,18 @@ static int write_tar_entry(const unsigned char *sha1,
const char *base, int baselen,
const char *filename, unsigned mode, int stage)
{
- static struct strbuf path;
+ static struct strbuf path = STRBUF_INIT;
int filenamelen = strlen(filename);
void *buffer;
enum object_type type;
unsigned long size;
- if (!path.alloc) {
- path.buf = xmalloc(PATH_MAX);
- path.alloc = PATH_MAX;
- path.len = path.eof = 0;
- }
- 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';
+ strbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1));
+ strbuf_reset(&path);
+ strbuf_add(&path, base, baselen);
+ strbuf_add(&path, filename, filenamelen);
if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
- strbuf_append_string(&path, "/");
+ strbuf_addch(&path, '/');
buffer = NULL;
size = 0;
} else {
diff --git a/builtin-apply.c b/builtin-apply.c
index 86d89a4a7..f953c5b76 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -181,34 +181,21 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c
static void *read_patch_file(int fd, unsigned long *sizep)
{
- unsigned long size = 0, alloc = CHUNKSIZE;
- void *buffer = xmalloc(alloc);
+ struct strbuf buf;
- 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));
- size += nr;
- }
- *sizep = size;
+ strbuf_init(&buf, 0);
+ if (strbuf_read(&buf, fd, 0) < 0)
+ die("git-apply: read returned %s", strerror(errno));
+ *sizep = buf.len;
/*
* Make sure that we have some slop in the buffer
* so that we can do speculative "memcmp" etc, and
* see to it that it is NUL-filled.
*/
- if (alloc < size + SLOP)
- buffer = xrealloc(buffer, size + SLOP);
- memset((char *) buffer + size, 0, SLOP);
- return buffer;
+ strbuf_grow(&buf, SLOP);
+ memset(buf.buf + buf.len, 0, SLOP);
+ return strbuf_detach(&buf);
}
static unsigned long linelen(const char *buffer, unsigned long size)
@@ -1454,39 +1441,28 @@ static void show_stats(struct patch *patch)
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) {
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:
fd = open(path, O_RDONLY);
if (fd < 0)
return error("unable to open %s", path);
- got = 0;
- for (;;) {
- ssize_t ret = xread(fd, buf + got, size - got);
- if (ret <= 0)
- break;
- got += ret;
+ if (strbuf_read(buf, fd, st->st_size) < 0) {
+ close(fd);
+ return -1;
}
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;
+ convert_to_git(path, buf->buf, buf->len, buf);
+ return 0;
default:
return -1;
}
@@ -1591,12 +1567,6 @@ static void remove_last_line(const char **rbuf, int *rsize)
*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)
{
/* plen is number of bytes to be copied from patch,
@@ -1673,10 +1643,9 @@ static int apply_line(char *output, const char *patch, int plen)
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;
- char *buf = desc->buffer;
const char *patch = frag->patch;
int offset, size = frag->size;
char *old = xmalloc(size);
@@ -1787,24 +1756,17 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
lines = 0;
pos = frag->newpos;
for (;;) {
- offset = find_offset(buf, desc->size,
+ offset = find_offset(buf->buf, buf->len,
oldlines, oldsize, pos, &lines);
- if (match_end && offset + oldsize != desc->size)
+ if (match_end && offset + oldsize != buf->len)
offset = -1;
if (match_beginning && offset)
offset = -1;
if (offset >= 0) {
- int diff;
- unsigned long size, alloc;
-
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;
- diff = newsize - oldsize;
- size = desc->size + diff;
- alloc = desc->alloc;
-
/* Warn if it was necessary to reduce the number
* of context lines.
*/
@@ -1814,19 +1776,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
" to apply fragment at %d\n",
leading, trailing, pos + lines);
- if (size > alloc) {
- 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);
+ strbuf_splice(buf, offset, oldsize, newlines, newsize);
offset = 0;
-
break;
}
@@ -1862,12 +1813,11 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
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;
- void *data;
- void *result;
+ unsigned long len;
+ void *dst;
/* Binary patch is irreversible without the optional second hunk */
if (apply_in_reverse) {
@@ -1878,29 +1828,24 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
? patch->new_name : patch->old_name);
fragment = fragment->next;
}
- data = (void*) fragment->patch;
switch (fragment->binary_patch_method) {
case BINARY_DELTA_DEFLATED:
- result = patch_delta(desc->buffer, desc->size,
- data,
- fragment->size,
- &dst_size);
- free(desc->buffer);
- desc->buffer = result;
- break;
+ dst = patch_delta(buf->buf, buf->len, fragment->patch,
+ fragment->size, &len);
+ if (!dst)
+ return -1;
+ /* XXX patch_delta NUL-terminates */
+ strbuf_attach(buf, dst, len, len + 1);
+ return 0;
case BINARY_LITERAL_DEFLATED:
- free(desc->buffer);
- desc->buffer = data;
- dst_size = fragment->size;
- break;
+ strbuf_reset(buf);
+ strbuf_add(buf, fragment->patch, fragment->size);
+ return 0;
}
- if (!desc->buffer)
- return -1;
- desc->size = desc->alloc = dst_size;
- 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;
unsigned char sha1[20];
@@ -1919,7 +1864,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
/* See if the old one matches what the patch
* 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))
return error("the patch applies to '%s' (%s), "
"which does not match the "
@@ -1928,16 +1873,14 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
}
else {
/* Otherwise, the old one must be empty. */
- if (desc->size)
+ if (buf->len)
return error("the patch applies to an empty "
"'%s' but it is not empty", name);
}
get_sha1_hex(patch->new_sha1_prefix, sha1);
if (is_null_sha1(sha1)) {
- free(desc->buffer);
- desc->alloc = desc->size = 0;
- desc->buffer = NULL;
+ strbuf_release(buf);
return 0; /* deletion patch */
}
@@ -1945,43 +1888,44 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
/* We already have the postimage */
enum object_type type;
unsigned long size;
+ char *result;
- free(desc->buffer);
- desc->buffer = read_sha1_file(sha1, &type, &size);
- if (!desc->buffer)
+ result = read_sha1_file(sha1, &type, &size);
+ if (!result)
return error("the necessary postimage %s for "
"'%s' cannot be read",
patch->new_sha1_prefix, name);
- desc->alloc = desc->size = size;
- }
- else {
- /* We have verified desc matches the preimage;
+ /* XXX read_sha1_file NUL-terminates */
+ strbuf_attach(buf, result, size, size + 1);
+ } else {
+ /* We have verified buf matches the preimage;
* apply the patch data to it, which is stored
* 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'",
name);
/* 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))
- 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;
}
-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;
const char *name = patch->old_name ? patch->old_name : patch->new_name;
if (patch->is_binary)
- return apply_binary(desc, patch);
+ return apply_binary(buf, patch);
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);
if (!apply_with_reject)
return -1;
@@ -1992,76 +1936,57 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
return 0;
}
-static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p,
- unsigned long *size_p)
+static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
{
if (!ce)
return 0;
if (S_ISGITLINK(ntohl(ce->ce_mode))) {
- *buf_p = xmalloc(100);
- *size_p = snprintf(*buf_p, 100,
- "Subproject commit %s\n", sha1_to_hex(ce->sha1));
+ strbuf_grow(buf, 100);
+ strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
} else {
enum object_type type;
- *buf_p = read_sha1_file(ce->sha1, &type, size_p);
- if (!*buf_p)
+ unsigned long sz;
+ char *result;
+
+ result = read_sha1_file(ce->sha1, &type, &sz);
+ if (!result)
return -1;
+ /* XXX read_sha1_file NUL-terminates */
+ strbuf_attach(buf, result, sz, sz + 1);
}
return 0;
}
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
- char *buf;
- unsigned long size, alloc;
- struct buffer_desc desc;
+ struct strbuf buf;
- size = 0;
- alloc = 0;
- buf = NULL;
+ strbuf_init(&buf, 0);
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);
- alloc = size;
} else if (patch->old_name) {
if (S_ISGITLINK(patch->old_mode)) {
- if (ce)
- read_file_or_gitlink(ce, &buf, &size);
- else {
+ if (ce) {
+ read_file_or_gitlink(ce, &buf);
+ } else {
/*
* There is no way to apply subproject
* patch without looking at the index.
*/
patch->fragments = NULL;
- size = 0;
}
- }
- else {
- size = xsize_t(st->st_size);
- 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);
+ } else {
+ if (read_old_data(st, patch->old_name, &buf))
+ return error("read of %s failed", patch->old_name);
}
}
- desc.size = size;
- desc.alloc = alloc;
- desc.buffer = buf;
-
- if (apply_fragments(&desc, patch) < 0)
+ if (apply_fragments(&buf, patch) < 0)
return -1; /* note with --reject this succeeds. */
-
- /* 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;
+ patch->result = buf.buf;
+ patch->resultsize = buf.len;
if (0 < patch->is_delete && patch->resultsize)
return error("removal patch leaves file contents");
@@ -2479,7 +2404,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)
{
int fd;
- char *nbuf;
+ struct strbuf nbuf;
if (S_ISGITLINK(mode)) {
struct stat st;
@@ -2498,23 +2423,16 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
if (fd < 0)
return -1;
- nbuf = convert_to_working_tree(path, buf, &size);
- if (nbuf)
- buf = nbuf;
-
- 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;
+ strbuf_init(&nbuf, 0);
+ if (convert_to_working_tree(path, buf, size, &nbuf)) {
+ size = nbuf.len;
+ buf = nbuf.buf;
}
+ write_or_die(fd, buf, size);
+ strbuf_release(&nbuf);
+
if (close(fd) < 0)
die("closing file %s: %s", path, strerror(errno));
- if (nbuf)
- free(nbuf);
return 0;
}
diff --git a/builtin-archive.c b/builtin-archive.c
index a90c65ce5..843a9e37b 100644
--- a/builtin-archive.c
+++ b/builtin-archive.c
@@ -81,95 +81,80 @@ static int run_remote_archiver(const char *remote, int argc,
return !!rv;
}
-static void *format_subst(const struct commit *commit, const char *format,
- unsigned long *sizep)
+static void format_subst(const struct commit *commit,
+ const char *src, size_t len,
+ struct strbuf *buf)
{
- unsigned long len = *sizep, result_len = 0;
- const char *a = format;
- char *result = NULL;
+ char *to_free = NULL;
+ struct strbuf fmt;
+ if (src == buf->buf)
+ to_free = strbuf_detach(buf);
+ strbuf_init(&fmt, 0);
for (;;) {
const char *b, *c;
- char *fmt, *formatted = NULL;
- unsigned long a_len, fmt_len, formatted_len, allocated = 0;
- b = memmem(a, len, "$Format:", 8);
- if (!b || a + len < b + 9)
+ b = memmem(src, len, "$Format:", 8);
+ if (!b || src + len < b + 9)
break;
c = memchr(b + 8, '$', len - 8);
if (!c)
break;
- a_len = b - a;
- fmt_len = 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,
- &allocated);
- free(fmt);
- result = xrealloc(result, result_len + a_len + formatted_len);
- memcpy(result + result_len, a, a_len);
- memcpy(result + result_len + a_len, formatted, formatted_len);
- result_len += a_len + formatted_len;
- len -= c + 1 - a;
- a = c + 1;
- }
+ strbuf_reset(&fmt);
+ strbuf_add(&fmt, b + 8, c - b - 8);
- if (result && len) {
- result = xrealloc(result, result_len + len);
- memcpy(result + result_len, a, len);
- result_len += len;
+ strbuf_add(buf, src, b - src);
+ format_commit_message(commit, fmt.buf, buf);
+ len -= c + 1 - src;
+ src = c + 1;
}
-
- *sizep = result_len;
-
- return result;
+ strbuf_add(buf, src, len);
+ strbuf_release(&fmt);
+ free(to_free);
}
-static void *convert_to_archive(const char *path,
- const void *src, unsigned long *sizep,
- const struct commit *commit)
+static int convert_to_archive(const char *path,
+ const void *src, size_t len,
+ struct strbuf *buf,
+ const struct commit *commit)
{
static struct git_attr *attr_export_subst;
struct git_attr_check check[1];
if (!commit)
- return NULL;
+ return 0;
- if (!attr_export_subst)
- attr_export_subst = git_attr("export-subst", 12);
+ if (!attr_export_subst)
+ attr_export_subst = git_attr("export-subst", 12);
check[0].attr = attr_export_subst;
if (git_checkattr(path, ARRAY_SIZE(check), check))
- return NULL;
+ return 0;
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,
unsigned int mode, enum object_type *type,
- unsigned long *size,
+ unsigned long *sizep,
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)) {
- converted = convert_to_working_tree(path, buffer, size);
- if (converted) {
- free(buffer);
- buffer = converted;
- }
-
- converted = convert_to_archive(path, buffer, size, commit);
- if (converted) {
- free(buffer);
- buffer = converted;
- }
+ struct strbuf buf;
+
+ strbuf_init(&buf, 0);
+ strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
+ convert_to_working_tree(path, buf.buf, buf.len, &buf);
+ convert_to_archive(path, buf.buf, buf.len, &buf, commit);
+ *sizep = buf.len;
+ buffer = buf.buf;
}
return buffer;
diff --git a/builtin-blame.c b/builtin-blame.c
index dc88a953a..e364b6c6c 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -2001,11 +2001,10 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
struct commit *commit;
struct origin *origin;
unsigned char head_sha1[20];
- char *buf;
+ struct strbuf buf;
const char *ident;
int fd;
time_t now;
- unsigned long fin_size;
int size, len;
struct cache_entry *ce;
unsigned mode;
@@ -2023,9 +2022,11 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
origin = make_origin(commit, path);
+ strbuf_init(&buf, 0);
if (!contents_from || strcmp("-", contents_from)) {
struct stat st;
const char *read_from;
+ unsigned long fin_size;
if (contents_from) {
if (stat(contents_from, &st) < 0)
@@ -2038,19 +2039,19 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
read_from = path;
}
fin_size = xsize_t(st.st_size);
- buf = xmalloc(fin_size+1);
mode = canon_mode(st.st_mode);
switch (st.st_mode & S_IFMT) {
case S_IFREG:
fd = open(read_from, O_RDONLY);
if (fd < 0)
die("cannot open %s", read_from);
- if (read_in_full(fd, buf, fin_size) != fin_size)
+ if (strbuf_read(&buf, fd, 0) != xsize_t(st.st_size))
die("cannot read %s", read_from);
break;
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);
+ buf.len = fin_size;
break;
default:
die("unsupported file type %s", read_from);
@@ -2059,26 +2060,13 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
else {
/* Reading from stdin */
contents_from = "standard input";
- buf = NULL;
- fin_size = 0;
mode = 0;
- while (1) {
- ssize_t cnt = 8192;
- 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);
+ if (strbuf_read(&buf, 0, 0) < 0)
+ die("read error %s from stdin", strerror(errno));
}
- buf[fin_size] = 0;
- origin->file.ptr = buf;
- origin->file.size = fin_size;
- pretend_sha1_file(buf, fin_size, OBJ_BLOB, origin->blob_sha1);
+ origin->file.ptr = buf.buf;
+ origin->file.size = buf.len;
+ pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
commit->util = origin;
/*
diff --git a/builtin-branch.c b/builtin-branch.c
index 5f5c1823c..3da8b55b8 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -268,23 +268,22 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
}
if (verbose) {
- char *subject = NULL;
- unsigned long subject_len = 0;
+ struct strbuf subject;
const char *sub = " **** invalid ref ****";
+ strbuf_init(&subject, 0);
+
commit = lookup_commit(item->sha1);
if (commit && !parse_commit(commit)) {
- pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
- &subject, &subject_len, 0,
- NULL, NULL, 0);
- sub = subject;
+ pretty_print_commit(CMIT_FMT_ONELINE, commit,
+ &subject, 0, NULL, NULL, 0);
+ sub = subject.buf;
}
printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
maxwidth, item->name,
branch_get_color(COLOR_BRANCH_RESET),
find_unique_abbrev(item->sha1, abbrev), sub);
- if (subject)
- free(subject);
+ strbuf_release(&subject);
} else {
printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
branch_get_color(COLOR_BRANCH_RESET));
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index 75377b9ca..a18ecc4ba 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -38,7 +38,6 @@
*/
#include "builtin.h"
#include "cache.h"
-#include "strbuf.h"
#include "quote.h"
#include "cache-tree.h"
@@ -274,13 +273,11 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
struct strbuf buf;
if (all)
die("git-checkout-index: don't mix '--all' and '--stdin'");
- strbuf_init(&buf);
+ strbuf_init(&buf, 0);
while (1) {
char *path_name;
const char *p;
-
- read_line(&buf, stdin, line_termination);
- if (buf.eof)
+ if (strbuf_getline(&buf, stdin, line_termination) == EOF)
break;
if (line_termination && buf.buf[0] == '"')
path_name = unquote_c_style(buf.buf, NULL);
@@ -293,6 +290,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
if (path_name != buf.buf)
free(path_name);
}
+ strbuf_release(&buf);
}
if (all)
diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c
index ccbcbe30d..88b0ab36e 100644
--- a/builtin-commit-tree.c
+++ b/builtin-commit-tree.c
@@ -14,36 +14,6 @@
/*
* 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)
{
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;
unsigned char tree_sha1[20];
unsigned char commit_sha1[20];
- char comment[1000];
- char *buffer;
- unsigned int size;
+ struct strbuf buffer;
int encoding_is_utf8;
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 */
encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
- init_buffer(&buffer, &size);
- add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
+ strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */
+ strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree_sha1));
/*
* 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.
*/
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 */
- add_buffer(&buffer, &size, "author %s\n", git_author_info(1));
- add_buffer(&buffer, &size, "committer %s\n", git_committer_info(1));
+ strbuf_addf(&buffer, "author %s\n", git_author_info(1));
+ strbuf_addf(&buffer, "committer %s\n", git_committer_info(1));
if (!encoding_is_utf8)
- add_buffer(&buffer, &size,
- "encoding %s\n", git_commit_encoding);
- add_buffer(&buffer, &size, "\n");
+ strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
+ strbuf_addch(&buffer, '\n');
/* And add the comment */
- while (fgets(comment, sizeof(comment), stdin) != NULL)
- add_buffer(&buffer, &size, "%s", comment);
+ if (strbuf_read(&buffer, 0, 0) < 0)
+ die("git-commit-tree: read returned %s", strerror(errno));
/* And check the encoding */
- buffer[size] = '\0';
- if (encoding_is_utf8 && !is_utf8(buffer))
+ if (encoding_is_utf8 && !is_utf8(buffer.buf))
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));
return 0;
}
diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c
index 24c7e6f7d..514a3cc01 100644
--- a/builtin-fetch--tool.c
+++ b/builtin-fetch--tool.c
@@ -3,26 +3,14 @@
#include "refs.h"
#include "commit.h"
-#define CHUNK_SIZE 1024
-
static char *get_stdin(void)
{
- size_t offset = 0;
- char *data = xmalloc(CHUNK_SIZE);
-
- while (1) {
- 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;
- data = xrealloc(data, offset + CHUNK_SIZE);
+ struct strbuf buf;
+ strbuf_init(&buf, 0);
+ if (strbuf_read(&buf, 0, 1024) < 0) {
+ die("error reading standard input: %s", strerror(errno));
}
- return data;
+ return strbuf_detach(&buf);
}
static void show_new(enum object_type type, unsigned char *sha1_new)
diff --git a/builtin-log.c b/builtin-log.c
index c6cc3aef5..60819d15c 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -792,13 +792,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
sign = '-';
if (verbose) {
- char *buf = NULL;
- unsigned long buflen = 0;
- pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
- &buf, &buflen, 0, NULL, NULL, 0);
+ struct strbuf buf;
+ strbuf_init(&buf, 0);
+ pretty_print_commit(CMIT_FMT_ONELINE, commit,
+ &buf, 0, NULL, NULL, 0);
printf("%c %s %s\n", sign,
- sha1_to_hex(commit->object.sha1), buf);
- free(buf);
+ sha1_to_hex(commit->object.sha1), buf.buf);
+ strbuf_release(&buf);
}
else {
printf("%c %s\n", sign,
diff --git a/builtin-rerere.c b/builtin-rerere.c
index 29d057c98..58288f61a 100644
--- a/builtin-rerere.c
+++ b/builtin-rerere.c
@@ -66,41 +66,20 @@ static int write_rr(struct path_list *rr, int out_fd)
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,
unsigned char *sha1, const char *output)
{
SHA_CTX ctx;
char buf[1024];
int hunk = 0, hunk_no = 0;
- struct buffer minus = { NULL, 0, 0 }, plus = { NULL, 0, 0 };
- struct buffer *one = &minus, *two = &plus;
+ struct strbuf minus, plus;
+ struct strbuf *one = &minus, *two = &plus;
FILE *f = fopen(path, "r");
FILE *out;
+ strbuf_init(&minus, 0);
+ strbuf_init(&plus, 0);
+
if (!f)
return error("Could not open %s", path);
@@ -122,36 +101,36 @@ static int handle_file(const char *path,
else if (!prefixcmp(buf, "======="))
hunk = 2;
else if (!prefixcmp(buf, ">>>>>>> ")) {
- int one_is_longer = (one->nr > two->nr);
- int common_len = one_is_longer ? two->nr : one->nr;
- int cmp = memcmp(one->ptr, two->ptr, common_len);
+ int one_is_longer = (one->len > two->len);
+ int common_len = one_is_longer ? two->len : one->len;
+ int cmp = memcmp(one->buf, two->buf, common_len);
hunk_no++;
hunk = 0;
if ((cmp > 0) || ((cmp == 0) && one_is_longer)) {
- struct buffer *swap = one;
+ struct strbuf *swap = one;
one = two;
two = swap;
}
if (out) {
fputs("<<<<<<<\n", out);
- fwrite(one->ptr, one->nr, 1, out);
+ fwrite(one->buf, one->len, 1, out);
fputs("=======\n", out);
- fwrite(two->ptr, two->nr, 1, out);
+ fwrite(two->buf, two->len, 1, out);
fputs(">>>>>>>\n", out);
}
if (sha1) {
- SHA1_Update(&ctx, one->ptr, one->nr);
+ SHA1_Update(&ctx, one->buf, one->len);
SHA1_Update(&ctx, "\0", 1);
- SHA1_Update(&ctx, two->ptr, two->nr);
+ SHA1_Update(&ctx, two->buf, two->len);
SHA1_Update(&ctx, "\0", 1);
}
- clear_buffer(one);
- clear_buffer(two);
+ strbuf_release(one);
+ strbuf_release(two);
} else if (hunk == 1)
- append_line(one, buf);
+ strbuf_addstr(one, buf);
else if (hunk == 2)
- append_line(two, buf);
+ strbuf_addstr(two, buf);
else if (out)
fputs(buf, out);
}
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 899a31d09..43b88fae2 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -80,13 +80,12 @@ static void show_commit(struct commit *commit)
putchar('\n');
if (revs.verbose_header) {
- char *buf = NULL;
- unsigned long buflen = 0;
- pretty_print_commit(revs.commit_format, commit, ~0,
- &buf, &buflen,
- revs.abbrev, NULL, NULL, revs.date_mode);
- printf("%s%c", buf, hdr_termination);
- free(buf);
+ struct strbuf buf;
+ strbuf_init(&buf, 0);
+ pretty_print_commit(revs.commit_format, commit,
+ &buf, revs.abbrev, NULL, NULL, revs.date_mode);
+ printf("%s%c", buf.buf, hdr_termination);
+ strbuf_release(&buf);
}
maybe_flush_or_die(stdout, "stdout");
if (commit->parents) {
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index 4fa87f608..07a0c2316 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -259,16 +259,15 @@ static void join_revs(struct commit_list **list_p,
static void show_one_commit(struct commit *commit, int no_name)
{
- char *pretty = NULL;
+ struct strbuf pretty;
const char *pretty_str = "(unavailable)";
- unsigned long pretty_len = 0;
struct commit_name *name = commit->util;
+ strbuf_init(&pretty, 0);
if (commit->object.parsed) {
- pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
- &pretty, &pretty_len,
- 0, NULL, NULL, 0);
- pretty_str = pretty;
+ pretty_print_commit(CMIT_FMT_ONELINE, commit,
+ &pretty, 0, NULL, NULL, 0);
+ pretty_str = pretty.buf;
}
if (!prefixcmp(pretty_str, "[PATCH] "))
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));
}
puts(pretty_str);
- free(pretty);
+ strbuf_release(&pretty);
}
static char *ref_name[MAX_REVS + 1];
diff --git a/builtin-stripspace.c b/builtin-stripspace.c
index 916355ca5..1ce284710 100644
--- a/builtin-stripspace.c
+++ b/builtin-stripspace.c
@@ -74,26 +74,22 @@ size_t stripspace(char *buffer, size_t length, int skip_comments)
int cmd_stripspace(int argc, const char **argv, const char *prefix)
{
- char *buffer;
- unsigned long size;
+ struct strbuf buf;
int strip_comments = 0;
if (argc > 1 && (!strcmp(argv[1], "-s") ||
!strcmp(argv[1], "--strip-comments")))
strip_comments = 1;
- size = 1024;
- buffer = xmalloc(size);
- if (read_fd(0, &buffer, &size)) {
- free(buffer);
+ strbuf_init(&buf, 0);
+ if (strbuf_read(&buf, 0, 1024) < 0)
die("could not read the input");
- }
- size = stripspace(buffer, size, strip_comments);
- write_or_die(1, buffer, size);
- if (size)
- putc('\n', stdout);
+ strbuf_setlen(&buf, stripspace(buf.buf, buf.len, strip_comments));
+ if (buf.len)
+ strbuf_addch(&buf, '\n');
- free(buffer);
+ write_or_die(1, buf.buf, buf.len);
+ strbuf_release(&buf);
return 0;
}
diff --git a/builtin-tag.c b/builtin-tag.c
index 3a9d2eea7..82ebda11b 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -17,7 +17,7 @@ static const char builtin_tag_usage[] =
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;
struct child_process child;
@@ -55,10 +55,8 @@ static void launch_editor(const char *path, char **buffer, unsigned long *len)
fd = open(path, O_RDONLY);
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",
- path, strerror(errno));
+ if (strbuf_read(buffer, fd, 0) < 0) {
+ die("could not read message file '%s': %s", path, strerror(errno));
}
close(fd);
}
@@ -184,7 +182,7 @@ static int verify_tag(const char *name, const char *ref,
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;
const char *args[4];
@@ -216,22 +214,22 @@ static ssize_t do_sign(char *buffer, size_t size, size_t max)
if (start_command(&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);
finish_command(&gpg);
return error("gpg did not accept the tag data");
}
close(gpg.in);
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)
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 size + len;
+ return 0;
}
static const char tag_template[] =
@@ -254,15 +252,13 @@ static int git_tag_config(const char *var, const char *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,
- char *message, int sign, unsigned char *result)
+ struct strbuf *buf, int message, int sign,
+ unsigned char *result)
{
enum object_type type;
- char header_buf[1024], *buffer = NULL;
- int header_len, max_size;
- unsigned long size = 0;
+ char header_buf[1024];
+ int header_len;
type = sha1_object_info(object, NULL);
if (type <= OBJ_NONE)
@@ -294,53 +290,40 @@ static void create_tag(const unsigned char *object, const char *tag,
write_or_die(fd, tag_template, strlen(tag_template));
close(fd);
- launch_editor(path, &buffer, &size);
+ launch_editor(path, buf);
unlink(path);
free(path);
}
- else {
- buffer = message;
- size = strlen(message);
- }
- size = stripspace(buffer, size, 1);
+ strbuf_setlen(buf, stripspace(buf->buf, buf->len, 1));
- if (!message && !size)
+ if (!message && !buf->len)
die("no tag message?");
/* insert the header and add the '\n' if needed: */
- 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) {
- ssize_t r = do_sign(buffer, size, max_size);
- if (r < 0)
- die("unable to sign the tag");
- size = r;
- }
+ if (buf->len)
+ strbuf_addch(buf, '\n');
+ strbuf_insert(buf, 0, header_buf, header_len);
- if (write_sha1_file(buffer, size, tag_type, result) < 0)
+ if (sign && do_sign(buf) < 0)
+ die("unable to sign the tag");
+ if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
die("unable to write tag file");
- free(buffer);
}
int cmd_tag(int argc, const char **argv, const char *prefix)
{
+ struct strbuf buf;
unsigned char object[20], prev[20];
- int annotate = 0, sign = 0, force = 0, lines = 0;
- char *message = NULL;
+ int annotate = 0, sign = 0, force = 0, lines = 0, message = 0;
char ref[PATH_MAX];
const char *object_ref, *tag;
int i;
struct ref_lock *lock;
git_config(git_tag_config);
+ strbuf_init(&buf, 0);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
@@ -376,11 +359,11 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die("option -m needs an argument.");
if (message)
die("only one -F or -m option is allowed.");
- message = xstrdup(argv[i]);
+ strbuf_addstr(&buf, argv[i]);
+ message = 1;
continue;
}
if (!strcmp(arg, "-F")) {
- unsigned long len;
int fd;
annotate = 1;
@@ -398,12 +381,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die("could not open '%s': %s",
argv[i], strerror(errno));
}
- len = 1024;
- message = xmalloc(len);
- if (read_fd(fd, &message, &len)) {
- free(message);
+ if (strbuf_read(&buf, fd, 1024) < 0) {
die("cannot read %s", argv[i]);
}
+ message = 1;
continue;
}
if (!strcmp(arg, "-u")) {
@@ -451,7 +432,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die("tag '%s' already exists", tag);
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);
if (!lock)
@@ -459,5 +440,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (write_ref_sha1(lock, object, NULL) < 0)
die("%s: cannot update the ref", ref);
+ strbuf_release(&buf);
return 0;
}
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 55fb679d6..acd5ab592 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -4,7 +4,6 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
-#include "strbuf.h"
#include "quote.h"
#include "cache-tree.h"
#include "tree-walk.h"
@@ -296,7 +295,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
static void read_index_info(int line_termination)
{
struct strbuf buf;
- strbuf_init(&buf);
+ strbuf_init(&buf, 0);
while (1) {
char *ptr, *tab;
char *path_name;
@@ -321,8 +320,7 @@ static void read_index_info(int line_termination)
* This format is to put higher order stages into the
* index file and matches git-ls-files --stage output.
*/
- read_line(&buf, stdin, line_termination);
- if (buf.eof)
+ if (strbuf_getline(&buf, stdin, line_termination) == EOF)
break;
errno = 0;
@@ -384,6 +382,7 @@ static void read_index_info(int line_termination)
bad_line:
die("malformed index info %s", buf.buf);
}
+ strbuf_release(&buf);
}
static const char update_index_usage[] =
@@ -707,12 +706,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
}
if (read_from_stdin) {
struct strbuf buf;
- strbuf_init(&buf);
+ strbuf_init(&buf, 0);
while (1) {
char *path_name;
const char *p;
- read_line(&buf, stdin, line_termination);
- if (buf.eof)
+ if (strbuf_getline(&buf, stdin, line_termination) == EOF)
break;
if (line_termination && buf.buf[0] == '"')
path_name = unquote_c_style(buf.buf, NULL);
@@ -727,6 +725,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
if (path_name != buf.buf)
free(path_name);
}
+ strbuf_release(&buf);
}
finish:
diff --git a/cache-tree.c b/cache-tree.c
index 077f03436..5471844af 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -235,8 +235,7 @@ static int update_one(struct cache_tree *it,
int missing_ok,
int dryrun)
{
- unsigned long size, offset;
- char *buffer;
+ struct strbuf buffer;
int i;
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.
*/
- size = 8192;
- buffer = xmalloc(size);
- offset = 0;
+ strbuf_init(&buffer, 8192);
for (i = 0; i < entries; i++) {
struct cache_entry *ce = cache[i];
@@ -332,15 +329,9 @@ static int update_one(struct cache_tree *it,
if (!ce->ce_mode)
continue; /* entry being removed */
- if (size < offset + entlen + 100) {
- size = alloc_nr(offset + entlen + 100);
- buffer = xrealloc(buffer, size);
- }
- offset += sprintf(buffer + offset,
- "%o %.*s", mode, entlen, path + baselen);
- buffer[offset++] = 0;
- hashcpy((unsigned char*)buffer + offset, sha1);
- offset += 20;
+ strbuf_grow(&buffer, entlen + 100);
+ strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
+ strbuf_add(&buffer, sha1, 20);
#if DEBUG
fprintf(stderr, "cache-tree update-one %o %.*s\n",
@@ -349,10 +340,10 @@ static int update_one(struct cache_tree *it,
}
if (dryrun)
- hash_sha1_file(buffer, offset, tree_type, it->sha1);
+ hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
else
- write_sha1_file(buffer, offset, tree_type, it->sha1);
- free(buffer);
+ write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1);
+ strbuf_release(&buffer);
it->entry_count = i;
#if DEBUG
fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
@@ -378,12 +369,10 @@ int cache_tree_update(struct cache_tree *it,
return 0;
}
-static void *write_one(struct cache_tree *it,
+static void write_one(struct cache_tree *it,
char *path,
int pathlen,
- char *buffer,
- unsigned long *size,
- unsigned long *offset)
+ struct strbuf *buffer)
{
int i;
@@ -393,13 +382,9 @@ static void *write_one(struct cache_tree *it,
* tree-sha1 (missing if invalid)
* subtree_nr "cache-tree" entries for subtrees.
*/
- if (*size < *offset + pathlen + 100) {
- *size = alloc_nr(*offset + pathlen + 100);
- buffer = xrealloc(buffer, *size);
- }
- *offset += sprintf(buffer + *offset, "%.*s%c%d %d\n",
- pathlen, path, 0,
- it->entry_count, it->subtree_nr);
+ strbuf_grow(buffer, pathlen + 100);
+ strbuf_add(buffer, path, pathlen);
+ strbuf_addf(buffer, "%c%d %d\n", 0, it->entry_count, it->subtree_nr);
#if DEBUG
if (0 <= it->entry_count)
@@ -412,8 +397,7 @@ static void *write_one(struct cache_tree *it,
#endif
if (0 <= it->entry_count) {
- hashcpy((unsigned char*)buffer + *offset, it->sha1);
- *offset += 20;
+ strbuf_add(buffer, it->sha1, 20);
}
for (i = 0; i < it->subtree_nr; i++) {
struct cache_tree_sub *down = it->down[i];
@@ -423,21 +407,20 @@ static void *write_one(struct cache_tree *it,
prev->name, prev->namelen) <= 0)
die("fatal - unsorted cache subtree");
}
- buffer = write_one(down->cache_tree, down->name, down->namelen,
- buffer, size, offset);
+ write_one(down->cache_tree, down->name, down->namelen, buffer);
}
- return buffer;
}
void *cache_tree_write(struct cache_tree *root, unsigned long *size_p)
{
char path[PATH_MAX];
- unsigned long size = 8192;
- char *buffer = xmalloc(size);
+ struct strbuf buffer;
- *size_p = 0;
path[0] = 0;
- return write_one(root, path, 0, buffer, &size, size_p);
+ strbuf_init(&buffer, 0);
+ write_one(root, path, 0, &buffer);
+ *size_p = buffer.len;
+ return strbuf_detach(&buffer);
}
static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
diff --git a/cache.h b/cache.h
index 824650016..8650d6233 100644
--- a/cache.h
+++ b/cache.h
@@ -2,6 +2,7 @@
#define CACHE_H
#include "git-compat-util.h"
+#include "strbuf.h"
#include SHA1_HEADER
#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 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 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_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);
@@ -591,8 +591,9 @@ extern void trace_printf(const char *format, ...);
extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
/* convert.c */
-extern char *convert_to_git(const char *path, const char *src, unsigned long *sizep);
-extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);
+/* returns 1 if *dst was used */
+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 */
extern int diff_auto_refresh_index;
diff --git a/commit.c b/commit.c
index 99f65cee0..85889f966 100644
--- a/commit.c
+++ b/commit.c
@@ -458,11 +458,11 @@ void clear_commit_marks(struct commit *commit, unsigned int mark)
/*
* 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;
- while (len--) {
+ for (;;) {
char c = *msg++;
if (!c)
break;
@@ -485,31 +485,25 @@ static int is_rfc2047_special(char 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)
{
- char *bp = buf;
- int i, needquote;
- char q_encoding[128];
- const char *q_encoding_fmt = "=?%s?q?";
+ int i, last;
- for (i = needquote = 0; !needquote && i < len; i++) {
+ for (i = 0; i < len; i++) {
int ch = line[i];
if (non_ascii(ch))
- needquote++;
- if ((i + 1 < len) &&
- (ch == '=' && line[i+1] == '?'))
- needquote++;
+ goto needquote;
+ if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
+ goto needquote;
}
- if (!needquote)
- return sprintf(buf, "%.*s", len, line);
-
- i = snprintf(q_encoding, sizeof(q_encoding), q_encoding_fmt, encoding);
- if (sizeof(q_encoding) < i)
- die("Insanely long encoding name %s", encoding);
- memcpy(bp, q_encoding, i);
- bp += i;
- for (i = 0; i < len; i++) {
+ strbuf_add(sb, line, len);
+ return;
+
+needquote:
+ strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
+ strbuf_addf(sb, "=?%s?q?", encoding);
+ for (i = last = 0; i < len; i++) {
unsigned ch = line[i] & 0xFF;
/*
* 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.
*/
if (is_rfc2047_special(ch) || ch == ' ') {
- sprintf(bp, "=%02X", ch);
- bp += 3;
+ strbuf_add(sb, line + last, i - last);
+ strbuf_addf(sb, "=%02X", ch);
+ last = i + 1;
}
- else
- *bp++ = ch;
}
- memcpy(bp, "?=", 2);
- bp += 2;
- return bp - buf;
-}
-
-static unsigned long bound_rfc2047(unsigned long len, const char *encoding)
-{
- /* upper bound of q encoded string of length 'len' */
- unsigned long elen = strlen(encoding);
-
- return len * 3 + elen + 100;
+ strbuf_add(sb, line + last, len - last);
+ strbuf_addstr(sb, "?=");
}
-static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
+static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
const char *line, enum date_mode dmode,
const char *encoding)
{
char *date;
int namelen;
unsigned long time;
- int tz, ret;
+ int tz;
const char *filler = " ";
if (fmt == CMIT_FMT_ONELINE)
- return 0;
+ return;
date = strchr(line, '>');
if (!date)
- return 0;
+ return;
namelen = ++date - line;
time = strtoul(date, &date, 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, '<');
int display_name_length;
if (!name_tail)
- return 0;
+ return;
while (line < name_tail && isspace(name_tail[-1]))
name_tail--;
display_name_length = name_tail - line;
filler = "";
- strcpy(buf, "From: ");
- ret = strlen(buf);
- ret += add_rfc2047(buf + ret, line, display_name_length,
- encoding);
- memcpy(buf + ret, name_tail, namelen - display_name_length);
- ret += namelen - display_name_length;
- buf[ret++] = '\n';
- }
- else {
- ret = sprintf(buf, "%s: %.*s%.*s\n", what,
+ strbuf_addstr(sb, "From: ");
+ add_rfc2047(sb, line, display_name_length, encoding);
+ strbuf_add(sb, name_tail, namelen - display_name_length);
+ strbuf_addch(sb, '\n');
+ } else {
+ strbuf_addf(sb, "%s: %.*s%.*s\n", what,
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
filler, namelen, line);
}
switch (fmt) {
case CMIT_FMT_MEDIUM:
- ret += sprintf(buf + ret, "Date: %s\n",
- show_date(time, tz, dmode));
+ strbuf_addf(sb, "Date: %s\n", show_date(time, tz, dmode));
break;
case CMIT_FMT_EMAIL:
- ret += sprintf(buf + ret, "Date: %s\n",
- show_date(time, tz, DATE_RFC2822));
+ strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
break;
case CMIT_FMT_FULLER:
- ret += sprintf(buf + ret, "%sDate: %s\n", what,
- show_date(time, tz, dmode));
+ strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
break;
default:
/* notin' */
break;
}
- return ret;
}
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;
}
-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;
- int offset;
if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
!parent || !parent->next)
- return 0;
+ return;
- offset = sprintf(buf, "Merge:");
+ strbuf_addstr(sb, "Merge:");
while (parent) {
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) ? "..." : "";
parent = parent->next;
- offset += sprintf(buf + offset, " %s%s", hex, dots);
+ strbuf_addf(sb, " %s%s", hex, dots);
}
- buf[offset++] = '\n';
- return offset;
+ strbuf_addch(sb, '\n');
}
static char *get_header(const struct commit *commit, const char *key)
@@ -665,47 +640,34 @@ static char *get_header(const struct commit *commit, const char *key)
static char *replace_encoding_header(char *buf, const char *encoding)
{
- char *encoding_header = strstr(buf, "\nencoding ");
- char *header_end = strstr(buf, "\n\n");
- char *end_of_encoding_header;
- int encoding_header_pos;
- int encoding_header_len;
- int new_len;
- int need_len;
- int buflen = strlen(buf) + 1;
-
- if (!header_end)
- header_end = buf + buflen;
- if (!encoding_header || encoding_header >= header_end)
- return buf;
- encoding_header++;
- end_of_encoding_header = strchr(encoding_header, '\n');
- if (!end_of_encoding_header)
+ struct strbuf tmp;
+ size_t start, len;
+ char *cp = buf;
+
+ /* guess if there is an encoding header before a \n\n */
+ while (strncmp(cp, "encoding ", strlen("encoding "))) {
+ cp = strchr(cp, '\n');
+ if (!cp || *++cp == '\n')
+ return buf;
+ }
+ start = cp - buf;
+ cp = strchr(cp, '\n');
+ if (!cp)
return buf; /* should not happen but be defensive */
- end_of_encoding_header++;
-
- encoding_header_len = end_of_encoding_header - encoding_header;
- encoding_header_pos = encoding_header - buf;
+ len = cp + 1 - (buf + start);
+ strbuf_init(&tmp, 0);
+ strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
if (is_encoding_utf8(encoding)) {
/* we have re-coded to UTF-8; drop the header */
- memmove(encoding_header, end_of_encoding_header,
- buflen - (encoding_header_pos + encoding_header_len));
- return buf;
- }
- new_len = strlen(encoding);
- 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;
+ strbuf_splice(&tmp, start, len, NULL, 0);
+ } else {
+ /* just replaces XXXX in 'encoding XXXX\n' */
+ strbuf_splice(&tmp, start + strlen("encoding "),
+ len - strlen("encoding \n"),
+ encoding, strlen(encoding));
}
- 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;
+ return tmp.buf;
}
static char *logmsg_reencode(const struct commit *commit,
@@ -787,8 +749,8 @@ static void fill_person(struct interp *table, const char *msg, int len)
interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
}
-long format_commit_message(const struct commit *commit, const void *format,
- char **buf_p, unsigned long *space_p)
+void format_commit_message(const struct commit *commit,
+ const void *format, struct strbuf *sb)
{
struct interp table[] = {
{ "%H" }, /* commit hash */
@@ -841,6 +803,7 @@ long format_commit_message(const struct commit *commit, const void *format,
};
struct commit_list *p;
char parents[1024];
+ unsigned long len;
int i;
enum { HEADER, SUBJECT, BODY } state;
const char *msg = commit->buffer;
@@ -921,21 +884,15 @@ long format_commit_message(const struct commit *commit, const void *format,
if (!table[i].value)
interp_set_entry(table, i, "<unknown>");
- do {
- char *buf = *buf_p;
- unsigned long space = *space_p;
-
- space = interpolate(buf, space, format,
- table, ARRAY_SIZE(table));
- if (!space)
- break;
- buf = xrealloc(buf, space);
- *buf_p = buf;
- *space_p = space;
- } while (1);
+ len = interpolate(sb->buf + sb->len, strbuf_avail(sb),
+ format, table, ARRAY_SIZE(table));
+ if (len > strbuf_avail(sb)) {
+ strbuf_grow(sb, len);
+ interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,
+ format, table, ARRAY_SIZE(table));
+ }
+ strbuf_setlen(sb, sb->len + len);
interp_clear_table(table, ARRAY_SIZE(table));
-
- return strlen(*buf_p);
}
static void pp_header(enum cmit_fmt fmt,
@@ -944,34 +901,24 @@ static void pp_header(enum cmit_fmt fmt,
const char *encoding,
const struct commit *commit,
const char **msg_p,
- unsigned long *len_p,
- unsigned long *ofs_p,
- char **buf_p,
- unsigned long *space_p)
+ struct strbuf *sb)
{
int parents_shown = 0;
for (;;) {
const char *line = *msg_p;
- char *dst;
- int linelen = get_one_line(*msg_p, *len_p);
- unsigned long len;
+ int linelen = get_one_line(*msg_p);
if (!linelen)
return;
*msg_p += linelen;
- *len_p -= linelen;
if (linelen == 1)
/* End of header */
return;
- ALLOC_GROW(*buf_p, linelen + *ofs_p + 20, *space_p);
- dst = *buf_p + *ofs_p;
-
if (fmt == CMIT_FMT_RAW) {
- memcpy(dst, line, linelen);
- *ofs_p += linelen;
+ strbuf_add(sb, line, linelen);
continue;
}
@@ -989,10 +936,8 @@ static void pp_header(enum cmit_fmt fmt,
parent = parent->next, num++)
;
/* with enough slop */
- num = *ofs_p + num * 50 + 20;
- ALLOC_GROW(*buf_p, num, *space_p);
- dst = *buf_p + *ofs_p;
- *ofs_p += add_merge_info(fmt, dst, commit, abbrev);
+ strbuf_grow(sb, num * 50 + 20);
+ add_merge_info(fmt, sb, commit, abbrev);
parents_shown = 1;
}
@@ -1002,129 +947,82 @@ static void pp_header(enum cmit_fmt fmt,
* FULLER shows both authors and dates.
*/
if (!memcmp(line, "author ", 7)) {
- len = linelen;
- if (fmt == CMIT_FMT_EMAIL)
- len = bound_rfc2047(linelen, encoding);
- ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);
- dst = *buf_p + *ofs_p;
- *ofs_p += add_user_info("Author", fmt, dst,
- line + 7, dmode, encoding);
+ strbuf_grow(sb, linelen + 80);
+ add_user_info("Author", fmt, sb, line + 7, dmode, encoding);
}
-
if (!memcmp(line, "committer ", 10) &&
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
- len = linelen;
- if (fmt == CMIT_FMT_EMAIL)
- len = bound_rfc2047(linelen, encoding);
- ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);
- dst = *buf_p + *ofs_p;
- *ofs_p += add_user_info("Commit", fmt, dst,
- line + 10, dmode, encoding);
+ strbuf_grow(sb, linelen + 80);
+ add_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
}
}
}
static void pp_title_line(enum cmit_fmt fmt,
const char **msg_p,
- unsigned long *len_p,
- unsigned long *ofs_p,
- char **buf_p,
- unsigned long *space_p,
- int indent,
+ struct strbuf *sb,
const char *subject,
const char *after_subject,
const char *encoding,
int plain_non_ascii)
{
- char *title;
- unsigned long title_alloc, title_len;
- unsigned long len;
+ struct strbuf title;
+
+ strbuf_init(&title, 80);
- title_len = 0;
- title_alloc = 80;
- title = xmalloc(title_alloc);
for (;;) {
const char *line = *msg_p;
- int linelen = get_one_line(line, *len_p);
- *msg_p += linelen;
- *len_p -= linelen;
+ int linelen = get_one_line(line);
+ *msg_p += linelen;
if (!linelen || is_empty_line(line, &linelen))
break;
- if (title_alloc <= title_len + linelen + 2) {
- title_alloc = title_len + linelen + 80;
- title = xrealloc(title, title_alloc);
- }
- len = 0;
- if (title_len) {
+ strbuf_grow(&title, linelen + 2);
+ if (title.len) {
if (fmt == CMIT_FMT_EMAIL) {
- len++;
- title[title_len++] = '\n';
+ strbuf_addch(&title, '\n');
}
- len++;
- title[title_len++] = ' ';
+ strbuf_addch(&title, ' ');
}
- memcpy(title + title_len, line, linelen);
- title_len += linelen;
+ strbuf_add(&title, line, linelen);
}
- /* Enough slop for the MIME header and rfc2047 */
- len = bound_rfc2047(title_len, encoding)+ 1000;
- if (subject)
- len += strlen(subject);
- if (after_subject)
- len += strlen(after_subject);
- if (encoding)
- len += strlen(encoding);
- ALLOC_GROW(*buf_p, title_len + *ofs_p + len, *space_p);
-
+ strbuf_grow(sb, title.len + 1024);
if (subject) {
- len = strlen(subject);
- memcpy(*buf_p + *ofs_p, subject, len);
- *ofs_p += len;
- *ofs_p += add_rfc2047(*buf_p + *ofs_p,
- title, title_len, encoding);
+ strbuf_addstr(sb, subject);
+ add_rfc2047(sb, title.buf, title.len, encoding);
} else {
- memcpy(*buf_p + *ofs_p, title, title_len);
- *ofs_p += title_len;
+ strbuf_addbuf(sb, &title);
}
- (*buf_p)[(*ofs_p)++] = '\n';
+ strbuf_addch(sb, '\n');
+
if (plain_non_ascii) {
const char *header_fmt =
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=%s\n"
"Content-Transfer-Encoding: 8bit\n";
- *ofs_p += snprintf(*buf_p + *ofs_p,
- *space_p - *ofs_p,
- header_fmt, encoding);
+ strbuf_addf(sb, header_fmt, encoding);
}
if (after_subject) {
- len = strlen(after_subject);
- memcpy(*buf_p + *ofs_p, after_subject, len);
- *ofs_p += len;
+ strbuf_addstr(sb, after_subject);
}
- free(title);
if (fmt == CMIT_FMT_EMAIL) {
- ALLOC_GROW(*buf_p, *ofs_p + 20, *space_p);
- (*buf_p)[(*ofs_p)++] = '\n';
+ strbuf_addch(sb, '\n');
}
+ strbuf_release(&title);
}
static void pp_remainder(enum cmit_fmt fmt,
const char **msg_p,
- unsigned long *len_p,
- unsigned long *ofs_p,
- char **buf_p,
- unsigned long *space_p,
+ struct strbuf *sb,
int indent)
{
int first = 1;
for (;;) {
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;
if (!linelen)
break;
@@ -1137,36 +1035,32 @@ static void pp_remainder(enum cmit_fmt fmt,
}
first = 0;
- ALLOC_GROW(*buf_p, *ofs_p + linelen + indent + 20, *space_p);
+ strbuf_grow(sb, linelen + indent + 20);
if (indent) {
- memset(*buf_p + *ofs_p, ' ', indent);
- *ofs_p += indent;
+ memset(sb->buf + sb->len, ' ', indent);
+ strbuf_setlen(sb, sb->len + indent);
}
- memcpy(*buf_p + *ofs_p, line, linelen);
- *ofs_p += linelen;
- (*buf_p)[(*ofs_p)++] = '\n';
+ strbuf_add(sb, line, linelen);
+ strbuf_addch(sb, '\n');
}
}
-unsigned long pretty_print_commit(enum cmit_fmt fmt,
- const struct commit *commit,
- unsigned long len,
- char **buf_p, unsigned long *space_p,
- int abbrev, const char *subject,
- const char *after_subject,
+void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
+ struct strbuf *sb, int abbrev,
+ const char *subject, const char *after_subject,
enum date_mode dmode)
{
- unsigned long offset = 0;
unsigned long beginning_of_body;
int indent = 4;
const char *msg = commit->buffer;
int plain_non_ascii = 0;
char *reencoded;
const char *encoding;
- char *buf;
- if (fmt == CMIT_FMT_USERFORMAT)
- return format_commit_message(commit, user_format, buf_p, space_p);
+ if (fmt == CMIT_FMT_USERFORMAT) {
+ format_commit_message(commit, user_format, sb);
+ return;
+ }
encoding = (git_log_output_encoding
? git_log_output_encoding
@@ -1176,7 +1070,6 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
reencoded = logmsg_reencode(commit, encoding);
if (reencoded) {
msg = reencoded;
- len = strlen(reencoded);
}
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
@@ -1191,14 +1084,13 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
if (fmt == CMIT_FMT_EMAIL && !after_subject) {
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) {
/* author could be non 7-bit ASCII but
* the log may be so; skip over the
* header part first.
*/
- if (ch == '\n' &&
- i + 1 < len && msg[i+1] == '\n')
+ if (ch == '\n' && msg[i+1] == '\n')
in_body = 1;
}
else if (non_ascii(ch)) {
@@ -1208,59 +1100,44 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
}
}
- pp_header(fmt, abbrev, dmode, encoding,
- commit, &msg, &len,
- &offset, buf_p, space_p);
+ pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb);
if (fmt != CMIT_FMT_ONELINE && !subject) {
- ALLOC_GROW(*buf_p, offset + 20, *space_p);
- (*buf_p)[offset++] = '\n';
+ strbuf_addch(sb, '\n');
}
/* Skip excess blank lines at the beginning of body, if any... */
for (;;) {
- int linelen = get_one_line(msg, len);
+ int linelen = get_one_line(msg);
int ll = linelen;
if (!linelen)
break;
if (!is_empty_line(msg, &ll))
break;
msg += linelen;
- len -= linelen;
}
/* These formats treat the title line specially. */
- if (fmt == CMIT_FMT_ONELINE
- || fmt == CMIT_FMT_EMAIL)
- pp_title_line(fmt, &msg, &len, &offset,
- buf_p, space_p, indent,
- subject, after_subject, encoding,
- plain_non_ascii);
-
- beginning_of_body = offset;
- if (fmt != CMIT_FMT_ONELINE)
- pp_remainder(fmt, &msg, &len, &offset,
- buf_p, space_p, indent);
-
- while (offset && isspace((*buf_p)[offset-1]))
- offset--;
+ if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
+ pp_title_line(fmt, &msg, sb, subject,
+ after_subject, encoding, plain_non_ascii);
- ALLOC_GROW(*buf_p, offset + 20, *space_p);
- buf = *buf_p;
+ beginning_of_body = sb->len;
+ if (fmt != CMIT_FMT_ONELINE)
+ pp_remainder(fmt, &msg, sb, indent);
+ strbuf_rtrim(sb);
/* Make sure there is an EOLN for the non-oneline case */
if (fmt != CMIT_FMT_ONELINE)
- buf[offset++] = '\n';
+ strbuf_addch(sb, '\n');
/*
* The caller may append additional body text in e-mail
* format. Make sure we did not strip the blank line
* between the header and the body.
*/
- if (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body)
- buf[offset++] = '\n';
- buf[offset] = '\0';
+ if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
+ strbuf_addch(sb, '\n');
free(reencoded);
- return offset;
}
struct commit *pop_commit(struct commit_list **stack)
@@ -1339,12 +1216,12 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
next=next->next;
}
/*
- * find the tips
- *
- * tips are nodes not reachable from any other node in the list
- *
- * the tips serve as a starting set for the work queue.
- */
+ * find the tips
+ *
+ * tips are nodes not reachable from any other node in the list
+ *
+ * the tips serve as a starting set for the work queue.
+ */
next=*list;
insert = &work;
while (next) {
@@ -1371,9 +1248,9 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
if (pn) {
/*
* parents are only enqueued for emission
- * when all their children have been emitted thereby
- * guaranteeing topological order.
- */
+ * when all their children have been emitted thereby
+ * guaranteeing topological order.
+ */
pn->indegree--;
if (!pn->indegree) {
if (!lifo)
@@ -1385,9 +1262,9 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
parents=parents->next;
}
/*
- * work_item is a commit all of whose children
- * have already been emitted. we can emit it now.
- */
+ * work_item is a commit all of whose children
+ * have already been emitted. we can emit it now.
+ */
*pptr = work_node->list_item;
pptr = &(*pptr)->next;
*pptr = NULL;
@@ -1483,8 +1360,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)
}
struct commit_list *get_merge_bases(struct commit *one,
- struct commit *two,
- int cleanup)
+ struct commit *two, int cleanup)
{
struct commit_list *list;
struct commit **rslt;
diff --git a/commit.h b/commit.h
index a8d76616d..b779de8cb 100644
--- a/commit.h
+++ b/commit.h
@@ -3,6 +3,7 @@
#include "object.h"
#include "tree.h"
+#include "strbuf.h"
#include "decorate.h"
struct commit_list {
@@ -61,8 +62,12 @@ enum cmit_fmt {
};
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 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);
+extern void format_commit_message(const struct commit *commit,
+ 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
* of its parents.
diff --git a/convert.c b/convert.c
index d77c8eb8b..508d30b2f 100644
--- a/convert.c
+++ b/convert.c
@@ -80,24 +80,19 @@ static int is_binary(unsigned long size, struct text_stat *stats)
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;
+ char *dst;
- if ((action == CRLF_BINARY) || !auto_crlf)
- return NULL;
-
- size = *sizep;
- if (!size)
- return NULL;
-
- gather_stats(src, size, &stats);
+ if ((action == CRLF_BINARY) || !auto_crlf || !len)
+ return 0;
+ gather_stats(src, len, &stats);
/* No CR? Nothing to convert, regardless. */
if (!stats.cr)
- return NULL;
+ return 0;
if (action == CRLF_GUESS) {
/*
@@ -106,24 +101,17 @@ static char *crlf_to_git(const char *path, const char *src, unsigned long *sizep
* stuff?
*/
if (stats.cr != stats.crlf)
- return NULL;
+ return 0;
/*
* And add some heuristics for binary vs text, of course...
*/
- if (is_binary(size, &stats))
- return NULL;
+ if (is_binary(len, &stats))
+ return 0;
}
- /*
- * Ok, allocate a new buffer, fill it in, and return it
- * to let the caller know that we switched buffers.
- */
- nsize = size - stats.crlf;
- buffer = xmalloc(nsize);
- *sizep = nsize;
-
- dst = buffer;
+ strbuf_grow(buf, len);
+ dst = buf->buf;
if (action == CRLF_GUESS) {
/*
* 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++;
if (c != '\r')
*dst++ = c;
- } while (--size);
+ } while (--len);
} else {
do {
unsigned char c = *src++;
- if (! (c == '\r' && (1 < size && *src == '\n')))
+ if (! (c == '\r' && (1 < len && *src == '\n')))
*dst++ = c;
- } while (--size);
+ } while (--len);
}
-
- return buffer;
+ strbuf_setlen(buf, dst - buf->buf);
+ return 1;
}
-static char *crlf_to_worktree(const char *path, const char *src, unsigned long *sizep, int action)
+static int crlf_to_worktree(const char *path, const char *src, size_t len,
+ struct strbuf *buf, int action)
{
- char *buffer, *dst;
- unsigned long size, nsize;
+ char *to_free = NULL;
struct text_stat stats;
- unsigned char last;
if ((action == CRLF_BINARY) || (action == CRLF_INPUT) ||
auto_crlf <= 0)
- return NULL;
+ return 0;
- size = *sizep;
- if (!size)
- return NULL;
+ if (!len)
+ return 0;
- gather_stats(src, size, &stats);
+ gather_stats(src, len, &stats);
/* No LF? Nothing to convert, regardless. */
if (!stats.lf)
- return NULL;
+ return 0;
/* Was it already in CRLF format? */
if (stats.lf == stats.crlf)
- return NULL;
+ return 0;
if (action == CRLF_GUESS) {
/* If we have any bare CR characters, we're not going to touch it */
if (stats.cr != stats.crlf)
- return NULL;
+ return 0;
- if (is_binary(size, &stats))
- return NULL;
+ if (is_binary(len, &stats))
+ return 0;
}
- /*
- * Ok, allocate a new buffer, fill it in, and return it
- * to let the caller know that we switched buffers.
- */
- nsize = size + stats.lf - stats.crlf;
- buffer = xmalloc(nsize);
- *sizep = nsize;
- last = 0;
-
- dst = buffer;
- do {
- unsigned char c = *src++;
- if (c == '\n' && last != '\r')
- *dst++ = '\r';
- *dst++ = c;
- last = c;
- } while (--size);
-
- return buffer;
+ /* are we "faking" in place editing ? */
+ if (src == buf->buf)
+ to_free = strbuf_detach(buf);
+
+ strbuf_grow(buf, len + stats.lf - stats.crlf);
+ for (;;) {
+ const char *nl = memchr(src, '\n', len);
+ if (!nl)
+ break;
+ if (nl > src && nl[-1] == '\r') {
+ strbuf_add(buf, src, nl + 1 - src);
+ } else {
+ strbuf_add(buf, src, nl - src);
+ strbuf_addstr(buf, "\r\n");
+ }
+ len -= nl + 1 - src;
+ src = nl + 1;
+ }
+ strbuf_add(buf, src, len);
+
+ free(to_free);
+ return 1;
}
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);
}
-static char *apply_filter(const char *path, const char *src,
- unsigned long *sizep, const char *cmd)
+static int apply_filter(const char *path, const char *src, size_t len,
+ struct strbuf *dst, const char *cmd)
{
/*
* 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
*/
- const int SLOP = 4096;
int pipe_feed[2];
- int status;
- char *dst;
- unsigned long dstsize, dstalloc;
+ int status, ret = 1;
struct child_process child_process;
+ struct strbuf nbuf;
if (!cmd)
- return NULL;
+ return 0;
memset(&child_process, 0, sizeof(child_process));
if (pipe(pipe_feed) < 0) {
error("cannot create pipe to run external filter %s", cmd);
- return NULL;
+ return 0;
}
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);
close(pipe_feed[0]);
close(pipe_feed[1]);
- return NULL;
+ return 0;
}
if (!child_process.pid) {
dup2(pipe_feed[1], 1);
close(pipe_feed[0]);
close(pipe_feed[1]);
- exit(filter_buffer(path, src, *sizep, cmd));
+ exit(filter_buffer(path, src, len, cmd));
}
close(pipe_feed[1]);
- dstalloc = *sizep;
- dst = xmalloc(dstalloc);
- 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);
- free(dst);
- dst = NULL;
- break;
- }
- dstsize += numread;
- if (dstalloc <= dstsize + SLOP) {
- dstalloc = dstsize + SLOP;
- dst = xrealloc(dst, dstalloc);
- }
+ strbuf_init(&nbuf, 0);
+ if (strbuf_read(&nbuf, pipe_feed[0], len) < 0) {
+ error("read from external filter %s failed", cmd);
+ ret = 0;
}
if (close(pipe_feed[0])) {
- error("read from external filter %s failed", cmd);
- free(dst);
- dst = NULL;
+ ret = error("read from external filter %s failed", cmd);
+ ret = 0;
}
-
status = finish_command(&child_process);
if (status) {
- error("external filter %s failed %d", cmd, -status);
- free(dst);
- dst = NULL;
+ ret = error("external filter %s failed %d", cmd, -status);
+ ret = 0;
}
- if (dst)
- *sizep = dstsize;
- return dst;
+ if (ret) {
+ *dst = nbuf;
+ } else {
+ strbuf_release(&nbuf);
+ }
+ return ret;
}
static struct convert_driver {
@@ -449,137 +419,104 @@ static int count_ident(const char *cp, unsigned long size)
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;
- unsigned long size;
- char *dst, *buf;
+ char *dst, *dollar;
- if (!ident)
- return NULL;
- size = *sizep;
- cnt = count_ident(src, size);
- if (!cnt)
- return NULL;
- buf = xmalloc(size);
-
- for (dst = buf; size; size--) {
- char ch = *src++;
- *dst++ = ch;
- if ((ch == '$') && (3 <= size) &&
- !memcmp("Id:", src, 3)) {
- unsigned long rem = size - 3;
- const char *cp = src + 3;
- do {
- ch = *cp++;
- if (ch == '$')
- break;
- rem--;
- } while (rem);
- if (!rem)
- continue;
+ if (!ident || !count_ident(src, len))
+ return 0;
+
+ strbuf_grow(buf, len);
+ dst = buf->buf;
+ for (;;) {
+ dollar = memchr(src, '$', len);
+ if (!dollar)
+ break;
+ memcpy(dst, src, dollar + 1 - src);
+ dst += dollar + 1 - src;
+ len -= dollar + 1 - src;
+ src = dollar + 1;
+
+ if (len > 3 && !memcmp(src, "Id:", 3)) {
+ dollar = memchr(src + 3, '$', len - 3);
+ if (!dollar)
+ break;
memcpy(dst, "Id$", 3);
dst += 3;
- size -= (cp - src);
- src = cp;
+ len -= dollar + 1 - src;
+ src = dollar + 1;
}
}
-
- *sizep = dst - buf;
- return buf;
+ memcpy(dst, src, len);
+ strbuf_setlen(buf, dst + len - buf->buf);
+ return 1;
}
-static char *ident_to_worktree(const char *path, const char *src, unsigned long *sizep, int ident)
+static int ident_to_worktree(const char *path, const char *src, size_t len,
+ struct strbuf *buf, int ident)
{
- int cnt;
- unsigned long size;
- char *dst, *buf;
unsigned char sha1[20];
+ char *to_free = NULL, *dollar;
+ int cnt;
if (!ident)
- return NULL;
+ return 0;
- size = *sizep;
- cnt = count_ident(src, size);
+ cnt = count_ident(src, len);
if (!cnt)
- return NULL;
+ return 0;
- hash_sha1_file(src, size, "blob", sha1);
- buf = xmalloc(size + cnt * 43);
-
- for (dst = buf; size; size--) {
- const char *cp;
- /* Fetch next source character, move the pointer on */
- char ch = *src++;
- /* Copy the current character to the destination */
- *dst++ = ch;
- /* If the current character is "$" or there are less than three
- * remaining bytes or the two bytes following this one are not
- * "Id", then simply read the next character */
- if ((ch != '$') || (size < 3) || memcmp("Id", src, 2))
- continue;
- /*
- * Here when
- * - There are more than 2 bytes remaining
- * - The current three bytes are "$Id"
- * with
- * - ch == "$"
- * - src[0] == "I"
- */
+ /* are we "faking" in place editing ? */
+ if (src == buf->buf)
+ to_free = strbuf_detach(buf);
+ hash_sha1_file(src, len, "blob", sha1);
- /*
- * It's possible that an expanded Id has crept its way into the
- * repository, we cope with that by stripping the expansion out
- */
- if (src[2] == ':') {
- /* Expanded keywords have "$Id:" at the front */
+ strbuf_grow(buf, len + cnt * 43);
+ for (;;) {
+ /* step 1: run to the next '$' */
+ dollar = memchr(src, '$', len);
+ if (!dollar)
+ break;
+ strbuf_add(buf, src, dollar + 1 - src);
+ len -= dollar + 1 - src;
+ src = dollar + 1;
- /* 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;
- 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 */
+ /* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
+ if (len < 3 || memcmp("Id", src, 2))
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++ = ' ';
+ /* 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
+ * repository, we cope with that by stripping the expansion out
+ */
+ dollar = memchr(src + 3, '$', len - 3);
+ if (!dollar) {
+ /* incomplete keyword, no more '$', so just quit the loop */
+ break;
+ }
- /* Adjust for the characters we've discarded */
- size -= (cp - src);
- src = cp;
+ len -= dollar + 1 - src;
+ src = dollar + 1;
+ } else {
+ /* it wasn't a "Id$" or "Id:xxxx$" */
+ continue;
+ }
- /* Copy the final "$" */
- *dst++ = *src++;
- size--;
+ /* step 4: substitute */
+ strbuf_addstr(buf, "Id: ");
+ strbuf_add(buf, sha1_to_hex(sha1), 40);
+ strbuf_addstr(buf, " $");
}
+ strbuf_add(buf, src, len);
- *sizep = dst - buf;
- return buf;
+ free(to_free);
+ return 1;
}
static int git_path_check_crlf(const char *path, struct git_attr_check *check)
@@ -618,13 +555,12 @@ static int git_path_check_ident(const char *path, struct git_attr_check *check)
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];
int crlf = CRLF_GUESS;
- int ident = 0;
+ int ident = 0, ret = 0;
char *filter = NULL;
- char *buf, *buf2;
setup_convert_check(check);
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
@@ -636,30 +572,25 @@ char *convert_to_git(const char *path, const char *src, unsigned long *sizep)
filter = drv->clean;
}
- buf = apply_filter(path, src, sizep, filter);
-
- buf2 = crlf_to_git(path, buf ? buf : src, sizep, crlf);
- if (buf2) {
- free(buf);
- buf = buf2;
+ ret |= apply_filter(path, src, len, dst, filter);
+ if (ret) {
+ src = dst->buf;
+ len = dst->len;
}
-
- buf2 = ident_to_git(path, buf ? buf : src, sizep, ident);
- if (buf2) {
- free(buf);
- buf = buf2;
+ ret |= crlf_to_git(path, src, len, dst, crlf);
+ if (ret) {
+ src = dst->buf;
+ len = dst->len;
}
-
- return buf;
+ return ret | ident_to_git(path, src, len, dst, ident);
}
-char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep)
+int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
{
struct git_attr_check check[3];
int crlf = CRLF_GUESS;
- int ident = 0;
+ int ident = 0, ret = 0;
char *filter = NULL;
- char *buf, *buf2;
setup_convert_check(check);
if (!git_checkattr(path, ARRAY_SIZE(check), check)) {
@@ -671,19 +602,15 @@ char *convert_to_working_tree(const char *path, const char *src, unsigned long *
filter = drv->smudge;
}
- buf = ident_to_worktree(path, src, sizep, ident);
-
- buf2 = crlf_to_worktree(path, buf ? buf : src, sizep, crlf);
- if (buf2) {
- free(buf);
- buf = buf2;
+ ret |= ident_to_worktree(path, src, len, dst, ident);
+ if (ret) {
+ src = dst->buf;
+ len = dst->len;
}
-
- buf2 = apply_filter(path, buf ? buf : src, sizep, filter);
- if (buf2) {
- free(buf);
- buf = buf2;
+ ret |= crlf_to_worktree(path, src, len, dst, crlf);
+ if (ret) {
+ src = dst->buf;
+ len = dst->len;
}
-
- return buf;
+ return ret | apply_filter(path, src, len, dst, filter);
}
diff --git a/diff.c b/diff.c
index 0ee9ea1c1..a5b69ed2d 100644
--- a/diff.c
+++ b/diff.c
@@ -1545,26 +1545,16 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
static int populate_from_stdin(struct diff_filespec *s)
{
-#define INCREMENT 1024
- char *buf;
- unsigned long size;
- ssize_t got;
-
- size = 0;
- buf = NULL;
- 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",
+ struct strbuf buf;
+
+ strbuf_init(&buf, 0);
+ if (strbuf_read(&buf, 0, 0) < 0)
+ return error("error while reading from stdin %s",
strerror(errno));
- size += got;
- }
+
s->should_munmap = 0;
- s->data = buf;
- s->size = size;
+ s->size = buf.len;
+ s->data = strbuf_detach(&buf);
s->should_free = 1;
return 0;
}
@@ -1609,10 +1599,9 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
if (!s->sha1_valid ||
reuse_worktree_file(s->path, s->sha1, 0)) {
+ struct strbuf buf;
struct stat st;
int fd;
- char *buf;
- unsigned long size;
if (!strcmp(s->path, "-"))
return populate_from_stdin(s);
@@ -1653,13 +1642,12 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
/*
* Convert from working tree format to canonical git format
*/
- size = s->size;
- buf = convert_to_git(s->path, s->data, &size);
- if (buf) {
+ strbuf_init(&buf, 0);
+ if (convert_to_git(s->path, s->data, s->size, &buf)) {
munmap(s->data, s->size);
s->should_munmap = 0;
- s->data = buf;
- s->size = size;
+ s->data = buf.buf;
+ s->size = buf.len;
s->should_free = 1;
}
}
diff --git a/entry.c b/entry.c
index fc3a506ec..4a8c73bfa 100644
--- a/entry.c
+++ b/entry.c
@@ -104,7 +104,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
long wrote;
switch (ntohl(ce->ce_mode) & S_IFMT) {
- char *buf, *new;
+ char *new;
+ struct strbuf buf;
unsigned long size;
case S_IFREG:
@@ -116,10 +117,11 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
/*
* Convert from git internal format to working tree format
*/
- buf = convert_to_working_tree(ce->name, new, &size);
- if (buf) {
+ strbuf_init(&buf, 0);
+ if (convert_to_working_tree(ce->name, new, size, &buf)) {
free(new);
- new = buf;
+ new = buf.buf;
+ size = buf.len;
}
if (to_tempfile) {
diff --git a/fast-import.c b/fast-import.c
index 078079d40..e2a483470 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -149,7 +149,6 @@ Format of STDIN stream:
#include "pack.h"
#include "refs.h"
#include "csum-file.h"
-#include "strbuf.h"
#include "quote.h"
#define PACK_ID_BITS 16
@@ -183,11 +182,10 @@ struct mark_set
struct last_object
{
- void *data;
- unsigned long len;
+ struct strbuf data;
uint32_t offset;
unsigned int depth;
- unsigned no_free:1;
+ unsigned no_swap : 1;
};
struct mem_pool
@@ -251,12 +249,6 @@ struct tag
unsigned char sha1[20];
};
-struct dbuf
-{
- void *buffer;
- size_t capacity;
-};
-
struct hash_list
{
struct hash_list *next;
@@ -317,15 +309,15 @@ static struct mark_set *marks;
static const char* mark_file;
/* Our last blob */
-static struct last_object last_blob;
+static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 };
/* Tree management */
static unsigned int tree_entry_alloc = 1000;
static void *avail_tree_entry;
static unsigned int avail_tree_table_sz = 100;
static struct avail_tree_content **avail_tree_table;
-static struct dbuf old_tree;
-static struct dbuf new_tree;
+static struct strbuf old_tree = STRBUF_INIT;
+static struct strbuf new_tree = STRBUF_INIT;
/* Branch data */
static unsigned long max_active_branches = 5;
@@ -340,14 +332,14 @@ static struct tag *last_tag;
/* Input stream parsing */
static whenspec_type whenspec = WHENSPEC_RAW;
-static struct strbuf command_buf;
+static struct strbuf command_buf = STRBUF_INIT;
static int unread_command_buf;
static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
static struct recent_command *cmd_tail = &cmd_hist;
static struct recent_command *rc_free;
static unsigned int cmd_save = 100;
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)
{
@@ -567,17 +559,6 @@ static char *pool_strdup(const char *s)
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)
{
struct mark_set *s = marks;
@@ -968,9 +949,7 @@ static void end_packfile(void)
free(old_p);
/* We can't carry a delta across packfiles. */
- free(last_blob.data);
- last_blob.data = NULL;
- last_blob.len = 0;
+ strbuf_release(&last_blob.data);
last_blob.offset = 0;
last_blob.depth = 0;
}
@@ -1006,8 +985,7 @@ static size_t encode_header(
static int store_object(
enum object_type type,
- void *dat,
- size_t datlen,
+ struct strbuf *dat,
struct last_object *last,
unsigned char *sha1out,
uintmax_t mark)
@@ -1021,10 +999,10 @@ static int store_object(
z_stream s;
hdrlen = sprintf((char*)hdr,"%s %lu", typename(type),
- (unsigned long)datlen) + 1;
+ (unsigned long)dat->len) + 1;
SHA1_Init(&c);
SHA1_Update(&c, hdr, hdrlen);
- SHA1_Update(&c, dat, datlen);
+ SHA1_Update(&c, dat->buf, dat->len);
SHA1_Final(sha1, &c);
if (sha1out)
hashcpy(sha1out, sha1);
@@ -1043,11 +1021,11 @@ static int store_object(
return 1;
}
- if (last && last->data && last->depth < max_depth) {
- delta = diff_delta(last->data, last->len,
- dat, datlen,
+ if (last && last->data.buf && last->depth < max_depth) {
+ delta = diff_delta(last->data.buf, last->data.len,
+ dat->buf, dat->len,
&deltalen, 0);
- if (delta && deltalen >= datlen) {
+ if (delta && deltalen >= dat->len) {
free(delta);
delta = NULL;
}
@@ -1060,8 +1038,8 @@ static int store_object(
s.next_in = delta;
s.avail_in = deltalen;
} else {
- s.next_in = dat;
- s.avail_in = datlen;
+ s.next_in = (void *)dat->buf;
+ s.avail_in = dat->len;
}
s.avail_out = deflateBound(&s, s.avail_in);
s.next_out = out = xmalloc(s.avail_out);
@@ -1084,8 +1062,8 @@ static int store_object(
memset(&s, 0, sizeof(s));
deflateInit(&s, zlib_compression_level);
- s.next_in = dat;
- s.avail_in = datlen;
+ s.next_in = (void *)dat->buf;
+ s.avail_in = dat->len;
s.avail_out = deflateBound(&s, s.avail_in);
s.next_out = out = xrealloc(out, s.avail_out);
while (deflate(&s, Z_FINISH) == Z_OK)
@@ -1119,7 +1097,7 @@ static int store_object(
} else {
if (last)
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);
pack_size += hdrlen;
}
@@ -1130,11 +1108,14 @@ static int store_object(
free(out);
free(delta);
if (last) {
- if (!last->no_free)
- free(last->data);
- last->data = dat;
+ if (last->no_swap) {
+ last->data = *dat;
+ } else {
+ struct strbuf tmp = *dat;
+ *dat = last->data;
+ last->data = tmp;
+ }
last->offset = e->offset;
- last->len = datlen;
}
return 0;
}
@@ -1230,14 +1211,10 @@ static int tecmp1 (const void *_a, const void *_b)
b->name->str_dat, b->name->str_len, b->versions[1].mode);
}
-static void mktree(struct tree_content *t,
- int v,
- unsigned long *szp,
- struct dbuf *b)
+static void mktree(struct tree_content *t, int v, struct strbuf *b)
{
size_t maxlen = 0;
unsigned int i;
- char *c;
if (!v)
qsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp0);
@@ -1249,28 +1226,23 @@ static void mktree(struct tree_content *t,
maxlen += t->entries[i]->name->str_len + 34;
}
- size_dbuf(b, maxlen);
- c = b->buffer;
+ strbuf_reset(b);
+ strbuf_grow(b, maxlen);
for (i = 0; i < t->entry_count; i++) {
struct tree_entry *e = t->entries[i];
if (!e->versions[v].mode)
continue;
- c += sprintf(c, "%o", (unsigned int)e->versions[v].mode);
- *c++ = ' ';
- strcpy(c, e->name->str_dat);
- c += e->name->str_len + 1;
- hashcpy((unsigned char*)c, e->versions[v].sha1);
- c += 20;
+ strbuf_addf(b, "%o %s%c", (unsigned int)e->versions[v].mode,
+ e->name->str_dat, '\0');
+ strbuf_add(b, e->versions[v].sha1, 20);
}
- *szp = c - (char*)b->buffer;
}
static void store_tree(struct tree_entry *root)
{
struct tree_content *t = root->tree;
unsigned int i, j, del;
- unsigned long new_len;
- struct last_object lo;
+ struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };
struct object_entry *le;
if (!is_null_sha1(root->versions[1].sha1))
@@ -1282,23 +1254,15 @@ static void store_tree(struct tree_entry *root)
}
le = find_object(root->versions[0].sha1);
- if (!S_ISDIR(root->versions[0].mode)
- || !le
- || le->pack_id != pack_id) {
- lo.data = NULL;
- lo.depth = 0;
- lo.no_free = 0;
- } else {
- mktree(t, 0, &lo.len, &old_tree);
- lo.data = old_tree.buffer;
+ if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
+ mktree(t, 0, &old_tree);
+ lo.data = old_tree;
lo.offset = le->offset;
lo.depth = t->delta_depth;
- lo.no_free = 1;
}
- mktree(t, 1, &new_len, &new_tree);
- store_object(OBJ_TREE, new_tree.buffer, new_len,
- &lo, root->versions[1].sha1, 0);
+ mktree(t, 1, &new_tree);
+ store_object(OBJ_TREE, &new_tree, &lo, root->versions[1].sha1, 0);
t->delta_depth = lo.depth;
for (i = 0, j = 0, del = 0; i < t->entry_count; i++) {
@@ -1585,20 +1549,25 @@ static void dump_marks(void)
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 {
if (unread_command_buf) {
unread_command_buf = 0;
- if (command_buf.eof)
- return;
} else {
struct recent_command *rc;
- command_buf.buf = NULL;
- read_line(&command_buf, stdin, '\n');
- if (command_buf.eof)
- return;
+ strbuf_detach(&command_buf);
+ stdin_eof = strbuf_getline(&command_buf, stdin, '\n');
+ if (stdin_eof)
+ return EOF;
rc = rc_free;
if (rc)
@@ -1617,6 +1586,8 @@ static void read_next_command(void)
cmd_tail = rc;
}
} while (command_buf.buf[0] == '#');
+
+ return 0;
}
static void skip_optional_lf(void)
@@ -1636,42 +1607,35 @@ static void cmd_mark(void)
next_mark = 0;
}
-static void *cmd_data (size_t *size)
+static void cmd_data(struct strbuf *sb)
{
- size_t length;
- char *buffer;
+ strbuf_reset(sb);
if (prefixcmp(command_buf.buf, "data "))
die("Expected 'data n' command, found: %s", command_buf.buf);
if (!prefixcmp(command_buf.buf + 5, "<<")) {
char *term = xstrdup(command_buf.buf + 5 + 2);
- size_t sz = 8192, term_len = command_buf.len - 5 - 2;
- length = 0;
- buffer = xmalloc(sz);
- command_buf.buf = NULL;
+ size_t term_len = command_buf.len - 5 - 2;
+
for (;;) {
- read_line(&command_buf, stdin, '\n');
- if (command_buf.eof)
+ if (strbuf_getline(&command_buf, stdin, '\n') == EOF)
die("EOF in data (terminator '%s' not found)", term);
if (term_len == command_buf.len
&& !strcmp(term, command_buf.buf))
break;
- ALLOC_GROW(buffer, length + command_buf.len, sz);
- memcpy(buffer + length,
- command_buf.buf,
- command_buf.len - 1);
- length += command_buf.len - 1;
- buffer[length++] = '\n';
+ strbuf_addbuf(sb, &command_buf);
+ strbuf_addch(sb, '\n');
}
free(term);
}
else {
- size_t n = 0;
+ size_t n = 0, length;
+
length = strtoul(command_buf.buf + 5, NULL, 10);
- buffer = xmalloc(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))
die("EOF in data (%lu bytes remaining)",
(unsigned long)(length - n));
@@ -1680,8 +1644,6 @@ static void *cmd_data (size_t *size)
}
skip_optional_lf();
- *size = length;
- return buffer;
}
static int validate_raw_date(const char *src, char *result, int maxlen)
@@ -1744,15 +1706,12 @@ static char *parse_ident(const char *buf)
static void cmd_new_blob(void)
{
- size_t l;
- void *d;
+ static struct strbuf buf = STRBUF_INIT;
read_next_command();
cmd_mark();
- d = cmd_data(&l);
-
- if (store_object(OBJ_BLOB, d, l, &last_blob, NULL, next_mark))
- free(d);
+ cmd_data(&buf);
+ store_object(OBJ_BLOB, &buf, &last_blob, NULL, next_mark);
}
static void unload_one_branch(void)
@@ -1848,14 +1807,13 @@ static void file_change_m(struct branch *b)
}
if (inline_data) {
- size_t l;
- void *d;
+ static struct strbuf buf = STRBUF_INIT;
+
if (!p_uq)
p = p_uq = xstrdup(p);
read_next_command();
- d = cmd_data(&l);
- if (store_object(OBJ_BLOB, d, l, &last_blob, sha1, 0))
- free(d);
+ cmd_data(&buf);
+ store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0);
} else if (oe) {
if (oe->type != OBJ_BLOB)
die("Not a blob (actually a %s): %s",
@@ -2062,9 +2020,8 @@ static struct hash_list *cmd_merge(unsigned int *count)
static void cmd_new_commit(void)
{
+ static struct strbuf msg = STRBUF_INIT;
struct branch *b;
- void *msg;
- size_t msglen;
char *sp;
char *author = NULL;
char *committer = NULL;
@@ -2089,7 +2046,7 @@ static void cmd_new_commit(void)
}
if (!committer)
die("Expected committer but didn't get one");
- msg = cmd_data(&msglen);
+ cmd_data(&msg);
read_next_command();
cmd_from(b);
merge_list = cmd_merge(&merge_count);
@@ -2101,7 +2058,7 @@ static void cmd_new_commit(void)
}
/* file_change* */
- while (!command_buf.eof && command_buf.len > 1) {
+ while (command_buf.len > 0) {
if (!prefixcmp(command_buf.buf, "M "))
file_change_m(b);
else if (!prefixcmp(command_buf.buf, "D "))
@@ -2116,53 +2073,47 @@ static void cmd_new_commit(void)
unread_command_buf = 1;
break;
}
- read_next_command();
+ if (read_next_command() == EOF)
+ break;
}
/* build the tree and the commit */
store_tree(&b->branch_tree);
hashcpy(b->branch_tree.versions[0].sha1,
b->branch_tree.versions[1].sha1);
- size_dbuf(&new_data, 114 + msglen
- + merge_count * 49
- + (author
- ? strlen(author) + strlen(committer)
- : 2 * strlen(committer)));
- sp = new_data.buffer;
- sp += sprintf(sp, "tree %s\n",
+
+ strbuf_reset(&new_data);
+ strbuf_addf(&new_data, "tree %s\n",
sha1_to_hex(b->branch_tree.versions[1].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) {
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);
merge_list = next;
}
- sp += sprintf(sp, "author %s\n", author ? author : committer);
- sp += sprintf(sp, "committer %s\n", committer);
- *sp++ = '\n';
- memcpy(sp, msg, msglen);
- sp += msglen;
+ strbuf_addf(&new_data,
+ "author %s\n"
+ "committer %s\n"
+ "\n",
+ author ? author : committer, committer);
+ strbuf_addbuf(&new_data, &msg);
free(author);
free(committer);
- free(msg);
- if (!store_object(OBJ_COMMIT,
- new_data.buffer, sp - (char*)new_data.buffer,
- NULL, b->sha1, next_mark))
+ if (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark))
b->pack_id = pack_id;
b->last_commit = object_count_by_type[OBJ_COMMIT];
}
static void cmd_new_tag(void)
{
+ static struct strbuf msg = STRBUF_INIT;
char *sp;
const char *from;
char *tagger;
struct branch *s;
- void *msg;
- size_t msglen;
struct tag *t;
uintmax_t from_mark = 0;
unsigned char sha1[20];
@@ -2213,24 +2164,21 @@ static void cmd_new_tag(void)
/* tag payload/message */
read_next_command();
- msg = cmd_data(&msglen);
+ cmd_data(&msg);
/* build the tag object */
- size_dbuf(&new_data, 67+strlen(t->name)+strlen(tagger)+msglen);
- sp = new_data.buffer;
- sp += sprintf(sp, "object %s\n", sha1_to_hex(sha1));
- sp += sprintf(sp, "type %s\n", commit_type);
- sp += sprintf(sp, "tag %s\n", t->name);
- sp += sprintf(sp, "tagger %s\n", tagger);
- *sp++ = '\n';
- memcpy(sp, msg, msglen);
- sp += msglen;
+ strbuf_reset(&new_data);
+ strbuf_addf(&new_data,
+ "object %s\n"
+ "type %s\n"
+ "tag %s\n"
+ "tagger %s\n"
+ "\n",
+ sha1_to_hex(sha1), commit_type, t->name, tagger);
+ strbuf_addbuf(&new_data, &msg);
free(tagger);
- free(msg);
- if (store_object(OBJ_TAG, new_data.buffer,
- sp - (char*)new_data.buffer,
- NULL, t->sha1, 0))
+ if (store_object(OBJ_TAG, &new_data, NULL, t->sha1, 0))
t->pack_id = MAX_PACK_ID;
else
t->pack_id = pack_id;
@@ -2256,7 +2204,7 @@ static void cmd_reset_branch(void)
else
b = new_branch(sp);
read_next_command();
- if (!cmd_from(b) && command_buf.len > 1)
+ if (!cmd_from(b) && command_buf.len > 0)
unread_command_buf = 1;
}
@@ -2273,7 +2221,7 @@ static void cmd_checkpoint(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);
fflush(stdout);
skip_optional_lf();
@@ -2323,7 +2271,7 @@ int main(int argc, const char **argv)
git_config(git_default_config);
alloc_objects(object_entry_alloc);
- strbuf_init(&command_buf);
+ strbuf_init(&command_buf, 0);
atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*));
branch_table = xcalloc(branch_table_sz, sizeof(struct branch*));
avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*));
@@ -2381,11 +2329,8 @@ int main(int argc, const char **argv)
prepare_packed_git();
start_packfile();
set_die_routine(die_nicely);
- for (;;) {
- read_next_command();
- if (command_buf.eof)
- break;
- else if (!strcmp("blob", command_buf.buf))
+ while (read_next_command() != EOF) {
+ if (!strcmp("blob", command_buf.buf))
cmd_new_blob();
else if (!prefixcmp(command_buf.buf, "commit "))
cmd_new_commit();
diff --git a/fetch.c b/fetch.c
index 811be87a3..b1c1f07b2 100644
--- a/fetch.c
+++ b/fetch.c
@@ -6,7 +6,6 @@
#include "tag.h"
#include "blob.h"
#include "refs.h"
-#include "strbuf.h"
int get_tree = 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;
struct strbuf buf;
*target = NULL; *write_ref = NULL;
- strbuf_init(&buf);
+ strbuf_init(&buf, 0);
while (1) {
char *rf_one = NULL;
char *tg_one;
- read_line(&buf, stdin, '\n');
- if (buf.eof)
+ if (strbuf_getline(&buf, stdin, '\n') == EOF)
break;
tg_one = buf.buf;
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;
targets++;
}
+ strbuf_release(&buf);
return targets;
}
diff --git a/git-compat-util.h b/git-compat-util.h
index 1bfbdeb94..f23d934f6 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -211,19 +211,20 @@ static inline void *xmalloc(size_t size)
return ret;
}
-static inline char *xstrndup(const char *str, size_t len)
+static inline void *xmemdupz(const void *data, size_t len)
{
- char *p;
-
- p = memchr(str, '\0', len);
- if (p)
- len = p - str;
- p = xmalloc(len + 1);
- memcpy(p, str, len);
+ char *p = xmalloc(len + 1);
+ memcpy(p, data, len);
p[len] = '\0';
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)
{
void *ret = realloc(ptr, size);
diff --git a/imap-send.c b/imap-send.c
index a5a069608..86e4a0f6a 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1160,28 +1160,18 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
static int
read_message( FILE *f, msg_data_t *msg )
{
- int len, r;
+ struct strbuf buf;
- memset( msg, 0, sizeof *msg );
- len = CHUNKSIZE;
- msg->data = xmalloc( len+1 );
- msg->data[0] = 0;
-
- while(!feof( f )) {
- if (msg->len >= len) {
- void *p;
- len += CHUNKSIZE;
- p = xrealloc(msg->data, len+1);
- if (!p)
- break;
- msg->data = p;
- }
- r = fread( &msg->data[msg->len], 1, len - msg->len, f );
- if (r <= 0)
+ memset(msg, 0, sizeof(*msg));
+ strbuf_init(&buf, 0);
+
+ do {
+ if (strbuf_fread(&buf, CHUNKSIZE, f) <= 0)
break;
- msg->len += r;
- }
- msg->data[msg->len] = 0;
+ } while (!feof(f));
+
+ msg->len = buf.len;
+ msg->data = strbuf_detach(&buf);
return msg->len;
}
diff --git a/interpolate.c b/interpolate.c
index 00826778f..3de583238 100644
--- a/interpolate.c
+++ b/interpolate.c
@@ -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 a number of bytes needed to hold the full substituted
- * string otherwise.
+ * Returns the length of the substituted string (not including the final \0).
+ * Like with snprintf, if the result is >= reslen, then it overflowed.
*/
unsigned long interpolate(char *result, unsigned long reslen,
@@ -61,8 +60,6 @@ unsigned long interpolate(char *result, unsigned long reslen,
int i;
char c;
- memset(result, 0, reslen);
-
while ((c = *src)) {
if (c == '%') {
/* Try to match an interpolation string. */
@@ -78,9 +75,9 @@ unsigned long interpolate(char *result, unsigned long reslen,
value = interps[i].value;
valuelen = strlen(value);
- if (newlen + valuelen + 1 < reslen) {
+ if (newlen + valuelen < reslen) {
/* Substitute. */
- strncpy(dest, value, valuelen);
+ memcpy(dest, value, valuelen);
dest += valuelen;
}
newlen += valuelen;
@@ -95,8 +92,9 @@ unsigned long interpolate(char *result, unsigned long reslen,
newlen++;
}
- if (newlen + 1 < reslen)
- return 0;
- else
- return newlen + 2;
+ /* XXX: the previous loop always keep room for the ending NUL,
+ we just need to check if there was room for a NUL in the first place */
+ if (reslen > 0)
+ *dest = '\0';
+ return newlen;
}
diff --git a/log-tree.c b/log-tree.c
index a6423718e..3e5e6acfa 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -79,25 +79,14 @@ static int detect_any_signoff(char *letter, int size)
return seen_head && seen_name;
}
-static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,
- unsigned long at, const char *signoff)
+static void append_signoff(struct strbuf *sb, const char *signoff)
{
static const char signed_off_by[] = "Signed-off-by: ";
size_t signoff_len = strlen(signoff);
int has_signoff = 0;
char *cp;
- char *buf;
- unsigned long buf_sz;
-
- buf = *buf_p;
- buf_sz = *buf_sz_p;
- if (buf_sz <= at + strlen(signed_off_by) + signoff_len + 3) {
- buf_sz += strlen(signed_off_by) + signoff_len + 3;
- buf = xrealloc(buf, buf_sz);
- *buf_p = buf;
- *buf_sz_p = buf_sz;
- }
- cp = buf;
+
+ cp = sb->buf;
/* First see if we already have the sign-off by the signer */
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;
cp += strlen(signed_off_by);
- if (cp + signoff_len >= buf + at)
+ if (cp + signoff_len >= sb->buf + sb->len)
break;
if (strncmp(cp, signoff, signoff_len))
continue;
if (!isspace(cp[signoff_len]))
continue;
/* we already have him */
- return at;
+ return;
}
if (!has_signoff)
- has_signoff = detect_any_signoff(buf, at);
+ has_signoff = detect_any_signoff(sb->buf, sb->len);
if (!has_signoff)
- buf[at++] = '\n';
-
- strcpy(buf + at, signed_off_by);
- at += strlen(signed_off_by);
- strcpy(buf + at, signoff);
- at += signoff_len;
- buf[at++] = '\n';
- buf[at] = 0;
- return at;
+ strbuf_addch(sb, '\n');
+
+ strbuf_addstr(sb, signed_off_by);
+ strbuf_add(sb, signoff, signoff_len);
+ strbuf_addch(sb, '\n');
}
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)
{
- char *msgbuf = NULL;
- unsigned long msgbuf_len = 0;
+ struct strbuf msgbuf;
struct log_info *log = opt->loginfo;
struct commit *commit = log->commit, *parent = log->parent;
int abbrev = opt->diffopt.abbrev;
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
const char *extra;
- int len;
const char *subject = NULL, *extra_headers = opt->extra_headers;
opt->loginfo = NULL;
@@ -288,18 +271,17 @@ void show_log(struct rev_info *opt, const char *sep)
/*
* And then the pretty-printed message itself
*/
- len = pretty_print_commit(opt->commit_format, commit, ~0u,
- &msgbuf, &msgbuf_len, abbrev, subject,
- extra_headers, opt->date_mode);
+ strbuf_init(&msgbuf, 0);
+ pretty_print_commit(opt->commit_format, commit, &msgbuf,
+ abbrev, subject, extra_headers, opt->date_mode);
if (opt->add_signoff)
- len = append_signoff(&msgbuf, &msgbuf_len, len,
- opt->add_signoff);
+ append_signoff(&msgbuf, opt->add_signoff);
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);
- free(msgbuf);
+ printf("%s%s%s", msgbuf.buf, extra, sep);
+ strbuf_release(&msgbuf);
}
int log_tree_diff_flush(struct rev_info *opt)
diff --git a/mktag.c b/mktag.c
index 38acd5a29..b05260c83 100644
--- a/mktag.c
+++ b/mktag.c
@@ -111,8 +111,7 @@ static int verify_tag(char *buffer, unsigned long size)
int main(int argc, char **argv)
{
- unsigned long size = 4096;
- char *buffer = xmalloc(size);
+ struct strbuf buf;
unsigned char result_sha1[20];
if (argc != 1)
@@ -120,21 +119,20 @@ int main(int argc, char **argv)
setup_git_directory();
- if (read_fd(0, &buffer, &size)) {
- free(buffer);
+ strbuf_init(&buf, 0);
+ if (strbuf_read(&buf, 0, 4096) < 0) {
die("could not read from stdin");
}
/* Verify it for some basic sanity: it needs to start with
"object <sha1>\ntype\ntagger " */
- if (verify_tag(buffer, size) < 0)
+ if (verify_tag(buf.buf, buf.len) < 0)
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");
- free(buffer);
-
+ strbuf_release(&buf);
printf("%s\n", sha1_to_hex(result_sha1));
return 0;
}
diff --git a/mktree.c b/mktree.c
index d86dde89d..9c137dec4 100644
--- a/mktree.c
+++ b/mktree.c
@@ -4,7 +4,6 @@
* Copyright (c) Junio C Hamano, 2006
*/
#include "cache.h"
-#include "strbuf.h"
#include "quote.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)
{
- char *buffer;
- unsigned long size, offset;
+ struct strbuf buf;
+ size_t size;
int i;
qsort(entries, used, sizeof(*entries), ent_compare);
for (size = i = 0; i < used; i++)
size += 32 + entries[i]->len;
- buffer = xmalloc(size);
- offset = 0;
+ strbuf_init(&buf, size);
for (i = 0; i < used; i++) {
struct treeent *ent = entries[i];
-
- if (offset + ent->len + 100 < size) {
- 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;
+ strbuf_addf(&buf, "%o %s%c", ent->mode, ent->name, '\0');
+ strbuf_add(&buf, ent->sha1, 20);
}
- write_sha1_file(buffer, offset, tree_type, sha1);
+
+ write_sha1_file(buf.buf, buf.len, tree_type, sha1);
}
static const char mktree_usage[] = "git-mktree [-z]";
@@ -90,18 +81,15 @@ int main(int ac, char **av)
av++;
}
- strbuf_init(&sb);
+ strbuf_init(&sb, 0);
while (1) {
- int len;
char *ptr, *ntr;
unsigned mode;
enum object_type type;
char *path;
- read_line(&sb, stdin, line_termination);
- if (sb.eof)
+ if (strbuf_getline(&sb, stdin, line_termination) == EOF)
break;
- len = sb.len;
ptr = sb.buf;
/* Input is non-recursive ls-tree output format
* mode SP type SP sha1 TAB name
@@ -111,7 +99,7 @@ int main(int ac, char **av)
die("input format error: %s", sb.buf);
ptr = ntr + 1; /* type */
ntr = strchr(ptr, ' ');
- if (!ntr || sb.buf + len <= ntr + 41 ||
+ if (!ntr || sb.buf + sb.len <= ntr + 40 ||
ntr[41] != '\t' ||
get_sha1_hex(ntr + 1, sha1))
die("input format error: %s", sb.buf);
@@ -132,6 +120,7 @@ int main(int ac, char **av)
if (path != ntr)
free(path);
}
+ strbuf_release(&sb);
write_tree(sha1);
puts(sha1_to_hex(sha1));
exit(0);
diff --git a/sha1_file.c b/sha1_file.c
index 9978a58da..59325d46b 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2302,68 +2302,25 @@ int has_sha1_file(const unsigned char *sha1)
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)
{
- unsigned long size = 4096;
- char *buf = xmalloc(size);
+ struct strbuf buf;
int ret;
- if (read_fd(fd, &buf, &size)) {
- free(buf);
+ strbuf_init(&buf, 0);
+ if (strbuf_read(&buf, fd, 4096) < 0) {
+ strbuf_release(&buf);
return -1;
}
if (!type)
type = blob_type;
if (write_object)
- ret = write_sha1_file(buf, size, type, sha1);
+ ret = write_sha1_file(buf.buf, buf.len, type, sha1);
else
- ret = hash_sha1_file(buf, size, type, sha1);
- free(buf);
+ ret = hash_sha1_file(buf.buf, buf.len, type, sha1);
+ strbuf_release(&buf);
+
return ret;
}
@@ -2385,12 +2342,12 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
* Convert blobs to git internal format
*/
if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) {
- unsigned long nsize = size;
- char *nbuf = convert_to_git(path, buf, &nsize);
- if (nbuf) {
+ struct strbuf nbuf;
+ strbuf_init(&nbuf, 0);
+ if (convert_to_git(path, buf, size, &nbuf)) {
munmap(buf, size);
- size = nsize;
- buf = nbuf;
+ size = nbuf.len;
+ buf = nbuf.buf;
re_allocated = 1;
}
}
diff --git a/strbuf.c b/strbuf.c
index e33d06b87..59383ac77 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,41 +1,167 @@
#include "cache.h"
-#include "strbuf.h"
-void strbuf_init(struct strbuf *sb) {
- sb->buf = NULL;
- sb->eof = sb->alloc = sb->len = 0;
+void strbuf_init(struct strbuf *sb, size_t hint)
+{
+ memset(sb, 0, sizeof(*sb));
+ if (hint)
+ strbuf_grow(sb, hint);
}
-static void strbuf_begin(struct strbuf *sb) {
+void strbuf_release(struct strbuf *sb)
+{
free(sb->buf);
- strbuf_init(sb);
+ memset(sb, 0, sizeof(*sb));
}
-static void inline strbuf_add(struct strbuf *sb, int ch) {
- if (sb->alloc <= sb->len) {
- sb->alloc = sb->alloc * 3 / 2 + 16;
- sb->buf = xrealloc(sb->buf, sb->alloc);
+void strbuf_reset(struct strbuf *sb)
+{
+ if (sb->len)
+ strbuf_setlen(sb, 0);
+}
+
+char *strbuf_detach(struct strbuf *sb)
+{
+ char *res = sb->buf;
+ strbuf_init(sb, 0);
+ return res;
+}
+
+void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
+{
+ strbuf_release(sb);
+ sb->buf = buf;
+ sb->len = len;
+ sb->alloc = alloc;
+ strbuf_grow(sb, 0);
+ sb->buf[sb->len] = '\0';
+}
+
+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");
+ 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';
+}
+
+void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
+{
+ strbuf_grow(sb, len);
+ if (pos > sb->len)
+ die("`pos' is too far after the end of the buffer");
+ memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos);
+ memcpy(sb->buf + pos, data, len);
+ strbuf_setlen(sb, sb->len + 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_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;
}
- sb->buf[sb->len++] = ch;
+ 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);
}
-static void strbuf_end(struct strbuf *sb) {
- strbuf_add(sb, 0);
+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;
}
-void read_line(struct strbuf *sb, FILE *fp, int term) {
- int ch;
- strbuf_begin(sb);
- if (feof(fp)) {
- sb->eof = 1;
- return;
+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;
+
+ strbuf_grow(sb, 0);
+ if (feof(fp))
+ return EOF;
+
+ strbuf_reset(sb);
while ((ch = fgetc(fp)) != EOF) {
if (ch == term)
break;
- strbuf_add(sb, ch);
+ strbuf_grow(sb, 1);
+ sb->buf[sb->len++] = ch;
}
if (ch == EOF && sb->len == 0)
- sb->eof = 1;
- strbuf_end(sb);
+ return EOF;
+
+ sb->buf[sb->len] = '\0';
+ return 0;
}
diff --git a/strbuf.h b/strbuf.h
index 74cc012c2..b2cbd976f 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -1,13 +1,105 @@
#ifndef 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 legal to copy the ->buf pointer away. Though if you want to reuse
+ * the strbuf after that, setting ->buf to NULL isn't legal.
+ * `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>
+
struct strbuf {
- int alloc;
- int len;
- int eof;
+ size_t alloc;
+ size_t len;
char *buf;
};
-extern void strbuf_init(struct strbuf *);
-extern void read_line(struct strbuf *, FILE *, int);
+#define STRBUF_INIT { 0, 0, NULL }
+
+/*----- strbuf life cycle -----*/
+extern void strbuf_init(struct strbuf *, size_t);
+extern void strbuf_release(struct strbuf *);
+extern void strbuf_reset(struct strbuf *);
+extern char *strbuf_detach(struct strbuf *);
+extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
+
+/*----- strbuf size related -----*/
+static inline size_t strbuf_avail(struct strbuf *sb) {
+ return sb->alloc ? sb->alloc - sb->len - 1 : 0;
+}
+static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
+ assert (len < sb->alloc);
+ sb->len = len;
+ sb->buf[len] = '\0';
+}
+
+extern void strbuf_grow(struct strbuf *, size_t);
+
+/*----- content related -----*/
+extern void strbuf_rtrim(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';
+}
+
+/* inserts after pos, or appends if pos >= sb->len */
+extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
+
+/* 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_getline(struct strbuf *, FILE *, int);
#endif /* STRBUF_H */
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 42e28ab75..dca2067b2 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -36,7 +36,8 @@ test_expect_success \
echo simple textfile >a/a &&
mkdir 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 &&
(p=long_path_to_a_file && cd a &&
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'
test_expect_success \
- 'create an archive with a substfile' \
- 'echo substfile export-subst >a/.gitattributes &&
+ 'create an archive with a substfiles' \
+ 'echo "substfile?" export-subst >a/.gitattributes &&
git archive HEAD >f.tar &&
rm a/.gitattributes'
test_expect_success \
- 'extract substfile' \
+ 'extract substfiles' \
'(mkdir f && cd f && $TAR xf -) <f.tar'
test_expect_success \
'validate substfile contents' \
'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
- >f/a/substfile.expected &&
- diff f/a/substfile.expected f/a/substfile'
+ >f/a/substfile1.expected &&
+ diff f/a/substfile1.expected f/a/substfile1 &&
+ diff a/substfile2 f/a/substfile2
+'
test_expect_success \
'git archive --format=zip' \