Merge branch 'ar/diff'
authorJunio C Hamano <junkio@cox.net>
Sun, 18 Mar 2007 22:48:06 +0000 (15:48 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 18 Mar 2007 22:48:06 +0000 (15:48 -0700)
* ar/diff:
Add tests for --quiet option of diff programs
try-to-simplify-commit: use diff-tree --quiet machinery.
revision.c: explain what tree_difference does
Teach --quiet to diff backends.
diff --quiet
Remove unused diffcore_std_no_resolve
Allow git-diff exit with codes similar to diff(1)

22 files changed:
Documentation/RelNotes-1.5.0.5.txt [new file with mode: 0644]
Documentation/config.txt
builtin-branch.c
builtin-pack-objects.c
cache.h
config.c
git-applymbox.sh
git-checkout.sh
git-fetch.sh
git-merge.sh
git-parse-remote.sh
local-fetch.c
pack-check.c
pack-redundant.c
pack.h
sha1_file.c
t/t3200-branch.sh
t/t5300-pack-object.sh
t/t5520-pull.sh
tree-diff.c
tree-walk.c
tree-walk.h
diff --git a/Documentation/RelNotes-1.5.0.5.txt b/Documentation/RelNotes-1.5.0.5.txt
new file mode 100644 (file)
index 0000000..aa86149
--- /dev/null
@@ -0,0 +1,28 @@
+GIT v1.5.0.5 Release Notes
+==========================
+
+Fixes since v1.5.0.3
+--------------------
+
+* Bugfixes
+
+  - git-merge (hence git-pull) did not refuse fast-forwarding
+    when the working tree had local changes that would have
+    conflicted with it.
+
+  - git.el does not add duplicate sign-off lines.
+
+  - git-commit shows the full stat of the resulting commit, not
+    just about the files in the current directory, when run from
+    a subdirectory.
+
+  - "git-checkout -m '@{8 hours ago}'" had a funny failure from
+    eval; fixed.
+
+  - git-gui updates.
+
+* Documentation updates
+
+* User manual updates
+
+
index aaae9ac3052b5a4de6ec53817e79797626f7da31..953acaee4c9b692802a4e98861dac8ceec315d54 100644 (file)
@@ -272,6 +272,10 @@ branch.<name>.merge::
        `git fetch`) to lookup the default branch for merging. Without
        this option, `git pull` defaults to merge the first refspec fetched.
        Specify multiple values to get an octopus merge.
+       If you wish to setup `git pull` so that it merges into <name> from
+       another branch in the local repository, you can point
+       branch.<name>.merge to the desired branch, and use the special setting
+       `.` (a period) for branch.<name>.remote.
 
 color.branch::
        A boolean to enable/disable color in the output of
index 42b1ff129e7d5bbea47a4d1af955395014f200f9..a4494ee337d70a400664e529e84f90d475a03b92 100644 (file)
@@ -372,9 +372,26 @@ static int get_remote_config(const char *key, const char *value)
        return 0;
 }
 
-static void set_branch_defaults(const char *name, const char *real_ref)
+static void set_branch_merge(const char *name, const char *config_remote,
+                            const char *config_repo)
 {
        char key[1024];
+       if (sizeof(key) <=
+           snprintf(key, sizeof(key), "branch.%s.remote", name))
+               die("what a long branch name you have!");
+       git_config_set(key, config_remote);
+
+       /*
+        * We do not have to check if we have enough space for
+        * the 'merge' key, since it's shorter than the
+        * previous 'remote' key, which we already checked.
+        */
+       snprintf(key, sizeof(key), "branch.%s.merge", name);
+       git_config_set(key, config_repo);
+}
+
+static void set_branch_defaults(const char *name, const char *real_ref)
+{
        const char *slash = strrchr(real_ref, '/');
 
        if (!slash)
@@ -384,21 +401,15 @@ static void set_branch_defaults(const char *name, const char *real_ref)
        start_len = strlen(real_ref);
        base_len = slash - real_ref;
        git_config(get_remote_config);
+       if (!config_repo && !config_remote &&
+           !prefixcmp(real_ref, "refs/heads/")) {
+               set_branch_merge(name, ".", real_ref);
+               printf("Branch %s set up to track local branch %s.\n",
+                      name, real_ref);
+       }
 
        if (config_repo && config_remote) {
-               if (sizeof(key) <=
-                   snprintf(key, sizeof(key), "branch.%s.remote", name))
-                       die("what a long branch name you have!");
-               git_config_set(key, config_remote);
-
-               /*
-                * We do not have to check if we have enough space for
-                * the 'merge' key, since it's shorter than the
-                * previous 'remote' key, which we already checked.
-                */
-               snprintf(key, sizeof(key), "branch.%s.merge", name);
-               git_config_set(key, config_repo);
-
+               set_branch_merge(name, config_remote, config_repo);
                printf("Branch %s set up to track remote branch %s.\n",
                       name, real_ref);
        }
index f8ebad0b2f2006d619dc06814acb6024ee674eec..73d448b890d61b79793290b6b9b9aceea0a89cdc 100644 (file)
@@ -166,11 +166,12 @@ static void prepare_pack_revindex(struct pack_revindex *rix)
        struct packed_git *p = rix->p;
        int num_ent = num_packed_objects(p);
        int i;
-       void *index = p->index_base + 256;
+       const char *index = p->index_data;
 
+       index += 4 * 256;
        rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
        for (i = 0; i < num_ent; i++) {
-               unsigned int hl = *((unsigned int *)((char *) index + 24*i));
+               uint32_t hl = *((uint32_t *)(index + 24 * i));
                rix->revindex[i].offset = ntohl(hl);
                rix->revindex[i].nr = i;
        }
@@ -217,11 +218,11 @@ static off_t find_packed_object_size(struct packed_git *p, off_t ofs)
        return entry[1].offset - ofs;
 }
 
