From af6eb82262e35687aa8f00d688e327cb845973fa Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 6 Sep 2007 13:20:09 +0200 Subject: Use strbuf API in apply, blame, commit-tree and diff Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-apply.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 976ec7704..90e328ef9 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -12,6 +12,7 @@ #include "blob.h" #include "delta.h" #include "builtin.h" +#include "strbuf.h" /* * --check turns on checking that the working tree matches the @@ -181,34 +182,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); + if (strbuf_read(&buf, fd) < 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) -- cgit v1.2.1 From f1696ee398e92bcea3cdc7b3da85d8e0f77f6c50 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 10 Sep 2007 12:35:04 +0200 Subject: Strbuf API extensions and fixes. * Add strbuf_rtrim to remove trailing spaces. * Add strbuf_insert to insert data at a given position. * Off-by one fix in strbuf_addf: strbuf_avail() does not counts the final \0 so the overflow test for snprintf is the strict comparison. This is not critical as the growth mechanism chosen will always allocate _more_ memory than asked, so the second test will not fail. It's some kind of miracle though. * Add size extension hints for strbuf_init and strbuf_read. If 0, default applies, else: + initial buffer has the given size for strbuf_init. + first growth checks it has at least this size rather than the default 8192. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-apply.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 90e328ef9..988e85f1e 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -184,8 +184,8 @@ static void *read_patch_file(int fd, unsigned long *sizep) { struct strbuf buf; - strbuf_init(&buf); - if (strbuf_read(&buf, fd) < 0) + strbuf_init(&buf, 0); + if (strbuf_read(&buf, fd, 0) < 0) die("git-apply: read returned %s", strerror(errno)); *sizep = buf.len; -- cgit v1.2.1 From 5ecd293d1420bf641a927a015877950f4d79c067 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 16 Sep 2007 15:51:04 +0200 Subject: Rewrite convert_to_{git,working_tree} to use strbuf's. * Now, those functions take an "out" strbuf argument, where they store their result if any. In that case, it also returns 1, else it returns 0. * those functions support "in place" editing, in the sense that it's OK to call them this way: convert_to_git(path, sb->buf, sb->len, sb); When doable, conversions are done in place for real, else the strbuf content is just replaced with the new one, transparentely for the caller. If you want to create a new filter working this way, being the accumulation of filter1, filter2, ... filtern, then your meta_filter would be: int meta_filter(..., const char *src, size_t len, struct strbuf *sb) { int ret = 0; ret |= filter1(...., src, len, sb); if (ret) { src = sb->buf; len = sb->len; } ret |= filter2(...., src, len, sb); if (ret) { src = sb->buf; len = sb->len; } .... return ret | filtern(..., src, len, sb); } That's why subfilters the convert_to_* functions called were also rewritten to work this way. Signed-off-by: Pierre Habouzit Acked-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-apply.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 988e85f1e..e5c29ebf3 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1446,8 +1446,7 @@ static int read_old_data(struct stat *st, const char *path, char **buf_p, unsign { int fd; unsigned long got; - unsigned long nsize; - char *nbuf; + struct strbuf nbuf; unsigned long size = *size_p; char *buf = *buf_p; @@ -1466,13 +1465,12 @@ static int read_old_data(struct stat *st, const char *path, char **buf_p, unsign got += ret; } close(fd); - nsize = got; - nbuf = convert_to_git(path, buf, &nsize); - if (nbuf) { + strbuf_init(&nbuf, 0); + if (convert_to_git(path, buf, size, &nbuf)) { free(buf); - *buf_p = nbuf; - *alloc_p = nsize; - *size_p = nsize; + *buf_p = nbuf.buf; + *alloc_p = nbuf.alloc; + *size_p = nbuf.len; } return got != size; default: @@ -2439,7 +2437,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; @@ -2458,9 +2456,11 @@ 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; + strbuf_init(&nbuf, 0); + if (convert_to_working_tree(path, buf, size, &nbuf)) { + size = nbuf.len; + buf = nbuf.buf; + } while (size) { int written = xwrite(fd, buf, size); @@ -2473,8 +2473,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf, } if (close(fd) < 0) die("closing file %s: %s", path, strerror(errno)); - if (nbuf) - free(nbuf); + strbuf_release(&nbuf); return 0; } -- cgit v1.2.1 From ba3ed09728cb25e004d3b732de14fca8aeb602f6 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sat, 15 Sep 2007 15:56:50 +0200 Subject: Now that cache.h needs strbuf.h, remove useless includes. Signed-off-by: Pierre Habouzit Acked-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-apply.c | 1 - 1 file changed, 1 deletion(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index e5c29ebf3..1256716ae 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -12,7 +12,6 @@ #include "blob.h" #include "delta.h" #include "builtin.h" -#include "strbuf.h" /* * --check turns on checking that the working tree matches the -- cgit v1.2.1 From c7f9cb14286fff23bfe65033d4ec63f84c77f554 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 16 Sep 2007 18:54:42 +0200 Subject: builtin-apply: use strbuf's instead of buffer_desc's. Signed-off-by: Pierre Habouzit Acked-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-apply.c | 212 +++++++++++++++++++------------------------------------- 1 file changed, 72 insertions(+), 140 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 1256716ae..61b51315e 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1441,37 +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; - struct strbuf 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); - strbuf_init(&nbuf, 0); - if (convert_to_git(path, buf, size, &nbuf)) { - free(buf); - *buf_p = nbuf.buf; - *alloc_p = nbuf.alloc; - *size_p = nbuf.len; - } - return got != size; + convert_to_git(path, buf->buf, buf->len, buf); + return 0; default: return -1; } @@ -1576,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, @@ -1651,10 +1636,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); @@ -1765,24 +1749,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. */ @@ -1792,19 +1769,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; } @@ -1840,12 +1806,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) { @@ -1856,29 +1821,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]; @@ -1897,7 +1857,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 " @@ -1906,16 +1866,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 */ } @@ -1923,43 +1881,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; @@ -1970,76 +1929,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"); @@ -2460,19 +2400,11 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf, size = nbuf.len; buf = nbuf.buf; } + write_or_die(fd, buf, size); + strbuf_release(&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; - } if (close(fd) < 0) die("closing file %s: %s", path, strerror(errno)); - strbuf_release(&nbuf); return 0; } -- cgit v1.2.1 From 182af8343c307436bb5364309aa6d4d46fa5911d Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 16 Sep 2007 00:32:36 +0200 Subject: Use xmemdupz() in many places. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-apply.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index f953c5b76..512c9b614 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -293,11 +293,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) return def; } - name = xmalloc(len + 1); - memcpy(name, start, len); - name[len] = 0; - free(def); - return name; + return xmemdupz(start, len); } static int count_slashes(const char *cp) @@ -687,10 +683,7 @@ static char *git_header_name(char *line, int llen) break; } if (second[len] == '\n' && !memcmp(name, second, len)) { - char *ret = xmalloc(len + 1); - memcpy(ret, name, len); - ret[len] = 0; - return ret; + return xmemdupz(name, len); } } } -- cgit v1.2.1 From ca0328354afbf4ec6941cb4312bfc6908ab06d73 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 19 Sep 2007 01:37:50 -0700 Subject: builtin-apply.c: fix a tiny leak introduced during xmemdupz() conversion. Signed-off-by: Junio C Hamano --- builtin-apply.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 512c9b614..db337f1ac 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -291,6 +291,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) int deflen = strlen(def); if (deflen < len && !strncmp(start, def, deflen)) return def; + free(def); } return xmemdupz(start, len); -- cgit v1.2.1 From 7fb1011e610a28518959b1d2d48cea17ecc32048 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 20 Sep 2007 00:42:14 +0200 Subject: Rework unquote_c_style to work on a strbuf. If the gain is not obvious in the diffstat, the resulting code is more readable, _and_ in checkout-index/update-index we now reuse the same buffer to unquote strings instead of always freeing/mallocing. This also is more coherent with the next patch that reworks quoting functions. The quoting function is also made more efficient scanning for backslashes and treating portions of strings without a backslash at once. Signed-off-by: Pierre Habouzit --- builtin-apply.c | 123 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 62 insertions(+), 61 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index db337f1ac..1cf68ede1 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -231,35 +231,33 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) { int len; const char *start = line; - char *name; if (*line == '"') { + struct strbuf name; + /* Proposed "new-style" GNU patch/diff format; see * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 */ - name = unquote_c_style(line, NULL); - if (name) { - char *cp = name; - while (p_value) { + strbuf_init(&name, 0); + if (!unquote_c_style(&name, line, NULL)) { + char *cp; + + for (cp = name.buf; p_value; p_value--) { cp = strchr(cp, '/'); if (!cp) break; cp++; - p_value--; } if (cp) { /* name can later be freed, so we need * to memmove, not just return cp */ - memmove(name, cp, strlen(cp) + 1); + strbuf_remove(&name, 0, cp - name.buf); free(def); - return name; - } - else { - free(name); - name = NULL; + return name.buf; } } + strbuf_release(&name); } for (;;) { @@ -567,29 +565,30 @@ static const char *stop_at_slash(const char *line, int llen) */ static char *git_header_name(char *line, int llen) { - int len; const char *name; const char *second = NULL; + size_t len; line += strlen("diff --git "); llen -= strlen("diff --git "); if (*line == '"') { const char *cp; - char *first = unquote_c_style(line, &second); - if (!first) - return NULL; + struct strbuf first; + struct strbuf sp; + + strbuf_init(&first, 0); + strbuf_init(&sp, 0); + + if (unquote_c_style(&first, line, &second)) + goto free_and_fail1; /* advance to the first slash */ - cp = stop_at_slash(first, strlen(first)); - if (!cp || cp == first) { - /* we do not accept absolute paths */ - free_first_and_fail: - free(first); - return NULL; - } - len = strlen(cp+1); - memmove(first, cp+1, len+1); /* including NUL */ + cp = stop_at_slash(first.buf, first.len); + /* we do not accept absolute paths */ + if (!cp || cp == first.buf) + goto free_and_fail1; + strbuf_remove(&first, 0, cp + 1 - first.buf); /* second points at one past closing dq of name. * find the second name. @@ -598,40 +597,40 @@ static char *git_header_name(char *line, int llen) second++; if (line + llen <= second) - goto free_first_and_fail; + goto free_and_fail1; if (*second == '"') { - char *sp = unquote_c_style(second, NULL); - if (!sp) - goto free_first_and_fail; - cp = stop_at_slash(sp, strlen(sp)); - if (!cp || cp == sp) { - free_both_and_fail: - free(sp); - goto free_first_and_fail; - } + if (unquote_c_style(&sp, second, NULL)) + goto free_and_fail1; + cp = stop_at_slash(sp.buf, sp.len); + if (!cp || cp == sp.buf) + goto free_and_fail1; /* They must match, otherwise ignore */ - if (strcmp(cp+1, first)) - goto free_both_and_fail; - free(sp); - return first; + if (strcmp(cp + 1, first.buf)) + goto free_and_fail1; + strbuf_release(&sp); + return first.buf; } /* unquoted second */ cp = stop_at_slash(second, line + llen - second); if (!cp || cp == second) - goto free_first_and_fail; + goto free_and_fail1; cp++; - if (line + llen - cp != len + 1 || - memcmp(first, cp, len)) - goto free_first_and_fail; - return first; + if (line + llen - cp != first.len + 1 || + memcmp(first.buf, cp, first.len)) + goto free_and_fail1; + return first.buf; + + free_and_fail1: + strbuf_release(&first); + strbuf_release(&sp); + return NULL; } /* unquoted first name */ name = stop_at_slash(line, llen); if (!name || name == line) return NULL; - name++; /* since the first name is unquoted, a dq if exists must be @@ -639,28 +638,30 @@ static char *git_header_name(char *line, int llen) */ for (second = name; second < line + llen; second++) { if (*second == '"') { - const char *cp = second; + struct strbuf sp; const char *np; - char *sp = unquote_c_style(second, NULL); - - if (!sp) - return NULL; - np = stop_at_slash(sp, strlen(sp)); - if (!np || np == sp) { - free_second_and_fail: - free(sp); - return NULL; - } + + strbuf_init(&sp, 0); + if (unquote_c_style(&sp, second, NULL)) + goto free_and_fail2; + + np = stop_at_slash(sp.buf, sp.len); + if (!np || np == sp.buf) + goto free_and_fail2; np++; - len = strlen(np); - if (len < cp - name && + + len = sp.buf + sp.len - np; + if (len < second - name && !strncmp(np, name, len) && isspace(name[len])) { /* Good */ - memmove(sp, np, len + 1); - return sp; + strbuf_remove(&sp, 0, np - sp.buf); + return sp.buf; } - goto free_second_and_fail; + + free_and_fail2: + strbuf_release(&sp); + return NULL; } } -- cgit v1.2.1 From 663af3422a648e87945e4d8c0cc3e13671f2bbde Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 20 Sep 2007 00:42:15 +0200 Subject: Full rework of quote_c_style and write_name_quoted. * quote_c_style works on a strbuf instead of a wild buffer. * quote_c_style is now clever enough to not add double quotes if not needed. * write_name_quoted inherits those advantages, but also take a different set of arguments. Now instead of asking for quotes or not, you pass a "terminator". If it's \0 then we assume you don't want to escape, else C escaping is performed. In any case, the terminator is also appended to the stream. It also no longer takes the prefix/prefix_len arguments, as it's seldomly used, and makes some optimizations harder. * write_name_quotedpfx is created to work like write_name_quoted and take the prefix/prefix_len arguments. Thanks to those API changes, diff.c has somehow lost weight, thanks to the removal of functions that were wrappers around the old write_name_quoted trying to give it a semantics like the new one, but performing a lot of allocations for this goal. Now we always write directly to the stream, no intermediate allocation is performed. As a side effect of the refactor in builtin-apply.c, the length of the bar graphs in diffstats are not affected anymore by the fact that the path was clipped. Signed-off-by: Pierre Habouzit --- builtin-apply.c | 77 ++++++++++++++++++++++----------------------------------- 1 file changed, 30 insertions(+), 47 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 1cf68ede1..01c9d6064 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -163,15 +163,14 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c fputs(pre, output); if (patch->old_name && patch->new_name && strcmp(patch->old_name, patch->new_name)) { - write_name_quoted(NULL, 0, patch->old_name, 1, output); + quote_c_style(patch->old_name, NULL, output, 0); fputs(" => ", output); - write_name_quoted(NULL, 0, patch->new_name, 1, output); - } - else { + quote_c_style(patch->new_name, NULL, output, 0); + } else { const char *n = patch->new_name; if (!n) n = patch->old_name; - write_name_quoted(NULL, 0, n, 1, output); + quote_c_style(n, NULL, output, 0); } fputs(post, output); } @@ -1379,61 +1378,50 @@ static const char minuses[]= "-------------------------------------------------- static void show_stats(struct patch *patch) { - const char *prefix = ""; - char *name = patch->new_name; - char *qname = NULL; - int len, max, add, del, total; - - if (!name) - name = patch->old_name; + struct strbuf qname; + char *cp = patch->new_name ? patch->new_name : patch->old_name; + int max, add, del; - if (0 < (len = quote_c_style(name, NULL, NULL, 0))) { - qname = xmalloc(len + 1); - quote_c_style(name, qname, NULL, 0); - name = qname; - } + strbuf_init(&qname, 0); + quote_c_style(cp, &qname, NULL, 0); /* * "scale" the filename */ - len = strlen(name); max = max_len; if (max > 50) max = 50; - if (len > max) { - char *slash; - prefix = "..."; - max -= 3; - name += len - max; - slash = strchr(name, '/'); - if (slash) - name = slash; + + if (qname.len > max) { + cp = strchr(qname.buf + qname.len + 3 - max, '/'); + if (!cp) + cp = qname.buf + qname.len + 3 - max; + strbuf_splice(&qname, 0, cp - qname.buf, "...", 3); + } + + if (patch->is_binary) { + printf(" %-*s | Bin\n", max, qname.buf); + strbuf_release(&qname); + return; } - len = max; + + printf(" %-*s |", max, qname.buf); + strbuf_release(&qname); /* * scale the add/delete */ - max = max_change; - if (max + len > 70) - max = 70 - len; - + max = max + max_change > 70 ? 70 - max : max_change; add = patch->lines_added; del = patch->lines_deleted; - total = add + del; if (max_change > 0) { - total = (total * max + max_change / 2) / max_change; + int total = ((add + del) * max + max_change / 2) / max_change; add = (add * max + max_change / 2) / max_change; del = total - add; } - if (patch->is_binary) - printf(" %s%-*s | Bin\n", prefix, len, name); - else - printf(" %s%-*s |%5d %.*s%.*s\n", prefix, - len, name, patch->lines_added + patch->lines_deleted, - add, pluses, del, minuses); - free(qname); + printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted, + add, pluses, del, minuses); } static int read_old_data(struct stat *st, const char *path, struct strbuf *buf) @@ -2228,13 +2216,8 @@ static void numstat_patch_list(struct patch *patch) if (patch->is_binary) printf("-\t-\t"); else - printf("%d\t%d\t", - patch->lines_added, patch->lines_deleted); - if (line_termination && quote_c_style(name, NULL, NULL, 0)) - quote_c_style(name, NULL, stdout, 0); - else - fputs(name, stdout); - putchar(line_termination); + printf("%d\t%d\t", patch->lines_added, patch->lines_deleted); + write_name_quoted(name, stdout, line_termination); } } -- cgit v1.2.1 From b315c5c08139c0d3c1e4867a305334e29da01d07 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 27 Sep 2007 12:58:23 +0200 Subject: strbuf change: be sure ->buf is never ever NULL. For that purpose, the ->buf is always initialized with a char * buf living in the strbuf module. It is made a char * so that we can sloppily accept things that perform: sb->buf[0] = '\0', and because you can't pass "" as an initializer for ->buf without making gcc unhappy for very good reasons. strbuf_init/_detach/_grow have been fixed to trust ->alloc and not ->buf anymore. as a consequence strbuf_detach is _mandatory_ to detach a buffer, copying ->buf isn't an option anymore, if ->buf is going to escape from the scope, and eventually be free'd. API changes: * strbuf_setlen now always works, so just make strbuf_reset a convenience macro. * strbuf_detatch takes a size_t* optional argument (meaning it can be NULL) to copy the buffer's len, as it was needed for this refactor to make the code more readable, and working like the callers. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-apply.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 01c9d6064..740623e6c 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -178,14 +178,13 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c #define CHUNKSIZE (8192) #define SLOP (16) -static void *read_patch_file(int fd, unsigned long *sizep) +static void *read_patch_file(int fd, size_t *sizep) { struct strbuf buf; 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 @@ -194,7 +193,7 @@ static void *read_patch_file(int fd, unsigned long *sizep) */ strbuf_grow(&buf, SLOP); memset(buf.buf + buf.len, 0, SLOP); - return strbuf_detach(&buf); + return strbuf_detach(&buf, sizep); } static unsigned long linelen(const char *buffer, unsigned long size) @@ -253,7 +252,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) */ strbuf_remove(&name, 0, cp - name.buf); free(def); - return name.buf; + return strbuf_detach(&name, NULL); } } strbuf_release(&name); @@ -607,7 +606,7 @@ static char *git_header_name(char *line, int llen) if (strcmp(cp + 1, first.buf)) goto free_and_fail1; strbuf_release(&sp); - return first.buf; + return strbuf_detach(&first, NULL); } /* unquoted second */ @@ -618,7 +617,7 @@ static char *git_header_name(char *line, int llen) if (line + llen - cp != first.len + 1 || memcmp(first.buf, cp, first.len)) goto free_and_fail1; - return first.buf; + return strbuf_detach(&first, NULL); free_and_fail1: strbuf_release(&first); @@ -655,7 +654,7 @@ static char *git_header_name(char *line, int llen) isspace(name[len])) { /* Good */ strbuf_remove(&sp, 0, np - sp.buf); - return sp.buf; + return strbuf_detach(&sp, NULL); } free_and_fail2: @@ -1968,8 +1967,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * if (apply_fragments(&buf, patch) < 0) return -1; /* note with --reject this succeeds. */ - patch->result = buf.buf; - patch->resultsize = buf.len; + patch->result = strbuf_detach(&buf, &patch->resultsize); if (0 < patch->is_delete && patch->resultsize) return error("removal patch leaves file contents"); -- cgit v1.2.1 From 387e7e19d7eb5444be8da8e99ed7491989dc1cbb Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 27 Sep 2007 15:25:55 +0200 Subject: strbuf_read_file enhancement, and use it. * make strbuf_read_file take a size hint (works like strbuf_read) * use it in a couple of places. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-apply.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index 740623e6c..fec96a8d9 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1425,8 +1425,6 @@ static void show_stats(struct patch *patch) static int read_old_data(struct stat *st, const char *path, struct strbuf *buf) { - int fd; - switch (st->st_mode & S_IFMT) { case S_IFLNK: strbuf_grow(buf, st->st_size); @@ -1435,14 +1433,8 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf) 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); - if (strbuf_read(buf, fd, st->st_size) < 0) { - close(fd); - return -1; - } - close(fd); + if (strbuf_read_file(buf, path, st->st_size) != st->st_size) + return error("unable to open or read %s", path); convert_to_git(path, buf->buf, buf->len, buf); return 0; default: -- cgit v1.2.1 From 9a76adebd6dfe144c3643e7e877fff2b41be5c8e Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 27 Sep 2007 13:33:19 +0200 Subject: Make read_patch_file work on a strbuf. So that we don't need to use strbuf_detach. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-apply.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'builtin-apply.c') diff --git a/builtin-apply.c b/builtin-apply.c index fec96a8d9..4113d66b5 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -178,12 +178,9 @@ static void say_patch_name(FILE *output, const char *pre, struct patch *patch, c #define CHUNKSIZE (8192) #define SLOP (16) -static void *read_patch_file(int fd, size_t *sizep) +static void read_patch_file(struct strbuf *sb, int fd) { - struct strbuf buf; - - strbuf_init(&buf, 0); - if (strbuf_read(&buf, fd, 0) < 0) + if (strbuf_read(sb, fd, 0) < 0) die("git-apply: read returned %s", strerror(errno)); /* @@ -191,9 +188,8 @@ static void *read_patch_file(int fd, size_t *sizep) * so that we can do speculative "memcmp" etc, and * see to it that it is NUL-filled. */ - strbuf_grow(&buf, SLOP); - memset(buf.buf + buf.len, 0, SLOP); - return strbuf_detach(&buf, sizep); + strbuf_grow(sb, SLOP); + memset(sb->buf + sb->len, 0, SLOP); } static unsigned long linelen(const char *buffer, unsigned long size) @@ -2633,22 +2629,22 @@ static void prefix_patches(struct patch *p) static int apply_patch(int fd, const char *filename, int inaccurate_eof) { - unsigned long offset, size; - char *buffer = read_patch_file(fd, &size); + size_t offset; + struct strbuf buf; struct patch *list = NULL, **listp = &list; int skipped_patch = 0; + strbuf_init(&buf, 0); patch_input_file = filename; - if (!buffer) - return -1; + read_patch_file(&buf, fd); offset = 0; - while (size > 0) { + while (offset < buf.len) { struct patch *patch; int nr; patch = xcalloc(1, sizeof(*patch)); patch->inaccurate_eof = inaccurate_eof; - nr = parse_chunk(buffer + offset, size, patch); + nr = parse_chunk(buf.buf + offset, buf.len, patch); if (nr < 0) break; if (apply_in_reverse) @@ -2666,7 +2662,6 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) skipped_patch++; } offset += nr; - size -= nr; } if (whitespace_error && (new_whitespace == error_on_whitespace)) @@ -2701,7 +2696,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) if (summary) summary_patch_list(list); - free(buffer); + strbuf_release(&buf); return 0; } -- cgit v1.2.1