From b449f4cfc972929b638b90d375b8960c37790618 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 6 Sep 2007 13:20:05 +0200 Subject: Rework strbuf API and semantics. The gory details are explained in strbuf.h. The change of semantics this patch enforces is that the embeded buffer has always a '\0' character after its last byte, to always make it a C-string. The offs-by-one changes are all related to that very change. A strbuf can be used to store byte arrays, or as an extended string library. The `buf' member can be passed to any C legacy string function, because strbuf operations always ensure there is a terminating \0 at the end of the buffer, not accounted in the `len' field of the structure. A strbuf can be used to generate a string/buffer whose final size is not really known, and then "strbuf_detach" can be used to get the built buffer, and keep the wrapping "strbuf" structure usable for further work again. Other interesting feature: strbuf_grow(sb, size) ensure that there is enough allocated space in `sb' to put `size' new octets of data in the buffer. It helps avoiding reallocating data for nothing when the problem the strbuf helps to solve has a known typical size. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- mktree.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'mktree.c') diff --git a/mktree.c b/mktree.c index d86dde89d6..86de5eb5f6 100644 --- a/mktree.c +++ b/mktree.c @@ -92,7 +92,6 @@ int main(int ac, char **av) strbuf_init(&sb); while (1) { - int len; char *ptr, *ntr; unsigned mode; enum object_type type; @@ -101,7 +100,6 @@ int main(int ac, char **av) read_line(&sb, stdin, line_termination); if (sb.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 +109,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); -- cgit v1.3 From d52bc66152834dff3fb5f32a54f6ed57730f58c6 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 6 Sep 2007 13:20:08 +0200 Subject: mktree: Simplify write_tree() using strbuf API Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- mktree.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'mktree.c') diff --git a/mktree.c b/mktree.c index 86de5eb5f6..2e84889c02 100644 --- a/mktree.c +++ b/mktree.c @@ -44,30 +44,23 @@ 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); + strbuf_grow(&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]"; -- cgit v1.3 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 --- archive-tar.c | 4 ++-- builtin-apply.c | 4 ++-- builtin-blame.c | 6 +++--- builtin-checkout-index.c | 2 +- builtin-commit-tree.c | 5 ++--- builtin-rerere.c | 4 ++-- builtin-update-index.c | 4 ++-- cache-tree.c | 5 ++--- diff.c | 4 ++-- fast-import.c | 4 ++-- fetch.c | 2 +- mktree.c | 5 ++--- strbuf.c | 33 +++++++++++++++++++++++++++------ strbuf.h | 10 ++++++++-- 14 files changed, 58 insertions(+), 34 deletions(-) (limited to 'mktree.c') diff --git a/archive-tar.c b/archive-tar.c index 0612bb6051..cc94cf3672 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -132,7 +132,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path, struct strbuf ext_header; memset(&header, 0, sizeof(header)); - strbuf_init(&ext_header); + strbuf_init(&ext_header, 0); if (!sha1) { *header.typeflag = TYPEFLAG_GLOBAL_HEADER; @@ -214,7 +214,7 @@ static void write_global_extended_header(const unsigned char *sha1) { struct strbuf ext_header; - strbuf_init(&ext_header); + 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); strbuf_release(&ext_header); diff --git a/builtin-apply.c b/builtin-apply.c index 90e328ef91..988e85f1e5 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; diff --git a/builtin-blame.c b/builtin-blame.c index 1b1e6da853..b004f06cd8 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -2023,7 +2023,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con origin = make_origin(commit, path); - strbuf_init(&buf); + strbuf_init(&buf, 0); if (!contents_from || strcmp("-", contents_from)) { struct stat st; const char *read_from; @@ -2046,7 +2046,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con fd = open(read_from, O_RDONLY); if (fd < 0) die("cannot open %s", read_from); - if (strbuf_read(&buf, fd) != xsize_t(st.st_size)) + if (strbuf_read(&buf, fd, 0) != xsize_t(st.st_size)) die("cannot read %s", read_from); break; case S_IFLNK: @@ -2062,7 +2062,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con /* Reading from stdin */ contents_from = "standard input"; mode = 0; - if (strbuf_read(&buf, 0) < 0) + if (strbuf_read(&buf, 0, 0) < 0) die("read error %s from stdin", strerror(errno)); } origin->file.ptr = buf.buf; diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 75377b9cab..153ba7dc12 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -274,7 +274,7 @@ 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; diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index bc9502c135..325334fd65 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -87,8 +87,7 @@ 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); - strbuf_init(&buffer); - strbuf_grow(&buffer, 8192); /* should avoid reallocs for the headers */ + strbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */ strbuf_addf(&buffer, "tree %s\n", sha1_to_hex(tree_sha1)); /* @@ -107,7 +106,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) strbuf_addch(&buffer, '\n'); /* And add the comment */ - if (strbuf_read(&buffer, 0) < 0) + if (strbuf_read(&buffer, 0, 0) < 0) die("git-commit-tree: read returned %s", strerror(errno)); /* And check the encoding */ diff --git a/builtin-rerere.c b/builtin-rerere.c index 98d7702168..826d346fbc 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -78,8 +78,8 @@ static int handle_file(const char *path, FILE *f = fopen(path, "r"); FILE *out; - strbuf_init(&minus); - strbuf_init(&plus); + strbuf_init(&minus, 0); + strbuf_init(&plus, 0); if (!f) return error("Could not open %s", path); diff --git a/builtin-update-index.c b/builtin-update-index.c index a7a4574f2b..9240a288a7 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -303,7 +303,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; @@ -716,7 +716,7 @@ 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; diff --git a/cache-tree.c b/cache-tree.c index 76af6f5d99..8f53c99f15 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -293,8 +293,7 @@ static int update_one(struct cache_tree *it, /* * Then write out the tree object for this level. */ - strbuf_init(&buffer); - strbuf_grow(&buffer, 8192); + strbuf_init(&buffer, 8192); for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; @@ -419,7 +418,7 @@ void *cache_tree_write(struct cache_tree *root, unsigned long *size_p) struct strbuf buffer; path[0] = 0; - strbuf_init(&buffer); + strbuf_init(&buffer, 0); write_one(root, path, 0, &buffer); *size_p = buffer.len; return strbuf_detach(&buffer); diff --git a/diff.c b/diff.c index 26d7bb96bc..7290309ea9 100644 --- a/diff.c +++ b/diff.c @@ -1548,8 +1548,8 @@ static int populate_from_stdin(struct diff_filespec *s) { struct strbuf buf; - strbuf_init(&buf); - if (strbuf_read(&buf, 0) < 0) + strbuf_init(&buf, 0); + if (strbuf_read(&buf, 0, 0) < 0) return error("error while reading from stdin %s", strerror(errno)); diff --git a/fast-import.c b/fast-import.c index 74ff0fdadd..2c0bfb9fab 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1640,7 +1640,7 @@ static void *cmd_data (size_t *size) { struct strbuf buffer; - strbuf_init(&buffer); + strbuf_init(&buffer, 0); if (prefixcmp(command_buf.buf, "data ")) die("Expected 'data n' command, found: %s", command_buf.buf); @@ -2318,7 +2318,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*)); diff --git a/fetch.c b/fetch.c index 811be87a3c..dd6ed9e41c 100644 --- a/fetch.c +++ b/fetch.c @@ -218,7 +218,7 @@ 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; diff --git a/mktree.c b/mktree.c index 2e84889c02..3891cd9fb3 100644 --- a/mktree.c +++ b/mktree.c @@ -51,9 +51,8 @@ static void write_tree(unsigned char *sha1) qsort(entries, used, sizeof(*entries), ent_compare); for (size = i = 0; i < used; i++) size += 32 + entries[i]->len; - strbuf_init(&buf); - strbuf_grow(&buf, size); + strbuf_init(&buf, size); for (i = 0; i < used; i++) { struct treeent *ent = entries[i]; strbuf_addf(&buf, "%o %s%c", ent->mode, ent->name, '\0'); @@ -83,7 +82,7 @@ int main(int ac, char **av) av++; } - strbuf_init(&sb); + strbuf_init(&sb, 0); while (1) { char *ptr, *ntr; unsigned mode; diff --git a/strbuf.c b/strbuf.c index 7136de14c6..d9190477e6 100644 --- a/strbuf.c +++ b/strbuf.c @@ -1,8 +1,10 @@ #include "cache.h" #include "strbuf.h" -void strbuf_init(struct strbuf *sb) { +void strbuf_init(struct strbuf *sb, size_t hint) { memset(sb, 0, sizeof(*sb)); + if (hint) + strbuf_grow(sb, hint); } void strbuf_release(struct strbuf *sb) { @@ -18,7 +20,7 @@ void strbuf_reset(struct strbuf *sb) { char *strbuf_detach(struct strbuf *sb) { char *res = sb->buf; - strbuf_init(sb); + strbuf_init(sb, 0); return res; } @@ -28,6 +30,24 @@ void strbuf_grow(struct strbuf *sb, size_t extra) { 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) { + pos = sb->len; + } else { + 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_add(struct strbuf *sb, const void *data, size_t len) { strbuf_grow(sb, len); memcpy(sb->buf + sb->len, data, len); @@ -44,12 +64,12 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) { if (len < 0) { len = 0; } - if (len >= strbuf_avail(sb)) { + 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)) { + if (len > strbuf_avail(sb)) { die("this should not happen, your snprintf is broken"); } } @@ -67,14 +87,14 @@ size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) { return res; } -ssize_t strbuf_read(struct strbuf *sb, int fd) +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; - strbuf_grow(sb, 8192); cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); if (cnt < 0) { strbuf_setlen(sb, oldlen); @@ -83,6 +103,7 @@ ssize_t strbuf_read(struct strbuf *sb, int fd) if (!cnt) break; sb->len += cnt; + strbuf_grow(sb, 8192); } sb->buf[sb->len] = '\0'; diff --git a/strbuf.h b/strbuf.h index b40dc99fd0..21fc111f9d 100644 --- a/strbuf.h +++ b/strbuf.h @@ -51,7 +51,7 @@ struct strbuf { #define STRBUF_INIT { 0, 0, 0, NULL } /*----- strbuf life cycle -----*/ -extern void strbuf_init(struct strbuf *); +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 *); @@ -68,6 +68,9 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) { 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); @@ -75,6 +78,9 @@ static inline void strbuf_addch(struct strbuf *sb, int 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); + 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)); @@ -88,7 +94,7 @@ 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); +extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); extern void read_line(struct strbuf *, FILE *, int); -- cgit v1.3 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 --- archive-tar.c | 1 - builtin-apply.c | 1 - builtin-blame.c | 1 - builtin-checkout-index.c | 1 - builtin-commit-tree.c | 1 - builtin-fetch--tool.c | 1 - builtin-rerere.c | 1 - builtin-stripspace.c | 1 - builtin-tag.c | 1 - builtin-update-index.c | 1 - cache-tree.c | 1 - convert.c | 1 - diff.c | 1 - fast-import.c | 1 - fetch.c | 1 - imap-send.c | 1 - mktag.c | 1 - mktree.c | 1 - sha1_file.c | 1 - strbuf.c | 1 - 20 files changed, 20 deletions(-) (limited to 'mktree.c') diff --git a/archive-tar.c b/archive-tar.c index cc94cf3672..a87bc4b83e 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" diff --git a/builtin-apply.c b/builtin-apply.c index e5c29ebf35..1256716aec 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 diff --git a/builtin-blame.c b/builtin-blame.c index b004f06cd8..e364b6c6c0 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -18,7 +18,6 @@ #include "cache-tree.h" #include "path-list.h" #include "mailmap.h" -#include "strbuf.h" static char blame_usage[] = "git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 153ba7dc12..85e8efe22f 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" diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 325334fd65..88b0ab36eb 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -8,7 +8,6 @@ #include "tree.h" #include "builtin.h" #include "utf8.h" -#include "strbuf.h" #define BLOCKING (1ul << 14) diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c index 90bdc32d13..514a3cc018 100644 --- a/builtin-fetch--tool.c +++ b/builtin-fetch--tool.c @@ -2,7 +2,6 @@ #include "cache.h" #include "refs.h" #include "commit.h" -#include "strbuf.h" static char *get_stdin(void) { diff --git a/builtin-rerere.c b/builtin-rerere.c index 826d346fbc..58288f61a3 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -1,7 +1,6 @@ #include "builtin.h" #include "cache.h" #include "path-list.h" -#include "strbuf.h" #include "xdiff/xdiff.h" #include "xdiff-interface.h" diff --git a/builtin-stripspace.c b/builtin-stripspace.c index c4cf2f05ca..1ce284710c 100644 --- a/builtin-stripspace.c +++ b/builtin-stripspace.c @@ -1,6 +1,5 @@ #include "builtin.h" #include "cache.h" -#include "strbuf.h" /* * Returns the length of a line, without trailing spaces. diff --git a/builtin-tag.c b/builtin-tag.c index 9f293421da..82ebda11b0 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -8,7 +8,6 @@ #include "cache.h" #include "builtin.h" -#include "strbuf.h" #include "refs.h" #include "tag.h" #include "run-command.h" diff --git a/builtin-update-index.c b/builtin-update-index.c index 9240a288a7..1091f1b26f 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" diff --git a/cache-tree.c b/cache-tree.c index 8f53c99f15..5471844af6 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,5 +1,4 @@ #include "cache.h" -#include "strbuf.h" #include "tree.h" #include "cache-tree.h" diff --git a/convert.c b/convert.c index 00a341c595..508d30b2f1 100644 --- a/convert.c +++ b/convert.c @@ -1,7 +1,6 @@ #include "cache.h" #include "attr.h" #include "run-command.h" -#include "strbuf.h" /* * convert.c - convert a file when checking it out and checking it in. diff --git a/diff.c b/diff.c index f41bcd94ab..56b672c4f0 100644 --- a/diff.c +++ b/diff.c @@ -9,7 +9,6 @@ #include "xdiff-interface.h" #include "color.h" #include "attr.h" -#include "strbuf.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 diff --git a/fast-import.c b/fast-import.c index 2c0bfb9fab..1866d346bf 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 diff --git a/fetch.c b/fetch.c index dd6ed9e41c..c256e6f6b4 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; diff --git a/imap-send.c b/imap-send.c index ecd4216a56..86e4a0f6a0 100644 --- a/imap-send.c +++ b/imap-send.c @@ -23,7 +23,6 @@ */ #include "cache.h" -#include "strbuf.h" typedef struct store_conf { char *name; diff --git a/mktag.c b/mktag.c index 7567f9ec29..b05260c83f 100644 --- a/mktag.c +++ b/mktag.c @@ -1,5 +1,4 @@ #include "cache.h" -#include "strbuf.h" #include "tag.h" /* diff --git a/mktree.c b/mktree.c index 3891cd9fb3..5dab4bd367 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" diff --git a/sha1_file.c b/sha1_file.c index 64b5b46698..59325d46be 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -14,7 +14,6 @@ #include "tag.h" #include "tree.h" #include "refs.h" -#include "strbuf.h" #ifndef O_NOATIME #if defined(__linux__) && (defined(__i386__) || defined(__PPC__)) diff --git a/strbuf.c b/strbuf.c index ff551ac9ff..c5f9e2a28f 100644 --- a/strbuf.c +++ b/strbuf.c @@ -1,5 +1,4 @@ #include "cache.h" -#include "strbuf.h" void strbuf_init(struct strbuf *sb, size_t hint) { -- cgit v1.3 From e6c019d0b0140fae1cdfd661746cbe319b6c3670 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 17 Sep 2007 11:19:04 +0200 Subject: Drop strbuf's 'eof' marker, and make read_line a first class citizen. read_line is now strbuf_getline, and is a first class citizen, it returns 0 when reading a line worked, EOF else. The ->eof marker was used non-locally by fast-import.c, mimic the same behaviour using a static int in "read_next_command", that now returns -1 on EOF, and avoids to call strbuf_getline when it's in EOF state. Also no longer automagically strbuf_release the buffer, it's counter intuitive and breaks fast-import in a very subtle way. Note: being at EOF implies that command_buf.len == 0. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-checkout-index.c | 5 ++--- builtin-update-index.c | 8 ++++---- fast-import.c | 34 +++++++++++++++++++--------------- fetch.c | 4 ++-- mktree.c | 4 ++-- strbuf.c | 20 ++++++++------------ strbuf.h | 5 ++--- 7 files changed, 39 insertions(+), 41 deletions(-) (limited to 'mktree.c') diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 85e8efe22f..a18ecc4bab 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -277,9 +277,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) 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); @@ -292,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-update-index.c b/builtin-update-index.c index 1091f1b26f..45e33f5584 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -327,8 +327,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; @@ -391,6 +390,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[] = @@ -719,8 +719,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) 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); @@ -735,6 +734,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/fast-import.c b/fast-import.c index 1866d346bf..da045662ac 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1584,20 +1584,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; strbuf_detach(&command_buf); - read_line(&command_buf, stdin, '\n'); - if (command_buf.eof) - return; + stdin_eof = strbuf_getline(&command_buf, stdin, '\n'); + if (stdin_eof) + return EOF; rc = rc_free; if (rc) @@ -1616,6 +1621,8 @@ static void read_next_command(void) cmd_tail = rc; } } while (command_buf.buf[0] == '#'); + + return 0; } static void skip_optional_lf(void) @@ -1648,8 +1655,7 @@ static void *cmd_data (size_t *size) 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)) @@ -2095,7 +2101,7 @@ static void cmd_new_commit(void) } /* file_change* */ - while (!command_buf.eof && command_buf.len > 0) { + while (command_buf.len > 0) { if (!prefixcmp(command_buf.buf, "M ")) file_change_m(b); else if (!prefixcmp(command_buf.buf, "D ")) @@ -2110,7 +2116,8 @@ 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 */ @@ -2375,11 +2382,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 c256e6f6b4..b1c1f07b2a 100644 --- a/fetch.c +++ b/fetch.c @@ -222,8 +222,7 @@ int pull_targets_stdin(char ***target, const char ***write_ref) 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'); @@ -239,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/mktree.c b/mktree.c index 5dab4bd367..9c137dec45 100644 --- a/mktree.c +++ b/mktree.c @@ -88,8 +88,7 @@ int main(int ac, char **av) enum object_type type; char *path; - read_line(&sb, stdin, line_termination); - if (sb.eof) + if (strbuf_getline(&sb, stdin, line_termination) == EOF) break; ptr = sb.buf; /* Input is non-recursive ls-tree output format @@ -121,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/strbuf.c b/strbuf.c index c5f9e2a28f..59383ac776 100644 --- a/strbuf.c +++ b/strbuf.c @@ -17,7 +17,6 @@ void strbuf_reset(struct strbuf *sb) { if (sb->len) strbuf_setlen(sb, 0); - sb->eof = 0; } char *strbuf_detach(struct strbuf *sb) @@ -145,14 +144,13 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) return sb->len - oldlen; } -void read_line(struct strbuf *sb, FILE *fp, int term) +int strbuf_getline(struct strbuf *sb, FILE *fp, int term) { int ch; - if (feof(fp)) { - strbuf_release(sb); - sb->eof = 1; - return; - } + + strbuf_grow(sb, 0); + if (feof(fp)) + return EOF; strbuf_reset(sb); while ((ch = fgetc(fp)) != EOF) { @@ -161,11 +159,9 @@ void read_line(struct strbuf *sb, FILE *fp, int term) strbuf_grow(sb, 1); sb->buf[sb->len++] = ch; } - if (ch == EOF && sb->len == 0) { - strbuf_release(sb); - sb->eof = 1; - } + if (ch == EOF && sb->len == 0) + return EOF; - strbuf_grow(sb, 1); sb->buf[sb->len] = '\0'; + return 0; } diff --git a/strbuf.h b/strbuf.h index f163c63e6f..b2cbd976f4 100644 --- a/strbuf.h +++ b/strbuf.h @@ -44,11 +44,10 @@ struct strbuf { size_t alloc; size_t len; - int eof; char *buf; }; -#define STRBUF_INIT { 0, 0, 0, NULL } +#define STRBUF_INIT { 0, 0, NULL } /*----- strbuf life cycle -----*/ extern void strbuf_init(struct strbuf *, size_t); @@ -101,6 +100,6 @@ 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 void read_line(struct strbuf *, FILE *, int); +extern int strbuf_getline(struct strbuf *, FILE *, int); #endif /* STRBUF_H */ -- cgit v1.3 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 ++++++++++++++++++++++++----------------------- builtin-checkout-index.c | 27 ++++++----- builtin-update-index.c | 51 +++++++++++--------- fast-import.c | 47 +++++++++--------- mktree.c | 25 +++++----- quote.c | 104 ++++++++++++++++++++------------------- quote.h | 2 +- 7 files changed, 191 insertions(+), 188 deletions(-) (limited to 'mktree.c') diff --git a/builtin-apply.c b/builtin-apply.c index db337f1aca..1cf68ede12 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; } } diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index a18ecc4bab..e6264c4bf0 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -270,26 +270,27 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) } if (read_from_stdin) { - struct strbuf buf; + struct strbuf buf, nbuf; + if (all) die("git-checkout-index: don't mix '--all' and '--stdin'"); + strbuf_init(&buf, 0); - while (1) { - char *path_name; + strbuf_init(&nbuf, 0); + while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; - if (strbuf_getline(&buf, stdin, line_termination) == EOF) - break; - if (line_termination && buf.buf[0] == '"') - path_name = unquote_c_style(buf.buf, NULL); - else - path_name = buf.buf; - p = prefix_path(prefix, prefix_length, path_name); + if (line_termination && buf.buf[0] == '"') { + strbuf_reset(&nbuf); + if (unquote_c_style(&nbuf, buf.buf, NULL)) + die("line is badly quoted"); + strbuf_swap(&buf, &nbuf); + } + p = prefix_path(prefix, prefix_length, buf.buf); checkout_file(p, prefix_length); - if (p < path_name || p > path_name + strlen(path_name)) + if (p < buf.buf || p > buf.buf + buf.len) free((char *)p); - if (path_name != buf.buf) - free(path_name); } + strbuf_release(&nbuf); strbuf_release(&buf); } diff --git a/builtin-update-index.c b/builtin-update-index.c index acd5ab5926..c76879ed7f 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -295,8 +295,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length) static void read_index_info(int line_termination) { struct strbuf buf; + struct strbuf uq; + strbuf_init(&buf, 0); - while (1) { + strbuf_init(&uq, 0); + while (strbuf_getline(&buf, stdin, line_termination) != EOF) { char *ptr, *tab; char *path_name; unsigned char sha1[20]; @@ -320,9 +323,6 @@ 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. */ - if (strbuf_getline(&buf, stdin, line_termination) == EOF) - break; - errno = 0; ul = strtoul(buf.buf, &ptr, 8); if (ptr == buf.buf || *ptr != ' ' @@ -347,15 +347,17 @@ static void read_index_info(int line_termination) if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ') goto bad_line; - if (line_termination && ptr[0] == '"') - path_name = unquote_c_style(ptr, NULL); - else - path_name = ptr; + path_name = ptr; + if (line_termination && path_name[0] == '"') { + strbuf_reset(&uq); + if (unquote_c_style(&uq, path_name, NULL)) { + die("git-update-index: bad quoting of path name"); + } + path_name = uq.buf; + } if (!verify_path(path_name)) { fprintf(stderr, "Ignoring path %s\n", path_name); - if (path_name != ptr) - free(path_name); continue; } @@ -383,6 +385,7 @@ static void read_index_info(int line_termination) die("malformed index info %s", buf.buf); } strbuf_release(&buf); + strbuf_release(&uq); } static const char update_index_usage[] = @@ -705,26 +708,26 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) free((char*)p); } if (read_from_stdin) { - struct strbuf buf; + struct strbuf buf, nbuf; + strbuf_init(&buf, 0); - while (1) { - char *path_name; + strbuf_init(&nbuf, 0); + while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; - if (strbuf_getline(&buf, stdin, line_termination) == EOF) - break; - if (line_termination && buf.buf[0] == '"') - path_name = unquote_c_style(buf.buf, NULL); - else - path_name = buf.buf; - p = prefix_path(prefix, prefix_length, path_name); + if (line_termination && buf.buf[0] == '"') { + strbuf_reset(&nbuf); + if (unquote_c_style(&nbuf, buf.buf, NULL)) + die("line is badly quoted"); + strbuf_swap(&buf, &nbuf); + } + p = prefix_path(prefix, prefix_length, buf.buf); update_one(p, NULL, 0); if (set_executable_bit) chmod_path(set_executable_bit, p); - if (p < path_name || p > path_name + strlen(path_name)) - free((char*) p); - if (path_name != buf.buf) - free(path_name); + if (p < buf.buf || p > buf.buf + buf.len) + free((char *)p); } + strbuf_release(&nbuf); strbuf_release(&buf); } diff --git a/fast-import.c b/fast-import.c index eddae22ea1..a870a44e3d 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1759,7 +1759,7 @@ static void load_branch(struct branch *b) static void file_change_m(struct branch *b) { const char *p = command_buf.buf + 2; - char *p_uq; + static struct strbuf uq = STRBUF_INIT; const char *endp; struct object_entry *oe = oe; unsigned char sha1[20]; @@ -1797,18 +1797,20 @@ static void file_change_m(struct branch *b) if (*p++ != ' ') die("Missing space after SHA1: %s", command_buf.buf); - p_uq = unquote_c_style(p, &endp); - if (p_uq) { + strbuf_reset(&uq); + if (!unquote_c_style(&uq, p, &endp)) { if (*endp) die("Garbage after path in: %s", command_buf.buf); - p = p_uq; + p = uq.buf; } if (inline_data) { static struct strbuf buf = STRBUF_INIT; - if (!p_uq) - p = p_uq = xstrdup(p); + if (p != uq.buf) { + strbuf_addstr(&uq, p); + p = uq.buf; + } read_next_command(); cmd_data(&buf); store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0); @@ -1826,56 +1828,54 @@ static void file_change_m(struct branch *b) } tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode, NULL); - free(p_uq); } static void file_change_d(struct branch *b) { const char *p = command_buf.buf + 2; - char *p_uq; + static struct strbuf uq = STRBUF_INIT; const char *endp; - p_uq = unquote_c_style(p, &endp); - if (p_uq) { + strbuf_reset(&uq); + if (!unquote_c_style(&uq, p, &endp)) { if (*endp) die("Garbage after path in: %s", command_buf.buf); - p = p_uq; + p = uq.buf; } tree_content_remove(&b->branch_tree, p, NULL); - free(p_uq); } static void file_change_cr(struct branch *b, int rename) { const char *s, *d; - char *s_uq, *d_uq; + static struct strbuf s_uq = STRBUF_INIT; + static struct strbuf d_uq = STRBUF_INIT; const char *endp; struct tree_entry leaf; s = command_buf.buf + 2; - s_uq = unquote_c_style(s, &endp); - if (s_uq) { + strbuf_reset(&s_uq); + if (!unquote_c_style(&s_uq, s, &endp)) { if (*endp != ' ') die("Missing space after source: %s", command_buf.buf); - } - else { + } else { endp = strchr(s, ' '); if (!endp) die("Missing space after source: %s", command_buf.buf); - s_uq = xmemdupz(s, endp - s); + strbuf_add(&s_uq, s, endp - s); } - s = s_uq; + s = s_uq.buf; endp++; if (!*endp) die("Missing dest: %s", command_buf.buf); d = endp; - d_uq = unquote_c_style(d, &endp); - if (d_uq) { + strbuf_reset(&d_uq); + if (!unquote_c_style(&d_uq, d, &endp)) { if (*endp) die("Garbage after dest in: %s", command_buf.buf); - d = d_uq; + d = d_uq.buf; } memset(&leaf, 0, sizeof(leaf)); @@ -1889,9 +1889,6 @@ static void file_change_cr(struct branch *b, int rename) leaf.versions[1].sha1, leaf.versions[1].mode, leaf.tree); - - free(s_uq); - free(d_uq); } static void file_change_deleteall(struct branch *b) diff --git a/mktree.c b/mktree.c index 9c137dec45..e0da110a98 100644 --- a/mktree.c +++ b/mktree.c @@ -66,6 +66,7 @@ static const char mktree_usage[] = "git-mktree [-z]"; int main(int ac, char **av) { struct strbuf sb; + struct strbuf p_uq; unsigned char sha1[20]; int line_termination = '\n'; @@ -82,14 +83,13 @@ int main(int ac, char **av) } strbuf_init(&sb, 0); - while (1) { + strbuf_init(&p_uq, 0); + while (strbuf_getline(&sb, stdin, line_termination) != EOF) { char *ptr, *ntr; unsigned mode; enum object_type type; char *path; - if (strbuf_getline(&sb, stdin, line_termination) == EOF) - break; ptr = sb.buf; /* Input is non-recursive ls-tree output format * mode SP type SP sha1 TAB name @@ -109,18 +109,21 @@ int main(int ac, char **av) *ntr++ = 0; /* now at the beginning of SHA1 */ if (type != type_from_string(ptr)) die("object type %s mismatch (%s)", ptr, typename(type)); - ntr += 41; /* at the beginning of name */ - if (line_termination && ntr[0] == '"') - path = unquote_c_style(ntr, NULL); - else - path = ntr; - append_to_tree(mode, sha1, path); + path = ntr + 41; /* at the beginning of name */ + if (line_termination && path[0] == '"') { + strbuf_reset(&p_uq); + if (unquote_c_style(&p_uq, path, NULL)) { + die("invalid quoting"); + } + path = p_uq.buf; + } - if (path != ntr) - free(path); + append_to_tree(mode, sha1, path); } + strbuf_release(&p_uq); strbuf_release(&sb); + write_tree(sha1); puts(sha1_to_hex(sha1)); exit(0); diff --git a/quote.c b/quote.c index d88bf75159..7771c9c678 100644 --- a/quote.c +++ b/quote.c @@ -239,73 +239,71 @@ int quote_c_style(const char *name, char *outbuf, FILE *outfp, int no_dq) /* * C-style name unquoting. * - * Quoted should point at the opening double quote. Returns - * an allocated memory that holds unquoted name, which the caller - * should free when done. Updates endp pointer to point at - * one past the ending double quote if given. + * Quoted should point at the opening double quote. + * + Returns 0 if it was able to unquote the string properly, and appends the + * result in the strbuf `sb'. + * + Returns -1 in case of error, and doesn't touch the strbuf. Though note + * that this function will allocate memory in the strbuf, so calling + * strbuf_release is mandatory whichever result unquote_c_style returns. + * + * Updates endp pointer to point at one past the ending double quote if given. */ - -char *unquote_c_style(const char *quoted, const char **endp) +int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp) { - const char *sp; - char *name = NULL, *outp = NULL; - int count = 0, ch, ac; - -#undef EMIT -#define EMIT(c) (outp ? (*outp++ = (c)) : (count++)) + size_t oldlen = sb->len, len; + int ch, ac; if (*quoted++ != '"') - return NULL; + return -1; + + for (;;) { + len = strcspn(quoted, "\"\\"); + strbuf_add(sb, quoted, len); + quoted += len; - while (1) { - /* first pass counts and allocates, second pass fills */ - for (sp = quoted; (ch = *sp++) != '"'; ) { - if (ch == '\\') { - switch (ch = *sp++) { - case 'a': ch = '\a'; break; - case 'b': ch = '\b'; break; - case 'f': ch = '\f'; break; - case 'n': ch = '\n'; break; - case 'r': ch = '\r'; break; - case 't': ch = '\t'; break; - case 'v': ch = '\v'; break; - - case '\\': case '"': - break; /* verbatim */ - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - /* octal */ + switch (*quoted++) { + case '"': + if (endp) + *endp = quoted + 1; + return 0; + case '\\': + break; + default: + goto error; + } + + switch ((ch = *quoted++)) { + case 'a': ch = '\a'; break; + case 'b': ch = '\b'; break; + case 'f': ch = '\f'; break; + case 'n': ch = '\n'; break; + case 'r': ch = '\r'; break; + case 't': ch = '\t'; break; + case 'v': ch = '\v'; break; + + case '\\': case '"': + break; /* verbatim */ + + /* octal values with first digit over 4 overflow */ + case '0': case '1': case '2': case '3': ac = ((ch - '0') << 6); - if ((ch = *sp++) < '0' || '7' < ch) - return NULL; + if ((ch = *quoted++) < '0' || '7' < ch) + goto error; ac |= ((ch - '0') << 3); - if ((ch = *sp++) < '0' || '7' < ch) - return NULL; + if ((ch = *quoted++) < '0' || '7' < ch) + goto error; ac |= (ch - '0'); ch = ac; break; default: - return NULL; /* malformed */ - } + goto error; } - EMIT(ch); + strbuf_addch(sb, ch); } - if (name) { - *outp = 0; - if (endp) - *endp = sp; - return name; - } - outp = name = xmalloc(count + 1); - } + error: + strbuf_setlen(sb, oldlen); + return -1; } void write_name_quoted(const char *prefix, int prefix_len, diff --git a/quote.h b/quote.h index 8a59cc55d1..f48a3fc584 100644 --- a/quote.h +++ b/quote.h @@ -43,9 +43,9 @@ extern int add_to_string(char **ptrp, int *sizep, const char *str, int quote); */ extern char *sq_dequote(char *); +extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); extern int quote_c_style(const char *name, char *outbuf, FILE *outfp, int nodq); -extern char *unquote_c_style(const char *quoted, const char **endp); extern void write_name_quoted(const char *prefix, int prefix_len, const char *name, int quote, FILE *out); -- cgit v1.3