-static unsigned char *find_packed_object_name(struct packed_git *p,
-                                             off_t ofs)
+static const unsigned char *find_packed_object_name(struct packed_git *p,
+                                                   off_t ofs)
 {
        struct revindex_entry *entry = find_packed_object(p, ofs);
-       return (unsigned char *)(p->index_base + 256) + 24 * entry->nr + 4;
+       return ((unsigned char *)p->index_data) + 4 * 256 + 24 * entry->nr + 4;
 }
 
 static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
@@ -996,7 +997,8 @@ static void check_object(struct object_entry *entry)
                 * delta.
                 */
                if (!no_reuse_delta) {
-                       unsigned char c, *base_name;
+                       unsigned char c;
+                       const unsigned char *base_name;
                        off_t ofs;
                        unsigned long used_0;
                        /* there is at least 20 bytes left in the pack */
diff --git a/cache.h b/cache.h
index a4762eda5c3dbf34fb1742b1c645395f092d8d6b..3818e10f8c1a65cc4e4cf339bb5f7f324e8a7c4c 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -371,10 +371,11 @@ struct pack_window {
 extern struct packed_git {
        struct packed_git *next;
        struct pack_window *windows;
-       uint32_t *index_base;
-       time_t mtime;
+       const void *index_data;
        off_t index_size;
        off_t pack_size;
+       time_t mtime;
+       int index_version;
        int pack_fd;
        int pack_local;
        unsigned char sha1[20];
@@ -412,7 +413,7 @@ extern int server_supports(const char *feature);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1);
 extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
-                                               char *idx_path);
+                                               const char *idx_path);
 
 extern void prepare_packed_git(void);
 extern void reprepare_packed_git(void);
@@ -424,7 +425,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
 extern void pack_report(void);
 extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
 extern void unuse_pack(struct pack_window **);
-extern struct packed_git *add_packed_git(char *, int, int);
+extern struct packed_git *add_packed_git(const char *, int, int);
 extern uint32_t num_packed_objects(const struct packed_git *p);
 extern int nth_packed_object_sha1(const struct packed_git *, uint32_t, unsigned char*);
 extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
index a3c7b772bce1d302e60bbf02212bb4ad4da0ee7b..d537311ae1d4321c3f5f90930f7451262caf2ae5 100644 (file)
--- a/config.c
+++ b/config.c
@@ -351,12 +351,12 @@ int git_default_config(const char *var, const char *value)
        }
 
        if (!strcmp(var, "i18n.commitencoding")) {
-               git_commit_encoding = strdup(value);
+               git_commit_encoding = xstrdup(value);
                return 0;
        }
 
        if (!strcmp(var, "i18n.logoutputencoding")) {
-               git_log_output_encoding = strdup(value);
+               git_log_output_encoding = xstrdup(value);
                return 0;
        }
 
index 2cbdc7eb3cc1c9843bd8877b39a194e677272260..3efd6a746407bdc38ba9d251332427c508e5ee40 100755 (executable)
@@ -77,9 +77,9 @@ do
     *)
            git-mailinfo $keep_subject $utf8 \
                .dotest/msg .dotest/patch <$i >.dotest/info || exit 1
-           test -s $dotest/patch || {
+           test -s .dotest/patch || {
                echo "Patch is empty.  Was is split wrong?"
-               stop_here $this
+               exit 1
            }
            git-stripspace < .dotest/msg > .dotest/msg-clean
            ;;
index fcadf200ee990f195ce3f5c72306cbf0206277cd..39ffa8b8a3322b623a6d4938d566453fe206ca69 100755 (executable)
@@ -89,7 +89,7 @@ while [ "$#" != "0" ]; do
     esac
 done
 
-case "$new_branch,$track" in
+case "$newbranch,$track" in
 ,--*)
        die "git checkout: --track and --no-track require -b"
 esac
index 9d45dd266a8110a2d39fe29ffeb84aacb6053623..e21804284398016a789b415dec9332700d33f8e6 100755 (executable)
@@ -157,7 +157,7 @@ then
        fi
 fi
 
