Merge branch 'rs/simplify-archive-tests'
authorJunio C Hamano <gitster@pobox.com>
Thu, 10 Jul 2014 18:27:53 +0000 (11:27 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 10 Jul 2014 18:27:54 +0000 (11:27 -0700)
* rs/simplify-archive-tests:
t5000, t5003: simplify commit

78 files changed:
Documentation/RelNotes/2.1.0.txt
Documentation/git-verify-commit.txt [new file with mode: 0644]
Makefile
advice.c
alias.c
branch.c
builtin.h
builtin/apply.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/diff-tree.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/log.c
builtin/merge.c
builtin/name-rev.c
builtin/push.c
builtin/receive-pack.c
builtin/remote.c
builtin/show-branch.c
builtin/verify-commit.c [new file with mode: 0644]
cache.h
column.c
command-list.txt
commit.c
compat/mingw.c
compat/mingw.h
compat/win32/dirent.c
compat/win32/dirent.h
compat/winansi.c
config.c
config.mak.uname
connect.c
convert.c
credential-cache--daemon.c
credential.c
daemon.c
diff.c
environment.c
fast-import.c
fetch-pack.c
fsck.c
git-compat-util.h
git.c
gpg-interface.c
gpg-interface.h
help.c
http-backend.c
http-push.c
http-walker.c
http.c
imap-send.c
line-log.c
match-trees.c
merge-recursive.c
merge.c
parse-options.c
preload-index.c
pretty.c
remote-curl.c
remote.c
sequencer.c
sha1_file.c
sha1_name.c
shell.c
strbuf.c
strbuf.h
symlinks.c
t/t6006-rev-list-format.sh
t/t7510-signed-commit.sh
transport-helper.c
transport.c
unpack-trees.c
urlmatch.c
walker.c
wt-status.c
index 828a439dc11e85fc5a7dbf57a4b602efa356e7b6..dbbbc868332e78ac4954c8d297ed13059da3645b 100644 (file)
@@ -111,6 +111,9 @@ Performance, Internal Implementation, etc.
 
  * Build procedure for 'subtree' (in contrib/) has been cleaned up.
 
+ * Patches maintained by msysgit folks for Windows port are being
+   upstreamed here a bit by bit.
+
  * The `core.deltabasecachelimit` used to default to 16 MiB , but this
    proved to be too small, and has been bumped to 96 MiB.
 
@@ -173,6 +176,17 @@ notes for details).
    columns are different.
    (merge 7d50987 as/pretty-truncate later to maint).
 
+ * "%G" (nothing after G) is an invalid pretty format specifier, but
+   the parser did not notice it as garbage.
+   (merge 958b2eb jk/pretty-G-format-fixes later to maint).
+
+ * A handful of code paths had to read the commit object more than
+   once when showing header fields that are usually not parsed.  The
+   internal data structure to keep track of the contents of the commit
+   object has been updated to reduce the need for this double-reading,
+   and to allow the caller find the length of the object.
+   (merge 218aa3a jk/commit-buffer-length later to maint).
+
  * The "mailmap.file" configuration option did not support the tilde
    expansion (i.e. ~user/path and ~/path).
    (merge 9352fd5 ow/config-mailmap-pathname later to maint).
@@ -270,6 +284,10 @@ notes for details).
    emptying the insn sheet.
    (merge ddb5432 rr/rebase-autostash-fix later to maint).
 
+ * During "git rebase --merge", a conflicted patch could not be
+   skipped with "--skip" if the next one also conflicted.
+   (merge 95104c7 bc/fix-rebase-merge-skip later to maint).
+
  * "git show -s" (i.e. show log message only) used to incorrectly emit
    an extra blank line after a merge commit.
    (merge ad2f725 mk/show-s-no-extra-blank-line-for-merges later to maint).
diff --git a/Documentation/git-verify-commit.txt b/Documentation/git-verify-commit.txt
new file mode 100644 (file)
index 0000000..9413e28
--- /dev/null
@@ -0,0 +1,28 @@
+git-verify-commit(1)
+====================
+
+NAME
+----
+git-verify-commit - Check the GPG signature of commits
+
+SYNOPSIS
+--------
+[verse]
+'git verify-commit' <commit>...
+
+DESCRIPTION
+-----------
+Validates the gpg signature created by 'git commit -S'.
+
+OPTIONS
+-------
+-v::
+--verbose::
+       Print the contents of the commit object before validating it.
+
+<commit>...::
+       SHA-1 identifiers of Git commit objects.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 07ea1058379ab963648d0df7fd2917e0d2efa8a7..b92418de7bc743a70f6113cb2af39c74a3cb312c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -999,6 +999,7 @@ BUILTIN_OBJS += builtin/update-ref.o
 BUILTIN_OBJS += builtin/update-server-info.o
 BUILTIN_OBJS += builtin/upload-archive.o
 BUILTIN_OBJS += builtin/var.o
+BUILTIN_OBJS += builtin/verify-commit.o
 BUILTIN_OBJS += builtin/verify-pack.o
 BUILTIN_OBJS += builtin/verify-tag.o
 BUILTIN_OBJS += builtin/write-tree.o
