diff options
author | Junio C Hamano <gitster@pobox.com> | 2007-09-27 00:52:47 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2007-09-27 00:52:47 -0700 |
commit | a17ba31b0b75365e1245e494d46abae4afc57480 (patch) | |
tree | 41c1d800c92e60d97a8b984dce086bcb3473dcc2 | |
parent | 0f729f21348c43a1c80f48faed2e753b1c923e85 (diff) | |
parent | 6d69b6f6ac27ab6f71a10da34b813ca25fd2a358 (diff) | |
download | git-a17ba31b0b75365e1245e494d46abae4afc57480.tar.gz git-a17ba31b0b75365e1245e494d46abae4afc57480.tar.xz |
Merge branch 'ph/strbuf' into kh/commit
* ph/strbuf:
Clean up stripspace a bit, use strbuf even more.
Add strbuf_read_file().
rerere: Fix use of an empty strbuf.buf
Small cache_tree_write refactor.
Make builtin-rerere use of strbuf nicer and more efficient.
Add strbuf_cmp.
strbuf_setlen(): do not barf on setting length of an empty buffer to 0
sq_quote_argv and add_to_string rework with strbuf's.
Full rework of quote_c_style and write_name_quoted.
Rework unquote_c_style to work on a strbuf.
strbuf API additions and enhancements.
nfv?asprintf are broken without va_copy, workaround them.
Fix the expansion pattern of the pseudo-static path buffer.
-rw-r--r-- | archive-tar.c | 5 | ||||
-rw-r--r-- | builtin-apply.c | 200 | ||||
-rw-r--r-- | builtin-blame.c | 3 | ||||
-rw-r--r-- | builtin-check-attr.c | 2 | ||||
-rw-r--r-- | builtin-checkout-index.c | 31 | ||||
-rw-r--r-- | builtin-ls-files.c | 13 | ||||
-rw-r--r-- | builtin-ls-tree.c | 6 | ||||
-rw-r--r-- | builtin-rerere.c | 45 | ||||
-rw-r--r-- | builtin-stripspace.c | 56 | ||||
-rw-r--r-- | builtin-tag.c | 16 | ||||
-rw-r--r-- | builtin-update-index.c | 51 | ||||
-rw-r--r-- | builtin.h | 1 | ||||
-rw-r--r-- | cache-tree.c | 19 | ||||
-rw-r--r-- | cache-tree.h | 2 | ||||
-rw-r--r-- | cache.h | 2 | ||||
-rw-r--r-- | combine-diff.c | 16 | ||||
-rw-r--r-- | commit.c | 2 | ||||
-rw-r--r-- | connect.c | 21 | ||||
-rw-r--r-- | diff.c | 303 | ||||
-rw-r--r-- | fast-import.c | 51 | ||||
-rw-r--r-- | git.c | 16 | ||||
-rw-r--r-- | imap-send.c | 13 | ||||
-rw-r--r-- | merge-recursive.c | 75 | ||||
-rw-r--r-- | mktree.c | 25 | ||||
-rw-r--r-- | quote.c | 407 | ||||
-rw-r--r-- | quote.h | 19 | ||||
-rw-r--r-- | read-cache.c | 19 | ||||
-rw-r--r-- | rsh.c | 32 | ||||
-rw-r--r-- | strbuf.c | 41 | ||||
-rw-r--r-- | strbuf.h | 28 | ||||
-rw-r--r-- | trace.c | 109 |
31 files changed, 731 insertions, 898 deletions
diff --git a/archive-tar.c b/archive-tar.c index a87bc4b83..e1bced560 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -238,15 +238,14 @@ static int write_tar_entry(const unsigned char *sha1, const char *filename, unsigned mode, int stage) { static struct strbuf path = STRBUF_INIT; - int filenamelen = strlen(filename); void *buffer; enum object_type type; unsigned long size; - strbuf_grow(&path, MAX(PATH_MAX, baselen + filenamelen + 1)); strbuf_reset(&path); + strbuf_grow(&path, PATH_MAX); strbuf_add(&path, base, baselen); - strbuf_add(&path, filename, filenamelen); + strbuf_addstr(&path, filename); if (S_ISDIR(mode) || S_ISGITLINK(mode)) { strbuf_addch(&path, '/'); buffer = NULL; diff --git a/builtin-apply.c b/builtin-apply.c index db337f1ac..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); } @@ -231,35 +230,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 +564,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 +596,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 +637,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; } } @@ -1378,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) @@ -2227,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); } } diff --git a/builtin-blame.c b/builtin-blame.c index e364b6c6c..16c0ca820 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -1430,8 +1430,7 @@ static void get_commit_info(struct commit *commit, static void write_filename_info(const char *path) { printf("filename "); - write_name_quoted(NULL, 0, path, 1, stdout); - putchar('\n'); + write_name_quoted(path, stdout, '\n'); } /* diff --git a/builtin-check-attr.c b/builtin-check-attr.c index d94973379..6afdfa10a 100644 --- a/builtin-check-attr.c +++ b/builtin-check-attr.c @@ -56,7 +56,7 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix) else if (ATTR_UNSET(value)) value = "unspecified"; - write_name_quoted("", 0, argv[i], 1, stdout); + quote_c_style(argv[i], NULL, stdout, 0); printf(": %s: %s\n", argv[j+1], value); } } diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index a18ecc4ba..70d619da8 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -66,9 +66,7 @@ static void write_tempfile_record(const char *name, int prefix_length) fputs(topath[checkout_stage], stdout); putchar('\t'); - write_name_quoted("", 0, name + prefix_length, - line_termination, stdout); - putchar(line_termination); + write_name_quoted(name + prefix_length, stdout, line_termination); for (i = 0; i < 4; i++) { topath[i][0] = 0; @@ -270,26 +268,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-ls-files.c b/builtin-ls-files.c index 48dd3f77a..2e6f43bb9 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -84,8 +84,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent) return; fputs(tag, stdout); - write_name_quoted("", 0, ent->name + offset, line_terminator, stdout); - putchar(line_terminator); + write_name_quoted(ent->name + offset, stdout, line_terminator); } static void show_other_files(struct dir_struct *dir) @@ -208,21 +207,15 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) if (!show_stage) { fputs(tag, stdout); - write_name_quoted("", 0, ce->name + offset, - line_terminator, stdout); - putchar(line_terminator); - } - else { + } else { printf("%s%06o %s %d\t", tag, ntohl(ce->ce_mode), abbrev ? find_unique_abbrev(ce->sha1,abbrev) : sha1_to_hex(ce->sha1), ce_stage(ce)); - write_name_quoted("", 0, ce->name + offset, - line_terminator, stdout); - putchar(line_terminator); } + write_name_quoted(ce->name + offset, stdout, line_terminator); } static void show_files(struct dir_struct *dir, const char *prefix) diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c index cb4be4fab..7abe333ce 100644 --- a/builtin-ls-tree.c +++ b/builtin-ls-tree.c @@ -112,10 +112,8 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen, abbrev ? find_unique_abbrev(sha1, abbrev) : sha1_to_hex(sha1)); } - write_name_quoted(base + chomp_prefix, baselen - chomp_prefix, - pathname, - line_termination, stdout); - putchar(line_termination); + write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix, + pathname, stdout, line_termination); return retval; } diff --git a/builtin-rerere.c b/builtin-rerere.c index 58288f61a..b8206744c 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -72,13 +72,9 @@ static int handle_file(const char *path, SHA_CTX ctx; char buf[1024]; int hunk = 0, hunk_no = 0; - struct strbuf minus, plus; - struct strbuf *one = &minus, *two = + + struct strbuf one, two; FILE *f = fopen(path, "r"); - FILE *out; - - strbuf_init(&minus, 0); - strbuf_init(&plus, 0); + FILE *out = NULL; if (!f) return error("Could not open %s", path); @@ -89,51 +85,50 @@ static int handle_file(const char *path, fclose(f); return error("Could not write %s", output); } - } else - out = NULL; + } if (sha1) SHA1_Init(&ctx); + strbuf_init(&one, 0); + strbuf_init(&two, 0); while (fgets(buf, sizeof(buf), f)) { if (!prefixcmp(buf, "<<<<<<< ")) hunk = 1; else if (!prefixcmp(buf, "=======")) hunk = 2; else if (!prefixcmp(buf, ">>>>>>> ")) { - 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); + int cmp = strbuf_cmp(&one, &two); hunk_no++; hunk = 0; - if ((cmp > 0) || ((cmp == 0) && one_is_longer)) { - struct strbuf *swap = one; - one = two; - two = swap; + if (cmp > 0) { + strbuf_swap(&one, &two); } if (out) { fputs("<<<<<<<\n", out); - fwrite(one->buf, one->len, 1, out); + fwrite(one.buf, one.len, 1, out); fputs("=======\n", out); - fwrite(two->buf, two->len, 1, out); + fwrite(two.buf, two.len, 1, out); fputs(">>>>>>>\n", out); } if (sha1) { - SHA1_Update(&ctx, one->buf, one->len); - SHA1_Update(&ctx, "\0", 1); - SHA1_Update(&ctx, two->buf, two->len); - SHA1_Update(&ctx, "\0", 1); + SHA1_Update(&ctx, one.buf ? one.buf : "", + one.len + 1); + SHA1_Update(&ctx, two.buf ? two.buf : "", + two.len + 1); } - strbuf_release(one); - strbuf_release(two); + strbuf_reset(&one); + strbuf_reset(&two); } else if (hunk == 1) - strbuf_addstr(one, buf); + strbuf_addstr(&one, buf); else if (hunk == 2) - strbuf_addstr(two, buf); + strbuf_addstr(&two, buf); else if (out) fputs(buf, out); } + strbuf_release(&one); + strbuf_release(&two); fclose(f); if (out) diff --git a/builtin-stripspace.c b/builtin-stripspace.c index 1ce284710..c0b21301b 100644 --- a/builtin-stripspace.c +++ b/builtin-stripspace.c @@ -8,17 +8,13 @@ */ static size_t cleanup(char *line, size_t len) { - if (len) { - if (line[len - 1] == '\n') - len--; - - while (len) { - unsigned char c = line[len - 1]; - if (!isspace(c)) - break; - len--; - } + while (len) { + unsigned char c = line[len - 1]; + if (!isspace(c)) + break; + len--; } + return len; } @@ -34,42 +30,42 @@ static size_t cleanup(char *line, size_t len) * If the input has only empty lines and spaces, * no output will be produced. * - * If last line has a newline at the end, it will be removed. + * If last line does not have a newline at the end, one is added. * * Enable skip_comments to skip every line starting with "#". */ -size_t stripspace(char *buffer, size_t length, int skip_comments) +void stripspace(struct strbuf *sb, int skip_comments) { - int empties = -1; + int empties = 0; size_t i, j, len, newlen; char *eol; - for (i = j = 0; i < length; i += len, j += newlen) { - eol = memchr(buffer + i, '\n', length - i); - len = eol ? eol - (buffer + i) + 1 : length - i; + /* We may have to add a newline. */ + strbuf_grow(sb, 1); - if (skip_comments && len && buffer[i] == '#') { + for (i = j = 0; i < sb->len; i += len, j += newlen) { + eol = memchr(sb->buf + i, '\n', sb->len - i); + len = eol ? eol - (sb->buf + i) + 1 : sb->len - i; + + if (skip_comments && len && sb->buf[i] == '#') { newlen = 0; continue; } - newlen = cleanup(buffer + i, len); + newlen = cleanup(sb->buf + i, len); /* Not just an empty line? */ if (newlen) { - if (empties != -1) - buffer[j++] = '\n'; - if (empties > 0) - buffer[j++] = '\n'; + if (empties > 0 && j > 0) + sb->buf[j++] = '\n'; empties = 0; - memmove(buffer + j, buffer + i, newlen); - continue; + memmove(sb->buf + j, sb->buf + i, newlen); + sb->buf[newlen + j++] = '\n'; + } else { + empties++; } - if (empties < 0) - continue; - empties++; } - return j; + strbuf_setlen(sb, j); } int cmd_stripspace(int argc, const char **argv, const char *prefix) @@ -85,9 +81,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix) if (strbuf_read(&buf, 0, 1024) < 0) die("could not read the input"); - strbuf_setlen(&buf, stripspace(buf.buf, buf.len, strip_comments)); - if (buf.len) - strbuf_addch(&buf, '\n'); + stripspace(&buf, strip_comments); write_or_die(1, buf.buf, buf.len); strbuf_release(&buf); diff --git a/builtin-tag.c b/builtin-tag.c index 82ebda11b..6132cac21 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -22,7 +22,6 @@ static void launch_editor(const char *path, struct strbuf *buffer) const char *editor, *terminal; struct child_process child; const char *args[3]; - int fd; editor = getenv("GIT_EDITOR"); if (!editor && editor_program) @@ -52,13 +51,9 @@ static void launch_editor(const char *path, struct strbuf *buffer) if (run_command(&child)) die("There was a problem with the editor %s.", editor); - fd = open(path, O_RDONLY); - if (fd < 0) - die("could not open '%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); + if (strbuf_read_file(buffer, path) < 0) + die("could not read message file '%s': %s", + path, strerror(errno)); } struct tag_filter { @@ -296,14 +291,11 @@ static void create_tag(const unsigned char *object, const char *tag, free(path); } - strbuf_setlen(buf, stripspace(buf->buf, buf->len, 1)); + stripspace(buf, 1); if (!message && !buf->len) die("no tag message?"); - /* insert the header and add the '\n' if needed: */ - if (buf->len) - strbuf_addch(buf, '\n'); strbuf_insert(buf, 0, header_buf, header_len); if (sign && do_sign(buf) < 0) diff --git a/builtin-update-index.c b/builtin-update-index.c index acd5ab592..c76879ed7 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); } @@ -7,7 +7,6 @@ extern const char git_version_string[]; extern const char git_usage_string[]; extern void help_unknown_cmd(const char *cmd); -extern size_t stripspace(char *buffer, size_t length, int skip_comments); extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix); extern void prune_packed_objects(int); diff --git a/cache-tree.c b/cache-tree.c index 5471844af..50b35264f 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -369,10 +369,8 @@ int cache_tree_update(struct cache_tree *it, return 0; } -static void write_one(struct cache_tree *it, - char *path, - int pathlen, - struct strbuf *buffer) +static void write_one(struct strbuf *buffer, struct cache_tree *it, + const char *path, int pathlen) { int i; @@ -407,20 +405,13 @@ static void write_one(struct cache_tree *it, prev->name, prev->namelen) <= 0) die("fatal - unsorted cache subtree"); } - write_one(down->cache_tree, down->name, down->namelen, buffer); + write_one(buffer, down->cache_tree, down->name, down->namelen); } } -void *cache_tree_write(struct cache_tree *root, unsigned long *size_p) +void cache_tree_write(struct strbuf *sb, struct cache_tree *root) { - char path[PATH_MAX]; - struct strbuf buffer; - - path[0] = 0; - strbuf_init(&buffer, 0); - write_one(root, path, 0, &buffer); - *size_p = buffer.len; - return strbuf_detach(&buffer); + write_one(sb, root, "", 0); } static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) diff --git a/cache-tree.h b/cache-tree.h index 119407e3a..8243228e4 100644 --- a/cache-tree.h +++ b/cache-tree.h @@ -22,7 +22,7 @@ void cache_tree_free(struct cache_tree **); void cache_tree_invalidate_path(struct cache_tree *, const char *); struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *); -void *cache_tree_write(struct cache_tree *root, unsigned long *size_p); +void cache_tree_write(struct strbuf *, struct cache_tree *root); struct cache_tree *cache_tree_read(const char *buffer, unsigned long size); int cache_tree_fully_valid(struct cache_tree *); @@ -585,8 +585,6 @@ extern void *alloc_object_node(void); extern void alloc_report(void); /* trace.c */ -extern int nfasprintf(char **str, const char *fmt, ...); -extern int nfvasprintf(char **str, const char *fmt, va_list va); extern void trace_printf(const char *format, ...); extern void trace_argv_printf(const char **argv, int count, const char *format, ...); diff --git a/combine-diff.c b/combine-diff.c index ef622340a..fe5a2a195 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -650,10 +650,7 @@ static void dump_quoted_path(const char *prefix, const char *path, const char *c_meta, const char *c_reset) { printf("%s%s", c_meta, prefix); - if (quote_c_style(path, NULL, NULL, 0)) - quote_c_style(path, NULL, stdout, 0); - else - printf("%s", path); + quote_c_style(path, NULL, stdout, 0); printf("%s\n", c_reset); } @@ -900,16 +897,7 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re putchar(inter_name_termination); } - if (line_termination) { - if (quote_c_style(p->path, NULL, NULL, 0)) - quote_c_style(p->path, NULL, stdout, 0); - else - printf("%s", p->path); - putchar(line_termination); - } - else { - printf("%s%c", p->path, line_termination); - } + write_name_quoted(p->path, stdout, line_termination); } void show_combined_diff(struct combine_diff_path *p, @@ -656,7 +656,7 @@ static char *replace_encoding_header(char *buf, const char *encoding) strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1); if (is_encoding_utf8(encoding)) { /* we have re-coded to UTF-8; drop the header */ - strbuf_splice(&tmp, start, len, NULL, 0); + strbuf_remove(&tmp, start, len); } else { /* just replaces XXXX in 'encoding XXXX\n' */ strbuf_splice(&tmp, start + strlen("encoding "), @@ -577,16 +577,13 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) if (pid < 0) die("unable to fork"); if (!pid) { - char command[MAX_CMD_LEN]; - char *posn = command; - int size = MAX_CMD_LEN; - int of = 0; + struct strbuf cmd; - of |= add_to_string(&posn, &size, prog, 0); - of |= add_to_string(&posn, &size, " ", 0); - of |= add_to_string(&posn, &size, path, 1); - - if (of) + strbuf_init(&cmd, MAX_CMD_LEN); + strbuf_addstr(&cmd, prog); + strbuf_addch(&cmd, ' '); + sq_quote_buf(&cmd, path); + if (cmd.len >= MAX_CMD_LEN) die("command line too long"); dup2(pipefd[1][0], 0); @@ -606,10 +603,10 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) ssh_basename++; if (!port) - execlp(ssh, ssh_basename, host, command, NULL); + execlp(ssh, ssh_basename, host, cmd.buf, NULL); else execlp(ssh, ssh_basename, "-p", port, host, - command, NULL); + cmd.buf, NULL); } else { unsetenv(ALTERNATE_DB_ENVIRONMENT); @@ -618,7 +615,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) unsetenv(GIT_WORK_TREE_ENVIRONMENT); unsetenv(GRAFT_ENVIRONMENT); unsetenv(INDEX_ENVIRONMENT); - execlp("sh", "sh", "-c", command, NULL); + execlp("sh", "sh", "-c", cmd.buf, NULL); } die("exec failed"); } @@ -181,44 +181,23 @@ int git_diff_ui_config(const char *var, const char *value) return git_default_config(var, value); } -static char *quote_one(const char *str) -{ - int needlen; - char *xp; - - if (!str) - return NULL; - needlen = quote_c_style(str, NULL, NULL, 0); - if (!needlen) - return xstrdup(str); - xp = xmalloc(needlen + 1); - quote_c_style(str, xp, NULL, 0); - return xp; -} - static char *quote_two(const char *one, const char *two) { int need_one = quote_c_style(one, NULL, NULL, 1); int need_two = quote_c_style(two, NULL, NULL, 1); - char *xp; + struct strbuf res; + strbuf_init(&res, 0); if (need_one + need_two) { - if (!need_one) need_one = strlen(one); - if (!need_two) need_one = strlen(two); - - xp = xmalloc(need_one + need_two + 3); - xp[0] = '"'; - quote_c_style(one, xp + 1, NULL, 1); - quote_c_style(two, xp + need_one + 1, NULL, 1); - strcpy(xp + need_one + need_two + 1, "\""); - return xp; + strbuf_addch(&res, '"'); + quote_c_style(one, &res, NULL, 1); + quote_c_style(two, &res, NULL, 1); + strbuf_addch(&res, '"'); + } else { + strbuf_addstr(&res, one); + strbuf_addstr(&res, two); } - need_one = strlen(one); - need_two = strlen(two); - xp = xmalloc(need_one + need_two + 1); - strcpy(xp, one); - strcpy(xp + need_one, two); - return xp; + return res.buf; } static const char *external_diff(void) @@ -670,27 +649,20 @@ static char *pprint_rename(const char *a, const char *b) { const char *old = a; const char *new = b; - char *name = NULL; + struct strbuf name; int pfx_length, sfx_length; int len_a = strlen(a); int len_b = strlen(b); + int a_midlen, b_midlen; int qlen_a = quote_c_style(a, NULL, NULL, 0); int qlen_b = quote_c_style(b, NULL, NULL, 0); + strbuf_init(&name, 0); if (qlen_a || qlen_b) { - if (qlen_a) len_a = qlen_a; - if (qlen_b) len_b = qlen_b; - name = xmalloc( len_a + len_b + 5 ); - if (qlen_a) - quote_c_style(a, name, NULL, 0); - else - memcpy(name, a, len_a); - memcpy(name + len_a, " => ", 4); - if (qlen_b) - quote_c_style(b, name + len_a + 4, NULL, 0); - else - memcpy(name + len_a + 4, b, len_b + 1); - return name; + quote_c_style(a, &name, NULL, 0); + strbuf_addstr(&name, " => "); + quote_c_style(b, &name, NULL, 0); + return name.buf; } /* Find common prefix */ @@ -719,24 +691,26 @@ static char *pprint_rename(const char *a, const char *b) * pfx{sfx-a => sfx-b} * name-a => name-b */ + a_midlen = len_a - pfx_length - sfx_length; + b_midlen = len_b - pfx_length - sfx_length; + if (a_midlen < 0) + a_midlen = 0; + if (b_midlen < 0) + b_midlen = 0; + + strbuf_grow(&name, pfx_length + a_midlen + b_midlen + sfx_length + 7); if (pfx_length + sfx_length) { - int a_midlen = len_a - pfx_length - sfx_length; - int b_midlen = len_b - pfx_length - sfx_length; - if (a_midlen < 0) a_midlen = 0; - if (b_midlen < 0) b_midlen = 0; - - name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7); - sprintf(name, "%.*s{%.*s => %.*s}%s", - pfx_length, a, - a_midlen, a + pfx_length, - b_midlen, b + pfx_length, - a + len_a - sfx_length); + strbuf_add(&name, a, pfx_length); + strbuf_addch(&name, '{'); } - else { - name = xmalloc(len_a + len_b + 5); - sprintf(name, "%s => %s", a, b); + strbuf_add(&name, a + pfx_length, a_midlen); + strbuf_addstr(&name, " => "); + strbuf_add(&name, b + pfx_length, b_midlen); + if (pfx_length + sfx_length) { + strbuf_addch(&name, '}'); + strbuf_add(&name, a + len_a - sfx_length, sfx_length); } - return name; + return name.buf; } struct diffstat_t { @@ -849,12 +823,13 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) int change = file->added + file->deleted; if (!file->is_renamed) { /* renames are already quoted by pprint_rename */ - len = quote_c_style(file->name, NULL, NULL, 0); - if (len) { - char *qname = xmalloc(len + 1); - quote_c_style(file->name, qname, NULL, 0); + struct strbuf buf; + strbuf_init(&buf, 0); + if (quote_c_style(file->name, &buf, NULL, 0)) { free(file->name); - file->name = qname; + file->name = buf.buf; + } else { + strbuf_release(&buf); } } @@ -992,12 +967,12 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options) printf("-\t-\t"); else printf("%d\t%d\t", file->added, file->deleted); - if (options->line_termination && !file->is_renamed && - quote_c_style(file->name, NULL, NULL, 0)) - quote_c_style(file->name, NULL, stdout, 0); - else + if (!file->is_renamed) { + write_name_quoted(file->name, stdout, options->line_termination); + } else { fputs(file->name, stdout); - putchar(options->line_termination); + putchar(options->line_termination); + } } } @@ -1941,50 +1916,46 @@ static int similarity_index(struct diff_filepair *p) static void run_diff(struct diff_filepair *p, struct diff_options *o) { const char *pgm = external_diff(); - char msg[PATH_MAX*2+300], *xfrm_msg; - struct diff_filespec *one; - struct diff_filespec *two; + struct strbuf msg; + char *xfrm_msg; + struct diff_filespec *one = p->one; + struct diff_filespec *two = p->two; const char *name; const char *other; - char *name_munged, *other_munged; int complete_rewrite = 0; - int len; + if (DIFF_PAIR_UNMERGED(p)) { - /* unmerged */ run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0); return; } - name = p->one->path; + name = p->one->path; other = (strcmp(name, p->two->path) ? p->two->path : NULL); - name_munged = quote_one(name); - other_munged = quote_one(other); - one = p->one; two = p->two; - diff_fill_sha1_info(one); diff_fill_sha1_info(two); - len = 0; + strbuf_init(&msg, PATH_MAX * 2 + 300); switch (p->status) { case DIFF_STATUS_COPIED: - len += snprintf(msg + len, sizeof(msg) - len, - "similarity index %d%%\n" - "copy from %s\n" - "copy to %s\n", - similarity_index(p), name_munged, other_munged); + strbuf_addf(&msg, "similarity index %d%%", similarity_index(p)); + strbuf_addstr(&msg, "\ncopy from "); + quote_c_style(name, &msg, NULL, 0); + strbuf_addstr(&msg, "\ncopy to "); + quote_c_style(other, &msg, NULL, 0); + strbuf_addch(&msg, '\n'); break; case DIFF_STATUS_RENAMED: - len += snprintf(msg + len, sizeof(msg) - len, - "similarity index %d%%\n" - "rename from %s\n" - "rename to %s\n", - similarity_index(p), name_munged, other_munged); + strbuf_addf(&msg, "similarity index %d%%", similarity_index(p)); + strbuf_addstr(&msg, "\nrename from "); + quote_c_style(name, &msg, NULL, 0); + strbuf_addstr(&msg, "\nrename to "); + quote_c_style(other, &msg, NULL, 0); + strbuf_addch(&msg, '\n'); break; case DIFF_STATUS_MODIFIED: if (p->score) { - len += snprintf(msg + len, sizeof(msg) - len, - "dissimilarity index %d%%\n", + strbuf_addf(&msg, "dissimilarity index %d%%\n", similarity_index(p)); complete_rewrite = 1; break; @@ -2004,19 +1975,17 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) abbrev = 40; } - len += snprintf(msg + len, sizeof(msg) - len, - "index %.*s..%.*s", + strbuf_addf(&msg, "index %.*s..%.*s", abbrev, sha1_to_hex(one->sha1), abbrev, sha1_to_hex(two->sha1)); if (one->mode == two->mode) - len += snprintf(msg + len, sizeof(msg) - len, - " %06o", one->mode); - len += snprintf(msg + len, sizeof(msg) - len, "\n"); + strbuf_addf(&msg, " %06o", one->mode); + strbuf_addch(&msg, '\n'); } - if (len) - msg[--len] = 0; - xfrm_msg = len ? msg : NULL; + if (msg.len) + strbuf_setlen(&msg, msg.len - 1); + xfrm_msg = msg.len ? msg.buf : NULL; if (!pgm && DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && @@ -2035,8 +2004,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o, complete_rewrite); - free(name_munged); - free(other_munged); + strbuf_release(&msg); } static void run_diffstat(struct diff_filepair *p, struct diff_options *o, @@ -2492,72 +2460,30 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len) return sha1_to_hex(sha1); } -static void diff_flush_raw(struct diff_filepair *p, - struct diff_options *options) +static void diff_flush_raw(struct diff_filepair *p, struct diff_options *opt) { - int two_paths; - char status[10]; - int abbrev = options->abbrev; - const char *path_one, *path_two; - int inter_name_termination = '\t'; - int line_termination = options->line_termination; - - if (!line_termination) - inter_name_termination = 0; + int line_termination = opt->line_termination; + int inter_name_termination = line_termination ? '\t' : '\0'; - path_one = p->one->path; - path_two = p->two->path; - if (line_termination) { - path_one = quote_one(path_one); - path_two = quote_one(path_two); + if (!(opt->output_format & DIFF_FORMAT_NAME_STATUS)) { + printf(":%06o %06o %s ", p->one->mode, p->two->mode, + diff_unique_abbrev(p->one->sha1, opt->abbrev)); + printf("%s ", diff_unique_abbrev(p->two->sha1, opt->abbrev)); } - - if (p->score) - sprintf(status, "%c%03d", p->status, similarity_index(p)); - else { - status[0] = p->status; - status[1] = 0; - } - switch (p->status) { - case DIFF_STATUS_COPIED: - case DIFF_STATUS_RENAMED: - two_paths = 1; - break; - case DIFF_STATUS_ADDED: - case DIFF_STATUS_DELETED: - two_paths = 0; - break; - default: - two_paths = 0; - break; - } - if (!(options->output_format & DIFF_FORMAT_NAME_STATUS)) { - printf(":%06o %06o %s ", - p->one->mode, p->two->mode, - diff_unique_abbrev(p->one->sha1, abbrev)); - printf("%s ", - diff_unique_abbrev(p->two->sha1, abbrev)); + if (p->score) { + printf("%c%03d%c", p->status, similarity_index(p), + inter_name_termination); + } else { + printf("%c%c", p->status, inter_name_termination); } - printf("%s%c%s", status, inter_name_termination, - two_paths || p->one->mode ? path_one : path_two); - if (two_paths) - printf("%c%s", inter_name_termination, path_two); - putchar(line_termination); - if (path_one != p->one->path) - free((void*)path_one); - if (path_two != p->two->path) - free((void*)path_two); -} -static void diff_flush_name(struct diff_filepair *p, struct diff_options *opt) -{ - char *path = p->two->path; - - if (opt->line_termination) - path = quote_one(p->two->path); - printf("%s%c", path, opt->line_termination); - if (p->two->path != path) - free(path); + if (p->status == DIFF_STATUS_COPIED || p->status == DIFF_STATUS_RENAMED) { + write_name_quoted(p->one->path, stdout, inter_name_termination); + write_name_quoted(p->two->path, stdout, line_termination); + } else { + const char *path = p->one->mode ? p->one->path : p->two->path; + write_name_quoted(path, stdout, line_termination); + } } int diff_unmodified_pair(struct diff_filepair *p) @@ -2567,14 +2493,11 @@ int diff_unmodified_pair(struct diff_filepair *p) * let transformers to produce diff_filepairs any way they want, * and filter and clean them up here before producing the output. */ - struct diff_filespec *one, *two; + struct diff_filespec *one = p->one, *two = p->two; if (DIFF_PAIR_UNMERGED(p)) return 0; /* unmerged is interesting */ - one = p->one; - two = p->two; - /* deletion, addition, mode or type change * and rename are all interesting. */ @@ -2763,32 +2686,27 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt) else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) diff_flush_raw(p, opt); else if (fmt & DIFF_FORMAT_NAME) - diff_flush_name(p, opt); + write_name_quoted(p->two->path, stdout, opt->line_termination); } static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs) { - char *name = quote_one(fs->path); if (fs->mode) - printf(" %s mode %06o %s\n", newdelete, fs->mode, name); + printf(" %s mode %06o ", newdelete, fs->mode); else - printf(" %s %s\n", newdelete, name); - free(name); + printf(" %s ", newdelete); + write_name_quoted(fs->path, stdout, '\n'); } static void show_mode_change(struct diff_filepair *p, int show_name) { if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) { + printf(" mode change %06o => %06o%c", p->one->mode, p->two->mode, + show_name ? ' ' : '\n'); if (show_name) { - char *name = quote_one(p->two->path); - printf(" mode change %06o => %06o %s\n", - p->one->mode, p->two->mode, name); - free(name); + write_name_quoted(p->two->path, stdout, '\n'); } - else - printf(" mode change %06o => %06o\n", - p->one->mode, p->two->mode); } } @@ -2818,12 +2736,11 @@ static void diff_summary(struct diff_filepair *p) break; default: if (p->score) { - char *name = quote_one(p->two->path); - printf(" rewrite %s (%d%%)\n", name, - similarity_index(p)); - free(name); - show_mode_change(p, 0); - } else show_mode_change(p, 1); + puts(" rewrite "); + write_name_quoted(p->two->path, stdout, ' '); + printf("(%d%%)\n", similarity_index(p)); + } + show_mode_change(p, !p->score); break; } } @@ -2837,14 +2754,14 @@ struct patch_id_t { static int remove_space(char *line, int len) { int i; - char *dst = line; - unsigned char c; + char *dst = line; + unsigned char c; - for (i = 0; i < len; i++) - if (!isspace((c = line[i]))) - *dst++ = c; + for (i = 0; i < len; i++) + if (!isspace((c = line[i]))) + *dst++ = c; - return dst - line; + return dst - line; } static void patch_id_consume(void *priv, char *line, unsigned long len) diff --git a/fast-import.c b/fast-import.c index f9906586e..a870a44e3 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1111,9 +1111,7 @@ static int store_object( if (last->no_swap) { last->data = *dat; } else { - struct strbuf tmp = *dat; - *dat = last->data; - last->data = tmp; + strbuf_swap(&last->data, dat); } last->offset = e->offset; } @@ -1761,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]; @@ -1799,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); @@ -1828,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)); @@ -1891,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) @@ -187,19 +187,13 @@ static int handle_alias(int *argcp, const char ***argv) if (alias_string) { if (alias_string[0] == '!') { if (*argcp > 1) { - int i, sz = PATH_MAX; - char *s = xmalloc(sz), *new_alias = s; + struct strbuf buf; - add_to_string(&s, &sz, alias_string, 0); + strbuf_init(&buf, PATH_MAX); + strbuf_addstr(&buf, alias_string); + sq_quote_argv(&buf, (*argv) + 1, *argcp - 1, PATH_MAX); free(alias_string); - alias_string = new_alias; - for (i = 1; i < *argcp && - !add_to_string(&s, &sz, " ", 0) && - !add_to_string(&s, &sz, (*argv)[i], 1) - ; i++) - ; /* do nothing */ - if (!sz) - die("Too many or long arguments"); + alias_string = buf.buf; } trace_printf("trace: alias to shell cmd: %s => %s\n", alias_command, alias_string + 1); diff --git a/imap-send.c b/imap-send.c index 905d09746..e95cdde06 100644 --- a/imap-send.c +++ b/imap-send.c @@ -105,6 +105,19 @@ static void free_generic_messages( message_t * ); static int nfsnprintf( char *buf, int blen, const char *fmt, ... ); +static int nfvasprintf(char **strp, const char *fmt, va_list ap) +{ + int len; + char tmp[8192]; + + len = vsnprintf(tmp, sizeof(tmp), fmt, ap); + if (len < 0) + die("Fatal: Out of memory\n"); + if (len >= sizeof(tmp)) + die("imap command overflow !\n"); + *strp = xmemdupz(tmp, len); + return len; +} static void arc4_init( void ); static unsigned char arc4_getbyte( void ); diff --git a/merge-recursive.c b/merge-recursive.c index 14b56c2f2..86767e6e8 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -85,63 +85,58 @@ struct stage_data unsigned processed:1; }; -struct output_buffer -{ - struct output_buffer *next; - char *str; -}; - static struct path_list current_file_set = {NULL, 0, 0, 1}; static struct path_list current_directory_set = {NULL, 0, 0, 1}; static int call_depth = 0; static int verbosity = 2; static int buffer_output = 1; -static struct output_buffer *output_list, *output_end; +static struct strbuf obuf = STRBUF_INIT; -static int show (int v) +static int show(int v) { return (!call_depth && verbosity >= v) || verbosity >= 5; } -static void output(int v, const char *fmt, ...) +static void flush_output(void) { - va_list args; - va_start(args, fmt); - if (buffer_output && show(v)) { - struct output_buffer *b = xmalloc(sizeof(*b)); - nfvasprintf(&b->str, fmt, args); - b->next = NULL; - if (output_end) - output_end->next = b; - else - output_list = b; - output_end = b; - } else if (show(v)) { - int i; - for (i = call_depth; i--;) - fputs(" ", stdout); - vfprintf(stdout, fmt, args); - fputc('\n', stdout); + if (obuf.len) { + fputs(obuf.buf, stdout); + strbuf_reset(&obuf); } - va_end(args); } -static void flush_output(void) +static void output(int v, const char *fmt, ...) { - struct output_buffer *b, *n; - for (b = output_list; b; b = n) { - int i; - for (i = call_depth; i--;) - fputs(" ", stdout); - fputs(b->str, stdout); - fputc('\n', stdout); - n = b->next; - free(b->str); - free(b); + int len; + va_list ap; + + if (!show(v)) + return; + + strbuf_grow(&obuf, call_depth * 2 + 2); + memset(obuf.buf + obuf.len, ' ', call_depth * 2); + strbuf_setlen(&obuf, obuf.len + call_depth * 2); + + va_start(ap, fmt); + len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap); + va_end(ap); + + if (len < 0) + len = 0; + if (len >= strbuf_avail(&obuf)) { + strbuf_grow(&obuf, len + 2); + va_start(ap, fmt); + len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap); + va_end(ap); + if (len >= strbuf_avail(&obuf)) { + die("this should not happen, your snprintf is broken"); + } } - output_list = NULL; - output_end = NULL; + strbuf_setlen(&obuf, obuf.len + len); + strbuf_add(&obuf, "\n", 1); + if (!buffer_output) + flush_output(); } static void output_commit_title(struct commit *commit) @@ -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); @@ -12,37 +12,31 @@ * a'b ==> a'\''b ==> 'a'\''b' * a!b ==> a'\!'b ==> 'a'\!'b' */ -#undef EMIT -#define EMIT(x) do { if (++len < n) *bp++ = (x); } while(0) - static inline int need_bs_quote(char c) { return (c == '\'' || c == '!'); } -static size_t sq_quote_buf(char *dst, size_t n, const char *src) +void sq_quote_buf(struct strbuf *dst, const char *src) { - char c; - char *bp = dst; - size_t len = 0; - - EMIT('\''); - while ((c = *src++)) { - if (need_bs_quote(c)) { - EMIT('\''); - EMIT('\\'); - EMIT(c); - EMIT('\''); - } else { - EMIT(c); + char *to_free = NULL; + + if (dst->buf == src) + to_free = strbuf_detach(dst); + + strbuf_addch(dst, '\''); + while (*src) { + size_t len = strcspn(src, "'\\"); + strbuf_add(dst, src, len); + src += len; + while (need_bs_quote(*src)) { + strbuf_addstr(dst, "'\\"); + strbuf_addch(dst, *src++); + strbuf_addch(dst, '\''); } } - EMIT('\''); - - if ( n ) - *bp = 0; - - return len; + strbuf_addch(dst, '\''); + free(to_free); } void sq_quote_print(FILE *stream, const char *src) @@ -62,11 +56,10 @@ void sq_quote_print(FILE *stream, const char *src) fputc('\'', stream); } -char *sq_quote_argv(const char** argv, int count) +void sq_quote_argv(struct strbuf *dst, const char** argv, int count, + size_t maxlen) { - char *buf, *to; int i; - size_t len = 0; /* Count argv if needed. */ if (count < 0) { @@ -74,53 +67,14 @@ char *sq_quote_argv(const char** argv, int count) ; /* just counting */ } - /* Special case: no argv. */ - if (!count) - return xcalloc(1,1); - - /* Get destination buffer length. */ - for (i = 0; i < count; i++) - len += sq_quote_buf(NULL, 0, argv[i]) + 1; - - /* Alloc destination buffer. */ - to = buf = xmalloc(len + 1); - /* Copy into destination buffer. */ + strbuf_grow(dst, 32 * count); for (i = 0; i < count; ++i) { - *to++ = ' '; - to += sq_quote_buf(to, len, argv[i]); + strbuf_addch(dst, ' '); + sq_quote_buf(dst, argv[i]); + if (maxlen && dst->len > maxlen) + die("Too many or long arguments"); } - - return buf; -} - -/* - * Append a string to a string buffer, with or without shell quoting. - * Return true if the buffer overflowed. - */ -int add_to_string(char **ptrp, int *sizep, const char *str, int quote) -{ - char *p = *ptrp; - int size = *sizep; - int oc; - int err = 0; - - if (quote) - oc = sq_quote_buf(p, size, str); - else { - oc = strlen(str); - memcpy(p, str, (size <= oc) ? size - 1 : oc); - } - - if (size <= oc) { - err = 1; - oc = size - 1; - } - - *ptrp += oc; - **ptrp = '\0'; - *sizep -= oc; - return err; } char *sq_dequote(char *arg) @@ -157,186 +111,213 @@ char *sq_dequote(char *arg) } } +/* 1 means: quote as octal + * 0 means: quote as octal if (quote_path_fully) + * -1 means: never quote + * c: quote as "\\c" + */ +#define X8(x) x, x, x, x, x, x, x, x +#define X16(x) X8(x), X8(x) +static signed char const sq_lookup[256] = { + /* 0 1 2 3 4 5 6 7 */ + /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a', + /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1, + /* 0x10 */ X16(1), + /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1, + /* 0x28 */ X16(-1), X16(-1), X16(-1), + /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1, + /* 0x60 */ X16(-1), X8(-1), + /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1, + /* 0x80 */ /* set to 0 */ +}; + +static inline int sq_must_quote(char c) { + return sq_lookup[(unsigned char)c] + quote_path_fully > 0; +} + +/* returns the longest prefix not needing a quote up to maxlen if positive. + This stops at the first \0 because it's marked as a character needing an + escape */ +static size_t next_quote_pos(const char *s, ssize_t maxlen) +{ + size_t len; + if (maxlen < 0) { + for (len = 0; !sq_must_quote(s[len]); len++); + } else { + for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++); + } + return len; +} + /* * C-style name quoting. * - * Does one of three things: - * - * (1) if outbuf and outfp are both NULL, inspect the input name and - * counts the number of bytes that are needed to hold c_style - * quoted version of name, counting the double quotes around - * it but not terminating NUL, and returns it. However, if name - * does not need c_style quoting, it returns 0. - * - * (2) if outbuf is not NULL, it must point at a buffer large enough - * to hold the c_style quoted version of name, enclosing double - * quotes, and terminating NUL. Fills outbuf with c_style quoted - * version of name enclosed in double-quote pair. Return value - * is undefined. + * (1) if sb and fp are both NULL, inspect the input name and counts the + * number of bytes that are needed to hold c_style quoted version of name, + * counting the double quotes around it but not terminating NUL, and + * returns it. + * However, if name does not need c_style quoting, it returns 0. * - * (3) if outfp is not NULL, outputs c_style quoted version of name, - * but not enclosed in double-quote pair. Return value is undefined. + * (2) if sb or fp are not NULL, it emits the c_style quoted version + * of name, enclosed with double quotes if asked and needed only. + * Return value is the same as in (1). */ - -static int quote_c_style_counted(const char *name, int namelen, - char *outbuf, FILE *outfp, int no_dq) +static size_t quote_c_style_counted(const char *name, ssize_t maxlen, + struct strbuf *sb, FILE *fp, int no_dq) { #undef EMIT -#define EMIT(c) \ - (outbuf ? (*outbuf++ = (c)) : outfp ? fputc(c, outfp) : (count++)) - -#define EMITQ() EMIT('\\') +#define EMIT(c) \ + do { \ + if (sb) strbuf_addch(sb, (c)); \ + if (fp) fputc((c), fp); \ + count++; \ + } while (0) +#define EMITBUF(s, l) \ + do { \ + if (sb) strbuf_add(sb, (s), (l)); \ + if (fp) fwrite((s), (l), 1, fp); \ + count += (l); \ + } while (0) + + size_t len, count = 0; + const char *p = name; - const char *sp; - unsigned char ch; - int count = 0, needquote = 0; + for (;;) { + int ch; - if (!no_dq) - EMIT('"'); - for (sp = name; sp < name + namelen; sp++) { - ch = *sp; - if (!ch) + len = next_quote_pos(p, maxlen); + if (len == maxlen || !p[len]) break; - if ((ch < ' ') || (ch == '"') || (ch == '\\') || - (quote_path_fully && (ch >= 0177))) { - needquote = 1; - switch (ch) { - case '\a': EMITQ(); ch = 'a'; break; - case '\b': EMITQ(); ch = 'b'; break; - case '\f': EMITQ(); ch = 'f'; break; - case '\n': EMITQ(); ch = 'n'; break; - case '\r': EMITQ(); ch = 'r'; break; - case '\t': EMITQ(); ch = 't'; break; - case '\v': EMITQ(); ch = 'v'; break; - - case '\\': /* fallthru */ - case '"': EMITQ(); break; - default: - /* octal */ - EMITQ(); - EMIT(((ch >> 6) & 03) + '0'); - EMIT(((ch >> 3) & 07) + '0'); - ch = (ch & 07) + '0'; - break; - } + + if (!no_dq && p == name) + EMIT('"'); + + EMITBUF(p, len); + EMIT('\\'); + p += len; + ch = (unsigned char)*p++; + if (sq_lookup[ch] >= ' ') { + EMIT(sq_lookup[ch]); + } else { + EMIT(((ch >> 6) & 03) + '0'); + EMIT(((ch >> 3) & 07) + '0'); + EMIT(((ch >> 0) & 07) + '0'); } - EMIT(ch); } + + EMITBUF(p, len); + if (p == name) /* no ending quote needed */ + return 0; + if (!no_dq) EMIT('"'); - if (outbuf) - *outbuf = 0; + return count; +} - return needquote ? count : 0; +size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq) +{ + return quote_c_style_counted(name, -1, sb, fp, nodq); } -int quote_c_style(const char *name, char *outbuf, FILE *outfp, int no_dq) +void write_name_quoted(const char *name, FILE *fp, int terminator) { - int cnt = strlen(name); - return quote_c_style_counted(name, cnt, outbuf, outfp, no_dq); + if (terminator) { + quote_c_style(name, NULL, fp, 0); + } else { + fputs(name, fp); + } + fputc(terminator, fp); +} + +extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, + const char *name, FILE *fp, int terminator) +{ + int needquote = 0; + + if (terminator) { + needquote = next_quote_pos(pfx, pfxlen) < pfxlen + || name[next_quote_pos(name, -1)]; + } + if (needquote) { + fputc('"', fp); + quote_c_style_counted(pfx, pfxlen, NULL, fp, 1); + quote_c_style(name, NULL, fp, 1); + fputc('"', fp); + } else { + fwrite(pfx, pfxlen, 1, fp); + fputs(name, fp); + } + fputc(terminator, fp); } /* * C-style name unquoting. * - * 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; + + 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; - 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 */ + 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); - } -} - -void write_name_quoted(const char *prefix, int prefix_len, - const char *name, int quote, FILE *out) -{ - int needquote; - - if (!quote) { - no_quote: - if (prefix_len) - fprintf(out, "%.*s", prefix_len, prefix); - fputs(name, out); - return; - } - - needquote = 0; - if (prefix_len) - needquote = quote_c_style_counted(prefix, prefix_len, - NULL, NULL, 0); - if (!needquote) - needquote = quote_c_style(name, NULL, NULL, 0); - if (needquote) { - fputc('"', out); - if (prefix_len) - quote_c_style_counted(prefix, prefix_len, - NULL, out, 1); - quote_c_style(name, NULL, out, 1); - fputc('"', out); - } - else - goto no_quote; + error: + strbuf_setlen(sb, oldlen); + return -1; } /* quoting as a string literal for other languages */ @@ -29,13 +29,10 @@ */ extern void sq_quote_print(FILE *stream, const char *src); -extern char *sq_quote_argv(const char** argv, int count); -/* - * Append a string to a string buffer, with or without shell quoting. - * Return true if the buffer overflowed. - */ -extern int add_to_string(char **ptrp, int *sizep, const char *str, int quote); +extern void sq_quote_buf(struct strbuf *, const char *src); +extern void sq_quote_argv(struct strbuf *, const char **argv, int count, + size_t maxlen); /* This unwraps what sq_quote() produces in place, but returns * NULL if the input does not look like what sq_quote would have @@ -43,12 +40,12 @@ extern int add_to_string(char **ptrp, int *sizep, const char *str, int quote); */ extern char *sq_dequote(char *); -extern 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 int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); +extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq); -extern void write_name_quoted(const char *prefix, int prefix_len, - const char *name, int quote, FILE *out); +extern void write_name_quoted(const char *name, FILE *, int terminator); +extern void write_name_quotedpfx(const char *pfx, size_t pfxlen, + const char *name, FILE *, int terminator); /* quoting as a string literal for other languages */ extern void perl_quote_print(FILE *stream, const char *src); diff --git a/read-cache.c b/read-cache.c index 2e40a3442..56202d13d 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1136,7 +1136,7 @@ int write_index(struct index_state *istate, int newfd) { SHA_CTX c; struct cache_header hdr; - int i, removed; + int i, err, removed; struct cache_entry **cache = istate->cache; int entries = istate->cache_nr; @@ -1165,16 +1165,15 @@ int write_index(struct index_state *istate, int newfd) /* Write extension data here */ if (istate->cache_tree) { - unsigned long sz; - void *data = cache_tree_write(istate->cache_tree, &sz); - if (data && - !write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) && - !ce_write(&c, newfd, data, sz)) - free(data); - else { - free(data); + struct strbuf sb; + + strbuf_init(&sb, 0); + cache_tree_write(&sb, istate->cache_tree); + err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0 + || ce_write(&c, newfd, sb.buf, sb.len) < 0; + strbuf_release(&sb); + if (err) return -1; - } } return ce_flush(&c, newfd); } @@ -10,12 +10,9 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, char *host; char *path; int sv[2]; - char command[COMMAND_SIZE]; - char *posn; - int sizen; - int of; int i; pid_t pid; + struct strbuf cmd; if (!strcmp(url, "-")) { *fd_in = 0; @@ -36,24 +33,23 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, if (!path) { return error("Bad URL: %s", url); } + /* $GIT_RSH <host> "env GIT_DIR=<path> <remote_prog> <args...>" */ - sizen = COMMAND_SIZE; - posn = command; - of = 0; - of |= add_to_string(&posn, &sizen, "env ", 0); - of |= add_to_string(&posn, &sizen, GIT_DIR_ENVIRONMENT "=", 0); - of |= add_to_string(&posn, &sizen, path, 1); - of |= add_to_string(&posn, &sizen, " ", 0); - of |= add_to_string(&posn, &sizen, remote_prog, 1); + strbuf_init(&cmd, COMMAND_SIZE); + strbuf_addstr(&cmd, "env "); + strbuf_addstr(&cmd, GIT_DIR_ENVIRONMENT "="); + sq_quote_buf(&cmd, path); + strbuf_addch(&cmd, ' '); + sq_quote_buf(&cmd, remote_prog); - for ( i = 0 ; i < rmt_argc ; i++ ) { - of |= add_to_string(&posn, &sizen, " ", 0); - of |= add_to_string(&posn, &sizen, rmt_argv[i], 1); + for (i = 0 ; i < rmt_argc ; i++) { + strbuf_addch(&cmd, ' '); + sq_quote_buf(&cmd, rmt_argv[i]); } - of |= add_to_string(&posn, &sizen, " -", 0); + strbuf_addstr(&cmd, " -"); - if ( of ) + if (cmd.len >= COMMAND_SIZE) return error("Command line too long"); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) @@ -74,7 +70,7 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, close(sv[1]); dup2(sv[0], 0); dup2(sv[0], 1); - execlp(ssh, ssh_basename, host, command, NULL); + execlp(ssh, ssh_basename, host, cmd.buf, NULL); } close(sv[0]); *fd_in = sv[1]; @@ -50,14 +50,16 @@ void strbuf_rtrim(struct strbuf *sb) sb->buf[sb->len] = '\0'; } -void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) +int strbuf_cmp(struct strbuf *a, struct strbuf *b) { - 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); + int cmp; + if (a->len < b->len) { + cmp = memcmp(a->buf, b->buf, a->len); + return cmp ? cmp : -1; + } else { + cmp = memcmp(a->buf, b->buf, b->len); + return cmp ? cmp : a->len != b->len; + } } void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, @@ -79,6 +81,16 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, strbuf_setlen(sb, sb->len + dlen - len); } +void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) +{ + strbuf_splice(sb, pos, 0, data, len); +} + +void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) +{ + strbuf_splice(sb, pos, len, NULL, 0); +} + void strbuf_add(struct strbuf *sb, const void *data, size_t len) { strbuf_grow(sb, len); @@ -165,3 +177,18 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term) sb->buf[sb->len] = '\0'; return 0; } + +int strbuf_read_file(struct strbuf *sb, const char *path) +{ + int fd, len; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + len = strbuf_read(sb, fd, 0); + close(fd); + if (len < 0) + return -1; + + return len; +} @@ -55,21 +55,30 @@ 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); +static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) { + struct strbuf tmp = *a; + *a = *b; + *b = tmp; +} /*----- strbuf size related -----*/ static inline size_t strbuf_avail(struct strbuf *sb) { - return sb->alloc ? sb->alloc - sb->len - 1 : 0; -} -static inline void strbuf_setlen(struct strbuf *sb, size_t len) { - assert (len < sb->alloc); - sb->len = len; - sb->buf[len] = '\0'; + return sb->alloc ? sb->alloc - sb->len - 1 : 0; } extern void strbuf_grow(struct strbuf *, size_t); +static inline void strbuf_setlen(struct strbuf *sb, size_t len) { + if (!sb->alloc) + strbuf_grow(sb, 0); + assert(len < sb->alloc); + sb->len = len; + sb->buf[len] = '\0'; +} + /*----- content related -----*/ extern void strbuf_rtrim(struct strbuf *); +extern int strbuf_cmp(struct strbuf *, struct strbuf *); /*----- add data in your buffer -----*/ static inline void strbuf_addch(struct strbuf *sb, int c) { @@ -78,12 +87,12 @@ 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_remove(struct strbuf *, size_t pos, size_t len); /* splice pos..pos+len with given data */ extern void strbuf_splice(struct strbuf *, size_t pos, size_t len, - const void *, size_t); + 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) { @@ -99,7 +108,10 @@ extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); /* XXX: if read fails, any partial read is undone */ extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); +extern int strbuf_read_file(struct strbuf *sb, const char *path); extern int strbuf_getline(struct strbuf *, FILE *, int); +extern void stripspace(struct strbuf *buf, int skip_comments); + #endif /* STRBUF_H */ @@ -25,33 +25,6 @@ #include "cache.h" #include "quote.h" -/* Stolen from "imap-send.c". */ -int nfvasprintf(char **strp, const char *fmt, va_list ap) -{ - int len; - char tmp[1024]; - - if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 || - !(*strp = xmalloc(len + 1))) - die("Fatal: Out of memory\n"); - if (len >= (int)sizeof(tmp)) - vsprintf(*strp, fmt, ap); - else - memcpy(*strp, tmp, len + 1); - return len; -} - -int nfasprintf(char **str, const char *fmt, ...) -{ - int rc; - va_list args; - - va_start(args, fmt); - rc = nfvasprintf(str, fmt, args); - va_end(args); - return rc; -} - /* Get a trace file descriptor from GIT_TRACE env variable. */ static int get_trace_fd(int *need_close) { @@ -89,63 +62,65 @@ static int get_trace_fd(int *need_close) static const char err_msg[] = "Could not trace into fd given by " "GIT_TRACE environment variable"; -void trace_printf(const char *format, ...) +void trace_printf(const char *fmt, ...) { - char *trace_str; - va_list rest; - int need_close = 0; - int fd = get_trace_fd(&need_close); + struct strbuf buf; + va_list ap; + int fd, len, need_close = 0; + fd = get_trace_fd(&need_close); if (!fd) return; - va_start(rest, format); - nfvasprintf(&trace_str, format, rest); - va_end(rest); - - write_or_whine_pipe(fd, trace_str, strlen(trace_str), err_msg); + strbuf_init(&buf, 0); + va_start(ap, fmt); + len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); + va_end(ap); + if (len >= strbuf_avail(&buf)) { + strbuf_grow(&buf, len - strbuf_avail(&buf) + 128); + va_start(ap, fmt); + len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); + va_end(ap); + if (len >= strbuf_avail(&buf)) + die("broken vsnprintf"); + } + strbuf_setlen(&buf, len); - free(trace_str); + write_or_whine_pipe(fd, buf.buf, buf.len, err_msg); + strbuf_release(&buf); if (need_close) close(fd); } -void trace_argv_printf(const char **argv, int count, const char *format, ...) +void trace_argv_printf(const char **argv, int count, const char *fmt, ...) { - char *argv_str, *format_str, *trace_str; - size_t argv_len, format_len, trace_len; - va_list rest; - int need_close = 0; - int fd = get_trace_fd(&need_close); + struct strbuf buf; + va_list ap; + int fd, len, need_close = 0; + fd = get_trace_fd(&need_close); if (!fd) return; - /* Get the argv string. */ - argv_str = sq_quote_argv(argv, count); - argv_len = strlen(argv_str); - - /* Get the formated string. */ - va_start(rest, format); - nfvasprintf(&format_str, format, rest); - va_end(rest); - - /* Allocate buffer for trace string. */ - format_len = strlen(format_str); - trace_len = argv_len + format_len + 1; /* + 1 for \n */ - trace_str = xmalloc(trace_len + 1); - - /* Copy everything into the trace string. */ - strncpy(trace_str, format_str, format_len); - strncpy(trace_str + format_len, argv_str, argv_len); - strcpy(trace_str + trace_len - 1, "\n"); - - write_or_whine_pipe(fd, trace_str, trace_len, err_msg); + strbuf_init(&buf, 0); + va_start(ap, fmt); + len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); + va_end(ap); + if (len >= strbuf_avail(&buf)) { + strbuf_grow(&buf, len - strbuf_avail(&buf) + 128); + va_start(ap, fmt); + len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); + va_end(ap); + if (len >= strbuf_avail(&buf)) + die("broken vsnprintf"); + } + strbuf_setlen(&buf, len); - free(argv_str); - free(format_str); - free(trace_str); + sq_quote_argv(&buf, argv, count, 0); + strbuf_addch(&buf, '\n'); + write_or_whine_pipe(fd, buf.buf, buf.len, err_msg); + strbuf_release(&buf); if (need_close) close(fd); |