-fetch_native () {
+fetch_all_at_once () {
 
   eval=$(echo "$1" | git-fetch--tool parse-reflist "-")
   eval "$eval"
@@ -165,7 +165,9 @@ fetch_native () {
     ( : subshell because we muck with IFS
       IFS="    $LF"
       (
-       if test -f "$remote" ; then
+       if test "$remote" = . ; then
+           git-show-ref $rref || echo failed "$remote"
+       elif test -f "$remote" ; then
            test -n "$shallow_depth" &&
                die "shallow clone with bundle is not supported"
            git-bundle unbundle "$remote" $rref ||
@@ -188,7 +190,7 @@ fetch_native () {
 
 }
 
-fetch_dumb () {
+fetch_per_ref () {
   reflist="$1"
   refs=
   rref=
@@ -292,10 +294,10 @@ fetch_dumb () {
 fetch_main () {
        case "$remote" in
        http://* | https://* | ftp://* | rsync://* )
-               fetch_dumb "$@"
+               fetch_per_ref "$@"
                ;;
        *)
-               fetch_native "$@"
+               fetch_all_at_once "$@"
                ;;
        esac
 }
index 6ce62c860a3732e1239e216fb7492a126216be67..8759c5a7e0f8748108d6eff005cde1e0893f3592 100755 (executable)
@@ -292,13 +292,13 @@ f,*)
        # Again the most common case of merging one remote.
        echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)"
        git-update-index --refresh 2>/dev/null
-       new_head=$(git-rev-parse --verify "$1^0") &&
-       git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" &&
        msg="Fast forward"
        if test -n "$have_message"
        then
                msg="$msg (no commit created; -m option ignored)"
        fi
+       new_head=$(git-rev-parse --verify "$1^0") &&
+       git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" &&
        finish "$new_head" "$msg" || exit
        dropsave
        exit 0
index c46131f6d6619aa07ddb72265583b1de0832ff3e..437b0c3b1bc522c4b5a4a3a656b97cb2009c43a0 100755 (executable)
@@ -9,6 +9,9 @@ get_data_source () {
        */*)
                echo ''
                ;;
+       .)
+               echo self
+               ;;
        *)
                if test "$(git-config --get "remote.$1.url")"
                then
@@ -31,6 +34,9 @@ get_remote_url () {
        '')
                echo "$1"
                ;;
+       self)
+               echo "$1"
+               ;;
        config)
                git-config --get "remote.$1.url"
                ;;
@@ -57,7 +63,7 @@ get_default_remote () {
 get_remote_default_refs_for_push () {
        data_source=$(get_data_source "$1")
        case "$data_source" in
-       '' | branches)
+       '' | branches | self)
                ;; # no default push mapping, just send matching refs.
        config)
                git-config --get-all "remote.$1.push" ;;
@@ -163,6 +169,10 @@ get_remote_default_refs_for_fetch () {
        case "$data_source" in
        '')
                echo "HEAD:" ;;
+       self)
+               canon_refs_list_for_fetch -d "$1" \
+                       $(git-for-each-ref --format='%(refname):')
+               ;;
        config)
                canon_refs_list_for_fetch -d "$1" \
                        $(git-config --get-all "remote.$1.fetch") ;;
@@ -177,7 +187,7 @@ get_remote_default_refs_for_fetch () {
                                        }' "$GIT_DIR/remotes/$1")
                ;;
        *)
-               die "internal error: get-remote-default-ref-for-push $1" ;;
+               die "internal error: get-remote-default-ref-for-fetch $1" ;;
        esac
 }
 
index 7cfe8b3587c10bf0791c066a72482771e7daae77..4b650efa8b19424a61566b7ec87e7808874a6721 100644 (file)
@@ -64,9 +64,9 @@ static int copy_file(const char *source, char *dest, const char *hex,
                }
                /* If we got ENOENT there is no point continuing. */
                if (errno == ENOENT) {
-                       if (warn_if_not_exists)
-                               fprintf(stderr, "does not exist %s\n", source);
-                       return -1;
+                       if (!warn_if_not_exists)
+                               return -1;
+                       return error("does not exist %s", source);
                }
        }
        if (use_symlink) {
@@ -74,9 +74,8 @@ static int copy_file(const char *source, char *dest, const char *hex,
                if (stat(source, &st)) {
                        if (!warn_if_not_exists && errno == ENOENT)
                                return -1;
-                       fprintf(stderr, "cannot stat %s: %s\n", source,
-                               strerror(errno));
-                       return -1;
+                       return error("cannot stat %s: %s", source,
+                                    strerror(errno));
                }
                if (!symlink(source, dest)) {
                        pull_say("symlink %s\n", hex);
@@ -90,25 +89,21 @@ static int copy_file(const char *source, char *dest, const char *hex,
                if (ifd < 0) {
                        if (!warn_if_not_exists && errno == ENOENT)
                                return -1;
-                       fprintf(stderr, "cannot open %s\n", source);
-                       return -1;
+                       return error("cannot open %s", source);
                }
                ofd = open(dest, O_WRONLY | O_CREAT | O_EXCL, 0666);
                if (ofd < 0) {
-                       fprintf(stderr, "cannot open %s\n", dest);
                        close(ifd);
-                       return -1;
+                       return error("cannot open %s", dest);
                }
                status = copy_fd(ifd, ofd);
                close(ofd);
                if (status)
-                       fprintf(stderr, "cannot write %s\n", dest);
-               else
-                       pull_say("copy %s\n", hex);
-               return status;
+                       return error("cannot write %s", dest);
+               pull_say("copy %s\n", hex);
+               return 0;
        }
-       fprintf(stderr, "failed to copy %s with given copy methods.\n", hex);
-       return -1;
+       return error("failed to copy %s with given copy methods.", hex);
 }
 
 static int fetch_pack(const unsigned char *sha1)
@@ -181,13 +176,11 @@ int fetch_ref(char *ref, unsigned char *sha1)
        ifd = open(filename, O_RDONLY);
        if (ifd < 0) {
                close(ifd);
-               fprintf(stderr, "cannot open %s\n", filename);
-               return -1;
+               return error("cannot open %s", filename);
        }
        if (read_in_full(ifd, hex, 40) != 40 || get_sha1_hex(hex, sha1)) {
                close(ifd);
-               fprintf(stderr, "cannot read from %s\n", filename);
-               return -1;
+               return error("cannot read from %s", filename);
        }
        close(ifd);
        pull_say("ref %s\n", sha1_to_hex(sha1));
index 299c514128b8b6330561a1a2b8ac30324a7ac479..d9883225eabf10ad9a3a169e7049c9ee25e5d9cd 100644 (file)
@@ -5,7 +5,7 @@ static int verify_packfile(struct packed_git *p,
                struct pack_window **w_curs)
 {
        off_t index_size = p->index_size;
-       void *index_base = p->index_base;
+       const unsigned char *index_base = p->index_data;
        SHA_CTX ctx;
        unsigned char sha1[20];
        off_t offset = 0, pack_sig = p->pack_size - 20;
@@ -31,7 +31,7 @@ static int verify_packfile(struct packed_git *p,
        if (hashcmp(sha1, use_pack(p, w_curs, pack_sig, NULL)))
                return error("Packfile %s SHA1 mismatch with itself",
                             p->pack_name);
-       if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40))
+       if (hashcmp(sha1, index_base + index_size - 40))
                return error("Packfile %s SHA1 mismatch with idx",
                             p->pack_name);
        unuse_pack(w_curs);
@@ -127,7 +127,7 @@ static void show_pack_info(struct packed_git *p)
 int verify_pack(struct packed_git *p, int verbose)
 {
        off_t index_size = p->index_size;
-       void *index_base = p->index_base;
+       const unsigned char *index_base = p->index_data;
        SHA_CTX ctx;
        unsigned char sha1[20];
        int ret;
@@ -137,7 +137,7 @@ int verify_pack(struct packed_git *p, int verbose)
        SHA1_Init(&ctx);
        SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20));
        SHA1_Final(sha1, &ctx);
-       if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20))
+       if (hashcmp(sha1, index_base + index_size - 20))
                ret = error("Packfile index for %s SHA1 mismatch",
                            p->pack_name);
 
index c8f7d9af7b502e12a3d36fc3b3e796e43b4f2bdb..40e579b2d9788bb0867b345c3596b1ad1539272a 100644 (file)
@@ -17,7 +17,7 @@ static int load_all_packs, verbose, alt_odb;
 
 struct llist_item {
        struct llist_item *next;
-       unsigned char *sha1;
+       const unsigned char *sha1;
 };
 static struct llist {
        struct llist_item *front;
@@ -104,9 +104,9 @@ static struct llist * llist_copy(struct llist *list)
        return ret;
 }
 
-static inline struct llist_item * llist_insert(struct llist *list,
-                                              struct llist_item *after,
-                                              unsigned char *sha1)
+static inline struct llist_item *llist_insert(struct llist *list,
+                                             struct llist_item *after,
+                                              const unsigned char *sha1)
 {
        struct llist_item *new = llist_item_get();
        new->sha1 = sha1;
@@ -128,12 +128,14 @@ static inline struct llist_item * llist_insert(struct llist *list,
        return new;
 }
 
-static inline struct llist_item *llist_insert_back(struct llist *list, unsigned char *sha1)
+static inline struct llist_item *llist_insert_back(struct llist *list,
+                                                  const unsigned char *sha1)
 {
        return llist_insert(list, list->back, sha1);
 }
 
-static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, unsigned char *sha1, struct llist_item *hint)
+static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
+                       const unsigned char *sha1, struct llist_item *hint)
 {
        struct llist_item *prev = NULL, *l;
 
@@ -246,12 +248,12 @@ static struct pack_list * pack_list_difference(const struct pack_list *A,
 static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
 {
        int p1_off, p2_off;
-       unsigned char *p1_base, *p2_base;
+       const unsigned char *p1_base, *p2_base;
        struct llist_item *p1_hint = NULL, *p2_hint = NULL;
 
        p1_off = p2_off = 256 * 4 + 4;
-       p1_base = (unsigned char *) p1->pack->index_base;
-       p2_base = (unsigned char *) p2->pack->index_base;
+       p1_base = p1->pack->index_data;
+       p2_base = p2->pack->index_data;
 
        while (p1_off <= p1->pack->index_size - 3 * 20 &&
               p2_off <= p2->pack->index_size - 3 * 20)
@@ -351,11 +353,11 @@ static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
 {
        size_t ret = 0;
        int p1_off, p2_off;
-       unsigned char *p1_base, *p2_base;
+       const unsigned char *p1_base, *p2_base;
 
        p1_off = p2_off = 256 * 4 + 4;
-       p1_base = (unsigned char *)p1->index_base;
-       p2_base = (unsigned char *)p2->index_base;
+       p1_base = p1->index_data;
+       p2_base = p2->index_data;
 
        while (p1_off <= p1->index_size - 3 * 20 &&
               p2_off <= p2->index_size - 3 * 20)
@@ -534,7 +536,7 @@ static struct pack_list * add_pack(struct packed_git *p)
 {
        struct pack_list l;
        size_t off;
-       unsigned char *base;
+       const unsigned char *base;
 
        if (!p->pack_local && !(alt_odb || verbose))
                return NULL;
@@ -543,7 +545,7 @@ static struct pack_list * add_pack(struct packed_git *p)
        llist_init(&l.all_objects);
 
        off = 256 * 4 + 4;
-       base = (unsigned char *)p->index_base;
+       base = p->index_data;
        while (off <= p->index_size - 3 * 20) {
                llist_insert_back(l.all_objects, base + off);
                off += 24;
diff --git a/pack.h b/pack.h
index deb427edbe43710dd2b76a3af0dbd87750344103..d4d412ccbb403f1374d41a00791eec3c16ba64ef 100644 (file)
--- a/pack.h
+++ b/pack.h
@@ -16,24 +16,15 @@ struct pack_header {
 };
 
 /*
- * Packed object index header
- *
- * struct pack_idx_header {
- *     uint32_t idx_signature;
- *     uint32_t idx_version;
- * };
- *
- * Note: this header isn't active yet.  In future versions of git
- * we may change the index file format.  At that time we would start
- * the first four bytes of the new index format with this signature,
- * as all older git binaries would find this value illegal and abort
- * reading the file.
+ * The first four bytes of index formats later than version 1 should
+ * start with this signature, as all older git binaries would find this
+ * value illegal and abort reading the file.
  *
  * This is the case because the number of objects in a packfile
  * cannot exceed 1,431,660,000 as every object would need at least
- * 3 bytes of data and the overall packfile cannot exceed 4 GiB due
- * to the 32 bit offsets used by the index.  Clearly the signature
- * exceeds this maximum.
+ * 3 bytes of data and the overall packfile cannot exceed 4 GiB with
+ * version 1 of the index file due to the offsets limited to 32 bits.
+ * Clearly the signature exceeds this maximum.
  *
  * Very old git binaries will also compare the first 4 bytes to the
  * next 4 bytes in the index and abort with a "non-monotonic index"
@@ -43,6 +34,15 @@ struct pack_header {
  */
 #define PACK_IDX_SIGNATURE 0xff744f63  /* "\377tOc" */
 
+/*
+ * Packed object index header
+ */
+struct pack_idx_header {
+       uint32_t idx_signature;
+       uint32_t idx_version;
+};
+
+
 extern int verify_pack(struct packed_git *, int);
 
 #define PH_ERROR_EOF           (-1)
index 5691448d732ffabc16d854001659870e503f665a..ee64865b607c70ff42f851b91c19316ef90ce7b9 100644 (file)
@@ -432,16 +432,15 @@ void pack_report()
                pack_mapped, peak_pack_mapped);
 }
 
-static int check_packed_git_idx(const char *path,
-       unsigned long *idx_size_,
-       void **idx_map_)
+static int check_packed_git_idx(const char *path,  struct packed_git *p)
 {
        void *idx_map;
-       uint32_t *index;
+       struct pack_idx_header *hdr;
        size_t idx_size;
-       uint32_t nr, i;
+       uint32_t nr, i, *index;
        int fd = open(path, O_RDONLY);
        struct stat st;
+
        if (fd < 0)
                return -1;
        if (fstat(fd, &st)) {
@@ -456,15 +455,12 @@ static int check_packed_git_idx(const char *path,
        idx_map = xmmap(NULL, idx_size, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);
 
-       index = idx_map;
-       *idx_map_ = idx_map;
-       *idx_size_ = idx_size;
-
        /* a future index format would start with this, as older git
         * binaries would fail the non-monotonic index check below.
         * give a nicer warning to the user if we can.
         */
-       if (index[0] == htonl(PACK_IDX_SIGNATURE)) {
+       hdr = idx_map;
+       if (hdr->idx_signature == htonl(PACK_IDX_SIGNATURE)) {
                munmap(idx_map, idx_size);
                return error("index file %s is a newer version"
                        " and is not supported by this binary"
@@ -473,6 +469,7 @@ static int check_packed_git_idx(const char *path,
        }
 
        nr = 0;
+       index = idx_map;
        for (i = 0; i < 256; i++) {
                uint32_t n = ntohl(index[i]);
                if (n < nr) {
@@ -494,6 +491,9 @@ static int check_packed_git_idx(const char *path,
                return error("wrong index file size in %s", path);
        }
 
+       p->index_version = 1;
+       p->index_data = idx_map;
+       p->index_size = idx_size;
        return 0;
 }
 
@@ -614,7 +614,7 @@ static int open_packed_git_1(struct packed_git *p)
                return error("end of packfile %s is unavailable", p->pack_name);
        if (read_in_full(p->pack_fd, sha1, sizeof(sha1)) != sizeof(sha1))
                return error("packfile %s signature is unavailable", p->pack_name);
-       idx_sha1 = ((unsigned char *)p->index_base) + p->index_size - 40;
+       idx_sha1 = ((unsigned char *)p->index_data) + p->index_size - 40;
        if (hashcmp(sha1, idx_sha1))
                return error("packfile %s does not match index", p->pack_name);
        return 0;
@@ -710,38 +710,37 @@ unsigned char* use_pack(struct packed_git *p,
        return win->base + offset;
 }
 
-struct packed_git *add_packed_git(char *path, int path_len, int local)
+struct packed_git *add_packed_git(const char *path, int path_len, int local)
 {
        struct stat st;
-       struct packed_git *p;
-       unsigned long idx_size;
-       void *idx_map;
-       unsigned char sha1[20];
+       struct packed_git *p = xmalloc(sizeof(*p) + path_len + 2);
 
-       if (check_packed_git_idx(path, &idx_size, &idx_map))
+       /*
+        * Make sure a corresponding .pack file exists and that
+        * the index looks sane.
+        */
+       path_len -= strlen(".idx");
+       if (path_len < 1)
                return NULL;
-
-       /* do we have a corresponding .pack file? */
-       strcpy(path + path_len - 4, ".pack");
-       if (stat(path, &st) || !S_ISREG(st.st_mode)) {
-               munmap(idx_map, idx_size);
+       memcpy(p->pack_name, path, path_len);
+       strcpy(p->pack_name + path_len, ".pack");
+       if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode) ||
+           check_packed_git_idx(path, p)) {
+               free(p);
                return NULL;
        }
+
        /* ok, it looks sane as far as we can check without
         * actually mapping the pack file.
         */
-       p = xmalloc(sizeof(*p) + path_len + 2);
-       strcpy(p->pack_name, path);
-       p->index_size = idx_size;
        p->pack_size = st.st_size;
-       p->index_base = idx_map;
        p->next = NULL;
        p->windows = NULL;
        p->pack_fd = -1;
        p->pack_local = local;
        p->mtime = st.st_mtime;
-       if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
-               hashcpy(p->sha1, sha1);
+       if (path_len < 40 || get_sha1_hex(path + path_len - 40, p->sha1))
+               hashclr(p->sha1);
        return p;
 }
 
@@ -751,23 +750,19 @@ struct packed_git *parse_pack_index(unsigned char *sha1)
        return parse_pack_index_file(sha1, path);
 }
 
-struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_path)
+struct packed_git *parse_pack_index_file(const unsigned char *sha1,
+                                        const char *idx_path)
 {
-       struct packed_git *p;
-       unsigned long idx_size;
-       void *idx_map;
-       char *path;
+       const char *path = sha1_pack_name(sha1);
+       struct packed_git *p = xmalloc(sizeof(*p) + strlen(path) + 2);
 
-       if (check_packed_git_idx(idx_path, &idx_size, &idx_map))
+       if (check_packed_git_idx(idx_path, p)) {
+               free(p);
                return NULL;
+       }
 
-       path = sha1_pack_name(sha1);
-
-       p = xmalloc(sizeof(*p) + strlen(path) + 2);
        strcpy(p->pack_name, path);
-       p->index_size = idx_size;
        p->pack_size = 0;
-       p->index_base = idx_map;
        p->next = NULL;
        p->windows = NULL;
        p->pack_fd = -1;
@@ -1357,6 +1352,65 @@ static void *unpack_compressed_entry(struct packed_git *p,
        return buffer;
 }
 
+#define MAX_DELTA_CACHE (256)
+
+static struct delta_base_cache_entry {
+       struct packed_git *p;
+       off_t base_offset;
+       unsigned long size;
+       void *data;
+       enum object_type type;
+} delta_base_cache[MAX_DELTA_CACHE];
+
+static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
+{
+       unsigned long hash;
+
+       hash = (unsigned long)p + (unsigned long)base_offset;
+       hash += (hash >> 8) + (hash >> 16);
+       return hash & 0xff;
+}
+
+static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
+       unsigned long *base_size, enum object_type *type, int keep_cache)
+{
+       void *ret;
+       unsigned long hash = pack_entry_hash(p, base_offset);
+       struct delta_base_cache_entry *ent = delta_base_cache + hash;
+
+       ret = ent->data;
+       if (ret && ent->p == p && ent->base_offset == base_offset)
+               goto found_cache_entry;
+       return unpack_entry(p, base_offset, type, base_size);
+
+found_cache_entry:
+       if (!keep_cache)
+               ent->data = NULL;
+       else {
+               ret = xmalloc(ent->size + 1);
+               memcpy(ret, ent->data, ent->size);
+               ((char *)ret)[ent->size] = 0;
+       }
+       *type = ent->type;
+       *base_size = ent->size;
+       return ret;
+}
+
+static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
+       void *base, unsigned long base_size, enum object_type type)
+{
+       unsigned long hash = pack_entry_hash(p, base_offset);
+       struct delta_base_cache_entry *ent = delta_base_cache + hash;
+
+       if (ent->data)
+               free(ent->data);
+       ent->p = p;
+       ent->base_offset = base_offset;
+       ent->type = type;
+       ent->data = base;
+       ent->size = base_size;
+}
+
 static void *unpack_delta_entry(struct packed_git *p,
                                struct pack_window **w_curs,
                                off_t curpos,
@@ -1370,7 +1424,7 @@ static void *unpack_delta_entry(struct packed_git *p,
        off_t base_offset;
 
        base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
-       base = unpack_entry(p, base_offset, type, &base_size);
+       base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0);
        if (!base)
                die("failed to read delta base object"
                    " at %"PRIuMAX" from %s",
@@ -1383,7 +1437,7 @@ static void *unpack_delta_entry(struct packed_git *p,
        if (!result)
                die("failed to apply delta");
        free(delta_data);
-       free(base);
+       add_delta_base_cache(p, base_offset, base, base_size, *type);
        return result;
 }
 
@@ -1423,24 +1477,27 @@ uint32_t num_packed_objects(const struct packed_git *p)
 int nth_packed_object_sha1(const struct packed_git *p, uint32_t n,
                           unsigned char* sha1)
 {
-       void *index = p->index_base + 256;
+       const unsigned char *index = p->index_data;
+       index += 4 * 256;
        if (num_packed_objects(p) <= n)
                return -1;
-       hashcpy(sha1, (unsigned char *) index + (24 * n) + 4);
+       hashcpy(sha1, index + 24 * n + 4);
        return 0;
 }
 
 off_t find_pack_entry_one(const unsigned char *sha1,
                                  struct packed_git *p)
 {
-       uint32_t *level1_ofs = p->index_base;
+       const uint32_t *level1_ofs = p->index_data;
        int hi = ntohl(level1_ofs[*sha1]);
        int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
-       void *index = p->index_base + 256;
+       const unsigned char *index = p->index_data;
+
+       index += 4 * 256;
 
        do {
                int mi = (lo + hi) / 2;
-               int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1);
+               int cmp = hashcmp(index + 24 * mi + 4, sha1);
                if (!cmp)
                        return ntohl(*((uint32_t *)((char *)index + (24 * mi))));
                if (cmp > 0)
@@ -1564,7 +1621,7 @@ static void *read_packed_sha1(const unsigned char *sha1,
        if (!find_pack_entry(sha1, &e, NULL))
                return NULL;
        else
-               return unpack_entry(e.p, e.offset, type, size);
+               return cache_or_unpack_entry(e.p, e.offset, size, type, 1);
 }
 
 /*
index 75c000a968c4b3a371393062e14801aa90ee53f1..9558bdb6318cc2956c43153084e1f1cc8386973f 100755 (executable)
@@ -145,9 +145,15 @@ test_expect_success 'test overriding tracking setup via --no-track' \
      git-config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
      (git-show-ref -q refs/remotes/local/master || git-fetch local) &&
      git-branch --no-track my2 local/master &&
+     git-config branch.autosetupmerge false &&
      ! test $(git-config branch.my2.remote) = local &&
      ! test $(git-config branch.my2.merge) = refs/heads/master'
 
+test_expect_success 'test local tracking setup' \
+    'git branch --track my6 s &&
+     test $(git-config branch.my6.remote) = . &&
+     test $(git-config branch.my6.merge) = refs/heads/s'
+
 # Keep this test last, as it changes the current branch
 cat >expect <<EOF
 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000     branch: Created from master
index f51154745586b246ecb30caee3f2150441911e1d..eacb1e92c20bf0efef069ff5ec0af792f95b1252 100755 (executable)
@@ -64,7 +64,7 @@ test_expect_success \
 cd "$TRASH"
 
 test_expect_success \
-    'pack with delta' \
+    'pack with REF_DELTA' \
     'pwd &&
      packname_2=$(git-pack-objects test-2 <obj-list)'
 
@@ -72,7 +72,7 @@ rm -fr .git2
 mkdir .git2
 
 test_expect_success \
-    'unpack with delta' \
+    'unpack with REF_DELTA' \
     'GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
      git-init &&
@@ -82,7 +82,7 @@ test_expect_success \
 unset GIT_OBJECT_DIRECTORY
 cd "$TRASH/.git2"
 test_expect_success \
-    'check unpack with delta' \
+    'check unpack with REF_DELTA' \
     '(cd ../.git && find objects -type f -print) |
      while read path
      do
@@ -93,6 +93,42 @@ test_expect_success \
      done'
 cd "$TRASH"
 
+test_expect_success \
+    'pack with OFS_DELTA' \
+    'pwd &&
+     packname_3=$(git-pack-objects --delta-base-offset test-3 <obj-list)'
+
+rm -fr .git2
+mkdir .git2
+
+test_expect_success \
+    'unpack with OFS_DELTA' \
+    'GIT_OBJECT_DIRECTORY=.git2/objects &&
+     export GIT_OBJECT_DIRECTORY &&
+     git-init &&
+     git-unpack-objects -n <test-3-${packname_3}.pack &&
+     git-unpack-objects <test-3-${packname_3}.pack'
+
+unset GIT_OBJECT_DIRECTORY
+cd "$TRASH/.git2"
+test_expect_success \
+    'check unpack with OFS_DELTA' \
+    '(cd ../.git && find objects -type f -print) |
+     while read path
+     do
+         cmp $path ../.git/$path || {
+            echo $path differs.
+            return 1
+        }
+     done'
+cd "$TRASH"
+
+test_expect_success \
+    'compare delta flavors' \
+    'size_2=`stat -c "%s" test-2-${packname_2}.pack` &&
+     size_3=`stat -c "%s" test-3-${packname_3}.pack` &&
+     test $size_2 -gt $size_3'
+
 rm -fr .git2
 mkdir .git2
 
@@ -111,12 +147,11 @@ test_expect_success \
     } >current &&
     diff expect current'
 
-
 test_expect_success \
-    'use packed deltified objects' \
+    'use packed deltified (REF_DELTA) objects' \
     'GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     rm -f .git2/objects/pack/test-?.idx &&
+     rm .git2/objects/pack/test-* &&
      cp test-2-${packname_2}.pack test-2-${packname_2}.idx .git2/objects/pack && {
         git-diff-tree --root -p $commit &&
         while read object
@@ -127,11 +162,28 @@ test_expect_success \
     } >current &&
     diff expect current'
 
+test_expect_success \
+    'use packed deltified (OFS_DELTA) objects' \
+    'GIT_OBJECT_DIRECTORY=.git2/objects &&
+     export GIT_OBJECT_DIRECTORY &&
+     rm .git2/objects/pack/test-* &&
+     cp test-3-${packname_3}.pack test-3-${packname_3}.idx .git2/objects/pack && {
+        git-diff-tree --root -p $commit &&
+        while read object
+        do
+           t=`git-cat-file -t $object` &&
+           git-cat-file $t $object || return 1
+        done <obj-list
+    } >current &&
+    diff expect current'
+
 unset GIT_OBJECT_DIRECTORY
 
 test_expect_success \
     'verify pack' \
-    'git-verify-pack test-1-${packname_1}.idx test-2-${packname_2}.idx'
+    'git-verify-pack   test-1-${packname_1}.idx \
+                       test-2-${packname_2}.idx \
+                       test-3-${packname_3}.idx'
 
 test_expect_success \
     'corrupt a pack and see if verify catches' \
@@ -194,6 +246,13 @@ test_expect_success \
      git-index-pack test-3.pack &&
      cmp test-3.idx test-2-${packname_2}.idx &&
 
+     cp test-3-${packname_3}.pack test-3.pack &&
+     git-index-pack -o tmp.idx test-3-${packname_3}.pack &&
+     cmp tmp.idx test-3-${packname_3}.idx &&
+
+     git-index-pack test-3.pack &&
+     cmp test-3.idx test-3-${packname_3}.idx &&
+
      :'
 
 test_done
index 7eb37838bb788dfb68361bca95860fd532276deb..243212d3dac03c19db18e9c8fcfc3b9049137cdd 100755 (executable)
@@ -29,5 +29,29 @@ test_expect_success 'checking the results' '
        diff file cloned/file
 '
 
+test_expect_success 'test . as a remote' '
+
+       git branch copy master &&
+       git config branch.copy.remote . &&
+       git config branch.copy.merge refs/heads/master &&
+       echo updated >file &&
+       git commit -a -m updated &&
+       git checkout copy &&
+       test `cat file` = file &&
+       git pull &&
+       test `cat file` = updated
+'
+
+test_expect_success 'the default remote . should not break explicit pull' '
+       git checkout -b second master^ &&
+       echo modified >file &&
+       git commit -a -m modified &&
+       git checkout copy &&
+       git reset --hard HEAD^ &&
+       test `cat file` = file &&
+       git pull . second &&
+       test `cat file` = modified
+'
+
 test_done
 
index 44cde74caf20ded9cd196c4e5d16f4d9ba251a22..3940962e79a5094e61270cd951d5d37c307d11a9 100644 (file)
@@ -5,9 +5,8 @@
 #include "diff.h"
 #include "tree.h"
 
-static char *malloc_base(const char *base, const char *path, int pathlen)
+static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)
 {
-       int baselen = strlen(base);
        char *newbase = xmalloc(baselen + pathlen + 2);
        memcpy(newbase, base, baselen);
        memcpy(newbase + baselen, path, pathlen);
@@ -16,9 +15,9 @@ static char *malloc_base(const char *base, const char *path, int pathlen)
 }
 
 static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
-                      const char *base);
+                      const char *base, int baselen);
 
-static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
+static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt)
 {
        unsigned mode1, mode2;
        const char *path1, *path2;
@@ -28,15 +27,15 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
        sha1 = tree_entry_extract(t1, &path1, &mode1);
        sha2 = tree_entry_extract(t2, &path2, &mode2);
 
-       pathlen1 = strlen(path1);
-       pathlen2 = strlen(path2);
+       pathlen1 = tree_entry_len(path1, sha1);
+       pathlen2 = tree_entry_len(path2, sha2);
        cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
        if (cmp < 0) {
-               show_entry(opt, "-", t1, base);
+               show_entry(opt, "-", t1, base, baselen);
                return -1;
        }
        if (cmp > 0) {
-               show_entry(opt, "+", t2, base);
+               show_entry(opt, "+", t2, base, baselen);
                return 1;
        }
        if (!opt->find_copies_harder && !hashcmp(sha1, sha2) && mode1 == mode2)
@@ -47,14 +46,14 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
         * file, we need to consider it a remove and an add.
         */
        if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
-               show_entry(opt, "-", t1, base);
-               show_entry(opt, "+", t2, base);
+               show_entry(opt, "-", t1, base, baselen);
+               show_entry(opt, "+", t2, base, baselen);
                return 0;
        }
 
        if (opt->recursive && S_ISDIR(mode1)) {
                int retval;
-               char *newbase = malloc_base(base, path1, pathlen1);
+               char *newbase = malloc_base(base, baselen, path1, pathlen1);
                if (opt->tree_in_recursive)
                        opt->change(opt, mode1, mode2,
                                    sha1, sha2, base, path1);
@@ -67,20 +66,20 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
        return 0;
 }
 
-static int interesting(struct tree_desc *desc, const char *base, struct diff_options *opt)
+static int interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt)
 {
        const char *path;
+       const unsigned char *sha1;
        unsigned mode;
        int i;
-       int baselen, pathlen;
+       int pathlen;
 
        if (!opt->nr_paths)
                return 1;
 
-       (void)tree_entry_extract(desc, &path, &mode);
+       sha1 = tree_entry_extract(desc, &path, &mode);
 
-       pathlen = strlen(path);
-       baselen = strlen(base);
+       pathlen = tree_entry_len(path, sha1);
 
        for (i=0; i < opt->nr_paths; i++) {
                const char *match = opt->paths[i];
@@ -121,18 +120,18 @@ static int interesting(struct tree_desc *desc, const char *base, struct diff_opt
 }
 
 /* A whole sub-tree went away or appeared */
-static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base)
+static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)
 {
        while (desc->size) {
-               if (interesting(desc, base, opt))
-                       show_entry(opt, prefix, desc, base);
+               if (interesting(desc, base, baselen, opt))
+                       show_entry(opt, prefix, desc, base, baselen);
                update_tree_entry(desc);
        }
 }
 
 /* A file entry went away or appeared */
 static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
-                      const char *base)
+                      const char *base, int baselen)
 {
        unsigned mode;
        const char *path;
@@ -140,7 +139,8 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
 
        if (opt->recursive && S_ISDIR(mode)) {
                enum object_type type;
-               char *newbase = malloc_base(base, path, strlen(path));
+               int pathlen = tree_entry_len(path, sha1);
+               char *newbase = malloc_base(base, baselen, path, pathlen);
                struct tree_desc inner;
                void *tree;
 
@@ -149,7 +149,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
                        die("corrupt tree sha %s", sha1_to_hex(sha1));
 
                inner.buf = tree;
-               show_tree(opt, prefix, &inner, newbase);
+               show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);
 
                free(tree);
                free(newbase);
@@ -160,28 +160,30 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
 
 int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
 {
+       int baselen = strlen(base);
+
        while (t1->size | t2->size) {
                if (opt->quiet && opt->has_changes)
                        break;
-               if (opt->nr_paths && t1->size && !interesting(t1, base, opt)) {
+               if (opt->nr_paths && t1->size && !interesting(t1, base, baselen, opt)) {
                        update_tree_entry(t1);
                        continue;
                }
-               if (opt->nr_paths && t2->size && !interesting(t2, base, opt)) {
+               if (opt->nr_paths && t2->size && !interesting(t2, base, baselen, opt)) {
                        update_tree_entry(t2);
                        continue;
                }
                if (!t1->size) {
-                       show_entry(opt, "+", t2, base);
+                       show_entry(opt, "+", t2, base, baselen);
                        update_tree_entry(t2);
                        continue;
                }
                if (!t2->size) {
-                       show_entry(opt, "-", t1, base);
+                       show_entry(opt, "-", t1, base, baselen);
                        update_tree_entry(t1);
                        continue;
                }
-               switch (compare_tree_entry(t1, t2, base, opt)) {
+               switch (compare_tree_entry(t1, t2, base, baselen, opt)) {
                case -1:
                        update_tree_entry(t1);
                        continue;
index 70f899957e8ce511f0f5a470e8b6927d58d1b63e..a4a4e2a9892fb10df32b113ca8b05848d11aff78 100644 (file)
@@ -32,7 +32,7 @@ static void entry_clear(struct name_entry *a)
 static void entry_extract(struct tree_desc *t, struct name_entry *a)
 {
        a->sha1 = tree_entry_extract(t, &a->path, &a->mode);
-       a->pathlen = strlen(a->path);
+       a->pathlen = tree_entry_len(a->path, a->sha1);
 }
 
 void update_tree_entry(struct tree_desc *desc)
@@ -169,7 +169,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
 
                sha1 = tree_entry_extract(t, &entry, mode);
                update_tree_entry(t);
-               entrylen = strlen(entry);
+               entrylen = tree_entry_len(entry, sha1);
                if (entrylen > namelen)
                        continue;
                cmp = memcmp(name, entry, entrylen);
index e57befa4dac0854906d5b792ce546dab0e6dcdc3..a0d7afd89bee1746912c61164e839daaa05a9b0c 100644 (file)
@@ -13,6 +13,11 @@ struct name_entry {
        int pathlen;
 };
 
+static inline int tree_entry_len(const char *name, const unsigned char *sha1)
+{
+       return (char *)sha1 - (char *)name - 1;
+}
+
 void update_tree_entry(struct tree_desc *);
 const unsigned char *tree_entry_extract(struct tree_desc *, const char **, unsigned int *);