index c50ebdf5fe82d88b901ca26668806c94e03fbb37..9b420331926c6bf1aa371f973d6a96886f419b06 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -61,9 +61,12 @@ void advise(const char *advice, ...)
 
 int git_default_advice_config(const char *var, const char *value)
 {
-       const char *k = skip_prefix(var, "advice.");
+       const char *k;
        int i;
 
+       if (!skip_prefix(var, "advice.", &k))
+               return 0;
+
        for (i = 0; i < ARRAY_SIZE(advice_config); i++) {
                if (strcmp(k, advice_config[i].name))
                        continue;
diff --git a/alias.c b/alias.c
index 5efc3d69866731d0f56464c522b00f253f84c187..758c8671494ad003a6e7e33f8a14b5450311bf54 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -5,7 +5,8 @@ static char *alias_val;
 
 static int alias_lookup_cb(const char *k, const char *v, void *cb)
 {
-       if (starts_with(k, "alias.") && !strcmp(k + 6, alias_key)) {
+       const char *name;
+       if (skip_prefix(k, "alias.", &name) && !strcmp(name, alias_key)) {
                if (!v)
                        return config_error_nonbool(k);
                alias_val = xstrdup(v);
index 660097bc29a682c4481308ba245e5e02f0661681..46e8aa86df1811ff19899869a33ecb48cacb107f 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -50,11 +50,11 @@ static int should_setup_rebase(const char *origin)
 
 void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
 {
-       const char *shortname = skip_prefix(remote, "refs/heads/");
+       const char *shortname = NULL;
        struct strbuf key = STRBUF_INIT;
        int rebasing = should_setup_rebase(origin);
 
-       if (shortname
+       if (skip_prefix(remote, "refs/heads/", &shortname)
            && !strcmp(local, shortname)
            && !origin) {
                warning(_("Not setting branch %s as its own upstream."),
index c47c110e0f18f3183d54c9afb63cffef686a21db..5d91f31ca25e0c16fca0e8c23d83706840bf6c57 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -128,6 +128,7 @@ extern int cmd_update_server_info(int argc, const char **argv, const char *prefi
 extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
 extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix);
 extern int cmd_var(int argc, const char **argv, const char *prefix);
+extern int cmd_verify_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
 extern int cmd_version(int argc, const char **argv, const char *prefix);
 extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
index 9c5724eaccfaee62ff10eb097adc39ace351cade..16cc93587fd78f620bdcc0d0841ca98ac3394d9e 100644 (file)
@@ -1281,9 +1281,7 @@ static int parse_git_header(const char *line, int len, unsigned int size, struct
         */
        patch->def_name = git_header_name(line, len);
        if (patch->def_name && root) {
-               char *s = xmalloc(root_len + strlen(patch->def_name) + 1);
-               strcpy(s, root);
-               strcpy(s + root_len, patch->def_name);
+               char *s = xstrfmt("%s%s", root, patch->def_name);
                free(patch->def_name);
                patch->def_name = s;
        }
@@ -3847,9 +3845,10 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = namelen;
        if (S_ISGITLINK(mode)) {
-               const char *s = buf;
+               const char *s;
 
-               if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
+               if (!skip_prefix(buf, "Subproject commit ", &s) ||
+                   get_sha1_hex(s, ce->sha1))
                        die(_("corrupt patch for submodule %s"), path);
        } else {
                if (!cached) {
index 652b1d2d1484032fab51165f1d0b0a41426d114f..0591b22a483619ac9a7d889a49e45ffa9d68ab72 100644 (file)
@@ -294,13 +294,13 @@ static char *resolve_symref(const char *src, const char *prefix)
 {
        unsigned char sha1[20];
        int flag;
-       const char *dst, *cp;
+       const char *dst;
 
        dst = resolve_ref_unsafe(src, sha1, 0, &flag);
        if (!(dst && (flag & REF_ISSYMREF)))
                return NULL;
-       if (prefix && (cp = skip_prefix(dst, prefix)))
-               dst = cp;
+       if (prefix)
+               skip_prefix(dst, prefix, &dst);
        return xstrdup(dst);
 }
 
index f1dc56e55f7b2200412142b10517458ccfda2952..463cfeea5067fe02d8eb1414018c97ff9a757176 100644 (file)
@@ -776,8 +776,8 @@ static int switch_branches(const struct checkout_opts *opts,
        if (!(flag & REF_ISSYMREF))
                old.path = NULL;
 
-       if (old.path && starts_with(old.path, "refs/heads/"))
-               old.name = old.path + strlen("refs/heads/");
+       if (old.path)
+               skip_prefix(old.path, "refs/heads/", &old.name);
 
        if (!new->name) {
                new->name = "HEAD";
index b12989d1caecb48128e8a468014f07b237b1a4cc..e15ca332b5637421fb187ce4db478c60dded958c 100644 (file)
@@ -584,11 +584,11 @@ static void update_remote_refs(const struct ref *refs,
 static void update_head(const struct ref *our, const struct ref *remote,
                        const char *msg)
 {
-       if (our && starts_with(our->name, "refs/heads/")) {
+       const char *head;
+       if (our && skip_prefix(our->name, "refs/heads/", &head)) {
                /* Local default branch link */
                create_symref("HEAD", our->name, NULL);
                if (!option_bare) {
-                       const char *head = skip_prefix(our->name, "refs/heads/");
                        update_ref(msg, "HEAD", our->old_sha1, NULL, 0,
                                   UPDATE_REFS_DIE_ON_ERR);
                        install_branch_config(0, head, option_origin, our->name);
@@ -696,16 +696,19 @@ static void write_refspec_config(const char* src_ref_prefix,
        if (option_mirror || !option_bare) {
                if (option_single_branch && !option_mirror) {
                        if (option_branch) {
-                               if (strstr(our_head_points_at->name, "refs/tags/"))
+                               if (starts_with(our_head_points_at->name, "refs/tags/"))
                                        strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
                                                our_head_points_at->name);
                                else
                                        strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
                                                branch_top->buf, option_branch);
                        } else if (remote_head_points_at) {
+                               const char *head = remote_head_points_at->name;
+                               if (!skip_prefix(head, "refs/heads/", &head))
+                                       die("BUG: remote HEAD points at non-head?");
+
                                strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
-                                               branch_top->buf,
-                                               skip_prefix(remote_head_points_at->name, "refs/heads/"));
+                                               branch_top->buf, head);
                        }
                        /*
                         * otherwise, the next "git fetch" will
index 84cec9a715341fedeabfaedfd82bbb64a4c3c255..461c3b1cade4a995d3eb3cc212645791245865e0 100644 (file)
@@ -1020,7 +1020,7 @@ static int message_is_empty(struct strbuf *sb)
 static int template_untouched(struct strbuf *sb)
 {
        struct strbuf tmpl = STRBUF_INIT;
-       char *start;
+       const char *start;
 
        if (cleanup_mode == CLEANUP_NONE && sb->len)
                return 0;
@@ -1029,8 +1029,7 @@ static int template_untouched(struct strbuf *sb)
                return 0;
 
        stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
-       start = (char *)skip_prefix(sb->buf, tmpl.buf);
-       if (!start)
+       if (!skip_prefix(sb->buf, tmpl.buf, &start))
                start = sb->buf;
        strbuf_release(&tmpl);
        return rest_is_empty(sb, start - sb->buf);
index be6417d166abf428d379a70b9d67f894da4641d1..ce0e019e0caa358e1f5e39e5ed51bec3945197e0 100644 (file)
@@ -22,14 +22,10 @@ static int stdin_diff_commit(struct commit *commit, char *line, int len)
        if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) {
                /* Graft the fake parents locally to the commit */
                int pos = 41;
-               struct commit_list **pptr, *parents;
+               struct commit_list **pptr;
 
                /* Free the real parent list */
-               for (parents = commit->parents; parents; ) {
-                       struct commit_list *tmp = parents->next;
-                       free(parents);
-                       parents = tmp;
-               }
+               free_commit_list(commit->parents);
                commit->parents = NULL;
                pptr = &(commit->parents);
                while (line[pos] && !get_sha1_hex(line + pos, sha1)) {
index dd46b61d9a31475e3d5289e41e6d7f57a0264b6f..e8d0cca3e4110e1ae6db82f21c899c44460cb849 100644 (file)
@@ -1082,16 +1082,11 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)
                refs = xcalloc(argc + 1, sizeof(const char *));
                for (i = 0; i < argc; i++) {
                        if (!strcmp(argv[i], "tag")) {
-                               char *ref;
                                i++;
                                if (i >= argc)
                                        die(_("You need to specify a tag name."));
-                               ref = xmalloc(strlen(argv[i]) * 2 + 22);
-                               strcpy(ref, "refs/tags/");
-                               strcat(ref, argv[i]);
-                               strcat(ref, ":refs/tags/");
-                               strcat(ref, argv[i]);
-                               refs[j++] = ref;
+                               refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s",
+                                                   argv[i], argv[i]);
                        } else
                                refs[j++] = argv[i];
                }
index ef8b254ef218249f7f1b0f28db7ea21110851917..79df05ef526bcd1a3be2971c9d467a930001639d 100644 (file)
@@ -100,7 +100,8 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
 {
        int i, len = strlen(line);
        struct origin_data *origin_data;
-       char *src, *origin;
+       char *src;
+       const char *origin;
        struct src_data *src_data;
        struct string_list_item *item;
        int pulling_head = 0;
@@ -164,8 +165,7 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
                origin = line;
                string_list_append(&src_data->tag, origin + 4);
                src_data->head_status |= 2;
-       } else if (starts_with(line, "remote-tracking branch ")) {
-               origin = line + strlen("remote-tracking branch ");
+       } else if (skip_prefix(line, "remote-tracking branch ", &origin)) {
                string_list_append(&src_data->r_branch, origin);
                src_data->head_status |= 2;
        } else {
@@ -178,11 +178,8 @@ static int handle_line(char *line, struct merge_parents *merge_parents)
                int len = strlen(origin);
                if (origin[0] == '\'' && origin[len - 1] == '\'')
                        origin = xmemdupz(origin + 1, len - 2);
-       } else {
-               char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
-               sprintf(new_origin, "%s of %s", origin, src);
-               origin = new_origin;
-       }
+       } else
+               origin = xstrfmt("%s of %s", origin, src);
        if (strcmp(".", src))
                origin_data->is_local_branch = 0;
        string_list_append(&origins, origin)->util = origin_data;
@@ -300,8 +297,8 @@ static void credit_people(struct strbuf *out,
        if (!them->nr ||
            (them->nr == 1 &&
             me &&
-            (me = skip_prefix(me, them->items->string)) != NULL &&
-            skip_prefix(me, " <")))
+            skip_prefix(me, them->items->string, &me) &&
+            starts_with(me, " <")))
                return;
        strbuf_addf(out, "\n%c %s ", comment_line_char, label);
        add_people_count(out, them);
index 92063dfc48a73c9b5fa4f9694dd4ac78d5575be3..27c1b65db46bb1bead9045b7b6be08a1ee199835 100644 (file)
@@ -871,7 +871,7 @@ static char *find_branch_name(struct rev_info *rev)
        int i, positive = -1;
        unsigned char branch_sha1[20];
        const unsigned char *tip_sha1;
-       const char *ref;
+       const char *ref, *v;
        char *full_ref, *branch = NULL;
 
        for (i = 0; i < rev->cmdline.nr; i++) {
@@ -887,9 +887,9 @@ static char *find_branch_name(struct rev_info *rev)
        ref = rev->cmdline.rev[positive].name;
        tip_sha1 = rev->cmdline.rev[positive].item->sha1;
        if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
-           starts_with(full_ref, "refs/heads/") &&
+           skip_prefix(full_ref, "refs/heads/", &v) &&
            !hashcmp(tip_sha1, branch_sha1))
-               branch = xstrdup(full_ref + strlen("refs/heads/"));
+               branch = xstrdup(v);
        free(full_ref);
        return branch;
 }
@@ -1396,10 +1396,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 
                if (check_head) {
                        unsigned char sha1[20];
-                       const char *ref;
+                       const char *ref, *v;
                        ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
-                       if (ref && starts_with(ref, "refs/heads/"))
-                               branch_name = xstrdup(ref + strlen("refs/heads/"));
+                       if (ref && skip_prefix(ref, "refs/heads/", &v))
+                               branch_name = xstrdup(v);
                        else
                                branch_name = xstrdup(""); /* no branch */
                }
index b49c310866f76434c3838484c0bf997a1230c7ed..86e9c61277990e2999d678af95824d5aec0b3df0 100644 (file)
@@ -1282,10 +1282,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                                printf(_("Commit %s has a good GPG signature by %s\n"),
                                       hex, signature_check.signer);
 
-                       free(signature_check.gpg_output);
-                       free(signature_check.gpg_status);
-                       free(signature_check.signer);
-                       free(signature_check.key);
+                       signature_check_clear(&signature_check);
                }
        }
 
index c824d4ec5f1c076e4833c690dad378125dde6da9..3c8f319be675d14a6ee60d303335190b7bdce9c8 100644 (file)
@@ -33,10 +33,7 @@ static void name_rev(struct commit *commit,
                return;
 
        if (deref) {
-               char *new_name = xmalloc(strlen(tip_name)+3);
-               strcpy(new_name, tip_name);
-               strcat(new_name, "^0");
-               tip_name = new_name;
+               tip_name = xstrfmt("%s^0", tip_name);
 
                if (generation)
                        die("generation: %d, but deref?", generation);
index f8dfea41e1ad8b6d888c1a2adc13eee87083491e..f50e3d5e77db6842ff3450560aad330f6a4bd91d 100644 (file)
@@ -127,11 +127,10 @@ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote
         * them the big ugly fully qualified ref.
         */
        const char *advice_maybe = "";
-       const char *short_upstream =
-               skip_prefix(branch->merge[0]->src, "refs/heads/");
+       const char *short_upstream = branch->merge[0]->src;
+
+       skip_prefix(short_upstream, "refs/heads/", &short_upstream);
 
-       if (!short_upstream)
-               short_upstream = branch->merge[0]->src;
        /*
         * Don't show advice for people who explicitly set
         * push.default.
index c3230817db4a7676eb74335b254f30597e66edd9..18458e81c6351d53afe1a50efff183889e5ab81b 100644 (file)
@@ -614,12 +614,9 @@ static void run_update_post_hook(struct command *commands)
        argv[0] = hook;
 
        for (argc = 1, cmd = commands; cmd; cmd = cmd->next) {
-               char *p;
                if (cmd->error_string || cmd->did_not_exist)
                        continue;
-               p = xmalloc(strlen(cmd->ref_name) + 1);
-               strcpy(p, cmd->ref_name);
-               argv[argc] = p;
+               argv[argc] = xstrdup(cmd->ref_name);
                argc++;
        }
        argv[argc] = NULL;
index c9102e8fe94b41af5136a9cc23db939effae147a..a8efe3da4d7dad3b17582c91671f0f475d54a9ac 100644 (file)
@@ -250,9 +250,7 @@ static struct string_list branch_list;
 
 static const char *abbrev_ref(const char *name, const char *prefix)
 {
-       const char *abbrev = skip_prefix(name, prefix);
-       if (abbrev)
-               return abbrev;
+       skip_prefix(name, prefix, &name);
        return name;
 }
 #define abbrev_branch(name) abbrev_ref((name), "refs/heads/")
index d87317290c0bbfffb7ac66fb7cff5c608f092d93..5fd4e4e48839a9dc2998d3fba0e48008b902b12a 100644 (file)
@@ -755,7 +755,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                }
 
                for (i = 0; i < reflog; i++) {
-                       char *logmsg, *m;
+                       char *logmsg;
                        const char *msg;
                        unsigned long timestamp;
                        int tz;
@@ -770,11 +770,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                                msg = "(none)";
                        else
                                msg++;
-                       m = xmalloc(strlen(msg) + 200);
-                       sprintf(m, "(%s) %s",
-                               show_date(timestamp, tz, 1),
-                               msg);
-                       reflog_msg[i] = m;
+                       reflog_msg[i] = xstrfmt("(%s) %s",
+                                               show_date(timestamp, tz, 1),
+                                               msg);
                        free(logmsg);
                        sprintf(nth_desc, "%s@{%d}", *av, base+i);
                        append_ref(nth_desc, sha1, 1);
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
new file mode 100644 (file)
index 0000000..b0f8504
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Builtin "git commit-commit"
+ *
+ * Copyright (c) 2014 Michael J Gruber <git@drmicha.warpmail.net>
+ *
+ * Based on git-verify-tag
+ */
+#include "cache.h"
+#include "builtin.h"
+#include "commit.h"
+#include "run-command.h"
+#include <signal.h>
+#include "parse-options.h"
+#include "gpg-interface.h"
+
+static const char * const verify_commit_usage[] = {
+               N_("git verify-commit [-v|--verbose] <commit>..."),
+               NULL
+};
+
+static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose)
+{
+       struct signature_check signature_check;
+
+       memset(&signature_check, 0, sizeof(signature_check));
+
+       check_commit_signature(lookup_commit(sha1), &signature_check);
+
+       if (verbose && signature_check.payload)
+               fputs(signature_check.payload, stdout);
+
+       if (signature_check.gpg_output)
+               fputs(signature_check.gpg_output, stderr);
+
+       signature_check_clear(&signature_check);
+       return signature_check.result != 'G';
+}
+
+static int verify_commit(const char *name, int verbose)
+{
+       enum object_type type;
+       unsigned char sha1[20];
+       char *buf;
+       unsigned long size;
+       int ret;
+
+       if (get_sha1(name, sha1))
+               return error("commit '%s' not found.", name);
+
+       buf = read_sha1_file(sha1, &type, &size);
+       if (!buf)
+               return error("%s: unable to read file.", name);
+       if (type != OBJ_COMMIT)
+               return error("%s: cannot verify a non-commit object of type %s.",
+                               name, typename(type));
+
+       ret = run_gpg_verify(sha1, buf, size, verbose);
+
+       free(buf);
+       return ret;
+}
+
+static int git_verify_commit_config(const char *var, const char *value, void *cb)
+{
+       int status = git_gpg_config(var, value, cb);
+       if (status)
+               return status;
+       return git_default_config(var, value, cb);
+}
+
+int cmd_verify_commit(int argc, const char **argv, const char *prefix)
+{
+       int i = 1, verbose = 0, had_error = 0;
+       const struct option verify_commit_options[] = {
+               OPT__VERBOSE(&verbose, N_("print commit contents")),
+               OPT_END()
+       };
+
+       git_config(git_verify_commit_config, NULL);
+
+       argc = parse_options(argc, argv, prefix, verify_commit_options,
+                            verify_commit_usage, PARSE_OPT_KEEP_ARGV0);
+       if (argc <= i)
+               usage_with_options(verify_commit_usage, verify_commit_options);
+
+       /* sometimes the program was terminated because this signal
+        * was received in the process of writing the gpg input: */
+       signal(SIGPIPE, SIG_IGN);
+       while (i < argc)
+               if (verify_commit(argv[i++], verbose))
+                       had_error = 1;
+       return had_error;
+}
diff --git a/cache.h b/cache.h
index df65231ac3db7ae08b5d9cfd37c505c4573c1675..44aa43993537f77bf0866b0da7a581d71779e6aa 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1090,12 +1090,16 @@ struct checkout {
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
 
 struct cache_def {
-       char path[PATH_MAX + 1];
-       int len;
+       struct strbuf path;
        int flags;
        int track_flags;
        int prefix_len_stat_func;
 };
+#define CACHE_DEF_INIT { STRBUF_INIT, 0, 0, 0 }
+static inline void cache_def_free(struct cache_def *cache)
+{
+       strbuf_release(&cache->path);
+}
 
 extern int has_symlink_leading_path(const char *name, int len);
 extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
index 1a468debb4abdda3cbb90fcc4972b3d40da6f2ed..ca878bcea7a42476a7c2b03e74897a2af87bec3f 100644 (file)
--- a/column.c
+++ b/column.c
@@ -336,8 +336,9 @@ static int column_config(const char *var, const char *value,
 int git_column_config(const char *var, const char *value,
                      const char *command, unsigned int *colopts)
 {
-       const char *it = skip_prefix(var, "column.");
-       if (!it)
+       const char *it;
+
+       if (!skip_prefix(var, "column.", &it))
                return 0;
 
        if (!strcmp(it, "ui"))
index cf36c3d71e3b8fc3382162ef939f3ed1f7d20775..a3ff0c9e60148e6dc98a6bd0d71d98cba4a7eae2 100644 (file)
@@ -132,6 +132,7 @@ git-update-server-info                  synchingrepositories
 git-upload-archive                      synchelpers
 git-upload-pack                         synchelpers
 git-var                                 plumbinginterrogators
+git-verify-commit                       ancillaryinterrogators
 git-verify-pack                         plumbinginterrogators
 git-verify-tag                          ancillaryinterrogators
 gitweb                                  ancillaryinterrogators
index 4ff8077dbfbc6cdd6c14728a3d33a78d075c236f..acb74b55d4ee72ddf626754535a9febeb05ba945 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -614,8 +614,7 @@ static void record_author_date(struct author_date_slab *author_date,
 
        for (buf = buffer; buf; buf = line_end + 1) {
                line_end = strchrnul(buf, '\n');
-               ident_line = skip_prefix(buf, "author ");
-               if (!ident_line) {
+               if (!skip_prefix(buf, "author ", &ident_line)) {
                        if (!line_end[0] || line_end[1] == '\n')
                                return; /* end of header */
                        continue;
@@ -1237,8 +1236,7 @@ static void parse_gpg_output(struct signature_check *sigc)
        for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
                const char *found, *next;
 
-               found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1);
-               if (!found) {
+               if (!skip_prefix(buf, sigcheck_gpg_status[i].check + 1, &found)) {
                        found = strstr(buf, sigcheck_gpg_status[i].check);
                        if (!found)
                                continue;
@@ -1272,6 +1270,7 @@ void check_commit_signature(const struct commit* commit, struct signature_check
                                      &gpg_output, &gpg_status);
        if (status && !gpg_output.len)
                goto out;
+       sigc->payload = strbuf_detach(&payload, NULL);
        sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
        sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
        parse_gpg_output(sigc);
index a0e13bc862c052d8c18a6cba1c47a5a15fd12f7b..3baaa4dfaedd1e451f810a6bead28b2f7e9aa95d 100644 (file)
@@ -441,7 +441,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
 static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
        int namelen;
-       static char alt_name[PATH_MAX];
+       char alt_name[PATH_MAX];
 
        if (!do_lstat(follow, file_name, buf))
                return 0;
@@ -831,9 +831,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
                              const char *dir,
                              int prepend_cmd, int fhin, int fhout, int fherr)
 {
-       STARTUPINFO si;
+       STARTUPINFOW si;
        PROCESS_INFORMATION pi;
        struct strbuf envblk, args;
+       wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
        unsigned flags;
        BOOL ret;
 
@@ -865,9 +866,14 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
        memset(&si, 0, sizeof(si));
        si.cb = sizeof(si);
        si.dwFlags = STARTF_USESTDHANDLES;
-       si.hStdInput = (HANDLE) _get_osfhandle(fhin);
-       si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
-       si.hStdError = (HANDLE) _get_osfhandle(fherr);
+       si.hStdInput = winansi_get_osfhandle(fhin);
+       si.hStdOutput = winansi_get_osfhandle(fhout);
+       si.hStdError = winansi_get_osfhandle(fherr);
+
+       if (xutftowcs_path(wcmd, cmd) < 0)
+               return -1;
+       if (dir && xutftowcs_path(wdir, dir) < 0)
+               return -1;
 
        /* concatenate argv, quoting args as we go */
        strbuf_init(&args, 0);
@@ -886,6 +892,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
                        free(quoted);
        }
 
+       wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
+       xutftowcs(wargs, args.buf, 2 * args.len + 1);
+       strbuf_release(&args);
+
        if (env) {
                int count = 0;
                char **e, **sorted_env;
@@ -907,12 +917,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
        }
 
        memset(&pi, 0, sizeof(pi));
-       ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
-               env ? envblk.buf : NULL, dir, &si, &pi);
+       ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
+               env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
 
        if (env)
                strbuf_release(&envblk);
-       strbuf_release(&args);
+       free(wargs);
 
        if (!ret) {
                errno = ENOENT;
@@ -941,10 +951,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
        return (pid_t)pi.dwProcessId;
 }
 
-static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
-                          int prepend_cmd)
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
 {
-       return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
+       return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
 }
 
 pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -986,7 +995,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
        return pid;
 }
 
-static int try_shell_exec(const char *cmd, char *const *argv, char **env)
+static int try_shell_exec(const char *cmd, char *const *argv)
 {
        const char *interpr = parse_interpreter(cmd);
        char **path;
@@ -1004,7 +1013,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
                argv2 = xmalloc(sizeof(*argv) * (argc+1));
                argv2[0] = (char *)cmd; /* full path to the script file */
                memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
-               pid = mingw_spawnve(prog, argv2, env, 1);
+               pid = mingw_spawnv(prog, argv2, 1);
                if (pid >= 0) {
                        int status;
                        if (waitpid(pid, &status, 0) < 0)
@@ -1019,19 +1028,20 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
        return pid;
 }
 
-static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
+int mingw_execv(const char *cmd, char *const *argv)
 {
        /* check if git_command is a shell script */
-       if (!try_shell_exec(cmd, argv, (char **)env)) {
+       if (!try_shell_exec(cmd, argv)) {
                int pid, status;
 
-               pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
+               pid = mingw_spawnv(cmd, (const char **)argv, 0);
                if (pid < 0)
-                       return;
+                       return -1;
                if (waitpid(pid, &status, 0) < 0)
                        status = 255;
                exit(status);
        }
+       return -1;
 }
 
 int mingw_execvp(const char *cmd, char *const *argv)
@@ -1040,7 +1050,7 @@ int mingw_execvp(const char *cmd, char *const *argv)
        char *prog = path_lookup(cmd, path, 0);
 
        if (prog) {
-               mingw_execve(prog, argv, environ);
+               mingw_execv(prog, argv);
                free(prog);
        } else
                errno = ENOENT;
@@ -1049,12 +1059,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
        return -1;
 }
 
-int mingw_execv(const char *cmd, char *const *argv)
-{
-       mingw_execve(cmd, argv, environ);
-       return -1;
-}
-
 int mingw_kill(pid_t pid, int sig)
 {
        if (pid > 0 && sig == SIGTERM) {
@@ -1847,3 +1851,150 @@ int mingw_offset_1st_component(const char *path)
 
        return offset + is_dir_sep(path[offset]);
 }
+
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+       int upos = 0, wpos = 0;
+       const unsigned char *utf = (const unsigned char*) utfs;
+       if (!utf || !wcs || wcslen < 1) {
+               errno = EINVAL;
+               return -1;
+       }
+       /* reserve space for \0 */
+       wcslen--;
+       if (utflen < 0)
+               utflen = INT_MAX;
+
+       while (upos < utflen) {
+               int c = utf[upos++] & 0xff;
+               if (utflen == INT_MAX && c == 0)
+                       break;
+
+               if (wpos >= wcslen) {
+                       wcs[wpos] = 0;
+                       errno = ERANGE;
+                       return -1;
+               }
+
+               if (c < 0x80) {
+                       /* ASCII */
+                       wcs[wpos++] = c;
+               } else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+                               (utf[upos] & 0xc0) == 0x80) {
+                       /* 2-byte utf-8 */
+                       c = ((c & 0x1f) << 6);
+                       c |= (utf[upos++] & 0x3f);
+                       wcs[wpos++] = c;
+               } else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+                               !(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+                               (utf[upos] & 0xc0) == 0x80 &&
+                               (utf[upos + 1] & 0xc0) == 0x80) {
+                       /* 3-byte utf-8 */
+                       c = ((c & 0x0f) << 12);
+                       c |= ((utf[upos++] & 0x3f) << 6);
+                       c |= (utf[upos++] & 0x3f);
+                       wcs[wpos++] = c;
+               } else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+                               wpos + 1 < wcslen &&
+                               !(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+                               !(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+                               (utf[upos] & 0xc0) == 0x80 &&
+                               (utf[upos + 1] & 0xc0) == 0x80 &&
+                               (utf[upos + 2] & 0xc0) == 0x80) {
+                       /* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+                       c = ((c & 0x07) << 18);
+                       c |= ((utf[upos++] & 0x3f) << 12);
+                       c |= ((utf[upos++] & 0x3f) << 6);
+                       c |= (utf[upos++] & 0x3f);
+                       c -= 0x10000;
+                       wcs[wpos++] = 0xd800 | (c >> 10);
+                       wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+               } else if (c >= 0xa0) {
+                       /* invalid utf-8 byte, printable unicode char: convert 1:1 */
+                       wcs[wpos++] = c;
+               } else {
+                       /* invalid utf-8 byte, non-printable unicode: convert to hex */
+                       static const char *hex = "0123456789abcdef";
+                       wcs[wpos++] = hex[c >> 4];
+                       if (wpos < wcslen)
+                               wcs[wpos++] = hex[c & 0x0f];
+               }
+       }
+       wcs[wpos] = 0;
+       return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+       if (!wcs || !utf || utflen < 1) {
+               errno = EINVAL;
+               return -1;
+       }
+       utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+       if (utflen)
+               return utflen - 1;
+       errno = ERANGE;
+       return -1;
+}
+
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+
+typedef struct {
+       int newmode;
+} _startupinfo;
+
+extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
+               _startupinfo *si);
+
+static NORETURN void die_startup()
+{
+       fputs("fatal: not enough memory for initialization", stderr);
+       exit(128);
+}
+
+void mingw_startup()
+{
+       int i, len, maxlen, argc;
+       char *buffer;
+       wchar_t **wenv, **wargv;
+       _startupinfo si;
+
+       /* get wide char arguments and environment */
+       si.newmode = 0;
+       if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
+               die_startup();
+
+       /* determine size of argv and environ conversion buffer */
+       maxlen = wcslen(_wpgmptr);
+       for (i = 1; i < argc; i++)
+               maxlen = max(maxlen, wcslen(wargv[i]));
+
+       /* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+       maxlen = 3 * maxlen + 1;
+       buffer = xmalloc(maxlen);
+
+       /* convert command line arguments and environment to UTF-8 */
+       len = xwcstoutf(buffer, _wpgmptr, maxlen);
+       __argv[0] = xmemdupz(buffer, len);
+       for (i = 1; i < argc; i++) {
+               len = xwcstoutf(buffer, wargv[i], maxlen);
+               __argv[i] = xmemdupz(buffer, len);
+       }
+       free(buffer);
+
+       /* initialize critical section for waitpid pinfo_t list */
+       InitializeCriticalSection(&pinfo_cs);
+
+       /* set up default file mode and file modes for stdin/out/err */
+       _fmode = _O_BINARY;
+       _setmode(_fileno(stdin), _O_BINARY);
+       _setmode(_fileno(stdout), _O_BINARY);
+       _setmode(_fileno(stderr), _O_BINARY);
+
+       /* initialize Unicode console */
+       winansi_init();
+}
index 3eaf822e28e23e6e46e82a9bb7c9db1ed42d252c..8dac6f9d6bc91c7949533d5d6d987530d6993b01 100644 (file)
@@ -317,12 +317,8 @@ int mingw_raise(int sig);
  * ANSI emulation wrappers
  */
 
-int winansi_fputs(const char *str, FILE *stream);
-int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
-int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
-#define fputs winansi_fputs
-#define printf(...) winansi_printf(__VA_ARGS__)
-#define fprintf(...) winansi_fprintf(__VA_ARGS__)
+void winansi_init(void);
+HANDLE winansi_get_osfhandle(int fd);
 
 /*
  * git specific compatibility
@@ -355,6 +351,110 @@ void mingw_open_html(const char *path);
 char **make_augmented_environ(const char *const *vars);
 void free_environ(char **env);
 
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+       return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+       int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+       if (result < 0 && errno == ERANGE)
+               errno = ENAMETOOLONG;
+       return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
 /*
  * A critical section used in the implementation of the spawn
  * functions (mingw_spawnv[p]e()) and waitpid(). Intialised in
@@ -363,22 +463,16 @@ void free_environ(char **env);
 extern CRITICAL_SECTION pinfo_cs;
 
 /*
- * A replacement of main() that ensures that argv[0] has a path
- * and that default fmode and std(in|out|err) are in binary mode
+ * A replacement of main() that adds win32 specific initialization.
  */
 
+void mingw_startup();
 #define main(c,v) dummy_decl_mingw_main(); \
 static int mingw_main(c,v); \
 int main(int argc, char **argv) \
 { \
-       extern CRITICAL_SECTION pinfo_cs; \
-       _fmode = _O_BINARY; \
-       _setmode(_fileno(stdin), _O_BINARY); \
-       _setmode(_fileno(stdout), _O_BINARY); \
-       _setmode(_fileno(stderr), _O_BINARY); \
-       argv[0] = xstrdup(_pgmptr); \
-       InitializeCriticalSection(&pinfo_cs); \
-       return mingw_main(argc, argv); \
+       mingw_startup(); \
+       return mingw_main(__argc, (void *)__argv); \
 } \
 static int mingw_main(c,v)
 
index 7a0debe51bcad9f8d46c9c675aa3a6bbaaf7f537..82a515c21b322a0e50c7b5dbdd12e74341b20e98 100644 (file)
@@ -1,96 +1,91 @@
-#include "../git-compat-util.h"
-#include "dirent.h"
+#include "../../git-compat-util.h"
 
 struct DIR {
        struct dirent dd_dir; /* includes d_type */
        HANDLE dd_handle;     /* FindFirstFile handle */
        int dd_stat;          /* 0-based index */
-       char dd_name[1];      /* extend struct */
 };
 
+static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
+{
+       /* copy file name from WIN32_FIND_DATA to dirent */
+       memcpy(ent->d_name, fdata->cFileName, sizeof(ent->d_name));
+
+       /* Set file type, based on WIN32_FIND_DATA */
+       if (fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+               ent->d_type = DT_DIR;
+       else
+               ent->d_type = DT_REG;
+}
+
 DIR *opendir(const char *name)
 {
-       DWORD attrs = GetFileAttributesA(name);
+       char pattern[MAX_PATH];
+       WIN32_FIND_DATAA fdata;
+       HANDLE h;
        int len;
-       DIR *p;
+       DIR *dir;
 
-       /* check for valid path */
-       if (attrs == INVALID_FILE_ATTRIBUTES) {
-               errno = ENOENT;
+       /* check that name is not NULL */
+       if (!name) {
+               errno = EINVAL;
                return NULL;
        }
-
-       /* check if it's a directory */
-       if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
-               errno = ENOTDIR;
-               return NULL;
-       }
-
        /* check that the pattern won't be too long for FindFirstFileA */
        len = strlen(name);
-       if (is_dir_sep(name[len - 1]))
-               len--;
        if (len + 2 >= MAX_PATH) {
                errno = ENAMETOOLONG;
                return NULL;
        }
-
-       p = malloc(sizeof(DIR) + len + 2);
-       if (!p)
+       /* copy name to temp buffer */
+       memcpy(pattern, name, len + 1);
+
+       /* append optional '/' and wildcard '*' */
+       if (len && !is_dir_sep(pattern[len - 1]))
+               pattern[len++] = '/';
+       pattern[len++] = '*';
+       pattern[len] = 0;
+
+       /* open find handle */
+       h = FindFirstFileA(pattern, &fdata);
+       if (h == INVALID_HANDLE_VALUE) {
+               DWORD err = GetLastError();
+               errno = (err == ERROR_DIRECTORY) ? ENOTDIR : err_win_to_posix(err);
                return NULL;
+       }
 
-       memset(p, 0, sizeof(DIR) + len + 2);
-       strcpy(p->dd_name, name);
-       p->dd_name[len] = '/';
-       p->dd_name[len+1] = '*';
-
-       p->dd_handle = INVALID_HANDLE_VALUE;
-       return p;
+       /* initialize DIR structure and copy first dir entry */
+       dir = xmalloc(sizeof(DIR));
+       dir->dd_handle = h;
+       dir->dd_stat = 0;
+       finddata2dirent(&dir->dd_dir, &fdata);
+       return dir;
 }
 
 struct dirent *readdir(DIR *dir)
 {
-       WIN32_FIND_DATAA buf;
-       HANDLE handle;
-
-       if (!dir || !dir->dd_handle) {
+       if (!dir) {
                errno = EBADF; /* No set_errno for mingw */
                return NULL;
        }
 
-       if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) {
-               DWORD lasterr;
-               handle = FindFirstFileA(dir->dd_name, &buf);
-               lasterr = GetLastError();
-               dir->dd_handle = handle;
-               if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) {
-                       errno = err_win_to_posix(lasterr);
+       /* if first entry, dirent has already been set up by opendir */
+       if (dir->dd_stat) {
+               /* get next entry and convert from WIN32_FIND_DATA to dirent */
+               WIN32_FIND_DATAA fdata;
+               if (FindNextFileA(dir->dd_handle, &fdata)) {
+                       finddata2dirent(&dir->dd_dir, &fdata);
+               } else {
+                       DWORD lasterr = GetLastError();
+                       /* POSIX says you shouldn't set errno when readdir can't
+                          find any more files; so, if another error we leave it set. */
+                       if (lasterr != ERROR_NO_MORE_FILES)
+                               errno = err_win_to_posix(lasterr);
                        return NULL;
                }
-       } else if (dir->dd_handle == INVALID_HANDLE_VALUE) {
-               return NULL;
-       } else if (!FindNextFileA(dir->dd_handle, &buf)) {
-               DWORD lasterr = GetLastError();
-               FindClose(dir->dd_handle);
-               dir->dd_handle = INVALID_HANDLE_VALUE;
-               /* POSIX says you shouldn't set errno when readdir can't
-                  find any more files; so, if another error we leave it set. */
-               if (lasterr != ERROR_NO_MORE_FILES)
-                       errno = err_win_to_posix(lasterr);
-               return NULL;
        }
 
-       /* We get here if `buf' contains valid data.  */
-       strcpy(dir->dd_dir.d_name, buf.cFileName);
        ++dir->dd_stat;
-
-       /* Set file type, based on WIN32_FIND_DATA */
-       dir->dd_dir.d_type = 0;
-       if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-               dir->dd_dir.d_type |= DT_DIR;
-       else
-               dir->dd_dir.d_type |= DT_REG;
-
        return &dir->dd_dir;
 }
 
@@ -101,8 +96,7 @@ int closedir(DIR *dir)
                return -1;
        }
 
-       if (dir->dd_handle != INVALID_HANDLE_VALUE)
-               FindClose(dir->dd_handle);
+       FindClose(dir->dd_handle);
        free(dir);
        return 0;
 }
index 927a25ca765ef4f393ba28d54e2478b29fca878e..8838cd61fc282b3713db76e088130f82b6c6fe33 100644 (file)
@@ -9,12 +9,8 @@ typedef struct DIR DIR;
 #define DT_LNK     3
 
 struct dirent {
-       long d_ino;                      /* Always zero. */
-       char d_name[FILENAME_MAX];       /* File name. */
-       union {
-               unsigned short d_reclen; /* Always zero. */
-               unsigned char  d_type;   /* Reimplementation adds this */
-       };
+       unsigned char d_type;      /* file type to prevent lstat after readdir */
+       char d_name[MAX_PATH];     /* file name */
 };
 
 DIR *opendir(const char *dirname);
index dedce2104eaf5cefbb1abef1b7921eb99c67a75e..efc5bb3a4b63166eccb33f6ec6a8ad57e4c9ac36 100644 (file)
@@ -2,15 +2,10 @@
  * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
  */
 
+#undef NOGDI
 #include "../git-compat-util.h"
-
-/*
- Functions to be wrapped:
-*/
-#undef printf
-#undef fprintf
-#undef fputs
-/* TODO: write */
+#include <wingdi.h>
+#include <winreg.h>
 
 /*
  ANSI codes used by git: m, K
@@ -23,29 +18,114 @@ static HANDLE console;
 static WORD plain_attr;
 static WORD attr;
 static int negative;
+static int non_ascii_used = 0;
+static HANDLE hthread, hread, hwrite;
+static HANDLE hconsole1, hconsole2;
+
+#ifdef __MINGW32__
+typedef struct _CONSOLE_FONT_INFOEX {
+       ULONG cbSize;
+       DWORD nFont;
+       COORD dwFontSize;
+       UINT FontFamily;
+       UINT FontWeight;
+       WCHAR FaceName[LF_FACESIZE];
+} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
+#endif
+
+typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL,
+               PCONSOLE_FONT_INFOEX);
+
+static void warn_if_raster_font(void)
+{
+       DWORD fontFamily = 0;
+       PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx;
+
+       /* don't bother if output was ascii only */
+       if (!non_ascii_used)
+               return;
+
+       /* GetCurrentConsoleFontEx is available since Vista */
+       pGetCurrentConsoleFontEx = (PGETCURRENTCONSOLEFONTEX) GetProcAddress(
+                       GetModuleHandle("kernel32.dll"),
+                       "GetCurrentConsoleFontEx");
+       if (pGetCurrentConsoleFontEx) {
+               CONSOLE_FONT_INFOEX cfi;
+               cfi.cbSize = sizeof(cfi);
+               if (pGetCurrentConsoleFontEx(console, 0, &cfi))
+                       fontFamily = cfi.FontFamily;
+       } else {
+               /* pre-Vista: check default console font in registry */
+               HKEY hkey;
+               if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, "Console",
+                               0, KEY_READ, &hkey)) {
+                       DWORD size = sizeof(fontFamily);
+                       RegQueryValueExA(hkey, "FontFamily", NULL, NULL,
+                                       (LPVOID) &fontFamily, &size);
+                       RegCloseKey(hkey);
+               }
+       }
+
+       if (!(fontFamily & TMPF_TRUETYPE)) {
+               const wchar_t *msg = L"\nWarning: Your console font probably "
+                       L"doesn\'t support Unicode. If you experience strange "
+                       L"characters in the output, consider switching to a "
+                       L"TrueType font such as Consolas!\n";
+               DWORD dummy;
+               WriteConsoleW(console, msg, wcslen(msg), &dummy, NULL);
+       }
+}
 
-static void init(void)
+static int is_console(int fd)
 {
        CONSOLE_SCREEN_BUFFER_INFO sbi;
+       HANDLE hcon;
 
        static int initialized = 0;
-       if (initialized)
-               return;
 
-       console = GetStdHandle(STD_OUTPUT_HANDLE);
-       if (console == INVALID_HANDLE_VALUE)
-               console = NULL;
+       /* get OS handle of the file descriptor */
+       hcon = (HANDLE) _get_osfhandle(fd);
+       if (hcon == INVALID_HANDLE_VALUE)
+               return 0;
 
-       if (!console)
-               return;
+       /* check if its a device (i.e. console, printer, serial port) */
+       if (GetFileType(hcon) != FILE_TYPE_CHAR)
+               return 0;
 
-       GetConsoleScreenBufferInfo(console, &sbi);
-       attr = plain_attr = sbi.wAttributes;
-       negative = 0;
+       /* check if its a handle to a console output screen buffer */
+       if (!GetConsoleScreenBufferInfo(hcon, &sbi))
+               return 0;
+
+       /* initialize attributes */
+       if (!initialized) {
+               console = hcon;
+               attr = plain_attr = sbi.wAttributes;
+               negative = 0;
+               initialized = 1;
+       }
 
-       initialized = 1;
+       return 1;
 }
 
+#define BUFFER_SIZE 4096
+#define MAX_PARAMS 16
+
+static void write_console(unsigned char *str, size_t len)
+{
+       /* only called from console_thread, so a static buffer will do */
+       static wchar_t wbuf[2 * BUFFER_SIZE + 1];
+       DWORD dummy;
+
+       /* convert utf-8 to utf-16 */
+       int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
+
+       /* write directly to console */
+       WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
+
+       /* remember if non-ascii characters are printed */
+       if (wlen != len)
+               non_ascii_used = 1;
+}
 
 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
@@ -90,18 +170,13 @@ static void erase_in_line(void)
                &dummy);
 }
 
-
-static const char *set_attr(const char *str)
+static void set_attr(char func, const int *params, int paramlen)
 {
-       const char *func;
-       size_t len = strspn(str, "0123456789;");
-       func = str + len;
-
-       switch (*func) {
+       int i;
+       switch (func) {
        case 'm':
-               do {
-                       long val = strtol(str, (char **)&str, 10);
-                       switch (val) {
+               for (i = 0; i < paramlen; i++) {
+                       switch (params[i]) {
                        case 0: /* reset */
                                attr = plain_attr;
                                negative = 0;
@@ -224,9 +299,7 @@ static const char *set_attr(const char *str)
                                /* Unsupported code */
                                break;
                        }
-                       str++;
-               } while (*(str-1) == ';');
-
+               }
                set_console_attr();
                break;
        case 'K':
@@ -236,122 +309,271 @@ static const char *set_attr(const char *str)
                /* Unsupported code */
                break;
        }
-
-       return func + 1;
 }
 
-static int ansi_emulate(const char *str, FILE *stream)
+enum {
+       TEXT = 0, ESCAPE = 033, BRACKET = '['
+};
+
+static DWORD WINAPI console_thread(LPVOID unused)
 {
-       int rv = 0;
-       const char *pos = str;
-
-       while (*pos) {
-               pos = strstr(str, "\033[");
-               if (pos) {
-                       size_t len = pos - str;
-
-                       if (len) {
-                               size_t out_len = fwrite(str, 1, len, stream);
-                               rv += out_len;
-                               if (out_len < len)
-                                       return rv;
+       unsigned char buffer[BUFFER_SIZE];
+       DWORD bytes;
+       int start, end = 0, c, parampos = 0, state = TEXT;
+       int params[MAX_PARAMS];
+
+       while (1) {
+               /* read next chunk of bytes from the pipe */
+               if (!ReadFile(hread, buffer + end, BUFFER_SIZE - end, &bytes,
+                               NULL)) {
+                       /* exit if pipe has been closed or disconnected */
+                       if (GetLastError() == ERROR_PIPE_NOT_CONNECTED ||
+                                       GetLastError() == ERROR_BROKEN_PIPE)
+                               break;
+                       /* ignore other errors */
+                       continue;
+               }
+
+               /* scan the bytes and handle ANSI control codes */
+               bytes += end;
+               start = end = 0;
+               while (end < bytes) {
+                       c = buffer[end++];
+                       switch (state) {
+                       case TEXT:
+                               if (c == ESCAPE) {
+                                       /* print text seen so far */
+                                       if (end - 1 > start)
+                                               write_console(buffer + start,
+                                                       end - 1 - start);
+
+                                       /* then start parsing escape sequence */
+                                       start = end - 1;
+                                       memset(params, 0, sizeof(params));
+                                       parampos = 0;
+                                       state = ESCAPE;
+                               }
+                               break;
+
+                       case ESCAPE:
+                               /* continue if "\033[", otherwise bail out */
+                               state = (c == BRACKET) ? BRACKET : TEXT;
+                               break;
+
+                       case BRACKET:
+                               /* parse [0-9;]* into array of parameters */
+                               if (c >= '0' && c <= '9') {
+                                       params[parampos] *= 10;
+                                       params[parampos] += c - '0';
+                               } else if (c == ';') {
+                                       /*
+                                        * next parameter, bail out if out of
+                                        * bounds
+                                        */
+                                       parampos++;
+                                       if (parampos >= MAX_PARAMS)
+                                               state = TEXT;
+                               } else {
+                                       /*
+                                        * end of escape sequence, change
+                                        * console attributes
+                                        */
+                                       set_attr(c, params, parampos + 1);
+                                       start = end;
+                                       state = TEXT;
+                               }
+                               break;
                        }
+               }
 
-                       str = pos + 2;
-                       rv += 2;
+               /* print remaining text unless parsing an escape sequence */
+               if (state == TEXT && end > start) {
+                       /* check for incomplete UTF-8 sequences and fix end */
+                       if (buffer[end - 1] >= 0x80) {
+                               if (buffer[end -1] >= 0xc0)
+                                       end--;
+                               else if (end - 1 > start &&
+                                               buffer[end - 2] >= 0xe0)
+                                       end -= 2;
+                               else if (end - 2 > start &&
+                                               buffer[end - 3] >= 0xf0)
+                                       end -= 3;
+                       }
 
-                       fflush(stream);
+                       /* print remaining complete UTF-8 sequences */
+                       if (end > start)
+                               write_console(buffer + start, end - start);
 
-                       pos = set_attr(str);
-                       rv += pos - str;
-                       str = pos;
+                       /* move remaining bytes to the front */
+                       if (end < bytes)
+                               memmove(buffer, buffer + end, bytes - end);
+                       end = bytes - end;
                } else {
-                       rv += strlen(str);
-                       fputs(str, stream);
-                       return rv;
+                       /* all data has been consumed, mark buffer empty */
+                       end = 0;
                }
        }
-       return rv;
+
+       /* check if the console font supports unicode */
+       warn_if_raster_font();
+
+       CloseHandle(hread);
+       return 0;
 }
 
-int winansi_fputs(const char *str, FILE *stream)
+static void winansi_exit(void)
 {
-       int rv;
-
-       if (!isatty(fileno(stream)))
-               return fputs(str, stream);
+       /* flush all streams */
+       _flushall();
 
-       init();
+       /* signal console thread to exit */
+       FlushFileBuffers(hwrite);
+       DisconnectNamedPipe(hwrite);
 
-       if (!console)
-               return fputs(str, stream);
+       /* wait for console thread to copy remaining data */
+       WaitForSingleObject(hthread, INFINITE);
 
-       rv = ansi_emulate(str, stream);
+       /* cleanup handles... */
+       CloseHandle(hwrite);
+       CloseHandle(hthread);
+}
 
-       if (rv >= 0)
-               return 0;
-       else
-               return EOF;
+static void die_lasterr(const char *fmt, ...)
+{
+       va_list params;
+       va_start(params, fmt);
+       errno = err_win_to_posix(GetLastError());
+       die_errno(fmt, params);
+       va_end(params);
 }
 
-static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
+static HANDLE duplicate_handle(HANDLE hnd)
 {
-       int len, rv;
-       char small_buf[256];
-       char *buf = small_buf;
-       va_list cp;
+       HANDLE hresult, hproc = GetCurrentProcess();
+       if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE,
+                       DUPLICATE_SAME_ACCESS))
+               die_lasterr("DuplicateHandle(%li) failed", (long) hnd);
+       return hresult;
+}
 
-       if (!isatty(fileno(stream)))
-               goto abort;
 
-       init();
+/*
+ * Make MSVCRT's internal file descriptor control structure accessible
+ * so that we can tweak OS handles and flags directly (we need MSVCRT
+ * to treat our pipe handle as if it were a console).
+ *
+ * We assume that the ioinfo structure (exposed by MSVCRT.dll via
+ * __pioinfo) starts with the OS handle and the flags. The exact size
+ * varies between MSVCRT versions, so we try different sizes until
+ * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
+ * isatty(1).
+ */
+typedef struct {
+       HANDLE osfhnd;
+       char osflags;
+} ioinfo;
 
-       if (!console)
-               goto abort;
+extern __declspec(dllimport) ioinfo *__pioinfo[];
 
-       va_copy(cp, list);
-       len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
-       va_end(cp);
+static size_t sizeof_ioinfo = 0;
 
-       if (len > sizeof(small_buf) - 1) {
-               buf = malloc(len + 1);
-               if (!buf)
-                       goto abort;
+#define IOINFO_L2E 5
+#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
 
-               len = vsnprintf(buf, len + 1, format, list);
-       }
+#define FDEV  0x40
 
-       rv = ansi_emulate(buf, stream);
+static inline ioinfo* _pioinfo(int fd)
+{
+       return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
+                       (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
+}
 
-       if (buf != small_buf)
-               free(buf);
-       return rv;
+static int init_sizeof_ioinfo()
+{
+       int istty, wastty;
+       /* don't init twice */
+       if (sizeof_ioinfo)
+               return sizeof_ioinfo >= 256;
+
+       sizeof_ioinfo = sizeof(ioinfo);
+       wastty = isatty(1);
+       while (sizeof_ioinfo < 256) {
+               /* toggle FDEV flag, check isatty, then toggle back */
+               _pioinfo(1)->osflags ^= FDEV;
+               istty = isatty(1);
+               _pioinfo(1)->osflags ^= FDEV;
+               /* return if we found the correct size */
+               if (istty != wastty)
+                       return 0;
+               sizeof_ioinfo += sizeof(void*);
+       }
+       error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
+       return 1;
+}
 
-abort:
-       rv = vfprintf(stream, format, list);
-       return rv;
+static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
+{
+       ioinfo *pioinfo;
+       HANDLE old_handle;
+
+       /* init ioinfo size if we haven't done so */
+       if (init_sizeof_ioinfo())
+               return INVALID_HANDLE_VALUE;
+
+       /* get ioinfo pointer and change the handles */
+       pioinfo = _pioinfo(fd);
+       old_handle = pioinfo->osfhnd;
+       pioinfo->osfhnd = new_handle;
+       return old_handle;
 }
 
-int winansi_fprintf(FILE *stream, const char *format, ...)
+void winansi_init(void)
 {
-       va_list list;
-       int rv;
+       int con1, con2;
+       char name[32];
 
-       va_start(list, format);
-       rv = winansi_vfprintf(stream, format, list);
-       va_end(list);
+       /* check if either stdout or stderr is a console output screen buffer */
+       con1 = is_console(1);
+       con2 = is_console(2);
+       if (!con1 && !con2)
+               return;
 
-       return rv;
+       /* create a named pipe to communicate with the console thread */
+       sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId());
+       hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND,
+               PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL);
+       if (hwrite == INVALID_HANDLE_VALUE)
+               die_lasterr("CreateNamedPipe failed");
+
+       hread = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+       if (hread == INVALID_HANDLE_VALUE)
+               die_lasterr("CreateFile for named pipe failed");
+
+       /* start console spool thread on the pipe's read end */
+       hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
+       if (hthread == INVALID_HANDLE_VALUE)
+               die_lasterr("CreateThread(console_thread) failed");
+
+       /* schedule cleanup routine */
+       if (atexit(winansi_exit))
+               die_errno("atexit(winansi_exit) failed");
+
+       /* redirect stdout / stderr to the pipe */
+       if (con1)
+               hconsole1 = swap_osfhnd(1, duplicate_handle(hwrite));
+       if (con2)
+               hconsole2 = swap_osfhnd(2, duplicate_handle(hwrite));
 }
 
-int winansi_printf(const char *format, ...)
+/*
+ * Returns the real console handle if stdout / stderr is a pipe redirecting
+ * to the console. Allows spawn / exec to pass the console to the next process.
+ */
+HANDLE winansi_get_osfhandle(int fd)
 {
-       va_list list;
-       int rv;
-
-       va_start(list, format);
-       rv = winansi_vfprintf(stdout, format, list);
-       va_end(list);
-
-       return rv;
+       HANDLE hnd = (HANDLE) _get_osfhandle(fd);
+       if ((fd == 1 || fd == 2) && isatty(fd)
+           && GetFileType(hnd) == FILE_TYPE_PIPE)
+               return (fd == 1) ? hconsole1 : hconsole2;
+       return hnd;
 }
index a1aef1cf3eca01e328b3e319636269236ea91ae0..ba882a1f51de347dc52fa8c52623dbc376f36d80 100644 (file)
--- a/config.c
+++ b/config.c
@@ -138,8 +138,7 @@ int git_config_include(const char *var, const char *value, void *data)
        if (ret < 0)
                return ret;
 
-       type = skip_prefix(var, "include.");
-       if (!type)
+       if (!skip_prefix(var, "include.", &type))
                return ret;
 
        if (!strcmp(type, "path"))
index 1ae675b05344912d8798b9856b60b03c282cf908..8131c81985d97c23d19c7ef489f0db988f6fbbc7 100644 (file)
@@ -354,6 +354,7 @@ ifeq ($(uname_S),Windows)
        NO_POSIX_GOODIES = UnfortunatelyYes
        NATIVE_CRLF = YesPlease
        DEFAULT_HELP_FORMAT = html
+       NO_D_INO_IN_DIRENT = YesPlease
 
        CC = compat/vcbuild/scripts/clink.pl
        AR = compat/vcbuild/scripts/lib.pl
@@ -503,6 +504,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        NO_INET_NTOP = YesPlease
        NO_POSIX_GOODIES = UnfortunatelyYes
        DEFAULT_HELP_FORMAT = html
+       NO_D_INO_IN_DIRENT = YesPlease
        COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -D_USE_32BIT_TIME_T -DNOGDI -Icompat -Icompat/win32
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
        COMPAT_OBJS += compat/mingw.o compat/winansi.o \
index 94a66502464400d5dfc47a4151cc2fd01780a0a4..37ff018f13f6f8f3137a9aec973b85848a8138eb 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -129,6 +129,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                char *name;
                int len, name_len;
                char *buffer = packet_buffer;
+               const char *arg;
 
                len = packet_read(in, &src_buf, &src_len,
                                  packet_buffer, sizeof(packet_buffer),
@@ -140,12 +141,12 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                if (!len)
                        break;
 
-               if (len > 4 && starts_with(buffer, "ERR "))
-                       die("remote error: %s", buffer + 4);
+               if (len > 4 && skip_prefix(buffer, "ERR ", &arg))
+                       die("remote error: %s", arg);
 
-               if (len == 48 && starts_with(buffer, "shallow ")) {
-                       if (get_sha1_hex(buffer + 8, old_sha1))
-                               die("protocol error: expected shallow sha-1, got '%s'", buffer + 8);
+               if (len == 48 && skip_prefix(buffer, "shallow ", &arg)) {
+                       if (get_sha1_hex(arg, old_sha1))
+                               die("protocol error: expected shallow sha-1, got '%s'", arg);
                        if (!shallow_points)
                                die("repository on the other end cannot be shallow");
                        sha1_array_append(shallow_points, old_sha1);
index ab80b723574ff88b6c9c4a7c98c8821600f3e6bc..cb5fbb45ea04cead65316ecf6b44730b17108122 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1121,9 +1121,9 @@ static int is_foreign_ident(const char *str)
 {
        int i;
 
-       if (!starts_with(str, "$Id: "))
+       if (!skip_prefix(str, "$Id: ", &str))
                return 0;
-       for (i = 5; str[i]; i++) {
+       for (i = 0; str[i]; i++) {
                if (isspace(str[i]) && str[i+1] != '$')
                        return 1;
        }
index 390f194252cc6d7c0c9f43e2a48692324bf0b665..3b370ca5e529c74e17e0f39da5c689ebc4ccfc25 100644 (file)
@@ -109,14 +109,12 @@ static int read_request(FILE *fh, struct credential *c,
        const char *p;
 
        strbuf_getline(&item, fh, '\n');
-       p = skip_prefix(item.buf, "action=");
-       if (!p)
+       if (!skip_prefix(item.buf, "action=", &p))
                return error("client sent bogus action line: %s", item.buf);
        strbuf_addstr(action, p);
 
        strbuf_getline(&item, fh, '\n');
-       p = skip_prefix(item.buf, "timeout=");
-       if (!p)
+       if (!skip_prefix(item.buf, "timeout=", &p))
                return error("client sent bogus timeout line: %s", item.buf);
        *timeout = atoi(p);
 
index e54753c75d1c2abf7916f1aa7075d4ada3cfc61f..4d79d320f89e956aa9233a170120f05b2473ca59 100644 (file)
@@ -40,8 +40,7 @@ static int credential_config_callback(const char *var, const char *value,
        struct credential *c = data;
        const char *key, *dot;
 
-       key = skip_prefix(var, "credential.");
-       if (!key)
+       if (!skip_prefix(var, "credential.", &key))
                return 0;
 
        if (!value)
index f9c63e96137aff6b5ae2376af3fca789ff03e975..1eb663172338ae24ef9229594f893e80c2e52f96 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -39,8 +39,8 @@ static int strict_paths;
 static int export_all_trees;
 
 /* Take all paths relative to this one if non-NULL */
-static char *base_path;
-static char *interpolated_path;
+static const char *base_path;
+static const char *interpolated_path;
 static int base_path_relaxed;
 
 /* Flag indicating client sent extra args. */
@@ -106,12 +106,12 @@ static void NORETURN daemon_die(const char *err, va_list params)
        exit(1);
 }
 
-static const char *path_ok(char *directory)
+static const char *path_ok(const char *directory)
 {
        static char rpath[PATH_MAX];
        static char interp_path[PATH_MAX];
        const char *path;
-       char *dir;
+       const char *dir;
 
        dir = directory;
 
@@ -131,7 +131,7 @@ static const char *path_ok(char *directory)
                         * "~alice/%s/foo".
                         */
                        int namlen, restlen = strlen(dir);
-                       char *slash = strchr(dir, '/');
+                       const char *slash = strchr(dir, '/');
                        if (!slash)
                                slash = dir + restlen;
                        namlen = slash - dir;
@@ -235,8 +235,10 @@ static int service_enabled;
 
 static int git_daemon_config(const char *var, const char *value, void *cb)
 {
-       if (starts_with(var, "daemon.") &&
-           !strcmp(var + 7, service_looking_at->config_name)) {
+       const char *service;
+
+       if (skip_prefix(var, "daemon.", &service) &&
+           !strcmp(service, service_looking_at->config_name)) {
                service_enabled = git_config_bool(var, value);
                return 0;
        }
@@ -253,7 +255,7 @@ static int daemon_error(const char *dir, const char *msg)
        return -1;
 }
 
-static char *access_hook;
+static const char *access_hook;
 
 static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
 {
@@ -318,7 +320,7 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        return -1;
 }
 
-static int run_service(char *dir, struct daemon_service *service)
+static int run_service(const char *dir, struct daemon_service *service)
 {
        const char *path;
        int enabled = service->enabled;
@@ -624,15 +626,16 @@ static int execute(void)
 
        for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
                struct daemon_service *s = &(daemon_service[i]);
-               int namelen = strlen(s->name);
-               if (starts_with(line, "git-") &&
-                   !strncmp(s->name, line + 4, namelen) &&
-                   line[namelen + 4] == ' ') {
+               const char *arg;
+
+               if (skip_prefix(line, "git-", &arg) &&
+                   skip_prefix(arg, s->name, &arg) &&
+                   *arg++ == ' ') {
                        /*
                         * Note: The directory here is probably context sensitive,
                         * and might depend on the actual service being performed.
                         */
-                       return run_service(line + namelen + 5, s);
+                       return run_service(arg, s);
                }
        }
 
@@ -1133,16 +1136,17 @@ int main(int argc, char **argv)
 
        for (i = 1; i < argc; i++) {
                char *arg = argv[i];
+               const char *v;
 
-               if (starts_with(arg, "--listen=")) {
-                       string_list_append(&listen_addr, xstrdup_tolower(arg + 9));
+               if (skip_prefix(arg, "--listen=", &v)) {
+                       string_list_append(&listen_addr, xstrdup_tolower(v));
                        continue;
                }
-               if (starts_with(arg, "--port=")) {
+               if (skip_prefix(arg, "--port=", &v)) {
                        char *end;
                        unsigned long n;
-                       n = strtoul(arg+7, &end, 0);
-                       if (arg[7] && !*end) {
+                       n = strtoul(v, &end, 0);
+                       if (*v && !*end) {
                                listen_port = n;
                                continue;
                        }
@@ -1168,20 +1172,20 @@ int main(int argc, char **argv)
                        export_all_trees = 1;
                        continue;
                }
-               if (starts_with(arg, "--access-hook=")) {
-                       access_hook = arg + 14;
+               if (skip_prefix(arg, "--access-hook=", &v)) {
+                       access_hook = v;
                        continue;
                }
-               if (starts_with(arg, "--timeout=")) {
-                       timeout = atoi(arg+10);
+               if (skip_prefix(arg, "--timeout=", &v)) {
+                       timeout = atoi(v);
                        continue;
                }
-               if (starts_with(arg, "--init-timeout=")) {
-                       init_timeout = atoi(arg+15);
+               if (skip_prefix(arg, "--init-timeout=", &v)) {
+                       init_timeout = atoi(v);
                        continue;
                }
-               if (starts_with(arg, "--max-connections=")) {
-                       max_connections = atoi(arg+18);
+               if (skip_prefix(arg, "--max-connections=", &v)) {
+                       max_connections = atoi(v);
                        if (max_connections < 0)
                                max_connections = 0;            /* unlimited */
                        continue;
@@ -1190,16 +1194,16 @@ int main(int argc, char **argv)
                        strict_paths = 1;
                        continue;
                }
-               if (starts_with(arg, "--base-path=")) {
-                       base_path = arg+12;
+               if (skip_prefix(arg, "--base-path=", &v)) {
+                       base_path = v;
                        continue;
                }
                if (!strcmp(arg, "--base-path-relaxed")) {
                        base_path_relaxed = 1;
                        continue;
                }
-               if (starts_with(arg, "--interpolated-path=")) {
-                       interpolated_path = arg+20;
+               if (skip_prefix(arg, "--interpolated-path=", &v)) {
+                       interpolated_path = v;
                        continue;
                }
                if (!strcmp(arg, "--reuseaddr")) {
@@ -1210,12 +1214,12 @@ int main(int argc, char **argv)
                        user_path = "";
                        continue;
                }
-               if (starts_with(arg, "--user-path=")) {
-                       user_path = arg + 12;
+               if (skip_prefix(arg, "--user-path=", &v)) {
+                       user_path = v;
                        continue;
                }
-               if (starts_with(arg, "--pid-file=")) {
-                       pid_file = arg + 11;
+               if (skip_prefix(arg, "--pid-file=", &v)) {
+                       pid_file = v;
                        continue;
                }
                if (!strcmp(arg, "--detach")) {
@@ -1223,28 +1227,28 @@ int main(int argc, char **argv)
                        log_syslog = 1;
                        continue;
                }
-               if (starts_with(arg, "--user=")) {
-                       user_name = arg + 7;
+               if (skip_prefix(arg, "--user=", &v)) {
+                       user_name = v;
                        continue;
                }
-               if (starts_with(arg, "--group=")) {
-                       group_name = arg + 8;
+               if (skip_prefix(arg, "--group=", &v)) {
+                       group_name = v;
                        continue;
                }
-               if (starts_with(arg, "--enable=")) {
-                       enable_service(arg + 9, 1);
+               if (skip_prefix(arg, "--enable=", &v)) {
+                       enable_service(v, 1);
                        continue;
                }
-               if (starts_with(arg, "--disable=")) {
-                       enable_service(arg + 10, 0);
+               if (skip_prefix(arg, "--disable=", &v)) {
+                       enable_service(v, 0);
                        continue;
                }
-               if (starts_with(arg, "--allow-override=")) {
-                       make_service_overridable(arg + 17, 1);
+               if (skip_prefix(arg, "--allow-override=", &v)) {
+                       make_service_overridable(v, 1);
                        continue;
                }
-               if (starts_with(arg, "--forbid-override=")) {
-                       make_service_overridable(arg + 18, 0);
+               if (skip_prefix(arg, "--forbid-override=", &v)) {
+                       make_service_overridable(v, 0);
                        continue;
                }
                if (!strcmp(arg, "--informative-errors")) {
diff --git a/diff.c b/diff.c
index bba9a558a60a490b7edd6dec370181a0941bf985..06bdfb8ae5acab2c6090ca4154a26fca6da8b74c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -52,23 +52,23 @@ static char diff_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_NORMAL,       /* FUNCINFO */
 };
 
-static int parse_diff_color_slot(const char *var, int ofs)
+static int parse_diff_color_slot(const char *var)
 {
-       if (!strcasecmp(var+ofs, "plain"))
+       if (!strcasecmp(var, "plain"))
                return DIFF_PLAIN;
-       if (!strcasecmp(var+ofs, "meta"))
+       if (!strcasecmp(var, "meta"))
                return DIFF_METAINFO;
-       if (!strcasecmp(var+ofs, "frag"))
+       if (!strcasecmp(var, "frag"))
                return DIFF_FRAGINFO;
-       if (!strcasecmp(var+ofs, "old"))
+       if (!strcasecmp(var, "old"))
                return DIFF_FILE_OLD;
-       if (!strcasecmp(var+ofs, "new"))
+       if (!strcasecmp(var, "new"))
                return DIFF_FILE_NEW;
-       if (!strcasecmp(var+ofs, "commit"))
+       if (!strcasecmp(var, "commit"))
                return DIFF_COMMIT;
-       if (!strcasecmp(var+ofs, "whitespace"))
+       if (!strcasecmp(var, "whitespace"))
                return DIFF_WHITESPACE;
-       if (!strcasecmp(var+ofs, "func"))
+       if (!strcasecmp(var, "func"))
                return DIFF_FUNCINFO;
        return -1;
 }
@@ -231,6 +231,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
 
 int git_diff_basic_config(const char *var, const char *value, void *cb)
 {
+       const char *name;
+
        if (!strcmp(var, "diff.renamelimit")) {
                diff_rename_limit_default = git_config_int(var, value);
                return 0;
@@ -239,8 +241,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
        if (userdiff_config(var, value) < 0)
                return -1;
 
-       if (starts_with(var, "diff.color.") || starts_with(var, "color.diff.")) {
-               int slot = parse_diff_color_slot(var, 11);
+       if (skip_prefix(var, "diff.color.", &name) ||
+           skip_prefix(var, "color.diff.", &name)) {
+               int slot = parse_diff_color_slot(name);
                if (slot < 0)
                        return 0;
                if (!value)
@@ -2341,6 +2344,7 @@ static void builtin_diff(const char *name_a,
        } else {
                /* Crazy xdl interfaces.. */
                const char *diffopts = getenv("GIT_DIFF_OPTS");
+               const char *v;
                xpparam_t xpp;
                xdemitconf_t xecfg;
                struct emit_callback ecbdata;
@@ -2379,10 +2383,10 @@ static void builtin_diff(const char *name_a,
                        xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
                if (!diffopts)
                        ;
-               else if (starts_with(diffopts, "--unified="))
-                       xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
-               else if (starts_with(diffopts, "-u"))
-                       xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
+               else if (skip_prefix(diffopts, "--unified=", &v))
+                       xecfg.ctxlen = strtoul(v, NULL, 10);
+               else if (skip_prefix(diffopts, "-u", &v))
+                       xecfg.ctxlen = strtoul(v, NULL, 10);
                if (o->word_diff)
                        init_diff_words_data(&ecbdata, o, one, two);
                xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
@@ -3391,12 +3395,10 @@ int parse_long_opt(const char *opt, const char **argv,
                   const char **optarg)
 {
        const char *arg = argv[0];
-       if (arg[0] != '-' || arg[1] != '-')
+       if (!skip_prefix(arg, "--", &arg))
                return 0;
-       arg += strlen("--");
-       if (!starts_with(arg, opt))
+       if (!skip_prefix(arg, opt, &arg))
                return 0;
-       arg += strlen(opt);
        if (*arg == '=') { /* stuck form: --option=value */
                *optarg = arg + 1;
                return 1;
@@ -3420,13 +3422,13 @@ static int stat_opt(struct diff_options *options, const char **av)
        int count = options->stat_count;
        int argcount = 1;
 
-       arg += strlen("--stat");
+       if (!skip_prefix(arg, "--stat", &arg))
+               die("BUG: stat option does not begin with --stat: %s", arg);
        end = (char *)arg;
 
        switch (*arg) {
        case '-':
-               if (starts_with(arg, "-width")) {
-                       arg += strlen("-width");
+               if (skip_prefix(arg, "-width", &arg)) {
                        if (*arg == '=')
                                width = strtoul(arg + 1, &end, 10);
                        else if (!*arg && !av[1])
@@ -3435,8 +3437,7 @@ static int stat_opt(struct diff_options *options, const char **av)
                                width = strtoul(av[1], &end, 10);
                                argcount = 2;
                        }
-               } else if (starts_with(arg, "-name-width")) {
-                       arg += strlen("-name-width");
+               } else if (skip_prefix(arg, "-name-width", &arg)) {
                        if (*arg == '=')
                                name_width = strtoul(arg + 1, &end, 10);
                        else if (!*arg && !av[1])
@@ -3445,8 +3446,7 @@ static int stat_opt(struct diff_options *options, const char **av)
                                name_width = strtoul(av[1], &end, 10);
                                argcount = 2;
                        }
-               } else if (starts_with(arg, "-graph-width")) {
-                       arg += strlen("-graph-width");
+               } else if (skip_prefix(arg, "-graph-width", &arg)) {
                        if (*arg == '=')
                                graph_width = strtoul(arg + 1, &end, 10);
                        else if (!*arg && !av[1])
@@ -3455,8 +3455,7 @@ static int stat_opt(struct diff_options *options, const char **av)
                                graph_width = strtoul(av[1], &end, 10);
                                argcount = 2;
                        }
-               } else if (starts_with(arg, "-count")) {
-                       arg += strlen("-count");
+               } else if (skip_prefix(arg, "-count", &arg)) {
                        if (*arg == '=')
                                count = strtoul(arg + 1, &end, 10);
                        else if (!*arg && !av[1])
@@ -3609,17 +3608,17 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->output_format |= DIFF_FORMAT_SHORTSTAT;
        else if (!strcmp(arg, "-X") || !strcmp(arg, "--dirstat"))
                return parse_dirstat_opt(options, "");
-       else if (starts_with(arg, "-X"))
-               return parse_dirstat_opt(options, arg + 2);
-       else if (starts_with(arg, "--dirstat="))
-               return parse_dirstat_opt(options, arg + 10);
+       else if (skip_prefix(arg, "-X", &arg))
+               return parse_dirstat_opt(options, arg);
+       else if (skip_prefix(arg, "--dirstat=", &arg))
+               return parse_dirstat_opt(options, arg);
        else if (!strcmp(arg, "--cumulative"))
                return parse_dirstat_opt(options, "cumulative");
        else if (!strcmp(arg, "--dirstat-by-file"))
                return parse_dirstat_opt(options, "files");
-       else if (starts_with(arg, "--dirstat-by-file=")) {
+       else if (skip_prefix(arg, "--dirstat-by-file=", &arg)) {
                parse_dirstat_opt(options, "files");
-               return parse_dirstat_opt(options, arg + 18);
+               return parse_dirstat_opt(options, arg);
        }
        else if (!strcmp(arg, "--check"))
                options->output_format |= DIFF_FORMAT_CHECKDIFF;
@@ -3669,9 +3668,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                DIFF_OPT_CLR(options, RENAME_EMPTY);
        else if (!strcmp(arg, "--relative"))
                DIFF_OPT_SET(options, RELATIVE_NAME);
-       else if (starts_with(arg, "--relative=")) {
+       else if (skip_prefix(arg, "--relative=", &arg)) {
                DIFF_OPT_SET(options, RELATIVE_NAME);
-               options->prefix = arg + 11;
+               options->prefix = arg;
        }
 
        /* xdiff options */
@@ -3722,8 +3721,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                DIFF_OPT_CLR(options, FOLLOW_RENAMES);
        else if (!strcmp(arg, "--color"))
                options->use_color = 1;
-       else if (starts_with(arg, "--color=")) {
-               int value = git_config_colorbool(NULL, arg+8);
+       else if (skip_prefix(arg, "--color=", &arg)) {
+               int value = git_config_colorbool(NULL, arg);
                if (value < 0)
                        return error("option `color' expects \"always\", \"auto\", or \"never\"");
                options->use_color = value;
@@ -3734,29 +3733,28 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->use_color = 1;
                options->word_diff = DIFF_WORDS_COLOR;
        }
-       else if (starts_with(arg, "--color-words=")) {
+       else if (skip_prefix(arg, "--color-words=", &arg)) {
                options->use_color = 1;
                options->word_diff = DIFF_WORDS_COLOR;
-               options->word_regex = arg + 14;
+               options->word_regex = arg;
        }
        else if (!strcmp(arg, "--word-diff")) {
                if (options->word_diff == DIFF_WORDS_NONE)
                        options->word_diff = DIFF_WORDS_PLAIN;
        }
-       else if (starts_with(arg, "--word-diff=")) {
-               const char *type = arg + 12;
-               if (!strcmp(type, "plain"))
+       else if (skip_prefix(arg, "--word-diff=", &arg)) {
+               if (!strcmp(arg, "plain"))
                        options->word_diff = DIFF_WORDS_PLAIN;
-               else if (!strcmp(type, "color")) {
+               else if (!strcmp(arg, "color")) {
                        options->use_color = 1;
                        options->word_diff = DIFF_WORDS_COLOR;
                }
-               else if (!strcmp(type, "porcelain"))
+               else if (!strcmp(arg, "porcelain"))
                        options->word_diff = DIFF_WORDS_PORCELAIN;
-               else if (!strcmp(type, "none"))
+               else if (!strcmp(arg, "none"))
                        options->word_diff = DIFF_WORDS_NONE;
                else
-                       die("bad --word-diff argument: %s", type);
+                       die("bad --word-diff argument: %s", arg);
        }
        else if ((argcount = parse_long_opt("word-diff-regex", av, &optarg))) {
                if (options->word_diff == DIFF_WORDS_NONE)
@@ -3779,13 +3777,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if (!strcmp(arg, "--ignore-submodules")) {
                DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
                handle_ignore_submodules_arg(options, "all");
-       } else if (starts_with(arg, "--ignore-submodules=")) {
+       } else if (skip_prefix(arg, "--ignore-submodules=", &arg)) {
                DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
-               handle_ignore_submodules_arg(options, arg + 20);
+               handle_ignore_submodules_arg(options, arg);
        } else if (!strcmp(arg, "--submodule"))
                DIFF_OPT_SET(options, SUBMODULE_LOG);
-       else if (starts_with(arg, "--submodule="))
-               return parse_submodule_opt(options, arg + 12);
+       else if (skip_prefix(arg, "--submodule=", &arg))
+               return parse_submodule_opt(options, arg);
 
        /* misc options */
        else if (!strcmp(arg, "-z"))
@@ -3820,8 +3818,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
        else if (!strcmp(arg, "--abbrev"))
                options->abbrev = DEFAULT_ABBREV;
-       else if (starts_with(arg, "--abbrev=")) {
-               options->abbrev = strtoul(arg + 9, NULL, 10);
+       else if (skip_prefix(arg, "--abbrev=", &arg)) {
+               options->abbrev = strtoul(arg, NULL, 10);
                if (options->abbrev < MINIMUM_ABBREV)
                        options->abbrev = MINIMUM_ABBREV;
                else if (40 < options->abbrev)
@@ -3902,16 +3900,13 @@ static int diff_scoreopt_parse(const char *opt)
        cmd = *opt++;
        if (cmd == '-') {
                /* convert the long-form arguments into short-form versions */
-               if (starts_with(opt, "break-rewrites")) {
-                       opt += strlen("break-rewrites");
+               if (skip_prefix(opt, "break-rewrites", &opt)) {
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'B';
-               } else if (starts_with(opt, "find-copies")) {
-                       opt += strlen("find-copies");
+               } else if (skip_prefix(opt, "find-copies", &opt)) {
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'C';
-               } else if (starts_with(opt, "find-renames")) {
-                       opt += strlen("find-renames");
+               } else if (skip_prefix(opt, "find-renames", &opt)) {
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'M';
                }
index 4dac5e9edd75499ccf52debc847807d2fc180730..565f65293bb25ebdcb6ada262bcca9164c3ea113 100644 (file)
@@ -124,6 +124,12 @@ static char *expand_namespace(const char *raw_namespace)
        return strbuf_detach(&buf, NULL);
 }
 
+static char *git_path_from_env(const char *envvar, const char *path)
+{
+       const char *value = getenv(envvar);
+       return value ? xstrdup(value) : git_pathdup("%s", path);
+}
+
 static void setup_git_env(void)
 {
        const char *gitfile;
@@ -134,19 +140,9 @@ static void setup_git_env(void)
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
        gitfile = read_gitfile(git_dir);
        git_dir = xstrdup(gitfile ? gitfile : git_dir);
-       git_object_dir = getenv(DB_ENVIRONMENT);
-       if (!git_object_dir) {
-               git_object_dir = xmalloc(strlen(git_dir) + 9);
-               sprintf(git_object_dir, "%s/objects", git_dir);
-       }
-       git_index_file = getenv(INDEX_ENVIRONMENT);
-       if (!git_index_file) {
-               git_index_file = xmalloc(strlen(git_dir) + 7);
-               sprintf(git_index_file, "%s/index", git_dir);
-       }
-       git_graft_file = getenv(GRAFT_ENVIRONMENT);
-       if (!git_graft_file)
-               git_graft_file = git_pathdup("info/grafts");
+       git_object_dir = git_path_from_env(DB_ENVIRONMENT, "objects");
+       git_index_file = git_path_from_env(INDEX_ENVIRONMENT, "index");
+       git_graft_file = git_path_from_env(GRAFT_ENVIRONMENT, "info/grafts");
        if (getenv(NO_REPLACE_OBJECTS_ENVIRONMENT))
                check_replace_refs = 0;
        namespace = expand_namespace(getenv(GIT_NAMESPACE_ENVIRONMENT));
index 6707a66471f2038a0c826c840a201a7362de95ed..fa635f75c328354f7a4b44ca1e22461b1eb16de1 100644 (file)
@@ -371,8 +371,8 @@ static volatile sig_atomic_t checkpoint_requested;
 static int cat_blob_fd = STDOUT_FILENO;
 
 static void parse_argv(void);
-static void parse_cat_blob(void);
-static void parse_ls(struct branch *b);
+static void parse_cat_blob(const char *p);
+static void parse_ls(const char *p, struct branch *b);
 
 static void write_branch_report(FILE *rpt, struct branch *b)
 {
@@ -1861,6 +1861,8 @@ static int read_next_command(void)
        }
 
        for (;;) {
+               const char *p;
+
                if (unread_command_buf) {
                        unread_command_buf = 0;
                } else {
@@ -1893,8 +1895,8 @@ static int read_next_command(void)
                        rc->prev->next = rc;
                        cmd_tail = rc;
                }
-               if (starts_with(command_buf.buf, "cat-blob ")) {
-                       parse_cat_blob();
+               if (skip_prefix(command_buf.buf, "cat-blob ", &p)) {
+                       parse_cat_blob(p);
                        continue;
                }
                if (command_buf.buf[0] == '#')
@@ -1912,8 +1914,9 @@ static void skip_optional_lf(void)
 
 static void parse_mark(void)
 {
-       if (starts_with(command_buf.buf, "mark :")) {
-               next_mark = strtoumax(command_buf.buf + 6, NULL, 10);
+       const char *v;
+       if (skip_prefix(command_buf.buf, "mark :", &v)) {
+               next_mark = strtoumax(v, NULL, 10);
                read_next_command();
        }
        else
@@ -1922,14 +1925,15 @@ static void parse_mark(void)
 
 static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
 {
+       const char *data;
        strbuf_reset(sb);
 
-       if (!starts_with(command_buf.buf, "data "))
+       if (!skip_prefix(command_buf.buf, "data ", &data))
                die("Expected 'data n' command, found: %s", command_buf.buf);
 
-       if (starts_with(command_buf.buf + 5, "<<")) {
-               char *term = xstrdup(command_buf.buf + 5 + 2);
-               size_t term_len = command_buf.len - 5 - 2;
+       if (skip_prefix(data, "<<", &data)) {
+               char *term = xstrdup(data);
+               size_t term_len = command_buf.len - (data - command_buf.buf);
 
                strbuf_detach(&command_buf, NULL);
                for (;;) {
@@ -1944,7 +1948,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
                free(term);
        }
        else {
-               uintmax_t len = strtoumax(command_buf.buf + 5, NULL, 10);
+               uintmax_t len = strtoumax(data, NULL, 10);
                size_t n = 0, length = (size_t)len;
 
                if (limit && limit < len) {
@@ -2265,15 +2269,14 @@ static uintmax_t parse_mark_ref_space(const char **p)
        char *end;
 
        mark = parse_mark_ref(*p, &end);
-       if (*end != ' ')
+       if (*end++ != ' ')
                die("Missing space after mark: %s", command_buf.buf);
        *p = end;
        return mark;
 }
 
-static void file_change_m(struct branch *b)
+static void file_change_m(const char *p, struct branch *b)
 {
-       const char *p = command_buf.buf + 2;
        static struct strbuf uq = STRBUF_INIT;
        const char *endp;
        struct object_entry *oe;
@@ -2301,20 +2304,17 @@ static void file_change_m(struct branch *b)
        if (*p == ':') {
                oe = find_mark(parse_mark_ref_space(&p));
                hashcpy(sha1, oe->idx.sha1);
-       } else if (starts_with(p, "inline ")) {
+       } else if (skip_prefix(p, "inline ", &p)) {
                inline_data = 1;
                oe = NULL; /* not used with inline_data, but makes gcc happy */
-               p += strlen("inline");  /* advance to space */
        } else {
                if (get_sha1_hex(p, sha1))
                        die("Invalid dataref: %s", command_buf.buf);
                oe = find_object(sha1);
                p += 40;
-               if (*p != ' ')
+               if (*p++ != ' ')
                        die("Missing space after SHA1: %s", command_buf.buf);
        }
-       assert(*p == ' ');
-       p++;  /* skip space */
 
        strbuf_reset(&uq);
        if (!unquote_c_style(&uq, p, &endp)) {
@@ -2374,9 +2374,8 @@ static void file_change_m(struct branch *b)
        tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
 }
 
-static void file_change_d(struct branch *b)
+static void file_change_d(const char *p, struct branch *b)
 {
-       const char *p = command_buf.buf + 2;
        static struct strbuf uq = STRBUF_INIT;
        const char *endp;
 
@@ -2389,15 +2388,14 @@ static void file_change_d(struct branch *b)
        tree_content_remove(&b->branch_tree, p, NULL, 1);
 }
 
-static void file_change_cr(struct branch *b, int rename)
+static void file_change_cr(const char *s, struct branch *b, int rename)
 {
-       const char *s, *d;
+       const char *d;
        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;
        strbuf_reset(&s_uq);
        if (!unquote_c_style(&s_uq, s, &endp)) {
                if (*endp != ' ')
@@ -2442,9 +2440,8 @@ static void file_change_cr(struct branch *b, int rename)
                leaf.tree);
 }
 
-static void note_change_n(struct branch *b, unsigned char *old_fanout)
+static void note_change_n(const char *p, struct branch *b, unsigned char *old_fanout)
 {
-       const char *p = command_buf.buf + 2;
        static struct strbuf uq = STRBUF_INIT;
        struct object_entry *oe;
        struct branch *s;
@@ -2474,20 +2471,17 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
        if (*p == ':') {
                oe = find_mark(parse_mark_ref_space(&p));
                hashcpy(sha1, oe->idx.sha1);
-       } else if (starts_with(p, "inline ")) {
+       } else if (skip_prefix(p, "inline ", &p)) {
                inline_data = 1;
                oe = NULL; /* not used with inline_data, but makes gcc happy */
-               p += strlen("inline");  /* advance to space */
        } else {
                if (get_sha1_hex(p, sha1))
                        die("Invalid dataref: %s", command_buf.buf);
                oe = find_object(sha1);
                p += 40;
-               if (*p != ' ')
+               if (*p++ != ' ')
                        die("Missing space after SHA1: %s", command_buf.buf);
        }
-       assert(*p == ' ');
-       p++;  /* skip space */
 
        /* <commit-ish> */
        s = lookup_branch(p);
@@ -2585,7 +2579,7 @@ static int parse_from(struct branch *b)
        const char *from;
        struct branch *s;
 
-       if (!starts_with(command_buf.buf, "from "))
+       if (!skip_prefix(command_buf.buf, "from ", &from))
                return 0;
 
        if (b->branch_tree.tree) {
@@ -2593,7 +2587,6 @@ static int parse_from(struct branch *b)
                b->branch_tree.tree = NULL;
        }
 
-       from = strchr(command_buf.buf, ' ') + 1;
        s = lookup_branch(from);
        if (b == s)
                die("Can't create a branch from itself: %s", b->name);
@@ -2634,8 +2627,7 @@ static struct hash_list *parse_merge(unsigned int *count)
        struct branch *s;
 
        *count = 0;
-       while (starts_with(command_buf.buf, "merge ")) {
-               from = strchr(command_buf.buf, ' ') + 1;
+       while (skip_prefix(command_buf.buf, "merge ", &from)) {
                n = xmalloc(sizeof(*n));
                s = lookup_branch(from);
                if (s)
@@ -2666,31 +2658,29 @@ static struct hash_list *parse_merge(unsigned int *count)
        return list;
 }
 
-static void parse_new_commit(void)
+static void parse_new_commit(const char *arg)
 {
        static struct strbuf msg = STRBUF_INIT;
        struct branch *b;
-       char *sp;
        char *author = NULL;
        char *committer = NULL;
        struct hash_list *merge_list = NULL;
        unsigned int merge_count;
        unsigned char prev_fanout, new_fanout;
+       const char *v;
 
-       /* Obtain the branch name from the rest of our command */
-       sp = strchr(command_buf.buf, ' ') + 1;
-       b = lookup_branch(sp);
+       b = lookup_branch(arg);
        if (!b)
-               b = new_branch(sp);
+               b = new_branch(arg);
 
        read_next_command();
        parse_mark();
-       if (starts_with(command_buf.buf, "author ")) {
-               author = parse_ident(command_buf.buf + 7);
+       if (skip_prefix(command_buf.buf, "author ", &v)) {
+               author = parse_ident(v);
                read_next_command();
        }
-       if (starts_with(command_buf.buf, "committer ")) {
-               committer = parse_ident(command_buf.buf + 10);
+       if (skip_prefix(command_buf.buf, "committer ", &v)) {
+               committer = parse_ident(v);
                read_next_command();
        }
        if (!committer)
@@ -2710,20 +2700,20 @@ static void parse_new_commit(void)
 
        /* file_change* */
        while (command_buf.len > 0) {
-               if (starts_with(command_buf.buf, "M "))
-                       file_change_m(b);
-               else if (starts_with(command_buf.buf, "D "))
-                       file_change_d(b);
-               else if (starts_with(command_buf.buf, "R "))
-                       file_change_cr(b, 1);
-               else if (starts_with(command_buf.buf, "C "))
-                       file_change_cr(b, 0);
-               else if (starts_with(command_buf.buf, "N "))
-                       note_change_n(b, &prev_fanout);
+               if (skip_prefix(command_buf.buf, "M ", &v))
+                       file_change_m(v, b);
+               else if (skip_prefix(command_buf.buf, "D ", &v))
+                       file_change_d(v, b);
+               else if (skip_prefix(command_buf.buf, "R ", &v))
+                       file_change_cr(v, b, 1);
+               else if (skip_prefix(command_buf.buf, "C ", &v))
+                       file_change_cr(v, b, 0);
+               else if (skip_prefix(command_buf.buf, "N ", &v))
+                       note_change_n(v, b, &prev_fanout);
                else if (!strcmp("deleteall", command_buf.buf))
                        file_change_deleteall(b);
-               else if (starts_with(command_buf.buf, "ls "))
-                       parse_ls(b);
+               else if (skip_prefix(command_buf.buf, "ls ", &v))
+                       parse_ls(v, b);
                else {
                        unread_command_buf = 1;
                        break;
@@ -2766,10 +2756,9 @@ static void parse_new_commit(void)
        b->last_commit = object_count_by_type[OBJ_COMMIT];
 }
 
-static void parse_new_tag(void)
+static void parse_new_tag(const char *arg)
 {
        static struct strbuf msg = STRBUF_INIT;
-       char *sp;
        const char *from;
        char *tagger;
        struct branch *s;
@@ -2777,12 +2766,11 @@ static void parse_new_tag(void)
        uintmax_t from_mark = 0;
        unsigned char sha1[20];
        enum object_type type;
+       const char *v;
 
-       /* Obtain the new tag name from the rest of our command */
-       sp = strchr(command_buf.buf, ' ') + 1;
        t = pool_alloc(sizeof(struct tag));
        memset(t, 0, sizeof(struct tag));
-       t->name = pool_strdup(sp);
+       t->name = pool_strdup(arg);
        if (last_tag)
                last_tag->next_tag = t;
        else
@@ -2791,9 +2779,8 @@ static void parse_new_tag(void)
        read_next_command();
 
        /* from ... */
-       if (!starts_with(command_buf.buf, "from "))
+       if (!skip_prefix(command_buf.buf, "from ", &from))
                die("Expected from command, got %s", command_buf.buf);
-       from = strchr(command_buf.buf, ' ') + 1;
        s = lookup_branch(from);
        if (s) {
                if (is_null_sha1(s->sha1))
@@ -2819,8 +2806,8 @@ static void parse_new_tag(void)
        read_next_command();
 
        /* tagger ... */
-       if (starts_with(command_buf.buf, "tagger ")) {
-               tagger = parse_ident(command_buf.buf + 7);
+       if (skip_prefix(command_buf.buf, "tagger ", &v)) {
+               tagger = parse_ident(v);
                read_next_command();
        } else
                tagger = NULL;
@@ -2849,14 +2836,11 @@ static void parse_new_tag(void)
                t->pack_id = pack_id;
 }
 
-static void parse_reset_branch(void)
+static void parse_reset_branch(const char *arg)
 {
        struct branch *b;
-       char *sp;
 
-       /* Obtain the branch name from the rest of our command */
-       sp = strchr(command_buf.buf, ' ') + 1;
-       b = lookup_branch(sp);
+       b = lookup_branch(arg);
        if (b) {
                hashclr(b->sha1);
                hashclr(b->branch_tree.versions[0].sha1);
@@ -2867,7 +2851,7 @@ static void parse_reset_branch(void)
                }
        }
        else
-               b = new_branch(sp);
+               b = new_branch(arg);
        read_next_command();
        parse_from(b);
        if (command_buf.len > 0)
@@ -2925,14 +2909,12 @@ static void cat_blob(struct object_entry *oe, unsigned char sha1[20])
                free(buf);
 }
 
-static void parse_cat_blob(void)
+static void parse_cat_blob(const char *p)
 {
-       const char *p;
        struct object_entry *oe = oe;
        unsigned char sha1[20];
 
        /* cat-blob SP <object> LF */
-       p = command_buf.buf + strlen("cat-blob ");
        if (*p == ':') {
                oe = find_mark(parse_mark_ref_eol(p));
                if (!oe)
@@ -3015,6 +2997,8 @@ static struct object_entry *parse_treeish_dataref(const char **p)
                        die("Invalid dataref: %s", command_buf.buf);
                e = find_object(sha1);
                *p += 40;
+               if (*(*p)++ != ' ')
+                       die("Missing space after tree-ish: %s", command_buf.buf);
        }
 
        while (!e || e->type != OBJ_TREE)
@@ -3049,14 +3033,12 @@ static void print_ls(int mode, const unsigned char *sha1, const char *path)
        cat_blob_write(line.buf, line.len);
 }
 
-static void parse_ls(struct branch *b)
+static void parse_ls(const char *p, struct branch *b)
 {
-       const char *p;
        struct tree_entry *root = NULL;
        struct tree_entry leaf = {NULL};
 
        /* ls SP (<tree-ish> SP)? <path> */
-       p = command_buf.buf + strlen("ls ");
        if (*p == '"') {
                if (!b)
                        die("Not in a commit: %s", command_buf.buf);
@@ -3068,8 +3050,6 @@ static void parse_ls(struct branch *b)
                if (!is_null_sha1(root->versions[1].sha1))
                        root->versions[1].mode = S_IFDIR;
                load_tree(root);
-               if (*p++ != ' ')
-                       die("Missing space after tree-ish: %s", command_buf.buf);
        }
        if (*p == '"') {
                static struct strbuf uq = STRBUF_INIT;
@@ -3207,9 +3187,9 @@ static void option_export_pack_edges(const char *edges)
 
 static int parse_one_option(const char *option)
 {
-       if (starts_with(option, "max-pack-size=")) {
+       if (skip_prefix(option, "max-pack-size=", &option)) {
                unsigned long v;
-               if (!git_parse_ulong(option + 14, &v))
+               if (!git_parse_ulong(option, &v))
                        return 0;
                if (v < 8192) {
                        warning("max-pack-size is now in bytes, assuming --max-pack-size=%lum", v);
@@ -3219,17 +3199,17 @@ static int parse_one_option(const char *option)
                        v = 1024 * 1024;
                }
                max_packsize = v;
-       } else if (starts_with(option, "big-file-threshold=")) {
+       } else if (skip_prefix(option, "big-file-threshold=", &option)) {
                unsigned long v;
-               if (!git_parse_ulong(option + 19, &v))
+               if (!git_parse_ulong(option, &v))
                        return 0;
                big_file_threshold = v;
-       } else if (starts_with(option, "depth=")) {
-               option_depth(option + 6);
-       } else if (starts_with(option, "active-branches=")) {
-               option_active_branches(option + 16);
-       } else if (starts_with(option, "export-pack-edges=")) {
-               option_export_pack_edges(option + 18);
+       } else if (skip_prefix(option, "depth=", &option)) {
+               option_depth(option);
+       } else if (skip_prefix(option, "active-branches=", &option)) {
+               option_active_branches(option);
+       } else if (skip_prefix(option, "export-pack-edges=", &option)) {
+               option_export_pack_edges(option);
        } else if (starts_with(option, "quiet")) {
                show_stats = 0;
        } else if (starts_with(option, "stats")) {
@@ -3243,15 +3223,16 @@ static int parse_one_option(const char *option)
 
 static int parse_one_feature(const char *feature, int from_stream)
 {
-       if (starts_with(feature, "date-format=")) {
-               option_date_format(feature + 12);
-       } else if (starts_with(feature, "import-marks=")) {
-               option_import_marks(feature + 13, from_stream, 0);
-       } else if (starts_with(feature, "import-marks-if-exists=")) {
-               option_import_marks(feature + strlen("import-marks-if-exists="),
-                                       from_stream, 1);
-       } else if (starts_with(feature, "export-marks=")) {
-               option_export_marks(feature + 13);
+       const char *arg;
+
+       if (skip_prefix(feature, "date-format=", &arg)) {
+               option_date_format(arg);
+       } else if (skip_prefix(feature, "import-marks=", &arg)) {
+               option_import_marks(arg, from_stream, 0);
+       } else if (skip_prefix(feature, "import-marks-if-exists=", &arg)) {
+               option_import_marks(arg, from_stream, 1);
+       } else if (skip_prefix(feature, "export-marks=", &arg)) {
+               option_export_marks(arg);
        } else if (!strcmp(feature, "cat-blob")) {
                ; /* Don't die - this feature is supported */
        } else if (!strcmp(feature, "relative-marks")) {
@@ -3271,10 +3252,8 @@ static int parse_one_feature(const char *feature, int from_stream)
        return 1;
 }
 
-static void parse_feature(void)
+static void parse_feature(const char *feature)
 {
-       char *feature = command_buf.buf + 8;
-
        if (seen_data_command)
                die("Got feature command '%s' after data command", feature);
 
@@ -3284,10 +3263,8 @@ static void parse_feature(void)
        die("This version of fast-import does not support feature %s.", feature);
 }
 
-static void parse_option(void)
+static void parse_option(const char *option)
 {
-       char *option = command_buf.buf + 11;
-
        if (seen_data_command)
                die("Got option command '%s' after data command", option);
 
@@ -3342,18 +3319,21 @@ static void parse_argv(void)
                if (*a != '-' || !strcmp(a, "--"))
                        break;
 
-               if (parse_one_option(a + 2))
+               if (!skip_prefix(a, "--", &a))
+                       die("unknown option %s", a);
+
+               if (parse_one_option(a))
                        continue;
 
-               if (parse_one_feature(a + 2, 0))
+               if (parse_one_feature(a, 0))
                        continue;
 
-               if (starts_with(a + 2, "cat-blob-fd=")) {
-                       option_cat_blob_fd(a + 2 + strlen("cat-blob-fd="));
+               if (skip_prefix(a, "cat-blob-fd=", &a)) {
+                       option_cat_blob_fd(a);
                        continue;
                }
 
-               die("unknown option %s", a);
+               die("unknown option --%s", a);
        }
        if (i != global_argc)
                usage(fast_import_usage);
@@ -3400,26 +3380,27 @@ int main(int argc, char **argv)
        set_die_routine(die_nicely);
        set_checkpoint_signal();
        while (read_next_command() != EOF) {
+               const char *v;
                if (!strcmp("blob", command_buf.buf))
                        parse_new_blob();
-               else if (starts_with(command_buf.buf, "ls "))
-                       parse_ls(NULL);
-               else if (starts_with(command_buf.buf, "commit "))
-                       parse_new_commit();
-               else if (starts_with(command_buf.buf, "tag "))
-                       parse_new_tag();
-               else if (starts_with(command_buf.buf, "reset "))
-                       parse_reset_branch();
+               else if (skip_prefix(command_buf.buf, "ls ", &v))
+                       parse_ls(v, NULL);
+               else if (skip_prefix(command_buf.buf, "commit ", &v))
+                       parse_new_commit(v);
+               else if (skip_prefix(command_buf.buf, "tag ", &v))
+                       parse_new_tag(v);
+               else if (skip_prefix(command_buf.buf, "reset ", &v))
+                       parse_reset_branch(v);
                else if (!strcmp("checkpoint", command_buf.buf))
                        parse_checkpoint();
                else if (!strcmp("done", command_buf.buf))
                        break;
                else if (starts_with(command_buf.buf, "progress "))
                        parse_progress();
-               else if (starts_with(command_buf.buf, "feature "))
-                       parse_feature();
-               else if (starts_with(command_buf.buf, "option git "))
-                       parse_option();
+               else if (skip_prefix(command_buf.buf, "feature ", &v))
+                       parse_feature(v);
+               else if (skip_prefix(command_buf.buf, "option git ", &v))
+                       parse_option(v);
                else if (starts_with(command_buf.buf, "option "))
                        /* ignore non-git options*/;
                else
index b12bd4c59a1105f4d3a82bbbd5208e3f7ebae0bb..b8a58fa7a542fe166ad71c9b17a4908c81d24a4f 100644 (file)
@@ -189,20 +189,23 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)
 {
        int len;
        char *line = packet_read_line(fd, &len);
+       const char *arg;
 
        if (!len)
                die("git fetch-pack: expected ACK/NAK, got EOF");
        if (!strcmp(line, "NAK"))
                return NAK;
-       if (starts_with(line, "ACK ")) {
-               if (!get_sha1_hex(line+4, result_sha1)) {
-                       if (len < 45)
+       if (skip_prefix(line, "ACK ", &arg)) {
+               if (!get_sha1_hex(arg, result_sha1)) {
+                       arg += 40;
+                       len -= arg - line;
+                       if (len < 1)
                                return ACK;
-                       if (strstr(line+45, "continue"))
+                       if (strstr(arg, "continue"))
                                return ACK_continue;
-                       if (strstr(line+45, "common"))
+                       if (strstr(arg, "common"))
                                return ACK_common;
-                       if (strstr(line+45, "ready"))
+                       if (strstr(arg, "ready"))
                                return ACK_ready;
                        return ACK;
                }
@@ -319,18 +322,19 @@ static int find_common(struct fetch_pack_args *args,
 
        if (args->depth > 0) {
                char *line;
+               const char *arg;
                unsigned char sha1[20];
 
                send_request(args, fd[1], &req_buf);
                while ((line = packet_read_line(fd[0], NULL))) {
-                       if (starts_with(line, "shallow ")) {
-                               if (get_sha1_hex(line + 8, sha1))
+                       if (skip_prefix(line, "shallow ", &arg)) {
+                               if (get_sha1_hex(arg, sha1))
                                        die("invalid shallow line: %s", line);
                                register_shallow(sha1);
                                continue;
                        }
-                       if (starts_with(line, "unshallow ")) {
-                               if (get_sha1_hex(line + 10, sha1))
+                       if (skip_prefix(line, "unshallow ", &arg)) {
+                               if (get_sha1_hex(arg, sha1))
                                        die("invalid unshallow line: %s", line);
                                if (!lookup_object(sha1))
                                        die("object not found: %s", line);
diff --git a/fsck.c b/fsck.c
index a7233c8d0b20c06f0aebffbec9c11dacb22b6769..a4e8593e78c85c244d2dc8bac0cca838c14bbd4a 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -279,20 +279,17 @@ static int fsck_ident(const char **ident, struct object *obj, fsck_error error_f
 static int fsck_commit_buffer(struct commit *commit, const char *buffer,
                              fsck_error error_func)
 {
-       const char *tmp;
        unsigned char tree_sha1[20], sha1[20];
        struct commit_graft *graft;
        int parents = 0;
        int err;
 
-       buffer = skip_prefix(buffer, "tree ");
-       if (!buffer)
+       if (!skip_prefix(buffer, "tree ", &buffer))
                return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line");
        if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n')
                return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1");
        buffer += 41;
-       while ((tmp = skip_prefix(buffer, "parent "))) {
-               buffer = tmp;
+       while (skip_prefix(buffer, "parent ", &buffer)) {
                if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n')
                        return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1");
                buffer += 41;
@@ -319,14 +316,12 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
                if (p || parents)
                        return error_func(&commit->object, FSCK_ERROR, "parent objects missing");
        }
-       buffer = skip_prefix(buffer, "author ");
-       if (!buffer)
+       if (!skip_prefix(buffer, "author ", &buffer))
                return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line");
        err = fsck_ident(&buffer, &commit->object, error_func);
        if (err)
                return err;
-       buffer = skip_prefix(buffer, "committer ");
-       if (!buffer)
+       if (!skip_prefix(buffer, "committer ", &buffer))
                return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'committer' line");
        err = fsck_ident(&buffer, &commit->object, error_func);
        if (err)
index 96f55547a379bc1bdc488fa4557360bbfd1ae253..9de31807108322aac327f66822d4929974d7ffd5 100644 (file)
@@ -349,13 +349,32 @@ extern void set_die_is_recursing_routine(int (*routine)(void));
 extern int starts_with(const char *str, const char *prefix);
 extern int ends_with(const char *str, const char *suffix);
 
-static inline const char *skip_prefix(const char *str, const char *prefix)
+/*
+ * If the string "str" begins with the string found in "prefix", return 1.
+ * The "out" parameter is set to "str + strlen(prefix)" (i.e., to the point in
+ * the string right after the prefix).
+ *
+ * Otherwise, return 0 and leave "out" untouched.
+ *
+ * Examples:
+ *
+ *   [extract branch name, fail if not a branch]
+ *   if (!skip_prefix(ref, "refs/heads/", &branch)
+ *     return -1;
+ *
+ *   [skip prefix if present, otherwise use whole string]
+ *   skip_prefix(name, "refs/heads/", &name);
+ */
+static inline int skip_prefix(const char *str, const char *prefix,
+                             const char **out)
 {
        do {
-               if (!*prefix)
-                       return str;
+               if (!*prefix) {
+                       *out = str;
+                       return 1;
+               }
        } while (*str++ == *prefix++);
-       return NULL;
+       return 0;
 }
 
 #if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
diff --git a/git.c b/git.c
index d6b4a5543f77071aff977f6d58e3ab6c5495f19d..5b6c7611be93c535491bbc9ba027e3acbad0db8f 100644 (file)
--- a/git.c
+++ b/git.c
@@ -91,8 +91,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                /*
                 * Check remaining flags.
                 */
-               if (starts_with(cmd, "--exec-path")) {
-                       cmd += 11;
+               if (skip_prefix(cmd, "--exec-path", &cmd)) {
                        if (*cmd == '=')
                                git_set_argv_exec_path(cmd + 1);
                        else {
@@ -129,8 +128,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                                *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
-               } else if (starts_with(cmd, "--git-dir=")) {
-                       setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
+               } else if (skip_prefix(cmd, "--git-dir=", &cmd)) {
+                       setenv(GIT_DIR_ENVIRONMENT, cmd, 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--namespace")) {
@@ -143,8 +142,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                                *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
-               } else if (starts_with(cmd, "--namespace=")) {
-                       setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1);
+               } else if (skip_prefix(cmd, "--namespace=", &cmd)) {
+                       setenv(GIT_NAMESPACE_ENVIRONMENT, cmd, 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--work-tree")) {
@@ -157,8 +156,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                                *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
-               } else if (starts_with(cmd, "--work-tree=")) {
-                       setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
+               } else if (skip_prefix(cmd, "--work-tree=", &cmd)) {
+                       setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "--bare")) {
@@ -479,6 +478,7 @@ static struct cmd_struct commands[] = {
        { "upload-archive", cmd_upload_archive },
        { "upload-archive--writer", cmd_upload_archive_writer },
        { "var", cmd_var, RUN_SETUP_GENTLY },
+       { "verify-commit", cmd_verify_commit, RUN_SETUP },
        { "verify-pack", cmd_verify_pack },
        { "verify-tag", cmd_verify_tag, RUN_SETUP },
        { "version", cmd_version },
@@ -623,8 +623,7 @@ int main(int argc, char **av)
         * So we just directly call the builtin handler, and die if
         * that one cannot handle it.
         */
-       if (starts_with(cmd, "git-")) {
-               cmd += 4;
+       if (skip_prefix(cmd, "git-", &cmd)) {
                argv[0] = cmd;
                handle_builtin(argc, argv);
                die("cannot handle %s as a builtin", cmd);
@@ -635,8 +634,8 @@ int main(int argc, char **av)
        argc--;
        handle_options(&argv, &argc, NULL);
        if (argc > 0) {
-               if (starts_with(argv[0], "--"))
-                       argv[0] += 2;
+               /* translate --help and --version into commands */
+               skip_prefix(argv[0], "--", &argv[0]);
        } else {
                /* The user didn't specify a command; give them help */
                commit_pager_choice();
index 8b0e87436b687ce26e3e4987129a2fc171069280..ff07012726ea28daa2551966d0555d2e8efa2375 100644 (file)
@@ -7,6 +7,20 @@
 static char *configured_signing_key;
 static const char *gpg_program = "gpg";
 
+void signature_check_clear(struct signature_check *sigc)
+{
+       free(sigc->payload);
+       free(sigc->gpg_output);
+       free(sigc->gpg_status);
+       free(sigc->signer);
+       free(sigc->key);
+       sigc->payload = NULL;
+       sigc->gpg_output = NULL;
+       sigc->gpg_status = NULL;
+       sigc->signer = NULL;
+       sigc->key = NULL;
+}
+
 void set_signing_key(const char *key)
 {
        free(configured_signing_key);
index a85cb5bc97cdd61000b4c48c54faa656aa3cfaca..37c23daff010b0de18fa12ff6a6167f45ff41ffc 100644 (file)
@@ -2,6 +2,7 @@
 #define GPG_INTERFACE_H
 
 struct signature_check {
+       char *payload;
        char *gpg_output;
        char *gpg_status;
        char result; /* 0 (not checked),
@@ -13,6 +14,7 @@ struct signature_check {
        char *key;
 };
 
+extern void signature_check_clear(struct signature_check *sigc);
 extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key);
 extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output, struct strbuf *gpg_status);
 extern int git_gpg_config(const char *, const char *, void *);
diff --git a/help.c b/help.c
index b266b09320c067221eb4fffa56e4778d5f8b3a9e..f31f29ac421e224a59726fc1f2dfc16d92faad0f 100644 (file)
--- a/help.c
+++ b/help.c
@@ -129,7 +129,6 @@ static void list_commands_in_dir(struct cmdnames *cmds,
                                         const char *path,
                                         const char *prefix)
 {
-       int prefix_len;
        DIR *dir = opendir(path);
        struct dirent *de;
        struct strbuf buf = STRBUF_INIT;
@@ -139,15 +138,15 @@ static void list_commands_in_dir(struct cmdnames *cmds,
                return;
        if (!prefix)
                prefix = "git-";
-       prefix_len = strlen(prefix);
 
        strbuf_addf(&buf, "%s/", path);
        len = buf.len;
 
        while ((de = readdir(dir)) != NULL) {
+               const char *ent;
                int entlen;
 
-               if (!starts_with(de->d_name, prefix))
+               if (!skip_prefix(de->d_name, prefix, &ent))
                        continue;
 
                strbuf_setlen(&buf, len);
@@ -155,11 +154,11 @@ static void list_commands_in_dir(struct cmdnames *cmds,
                if (!is_executable(buf.buf))
                        continue;
 
-               entlen = strlen(de->d_name) - prefix_len;
-               if (has_extension(de->d_name, ".exe"))
+               entlen = strlen(ent);
+               if (has_extension(ent, ".exe"))
                        entlen -= 4;
 
-               add_cmdname(cmds, de->d_name + prefix_len, entlen);
+               add_cmdname(cmds, ent, entlen);
        }
        closedir(dir);
        strbuf_release(&buf);
@@ -251,11 +250,13 @@ static struct cmdnames aliases;
 
 static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
 {
+       const char *p;
+
        if (!strcmp(var, "help.autocorrect"))
                autocorrect = git_config_int(var,value);
        /* Also use aliases for command lookup */
-       if (starts_with(var, "alias."))
-               add_cmdname(&aliases, var + 6, strlen(var + 6));
+       if (skip_prefix(var, "alias.", &p))
+               add_cmdname(&aliases, p, strlen(p));
 
        return git_default_config(var, value, cb);
 }
@@ -412,11 +413,12 @@ static int append_similar_ref(const char *refname, const unsigned char *sha1,
 {
        struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
        char *branch = strrchr(refname, '/') + 1;
+       const char *remote;
+
        /* A remote branch of the same name is deemed similar */
-       if (starts_with(refname, "refs/remotes/") &&
+       if (skip_prefix(refname, "refs/remotes/", &remote) &&
            !strcmp(branch, cb->base_ref))
-               string_list_append(cb->similar_refs,
-                                  refname + strlen("refs/remotes/"));
+               string_list_append(cb->similar_refs, remote);
        return 0;
 }
 
index d2c0a625cef558df252af6927cd3a86424674862..57290d9bdafc730afaac3ddf8564d85ead39eb31 100644 (file)
@@ -221,17 +221,19 @@ static void get_idx_file(char *name)
 
 static int http_config(const char *var, const char *value, void *cb)
 {
+       const char *p;
+
        if (!strcmp(var, "http.getanyfile")) {
                getanyfile = git_config_bool(var, value);
                return 0;
        }
 
-       if (starts_with(var, "http.")) {
+       if (skip_prefix(var, "http.", &p)) {
                int i;
 
                for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
                        struct rpc_service *svc = &rpc_service[i];
-                       if (!strcmp(var + 5, svc->config_name)) {
+                       if (!strcmp(p, svc->config_name)) {
                                svc->enabled = git_config_bool(var, value);
                                return 0;
                        }
@@ -244,15 +246,16 @@ static int http_config(const char *var, const char *value, void *cb)
 
 static struct rpc_service *select_service(const char *name)
 {
+       const char *svc_name;
        struct rpc_service *svc = NULL;
        int i;
 
-       if (!starts_with(name, "git-"))
+       if (!skip_prefix(name, "git-", &svc_name))
                forbidden("Unsupported service: '%s'", name);
 
        for (i = 0; i < ARRAY_SIZE(rpc_service); i++) {
                struct rpc_service *s = &rpc_service[i];
-               if (!strcmp(s->name, name + 4)) {
+               if (!strcmp(s->name, svc_name)) {
                        svc = s;
                        break;
                }
index de00d1693af902713ab5562e9d87fe621b02f955..6c3cc1725a9461876c7db11b9818eb553afb2fc2 100644 (file)
@@ -719,14 +719,10 @@ static int fetch_indices(void)
        return ret;
 }
 
-static void one_remote_object(const char *hex)
+static void one_remote_object(const unsigned char *sha1)
 {
-       unsigned char sha1[20];
        struct object *obj;
 
-       if (get_sha1_hex(hex, sha1) != 0)
-               return;
-
        obj = lookup_object(sha1);
        if (!obj)
                obj = parse_object(sha1);
@@ -767,15 +763,13 @@ static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
 
        if (tag_closed && ctx->cdata) {
                if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) {
-                       lock->owner = xmalloc(strlen(ctx->cdata) + 1);
-                       strcpy(lock->owner, ctx->cdata);
+                       lock->owner = xstrdup(ctx->cdata);
                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
-                       if (starts_with(ctx->cdata, "Second-"))
-                               lock->timeout =
-                                       strtol(ctx->cdata + 7, NULL, 10);
+                       const char *arg;
+                       if (skip_prefix(ctx->cdata, "Second-", &arg))
+                               lock->timeout = strtol(arg, NULL, 10);
                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
-                       lock->token = xmalloc(strlen(ctx->cdata) + 1);
-                       strcpy(lock->token, ctx->cdata);
+                       lock->token = xstrdup(ctx->cdata);
 
                        git_SHA1_Init(&sha_ctx);
                        git_SHA1_Update(&sha_ctx, lock->token, strlen(lock->token));
@@ -856,8 +850,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        struct xml_ctx ctx;
        char *escaped;
 
-       url = xmalloc(strlen(repo->url) + strlen(path) + 1);
-       sprintf(url, "%s%s", repo->url, path);
+       url = xstrfmt("%s%s", repo->url, path);
 
        /* Make sure leading directories exist for the remote ref */
        ep = strchr(url + strlen(repo->url) + 1, '/');
@@ -1020,26 +1013,38 @@ static void remote_ls(const char *path, int flags,
                      void (*userFunc)(struct remote_ls_ctx *ls),
                      void *userData);
 
+/* extract hex from sharded "xx/x{40}" filename */
+static int get_sha1_hex_from_objpath(const char *path, unsigned char *sha1)
+{
+       char hex[40];
+
+       if (strlen(path) != 41)
+               return -1;
+
+       memcpy(hex, path, 2);
+       path += 2;
+       path++; /* skip '/' */
+       memcpy(hex, path, 38);
+
+       return get_sha1_hex(hex, sha1);
+}
+
 static void process_ls_object(struct remote_ls_ctx *ls)
 {
        unsigned int *parent = (unsigned int *)ls->userData;
-       char *path = ls->dentry_name;
-       char *obj_hex;
+       const char *path = ls->dentry_name;
+       unsigned char sha1[20];
 
        if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) {
                remote_dir_exists[*parent] = 1;
                return;
        }
 
-       if (strlen(path) != 49)
+       if (!skip_prefix(path, "objects/", &path) ||
+           get_sha1_hex_from_objpath(path, sha1))
                return;
-       path += 8;
-       obj_hex = xmalloc(strlen(path));
-       /* NB: path is not null-terminated, can not use strlcpy here */
-       memcpy(obj_hex, path, 2);
-       strcpy(obj_hex + 2, path + 3);
-       one_remote_object(obj_hex);
-       free(obj_hex);
+
+       one_remote_object(sha1);
 }
 
 static void process_ls_ref(struct remote_ls_ctx *ls)
@@ -1117,7 +1122,7 @@ static void remote_ls(const char *path, int flags,
                      void (*userFunc)(struct remote_ls_ctx *ls),
                      void *userData)
 {
-       char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
+       char *url = xstrfmt("%s%s", repo->url, path);
        struct active_request_slot *slot;
        struct slot_results results;
        struct strbuf in_buffer = STRBUF_INIT;
@@ -1133,8 +1138,6 @@ static void remote_ls(const char *path, int flags,
        ls.userData = userData;
        ls.userFunc = userFunc;
 
-       sprintf(url, "%s%s", repo->url, path);
-
        strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST);
 
        dav_headers = curl_slist_append(dav_headers, "Depth: 1");
@@ -1536,10 +1539,9 @@ static void update_remote_info_refs(struct remote_lock *lock)
 
 static int remote_exists(const char *path)
 {
-       char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
+       char *url = xstrfmt("%s%s", repo->url, path);
        int ret;
 
-       sprintf(url, "%s%s", repo->url, path);
 
        switch (http_get_strbuf(url, NULL, NULL)) {
        case HTTP_OK:
@@ -1559,11 +1561,9 @@ static int remote_exists(const char *path)
 
 static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
 {
-       char *url;
+       char *url = xstrfmt("%s%s", repo->url, path);
        struct strbuf buffer = STRBUF_INIT;
-
-       url = xmalloc(strlen(repo->url) + strlen(path) + 1);
-       sprintf(url, "%s%s", repo->url, path);
+       const char *name;
 
        if (http_get_strbuf(url, &buffer, NULL) != HTTP_OK)
                die("Couldn't get %s for remote symref\n%s", url,
@@ -1578,8 +1578,8 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
                return;
 
        /* If it's a symref, set the refname; otherwise try for a sha1 */
-       if (starts_with((char *)buffer.buf, "ref: ")) {
-               *symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
+       if (skip_prefix(buffer.buf, "ref: ", &name)) {
+               *symref = xmemdupz(name, buffer.len - (name - buffer.buf));
        } else {
                get_sha1_hex(buffer.buf, sha1);
        }
@@ -1673,8 +1673,7 @@ static int delete_remote_branch(const char *pattern, int force)
        fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
        if (dry_run)
                return 0;
-       url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1);
-       sprintf(url, "%s%s", repo->url, remote_ref->name);
+       url = xstrfmt("%s%s", repo->url, remote_ref->name);
        slot = get_active_slot();
        slot->results = &results;
        curl_setup_http_get(slot->curl, url, DAV_DELETE);
index 1516c5eb290746bad4551515fda7930d2f55d32b..dbddfaa1773265a2917d4715158f16845d7139e5 100644 (file)
@@ -341,8 +341,7 @@ static void fetch_alternates(struct walker *walker, const char *base)
        if (walker->get_verbosely)
                fprintf(stderr, "Getting alternates list for %s\n", base);
 
-       url = xmalloc(strlen(base) + 31);
-       sprintf(url, "%s/objects/info/http-alternates", base);
+       url = xstrfmt("%s/objects/info/http-alternates", base);
 
        /*
         * Use a callback to process the result, since another request
@@ -566,8 +565,7 @@ struct walker *get_http_walker(const char *url)
        struct walker *walker = xmalloc(sizeof(struct walker));
 
        data->alt = xmalloc(sizeof(*data->alt));
-       data->alt->base = xmalloc(strlen(url) + 1);
-       strcpy(data->alt->base, url);
+       data->alt->base = xstrdup(url);
        for (s = data->alt->base + strlen(data->alt->base) - 1; *s == '/'; --s)
                *s = 0;
 
diff --git a/http.c b/http.c
index 3a28b219be5ecb270a6ff0422c7a4a5cdda023f0..c8cd50dd0c2b2213a86957cd4b24c03c0d85717d 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1087,11 +1087,10 @@ static int update_url_from_redirect(struct strbuf *base,
        if (!strcmp(asked, got->buf))
                return 0;
 
-       if (!starts_with(asked, base->buf))
+       if (!skip_prefix(asked, base->buf, &tail))
                die("BUG: update_url_from_redirect: %s is not a superset of %s",
                    asked, base->buf);
 
-       tail = asked + base->len;
        tail_len = strlen(tail);
 
        if (got->len < tail_len ||
index 83a6ed2ac338d7fc82f3bed6fcb93ffe8dae5739..524fbabc96f450f1faed196c1743d2f8d697b587 100644 (file)
@@ -1328,13 +1328,9 @@ static char *imap_folder;
 
 static int git_imap_config(const char *key, const char *val, void *cb)
 {
-       char imap_key[] = "imap.";
-
-       if (strncmp(key, imap_key, sizeof imap_key - 1))
+       if (!skip_prefix(key, "imap.", &key))
                return 0;
 
-       key += sizeof imap_key - 1;
-
        /* check booleans first, and barf on others */
        if (!strcmp("sslverify", key))
                server.ssl_verify = git_config_bool(key, val);
index 150010105806291180d9e6bdfcf1939fb242f2ac..afcc98db930a36358283ff199a428b6c5bbbaf8f 100644 (file)
@@ -1174,9 +1174,7 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
                         */
                        add_line_range(rev, parents[i], cand[i]);
                        clear_commit_line_range(rev, commit);
-                       commit->parents = xmalloc(sizeof(struct commit_list));
-                       commit->parents->item = parents[i];
-                       commit->parents->next = NULL;
+                       commit_list_append(parents[i], &commit->parents);
                        free(parents);
                        free(cand);
                        free_diffqueues(nparents, diffqueues);
index e80b4af354f87caa7a5130660e9c9c530246b8be..1ce0954a3e5915a6bcc30448c9d99fdaba32bcab 100644 (file)
@@ -140,17 +140,12 @@ static void match_trees(const unsigned char *hash1,
                        goto next;
                score = score_trees(elem, hash2);
                if (*best_score < score) {
-                       char *newpath;
-                       newpath = xmalloc(strlen(base) + strlen(path) + 1);
-                       sprintf(newpath, "%s%s", base, path);
                        free(*best_match);
-                       *best_match = newpath;
+                       *best_match = xstrfmt("%s%s", base, path);
                        *best_score = score;
                }
                if (recurse_limit) {
-                       char *newbase;
-                       newbase = xmalloc(strlen(base) + strlen(path) + 2);
-                       sprintf(newbase, "%s%s/", base, path);
+                       char *newbase = xstrfmt("%s%s/", base, path);
                        match_trees(elem, hash2, best_score, best_match,
                                    newbase, recurse_limit - 1);
                        free(newbase);
index d38a3b2eb5bf4b0940a2aa4d5c32f02b9f35cc15..b5c3c5314f8a4b30dc19b12f311383dd189ae3db 100644 (file)
@@ -603,25 +603,36 @@ static int remove_file(struct merge_options *o, int clean,
        return 0;
 }
 
+/* add a string to a strbuf, but converting "/" to "_" */
+static void add_flattened_path(struct strbuf *out, const char *s)
+{
+       size_t i = out->len;
+       strbuf_addstr(out, s);
+       for (; i < out->len; i++)
+               if (out->buf[i] == '/')
+                       out->buf[i] = '_';
+}
+
 static char *unique_path(struct merge_options *o, const char *path, const char *branch)
 {
-       char *newpath = xmalloc(strlen(path) + 1 + strlen(branch) + 8 + 1);
+       struct strbuf newpath = STRBUF_INIT;
        int suffix = 0;
        struct stat st;
-       char *p = newpath + strlen(path);
-       strcpy(newpath, path);
-       *(p++) = '~';
-       strcpy(p, branch);
-       for (; *p; ++p)
-               if ('/' == *p)
-                       *p = '_';
-       while (string_list_has_string(&o->current_file_set, newpath) ||
-              string_list_has_string(&o->current_directory_set, newpath) ||
-              lstat(newpath, &st) == 0)
-               sprintf(p, "_%d", suffix++);
-
-       string_list_insert(&o->current_file_set, newpath);
-       return newpath;
+       size_t base_len;
+
+       strbuf_addf(&newpath, "%s~", path);
+       add_flattened_path(&newpath, branch);
+
+       base_len = newpath.len;
+       while (string_list_has_string(&o->current_file_set, newpath.buf) ||
+              string_list_has_string(&o->current_directory_set, newpath.buf) ||
+              lstat(newpath.buf, &st) == 0) {
+               strbuf_setlen(&newpath, base_len);
+               strbuf_addf(&newpath, "_%d", suffix++);
+       }
+
+       string_list_insert(&o->current_file_set, newpath.buf);
+       return strbuf_detach(&newpath, NULL);
 }
 
 static int dir_in_way(const char *path, int check_working_copy)
@@ -971,14 +982,10 @@ merge_file_special_markers(struct merge_options *o,
        char *side2 = NULL;
        struct merge_file_info mfi;
 
-       if (filename1) {
-               side1 = xmalloc(strlen(branch1) + strlen(filename1) + 2);
-               sprintf(side1, "%s:%s", branch1, filename1);
-       }
-       if (filename2) {
-               side2 = xmalloc(strlen(branch2) + strlen(filename2) + 2);
-               sprintf(side2, "%s:%s", branch2, filename2);
-       }
+       if (filename1)
+               side1 = xstrfmt("%s:%s", branch1, filename1);
+       if (filename2)
+               side2 = xstrfmt("%s:%s", branch2, filename2);
 
        mfi = merge_file_1(o, one, a, b,
                           side1 ? side1 : branch1, side2 ? side2 : branch2);
@@ -2065,6 +2072,8 @@ void init_merge_options(struct merge_options *o)
 
 int parse_merge_opt(struct merge_options *o, const char *s)
 {
+       const char *arg;
+
        if (!s || !*s)
                return -1;
        if (!strcmp(s, "ours"))
@@ -2073,14 +2082,14 @@ int parse_merge_opt(struct merge_options *o, const char *s)
                o->recursive_variant = MERGE_RECURSIVE_THEIRS;
        else if (!strcmp(s, "subtree"))
                o->subtree_shift = "";
-       else if (starts_with(s, "subtree="))
-               o->subtree_shift = s + strlen("subtree=");
+       else if (skip_prefix(s, "subtree=", &arg))
+               o->subtree_shift = arg;
        else if (!strcmp(s, "patience"))
                o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
        else if (!strcmp(s, "histogram"))
                o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
-       else if (starts_with(s, "diff-algorithm=")) {
-               long value = parse_algorithm_value(s + strlen("diff-algorithm="));
+       else if (skip_prefix(s, "diff-algorithm=", &arg)) {
+               long value = parse_algorithm_value(arg);
                if (value < 0)
                        return -1;
                /* clear out previous settings */
@@ -2098,9 +2107,8 @@ int parse_merge_opt(struct merge_options *o, const char *s)
                o->renormalize = 1;
        else if (!strcmp(s, "no-renormalize"))
                o->renormalize = 0;
-       else if (starts_with(s, "rename-threshold=")) {
-               const char *score = s + strlen("rename-threshold=");
-               if ((o->rename_score = parse_rename_score(&score)) == -1 || *score != 0)
+       else if (skip_prefix(s, "rename-threshold=", &arg)) {
+               if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)
                        return -1;
        }
        else
diff --git a/merge.c b/merge.c
index 70f1000fcbef5cb04e5b25791b482b5f40fab204..1fa6e52bba8de83820b9a658f738630a9d6f250a 100644 (file)
--- a/merge.c
+++ b/merge.c
@@ -18,39 +18,23 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
                      const char **xopts, struct commit_list *common,
                      const char *head_arg, struct commit_list *remotes)
 {
-       const char **args;
-       int i = 0, x = 0, ret;
+       struct argv_array args = ARGV_ARRAY_INIT;
+       int i, ret;
        struct commit_list *j;
-       struct strbuf buf = STRBUF_INIT;
 
-       args = xmalloc((4 + xopts_nr + commit_list_count(common) +
-                       commit_list_count(remotes)) * sizeof(char *));
-       strbuf_addf(&buf, "merge-%s", strategy);
-       args[i++] = buf.buf;
-       for (x = 0; x < xopts_nr; x++) {
-               char *s = xmalloc(strlen(xopts[x])+2+1);
-               strcpy(s, "--");
-               strcpy(s+2, xopts[x]);
-               args[i++] = s;
-       }
-       for (j = common; j; j = j->next)
-               args[i++] = xstrdup(merge_argument(j->item));
-       args[i++] = "--";
-       args[i++] = head_arg;
-       for (j = remotes; j; j = j->next)
-               args[i++] = xstrdup(merge_argument(j->item));
-       args[i] = NULL;
-       ret = run_command_v_opt(args, RUN_GIT_CMD);
-       strbuf_release(&buf);
-       i = 1;
-       for (x = 0; x < xopts_nr; x++)
-               free((void *)args[i++]);
+       argv_array_pushf(&args, "merge-%s", strategy);
+       for (i = 0; i < xopts_nr; i++)
+               argv_array_pushf(&args, "--%s", xopts[i]);
        for (j = common; j; j = j->next)
-               free((void *)args[i++]);
-       i += 2;
+               argv_array_push(&args, merge_argument(j->item));
+       argv_array_push(&args, "--");
+       argv_array_push(&args, head_arg);
        for (j = remotes; j; j = j->next)
-               free((void *)args[i++]);
-       free(args);
+               argv_array_push(&args, merge_argument(j->item));
+
+       ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
+       argv_array_clear(&args);
+
        discard_cache();
        if (read_cache() < 0)
                die(_("failed to read the cache"));
index b536896f2689dee23afae7d3a169c065592aaabe..e7dafa80d55adb9b863c23f711389e5eaa6b2c5e 100644 (file)
@@ -231,7 +231,8 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                        continue;
 
 again:
-               rest = skip_prefix(arg, long_name);
+               if (!skip_prefix(arg, long_name, &rest))
+                       rest = NULL;
                if (options->type == OPTION_ARGUMENT) {
                        if (!rest)
                                continue;
@@ -280,12 +281,13 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                                continue;
                        }
                        flags |= OPT_UNSET;
-                       rest = skip_prefix(arg + 3, long_name);
-                       /* abbreviated and negated? */
-                       if (!rest && starts_with(long_name, arg + 3))
-                               goto is_abbreviated;
-                       if (!rest)
-                               continue;
+                       if (!skip_prefix(arg + 3, long_name, &rest)) {
+                               /* abbreviated and negated? */
+                               if (starts_with(long_name, arg + 3))
+                                       goto is_abbreviated;
+                               else
+                                       continue;
+                       }
                }
                if (*rest) {
                        if (*rest != '=')
index 968ee25eae13f82fe4f93254d77660456732a5c6..79ce8a998b0008f9182fa127b85d63feff4592d0 100644 (file)
@@ -37,9 +37,8 @@ static void *preload_thread(void *_data)
        struct thread_data *p = _data;
        struct index_state *index = p->index;
        struct cache_entry **cep = index->cache + p->offset;
-       struct cache_def cache;
+       struct cache_def cache = CACHE_DEF_INIT;
 
-       memset(&cache, 0, sizeof(cache));
        nr = p->nr;
        if (nr + p->offset > index->cache_nr)
                nr = index->cache_nr - p->offset;
@@ -64,6 +63,7 @@ static void *preload_thread(void *_data)
                        continue;
                ce_mark_uptodate(ce);
        } while (--nr > 0);
+       cache_def_free(&cache);
        return NULL;
 }
 
index c93c14b080b8f23fc30fa58b85c9d70f063c7225..14357e233f3174963add310a29bb35c3de229121 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -40,10 +40,9 @@ static int git_pretty_formats_config(const char *var, const char *value, void *c
        const char *fmt;
        int i;
 
-       if (!starts_with(var, "pretty."))
+       if (!skip_prefix(var, "pretty.", &name))
                return 0;
 
-       name = var + strlen("pretty.");
        for (i = 0; i < builtin_formats_len; i++) {
                if (!strcmp(commit_formats[i].name, name))
                        return 0;
@@ -1249,6 +1248,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                        if (c->signature_check.key)
                                strbuf_addstr(sb, c->signature_check.key);
                        break;
+               default:
+                       return 0;
                }
                return 2;
        }
@@ -1519,8 +1520,6 @@ void format_commit_message(const struct commit *commit,
 
        free(context.commit_encoding);
        unuse_commit_buffer(commit, context.message);
-       free(context.signature_check.gpg_output);
-       free(context.signature_check.signer);
 }
 
 static void pp_header(struct pretty_print_context *pp,
index 4493b389ded6a814bd8c40481f3d06855c963bd7..cdcca2903b100c775d4e004312086581f5839ad4 100644 (file)
@@ -791,9 +791,9 @@ static void parse_fetch(struct strbuf *buf)
        int alloc_heads = 0, nr_heads = 0;
 
        do {
-               if (starts_with(buf->buf, "fetch ")) {
-                       char *p = buf->buf + strlen("fetch ");
-                       char *name;
+               const char *p;
+               if (skip_prefix(buf->buf, "fetch ", &p)) {
+                       const char *name;
                        struct ref *ref;
                        unsigned char old_sha1[20];
 
@@ -968,6 +968,8 @@ int main(int argc, const char **argv)
        http_init(remote, url.buf, 0);
 
        do {
+               const char *arg;
+
                if (strbuf_getline(&buf, stdin, '\n') == EOF) {
                        if (ferror(stdin))
                                fprintf(stderr, "Error reading command stream\n");
@@ -989,9 +991,8 @@ int main(int argc, const char **argv)
                } else if (starts_with(buf.buf, "push ")) {
                        parse_push(&buf);
 
-               } else if (starts_with(buf.buf, "option ")) {
-                       char *name = buf.buf + strlen("option ");
-                       char *value = strchr(name, ' ');
+               } else if (skip_prefix(buf.buf, "option ", &arg)) {
+                       char *value = strchr(arg, ' ');
                        int result;
 
                        if (value)
@@ -999,7 +1000,7 @@ int main(int argc, const char **argv)
                        else
                                value = "true";
 
-                       result = set_option(name, value);
+                       result = set_option(arg, value);
                        if (!result)
                                printf("ok\n");
                        else if (result < 0)
index ae040432037f7463233c5add8257b17ace365b23..3d6c86a36f26406305d58505b10db3f747a2546c 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -170,7 +170,6 @@ static struct branch *make_branch(const char *name, int len)
 {
        struct branch *ret;
        int i;
-       char *refname;
 
        for (i = 0; i < branches_nr; i++) {
                if (len ? (!strncmp(name, branches[i]->name, len) &&
@@ -186,10 +185,7 @@ static struct branch *make_branch(const char *name, int len)
                ret->name = xstrndup(name, len);
        else
                ret->name = xstrdup(name);
-       refname = xmalloc(strlen(name) + strlen("refs/heads/") + 1);
-       strcpy(refname, "refs/heads/");
-       strcpy(refname + strlen("refs/heads/"), ret->name);
-       ret->refname = refname;
+       ret->refname = xstrfmt("refs/heads/%s", ret->name);
 
        return ret;
 }
@@ -488,9 +484,8 @@ static void read_config(void)
        current_branch = NULL;
        head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
        if (head_ref && (flag & REF_ISSYMREF) &&
-           starts_with(head_ref, "refs/heads/")) {
-               current_branch =
-                       make_branch(head_ref + strlen("refs/heads/"), 0);
+           skip_prefix(head_ref, "refs/heads/", &head_ref)) {
+               current_branch = make_branch(head_ref, 0);
        }
        git_config(handle_config, NULL);
        if (branch_pushremote_name) {
index c513d7eeb4d747cbc41950e3ff197aca8d81d6d4..cdd30c07379621561edf7b7fb23c5607571edf4f 100644 (file)
@@ -361,18 +361,13 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
 {
        struct argv_array array;
        int rc;
-       char *gpg_sign;
 
        argv_array_init(&array);
        argv_array_push(&array, "commit");
        argv_array_push(&array, "-n");
 
-       if (opts->gpg_sign) {
-               gpg_sign = xmalloc(3 + strlen(opts->gpg_sign));
-               sprintf(gpg_sign, "-S%s", opts->gpg_sign);
-               argv_array_push(&array, gpg_sign);
-               free(gpg_sign);
-       }
+       if (opts->gpg_sign)
+               argv_array_pushf(&array, "-S%s", opts->gpg_sign);
        if (opts->signoff)
                argv_array_push(&array, "-s");
        if (!opts->edit) {
index 34d527f6708fe242f75b7fa0fa98e36a5c96a3be..a38854ce553c1e59294d5542a37a5404ccd66dc5 100644 (file)
@@ -315,7 +315,8 @@ static int link_alt_odb_entry(const char *entry, const char *relative_base, int
         * thing twice, or object directory itself.
         */
        for (alt = alt_odb_list; alt; alt = alt->next) {
-               if (!memcmp(ent->base, alt->base, pfxlen)) {
+               if (pfxlen == alt->name - alt->base - 1 &&
+                   !memcmp(ent->base, alt->base, pfxlen)) {
                        free(ent);
                        return -1;
                }
index c2c938c4e161fc6849a87a7a19336712f36f74ff..5bfa8416999d35d6bb5c615d86763f013b7df748 100644 (file)
@@ -901,10 +901,8 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
        const char *match = NULL, *target = NULL;
        size_t len;
 
-       if (starts_with(message, "checkout: moving from ")) {
-               match = message + strlen("checkout: moving from ");
+       if (skip_prefix(message, "checkout: moving from ", &match))
                target = strstr(match, " to ");
-       }
 
        if (!match || !target)
                return 0;
@@ -1242,10 +1240,7 @@ static void diagnose_invalid_sha1_path(const char *prefix,
                die("Path '%s' exists on disk, but not in '%.*s'.",
                    filename, object_name_len, object_name);
        if (errno == ENOENT || errno == ENOTDIR) {
-               char *fullname = xmalloc(strlen(filename)
-                                            + strlen(prefix) + 1);
-               strcpy(fullname, prefix);
-               strcat(fullname, filename);
+               char *fullname = xstrfmt("%s%s", prefix, filename);
 
                if (!get_tree_entry(tree_sha1, fullname,
                                    sha1, &mode)) {
diff --git a/shell.c b/shell.c
index 5c0d47a5cc1ae85a03e40321e97ddfa859ff7e1a..ace62e4b6503d821962242f9cf3bd9af22bc39b9 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -46,11 +46,7 @@ static int is_valid_cmd_name(const char *cmd)
 
 static char *make_cmd(const char *prog)
 {
-       char *prefix = xmalloc((strlen(prog) + strlen(COMMAND_DIR) + 2));
-       strcpy(prefix, COMMAND_DIR);
-       strcat(prefix, "/");
-       strcat(prefix, prog);
-       return prefix;
+       return xstrfmt("%s/%s", COMMAND_DIR, prog);
 }
 
 static void cd_to_homedir(void)
index ac62982e672c22457468f601b35716dc9a52a81c..12c78656ca9ddb51fb62b95be29d18056911803f 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -600,3 +600,22 @@ char *xstrdup_tolower(const char *string)
        result[i] = '\0';
        return result;
 }
+
+char *xstrvfmt(const char *fmt, va_list ap)
+{
+       struct strbuf buf = STRBUF_INIT;
+       strbuf_vaddf(&buf, fmt, ap);
+       return strbuf_detach(&buf, NULL);
+}
+
+char *xstrfmt(const char *fmt, ...)
+{
+       va_list ap;
+       char *ret;
+
+       va_start(ap, fmt);
+       ret = xstrvfmt(fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
index e9ad03eabe72dc2ee6e7e0086baca71d343264ce..a594c24b2b0e9e82c16de1bb787758d561cb2e7b 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -187,4 +187,13 @@ extern int fprintf_ln(FILE *fp, const char *fmt, ...);
 
 char *xstrdup_tolower(const char *);
 
+/*
+ * Create a newly allocated string using printf format. You can do this easily
+ * with a strbuf, but this provides a shortcut to save a few lines.
+ */
+__attribute__((format (printf, 1, 0)))
+char *xstrvfmt(const char *fmt, va_list ap);
+__attribute__((format (printf, 1, 2)))
+char *xstrfmt(const char *fmt, ...);
+
 #endif /* STRBUF_H */
index c2b41a85013eec87a412badc4097f364d547726d..5261e8cf499006c1d84fc42a3e96e4dee7f09ba1 100644 (file)
@@ -35,12 +35,11 @@ static int longest_path_match(const char *name_a, int len_a,
        return match_len;
 }
 
-static struct cache_def default_cache;
+static struct cache_def default_cache = CACHE_DEF_INIT;
 
 static inline void reset_lstat_cache(struct cache_def *cache)
 {
-       cache->path[0] = '\0';
-       cache->len = 0;
+       strbuf_reset(&cache->path);
        cache->flags = 0;
        /*
         * The track_flags and prefix_len_stat_func members is only
@@ -73,7 +72,7 @@ static int lstat_cache_matchlen(struct cache_def *cache,
                                int prefix_len_stat_func)
 {
        int match_len, last_slash, last_slash_dir, previous_slash;
-       int save_flags, max_len, ret;
+       int save_flags, ret;
        struct stat st;
 
        if (cache->track_flags != track_flags ||
@@ -93,14 +92,14 @@ static int lstat_cache_matchlen(struct cache_def *cache,
                 * the 2 "excluding" path types.
                 */
                match_len = last_slash =
-                       longest_path_match(name, len, cache->path, cache->len,
-                                          &previous_slash);
+                       longest_path_match(name, len, cache->path.buf,
+                                          cache->path.len, &previous_slash);
                *ret_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
 
                if (!(track_flags & FL_FULLPATH) && match_len == len)
                        match_len = last_slash = previous_slash;
 
-               if (*ret_flags && match_len == cache->len)
+               if (*ret_flags && match_len == cache->path.len)
                        return match_len;
                /*
                 * If we now have match_len > 0, we would know that
@@ -121,21 +120,22 @@ static int lstat_cache_matchlen(struct cache_def *cache,
         */
        *ret_flags = FL_DIR;
        last_slash_dir = last_slash;
-       max_len = len < PATH_MAX ? len : PATH_MAX;
-       while (match_len < max_len) {
+       if (len > cache->path.len)
+               strbuf_grow(&cache->path, len - cache->path.len);
+       while (match_len < len) {
                do {
-                       cache->path[match_len] = name[match_len];
+                       cache->path.buf[match_len] = name[match_len];
                        match_len++;
-               } while (match_len < max_len && name[match_len] != '/');
-               if (match_len >= max_len && !(track_flags & FL_FULLPATH))
+               } while (match_len < len && name[match_len] != '/');
+               if (match_len >= len && !(track_flags & FL_FULLPATH))
                        break;
                last_slash = match_len;
-               cache->path[last_slash] = '\0';
+               cache->path.buf[last_slash] = '\0';
 
                if (last_slash <= prefix_len_stat_func)
-                       ret = stat(cache->path, &st);
+                       ret = stat(cache->path.buf, &st);
                else
-                       ret = lstat(cache->path, &st);
+                       ret = lstat(cache->path.buf, &st);
 
                if (ret) {
                        *ret_flags = FL_LSTATERR;
@@ -158,12 +158,11 @@ static int lstat_cache_matchlen(struct cache_def *cache,
         * for the moment!
         */
        save_flags = *ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
-       if (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {
-               cache->path[last_slash] = '\0';
-               cache->len = last_slash;
+       if (save_flags && last_slash > 0) {
+               cache->path.buf[last_slash] = '\0';
+               cache->path.len = last_slash;
                cache->flags = save_flags;
-       } else if ((track_flags & FL_DIR) &&
-                  last_slash_dir > 0 && last_slash_dir <= PATH_MAX) {
+       } else if ((track_flags & FL_DIR) && last_slash_dir > 0) {
                /*
                 * We have a separate test for the directory case,
                 * since it could be that we have found a symlink or a
@@ -175,8 +174,8 @@ static int lstat_cache_matchlen(struct cache_def *cache,
                 * can still cache the path components before the last
                 * one (the found symlink or non-existing component).
                 */
-               cache->path[last_slash_dir] = '\0';
-               cache->len = last_slash_dir;
+               cache->path.buf[last_slash_dir] = '\0';
+               cache->path.len = last_slash_dir;
                cache->flags = FL_DIR;
        } else {
                reset_lstat_cache(cache);
@@ -273,21 +272,18 @@ static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name
                FL_DIR;
 }
 
-static struct removal_def {
-       char path[PATH_MAX];
-       int len;
-} removal;
+static struct strbuf removal = STRBUF_INIT;
 
 static void do_remove_scheduled_dirs(int new_len)
 {
        while (removal.len > new_len) {
-               removal.path[removal.len] = '\0';
-               if (rmdir(removal.path))
+               removal.buf[removal.len] = '\0';
+               if (rmdir(removal.buf))
                        break;
                do {
                        removal.len--;
                } while (removal.len > new_len &&
-                        removal.path[removal.len] != '/');
+                        removal.buf[removal.len] != '/');
        }
        removal.len = new_len;
 }
@@ -297,7 +293,7 @@ void schedule_dir_for_removal(const char *name, int len)
        int match_len, last_slash, i, previous_slash;
 
        match_len = last_slash = i =
-               longest_path_match(name, len, removal.path, removal.len,
+               longest_path_match(name, len, removal.buf, removal.len,
                                   &previous_slash);
        /* Find last slash inside 'name' */
        while (i < len) {
@@ -317,11 +313,8 @@ void schedule_dir_for_removal(const char *name, int len)
         * If we go deeper down the directory tree, we only need to
         * save the new path components as we go down.
         */
-       if (match_len < last_slash) {
-               memcpy(&removal.path[match_len], &name[match_len],
-                      last_slash - match_len);
-               removal.len = last_slash;
-       }
+       if (match_len < last_slash)
+               strbuf_add(&removal, &name[match_len], last_slash - match_len);
 }
 
 void remove_scheduled_dirs(void)
index c277db64f75ac9f9c0cd617262824d76959fbfbd..88ed3191e871cd9a164c3c903f69b07e7d9cf937 100755 (executable)
@@ -468,4 +468,10 @@ test_expect_success 'single-character name is parsed correctly' '
        test_cmp expect actual
 '
 
+test_expect_success 'unused %G placeholders are passed through' '
+       echo "%GX %G" >expect &&
+       git log -1 --format="%GX %G" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 5ddac1a9f740c03f1d94f75db2c6e54dd3391eda..474dab381aef027207026cb938df7a09cc7a9056 100755 (executable)
@@ -43,44 +43,74 @@ test_expect_success GPG 'create signed commits' '
 
        test_tick && git rebase -f HEAD^^ && git tag sixth-signed HEAD^ &&
        git tag seventh-signed
+
+       echo 8 >file && test_tick && git commit -a -m eighth -SB7227189 &&
+       git tag eighth-signed-alt
 '
 
-test_expect_success GPG 'show signatures' '
+test_expect_success GPG 'verify and show signatures' '
        (
-               for commit in initial second merge fourth-signed fifth-signed sixth-signed master
+               for commit in initial second merge fourth-signed fifth-signed sixth-signed seventh-signed
                do
+                       git verify-commit $commit &&
                        git show --pretty=short --show-signature $commit >actual &&
-                       grep "Good signature from" actual || exit 1
-                       ! grep "BAD signature from" actual || exit 1
-                       echo $commit OK
+                       grep "Good signature from" actual &&
+                       ! grep "BAD signature from" actual &&
+                       echo $commit OK || exit 1
                done
        ) &&
        (
                for commit in merge^2 fourth-unsigned sixth-unsigned seventh-unsigned
                do
+                       test_must_fail git verify-commit $commit &&
                        git show --pretty=short --show-signature $commit >actual &&
-                       grep "Good signature from" actual && exit 1
-                       ! grep "BAD signature from" actual || exit 1
-                       echo $commit OK
+                       ! grep "Good signature from" actual &&
+                       ! grep "BAD signature from" actual &&
+                       echo $commit OK || exit 1
+               done
+       ) &&
+       (
+               for commit in eighth-signed-alt
+               do
+                       git show --pretty=short --show-signature $commit >actual &&
+                       grep "Good signature from" actual &&
+                       ! grep "BAD signature from" actual &&
+                       grep "not certified" actual &&
+                       echo $commit OK || exit 1
                done
        )
 '
 
+test_expect_success GPG 'show signed commit with signature' '
+       git show -s initial >commit &&
+       git show -s --show-signature initial >show &&
+       git verify-commit -v initial >verify.1 2>verify.2 &&
+       git cat-file commit initial >cat &&
+       grep -v "gpg: " show >show.commit &&
+       grep "gpg: " show >show.gpg &&
+       grep -v "^ " cat | grep -v "^gpgsig " >cat.commit &&
+       test_cmp show.commit commit &&
+       test_cmp show.gpg verify.2 &&
+       test_cmp cat.commit verify.1
+'
+
 test_expect_success GPG 'detect fudged signature' '
-       git cat-file commit master >raw &&
+       git cat-file commit seventh-signed >raw &&
 
        sed -e "s/seventh/7th forged/" raw >forged1 &&
        git hash-object -w -t commit forged1 >forged1.commit &&
+       ! git verify-commit $(cat forged1.commit) &&
        git show --pretty=short --show-signature $(cat forged1.commit) >actual1 &&
        grep "BAD signature from" actual1 &&
        ! grep "Good signature from" actual1
 '
 
 test_expect_success GPG 'detect fudged signature with NUL' '
-       git cat-file commit master >raw &&
+       git cat-file commit seventh-signed >raw &&
        cat raw >forged2 &&
        echo Qwik | tr "Q" "\000" >>forged2 &&
        git hash-object -w -t commit forged2 >forged2.commit &&
+       ! git verify-commit $(cat forged2.commit) &&
        git show --pretty=short --show-signature $(cat forged2.commit) >actual2 &&
        grep "BAD signature from" actual2 &&
        ! grep "Good signature from" actual2
@@ -89,9 +119,50 @@ test_expect_success GPG 'detect fudged signature with NUL' '
 test_expect_success GPG 'amending already signed commit' '
        git checkout fourth-signed^0 &&
        git commit --amend -S --no-edit &&
+       git verify-commit HEAD &&
        git show -s --show-signature HEAD >actual &&
        grep "Good signature from" actual &&
        ! grep "BAD signature from" actual
 '
 
+test_expect_success GPG 'show good signature with custom format' '
+       cat >expect <<-\EOF &&
+       G
+       13B6F51ECDDE430D
+       C O Mitter <committer@example.com>
+       EOF
+       git log -1 --format="%G?%n%GK%n%GS" sixth-signed >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show bad signature with custom format' '
+       cat >expect <<-\EOF &&
+       B
+       13B6F51ECDDE430D
+       C O Mitter <committer@example.com>
+       EOF
+       git log -1 --format="%G?%n%GK%n%GS" $(cat forged1.commit) >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show unknown signature with custom format' '
+       cat >expect <<-\EOF &&
+       U
+       61092E85B7227189
+       Eris Discordia <discord@example.net>
+       EOF
+       git log -1 --format="%G?%n%GK%n%GS" eighth-signed-alt >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success GPG 'show lack of signature with custom format' '
+       cat >expect <<-\EOF &&
+       N
+
+
+       EOF
+       git log -1 --format="%G?%n%GK%n%GS" seventh-unsigned >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 84c616f180bebc730d05f306906558dd0abad2a4..3d8fe7d801293a338f13dfd01ba352e84c658813 100644 (file)
@@ -153,7 +153,7 @@ static struct child_process *get_helper(struct transport *transport)
        write_constant(helper->in, "capabilities\n");
 
        while (1) {
-               const char *capname;
+               const char *capname, *arg;
                int mandatory = 0;
                if (recvline(data, &buf))
                        exit(128);
@@ -183,19 +183,19 @@ static struct child_process *get_helper(struct transport *transport)
                        data->export = 1;
                else if (!strcmp(capname, "check-connectivity"))
                        data->check_connectivity = 1;
-               else if (!data->refspecs && starts_with(capname, "refspec ")) {
+               else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) {
                        ALLOC_GROW(refspecs,
                                   refspec_nr + 1,
                                   refspec_alloc);
-                       refspecs[refspec_nr++] = xstrdup(capname + strlen("refspec "));
+                       refspecs[refspec_nr++] = xstrdup(arg);
                } else if (!strcmp(capname, "connect")) {
                        data->connect = 1;
                } else if (!strcmp(capname, "signed-tags")) {
                        data->signed_tags = 1;
-               } else if (starts_with(capname, "export-marks ")) {
-                       data->export_marks = xstrdup(capname + strlen("export-marks "));
-               } else if (starts_with(capname, "import-marks")) {
-                       data->import_marks = xstrdup(capname + strlen("import-marks "));
+               } else if (skip_prefix(capname, "export-marks ", &arg)) {
+                       data->export_marks = xstrdup(arg);
+               } else if (skip_prefix(capname, "import-marks ", &arg)) {
+                       data->import_marks = xstrdup(arg);
                } else if (starts_with(capname, "no-private-update")) {
                        data->no_private_update = 1;
                } else if (mandatory) {
index 325f03e1eef97df296bb1cc9f7d2d33c218dde26..59c9727d8d63d548001513c1560b5c7a7e065b95 100644 (file)
@@ -192,7 +192,9 @@ static void set_upstreams(struct transport *transport, struct ref *refs,
 
 static const char *rsync_url(const char *url)
 {
-       return !starts_with(url, "rsync://") ? skip_prefix(url, "rsync:") : url;
+       if (!starts_with(url, "rsync://"))
+               skip_prefix(url, "rsync:", &url);
+       return url;
 }
 
 static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
index e9a05b908589a0fa8c446b1896821b77aa24596c..0ac39e93a08733ee46f42dfa1170af7333ae43e5 100644 (file)
@@ -56,17 +56,15 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
        int i;
        const char **msgs = opts->msgs;
        const char *msg;
-       char *tmp;
        const char *cmd2 = strcmp(cmd, "checkout") ? cmd : "switch branches";
+
        if (advice_commit_before_merge)
                msg = "Your local changes to the following files would be overwritten by %s:\n%%s"
                        "Please, commit your changes or stash them before you can %s.";
        else
                msg = "Your local changes to the following files would be overwritten by %s:\n%%s";
-       tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen(cmd2) - 2);
-       sprintf(tmp, msg, cmd, cmd2);
-       msgs[ERROR_WOULD_OVERWRITE] = tmp;
-       msgs[ERROR_NOT_UPTODATE_FILE] = tmp;
+       msgs[ERROR_WOULD_OVERWRITE] = msgs[ERROR_NOT_UPTODATE_FILE] =
+               xstrfmt(msg, cmd, cmd2);
 
        msgs[ERROR_NOT_UPTODATE_DIR] =
                "Updating the following directories would lose untracked files in it:\n%s";
@@ -76,12 +74,9 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
                        "Please move or remove them before you can %s.";
        else
                msg = "The following untracked working tree files would be %s by %s:\n%%s";
-       tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("removed") + strlen(cmd2) - 4);
-       sprintf(tmp, msg, "removed", cmd, cmd2);
-       msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = tmp;
-       tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("overwritten") + strlen(cmd2) - 4);
-       sprintf(tmp, msg, "overwritten", cmd, cmd2);
-       msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = tmp;
+
+       msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = xstrfmt(msg, "removed", cmd, cmd2);
+       msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = xstrfmt(msg, "overwritten", cmd, cmd2);
 
        /*
         * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
index ec87cba75099ebe05e936430ca3b688275e01a4a..3d4c54b5cd5d6f6cb4e0ea97550799eb9d46f033 100644 (file)
@@ -483,8 +483,7 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
        int user_matched = 0;
        int retval;
 
-       key = skip_prefix(var, collect->section);
-       if (!key || *(key++) != '.') {
+       if (!skip_prefix(var, collect->section, &key) || *(key++) != '.') {
                if (collect->cascade_fn)
                        return collect->cascade_fn(var, value, cb);
                return 0; /* not interested */
index 1dd86b8f33e04cfc6c0616578416acb1160b5718..014826464e07c93374868c61673cfe308961dfb7 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -253,7 +253,8 @@ int walker_fetch(struct walker *walker, int targets, char **target,
 {
        struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
        unsigned char *sha1 = xmalloc(targets * 20);
-       char *msg;
+       const char *msg;
+       char *to_free = NULL;
        int ret;
        int i;
 
@@ -285,21 +286,19 @@ int walker_fetch(struct walker *walker, int targets, char **target,
        if (loop(walker))
                goto unlock_and_fail;
 
-       if (write_ref_log_details) {
-               msg = xmalloc(strlen(write_ref_log_details) + 12);
-               sprintf(msg, "fetch from %s", write_ref_log_details);
-       } else {
-               msg = NULL;
-       }
+       if (write_ref_log_details)
+               msg = to_free = xstrfmt("fetch from %s", write_ref_log_details);
+       else
+               msg = "fetch (unknown)";
        for (i = 0; i < targets; i++) {
                if (!write_ref || !write_ref[i])
                        continue;
-               ret = write_ref_sha1(lock[i], &sha1[20 * i], msg ? msg : "fetch (unknown)");
+               ret = write_ref_sha1(lock[i], &sha1[20 * i], msg);
                lock[i] = NULL;
                if (ret)
                        goto unlock_and_fail;
        }
-       free(msg);
+       free(to_free);
 
        return 0;
 
@@ -307,6 +306,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
        for (i = 0; i < targets; i++)
                if (lock[i])
                        unlock_ref(lock[i]);
+       free(to_free);
 
        return -1;
 }
index 318a191238fb831da8b72f04886b311f1c2c2567..882cfe9fb050efe84e2330b9aea76685c6a7f891 100644 (file)
@@ -734,37 +734,34 @@ static void wt_status_print_changed(struct wt_status *s)
 static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted)
 {
        struct child_process sm_summary;
-       char summary_limit[64];
-       char index[PATH_MAX];
-       const char *env[] = { NULL, NULL };
+       struct argv_array env = ARGV_ARRAY_INIT;
        struct argv_array argv = ARGV_ARRAY_INIT;
        struct strbuf cmd_stdout = STRBUF_INIT;
        struct strbuf summary = STRBUF_INIT;
        char *summary_content;
        size_t len;
 
-       sprintf(summary_limit, "%d", s->submodule_summary);
-       snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
+       argv_array_pushf(&env, "GIT_INDEX_FILE=%s", s->index_file);
 
-       env[0] = index;
        argv_array_push(&argv, "submodule");
        argv_array_push(&argv, "summary");
        argv_array_push(&argv, uncommitted ? "--files" : "--cached");
        argv_array_push(&argv, "--for-status");
        argv_array_push(&argv, "--summary-limit");
-       argv_array_push(&argv, summary_limit);
+       argv_array_pushf(&argv, "%d", s->submodule_summary);
        if (!uncommitted)
                argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
 
        memset(&sm_summary, 0, sizeof(sm_summary));
        sm_summary.argv = argv.argv;
-       sm_summary.env = env;
+       sm_summary.env = env.argv;
        sm_summary.git_cmd = 1;
        sm_summary.no_stdin = 1;
        fflush(s->fp);
        sm_summary.out = -1;
 
        run_command(&sm_summary);
+       argv_array_clear(&env);
        argv_array_clear(&argv);
 
        len = strbuf_read(&cmd_stdout, sm_summary.out, 1024);