From 394737eb4202844b6501851d7c8588164d370060 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 15 Oct 2006 00:34:47 -0700 Subject: [PATCH 001/781] pack-objects: use of version 3 delta is now optional. This introduces a new configuration item, pack.deltaversion, to control whether pack-objects is allowed to use version 3 delta. By default, we keep generating version 2 delta (and version 2 packfile format) to be compatible with git earlier than v1.2.0. This configuration affects the command in the following ways: - the resulting packfile will have the specified version; - when generating delta, larger copies are allowed only when deltaversion is 3; - the logic to reuse delta from existing packs refuses to reuse delta from packs that uses delta version 3 when the configuration is set to 2. Signed-off-by: Junio C Hamano --- builtin-pack-objects.c | 17 +++++++++++++---- cache.h | 1 + delta.h | 2 ++ diff-delta.c | 15 +++++++++++++-- environment.c | 3 +++ sha1_file.c | 1 + 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 96c069a81d..3532dc8557 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -456,7 +456,7 @@ static void write_pack_file(void) fprintf(stderr, "Writing %d objects.\n", nr_result); hdr.hdr_signature = htonl(PACK_SIGNATURE); - hdr.hdr_version = htonl(PACK_VERSION); + hdr.hdr_version = htonl(delta_version); hdr.hdr_entries = htonl(nr_result); sha1write(f, &hdr, sizeof(hdr)); offset = sizeof(hdr); @@ -914,12 +914,15 @@ static void check_object(struct object_entry *entry) /* Check if it is delta, and the base is also an object * we are going to pack. If so we will reuse the existing * delta. + * + * Also make sure that we do not reuse delta from an existing + * pack that uses higher delta version than allowed. */ if (!no_reuse_delta && entry->in_pack_type == OBJ_DELTA && (base_entry = locate_object_entry(base)) && - (!base_entry->preferred_base)) { - + (!base_entry->preferred_base) && + entry->in_pack->pack_version <= delta_version) { /* Depth value does not matter - find_deltas() * will never consider reused delta as the * base object to deltify other objects @@ -1101,6 +1104,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, * on an earlier try, but only when reusing delta data. */ if (!no_reuse_delta && trg_entry->in_pack && + trg_entry->in_pack->pack_version <= delta_version && trg_entry->in_pack == src_entry->in_pack) return 0; @@ -1326,10 +1330,15 @@ static void setup_progress_signal(void) static int git_pack_config(const char *k, const char *v) { - if(!strcmp(k, "pack.window")) { + if (!strcmp(k, "pack.window")) { window = git_config_int(k, v); return 0; } + if (!strcmp(k, "pack.deltaversion")) { + delta_version = git_config_int(k, v); + if (!pack_version_ok(htonl(delta_version))) + die("value %s for '%s' not allowed", v, k); + } return git_default_config(k, v); } diff --git a/cache.h b/cache.h index c35470107d..724c09ae4f 100644 --- a/cache.h +++ b/cache.h @@ -337,6 +337,7 @@ extern struct packed_git { unsigned int pack_last_used; unsigned int pack_use_cnt; int pack_local; + int pack_version; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ diff --git a/delta.h b/delta.h index 7b3f86d85f..55af3d285e 100644 --- a/delta.h +++ b/delta.h @@ -1,6 +1,8 @@ #ifndef DELTA_H #define DELTA_H +extern int delta_version; + /* opaque object for delta index */ struct delta_index; diff --git a/diff-delta.c b/diff-delta.c index fa16d06c8d..2f6dcfb0d7 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -253,10 +253,13 @@ create_delta(const struct delta_index *index, int inscnt; const unsigned char *ref_data, *ref_top, *data, *top; unsigned char *out; + unsigned int ref_size_limit; if (!trg_buf || !trg_size) return NULL; + ref_size_limit = (delta_version > 2) ? 0xffffff : 0x10000; + outpos = 0; outsize = 8192; if (max_size && outsize >= max_size) @@ -308,8 +311,8 @@ create_delta(const struct delta_index *index, continue; if (ref_size > top - src) ref_size = top - src; - if (ref_size > 0x10000) - ref_size = 0x10000; + if (ref_size > ref_size_limit) + ref_size = ref_size_limit; if (ref_size <= msize) break; while (ref_size-- && *src++ == *ref) @@ -318,6 +321,8 @@ create_delta(const struct delta_index *index, /* this is our best match so far */ msize = ref - entry->ptr; moff = entry->ptr - ref_data; + if (delta_version > 2 && msize >= 0x10000) + break; /* this is good enough */ } } @@ -381,6 +386,12 @@ create_delta(const struct delta_index *index, if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; } msize >>= 8; if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; } + if (delta_version > 2) { + msize >>= 8; + if (msize & 0xff) { + out[outpos++] = msize; i |= 0x40; + } + } *op = i; } diff --git a/environment.c b/environment.c index 63b1d155be..e266f83a8e 100644 --- a/environment.c +++ b/environment.c @@ -8,6 +8,7 @@ * are. */ #include "cache.h" +#include "pack.h" char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; @@ -25,6 +26,8 @@ const char *apply_default_whitespace; int zlib_compression_level = Z_DEFAULT_COMPRESSION; int pager_in_use; int pager_use_color = 1; +/* by default we allow 2 but up to PACK_VERSION is allowed */ +int delta_version = 2; static const char *git_dir; static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; diff --git a/sha1_file.c b/sha1_file.c index d111be74a3..665318243c 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -527,6 +527,7 @@ int use_packed_git(struct packed_git *p) p->pack_size - 20)) { die("packfile %s does not match index.", p->pack_name); } + p->pack_version = ntohl(hdr->hdr_version); } p->pack_last_used = pack_used_ctr++; p->pack_use_cnt++; From 69a4752063748932d26901fe1aca61381d381a7d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 15 Oct 2006 12:28:58 -0700 Subject: [PATCH 002/781] Revert "pack-objects: use of version 3 delta is now optional." This reverts commit 394737eb4202844b6501851d7c8588164d370060. Saving a few bytes per every 64kB of delta copied is not worth, when compared with the cost of backward compatibility worries. --- builtin-pack-objects.c | 17 ++++------------- cache.h | 1 - delta.h | 2 -- diff-delta.c | 15 ++------------- environment.c | 3 --- sha1_file.c | 1 - 6 files changed, 6 insertions(+), 33 deletions(-) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 3532dc8557..96c069a81d 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -456,7 +456,7 @@ static void write_pack_file(void) fprintf(stderr, "Writing %d objects.\n", nr_result); hdr.hdr_signature = htonl(PACK_SIGNATURE); - hdr.hdr_version = htonl(delta_version); + hdr.hdr_version = htonl(PACK_VERSION); hdr.hdr_entries = htonl(nr_result); sha1write(f, &hdr, sizeof(hdr)); offset = sizeof(hdr); @@ -914,15 +914,12 @@ static void check_object(struct object_entry *entry) /* Check if it is delta, and the base is also an object * we are going to pack. If so we will reuse the existing * delta. - * - * Also make sure that we do not reuse delta from an existing - * pack that uses higher delta version than allowed. */ if (!no_reuse_delta && entry->in_pack_type == OBJ_DELTA && (base_entry = locate_object_entry(base)) && - (!base_entry->preferred_base) && - entry->in_pack->pack_version <= delta_version) { + (!base_entry->preferred_base)) { + /* Depth value does not matter - find_deltas() * will never consider reused delta as the * base object to deltify other objects @@ -1104,7 +1101,6 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, * on an earlier try, but only when reusing delta data. */ if (!no_reuse_delta && trg_entry->in_pack && - trg_entry->in_pack->pack_version <= delta_version && trg_entry->in_pack == src_entry->in_pack) return 0; @@ -1330,15 +1326,10 @@ static void setup_progress_signal(void) static int git_pack_config(const char *k, const char *v) { - if (!strcmp(k, "pack.window")) { + if(!strcmp(k, "pack.window")) { window = git_config_int(k, v); return 0; } - if (!strcmp(k, "pack.deltaversion")) { - delta_version = git_config_int(k, v); - if (!pack_version_ok(htonl(delta_version))) - die("value %s for '%s' not allowed", v, k); - } return git_default_config(k, v); } diff --git a/cache.h b/cache.h index 724c09ae4f..c35470107d 100644 --- a/cache.h +++ b/cache.h @@ -337,7 +337,6 @@ extern struct packed_git { unsigned int pack_last_used; unsigned int pack_use_cnt; int pack_local; - int pack_version; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ diff --git a/delta.h b/delta.h index 55af3d285e..7b3f86d85f 100644 --- a/delta.h +++ b/delta.h @@ -1,8 +1,6 @@ #ifndef DELTA_H #define DELTA_H -extern int delta_version; - /* opaque object for delta index */ struct delta_index; diff --git a/diff-delta.c b/diff-delta.c index 2f6dcfb0d7..fa16d06c8d 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -253,13 +253,10 @@ create_delta(const struct delta_index *index, int inscnt; const unsigned char *ref_data, *ref_top, *data, *top; unsigned char *out; - unsigned int ref_size_limit; if (!trg_buf || !trg_size) return NULL; - ref_size_limit = (delta_version > 2) ? 0xffffff : 0x10000; - outpos = 0; outsize = 8192; if (max_size && outsize >= max_size) @@ -311,8 +308,8 @@ create_delta(const struct delta_index *index, continue; if (ref_size > top - src) ref_size = top - src; - if (ref_size > ref_size_limit) - ref_size = ref_size_limit; + if (ref_size > 0x10000) + ref_size = 0x10000; if (ref_size <= msize) break; while (ref_size-- && *src++ == *ref) @@ -321,8 +318,6 @@ create_delta(const struct delta_index *index, /* this is our best match so far */ msize = ref - entry->ptr; moff = entry->ptr - ref_data; - if (delta_version > 2 && msize >= 0x10000) - break; /* this is good enough */ } } @@ -386,12 +381,6 @@ create_delta(const struct delta_index *index, if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; } msize >>= 8; if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; } - if (delta_version > 2) { - msize >>= 8; - if (msize & 0xff) { - out[outpos++] = msize; i |= 0x40; - } - } *op = i; } diff --git a/environment.c b/environment.c index e266f83a8e..63b1d155be 100644 --- a/environment.c +++ b/environment.c @@ -8,7 +8,6 @@ * are. */ #include "cache.h" -#include "pack.h" char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; @@ -26,8 +25,6 @@ const char *apply_default_whitespace; int zlib_compression_level = Z_DEFAULT_COMPRESSION; int pager_in_use; int pager_use_color = 1; -/* by default we allow 2 but up to PACK_VERSION is allowed */ -int delta_version = 2; static const char *git_dir; static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; diff --git a/sha1_file.c b/sha1_file.c index 665318243c..d111be74a3 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -527,7 +527,6 @@ int use_packed_git(struct packed_git *p) p->pack_size - 20)) { die("packfile %s does not match index.", p->pack_name); } - p->pack_version = ntohl(hdr->hdr_version); } p->pack_last_used = pack_used_ctr++; p->pack_use_cnt++; From 0edad44201d9edf4c7d4640c8af9212e3ee23da9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 4 Nov 2006 12:24:05 -0800 Subject: [PATCH 003/781] adjust_shared_perm: chmod() only when needed. When widening permission for files and directories in a 'shared' repository for a user with inappropriate umask() setting for shared work, make sure we call chmod() only when we actually need to. The primary idea owes credit to Johannes. Signed-off-by: Junio C Hamano --- path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/path.c b/path.c index bb89fb02dc..d2c076d7cb 100644 --- a/path.c +++ b/path.c @@ -279,7 +279,7 @@ int adjust_shared_perm(const char *path) : 0)); if (S_ISDIR(mode)) mode |= S_ISGID; - if (chmod(path, mode) < 0) + if ((mode & st.st_mode) != mode && chmod(path, mode) < 0) return -2; return 0; } From a2a92ab17fe120f6b28d123ac2fd41f066f0de1e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 29 Nov 2006 18:53:13 -0800 Subject: [PATCH 004/781] git-merge: preserve and merge local changes when doing fast forward The idea and the logic are identical to what "checkout -m" does when switching the branches. Instead of refusing the two-way merge, perform the three-way merge between the old head, the working tree and the new head, and leave the (potentially conflicted) merge result in the working tree. When the resulting conflict were too much to handle for the user, there is no easy way to get that back, so they are stashed away in $GIT_DIR/LOCAL_DIFF file. We do the same for "git checkout -m". If this turns out to be a sane thing to do, we probably should make the common logic between "checkout -m" and this into a built-in command. Signed-off-by: Junio C Hamano --- git-checkout.sh | 7 +++++++ git-merge.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/git-checkout.sh b/git-checkout.sh index 737abd0c09..5bf399a276 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -168,6 +168,9 @@ else exit 1 ;; esac + # First stash away the local changes + git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF + # Match the index to the working tree, and do a three-way. git diff-files --name-only | git update-index --remove --stdin && work=`git write-tree` && @@ -195,6 +198,10 @@ else sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" echo "$unmerged" ) | git update-index --index-info + + echo >&2 "Conflicts in locally modified files:" + git diff --name-only --diff-filter=U >&2 + echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" ;; esac exit 0 diff --git a/git-merge.sh b/git-merge.sh index 272f004622..798aad3576 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -91,6 +91,51 @@ finish () { esac } +merge_local_changes () { + merge_error=$(git-read-tree -m -u $1 $2 2>&1) || ( + + # First stash away the local changes + git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF + + # Match the index to the working tree, and do a three-way. + git diff-files --name-only | + git update-index --remove --stdin && + work=`git write-tree` && + git read-tree --reset -u $2 && + git read-tree -m -u --aggressive $1 $2 $work || exit + + echo >&2 "Carrying local changes forward." + if result=`git write-tree 2>/dev/null` + then + echo >&2 "Trivially automerged." + else + git merge-index -o git-merge-one-file -a + fi + + # Do not register the cleanly merged paths in the index + # yet; this is not a real merge before committing, but + # just carrying the working tree changes along. + unmerged=`git ls-files -u` + git read-tree --reset $2 + case "$unmerged" in + '') ;; + *) + ( + z40=0000000000000000000000000000000000000000 + echo "$unmerged" | + sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" + echo "$unmerged" + ) | git update-index --index-info + + echo >&2 "Conflicts in locally modified files:" + git diff --name-only --diff-filter=U >&2 + echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" + ;; + esac + exit 0 + ) +} + case "$#" in 0) usage ;; esac rloga= have_message= @@ -264,7 +309,7 @@ f,*) 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 -u -v -m $head "$new_head" && + merge_local_changes $head $new_head && finish "$new_head" "Fast forward" dropsave exit 0 From 40e0e66bb00646fbdc998c4fe01280470489d0e5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 8 Jan 2007 23:26:19 -0800 Subject: [PATCH 005/781] merge_base(): move traversal into a separate function. Signed-off-by: Junio C Hamano --- commit.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/commit.c b/commit.c index aa14c5adb0..53f43e3638 100644 --- a/commit.c +++ b/commit.c @@ -1034,25 +1034,10 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *merge_bases(struct commit *one, struct commit *two) +static struct commit_list *base_traverse(struct commit_list *list) { - struct commit_list *list = NULL; struct commit_list *result = NULL; - if (one == two) - /* We do not mark this even with RESULT so we do not - * have to clean it up. - */ - return commit_list_insert(one, &result); - - parse_commit(one); - parse_commit(two); - - one->object.flags |= PARENT1; - two->object.flags |= PARENT2; - insert_by_date(one, &list); - insert_by_date(two, &list); - while (interesting(list)) { struct commit *commit; struct commit_list *parents; @@ -1098,6 +1083,27 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two) return result; } +static struct commit_list *merge_bases(struct commit *one, struct commit *two) +{ + struct commit_list *list = NULL; + + if (one == two) + /* We do not mark this even with RESULT so we do not + * have to clean it up. + */ + return commit_list_insert(one, &list); + + parse_commit(one); + parse_commit(two); + + one->object.flags |= PARENT1; + two->object.flags |= PARENT2; + insert_by_date(one, &list); + insert_by_date(two, &list); + + return base_traverse(list); +} + struct commit_list *get_merge_bases(struct commit *one, struct commit *two, int cleanup) From dc3806d39698899fe81e55c0daa5bd9d30d13d9c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 9 Jan 2007 01:32:25 -0800 Subject: [PATCH 006/781] in_merge_bases(): optimization The callers of in_merge_bases() are interested in finding out if the given commit is reachable from others, and we do not have to compute the true merge base. Signed-off-by: Junio C Hamano --- commit.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/commit.c b/commit.c index 53f43e3638..bbfe7dc686 100644 --- a/commit.c +++ b/commit.c @@ -1034,7 +1034,7 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *base_traverse(struct commit_list *list) +static struct commit_list *base_traverse(struct commit_list *list, struct commit *stop) { struct commit_list *result = NULL; @@ -1068,10 +1068,20 @@ static struct commit_list *base_traverse(struct commit_list *list) p->object.flags |= flags; insert_by_date(p, &list); } + if (stop && (stop->object.flags & PARENT2)) { + free_commit_list(list); + list = NULL; + insert_by_date(stop, &list); + return list; + } } /* Clean up the result to remove stale ones */ free_commit_list(list); + + if (stop) + return NULL; + list = result; result = NULL; while (list) { struct commit_list *n = list->next; @@ -1101,7 +1111,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two) insert_by_date(one, &list); insert_by_date(two, &list); - return base_traverse(list); + return base_traverse(list, NULL); } struct commit_list *get_merge_bases(struct commit *one, @@ -1166,20 +1176,30 @@ struct commit_list *get_merge_bases(struct commit *one, int in_merge_bases(struct commit *commit, struct commit **reference, int num) { - struct commit_list *bases, *b; - int ret = 0; + struct commit_list *result, *list; + int i, ret; - if (num == 1) - bases = get_merge_bases(commit, *reference, 1); - else - die("not yet"); - for (b = bases; b; b = b->next) { - if (!hashcmp(commit->object.sha1, b->item->object.sha1)) { - ret = 1; - break; + list = NULL; + parse_commit(commit); + commit->object.flags |= PARENT1; + insert_by_date(commit, &list); + + for (i = 0; i < num; i++) { + struct commit *two = reference[i]; + parse_commit(two); + if (!(two->object.flags & PARENT2)) { + two->object.flags |= PARENT2; + insert_by_date(two, &list); } } + result = base_traverse(list, commit); + ret = !!result; + free_commit_list(result); - free_commit_list(bases); + clear_commit_marks(commit, all_flags); + for (i = 0; i < num; i++) { + struct commit *two = reference[i]; + clear_commit_marks(two, all_flags); + } return ret; } From cdea3553ef02b463afb66c4251b8574ba1365ede Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:36:47 +0100 Subject: [PATCH 007/781] Split the big verify-pack test into individual tests. This makes it easier to spot which of the tests failed. --- t/t5300-pack-object.sh | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index f511547455..622c5f9968 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -134,49 +134,51 @@ test_expect_success \ 'git-verify-pack test-1-${packname_1}.idx test-2-${packname_2}.idx' test_expect_success \ - 'corrupt a pack and see if verify catches' \ + 'verify-pack catches mismatched .idx and .pack files' \ 'cp test-1-${packname_1}.idx test-3.idx && cp test-2-${packname_2}.pack test-3.pack && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : PACK_SIGNATURE && - cp test-1-${packname_1}.pack test-3.pack && +test_expect_success \ + 'verify-pack catches a corrupted pack signature' \ + 'cp test-1-${packname_1}.pack test-3.pack && dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : PACK_VERSION && - cp test-1-${packname_1}.pack test-3.pack && +test_expect_success \ + 'verify-pack catches a corrupted pack version' \ + 'cp test-1-${packname_1}.pack test-3.pack && dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : TYPE/SIZE byte of the first packed object data && - cp test-1-${packname_1}.pack test-3.pack && +test_expect_success \ + 'verify-pack catches a corrupted type/size of the 1st packed object data' \ + 'cp test-1-${packname_1}.pack test-3.pack && dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && if git-verify-pack test-3.idx then false else :; - fi && + fi' - : sum of the index file itself && - l=`wc -c Date: Thu, 18 Jan 2007 11:21:30 +0100 Subject: [PATCH 008/781] Lose perl dependency. Perl is just used to reverse stdin, which can be done with a simple sed construct as well. Signed-off-by: Simon 'corecode' Schubert --- git-rebase.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-rebase.sh b/git-rebase.sh index c8bd0f99d1..c34a0d2fc5 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -332,7 +332,7 @@ echo "$prev_head" > "$dotest/prev_head" msgnum=0 for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \ - | @@PERL@@ -e 'print reverse <>'` + | sed -ne '1!G;$p;h'` do msgnum=$(($msgnum + 1)) echo "$cmt" > "$dotest/cmt.$msgnum" From 9983977758b00215f93ec636f009df5312a74537 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 16 Jan 2007 16:35:34 +0100 Subject: [PATCH 009/781] Move the revision walker into a separate function. --- upload-pack.c | 70 +++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 3a466c6a3e..0ce8ceeeac 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -96,6 +96,42 @@ static void show_edge(struct commit *commit) fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1)); } +static void do_rev_list(int create_full_pack) +{ + int i; + struct rev_info revs; + + if (create_full_pack) + use_thin_pack = 0; /* no point doing it */ + init_revisions(&revs, NULL); + revs.tag_objects = 1; + revs.tree_objects = 1; + revs.blob_objects = 1; + if (use_thin_pack) + revs.edge_hint = 1; + + if (create_full_pack) { + const char *args[] = {"rev-list", "--all", NULL}; + setup_revisions(2, args, &revs, NULL); + } else { + for (i = 0; i < want_obj.nr; i++) { + struct object *o = want_obj.objects[i].item; + /* why??? */ + o->flags &= ~UNINTERESTING; + add_pending_object(&revs, o, NULL); + } + for (i = 0; i < have_obj.nr; i++) { + struct object *o = have_obj.objects[i].item; + o->flags |= UNINTERESTING; + add_pending_object(&revs, o, NULL); + } + setup_revisions(0, NULL, &revs, NULL); + } + prepare_revision_walk(&revs); + mark_edges_uninteresting(revs.commits, &revs, show_edge); + traverse_commit_list(&revs, show_commit, show_object); +} + static void create_pack_file(void) { /* Pipes between rev-list to pack-objects, pack-objects to us @@ -116,40 +152,8 @@ static void create_pack_file(void) die("git-upload-pack: unable to fork git-rev-list"); if (!pid_rev_list) { - int i; - struct rev_info revs; - pack_pipe = fdopen(lp_pipe[1], "w"); - - if (create_full_pack) - use_thin_pack = 0; /* no point doing it */ - init_revisions(&revs, NULL); - revs.tag_objects = 1; - revs.tree_objects = 1; - revs.blob_objects = 1; - if (use_thin_pack) - revs.edge_hint = 1; - - if (create_full_pack) { - const char *args[] = {"rev-list", "--all", NULL}; - setup_revisions(2, args, &revs, NULL); - } else { - for (i = 0; i < want_obj.nr; i++) { - struct object *o = want_obj.objects[i].item; - /* why??? */ - o->flags &= ~UNINTERESTING; - add_pending_object(&revs, o, NULL); - } - for (i = 0; i < have_obj.nr; i++) { - struct object *o = have_obj.objects[i].item; - o->flags |= UNINTERESTING; - add_pending_object(&revs, o, NULL); - } - setup_revisions(0, NULL, &revs, NULL); - } - prepare_revision_walk(&revs); - mark_edges_uninteresting(revs.commits, &revs, show_edge); - traverse_commit_list(&revs, show_commit, show_object); + do_rev_list(create_full_pack); exit(0); } From 14cd93911230bc2306d548eb7393f01a36d801b4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 22 Dec 2006 11:43:50 +0100 Subject: [PATCH 010/781] Make git compile under MinGW. These changes are courtesy Johannes Schindelin. --- Makefile | 24 +++++- builtin-count-objects.c | 4 + compat/mingw.c | 164 ++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 108 ++++++++++++++++++++++++-- help.c | 2 +- ident.c | 22 ++++++ path.c | 11 +++ 7 files changed, 324 insertions(+), 11 deletions(-) create mode 100644 compat/mingw.c diff --git a/Makefile b/Makefile index 963a8f64e9..64d7f49019 100644 --- a/Makefile +++ b/Makefile @@ -192,9 +192,8 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS = \ - git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \ + git-fetch-pack$X git-fsck-objects$X \ git-hash-object$X git-index-pack$X git-local-fetch$X \ - git-daemon$X \ git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \ git-peek-remote$X git-receive-pack$X \ git-send-pack$X git-shell$X \ @@ -203,7 +202,7 @@ PROGRAMS = \ git-update-server-info$X \ git-upload-pack$X git-verify-pack$X \ git-pack-redundant$X git-var$X \ - git-merge-tree$X git-imap-send$X \ + git-merge-tree$X \ git-merge-recursive$X \ $(EXTRA_PROGRAMS) @@ -412,6 +411,25 @@ ifeq ($(uname_S),IRIX64) # for now, build 32-bit version BASIC_LDFLAGS += -L/usr/lib32 endif +ifneq (,$(findstring MINGW,$(uname_S))) + SHELL_PATH = $(shell cd /bin && pwd -W)/sh + NO_MMAP=YesPlease + NO_PREAD=YesPlease + NO_OPENSSL=YesPlease + NO_CURL=YesPlease + NO_SYMLINK_HEAD=YesPlease + NO_IPV6=YesPlease + NO_ETC_PASSWD=YesPlease + NO_SETENV=YesPlease + NO_UNSETENV=YesPlease + NO_STRCASESTR=YesPlease + NO_STRLCPY=YesPlease + NO_ICONV=YesPlease + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS + COMPAT_OBJS += compat/mingw.o + EXTLIBS += -lws2_32 + X = .exe +endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease endif diff --git a/builtin-count-objects.c b/builtin-count-objects.c index f5b22bb80e..a2df569a0d 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -44,7 +44,11 @@ static void count_objects(DIR *d, char *path, int len, int verbose, if (lstat(path, &st) || !S_ISREG(st.st_mode)) bad = 1; else +#ifndef NO_ST_BLOCKS (*loose_size) += st.st_blocks; +#else + (*loose_size) += (st.st_size+511)/512; +#endif } if (bad) { if (verbose) { diff --git a/compat/mingw.c b/compat/mingw.c new file mode 100644 index 0000000000..0f7077983f --- /dev/null +++ b/compat/mingw.c @@ -0,0 +1,164 @@ +#include +#include "../git-compat-util.h" + +int readlink(const char *path, char *buf, size_t bufsiz) +{ + errno = EINVAL; + return -1; +} + +int symlink(const char *oldpath, const char *newpath) +{ + errno = EFAULT; + return -1; +} + +int fchmod(int fildes, mode_t mode) +{ + errno = EBADF; + return -1; +} + +int lstat(const char *file_name, struct stat *buf) +{ + return stat(file_name, buf); +} + +/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ +int socketpair(int d, int type, int protocol, int sv[2]) +{ + return -1; +} +int syslog(int type, char *bufp, ...) +{ + return -1; +} +unsigned int alarm(unsigned int seconds) +{ + return 0; +} +#include +int fork() +{ + return -1; +} +typedef int pid_t; +pid_t waitpid(pid_t pid, int *status, int options) +{ + errno = ECHILD; + return -1; +} + +int kill(pid_t pid, int sig) +{ + return -1; +} +int sigaction(int p1, const struct sigaction *p2, struct sigaction *p3) +{ + return -1; +} +int sigemptyset(sigset_t *p1) +{ + return -1; +} +int setitimer(int __which, const struct itimerval *__value, + struct itimerval *__ovalue) +{ + return -1; +} +unsigned int sleep (unsigned int __seconds) +{ + return 0; +} +const char *inet_ntop(int af, const void *src, + char *dst, size_t cnt) +{ + return NULL; +} +int mkstemp (char *__template) +{ + return -1; +} +int gettimeofday(struct timeval *tv, void *tz) +{ + return -1; +} +int pipe(int filedes[2]) +{ + return -1; +} + +int poll(struct pollfd *ufds, unsigned int nfds, int timeout) +{ + return -1; +} + +int fnmatch(const char *pattern, const char *string, int flags) +{ + return -1; +} + +int regcomp(regex_t *preg, const char *regex, int cflags) +{ + return -1; +} +size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +{ + return 0; +} +void regfree(regex_t *preg) +{ +} + +int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) +{ + return -1; +} + +#undef mkdir +int git_mkdir(const char *path, int mode) +{ + return mkdir(path); +} + +#include + +struct tm *gmtime_r(const time_t *timep, struct tm *result) +{ + memcpy(result, gmtime(timep), sizeof(struct tm)); + return result; +} + +struct tm *localtime_r(const time_t *timep, struct tm *result) +{ + memcpy(result, localtime(timep), sizeof(struct tm)); + return result; +} + +#undef getcwd +char *mingw_getcwd(char *pointer, int len) +{ + char *ret = getcwd(pointer, len); + if (!ret) + return ret; + if (pointer[0] != 0 && pointer[1] == ':') { + int i; + pointer[1] = pointer[0]; + pointer[0] = '/'; + for (i = 2; pointer[i]; i++) + /* Thanks, Bill. You'll burn in hell for that. */ + if (pointer[i] == '\\') + pointer[i] = '/'; + } + return ret; +} +const char *strptime(char *buf, const char *format, struct tm *tm) +{ + die("MinGW does not yet support strptime!"); +} +void sync(void) +{ +} +void openlog(const char *ident, int option, int facility) +{ +} diff --git a/git-compat-util.h b/git-compat-util.h index bf3ceb8027..2bdae6725d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -35,21 +35,23 @@ #include #include #include -#include -#include -#include -#include +//#include +//#include +//#include +//#include #include #include -#include -#include -#include +//#include +//#include +//#include +#ifndef NO_ETC_PASSWD #include #include #include #undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */ #include #define _ALL_SOURCE 1 +#endif #ifndef NO_ICONV #include @@ -271,4 +273,96 @@ static inline int sane_case(int x, int high) return x; } +// MinGW + +#ifndef S_ISLNK +#define S_ISLNK(x) 0 +#define S_IFLNK 0 +#endif + +#ifndef S_ISGRP +#define S_ISGRP(x) 0 +#define S_IRGRP 0 +#define S_IWGRP 0 +#define S_IXGRP 0 +#define S_ISGID 0 +#define S_IROTH 0 +#define S_IXOTH 0 +#endif + +int readlink(const char *path, char *buf, size_t bufsiz); +int symlink(const char *oldpath, const char *newpath); +#define link symlink +int fchmod(int fildes, mode_t mode); +int lstat(const char *file_name, struct stat *buf); + +/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ +int socketpair(int d, int type, int protocol, int sv[2]); +#define AF_UNIX 0 +#define SOCK_STREAM 0 +int syslog(int type, char *bufp, ...); +#define LOG_ERR 1 +#define LOG_INFO 2 +#define LOG_DAEMON 4 +unsigned int alarm(unsigned int seconds); +#include +int fork(); +typedef int pid_t; +pid_t waitpid(pid_t pid, int *status, int options); +#define WIFEXITED(x) 0 +#define WEXITSTATUS(x) 1 +#define WIFSIGNALED(x) -1 +#define WTERMSIG(x) 0 +#define WNOHANG 0 +#define SIGKILL 0 +#define SIGCHLD 0 +#define SIGALRM 0 +#define ECONNABORTED 0 + +int kill(pid_t pid, int sig); +unsigned int sleep (unsigned int __seconds); +const char *inet_ntop(int af, const void *src, + char *dst, size_t cnt); +int mkstemp (char *__template); +int gettimeofday(struct timeval *tv, void *tz); +int pipe(int filedes[2]); + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; +int poll(struct pollfd *ufds, unsigned int nfds, int timeout); +#define POLLIN 1 +#define POLLHUP 2 +int fnmatch(const char *pattern, const char *string, int flags); +#define FNM_PATHNAME 1 + +typedef int siginfo_t; +struct sigaction { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; +#define SA_RESTART 0 +#define ITIMER_REAL 0 + +struct itimerval { struct timeval it_interval, it_value; }; + +int git_mkdir(const char *path, int mode); +#define mkdir git_mkdir + +#include +struct tm *gmtime_r(const time_t *timep, struct tm *result); +struct tm *localtime_r(const time_t *timep, struct tm *result); +#define hstrerror strerror + +char *mingw_getcwd(char *pointer, int len); +#define getcwd mingw_getcwd + +#define setlinebuf(x) +#define fsync(x) + #endif diff --git a/help.c b/help.c index 341b9e370e..2f7ef39661 100644 --- a/help.c +++ b/help.c @@ -7,7 +7,7 @@ #include "builtin.h" #include "exec_cmd.h" #include "common-cmds.h" -#include +//#include /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) diff --git a/ident.c b/ident.c index 6ad8fedd60..83ce631a06 100644 --- a/ident.c +++ b/ident.c @@ -9,6 +9,8 @@ static char git_default_date[50]; +#ifndef NO_ETC_PASSWD + static void copy_gecos(struct passwd *w, char *name, int sz) { char *src, *dst; @@ -77,6 +79,8 @@ int setup_ident(void) return 0; } +#else /* NO_ETC_PASSWD */ + static int add_raw(char *buf, int size, int offset, const char *str) { int len = strlen(str); @@ -152,6 +156,13 @@ static int copy(char *buf, int size, int offset, const char *src) return offset; } +int setup_ident(void) +{ + return 0; +} + +#endif + static const char au_env[] = "GIT_AUTHOR_NAME"; static const char co_env[] = "GIT_COMMITTER_NAME"; static const char *env_hint = @@ -219,6 +230,8 @@ const char *git_committer_info(int error_on_no_name) error_on_no_name); } +#ifndef NO_ETC_PASSWD + void ignore_missing_committer_name() { /* If we did not get a name from the user's gecos entry then @@ -233,3 +246,12 @@ void ignore_missing_committer_name() strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name)); } } + +#else + +void ignore_missing_committer_name() +{ + strcpy(git_default_name, "unknown"); +} + +#endif diff --git a/path.c b/path.c index c5d25a4b90..d66d6a1ec1 100644 --- a/path.c +++ b/path.c @@ -140,6 +140,8 @@ int validate_headref(const char *path) return -1; } +#ifndef NO_ETC_PASSWD + static char *user_path(char *buf, char *path, int sz) { struct passwd *pw; @@ -179,6 +181,15 @@ static char *user_path(char *buf, char *path, int sz) return buf; } +#else + +static char *user_path(char *buf, char *path, int sz) +{ + return getenv("HOME"); +} + +#endif + /* * First, one directory to try is determined by the following algorithm. * From 65e40a61951a62393ec474724d7ffad677afa57e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 15:38:36 +0200 Subject: [PATCH 011/781] Provide inlined mkdir wrapper. --- compat/mingw.c | 6 ------ git-compat-util.h | 5 ++++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0f7077983f..f85b0d2f52 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -115,12 +115,6 @@ int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t p return -1; } -#undef mkdir -int git_mkdir(const char *path, int mode) -{ - return mkdir(path); -} - #include struct tm *gmtime_r(const time_t *timep, struct tm *result) diff --git a/git-compat-util.h b/git-compat-util.h index 2bdae6725d..4ad37467e9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -351,7 +351,10 @@ struct sigaction { struct itimerval { struct timeval it_interval, it_value; }; -int git_mkdir(const char *path, int mode); +static inline int git_mkdir(const char *path, int mode) +{ + return mkdir(path); +} #define mkdir git_mkdir #include From 649a5ce8d65248df5aed42926a207f9b8f1f806a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 12:34:51 +0200 Subject: [PATCH 012/781] require regex (http://ftp.gnu.org/pub/gnu/regex/) --- Makefile | 2 +- compat/mingw.c | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 64d7f49019..0f3460567b 100644 --- a/Makefile +++ b/Makefile @@ -427,7 +427,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_ICONV=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS COMPAT_OBJS += compat/mingw.o - EXTLIBS += -lws2_32 + EXTLIBS += -lws2_32 -lregex X = .exe endif ifneq (,$(findstring arm,$(uname_M))) diff --git a/compat/mingw.c b/compat/mingw.c index f85b0d2f52..d2e83f74a3 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -98,23 +98,6 @@ int fnmatch(const char *pattern, const char *string, int flags) return -1; } -int regcomp(regex_t *preg, const char *regex, int cflags) -{ - return -1; -} -size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) -{ - return 0; -} -void regfree(regex_t *preg) -{ -} - -int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) -{ - return -1; -} - #include struct tm *gmtime_r(const time_t *timep, struct tm *result) From b4792a360ea7acad4d45aa85ad5fdc0cf44dfbdb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 17:25:42 +0200 Subject: [PATCH 013/781] Include fnmatch from GNU make. --- Makefile | 4 +- compat/fnmatch.c | 488 ++++++++++++++++++++++++++++++++++++++++++++++ compat/fnmatch.h | 84 ++++++++ compat/mingw.c | 5 - git-compat-util.h | 4 +- 5 files changed, 575 insertions(+), 10 deletions(-) create mode 100755 compat/fnmatch.c create mode 100644 compat/fnmatch.h diff --git a/Makefile b/Makefile index 0f3460567b..874e529e58 100644 --- a/Makefile +++ b/Makefile @@ -425,8 +425,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease NO_ICONV=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS - COMPAT_OBJS += compat/mingw.o + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -I compat + COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex X = .exe endif diff --git a/compat/fnmatch.c b/compat/fnmatch.c new file mode 100755 index 0000000000..1f4ead5f98 --- /dev/null +++ b/compat/fnmatch.c @@ -0,0 +1,488 @@ +/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#include +#include +#include + +#if HAVE_STRING_H || defined _LIBC +# include +#else +# include +#endif + +#if defined STDC_HEADERS || defined _LIBC +# include +#endif + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +#endif + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined _LIBC || !defined __GNU_LIBRARY__ + + +# if defined STDC_HEADERS || !defined isascii +# define ISASCII(c) 1 +# else +# define ISASCII(c) isascii(c) +# endif + +# ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +# else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +# endif +# ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +# else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +# endif + +# define ISPRINT(c) (ISASCII (c) && isprint (c)) +# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +# define ISALNUM(c) (ISASCII (c) && isalnum (c)) +# define ISALPHA(c) (ISASCII (c) && isalpha (c)) +# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +# define ISLOWER(c) (ISASCII (c) && islower (c)) +# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +# define ISSPACE(c) (ISASCII (c) && isspace (c)) +# define ISUPPER(c) (ISASCII (c) && isupper (c)) +# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +# else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +# if !defined _LIBC && !defined getenv +extern char *getenv (); +# endif + +# ifndef errno +extern int errno; +# endif + +/* This function doesn't exist on most systems. */ + +# if !defined HAVE___STRCHRNUL && !defined _LIBC +static char * +__strchrnul (s, c) + const char *s; + int c; +{ + char *result = strchr (s, c); + if (result == NULL) + result = strchr (s, '\0'); + return result; +} +# endif + +# ifndef internal_function +/* Inside GNU libc we mark some function in a special way. In other + environments simply ignore the marking. */ +# define internal_function +# endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +static int internal_fnmatch __P ((const char *pattern, const char *string, + int no_leading_period, int flags)) + internal_function; +static int +internal_function +internal_fnmatch (pattern, string, no_leading_period, flags) + const char *pattern; + const char *string; + int no_leading_period; + int flags; +{ + register const char *p = pattern, *n = string; + register unsigned char c; + +/* Note that this evaluates C many times. */ +# ifdef _LIBC +# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) +# else +# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) +# endif + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if (*n == '/' && (flags & FNM_FILE_NAME)) + return FNM_NOMATCH; + else if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; + c = FOLD (c); + } + if (FOLD ((unsigned char) *n) != c) + return FNM_NOMATCH; + break; + + case '*': + if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* A slash does not match a wildcard under FNM_FILE_NAME. */ + return FNM_NOMATCH; + else if (c == '?') + { + /* A ? needs to match one character. */ + if (*n == '\0') + /* There isn't another character; no match. */ + return FNM_NOMATCH; + else + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + less than three characters. */ + ++n; + } + } + + if (c == '\0') + /* The wildcard(s) is/are the last element of the pattern. + If the name is a file name and contains another slash + this does mean it cannot match. */ + return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL + ? FNM_NOMATCH : 0); + else + { + const char *endp; + + endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0'); + + if (c == '[') + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + for (--p; n < endp; ++n) + if (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) + == 0) + return 0; + } + else if (c == '/' && (flags & FNM_FILE_NAME)) + { + while (*n != '\0' && *n != '/') + ++n; + if (*n == '/' + && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD, + flags) == 0)) + return 0; + } + else + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *p; + c = FOLD (c); + for (--p; n < endp; ++n) + if (FOLD ((unsigned char) *n) == c + && (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) == 0)) + return 0; + } + } + + /* If we come here no match is possible with the wildcard. */ + return FNM_NOMATCH; + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + static int posixly_correct; + register int not; + char cold; + + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + if (*n == '\0') + return FNM_NOMATCH; + + if (*n == '.' && no_leading_period && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))) + return FNM_NOMATCH; + + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* `/' cannot be matched. */ + return FNM_NOMATCH; + + not = (*p == '!' || (posixly_correct < 0 && *p == '^')); + if (not) + ++p; + + c = *p++; + for (;;) + { + unsigned char fn = FOLD ((unsigned char) *n); + + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + c = FOLD ((unsigned char) *p); + ++p; + + if (c == fn) + goto matched; + } + else if (c == '[' && *p == ':') + { + /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + size_t c1 = 0; +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wctype_t wt; +# endif + const char *startp = p; + + for (;;) + { + if (c1 == CHAR_CLASS_MAX_LENGTH) + /* The name is too long and therefore the pattern + is ill-formed. */ + return FNM_NOMATCH; + + c = *++p; + if (c == ':' && p[1] == ']') + { + p += 2; + break; + } + if (c < 'a' || c >= 'z') + { + /* This cannot possibly be a character class name. + Match it as a normal range. */ + p = startp; + c = '['; + goto normal_bracket; + } + str[c1++] = c; + } + str[c1] = '\0'; + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wt = IS_CHAR_CLASS (str); + if (wt == 0) + /* Invalid character class name. */ + return FNM_NOMATCH; + + if (__iswctype (__btowc ((unsigned char) *n), wt)) + goto matched; +# else + if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n)) + || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n)) + || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n)) + || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n)) + || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n)) + || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n)) + || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n)) + || (STREQ (str, "print") && ISPRINT ((unsigned char) *n)) + || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n)) + || (STREQ (str, "space") && ISSPACE ((unsigned char) *n)) + || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n)) + || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n))) + goto matched; +# endif + } + else if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + else + { + normal_bracket: + if (FOLD (c) == fn) + goto matched; + + cold = c; + c = *p++; + + if (c == '-' && *p != ']') + { + /* It is a range. */ + unsigned char cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + + if (cold <= fn && fn <= FOLD (cend)) + goto matched; + + c = *p++; + } + } + + if (c == ']') + break; + } + + if (!not) + return FNM_NOMATCH; + break; + + matched: + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + else if (c == '[' && *p == ':') + { + do + if (*++p == '\0') + return FNM_NOMATCH; + while (*p != ':' || p[1] == ']'); + p += 2; + c = *p; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD ((unsigned char) *n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; + +# undef FOLD +} + + +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/compat/fnmatch.h b/compat/fnmatch.h new file mode 100644 index 0000000000..cc3ec37940 --- /dev/null +++ b/compat/fnmatch.h @@ -0,0 +1,84 @@ +/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _FNMATCH_H +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# if !defined __GLIBC__ || !defined __P +# undef __P +# define __P(protos) protos +# endif +#else /* Not C++ or ANSI C. */ +# undef __P +# define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + +#ifndef const +# if (defined __STDC__ && __STDC__) || defined __cplusplus +# define __const const +# else +# define __const +# endif +#endif + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE +# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* This value is returned if the implementation does not support + `fnmatch'. Since this is not the case here it will never be + returned but the conformance test suites still require the symbol + to be defined. */ +#ifdef _XOPEN_SOURCE +# define FNM_NOSYS (-1) +#endif + +/* Match NAME against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((__const char *__pattern, __const char *__name, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/compat/mingw.c b/compat/mingw.c index d2e83f74a3..2d3df81a8d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -93,11 +93,6 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) return -1; } -int fnmatch(const char *pattern, const char *string, int flags) -{ - return -1; -} - #include struct tm *gmtime_r(const time_t *timep, struct tm *result) diff --git a/git-compat-util.h b/git-compat-util.h index 4ad37467e9..d361fcaee8 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -36,7 +36,7 @@ #include #include //#include -//#include +#include //#include //#include #include @@ -335,8 +335,6 @@ struct pollfd { int poll(struct pollfd *ufds, unsigned int nfds, int timeout); #define POLLIN 1 #define POLLHUP 2 -int fnmatch(const char *pattern, const char *string, int flags); -#define FNM_PATHNAME 1 typedef int siginfo_t; struct sigaction { From 27317da439ad65226cd4167163b8316627a2bbfa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 18 Sep 2006 17:15:43 +0200 Subject: [PATCH 014/781] implement mkstemp() --- compat/mingw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2d3df81a8d..4e44f93e21 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -77,7 +77,15 @@ const char *inet_ntop(int af, const void *src, } int mkstemp (char *__template) { - return -1; + char *temp = xstrdup(__template); + char *filename = mktemp(__template); + int fd; + + if (filename == NULL) + return -1; + fd = open(filename, O_RDWR | O_CREAT); + free(filename); + return fd; } int gettimeofday(struct timeval *tv, void *tz) { From 8d1bfddd0cd58d09da3527146f6c9eee1b244aa4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 18:48:25 +0200 Subject: [PATCH 015/781] make default open mode O_BINARY --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4e44f93e21..67708e5fe0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,6 +1,10 @@ #include +#include +#include #include "../git-compat-util.h" +unsigned int _CRT_fmode = _O_BINARY; + int readlink(const char *path, char *buf, size_t bufsiz) { errno = EINVAL; From 9c6663c41923c070d66b883cc26e7050f30aa387 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 18 Sep 2006 17:02:59 +0200 Subject: [PATCH 016/781] strip extension and handle DRIVE: notation --- Makefile | 3 ++- git.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 874e529e58..20065b7a11 100644 --- a/Makefile +++ b/Makefile @@ -425,7 +425,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease NO_ICONV=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -I compat + NO_SVN_TESTS=YesPlease + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex X = .exe diff --git a/git.c b/git.c index a291177701..f893f373e1 100644 --- a/git.c +++ b/git.c @@ -280,6 +280,15 @@ static void handle_internal_command(int argc, const char **argv, char **envp) }; int i; +#ifdef STRIP_EXTENSION + i = strlen(argv[0]) - strlen(STRIP_EXTENSION); + if (i > 0 && !strcmp(argv[0] + i, STRIP_EXTENSION)) { + char *argv0 = strdup(argv[0]); + argv[0] = cmd = argv0; + argv0[i] = '\0'; + } +#endif + /* Turn "git cmd --help" into "git help cmd" */ if (argc > 1 && !strcmp(argv[1], "--help")) { argv[1] = argv[0]; @@ -325,6 +334,16 @@ int main(int argc, const char **argv, char **envp) cmd = slash; } +#ifdef __MINGW32__ + slash = strrchr(cmd, '\\'); + if (slash) { + *slash++ = 0; + if (cmd[1] == ':') + exec_path = cmd; + cmd = slash; + } +#endif + /* * "git-xxxx" is the same as "git xxxx", but we obviously: * From 4a4ae17738a52abf6dbd64ba9f01fe497229337d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 12:29:28 +0200 Subject: [PATCH 017/781] close fd of lockfile before unlinking --- cache.h | 1 + lockfile.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cache.h b/cache.h index e6e19bdef3..c944e843e0 100644 --- a/cache.h +++ b/cache.h @@ -180,6 +180,7 @@ extern int refresh_cache(unsigned int flags); struct lock_file { struct lock_file *next; + int fd; char on_list; char filename[PATH_MAX]; }; diff --git a/lockfile.c b/lockfile.c index 4824f4dc02..bf80246dc3 100644 --- a/lockfile.c +++ b/lockfile.c @@ -8,8 +8,10 @@ static struct lock_file *lock_file_list; static void remove_lock_file(void) { while (lock_file_list) { - if (lock_file_list->filename[0]) + if (lock_file_list->filename[0]) { + close(lock_file_list->fd); unlink(lock_file_list->filename); + } lock_file_list = lock_file_list->next; } } @@ -23,10 +25,9 @@ static void remove_lock_file_on_signal(int signo) static int lock_file(struct lock_file *lk, const char *path) { - int fd; sprintf(lk->filename, "%s.lock", path); - fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); - if (0 <= fd) { + lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); + if (0 <= lk->fd) { if (!lk->on_list) { lk->next = lock_file_list; lock_file_list = lk; @@ -42,7 +43,7 @@ static int lock_file(struct lock_file *lk, const char *path) } else lk->filename[0] = 0; - return fd; + return lk->fd; } int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error) @@ -57,9 +58,11 @@ int commit_lock_file(struct lock_file *lk) { char result_file[PATH_MAX]; int i; + close(lk->fd); strcpy(result_file, lk->filename); i = strlen(result_file) - 5; /* .lock */ result_file[i] = 0; + unlink(result_file); i = rename(lk->filename, result_file); lk->filename[0] = 0; return i; @@ -67,8 +70,10 @@ int commit_lock_file(struct lock_file *lk) void rollback_lock_file(struct lock_file *lk) { - if (lk->filename[0]) + if (lk->filename[0]) { + close(lk->fd); unlink(lk->filename); + } lk->filename[0] = 0; } From 41dfee75f14528b1978980da5bea6d8f7eb02b63 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 15:09:40 +0200 Subject: [PATCH 018/781] fix 'git bla' for .exe files --- exec_cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 3996bce33f..18b9659e6e 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -44,9 +44,11 @@ int execv_git_cmd(const char **argv) const char *exec_dir = paths[i]; const char *tmp; - if (!exec_dir || !*exec_dir) continue; - +#ifdef __MINGW32__ + if (*exec_dir != '/' && exec_dir[1] != ':') { +#else if (*exec_dir != '/') { +#endif if (!getcwd(git_command, sizeof(git_command))) { fprintf(stderr, "git: cannot determine " "current directory: %s\n", From 1c68fe96bcb66ce340cb1cc40acaddaba2f7fc11 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 19:03:20 +0200 Subject: [PATCH 019/781] unlink target of rename before renaming --- refs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/refs.c b/refs.c index 7d858637c4..1c0bf70f2c 100644 --- a/refs.c +++ b/refs.c @@ -339,6 +339,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master) error("Unable to write to %s", lockpath); return -2; } + unlink(git_HEAD); if (rename(lockpath, git_HEAD) < 0) { unlink(lockpath); error("Unable to create %s", git_HEAD); From c9467728c6b88dd4392c70d871c629454ff55738 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 12:00:06 +0200 Subject: [PATCH 020/781] close fd before renaming --- config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.c b/config.c index b6082f597c..7ada9b73c5 100644 --- a/config.c +++ b/config.c @@ -812,6 +812,8 @@ int git_config_set_multivar(const char* key, const char* value, unlink(config_filename); } + close(fd); + fd = -1; if (rename(lock_file, config_filename) < 0) { fprintf(stderr, "Could not rename the lock file?\n"); ret = 4; From 4720571a2d6b27de32db3367817d71da0f9b0535 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 27 Dec 2006 15:36:36 +0100 Subject: [PATCH 021/781] Fix mkstemp emulation to not free the template string. The template argument was strduped unnecessarily and then not used, and the wrong string was freed. --- compat/mingw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 67708e5fe0..ac4d4eb7fe 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -81,15 +81,10 @@ const char *inet_ntop(int af, const void *src, } int mkstemp (char *__template) { - char *temp = xstrdup(__template); char *filename = mktemp(__template); - int fd; - if (filename == NULL) return -1; - fd = open(filename, O_RDWR | O_CREAT); - free(filename); - return fd; + return open(filename, O_RDWR | O_CREAT); } int gettimeofday(struct timeval *tv, void *tz) { From 5a9f377e1db79f18c7acdede78b47ac32d6abf2b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:49:31 +0100 Subject: [PATCH 022/781] Add back the exec_path checks that were removed inadvertedly. --- exec_cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exec_cmd.c b/exec_cmd.c index 18b9659e6e..68c39e348c 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -44,6 +44,8 @@ int execv_git_cmd(const char **argv) const char *exec_dir = paths[i]; const char *tmp; + if (!exec_dir || !*exec_dir) continue; + #ifdef __MINGW32__ if (*exec_dir != '/' && exec_dir[1] != ':') { #else From 861429a7c37cce27b07331ab9106c3c52c68cf2d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:54:11 +0100 Subject: [PATCH 023/781] Be prepared for DOS-like drive letters in the getcwd() result. An earlier patch has implemented getcwd() so that it converts the drive letter into the POSIX-like path that is used internally by MinGW (C:\foo => /c/foo), but this style does not work outside the MinGW shell. It is better to just convert the backslashes to forward slashes and handle the drive letter explicitly. --- compat/mingw.c | 2 -- setup.c | 12 ++++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ac4d4eb7fe..f22ab57461 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -122,8 +122,6 @@ char *mingw_getcwd(char *pointer, int len) return ret; if (pointer[0] != 0 && pointer[1] == ':') { int i; - pointer[1] = pointer[0]; - pointer[0] = '/'; for (i = 2; pointer[i]; i++) /* Thanks, Bill. You'll burn in hell for that. */ if (pointer[i] == '\\') diff --git a/setup.c b/setup.c index cc97f9f5c1..707f8f9a55 100644 --- a/setup.c +++ b/setup.c @@ -173,6 +173,7 @@ const char *setup_git_directory_gently(int *nongit_ok) static char cwd[PATH_MAX+1]; const char *gitdirenv; int len, offset; + int minoffset = 0; /* * If GIT_DIR is set explicitly, we're not going @@ -192,8 +193,15 @@ const char *setup_git_directory_gently(int *nongit_ok) die("Not a git repository: '%s'", gitdirenv); } +#ifdef __MINGW32__ + if (!getcwd(cwd, sizeof(cwd)) || !(cwd[0] == '/' || cwd[1] == ':')) + die("Unable to read current working directory"); + if (cwd[1] == ':') + minoffset = 2; +#else if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/') die("Unable to read current working directory"); +#endif offset = len = strlen(cwd); for (;;) { @@ -201,7 +209,7 @@ const char *setup_git_directory_gently(int *nongit_ok) break; chdir(".."); do { - if (!offset) { + if (offset <= minoffset) { if (is_git_directory(cwd)) { if (chdir(cwd)) die("Cannot come back to cwd"); @@ -216,7 +224,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } die("Not a git repository"); } - } while (cwd[--offset] != '/'); + } while (offset > minoffset && cwd[--offset] != '/'); } if (offset == len) From d9634b14f93e9611c110ef4bacf2ce46e1a23268 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:56:45 +0100 Subject: [PATCH 024/781] Windows does not support C99 format strings. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 20065b7a11..9d4944a12d 100644 --- a/Makefile +++ b/Makefile @@ -425,6 +425,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease NO_ICONV=YesPlease + NO_C99_FORMAT = YesPlease NO_SVN_TESTS=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o From 90262b5faeceac9e3c63933e6350f01a52279189 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 08:57:42 +0100 Subject: [PATCH 025/781] Use the Windows style PATH separator. --- git.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git.c b/git.c index f893f373e1..8b31a0fcab 100644 --- a/git.c +++ b/git.c @@ -20,7 +20,11 @@ static void prepend_to_path(const char *dir, int len) path = xmalloc(path_len + 1); memcpy(path, dir, len); +#ifdef __MINGW32__ + path[len] = ';'; +#else path[len] = ':'; +#endif memcpy(path + len + 1, old_path, path_len - len); setenv("PATH", path, 1); From 2de27f2cbb43b30d5465be33541c98b453a076e6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 09:01:17 +0100 Subject: [PATCH 026/781] Implement a wrapper of execve that can invoke shell scripts. When an external git command is invoked, it can be a Bourne shell script. This patch looks into the command file to see whether it is one. In this case, the command line is rearranged to invoke the shell with the proper arguments. Moreover, the arguments are quoted if necessary because Windows' spawn functions paste the arguments again into a command line that is disassembled by the invoked process. --- compat/mingw.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 2 ++ 2 files changed, 90 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index f22ab57461..18aecd9bf5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -139,3 +139,91 @@ void sync(void) void openlog(const char *ident, int option, int facility) { } + +static const char *quote_arg(const char *arg) +{ + /* count chars to quote */ + int len = 0, n = 0; + int force_quotes = 0; + char *q, *d; + const char *p = arg; + while (*p) { + if (isspace(*p)) + force_quotes = 1; + else if (*p == '"' || *p == '\\') + n++; + len++; + p++; + } + if (!force_quotes && n == 0) + return arg; + + /* insert \ where necessary */ + d = q = xmalloc(len+n+3); + *d++ = '"'; + while (*arg) { + if (*arg == '"' || *arg == '\\') + *d++ = '\\'; + *d++ = *arg++; + } + *d++ = '"'; + *d++ = 0; + return q; +} + +static void quote_argv(const char **dst, const char **src) +{ + while (*src) + *dst++ = quote_arg(*src++); + *dst = NULL; +} + +static int try_shell_exec(const char *cmd, const char **argv, const char **env) +{ + char buf[100], *p; + const char **sh_argv; + int n; + int fd = open(cmd, O_RDONLY); + if (fd < 0) + return 0; + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if (n < 5) /* at least '#!/sh' and not error */ + return 0; + + /* check whether the interpreter is sh */ + if (buf[0] != '#' || buf[1] != '!') + return 0; + buf[n] = '\0'; + p = strchr(buf, '\n'); + if (!p || + (p[-3] != '/' && p[-3] != '\\') || + p[-2] != 's' || p[-1] != 'h') + return 0; + + /* + * expand + * git-foo args... + * into + * sh git-foo args... + */ + for (n = 0; argv[n];) n++; + sh_argv = xmalloc((n+2)*sizeof(char*)); + sh_argv[0] = "sh"; + sh_argv[1] = cmd; + quote_argv(&sh_argv[2], &argv[1]); + n = spawnvpe(_P_WAIT, "sh", sh_argv, env); + if (n == -1) + return 1; /* indicate that we tried but failed */ + exit(n); +} + +void mingw_execve(const char *cmd, const char **argv, const char **env) +{ + /* check if git_command is a shell script */ + if (!try_shell_exec(cmd, argv, env)) { + int ret = spawnve(_P_WAIT, cmd, argv, env); + if (ret != -1) + exit(ret); + } +} diff --git a/git-compat-util.h b/git-compat-util.h index d361fcaee8..4b213815b7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -306,6 +306,8 @@ int syslog(int type, char *bufp, ...); #define LOG_DAEMON 4 unsigned int alarm(unsigned int seconds); #include +void mingw_execve(const char *cmd, const char **argv, const char **env); +#define execve mingw_execve int fork(); typedef int pid_t; pid_t waitpid(pid_t pid, int *status, int options); From ff61d9fc99a60a7c0320538a278d5f58680e120d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 29 Dec 2006 09:03:45 +0100 Subject: [PATCH 027/781] Work around missing EISDIR errno values. Windows does not return EISDIR when a directory is opened as file. These instances are detected by checking explicitly whether the offending file is indeed a directory, and then the errno value is adjusted accordingly. --- refs.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/refs.c b/refs.c index 1c0bf70f2c..f48045c5c9 100644 --- a/refs.c +++ b/refs.c @@ -838,6 +838,15 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) retry: if (log && rename(git_path("tmp-renamed-log"), git_path("logs/%s", newref))) { +#ifdef __MINGW32__ + if (errno == EEXIST) { + struct stat st; + if (stat(git_path("logs/%s", newref), &st) == 0 && S_ISDIR(st.st_mode)) + errno = EISDIR; + else + errno = EEXIST; + } +#endif if (errno==EISDIR || errno==ENOTDIR) { /* * rename(a, b) when b is an existing @@ -946,6 +955,15 @@ static int log_ref_write(struct ref_lock *lock, if (!(oflags & O_CREAT) && errno == ENOENT) return 0; +#ifdef __MINGW32__ + if ((oflags & O_CREAT) && errno == EACCES) { + struct stat st; + if (stat(lock->log_file, &st) == 0 && S_ISDIR(st.st_mode)) + errno = EISDIR; + else + errno = EACCES; + } +#endif if ((oflags & O_CREAT) && errno == EISDIR) { if (remove_empty_directories(lock->log_file)) { return error("There are still logs under '%s'", From 48f967a1615e785794a3b91cbde7df95b1b1614d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:30:15 +0100 Subject: [PATCH 028/781] Make a pipe() wrapper that uses Windows's _pipe(). --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 18aecd9bf5..6e0119ad5f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -92,7 +92,7 @@ int gettimeofday(struct timeval *tv, void *tz) } int pipe(int filedes[2]) { - return -1; + return _pipe(filedes, 4096, 0); } int poll(struct pollfd *ufds, unsigned int nfds, int timeout) From 0bb0ca215830c19220a2cc78ca7c5a3b16b6f1df Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:33:35 +0100 Subject: [PATCH 029/781] Windows cannot unlink() a file that is read-only. --- builtin-prune-packed.c | 10 ++++++++-- index-pack.c | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 977730064b..639fbed2fc 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -25,8 +25,14 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) printf("rm -f %s\n", pathname); - else if (unlink(pathname) < 0) - error("unable to unlink %s", pathname); + else { +#ifdef __MINGW32__ + /* read-only files cannot be removed */ + chmod(pathname, 0666); +#endif + if (unlink(pathname) < 0) + error("unable to unlink %s", pathname); + } } pathname[len] = 0; rmdir(pathname); diff --git a/index-pack.c b/index-pack.c index 72e0962415..040957c016 100644 --- a/index-pack.c +++ b/index-pack.c @@ -700,6 +700,10 @@ static const char *write_index_file(const char *index_name, unsigned char *sha1) fd = mkstemp(tmpfile); index_name = xstrdup(tmpfile); } else { +#ifdef __MINGW32__ + /* read-only files cannot be removed */ + chmod(index_name, 0666); +#endif unlink(index_name); fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600); } From ee4a2fe93d663eaf2dbf0480cb27d2b8f2dbaee8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:35:42 +0100 Subject: [PATCH 030/781] MinGW cannot support sideband communication. --- fetch-pack.c | 2 ++ upload-pack.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fetch-pack.c b/fetch-pack.c index 1530a94794..48670f9c62 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -564,6 +564,7 @@ static int fetch_pack(int fd[2], int nr_match, char **match) fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } +#ifndef __MINGW32__ if (server_supports("side-band-64k")) { if (verbose) fprintf(stderr, "Server supports side-band-64k\n"); @@ -574,6 +575,7 @@ static int fetch_pack(int fd[2], int nr_match, char **match) fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } +#endif if (!ref) { packet_flush(fd[1]); die("no matching remote head"); diff --git a/upload-pack.c b/upload-pack.c index 0ce8ceeeac..ec0f0cbfbe 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -537,10 +537,12 @@ static void receive_needs(void) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) use_ofs_delta = 1; +#ifndef __MINGW32__ if (strstr(line+45, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (strstr(line+45, "side-band")) use_sideband = DEFAULT_PACKET_MAX; +#endif /* We have sent all our refs already, and the other end * should have chosen out of them; otherwise they are From 4b5821b21b5fb83da0e5884ed5d43c658577d9a5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:39:08 +0100 Subject: [PATCH 031/781] Implement a subset of waitpid() in terms of Windows's _cwait(). --- compat/mingw.c | 6 ------ git-compat-util.h | 14 ++++++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6e0119ad5f..2f9e9dd61c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -46,12 +46,6 @@ int fork() { return -1; } -typedef int pid_t; -pid_t waitpid(pid_t pid, int *status, int options) -{ - errno = ECHILD; - return -1; -} int kill(pid_t pid, int sig) { diff --git a/git-compat-util.h b/git-compat-util.h index 4b213815b7..846969b408 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -310,12 +310,14 @@ void mingw_execve(const char *cmd, const char **argv, const char **env); #define execve mingw_execve int fork(); typedef int pid_t; -pid_t waitpid(pid_t pid, int *status, int options); -#define WIFEXITED(x) 0 -#define WEXITSTATUS(x) 1 -#define WIFSIGNALED(x) -1 -#define WTERMSIG(x) 0 -#define WNOHANG 0 +#define waitpid(pid, status, options) \ + ((options == 0) ? _cwait((status), (pid), 0) \ + : (errno = EINVAL, -1)) +#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ +#define WEXITSTATUS(x) ((x) & 0xff) +#define WIFSIGNALED(x) ((unsigned)(x) > 259) +#define WTERMSIG(x) (x) +#define WNOHANG 1 #define SIGKILL 0 #define SIGCHLD 0 #define SIGALRM 0 From aa0dba94438d061850e3a8a99f588e5b782afeda Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:45:20 +0100 Subject: [PATCH 032/781] Add a cpio emulation script based on GNU tar. --- Makefile | 3 ++- cpio.sh | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 cpio.sh diff --git a/Makefile b/Makefile index 9d4944a12d..2aa3bed4e6 100644 --- a/Makefile +++ b/Makefile @@ -177,7 +177,8 @@ SCRIPT_SH = \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ git-merge-resolve.sh git-merge-ours.sh \ - git-lost-found.sh git-quiltimport.sh + git-lost-found.sh git-quiltimport.sh \ + cpio.sh SCRIPT_PERL = \ git-add--interactive.perl \ diff --git a/cpio.sh b/cpio.sh new file mode 100644 index 0000000000..a0a5a372f2 --- /dev/null +++ b/cpio.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# +# Emulates some cpio behavior using GNU tar + +die() { + echo >&2 "$@" + exit 1 +} + +tr0=cat + +while test $# -gt 0; do + case "$1" in + -0) tr0="tr '\0' ' '";; + -o) mode=o;; + -iuv) ;; + -pumd|-pumdl) + mode=p + dir="$2" + shift + ;; + *) die "cpio emulation supports only -0, -o, -iuv, -pumdl";; + esac + shift +done + +case $mode in +o) + files=.cpiofiles$$ + $tr0 > $files + tar --create --file=- --files-from=$files --exclude=$files + rc=$? + rm -f $files + exit $rc + ;; +p) + files=.cpiofiles$$ + $tr0 > $files + tar --create --file=- --files-from=$files --exclude=$files | + tar --extract --directory="$dir" --file=- + rm -f $files + ;; +*) + tar xvf - || exit +esac From 0400c502c3dff7810175e364ab9422552a83ec19 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 11:52:29 +0100 Subject: [PATCH 033/781] Factor fork()/exec() work into a spawn() like function. Windows does not have fork(), but something called spawn() that is roughly equivalent to a fork()/exec() pair, factor out the Unix style code into a function that does it more similarly to spawn(). Now the Windows style spawn() can more easily be employed to achieve the same that the Unix style code does. --- Makefile | 3 +- compat/mingw.c | 2 +- connect.c | 85 +++++++++++------------------ spawn-pipe.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++ spawn-pipe.h | 4 ++ 5 files changed, 178 insertions(+), 57 deletions(-) create mode 100644 spawn-pipe.c create mode 100644 spawn-pipe.h diff --git a/Makefile b/Makefile index 2aa3bed4e6..105e2d1b6e 100644 --- a/Makefile +++ b/Makefile @@ -240,7 +240,7 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - utf8.h + spawn-pipe.h utf8.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@ -252,6 +252,7 @@ LIB_OBJS = \ date.o diff-delta.o entry.o exec_cmd.o ident.o \ interpolate.o \ lockfile.o \ + spawn-pipe.o \ object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \ reachable.o \ quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \ diff --git a/compat/mingw.c b/compat/mingw.c index 2f9e9dd61c..8b8282bfd5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -165,7 +165,7 @@ static const char *quote_arg(const char *arg) return q; } -static void quote_argv(const char **dst, const char **src) +void quote_argv(const char **dst, const char **src) { while (*src) *dst++ = quote_arg(*src++); diff --git a/connect.c b/connect.c index 66daa11a57..171f34837f 100644 --- a/connect.c +++ b/connect.c @@ -3,6 +3,7 @@ #include "pkt-line.h" #include "quote.h" #include "refs.h" +#include "spawn-pipe.h" static char *server_capabilities; @@ -620,23 +621,13 @@ static void git_proxy_connect(int fd[2], char *host) if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0) die("unable to create pipe pair for communication"); - pid = fork(); - if (!pid) { - dup2(pipefd[1][0], 0); - dup2(pipefd[0][1], 1); - close(pipefd[0][0]); - close(pipefd[0][1]); - close(pipefd[1][0]); - close(pipefd[1][1]); - execlp(git_proxy_command, git_proxy_command, host, port, NULL); - die("exec failed"); + + { + const char *argv[] = { NULL, host, port, NULL }; + spawnvpe_pipe(git_proxy_command, argv, environ, pipefd[1], pipefd[0]); } - if (pid < 0) - die("fork failed"); fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; - close(pipefd[0][1]); - close(pipefd[1][0]); } #define MAX_CMD_LEN 1024 @@ -740,53 +731,37 @@ pid_t git_connect(int fd[2], char *url, const char *prog) if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0) die("unable to create pipe pair for communication"); - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - char command[MAX_CMD_LEN]; - char *posn = command; - int size = MAX_CMD_LEN; - int of = 0; - of |= add_to_string(&posn, &size, prog, 0); - of |= add_to_string(&posn, &size, " ", 0); - of |= add_to_string(&posn, &size, path, 1); + char command[MAX_CMD_LEN]; + char *posn = command; + int size = MAX_CMD_LEN; + int of = 0; - if (of) - die("command line too long"); + of |= add_to_string(&posn, &size, prog, 0); + of |= add_to_string(&posn, &size, " ", 0); + of |= add_to_string(&posn, &size, path, 1); - dup2(pipefd[1][0], 0); - dup2(pipefd[0][1], 1); - close(pipefd[0][0]); - close(pipefd[0][1]); - close(pipefd[1][0]); - close(pipefd[1][1]); - if (protocol == PROTO_SSH) { - const char *ssh, *ssh_basename; - ssh = getenv("GIT_SSH"); - if (!ssh) ssh = "ssh"; - ssh_basename = strrchr(ssh, '/'); - if (!ssh_basename) - ssh_basename = ssh; - else - ssh_basename++; - execlp(ssh, ssh_basename, host, command, NULL); - } - else { - unsetenv(ALTERNATE_DB_ENVIRONMENT); - unsetenv(DB_ENVIRONMENT); - unsetenv(GIT_DIR_ENVIRONMENT); - unsetenv(GRAFT_ENVIRONMENT); - unsetenv(INDEX_ENVIRONMENT); - execlp("sh", "sh", "-c", command, NULL); - } - die("exec failed"); + if (of) + die("command line too long"); + + if (protocol == PROTO_SSH) { + const char *argv[] = { NULL, host, command, NULL }; + const char *ssh = getenv("GIT_SSH"); + if (!ssh) ssh = "ssh"; + pid = spawnvpe_pipe(ssh, argv, environ, pipefd[1], pipefd[0]); + } + else { + const char *argv[] = { NULL, "-c", command, NULL }; + const char **env = copy_environ(); + env_unsetenv(env, ALTERNATE_DB_ENVIRONMENT); + env_unsetenv(env, DB_ENVIRONMENT); + env_unsetenv(env, GIT_DIR_ENVIRONMENT); + env_unsetenv(env, GRAFT_ENVIRONMENT); + env_unsetenv(env, INDEX_ENVIRONMENT); + pid = spawnvpe_pipe("sh", argv, env, pipefd[1], pipefd[0]); } fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; - close(pipefd[0][1]); - close(pipefd[1][0]); if (free_path) free(path); return pid; diff --git a/spawn-pipe.c b/spawn-pipe.c new file mode 100644 index 0000000000..fc179c8cdc --- /dev/null +++ b/spawn-pipe.c @@ -0,0 +1,141 @@ +#include "git-compat-util.h" +#include "spawn-pipe.h" + +extern char **environ; + +/* cmd specifies the command to invoke. + * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. + * env specifies the environment. + * pin and pout specify pipes; the read end of pin is made the standard input + * of the spawned process, and the write end of pout is mad the standard output. + * The respective unused ends of the pipes are closed both in the parent + * process as well as in the child process. + * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to + * indicate that no processing shall occur. + */ +int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, + int pin[], int pout[]) +{ + const char *cmd_basename = strrchr(cmd, '/'); + pid_t pid; + +#ifdef __MINGW32__ + int s0 = -1, s1 = -1, argc; + const char **qargv; + extern void quote_argv(const char **dst, const char **src); + + if (!cmd_basename) + cmd_basename = strrchr(cmd, '\\'); +#endif + + if (!cmd_basename) + cmd_basename = cmd; + else + cmd_basename++; + argv[0] = cmd_basename; + +#ifndef __MINGW32__ + pid = fork(); + if (pid < 0) + die("unable to fork"); + if (!pid) { + if (pin) { + if (pin[0] >= 0) { + dup2(pin[0], 0); + close(pin[0]); + } + if (pin[1] >= 0) + close(pin[1]); + } + if (pout) { + if (pout[1] >= 0) { + dup2(pout[1], 1); + close(pout[1]); + } + if (pout[0] >= 0) + close(pout[0]); + } + environ = env; + execvp(cmd, argv); + die("exec failed"); + } + + if (pin && pin[0] >= 0) + close(pin[0]); + if (pout && pout[1] >= 1) + close(pout[1]); +#else + if (pin) { + if (pin[0] >= 0) { + s0 = dup(0); + dup2(pin[0], 0); + close(pin[0]); + } + } + if (pout) { + if (pout[1] >= 0) { + s1 = dup(1); + dup2(pout[1], 1); + close(pout[1]); + } + } + + for (argc = 0; argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + quote_argv(qargv, argv); + + pid = spawnvpe(_P_NOWAIT, cmd, qargv, env); + + free(qargv); /* TODO: quoted args should be freed, too */ + + if (s0 >= 0) { + dup2(s0, 0); + close(s0); + } + if (s1 >= 0) { + dup2(s1, 1); + close(s1); + } +#endif + + return pid; +} + +const char **copy_environ() +{ + return copy_env(environ); +} + +const char **copy_env(const char **env) +{ + const char **s; + int n = 1; + for (s = env; *s; s++) + n++; + s = xmalloc(n*sizeof(const char *)); + memcpy(s, env, n*sizeof(const char *)); + return s; +} + +void env_unsetenv(const char **env, const char *name) +{ + int src, dst; + size_t nmln; + + nmln = strlen(name); + + for (src = dst = 0; env[src]; ++src) { + size_t enln; + enln = strlen(env[src]); + if (enln > nmln) { + /* might match, and can test for '=' safely */ + if (0 == strncmp (env[src], name, nmln) + && '=' == env[src][nmln]) + /* matches, so skip */ + continue; + } + env[dst] = env[src]; + ++dst; + } + env[dst] = NULL; +} diff --git a/spawn-pipe.h b/spawn-pipe.h new file mode 100644 index 0000000000..41eb81de63 --- /dev/null +++ b/spawn-pipe.h @@ -0,0 +1,4 @@ +int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); +const char **copy_environ(); +const char **copy_env(const char **env); +void env_unsetenv(const char **env, const char *name); From 8f9e40a3964d003f04e56520ad7b18a1abda13c6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:49:34 +0100 Subject: [PATCH 034/781] Use the spawn workhorse instead of a fork()/exec() pair. --- diff.c | 13 +++---------- merge-index.c | 20 +++----------------- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/diff.c b/diff.c index f11a633da5..12161b6f87 100644 --- a/diff.c +++ b/diff.c @@ -8,6 +8,7 @@ #include "delta.h" #include "xdiff-interface.h" #include "color.h" +#include "spawn-pipe.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -1498,13 +1499,7 @@ static int spawn_prog(const char *pgm, const char **arg) int status; fflush(NULL); - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - execvp(pgm, (char *const*) arg); - exit(255); - } + pid = spawnvpe_pipe(pgm, arg, environ, NULL, NULL); while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) @@ -1545,7 +1540,7 @@ static void run_external_diff(const char *pgm, int retval; static int atexit_asked = 0; const char *othername; - const char **arg = &spawn_arg[0]; + const char **arg = &spawn_arg[1]; othername = (other? other : name); if (one && two) { @@ -1561,7 +1556,6 @@ static void run_external_diff(const char *pgm, } if (one && two) { - *arg++ = pgm; *arg++ = name; *arg++ = temp[0].name; *arg++ = temp[0].hex; @@ -1574,7 +1568,6 @@ static void run_external_diff(const char *pgm, *arg++ = xfrm_msg; } } else { - *arg++ = pgm; *arg++ = name; } *arg = NULL; diff --git a/merge-index.c b/merge-index.c index a9983dd78a..6c2e00842e 100644 --- a/merge-index.c +++ b/merge-index.c @@ -1,29 +1,16 @@ #include "cache.h" +#include "spawn-pipe.h" static const char *pgm; -static const char *arguments[8]; +static const char *arguments[9]; /* last one is always NULL */ static int one_shot, quiet; static int err; static void run_program(void) { - pid_t pid = fork(); + pid_t pid = spawnvpe_pipe(pgm, arguments, environ, NULL, NULL); int status; - if (pid < 0) - die("unable to fork"); - if (!pid) { - execlp(pgm, arguments[0], - arguments[1], - arguments[2], - arguments[3], - arguments[4], - arguments[5], - arguments[6], - arguments[7], - NULL); - die("unable to execute '%s'", pgm); - } if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) { if (one_shot) { err++; @@ -41,7 +28,6 @@ static int merge_entry(int pos, const char *path) if (pos >= active_nr) die("git-merge-index: %s not in the cache", path); - arguments[0] = pgm; arguments[1] = ""; arguments[2] = ""; arguments[3] = ""; From e7a70c5ddfa0f925760c131c2c60c25b814df222 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:46:07 +0100 Subject: [PATCH 035/781] Windows does not have the close-on-exec flag. --- sha1_file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sha1_file.c b/sha1_file.c index 3025440941..14ec604797 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -572,6 +572,7 @@ static void open_packed_git(struct packed_git *p) } else if (p->pack_size != st.st_size) die("packfile %s size changed", p->pack_name); +#ifndef __MINGW32__ /* We leave these file descriptors open with sliding mmap; * there is no point keeping them open across exec(), though. */ @@ -581,6 +582,7 @@ static void open_packed_git(struct packed_git *p) fd_flag |= FD_CLOEXEC; if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1) die("cannot set FD_CLOEXEC"); +#endif /* Verify we recognize this pack file format. */ if (read_in_full(p->pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) From 2bd27c7c97f73a8da1c65a2d0096e094283ac59f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:48:23 +0100 Subject: [PATCH 036/781] Report failure when a process cannot be spawned (MinGW only). --- spawn-pipe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spawn-pipe.c b/spawn-pipe.c index fc179c8cdc..716c52902c 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -85,6 +85,8 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, quote_argv(qargv, argv); pid = spawnvpe(_P_NOWAIT, cmd, qargv, env); + if (pid < 0) + die("unable to run %s", cmd); free(qargv); /* TODO: quoted args should be freed, too */ From 4ba0bd54b35f6ac637ec1274911dde1629aa04a1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 17:45:25 +0100 Subject: [PATCH 037/781] rename() fails on Windows if the destination exists. --- builtin-reflog.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/builtin-reflog.c b/builtin-reflog.c index 6d14184736..4877bb060b 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -274,6 +274,12 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, if (fclose(cb.newlog)) status |= error("%s: %s", strerror(errno), newlog_path); +#ifdef __MINGW32__ + /* rename fails if the destination exists */ + if (unlink(lock->log_file)) + status |= error("cannot remove %s", lock->log_file); + else +#endif if (rename(newlog_path, lock->log_file)) { status |= error("cannot rename %s to %s", newlog_path, lock->log_file); From 09653a29cf4e6c010997c5a7da7945573da34612 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 11 Jan 2007 13:45:41 +0100 Subject: [PATCH 038/781] Move script detection into a helper function that returns the interpreter. This will be needed later in the spawn helper functions, too, where we want to start a shell or perl script from an exe. --- compat/mingw.c | 45 +++++++++++++++++++++++++++++++-------------- git-compat-util.h | 3 +++ spawn-pipe.c | 1 - 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8b8282bfd5..53b3f780a4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -172,27 +172,44 @@ void quote_argv(const char **dst, const char **src) *dst = NULL; } -static int try_shell_exec(const char *cmd, const char **argv, const char **env) +const char *parse_interpreter(const char *cmd) { - char buf[100], *p; - const char **sh_argv; - int n; - int fd = open(cmd, O_RDONLY); + static char buf[100]; + char *p; + int n, fd; + + /* don't even try a .exe */ + n = strlen(cmd); + if (n >= 4 && !strcasecmp(cmd+n-4, ".exe")) + return NULL; + + fd = open(cmd, O_RDONLY); if (fd < 0) - return 0; + return NULL; n = read(fd, buf, sizeof(buf)-1); close(fd); - if (n < 5) /* at least '#!/sh' and not error */ - return 0; + if (n < 4) /* at least '#!/x' and not error */ + return NULL; - /* check whether the interpreter is sh */ if (buf[0] != '#' || buf[1] != '!') - return 0; + return NULL; buf[n] = '\0'; p = strchr(buf, '\n'); - if (!p || - (p[-3] != '/' && p[-3] != '\\') || - p[-2] != 's' || p[-1] != 'h') + if (!p) + return NULL; + + *p = '\0'; + if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\'))) + return NULL; + return p+1; +} + +static int try_shell_exec(const char *cmd, const char **argv, const char **env) +{ + const char **sh_argv; + int n; + const char *interpr = parse_interpreter(cmd); + if (!interpr) return 0; /* @@ -203,7 +220,7 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) */ for (n = 0; argv[n];) n++; sh_argv = xmalloc((n+2)*sizeof(char*)); - sh_argv[0] = "sh"; + sh_argv[0] = interpr; sh_argv[1] = cmd; quote_argv(&sh_argv[2], &argv[1]); n = spawnvpe(_P_WAIT, "sh", sh_argv, env); diff --git a/git-compat-util.h b/git-compat-util.h index 846969b408..bf42191ab7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -370,4 +370,7 @@ char *mingw_getcwd(char *pointer, int len); #define setlinebuf(x) #define fsync(x) +extern void quote_argv(const char **dst, const char **src); +extern const char *parse_interpreter(const char *cmd); + #endif diff --git a/spawn-pipe.c b/spawn-pipe.c index 716c52902c..87ad789775 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -22,7 +22,6 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, #ifdef __MINGW32__ int s0 = -1, s1 = -1, argc; const char **qargv; - extern void quote_argv(const char **dst, const char **src); if (!cmd_basename) cmd_basename = strrchr(cmd, '\\'); From 23960ed3c315dc0f39cebcf317ff4d3ba16ccee8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 12 Jan 2007 10:10:25 +0100 Subject: [PATCH 039/781] Enable the spawn workhorse function to spawn shell scripts. For this purpose the path lookup is done manually, and the found file is inspected for the interpreter. If one is found, the script is spawned under the interpreter; otherwise, the program is spawned normally. --- spawn-pipe.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index 87ad789775..53a1487d32 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -3,6 +3,53 @@ extern char **environ; +#ifdef __MINGW32__ +static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +{ + char path[MAX_PATH]; + snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); + + if (tryexe && access(path, 0) == 0) + return xstrdup(path); + path[strlen(path)-4] = '\0'; + if (access(path, 0) == 0) + return xstrdup(path); + return NULL; +} + +/* + * Determines the absolute path of cmd based on the PATH environment variable. + * If cmd contains a slash or backslash, no lookup is performed. + */ +static char *path_lookup(const char *cmd) +{ + char *p, *envpath = getenv("PATH"); + char *prog = NULL; + int len = strlen(cmd); + int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + + if (strchr(cmd, '/') || strchr(cmd, '\\') || + !envpath || !*envpath) + envpath = ""; + envpath = xstrdup(envpath); + p = envpath; + while (p && !prog) { + const char *dir = p; + p = strchr(p, ';'); + if (p) *p++ = '\0'; + if (*dir) + prog = lookup_prog(dir, cmd, tryexe); + } + free(envpath); + if (!prog) { + prog = lookup_prog(".", cmd, tryexe); + if (!prog) + prog = xstrdup(cmd); + } + return prog; +} +#endif + /* cmd specifies the command to invoke. * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. * env specifies the environment. @@ -21,7 +68,8 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, #ifdef __MINGW32__ int s0 = -1, s1 = -1, argc; - const char **qargv; + char *prog; + const char **qargv, *interpr; if (!cmd_basename) cmd_basename = strrchr(cmd, '\\'); @@ -79,15 +127,26 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, } } + prog = path_lookup(cmd); + interpr = parse_interpreter(prog); + for (argc = 0; argv[argc];) argc++; qargv = xmalloc((argc+2)*sizeof(char*)); - quote_argv(qargv, argv); + if (!interpr) { + quote_argv(qargv, argv); + pid = spawnve(_P_NOWAIT, prog, qargv, env); + } else { + qargv[0] = interpr; + argv[0] = prog; + quote_argv(&qargv[1], argv); + pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); + } - pid = spawnvpe(_P_NOWAIT, cmd, qargv, env); if (pid < 0) die("unable to run %s", cmd); free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); if (s0 >= 0) { dup2(s0, 0); From 5f38ff014e868ea0ae9210b4a2fbd56ebc8283da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 16 Jan 2007 14:58:49 +0100 Subject: [PATCH 040/781] Split PATH into parts in advance, and pass the result to the new spawnvppe_pipe. --- spawn-pipe.c | 88 ++++++++++++++++++++++++++++++++++++++++++---------- spawn-pipe.h | 1 + 2 files changed, 73 insertions(+), 16 deletions(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index 53a1487d32..b828809820 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -18,29 +18,72 @@ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) } /* - * Determines the absolute path of cmd based on the PATH environment variable. + * Splits the PATH into parts. + */ +char **get_path_split() +{ + char *p, **path, *envpath = getenv("PATH"); + int i, n = 0; + + if (!envpath || !*envpath) + return NULL; + + envpath = xstrdup(envpath); + p = envpath; + while (p) { + char *dir = p; + p = strchr(p, ';'); + if (p) *p++ = '\0'; + if (*dir) { /* not earlier, catches series of ; */ + ++n; + } + } + if (!n) + return NULL; + + path = xmalloc((n+1)*sizeof(char*)); + p = envpath; + i = 0; + do { + if (*p) + path[i++] = xstrdup(p); + p = p+strlen(p)+1; + } while (i < n); + path[i] = NULL; + + free(envpath); + + return path; +} + +void free_path_split(char **path) +{ + if (!path) + return; + + char **p = path; + while (*p) + free(*p++); + free(path); +} + +/* + * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -static char *path_lookup(const char *cmd) +static char *path_lookup(const char *cmd, char **path) { - char *p, *envpath = getenv("PATH"); + char **p = path; char *prog = NULL; int len = strlen(cmd); int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); - if (strchr(cmd, '/') || strchr(cmd, '\\') || - !envpath || !*envpath) - envpath = ""; - envpath = xstrdup(envpath); - p = envpath; - while (p && !prog) { - const char *dir = p; - p = strchr(p, ';'); - if (p) *p++ = '\0'; - if (*dir) - prog = lookup_prog(dir, cmd, tryexe); + if (strchr(cmd, '/') || strchr(cmd, '\\')) + p = NULL; + + while (*p && !prog) { + prog = lookup_prog(*p++, cmd, tryexe); } - free(envpath); if (!prog) { prog = lookup_prog(".", cmd, tryexe); if (!prog) @@ -62,6 +105,19 @@ static char *path_lookup(const char *cmd) */ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) +{ + char **path = get_path_split(); + + pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); + + free_path_split(path); + + return pid; +} + +int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, + char **path, + int pin[], int pout[]) { const char *cmd_basename = strrchr(cmd, '/'); pid_t pid; @@ -127,7 +183,7 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, } } - prog = path_lookup(cmd); + prog = path_lookup(cmd, path); interpr = parse_interpreter(prog); for (argc = 0; argv[argc];) argc++; diff --git a/spawn-pipe.h b/spawn-pipe.h index 41eb81de63..3807819ae8 100644 --- a/spawn-pipe.h +++ b/spawn-pipe.h @@ -1,3 +1,4 @@ +int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); const char **copy_environ(); const char **copy_env(const char **env); From ec1fcbb0a9432e0baccc43484caa57c7c2042118 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 09:37:38 +0100 Subject: [PATCH 041/781] Make the pager work. --- pager.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pager.c b/pager.c index 4587fbbdb5..b2a37e2658 100644 --- a/pager.c +++ b/pager.c @@ -1,19 +1,26 @@ #include "cache.h" +#include "spawn-pipe.h" /* * This is split up from the rest of git so that we might do * something different on Windows, for example. */ +#ifndef __MINGW32__ static void run_pager(const char *pager) { execlp(pager, pager, NULL); execl("/bin/sh", "sh", "-c", pager, NULL); } +#endif void setup_pager(void) { +#ifndef __MINGW32__ pid_t pid; +#else + const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +#endif int fd[2]; const char *pager = getenv("GIT_PAGER"); @@ -30,6 +37,7 @@ void setup_pager(void) if (pipe(fd) < 0) return; +#ifndef __MINGW32__ pid = fork(); if (pid < 0) { close(fd[0]); @@ -54,4 +62,14 @@ void setup_pager(void) run_pager(pager); die("unable to execute pager '%s'", pager); exit(255); +#else + /* spawn the pager */ + pager_argv[2] = pager; + if (spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL) < 0) + return; + + /* original process continues, but writes to the pipe */ + dup2(fd[1], 1); + close(fd[1]); +#endif } From 85e94b981ef0df32c3e5170499298369513bf864 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 14:04:06 +0100 Subject: [PATCH 042/781] Do not leak pipe file handles into the child processes. Windows's _pipe() by default allocates inheritable pipes. However, when a spawn happens, we do not have a possiblility to close the unused pipe ends in the child process. This is a problem. Consider the following situation: The child process only reads from the pipe and the parent process uses only the writable end; the parent even closes the writable end. As it happens, the child at this time usually still waits for input in a read(). But since the child has inherited an open writable end, it does not get EOF and hangs ad infinitum. For this reason, pipe handles must not be inheritable. At the first glance, this is curious, since after all it is the purpose of pipes to be inherited by child processes. However, in all cases where this inheritance is needed for a file descriptor, it is dup2()'d to stdin or stdout anyway, and, lo and behold, Windows's dup2() creates inheritable duplicates. --- compat/mingw.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 53b3f780a4..8ed621d004 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -86,7 +86,47 @@ int gettimeofday(struct timeval *tv, void *tz) } int pipe(int filedes[2]) { - return _pipe(filedes, 4096, 0); + int fd; + HANDLE h[2], parent; + + if (_pipe(filedes, 4096, 0) < 0) + return -1; + + parent = GetCurrentProcess(); + + if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[0]), + parent, &h[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) { + close(filedes[0]); + close(filedes[1]); + return -1; + } + if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[1]), + parent, &h[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) { + close(filedes[0]); + close(filedes[1]); + CloseHandle(h[0]); + return -1; + } + fd = _open_osfhandle(h[0], O_NOINHERIT); + if (fd < 0) { + close(filedes[0]); + close(filedes[1]); + CloseHandle(h[0]); + CloseHandle(h[1]); + return -1; + } + close(filedes[0]); + filedes[0] = fd; + fd = _open_osfhandle(h[1], O_NOINHERIT); + if (fd < 0) { + close(filedes[0]); + close(filedes[1]); + CloseHandle(h[1]); + return -1; + } + close(filedes[1]); + filedes[1] = fd; + return 0; } int poll(struct pollfd *ufds, unsigned int nfds, int timeout) From 16ea9c7aa337b1acb7c1041b4730a4b168096706 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 14:18:11 +0100 Subject: [PATCH 043/781] Make sure that the pager terminates before the process that feeds it. Since the pager was spawned as child process, it does not notice when the parent (which feeds its stdin) terminates. If the pager is 'less' it so looses control over the terminal and cannot be controled by the user anymore. For this reason, we register a function atexit() that explicitly waits for the pager to terminate. --- pager.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pager.c b/pager.c index b2a37e2658..d72c5e8d94 100644 --- a/pager.c +++ b/pager.c @@ -12,6 +12,13 @@ static void run_pager(const char *pager) execlp(pager, pager, NULL); execl("/bin/sh", "sh", "-c", pager, NULL); } +#else +static pid_t pager_pid; +static void collect_pager(void) +{ + close(1); /* signals EOF to pager */ + cwait(NULL, pager_pid, 0); +} #endif void setup_pager(void) @@ -65,11 +72,15 @@ void setup_pager(void) #else /* spawn the pager */ pager_argv[2] = pager; - if (spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL) < 0) + pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL); + if (pager_pid < 0) return; /* original process continues, but writes to the pipe */ dup2(fd[1], 1); close(fd[1]); + + /* this makes sure that the parent terminates after the pager */ + atexit(collect_pager); #endif } From c823cea00ef2b5e14457efe437db3a4aefe75667 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 14:04:41 +0100 Subject: [PATCH 044/781] Implement sleep(). --- compat/mingw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/compat/mingw.c b/compat/mingw.c index 8ed621d004..6d067c9450 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -66,6 +66,7 @@ int setitimer(int __which, const struct itimerval *__value, } unsigned int sleep (unsigned int __seconds) { + Sleep(__seconds*1000); return 0; } const char *inet_ntop(int af, const void *src, From c84f02153b70b80a7463c3bea255e773d8f5cb8f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 18:07:44 +0100 Subject: [PATCH 045/781] Add a spawnv_git_cmd() function and use it in fetch-pack.c. This function is intended to be used in place of exec[vl]_git_cmd() that follows a fork. It constructs the (at most) 3 paths that execv_git_cmd() searches manually for the git command and hands them over to spawnvppe_pipe(). The use case in get_pack() is one of the simplest possible. --- exec_cmd.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ exec_cmd.h | 1 + fetch-pack.c | 10 +------ 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 68c39e348c..9f31b040de 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,6 +1,7 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" +#include "spawn-pipe.h" #define MAX_ARGS 32 extern char **environ; @@ -137,3 +138,86 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } + +int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) +{ + char cmd[100]; + int i, rc; + pid_t pid; + const char *paths[] = { current_exec_path, + getenv(EXEC_PATH_ENVIRONMENT), + builtin_exec_path }; + char p[3][PATH_MAX + 1]; + char *usedpaths[4], **up = usedpaths; + const char *tmp; + + for (i = 0; i < ARRAY_SIZE(paths); ++i) { + size_t len; + const char *exec_dir = paths[i]; + + if (!exec_dir || !*exec_dir) continue; + +#ifdef __MINGW32__ + if (*exec_dir != '/' && exec_dir[1] != ':') { +#else + if (*exec_dir != '/') { +#endif + if (!getcwd(p[i], sizeof(p[i]))) { + fprintf(stderr, "git: cannot determine " + "current directory: %s\n", + strerror(errno)); + return -1; + } + len = strlen(p[i]); + + /* Trivial cleanup */ + while (!strncmp(exec_dir, "./", 2)) { + exec_dir += 2; + while (*exec_dir == '/') + exec_dir++; + } + + rc = snprintf(p[i] + len, + sizeof(p[i]) - len, "/%s", + exec_dir); + if (rc < 0 || rc >= sizeof(p[i]) - len) { + fprintf(stderr, "git: command name given " + "is too long.\n"); + return -1; + } + } else { + if (strlen(exec_dir) + 1 > sizeof(p[i])) { + fprintf(stderr, "git: command name given " + "is too long.\n"); + return -1; + } + strcpy(p[i], exec_dir); + } + *up++ = p[i]; + } + *up = NULL; + + rc = snprintf(cmd, sizeof(cmd), "git-%s", argv[0]); + if (rc < 0 || rc >= sizeof(cmd)) { + fprintf(stderr, + "git: command name given is too long.\n"); + return -1; + } + + /* argv[0] must be the git command, but the argv array + * belongs to the caller. Save argv[0] and + * restore it later. + */ + + tmp = argv[0]; + argv[0] = cmd; + + trace_argv_printf(argv, -1, "trace: exec:"); + + pid = spawnvppe_pipe(cmd, argv, environ, usedpaths, + pin, pout); + + argv[0] = tmp; + return pid; + +} diff --git a/exec_cmd.h b/exec_cmd.h index 989621ff4e..eefb4afe40 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -5,6 +5,7 @@ extern void git_set_exec_path(const char *exec_path); extern const char* git_exec_path(void); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); +extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]); #endif /* __GIT_EXEC_CMD_H_ */ diff --git a/fetch-pack.c b/fetch-pack.c index 48670f9c62..10683bee9a 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -493,17 +493,9 @@ static int get_pack(int xd[2], const char **argv) int fd[2]; side_pid = setup_sideband(fd, xd); - pid = fork(); + pid = spawnv_git_cmd(argv, fd, NULL); if (pid < 0) die("fetch-pack: unable to fork off %s", argv[0]); - if (!pid) { - dup2(fd[0], 0); - close(fd[0]); - close(fd[1]); - execv_git_cmd(argv); - die("%s exec failed", argv[0]); - } - close(fd[0]); close(fd[1]); while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) From 2d6dacec88dd8dddae75b4a60b7a1944ac278354 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 19 Jan 2007 13:03:09 +0100 Subject: [PATCH 046/781] Make upload-pack.c work under MinGW. The forked rev-list process is turned into a thread. This should be OK since the rest of upload-pack does not access the revision machinery. In order to avoid the poll() call that waits for two file descriptors, it was necessary to remove sideband support. Then only one file descriptor needs to be monitored, which can be done in a simple while loop. --- upload-pack.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/upload-pack.c b/upload-pack.c index ec0f0cbfbe..ace719ce1a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -96,7 +96,7 @@ static void show_edge(struct commit *commit) fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1)); } -static void do_rev_list(int create_full_pack) +static void do_rev_list(void *create_full_pack) { int i; struct rev_info revs; @@ -130,10 +130,13 @@ static void do_rev_list(int create_full_pack) prepare_revision_walk(&revs); mark_edges_uninteresting(revs.commits, &revs, show_edge); traverse_commit_list(&revs, show_commit, show_object); + fflush(pack_pipe); + fclose(pack_pipe); } static void create_pack_file(void) { +#ifndef __MINGW32__ /* Pipes between rev-list to pack-objects, pack-objects to us * and pack-objects error stream for progress bar. */ @@ -339,6 +342,86 @@ static void create_pack_file(void) kill(pid_rev_list, SIGKILL); send_client_data(3, abort_msg, sizeof(abort_msg)); die("git-upload-pack: %s", abort_msg); +#else + /* Pipes between rev-list to pack-objects, pack-objects to us. */ + int lp_pipe[2], pu_pipe[2]; + pid_t pid_pack_objects; + int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); + char data[8193]; + char abort_msg[] = "aborting due to possible repository " + "corruption on the remote side."; + int buffered = -1; + ssize_t sz; + char *cp; + const char* argv[] = { "pack-objects", "--stdout", "-q", + use_ofs_delta ? "--delta-base-offset" : NULL, + NULL }; + + if (pipe(lp_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + pack_pipe = fdopen(lp_pipe[1], "w"); + if (_beginthread(do_rev_list, 0, create_full_pack ? &create_full_pack : NULL) < 0) + die("git-upload-pack: unable to run rev-list: %s", strerror(errno)); + + if (pipe(pu_pipe) < 0) + die("git-upload-pack: unable to create pipe"); + + pid_pack_objects = spawnv_git_cmd(argv, lp_pipe, pu_pipe); + if (pid_pack_objects < 0) + die("git-upload-pack: unable to run git-pack-objects"); + + /* We read from pu_pipe[0] to capture the pack data. */ + + while ((sz = xread(pu_pipe[0], data+1, sizeof(data)-1)) > 0) { + cp = data+1; + /* Data ready; we keep the last byte to ourselves in case we + * detect broken rev-list, so that we can leave the stream + * corrupted. This is unfortunate -- unpack-objects would + * happily accept a valid pack data with trailing garbage, so + * appending garbage after we pass all the pack data is not + * good enough to signal breakage to downstream. + */ + if (0 <= buffered) { + *--cp = buffered; + sz++; + } + if (1 < sz) { + buffered = cp[sz-1] & 0xFF; + sz--; + } + else + buffered = -1; + sz = send_client_data(1, cp, sz); + if (sz < 0) + goto fail; + } + if (sz == 0) { + close(pu_pipe[0]); + pu_pipe[0] = -1; + } + else + goto fail; + + /* flush the data */ + if (0 <= buffered) { + data[0] = buffered; + sz = send_client_data(1, data, 1); + if (sz < 0) + goto fail; + fprintf(stderr, "flushed.\n"); + } + if (use_sideband) + packet_flush(1); + if (waitpid(pid_pack_objects, NULL, 0) < 0) + die("git-upload-pack: waiting for pack-objects: %s", + strerror(errno)); + return; + + fail: + kill(pid_pack_objects, SIGKILL); + send_client_data(3, abort_msg, sizeof(abort_msg)); + die("git-upload-pack: %s", abort_msg); +#endif } static int got_sha1(char *hex, unsigned char *sha1) From b61aae484eee63db583579db4ab4773b9e001b7e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 19 Jan 2007 13:16:58 +0100 Subject: [PATCH 047/781] Add a README.MinGW with instructions. --- README.MinGW | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 README.MinGW diff --git a/README.MinGW b/README.MinGW new file mode 100644 index 0000000000..ece360c806 --- /dev/null +++ b/README.MinGW @@ -0,0 +1,53 @@ +This is a port of GIT to Windows using MinGW. + +The goal of this port is to have the tools runnable from the Windows +command line, not from MinGW's rxvt+bash environment. + +(Note: This file was written after-the-fact and may contain errors. +If you are trying this, please make notes and update it.) + + +INSTALLATION +------------ + +In order to compile this code you need: + +- MSYS, e.g. MSYS-1.0.11-2004.04.30-1.exe +- MinGW, e.g. MinGW-5.0.2.exe +- mingwruntime, e.g. mingw-runtime-3.9.tar.gz +- compilers and tools: + binutils-2.15.91-20040904-1.tar.gz + gcc-core-3.4.2-20040916-1.tar.gz + gcc-g++-3.4.2-20040916-1.tar.gz + gdb-6.3-2.exe + mingw32-make-3.80.0-3.tar.gz + unzip-5.51-1-bin.zip (this is not from MinGW, iirc) +- additional libraries: + zlib-1.2.3-mingwPORT-1.tar + w32api-3.6.tar.gz + regex-0.12.tar.gz (from the GNU site) + compile this into regex.o, ar it into libregex.a + and install it in /mingw/lib, include file into + /mingw/include + tcltk-8.4.1-1.exe (for gitk, but it's untested so far) + +It is absolutely necessary that you install MSYS in a path that does not +contain special characters, like spaces. I have it in + + D:\MSYS\1.0 + D:\MSYS\1.0\mingw + +STATUS +------ + +This code base will not compile on a POSIX system, although any help +to introduce the necessary #ifdefs is welcome. As such the status quo +is in no way intended to be merged upstream. + +The toolset has only been used to run the test suite. +The plumbing that does the repository manipulation works, as well as +the porcelains that you need for daily (local!) work. + +pull, clone, fetch, do not work. This means that you must copy a repo +to your Windows using some plain copy instructions (be it Explorer +or command line). From cb0ad0c0af084b52a72791feeca7c70bd8ed855a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 Sep 2006 15:11:29 +0200 Subject: [PATCH 048/781] fix t0000 for absence of symlinks --- Makefile | 2 ++ t/Makefile | 4 ++++ t/t0000-basic.sh | 32 ++++++++++++++++++++++++++++---- t/test-lib.sh | 2 ++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 105e2d1b6e..3144430a97 100644 --- a/Makefile +++ b/Makefile @@ -428,6 +428,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRLCPY=YesPlease NO_ICONV=YesPlease NO_C99_FORMAT = YesPlease + NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o @@ -832,6 +833,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS # However, the environment gets quite big, and some programs have problems # with that. +export NO_SYMLINKS export NO_SVN_TESTS test: all diff --git a/t/Makefile b/t/Makefile index 19e38508a7..8cca7120ce 100644 --- a/t/Makefile +++ b/t/Makefile @@ -13,6 +13,10 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) +ifdef NO_SYMLINKS + GIT_TEST_OPTS += --no-symlinks +endif + all: $(T) clean $(T): diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 186de70243..81ec70ff93 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -30,6 +30,22 @@ fi . ./test-lib.sh +test "$no_symlinks" && { + DIFF=$(which diff) + + function diff () { + opt= + case "$1" in -*) opt=$1; shift;; esac + tr -d "\015" < $1 > $1.doof + grep -v "^:\?120000" < $2 | \ + sed -e s/58a09c23e2ca152193f2786e06986b7b6712bdbe/600f42758e4458c37c2c1f8063378f540b4efad7/ \ + -e s/21ae8269cacbe57ae09138dcc3a2887f904d02b3/cfb8591b2f65de8b8cc1020cd7d9e67e7793b325/ \ + -e s/3c5e5399f3a333eddecce7a9b9465b63f65f51e2/ce580448f0148b985a513b693fdf7d802cacb44f/ \ + > $2.doof + $DIFF $opt $1.doof $2.doof + } +} + ################################################################ # git-init has been done in an empty repository. # make sure it is empty. @@ -113,6 +129,7 @@ cat >expected <<\EOF 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym EOF + test_expect_success \ 'validate git-ls-files output for a known tree.' \ 'diff current expected' @@ -120,9 +137,11 @@ test_expect_success \ test_expect_success \ 'writing tree out with git-write-tree.' \ 'tree=$(git-write-tree)' +expected_tree=087704a96baf1c2d1c869a8b084481e121c88b5b +test "$no_symlinks" && expected_tree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b' + 'test "$tree" = "$expected_tree"' test_expect_success \ 'showing tree with git-ls-tree' \ @@ -180,16 +199,20 @@ test_expect_success \ test_expect_success \ 'writing partial tree out with git-write-tree --prefix.' \ 'ptree=$(git-write-tree --prefix=path3)' +expected_tree=21ae8269cacbe57ae09138dcc3a2887f904d02b3 +test "$no_symlinks" && expected_tree=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3' + 'test "$ptree" = "$expected_tree"' test_expect_success \ 'writing partial tree out with git-write-tree --prefix.' \ 'ptree=$(git-write-tree --prefix=path3/subp3)' +expect_tree=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 +test "$no_symlinks" && expect_tree=ce580448f0148b985a513b693fdf7d802cacb44f test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2' + 'test "$ptree" = "$expect_tree"' cat >badobjects <expected <<\EOF EOF test_expect_success \ 'validate git-diff-files output for a know cache/work tree state.' \ - 'git-diff-files >current && diff >/dev/null -b current expected' + 'git-diff-files >current && diff -b current expected' test_expect_success \ 'git-update-index --refresh should succeed.' \ @@ -246,6 +269,7 @@ test_expect_success \ ################################################################ P=087704a96baf1c2d1c869a8b084481e121c88b5b +test "$no_symlinks" && P=7bb943559a305bdd6bdee2cef6e5df2413c3d30a test_expect_success \ 'git-commit-tree records the correct tree in a commit.' \ 'commit0=$(echo NO | git-commit-tree $P) && diff --git a/t/test-lib.sh b/t/test-lib.sh index 8e3ee6cd7b..8bf0345ef6 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -78,6 +78,8 @@ do --no-python) # noop now... shift ;; + --no-symlinks) + no_symlinks=t; shift ;; *) break ;; esac From 3e70ecba72a43a06ce64cdec2396e663a62b22bc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 13:20:49 +0200 Subject: [PATCH 049/781] prepare more tests for lacking symlinks --- t/t2001-checkout-cache-clash.sh | 2 ++ t/t2003-checkout-cache-mkdir.sh | 4 ++++ t/t2004-checkout-cache-temp.sh | 2 ++ t/t2100-update-cache-badpath.sh | 2 ++ t/t3000-ls-files-others.sh | 1 + 5 files changed, 11 insertions(+) diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index 0dcab8f1de..825119b01c 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -59,10 +59,12 @@ test_expect_success \ 'git-read-tree -m $tree1 && git-checkout-index -f -a' test_debug 'show_files $tree1' +test "$no_symlinks" || { ln -s path0 path1 test_expect_success \ 'git-update-index --add a symlink.' \ 'git-update-index --add path1' +} test_expect_success \ 'writing tree out with git-write-tree' \ 'tree3=$(git-write-tree)' diff --git a/t/t2003-checkout-cache-mkdir.sh b/t/t2003-checkout-cache-mkdir.sh index f9bc90aee4..6aa00f8edb 100755 --- a/t/t2003-checkout-cache-mkdir.sh +++ b/t/t2003-checkout-cache-mkdir.sh @@ -19,6 +19,7 @@ test_expect_success \ echo rezrov >path1/file1 && git-update-index --add path0 path1/file1' +test "$no_symlinks" || { test_expect_success \ 'have symlink in place where dir is expected.' \ 'rm -fr path0 path1 && @@ -27,6 +28,7 @@ test_expect_success \ git-checkout-index -f -a && test ! -h path1 && test -d path1 && test -f path1/file1 && test ! -f path2/file1' +} test_expect_success \ 'use --prefix=path2/' \ @@ -58,6 +60,7 @@ test_expect_success \ test ! -f path0 && test ! -f path1/file1' +test "$no_symlinks" || { # Linus fix #1 test_expect_success \ 'use --prefix=tmp/orary/ where tmp is a symlink' \ @@ -92,5 +95,6 @@ test_expect_success \ test ! -h tmp-path1 && test -d tmp-path1 && test -f tmp-path1/file1' +} test_done diff --git a/t/t2004-checkout-cache-temp.sh b/t/t2004-checkout-cache-temp.sh index c100959cad..1bf63d37e7 100755 --- a/t/t2004-checkout-cache-temp.sh +++ b/t/t2004-checkout-cache-temp.sh @@ -194,6 +194,7 @@ test_expect_success \ test $(cat ../$s1) = tree1asubdir/path5) )' +test "$no_symlinks" || { test_expect_success \ 'checkout --temp symlink' ' rm -f path* .merge_* out .git/index && @@ -208,5 +209,6 @@ test $(cut "-d " -f2 out) = a && p=$(cut "-d " -f1 out) && test -f $p && test $(cat $p) = b' +} test_done diff --git a/t/t2100-update-cache-badpath.sh b/t/t2100-update-cache-badpath.sh index 5bc0a3bed3..cc3bd9f775 100755 --- a/t/t2100-update-cache-badpath.sh +++ b/t/t2100-update-cache-badpath.sh @@ -29,6 +29,7 @@ date >path0 ln -s xyzzy path1 date >path2/file2 date >path3/file3 +test "$no_symlinks" && date > path1 test_expect_success \ 'git-update-index --add to add various paths.' \ @@ -41,6 +42,7 @@ date >path2 ln -s frotz path3 date >path0/file0 date >path1/file1 +test "$no_symlinks" && date > path3 for p in path0/file0 path1/file1 path2 path3 do diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh index adcbe03d56..b470eb46be 100755 --- a/t/t3000-ls-files-others.sh +++ b/t/t3000-ls-files-others.sh @@ -18,6 +18,7 @@ filesystem. date >path0 ln -s xyzzy path1 +test "$no_symlinks" && date > path1 mkdir path2 path3 date >path2/file2 date >path2-junk From 8e128cd8c18d3cac811b9d70ee8b34fc1eae8785 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 Sep 2006 17:34:43 +0200 Subject: [PATCH 050/781] fix more tests for lacking symlinks --- t/t3010-ls-files-killed-modified.sh | 7 +++++++ t/t3100-ls-tree-restrict.sh | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh index 5fc1976711..bf5b20f8a3 100755 --- a/t/t3010-ls-files-killed-modified.sh +++ b/t/t3010-ls-files-killed-modified.sh @@ -37,6 +37,13 @@ modified without reporting path9 and path10. ' . ./test-lib.sh +test "$no_symlinks" && { + function ln () { + test "$1" = -s && shift + date > "$2" + } +} + date >path0 ln -s xyzzy path1 mkdir path2 path3 diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 2ec06d3d39..33df0f95eb 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -18,6 +18,24 @@ path2/baz. Also path0/ should snow nothing. ' . ./test-lib.sh +test "$no_symlinks" && { + function ln () { + test "$1" = -s && shift + date > "$2" + } + DIFF=$(which diff) + function diff () { + opt= + if test "$1" = -u; then + opt="$1" + shift + fi + sed s/^120000/100644/ < "$1" > "$1".doof + $DIFF $opt "$1".doof "$2" + } +} + + test_expect_success \ 'setup' \ 'mkdir path2 path2/baz && From 6e5bd6187c3ad2529a85f1ea063b13695c05b91b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:29:04 +0100 Subject: [PATCH 051/781] Even more tests to skip due to missing symbolic link support. --- t/t3200-branch.sh | 2 ++ t/t4004-diff-rename-symlink.sh | 7 +++++++ t/t4008-diff-break-rewrite.sh | 4 ++++ t/t4011-diff-symlink.sh | 7 +++++++ t/t4115-apply-symlink.sh | 7 +++++++ t/t5000-tar-tree.sh | 7 +++++++ 6 files changed, 34 insertions(+) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index bb80e4286a..258b0c1658 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -110,11 +110,13 @@ test_expect_success 'config information was renamed, too' \ "test $(git-repo-config branch.s.dummy) = Hello && ! git-repo-config branch.s/s/dummy" +test "$no_symlinks" || { test_expect_failure \ 'git-branch -m u v should fail when the reflog for u is a symlink' \ 'git-branch -l u && mv .git/logs/refs/heads/u real-u && ln -s real-u .git/logs/refs/heads/u && git-branch -m u v' +} test_done diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh index a23aaa0a94..61b0fc7cab 100755 --- a/t/t4004-diff-rename-symlink.sh +++ b/t/t4004-diff-rename-symlink.sh @@ -12,6 +12,13 @@ by an edit for them. . ./test-lib.sh . ../diff-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success \ 'prepare reference tree' \ 'echo xyzzy | tr -d '\\\\'012 >yomin && diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 263ac1ebf7..f0c853af29 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -99,6 +99,8 @@ test_expect_success \ 'validate result of -B -M (#4)' \ 'compare_diff_raw expected current' +test "$no_symlinks" || { + test_expect_success \ 'make file0 into something completely different' \ 'rm -f file0 && @@ -148,6 +150,8 @@ test_expect_success \ 'validate result of -M (#7)' \ 'compare_diff_raw expected current' +} # end symlink tests + test_expect_success \ 'file1 edited to look like file0 and file0 rename-edited to file2' \ 'rm -f file0 file1 && diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index 379a831f0b..2e415c0816 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -9,6 +9,13 @@ test_description='Test diff of symlinks. . ./test-lib.sh . ../diff-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + cat > expected << EOF diff --git a/frotz b/frotz new file mode 120000 diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index d5f2cfb186..524d72f0dd 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -9,6 +9,13 @@ test_description='git-apply symlinks and partial files . ./test-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success setup ' ln -s path1/path2/path3/path4/path5 link1 && diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index cf08e9279c..fcfa7e4e41 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -28,6 +28,13 @@ commit id embedding: TAR=${TAR:-tar} UNZIP=${UNZIP:-unzip} +test "$no_symlinks" && { + function ln () { + test "$1" = -s && shift + date > "$2" + } +} + test_expect_success \ 'populate workdir' \ 'mkdir a b c && From f603a1c5620c6d1bca4ca084638a72b67aff07c6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:29:35 +0100 Subject: [PATCH 052/781] Use the git wrapper to invoke git commit. --- t/t3400-rebase.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index b9d3131cc2..1c728c8459 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -15,15 +15,15 @@ test_expect_success \ 'prepare repository with topic branch, then rebase against master' \ 'echo First > A && git-update-index --add A && - git-commit -m "Add A." && + git commit -m "Add A." && git checkout -b my-topic-branch && echo Second > B && git-update-index --add B && - git-commit -m "Add B." && + git commit -m "Add B." && git checkout -f master && echo Third >> A && git-update-index A && - git-commit -m "Modify A." && + git commit -m "Modify A." && git checkout -f my-topic-branch && git rebase master' From 32713b461256c42abd829ca62774649eb7182855 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:38:32 +0100 Subject: [PATCH 053/781] Work around missing tools on MinGW. egrep cannot be called from the Windows command line. dd and sum are not available. --- t/t1002-read-tree-m-u-2way.sh | 6 ++++++ t/t3800-mktag.sh | 2 +- t/t5300-pack-object.sh | 30 +++++++++++++++++++++--------- t/t5301-sliding-window.sh | 4 ++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index da3c81357b..6012df56eb 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,6 +10,12 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh +sum ./test-lib.sh >/dev/null 2>&1 || { + function sum () { + md5sum "$@" + } +} + _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh index ede4d42495..d45e10d026 100755 --- a/t/t3800-mktag.sh +++ b/t/t3800-mktag.sh @@ -15,7 +15,7 @@ check_verify_failure () { test_expect_success \ "$1" \ 'git-mktag message || - egrep -q -f expect.pat message' + grep -E -q -f expect.pat message' } ########################################################### diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 622c5f9968..508803a8e0 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -10,12 +10,28 @@ test_description='git-pack-object TRASH=`pwd` +x4k=xxxxxxxx +x4k="$x4k$x4k$x4k$x4k$x4k$x4k$x4k$x4k" +x4k="$x4k$x4k$x4k$x4k$x4k$x4k$x4k$x4k" +x4k="$x4k$x4k$x4k$x4k$x4k$x4k$x4k$x4k" + +corrupt() +{ + ( + read -d "" -n $4 l + echo -n "$l" + read -d "" -n $3 l + echo -n ${x4k:0:$3} | tr x '\0' + cat + ) < $1 > $2 +} + test_expect_success \ 'setup' \ 'rm -f .git/index* for i in a b c do - dd if=/dev/zero bs=4k count=1 | tr "\\0" $i >$i && + echo -n "$x4k" | tr x $i >$i && git-update-index --add $i || return 1 done && cat c >d && echo foo >>d && git-update-index --add d && @@ -144,8 +160,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted pack signature' \ - 'cp test-1-${packname_1}.pack test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 && + 'corrupt test-1-${packname_1}.pack test-3.pack 1 2 && if git-verify-pack test-3.idx then false else :; @@ -153,8 +168,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted pack version' \ - 'cp test-1-${packname_1}.pack test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 && + 'corrupt test-1-${packname_1}.pack test-3.pack 1 7 && if git-verify-pack test-3.idx then false else :; @@ -162,8 +176,7 @@ test_expect_success \ test_expect_success \ 'verify-pack catches a corrupted type/size of the 1st packed object data' \ - 'cp test-1-${packname_1}.pack test-3.pack && - dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 && + 'corrupt test-1-${packname_1}.pack test-3.pack 1 12 && if git-verify-pack test-3.idx then false else :; @@ -173,8 +186,7 @@ test_expect_success \ 'verify-pack catches a corrupted sum of the index file itself' \ 'l=`wc -c Date: Mon, 8 Jan 2007 18:40:11 +0100 Subject: [PATCH 054/781] Work around CF-LF mismatches introduced by non-MinGW tools. --- t/t1003-read-tree-prefix.sh | 4 ++++ t/t4109-apply-multifrag.sh | 4 ++++ t/t4110-apply-scan.sh | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh index 48ab117d75..1c595f18bb 100755 --- a/t/t1003-read-tree-prefix.sh +++ b/t/t1003-read-tree-prefix.sh @@ -8,6 +8,10 @@ test_description='git-read-tree --prefix test. . ./test-lib.sh +cmp () { + diff -w "$@" +} + test_expect_success setup ' echo hello >one && git-update-index --add one && diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh index 5988e1ae4c..20f46fc1ca 100755 --- a/t/t4109-apply-multifrag.sh +++ b/t/t4109-apply-multifrag.sh @@ -9,6 +9,10 @@ test_description='git-apply test patches with multiple fragments. ' . ./test-lib.sh +cmp () { + diff -w "$@" +} + # setup cat > patch1.patch <<\EOF diff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh index 005f744816..c7cbe4ef64 100755 --- a/t/t4110-apply-scan.sh +++ b/t/t4110-apply-scan.sh @@ -9,6 +9,10 @@ test_description='git-apply test for patches which require scanning forwards and ' . ./test-lib.sh +cmp () { + diff -w "$@" +} + # setup cat > patch1.patch <<\EOF From 306e27d8ee4d61584c0bd6d4b46daabc1f95095b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Jan 2007 14:18:14 +0100 Subject: [PATCH 055/781] Recommend msysDTK for perl and ssh. --- README.MinGW | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MinGW b/README.MinGW index ece360c806..8c704052e8 100644 --- a/README.MinGW +++ b/README.MinGW @@ -22,6 +22,7 @@ In order to compile this code you need: gdb-6.3-2.exe mingw32-make-3.80.0-3.tar.gz unzip-5.51-1-bin.zip (this is not from MinGW, iirc) + msysDTK-1.0.1.exe (contains ssh, perl) - additional libraries: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz From 562cd8385d5ebc4461cef15a91997dd0a4cd1666 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Jan 2007 14:19:23 +0100 Subject: [PATCH 056/781] In the host:/path notation require 'host' to be at least 2 chars long. This is necessary to distinguish the notation from the DOS-style C:/path notation with a drive letter. --- connect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index 171f34837f..d3964b8059 100644 --- a/connect.c +++ b/connect.c @@ -680,7 +680,8 @@ pid_t git_connect(int fd[2], char *url, const char *prog) path = strchr(end, c); if (c == ':') { - if (path) { + /* host must have at least 2 chars to catch DOS C:/path */ + if (path && path - end > 1) { protocol = PROTO_SSH; *path++ = '\0'; } else From d576539c9255d22425efcc55f7e9720fbb8a42d1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Jan 2007 17:06:51 +0100 Subject: [PATCH 057/781] Do not skip the initialization of the date string. Due to some rebasing in the past, new functions that have been introduced upstream moved into the MinGW portion of the #ifdefs just by coincidend, but the initialization of the date string remained in the original spot. The consequence was that all commits that did not use GIT_*_DATE were created with an empty date part. This removes the second instance of setup_ident(), which was lacking the initialization. --- ident.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/ident.c b/ident.c index 83ce631a06..145f54a505 100644 --- a/ident.c +++ b/ident.c @@ -45,8 +45,11 @@ static void copy_gecos(struct passwd *w, char *name, int sz) } +#endif + int setup_ident(void) { +#ifndef NO_ETC_PASSWD int len; struct passwd *pw = getpwuid(getuid()); @@ -74,13 +77,12 @@ int setup_ident(void) else strlcpy(git_default_email + len, "(none)", sizeof(git_default_email) - len); } +#endif /* And set the default date */ datestamp(git_default_date, sizeof(git_default_date)); return 0; } -#else /* NO_ETC_PASSWD */ - static int add_raw(char *buf, int size, int offset, const char *str) { int len = strlen(str); @@ -156,13 +158,6 @@ static int copy(char *buf, int size, int offset, const char *src) return offset; } -int setup_ident(void) -{ - return 0; -} - -#endif - static const char au_env[] = "GIT_AUTHOR_NAME"; static const char co_env[] = "GIT_COMMITTER_NAME"; static const char *env_hint = From 6397c3119ecaa258b5185315c64062bec29bcd86 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 10:06:25 +0100 Subject: [PATCH 058/781] Expect absolute paths with a drive letter. This allows the alternates database to refer to other object databases via a DOS-like path with a drive letter. Furthermore, update-ref sometimes operates on absolute paths. --- sha1_file.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index 14ec604797..7146699c0b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -80,14 +80,22 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) return 0; } +/* returns the number of chars to skip to first component */ +static inline int is_path_absolute(const char *path) +{ +#ifdef __MINGW32__ + if (isalpha(path[0]) && path[1] == ':') + return 2 + (path[2] == '/'); + /* TODO: C:dir/file 'relative' paths are not catered for */ +#endif + return *path == '/'; +} + int safe_create_leading_directories(char *path) { - char *pos = path; + char *pos = path + is_path_absolute(path); struct stat st; - if (*pos == '/') - pos++; - while (pos) { pos = strchr(pos, '/'); if (!pos) @@ -252,7 +260,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative int entlen = pfxlen + 43; int base_len = -1; - if (*entry != '/' && relative_base) { + if (!is_path_absolute(entry) && relative_base) { /* Relative alt-odb */ if (base_len < 0) base_len = strlen(relative_base) + 1; @@ -261,7 +269,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative } ent = xmalloc(sizeof(*ent) + entlen); - if (*entry != '/' && relative_base) { + if (!is_path_absolute(entry) && relative_base) { memcpy(ent->base, relative_base, base_len - 1); ent->base[base_len - 1] = '/'; memcpy(ent->base + base_len, entry, len); @@ -332,7 +340,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep, while (cp < ep && *cp != sep) cp++; if (last != cp) { - if ((*last != '/') && depth) { + if (!is_path_absolute(last) && depth) { error("%s: ignoring relative alternate object store %s", relative_base, last); } else { From 5bc08ee66f49beedb5327446ff147e92345df65c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 13:20:18 +0100 Subject: [PATCH 059/781] Strip \r from the input. Sometimes CRLF ends up in FETCH_HEAD. As a consequence, the fetch source '.' is not recognized as a special case. --- builtin-fmt-merge-msg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index 87d3d63ec7..252c7eb4b5 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -95,6 +95,8 @@ static int handle_line(char *line) return 3; if (line[len - 1] == '\n') + line[len - 1] = 0, --len; + if (line[len - 1] == '\r') line[len - 1] = 0; line += 42; From e40c594146c4368e43ce823df6dcc89589b8e547 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 23 Jan 2007 13:39:09 +0100 Subject: [PATCH 060/781] mingw: always chmod(, 0666) before unlink() On Windows, a read-only file cannot be deleted. To make sure that deletion does not fail because of this, always call chmod() before unlink(). Signed-off-by: Johannes Schindelin --- git-compat-util.h | 7 +++++++ index-pack.c | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index bf42191ab7..4c3250858b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -359,6 +359,13 @@ static inline int git_mkdir(const char *path, int mode) } #define mkdir git_mkdir +static inline int git_unlink(const char *pathname) { + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} +#define unlink git_unlink + #include struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); diff --git a/index-pack.c b/index-pack.c index 040957c016..72e0962415 100644 --- a/index-pack.c +++ b/index-pack.c @@ -700,10 +700,6 @@ static const char *write_index_file(const char *index_name, unsigned char *sha1) fd = mkstemp(tmpfile); index_name = xstrdup(tmpfile); } else { -#ifdef __MINGW32__ - /* read-only files cannot be removed */ - chmod(index_name, 0666); -#endif unlink(index_name); fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600); } From 45c0d8773de8636ce6822b27b82ebf0935cb64e0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 14:19:48 +0100 Subject: [PATCH 061/781] Remove the unused strptime() stub. strptime() is only used in convert-objects.c, but we do not build that one (for reasons I do not recall anymore). That tool should be unnecessary anyway. --- compat/mingw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6d067c9450..f5b64fc564 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -164,13 +164,11 @@ char *mingw_getcwd(char *pointer, int len) } return ret; } -const char *strptime(char *buf, const char *format, struct tm *tm) -{ - die("MinGW does not yet support strptime!"); -} + void sync(void) { } + void openlog(const char *ident, int option, int facility) { } From 58352818740fff00666d23e8eaa102de1eb54747 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Jan 2007 14:45:09 +0100 Subject: [PATCH 062/781] Clean up another instance of unlink that was explicitly chmod(, 0666)ed. --- builtin-prune-packed.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 639fbed2fc..6473d327e6 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -26,10 +26,6 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) if (opts & DRY_RUN) printf("rm -f %s\n", pathname); else { -#ifdef __MINGW32__ - /* read-only files cannot be removed */ - chmod(pathname, 0666); -#endif if (unlink(pathname) < 0) error("unable to unlink %s", pathname); } From 28b06b3aab31c91237788e394cfc4771f029b355 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 09:08:11 +0100 Subject: [PATCH 063/781] Simplify the cpio look-alike. We don't need to write the file list into a temporary file, because GNU tar can take --files-from stdin in --create mode. Furthermore, it understands --null, so that we don't need to translate the zero byte termination to newlines (which incorrectly had been translated to space). --- cpio.sh | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/cpio.sh b/cpio.sh index a0a5a372f2..0b219fa729 100644 --- a/cpio.sh +++ b/cpio.sh @@ -7,11 +7,11 @@ die() { exit 1 } -tr0=cat +null= while test $# -gt 0; do case "$1" in - -0) tr0="tr '\0' ' '";; + -0) null=--null;; -o) mode=o;; -iuv) ;; -pumd|-pumdl) @@ -26,20 +26,12 @@ done case $mode in o) - files=.cpiofiles$$ - $tr0 > $files - tar --create --file=- --files-from=$files --exclude=$files - rc=$? - rm -f $files - exit $rc + tar --create --file=- $null --files-from=- ;; p) - files=.cpiofiles$$ - $tr0 > $files - tar --create --file=- --files-from=$files --exclude=$files | + tar --create --file=- $null --files-from=- | tar --extract --directory="$dir" --file=- - rm -f $files ;; *) - tar xvf - || exit + tar xvf - esac From 4feaf032d3c2e144e0dca61e004481164dace56a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 09:37:48 +0100 Subject: [PATCH 064/781] Do not complain if no committer identifier can be written to the reflog. git clone leaves a half-baked clone without the HEAD ref and no working tree, but with the full repository, if it cannot find the committer information in the GECOS field. For a first-time user this may be puzzling since git clone may be the very first git command to be tried. The reflog is entirely local information, and the warning about the missing information is printed anyway, so there is a hint for the user how to fill it in. --- refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/refs.c b/refs.c index 7d858637c4..d6c717f1c9 100644 --- a/refs.c +++ b/refs.c @@ -958,7 +958,7 @@ static int log_ref_write(struct ref_lock *lock, lock->log_file, strerror(errno)); } - committer = git_committer_info(1); + committer = git_committer_info(0); if (msg) { maxlen = strlen(committer) + strlen(msg) + 2*40 + 5; logrec = xmalloc(maxlen); From 18bf4a4beafb904ab0ee2fcb3a59b7d95f42c9ef Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 10:46:24 +0100 Subject: [PATCH 065/781] Cpio emulator: do not copy files repeatedly in pass-through mode. Files were stored each time when they were mentioned in the file list as well as for each of its directories and parent directories. Now we filter out directory names because they are implied for the files that they contain, but we do list empty directories. The only case where this is relevant is the pass-through mode that git clone of a local directory uses. --- cpio.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/cpio.sh b/cpio.sh index 0b219fa729..2816e34851 100644 --- a/cpio.sh +++ b/cpio.sh @@ -24,12 +24,27 @@ while test $# -gt 0; do shift done +filterdirs() { + while read f; do + if test -d "$f"; then + # list only empty directories + if test -z "$(ls -A "$f")"; then + echo "$f" + fi + else + echo "$f" + fi + done +} + case $mode in o) tar --create --file=- $null --files-from=- ;; p) - tar --create --file=- $null --files-from=- | + test -z "$null" || die "cpio: cannot use -0 in pass-through mode" + filterdirs | + tar --create --file=- --files-from=- | tar --extract --directory="$dir" --file=- ;; *) From 8c5c2ae8fca650b5d0214fff95d611a6b099ca16 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 13:13:14 +0100 Subject: [PATCH 066/781] Update the status part of README.MinGW. pull, fetch, clone work to a large extent. Hurray! --- README.MinGW | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/README.MinGW b/README.MinGW index 8c704052e8..ebd7c0c2ba 100644 --- a/README.MinGW +++ b/README.MinGW @@ -45,10 +45,34 @@ This code base will not compile on a POSIX system, although any help to introduce the necessary #ifdefs is welcome. As such the status quo is in no way intended to be merged upstream. -The toolset has only been used to run the test suite. -The plumbing that does the repository manipulation works, as well as -the porcelains that you need for daily (local!) work. +This works: -pull, clone, fetch, do not work. This means that you must copy a repo -to your Windows using some plain copy instructions (be it Explorer -or command line). +- All the plumbings. +- Many porcelains, in particular, checkout, add, rm, commit, diff, + branch, merge, rebase, log, show, bisect, grep... +- pull, clone, fetch via ssh. +- local pull, clone, fetch. +- gitk, if invoked as "wish84 \bin\gitk", but there are + artefacts in its layout. + +This does not work: + +- pull, clone, fetch via native GIT protocol. +- push +- blame +- daemon, svn, *import, cvs* +- and certainly a lot more that I never have found a need to look at. + +Caveats (aka bugs): + +- The automatic pager of commands like log or diff does not work + correctly: It does not display some portion of text at the end. + That is, if what you should see is less than 4K, you see nothing at + all; otherwise something up to 4K at the end is missing. Use + `git log | less' in these cases. Or `set PAGER=cat' (which is + optimized to skip the pager entirely). +- Internally, the ported tools must do their own command line quoting + when other plumbings are executed. This sort of quoting is currently + implemented *very* simplistic: It just watches out for whitespace + and double quote `"' characters. This may become a problem if you have + exotic characters in your file names. From 46580d2192d79a469f8b40fc1081db9116ad5517 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 16:03:42 +0100 Subject: [PATCH 067/781] Add a missing fork() error check. --- send-pack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/send-pack.c b/send-pack.c index 6756264b29..4bf9466610 100644 --- a/send-pack.c +++ b/send-pack.c @@ -25,6 +25,8 @@ static int pack_objects(int fd, struct ref *refs) if (pipe(pipe_fd) < 0) return error("send-pack: pipe failed"); pid = fork(); + if (pid < 0) + return error("send-pack: unable to fork git-pack-objects"); if (!pid) { /* * The child becomes pack-objects --revs; we feed From 2033ba137a361d0d36c644de45e3d01578a4b77c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 17:06:21 +0100 Subject: [PATCH 068/781] Use spawn*_pipe() instead of fork()/exec() in send-pack and receive-pack. --- receive-pack.c | 10 +--------- send-pack.c | 45 ++++++++++++++++++--------------------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/receive-pack.c b/receive-pack.c index cf83109859..5690f9985c 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -325,17 +325,9 @@ static const char *unpack(void) if (pipe(fd) < 0) return "index-pack pipe failed"; - pid = fork(); + pid = spawnv_git_cmd(keeper, NULL, fd); if (pid < 0) return "index-pack fork failed"; - if (!pid) { - dup2(fd[1], 1); - close(fd[1]); - close(fd[0]); - execv_git_cmd(keeper); - die("execv of index-pack failed"); - } - close(fd[1]); /* * The first thing we expects from index-pack's output diff --git a/send-pack.c b/send-pack.c index 4bf9466610..d1e1372041 100644 --- a/send-pack.c +++ b/send-pack.c @@ -20,44 +20,35 @@ static int use_thin_pack; static int pack_objects(int fd, struct ref *refs) { int pipe_fd[2]; + int pack_fd[2] = { -1, fd }; pid_t pid; + /* + * The child becomes pack-objects --revs; we feed + * the revision parameters to it via its stdin and + * let its stdout go back to the other end. + */ + static const char *args[] = { + "pack-objects", + "--all-progress", + "--revs", + "--stdout", + NULL, + NULL, + }; + if (use_thin_pack) + args[4] = "--thin"; + if (pipe(pipe_fd) < 0) return error("send-pack: pipe failed"); - pid = fork(); + pid = spawnv_git_cmd(args, pipe_fd, pack_fd); if (pid < 0) return error("send-pack: unable to fork git-pack-objects"); - if (!pid) { - /* - * The child becomes pack-objects --revs; we feed - * the revision parameters to it via its stdin and - * let its stdout go back to the other end. - */ - static const char *args[] = { - "pack-objects", - "--all-progress", - "--revs", - "--stdout", - NULL, - NULL, - }; - if (use_thin_pack) - args[4] = "--thin"; - dup2(pipe_fd[0], 0); - dup2(fd, 1); - close(pipe_fd[0]); - close(pipe_fd[1]); - close(fd); - execv_git_cmd(args); - die("git-pack-objects exec failed (%s)", strerror(errno)); - } /* * We feed the pack-objects we just spawned with revision * parameters by writing to the pipe. */ - close(pipe_fd[0]); - close(fd); while (refs) { char buf[42]; From 10c1047e091e93854a5df231b4bf6b2ebdc51d41 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 24 Jan 2007 18:48:14 +0100 Subject: [PATCH 069/781] Fix path_lookup() when the program to invoke contains a slash. In this case, no path lookup actually takes place, and the returned program name is equal to the passed in program name. But this code path contained a thinko that crashed. --- spawn-pipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index b828809820..b4c2538b04 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -79,9 +79,9 @@ static char *path_lookup(const char *cmd, char **path) int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); if (strchr(cmd, '/') || strchr(cmd, '\\')) - p = NULL; + prog = xstrdup(cmd); - while (*p && !prog) { + while (!prog && *p) { prog = lookup_prog(*p++, cmd, tryexe); } if (!prog) { From daabe66f1811adc90825a75ff1b4116e4e7f4a4c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 09:17:06 +0100 Subject: [PATCH 070/781] MinGW: Change the name of hook scripts to make them not executable by default. Since on Windows there is no 'executable' bit whose absence would deny execution of a script, we must change the hook scripts' names entirely to inhibit that they can be invoked by the tools. --- Makefile | 3 ++- templates/Makefile | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3144430a97..7e4fed4416 100644 --- a/Makefile +++ b/Makefile @@ -434,6 +434,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex X = .exe + NOEXECTEMPL = .noexec endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease @@ -635,7 +636,7 @@ endif all:: $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all - $(MAKE) -C templates + $(MAKE) -C templates NOEXECTEMPL='$(NOEXECTEMPL)' strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X diff --git a/templates/Makefile b/templates/Makefile index 9e1ae1a4e0..68614c1cc7 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -5,6 +5,8 @@ TAR ?= tar prefix ?= $(HOME) template_dir ?= $(prefix)/share/git-core/templates/ # DESTDIR= +# set NOEXECTEMPL to non-empty to change the names of hook scripts +# so that the tools will not find them # Shell quote (do not use $(call) to accomodate ancient setups); DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) @@ -27,7 +29,11 @@ boilerplates.made : $(bpsrc) mkdir -p blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - *) cp $$boilerplate blt/$$dst ;; \ + *) if head -1 $$boilerplate | grep -q '^#!/'; then \ + cp $$boilerplate blt/$${dst}$(NOEXECTEMPL); \ + else \ + cp $$boilerplate blt/$$dst; \ + fi ;; \ esac || exit; \ done || exit date >$@ From 479be60605163c7befec1880c72e2cbf584cf206 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 11:12:37 +0100 Subject: [PATCH 071/781] Use spawn*_pipe() instead of fork()/exec() in run_command_*(). --- run-command.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/run-command.c b/run-command.c index cfbad74d14..eb6fefb98b 100644 --- a/run-command.c +++ b/run-command.c @@ -1,28 +1,31 @@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" +#include "spawn-pipe.h" int run_command_v_opt(const char **argv, int flags) { - pid_t pid = fork(); + pid_t pid; + int fd_i[2] = { -1, -1 }; + int fd_o[2] = { -1, -1 }; + if (flags & RUN_COMMAND_NO_STDIN) { +#ifndef __MINGW32__ + fd_i[0] = open("/dev/null", O_RDWR); +#else + fd_i[0] = open("nul", O_RDWR); +#endif + } + if (flags & RUN_COMMAND_STDOUT_TO_STDERR) + fd_o[1] = dup(2); + + if (flags & RUN_GIT_CMD) { + pid = spawnv_git_cmd(argv, fd_i, fd_o); + } else { + pid = spawnvpe_pipe(argv[0], argv, environ, fd_i, fd_o); + } if (pid < 0) return -ERR_RUN_COMMAND_FORK; - if (!pid) { - if (flags & RUN_COMMAND_NO_STDIN) { - int fd = open("/dev/null", O_RDWR); - dup2(fd, 0); - close(fd); - } - if (flags & RUN_COMMAND_STDOUT_TO_STDERR) - dup2(2, 1); - if (flags & RUN_GIT_CMD) { - execv_git_cmd(argv); - } else { - execvp(argv[0], (char *const*) argv); - } - die("exec %s failed.", argv[0]); - } for (;;) { int status, code; pid_t waiting = waitpid(pid, &status, 0); From 62404b843d5a180527aed2007c13a10e6c8b2fa5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 11:31:31 +0100 Subject: [PATCH 072/781] README.MinGW: push works now locally and via ssh! --- README.MinGW | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.MinGW b/README.MinGW index ebd7c0c2ba..0f15eaf92c 100644 --- a/README.MinGW +++ b/README.MinGW @@ -50,15 +50,14 @@ This works: - All the plumbings. - Many porcelains, in particular, checkout, add, rm, commit, diff, branch, merge, rebase, log, show, bisect, grep... -- pull, clone, fetch via ssh. -- local pull, clone, fetch. +- pull, clone, fetch, push via ssh. +- local pull, clone, fetch, push. - gitk, if invoked as "wish84 \bin\gitk", but there are artefacts in its layout. This does not work: -- pull, clone, fetch via native GIT protocol. -- push +- pull, clone, fetch, push via native GIT protocol. - blame - daemon, svn, *import, cvs* - and certainly a lot more that I never have found a need to look at. From 273855b70fd6fcf14a4d77d3bee13bffc22188da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 25 Jan 2007 14:56:02 +0100 Subject: [PATCH 073/781] spawnvppe_pipe(): Don't die on error, some callers want to handle it. --- connect.c | 7 ++++++- diff.c | 2 ++ merge-index.c | 3 +++ spawn-pipe.c | 3 --- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/connect.c b/connect.c index 64222f9ad9..3612c5538c 100644 --- a/connect.c +++ b/connect.c @@ -624,8 +624,11 @@ static void git_proxy_connect(int fd[2], char *host) { const char *argv[] = { NULL, host, port, NULL }; - spawnvpe_pipe(git_proxy_command, argv, environ, pipefd[1], pipefd[0]); + pid = spawnvpe_pipe(git_proxy_command, argv, environ, + pipefd[1], pipefd[0]); } + if (pid < 0) + die("fork failed"); fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; } @@ -761,6 +764,8 @@ pid_t git_connect(int fd[2], char *url, const char *prog) env_unsetenv(env, INDEX_ENVIRONMENT); pid = spawnvpe_pipe("sh", argv, env, pipefd[1], pipefd[0]); } + if (pid < 0) + die("unable to fork"); fd[0] = pipefd[0][0]; fd[1] = pipefd[1][1]; if (free_path) diff --git a/diff.c b/diff.c index 12161b6f87..224d369288 100644 --- a/diff.c +++ b/diff.c @@ -1500,6 +1500,8 @@ static int spawn_prog(const char *pgm, const char **arg) fflush(NULL); pid = spawnvpe_pipe(pgm, arg, environ, NULL, NULL); + if (pid < 0) + die("unable to fork"); while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) diff --git a/merge-index.c b/merge-index.c index 6c2e00842e..bc85e35f4d 100644 --- a/merge-index.c +++ b/merge-index.c @@ -11,6 +11,9 @@ static void run_program(void) pid_t pid = spawnvpe_pipe(pgm, arguments, environ, NULL, NULL); int status; + if (pid < 0) + die("unable to fork"); + if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) { if (one_shot) { err++; diff --git a/spawn-pipe.c b/spawn-pipe.c index b4c2538b04..7d8aa7d6c7 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -198,9 +198,6 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); } - if (pid < 0) - die("unable to run %s", cmd); - free(qargv); /* TODO: quoted args should be freed, too */ free(prog); From 8c8bb94f94f1d972c7ffadda4744cf343fac6f34 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 26 Jan 2007 14:41:01 +0100 Subject: [PATCH 074/781] gitk: Use peek-remote instead of ls-remote. git --git-dir is certainly always local, so there is no need to ask for the advanced services of ls-remote. --- gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk b/gitk index 031c829f26..e415915b74 100755 --- a/gitk +++ b/gitk @@ -309,7 +309,7 @@ proc readrefs {} { foreach v {tagids idtags headids idheads otherrefids idotherrefs} { catch {unset $v} } - set refd [open [list | git ls-remote [gitdir]] r] + set refd [open [list | git peek-remote [gitdir]] r] while {0 <= [set n [gets $refd line]]} { if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \ match id path]} { From f002a73f048a49c75b9d808b96bf84cbb630113c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 29 Jan 2007 13:41:10 +0100 Subject: [PATCH 075/781] Implement a usable gettimeofday(). For simplicity, my_mktime() of date.c is reused to avoid the convolutions that gmtime() and localtime() would implicate. --- compat/mingw.c | 18 +++++++++++++++++- date.c | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f5b64fc564..7f5067676c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -81,10 +81,26 @@ int mkstemp (char *__template) return -1; return open(filename, O_RDWR | O_CREAT); } + int gettimeofday(struct timeval *tv, void *tz) { - return -1; + extern time_t my_mktime(struct tm *tm); + SYSTEMTIME st; + struct tm tm; + GetSystemTime(&st); + tm.tm_year = st.wYear-1900; + tm.tm_mon = st.wMonth-1; + tm.tm_mday = st.wDay; + tm.tm_hour = st.wHour; + tm.tm_min = st.wMinute; + tm.tm_sec = st.wSecond; + tv->tv_sec = my_mktime(&tm); + if (tv->tv_sec < 0) + return -1; + tv->tv_usec = st.wMilliseconds*1000; + return 0; } + int pipe(int filedes[2]) { int fd; diff --git a/date.c b/date.c index 542c004c2e..11aa176a7f 100644 --- a/date.c +++ b/date.c @@ -6,7 +6,7 @@ #include "cache.h" -static time_t my_mktime(struct tm *tm) +time_t my_mktime(struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 From 5c098f977167ae604483848323c123c2ae620e6b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 29 Jan 2007 13:46:49 +0100 Subject: [PATCH 076/781] Ignore cpio, the cpio emulator. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6da1cdbd0d..8cd125a9d1 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,4 @@ config.status config.mak.autogen config.mak.append configure +cpio From 3b3ed42c0371b1b99163024ba0dd289b3471a886 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 29 Jan 2007 18:34:37 +0100 Subject: [PATCH 077/781] Update README.MinGW: blame works. --- README.MinGW | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.MinGW b/README.MinGW index 0f15eaf92c..3c67064f3f 100644 --- a/README.MinGW +++ b/README.MinGW @@ -51,14 +51,13 @@ This works: - Many porcelains, in particular, checkout, add, rm, commit, diff, branch, merge, rebase, log, show, bisect, grep... - pull, clone, fetch, push via ssh. -- local pull, clone, fetch, push. +- Local pull, clone, fetch, push. - gitk, if invoked as "wish84 \bin\gitk", but there are artefacts in its layout. This does not work: - pull, clone, fetch, push via native GIT protocol. -- blame - daemon, svn, *import, cvs* - and certainly a lot more that I never have found a need to look at. From 3a8b35c3e37369014dc06c767e8fa569150a1e59 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 31 Jan 2007 18:04:12 +0100 Subject: [PATCH 078/781] Renaming .gitk-new to .gitk fails if there is already a .gitk. Remove the existing one before renaming. --- gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk b/gitk index 7ef401fb6d..f17ba365eb 100755 --- a/gitk +++ b/gitk @@ -822,6 +822,7 @@ proc savestuff {w} { } puts $f "}" close $f + catch {file delete "~/.gitk"} file rename -force "~/.gitk-new" "~/.gitk" } set stuffsaved 1 From 1973bc88c31030094b8e9191d148dfd2133b431c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 29 Jan 2007 21:53:28 -0800 Subject: [PATCH 079/781] Use show-ref instead of ls-remote It used to be ls-remote on self was the only easy way to grab the ref information. Now we have show-ref which does not involve fork and IPC, so use it. Signed-off-by: Junio C Hamano --- gitk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index 031c829f26..fc86af4dcf 100755 --- a/gitk +++ b/gitk @@ -309,9 +309,9 @@ proc readrefs {} { foreach v {tagids idtags headids idheads otherrefids idotherrefs} { catch {unset $v} } - set refd [open [list | git ls-remote [gitdir]] r] + set refd [open [list | git show-ref] r] while {0 <= [set n [gets $refd line]]} { - if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \ + if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \ match id path]} { continue } From f48ce084de9afc7e0c5225b3fa51f4374b42f2ee Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 Feb 2007 15:41:43 +0100 Subject: [PATCH 080/781] MinGW: Make git native protocol work. As it turns out, the things returned by Winsock2's socket() are handles that can be passed to ReadFile()/WriteFile() - almost. The way this works is by wrapping those handles into file descriptors with _open_osfhandle(). But it turns out that the sockets created by the plain socket() function are prepared for "overlapped" I/O, which confuses ReadFile()/WriteFile(). Therefore, a reimplementation is provided that uses WSASocket() to explicitly asks for non-overlapped sockets. Special thanks got to H. Peter Anvin, who provided the necessary clues. --- README.MinGW | 6 +++--- compat/mingw.c | 19 +++++++++++++++++++ connect.c | 16 ++++++++++++++++ git-compat-util.h | 3 +++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/README.MinGW b/README.MinGW index 3c67064f3f..4a454edf2c 100644 --- a/README.MinGW +++ b/README.MinGW @@ -50,14 +50,14 @@ This works: - All the plumbings. - Many porcelains, in particular, checkout, add, rm, commit, diff, branch, merge, rebase, log, show, bisect, grep... -- pull, clone, fetch, push via ssh. +- pull, clone, fetch, push via native git protocal as well as ssh. - Local pull, clone, fetch, push. - gitk, if invoked as "wish84 \bin\gitk", but there are - artefacts in its layout. + artefacts in its layout. A workaround by Mark Levedahl is in + branch 'devel'. This does not work: -- pull, clone, fetch, push via native GIT protocol. - daemon, svn, *import, cvs* - and certainly a lot more that I never have found a need to look at. diff --git a/compat/mingw.c b/compat/mingw.c index 7f5067676c..6887968a10 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -293,3 +293,22 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) exit(ret); } } + +int mingw_socket(int domain, int type, int protocol) +{ + SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); + if (s == INVALID_SOCKET) { + /* + * WSAGetLastError() values are regular BSD error codes + * biased by WSABASEERR. + * However, strerror() does not know about networking + * specific errors, which are values beginning at 38 or so. + * Therefore, we choose to leave the biased error code + * in errno so that _if_ someone looks up the code somewhere, + * then it is at least the number that are usually listed. + */ + errno = WSAGetLastError(); + return -1; + } + return s; +} diff --git a/connect.c b/connect.c index 3612c5538c..39cc73e9aa 100644 --- a/connect.c +++ b/connect.c @@ -527,7 +527,23 @@ static int git_tcp_connect_sock(char *host) static void git_tcp_connect(int fd[2], char *host) { +#ifndef __MINGW32__ int sockfd = git_tcp_connect_sock(host); +#else + int sockfd; + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2,2), &wsa)) + die("unable to initialize winsock subsystem, error %d", + WSAGetLastError()); + atexit((void(*)(void)) WSACleanup); + + sockfd = git_tcp_connect_sock(host); + /* convert into a file descriptor */ + if ((sockfd = _open_osfhandle(sockfd, O_RDWR|O_BINARY)) < 0) + die("unable to make a socket file descriptor: %s", + strerror(errno)); +#endif fd[0] = sockfd; fd[1] = dup(sockfd); diff --git a/git-compat-util.h b/git-compat-util.h index 37ac8dbc23..cafca04d01 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -374,6 +374,9 @@ struct tm *localtime_r(const time_t *timep, struct tm *result); char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd +int mingw_socket(int domain, int type, int protocol); +#define socket mingw_socket + #define setlinebuf(x) #define fsync(x) From 1ed87d37f22ff90823cd1fd719193a3d9a279cbb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 5 Feb 2007 17:07:42 -0800 Subject: [PATCH 081/781] receive-pack.c: fix mismerge. Commit 29d231eb mismerged to introduce style breakage. Signed-off-by: Junio C Hamano --- receive-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/receive-pack.c b/receive-pack.c index c51f417aed..7311c822dd 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -423,7 +423,7 @@ int main(int argc, char **argv) if (!dir) usage(receive_pack_usage); - if(!enter_repo(dir, 0)) + if (!enter_repo(dir, 0)) die("'%s': unable to chdir or not a git archive", dir); if (is_repository_shallow()) From 8101270a3f1ac743b665b0bd93564316f71d1923 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Feb 2007 19:37:40 -0800 Subject: [PATCH 082/781] Revert "in_merge_bases(): optimization" This reverts commit dc3806d39698899fe81e55c0daa5bd9d30d13d9c. --- commit.c | 46 +++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/commit.c b/commit.c index bbb9840c48..b37e3dd0ad 100644 --- a/commit.c +++ b/commit.c @@ -1063,7 +1063,7 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *base_traverse(struct commit_list *list, struct commit *stop) +static struct commit_list *base_traverse(struct commit_list *list) { struct commit_list *result = NULL; @@ -1097,20 +1097,10 @@ static struct commit_list *base_traverse(struct commit_list *list, struct commit p->object.flags |= flags; insert_by_date(p, &list); } - if (stop && (stop->object.flags & PARENT2)) { - free_commit_list(list); - list = NULL; - insert_by_date(stop, &list); - return list; - } } /* Clean up the result to remove stale ones */ free_commit_list(list); - - if (stop) - return NULL; - list = result; result = NULL; while (list) { struct commit_list *n = list->next; @@ -1140,7 +1130,7 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two) insert_by_date(one, &list); insert_by_date(two, &list); - return base_traverse(list, NULL); + return base_traverse(list); } struct commit_list *get_merge_bases(struct commit *one, @@ -1205,30 +1195,20 @@ struct commit_list *get_merge_bases(struct commit *one, int in_merge_bases(struct commit *commit, struct commit **reference, int num) { - struct commit_list *result, *list; - int i, ret; + struct commit_list *bases, *b; + int ret = 0; - list = NULL; - parse_commit(commit); - commit->object.flags |= PARENT1; - insert_by_date(commit, &list); - - for (i = 0; i < num; i++) { - struct commit *two = reference[i]; - parse_commit(two); - if (!(two->object.flags & PARENT2)) { - two->object.flags |= PARENT2; - insert_by_date(two, &list); + if (num == 1) + bases = get_merge_bases(commit, *reference, 1); + else + die("not yet"); + for (b = bases; b; b = b->next) { + if (!hashcmp(commit->object.sha1, b->item->object.sha1)) { + ret = 1; + break; } } - result = base_traverse(list, commit); - ret = !!result; - free_commit_list(result); - clear_commit_marks(commit, all_flags); - for (i = 0; i < num; i++) { - struct commit *two = reference[i]; - clear_commit_marks(two, all_flags); - } + free_commit_list(bases); return ret; } From 5e52001ae27ba4c1b3b86864819a5fe895a0c32e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Feb 2007 19:37:46 -0800 Subject: [PATCH 083/781] Revert "merge_base(): move traversal into a separate function." This reverts commit 40e0e66bb00646fbdc998c4fe01280470489d0e5. --- commit.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/commit.c b/commit.c index b37e3dd0ad..8d279b0b63 100644 --- a/commit.c +++ b/commit.c @@ -1063,10 +1063,25 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *base_traverse(struct commit_list *list) +static struct commit_list *merge_bases(struct commit *one, struct commit *two) { + struct commit_list *list = NULL; struct commit_list *result = NULL; + if (one == two) + /* We do not mark this even with RESULT so we do not + * have to clean it up. + */ + return commit_list_insert(one, &result); + + parse_commit(one); + parse_commit(two); + + one->object.flags |= PARENT1; + two->object.flags |= PARENT2; + insert_by_date(one, &list); + insert_by_date(two, &list); + while (interesting(list)) { struct commit *commit; struct commit_list *parents; @@ -1112,27 +1127,6 @@ static struct commit_list *base_traverse(struct commit_list *list) return result; } -static struct commit_list *merge_bases(struct commit *one, struct commit *two) -{ - struct commit_list *list = NULL; - - if (one == two) - /* We do not mark this even with RESULT so we do not - * have to clean it up. - */ - return commit_list_insert(one, &list); - - parse_commit(one); - parse_commit(two); - - one->object.flags |= PARENT1; - two->object.flags |= PARENT2; - insert_by_date(one, &list); - insert_by_date(two, &list); - - return base_traverse(list); -} - struct commit_list *get_merge_bases(struct commit *one, struct commit *two, int cleanup) From 079f7cb27b6636f9153c24a82f3d5d74a7b0b6b1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 13 Feb 2007 19:44:24 -0800 Subject: [PATCH 084/781] Revert jc/3way topic altogether. Signed-off-by: Junio C Hamano --- git-checkout.sh | 7 ------- git-merge.sh | 47 +---------------------------------------------- 2 files changed, 1 insertion(+), 53 deletions(-) diff --git a/git-checkout.sh b/git-checkout.sh index 3e09f4d92b..14835a4aa9 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -191,9 +191,6 @@ else exit 1 ;; esac - # First stash away the local changes - git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF - # Match the index to the working tree, and do a three-way. git diff-files --name-only | git update-index --remove --stdin && work=`git write-tree` && @@ -218,10 +215,6 @@ else sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" echo "$unmerged" ) | git update-index --index-info - - echo >&2 "Conflicts in locally modified files:" - git diff --name-only --diff-filter=U >&2 - echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" ;; esac exit 0 diff --git a/git-merge.sh b/git-merge.sh index b0f4c67bf8..04a5eb0f29 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -97,51 +97,6 @@ finish () { esac } -merge_local_changes () { - merge_error=$(git-read-tree -m -u --exclude-per-directory=.gitignore $1 $2 2>&1) || ( - - # First stash away the local changes - git diff-index --binary -p HEAD >"$GIT_DIR"/LOCAL_DIFF - - # Match the index to the working tree, and do a three-way. - git diff-files --name-only | - git update-index --remove --stdin && - work=`git write-tree` && - git read-tree --reset -u $2 && - git read-tree -m -u --aggressive --exclude-per-directory=.gitignore $1 $2 $work || exit - - echo >&2 "Carrying local changes forward." - if result=`git write-tree 2>/dev/null` - then - echo >&2 "Trivially automerged." - else - git merge-index -o git-merge-one-file -a - fi - - # Do not register the cleanly merged paths in the index - # yet; this is not a real merge before committing, but - # just carrying the working tree changes along. - unmerged=`git ls-files -u` - git read-tree --reset $2 - case "$unmerged" in - '') ;; - *) - ( - z40=0000000000000000000000000000000000000000 - echo "$unmerged" | - sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" - echo "$unmerged" - ) | git update-index --index-info - - echo >&2 "Conflicts in locally modified files:" - git diff --name-only --diff-filter=U >&2 - echo >&2 "Your local changes are found in $GIT_DIR/LOCAL_DIFF" - ;; - esac - exit 0 - ) -} - merge_name () { remote="$1" rh=$(git-rev-parse --verify "$remote^0" 2>/dev/null) || return @@ -335,7 +290,7 @@ f,*) 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") && - merge_local_changes $head $new_head && + git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && finish "$new_head" "Fast forward" dropsave exit 0 From 0bcd515c57e355e02531c5d00d747a54df3e5942 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 11:38:15 +0100 Subject: [PATCH 085/781] mkstemp implementation: Specify a umask for open(). We have been lucky in the past that the missing argument was taken from whatever random value was on the stack and it was still a somewhat useful umask, but we should really specify 0600 there. --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6887968a10..70a8e1f78f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -79,7 +79,7 @@ int mkstemp (char *__template) char *filename = mktemp(__template); if (filename == NULL) return -1; - return open(filename, O_RDWR | O_CREAT); + return open(filename, O_RDWR | O_CREAT, 0600); } int gettimeofday(struct timeval *tv, void *tz) From f67787066394b2b348071a8046aad00ef553d3f7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 12:11:54 +0100 Subject: [PATCH 086/781] strtoumax is not available on Windows; fall back to strtoul. --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index cafca04d01..761458cef9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -379,6 +379,7 @@ int mingw_socket(int domain, int type, int protocol); #define setlinebuf(x) #define fsync(x) +#define strtoumax strtoul extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From e919589df17960ff9a1ce653032ee0a4876aca06 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 10:50:41 +0100 Subject: [PATCH 087/781] Move #include to git-compat-util.h. --- git-compat-util.h | 1 + pager.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 761458cef9..1f2f187284 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -39,6 +39,7 @@ #include //#include //#include +//#include #include #include //#include diff --git a/pager.c b/pager.c index 48b3cb3c17..a63fe31bb5 100644 --- a/pager.c +++ b/pager.c @@ -1,8 +1,6 @@ #include "cache.h" #include "spawn-pipe.h" -#include - /* * This is split up from the rest of git so that we might do * something different on Windows, for example. From b565323c2dd91483496119102dd5e49295c26d31 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 13:13:31 +0100 Subject: [PATCH 088/781] Funny characters in file names are not supported on Windows, skip test. --- t/t4016-diff-quote.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index edde8f5568..174ea4b6f1 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -8,6 +8,13 @@ test_description='Quoting paths in diff output. . ./test-lib.sh +if test "$no_symlinks" +then + say 'Filenames with tabs and new-lines not supported, skipping tests.' + test_done + exit +fi + P0='pathname' P1='pathname with HT' P2='pathname with SP' From e62f9693f184d53b27820139ab4f811f41b2ced3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 13:43:18 +0100 Subject: [PATCH 089/781] Update README.MinGW. gitk's layout works now well with the upstream version. --- README.MinGW | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.MinGW b/README.MinGW index 4a454edf2c..c6c059e24d 100644 --- a/README.MinGW +++ b/README.MinGW @@ -30,7 +30,7 @@ In order to compile this code you need: compile this into regex.o, ar it into libregex.a and install it in /mingw/lib, include file into /mingw/include - tcltk-8.4.1-1.exe (for gitk, but it's untested so far) + tcltk-8.4.1-1.exe (for gitk, git-gui) It is absolutely necessary that you install MSYS in a path that does not contain special characters, like spaces. I have it in @@ -52,9 +52,7 @@ This works: branch, merge, rebase, log, show, bisect, grep... - pull, clone, fetch, push via native git protocal as well as ssh. - Local pull, clone, fetch, push. -- gitk, if invoked as "wish84 \bin\gitk", but there are - artefacts in its layout. A workaround by Mark Levedahl is in - branch 'devel'. +- gitk, if invoked as "wish84 \bin\gitk". Ditto for git-gui. This does not work: From e0dd8fcfe3055d3874c2351cb6c227200b49ee1b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 09:57:47 +0100 Subject: [PATCH 090/781] Revert "Funny characters in file names are not supported on Windows, skip test." This reverts commit b565323c2dd91483496119102dd5e49295c26d31. A better, generic solution is now in upstream. --- t/t4016-diff-quote.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index a203653b76..2e7cd5f255 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -8,13 +8,6 @@ test_description='Quoting paths in diff output. . ./test-lib.sh -if test "$no_symlinks" -then - say 'Filenames with tabs and new-lines not supported, skipping tests.' - test_done - exit -fi - P0='pathname' P1='pathname with HT' P2='pathname with SP' From dfa7eac0c0a6fac5e55c5ee77c4410630b07872f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 09:58:40 +0100 Subject: [PATCH 091/781] Use compat/strtoumax.c as a substitute for the missing strtoumax. This reverts commit f67787066394b2b348071a8046aad00ef553d3f7 and uses the compatibility facilities that upstream includes. --- Makefile | 1 + git-compat-util.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index afe4cd8d1b..95b92a3597 100644 --- a/Makefile +++ b/Makefile @@ -437,6 +437,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRLCPY=YesPlease NO_ICONV=YesPlease NO_C99_FORMAT = YesPlease + NO_STRTOUMAX = YesPlease NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat diff --git a/git-compat-util.h b/git-compat-util.h index 74f8317467..a8df17ae43 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -395,7 +395,6 @@ int mingw_socket(int domain, int type, int protocol); #define setlinebuf(x) #define fsync(x) -#define strtoumax strtoul extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From fba729381275254038c1e5a301b10e2b103d727d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 10:38:16 +0100 Subject: [PATCH 092/781] Flush stdout before closing it. This embarrassing omission was the reason that only incomplete data was sent to the automatically invoked pager. --- README.MinGW | 6 ------ pager.c | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/README.MinGW b/README.MinGW index c6c059e24d..a8ad34bc4b 100644 --- a/README.MinGW +++ b/README.MinGW @@ -61,12 +61,6 @@ This does not work: Caveats (aka bugs): -- The automatic pager of commands like log or diff does not work - correctly: It does not display some portion of text at the end. - That is, if what you should see is less than 4K, you see nothing at - all; otherwise something up to 4K at the end is missing. Use - `git log | less' in these cases. Or `set PAGER=cat' (which is - optimized to skip the pager entirely). - Internally, the ported tools must do their own command line quoting when other plumbings are executed. This sort of quoting is currently implemented *very* simplistic: It just watches out for whitespace diff --git a/pager.c b/pager.c index a63fe31bb5..f4f999ef6e 100644 --- a/pager.c +++ b/pager.c @@ -26,6 +26,7 @@ static void run_pager(const char *pager) static pid_t pager_pid; static void collect_pager(void) { + fflush(stdout); close(1); /* signals EOF to pager */ cwait(NULL, pager_pid, 0); } From 3077c83763853b703f52c1279e6d5a7e7e179599 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 11:38:16 +0100 Subject: [PATCH 093/781] Really run scripts under the interpreter specified in the first line. Earlier we would have run all scripts under 'sh', but only changed the name (argv[0]) to the parsed interpreter. While we are here, also ignore command line options specified in the interpreter line; perl's -w is the common case. --- compat/mingw.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 70a8e1f78f..dbc13f0c8a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -230,7 +230,7 @@ void quote_argv(const char **dst, const char **src) const char *parse_interpreter(const char *cmd) { static char buf[100]; - char *p; + char *p, *opt; int n, fd; /* don't even try a .exe */ @@ -256,6 +256,9 @@ const char *parse_interpreter(const char *cmd) *p = '\0'; if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\'))) return NULL; + /* strip options */ + if ((opt = strchr(p+1, ' '))) + *opt = '\0'; return p+1; } @@ -278,7 +281,7 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) sh_argv[0] = interpr; sh_argv[1] = cmd; quote_argv(&sh_argv[2], &argv[1]); - n = spawnvpe(_P_WAIT, "sh", sh_argv, env); + n = spawnvpe(_P_WAIT, interpr, sh_argv, env); if (n == -1) return 1; /* indicate that we tried but failed */ exit(n); From bd2f73a6ba6daf6158112874414d338c7b0e528d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Feb 2007 11:44:19 +0100 Subject: [PATCH 094/781] Support the tools scripted in perl. There is one subtlety in perl/Makefile: The $(prefix) may contain a drive letter-colon combination. But unfortunately, the perl scripts contain a stance that splits the path at colons to find Git.pm. For this reason, we convert the path to the MSYS style, which does not have the colon. --- Makefile | 2 ++ perl/Makefile | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 95b92a3597..cb32c2f2e7 100644 --- a/Makefile +++ b/Makefile @@ -424,6 +424,7 @@ ifeq ($(uname_S),IRIX64) endif ifneq (,$(findstring MINGW,$(uname_S))) SHELL_PATH = $(shell cd /bin && pwd -W)/sh + PERL_PATH = $(shell cd /bin && pwd -W)/perl NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease @@ -440,6 +441,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRTOUMAX = YesPlease NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease + NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o EXTLIBS += -lws2_32 -lregex diff --git a/perl/Makefile b/perl/Makefile index 099beda873..fdb7cb9886 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -16,7 +16,11 @@ clean: $(RM) $(makfile).old ifdef NO_PERL_MAKEMAKER -instdir_SQ = $(subst ','\'',$(prefix)/lib) +# We exploit that /bin/sh transforms the DOS-Stype path in TEMP into +# the MSYS style pseudo-mount form. +# This colon-free from is needed because our perl scripts look at +# $(instdir_SQ) and split it at colons. +instdir_SQ = $(subst ','\'',$(shell cmd /x/d/c "set TEMP=$(prefix)/lib && sh -c 'echo \$$TEMP'")) $(makfile): ../GIT-CFLAGS Makefile echo all: > $@ echo ' :' >> $@ From e5805d2c579f9040d0381b046313e9ef0f189711 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 1 Mar 2007 10:40:57 +0100 Subject: [PATCH 095/781] Use /tmp instead of /var/tmp. --- git-gui/CREDITS-GEN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/CREDITS-GEN b/git-gui/CREDITS-GEN index d1b0f86355..1aff2f8088 100755 --- a/git-gui/CREDITS-GEN +++ b/git-gui/CREDITS-GEN @@ -36,7 +36,7 @@ generate_credits () # that fact. # -credits_tmp=/var/tmp/gitgui-credits-$$ +credits_tmp=/tmp/gitgui-credits-$$ trap 'rm -f "$credits_tmp"' 0 orig="$credits_tmp" From 02560cdbcffb497304513b84f14b4bf5a0ec8a9c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 1 Mar 2007 22:09:05 +0100 Subject: [PATCH 096/781] Include regex.[ch] in compat/ They are both GPLed, so there is no problem with it. Signed-off-by: Johannes Schindelin --- Makefile | 4 +- compat/regex.c | 4921 ++++++++++++++++++++++++++++++++++++++++++++++++ compat/regex.h | 490 +++++ 3 files changed, 5413 insertions(+), 2 deletions(-) create mode 100644 compat/regex.c create mode 100644 compat/regex.h diff --git a/Makefile b/Makefile index cb32c2f2e7..92151f25d4 100644 --- a/Makefile +++ b/Makefile @@ -443,8 +443,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o - EXTLIBS += -lws2_32 -lregex + COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o + EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec endif diff --git a/compat/regex.c b/compat/regex.c new file mode 100644 index 0000000000..2d57c70b9c --- /dev/null +++ b/compat/regex.c @@ -0,0 +1,4921 @@ +/* Extended regular expression matching and search library, + version 0.12. + (Implements POSIX draft P10003.2/D11.2, except for + internationalization features.) + + Copyright (C) 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (REGEX_MALLOC) + #pragma alloca +#endif + +#define _GNU_SOURCE + +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +#include + +/* We used to test for `BSTRING' here, but only GCC and Emacs define + `BSTRING', as far as I know, and neither of them use this code. */ +#include +#ifndef bcmp +#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) +#endif +#ifndef bcopy +#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#endif +#ifndef bzero +#define bzero(s, n) memset ((s), 0, (n)) +#endif + +#include + + +/* Define the syntax stuff for \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +#ifndef Sword +#define Sword 1 +#endif + +#ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +#else /* not SYNTAX_TABLE */ + +/* How many characters in the character set. */ +#define CHAR_SET_SIZE 256 + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +#endif /* not SYNTAX_TABLE */ + +#define SYNTAX(c) re_syntax_table[c] + + +/* Get the interface, including the syntax bits. */ +#include "regex.h" + +/* isalpha etc. are used for the character classes. */ +#include + +#ifndef isascii +#define isascii(c) 1 +#endif + +#ifdef isblank +#define ISBLANK(c) (isascii (c) && isblank (c)) +#else +#define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +#define ISGRAPH(c) (isascii (c) && isgraph (c)) +#else +#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (isascii (c) && isprint (c)) +#define ISDIGIT(c) (isascii (c) && isdigit (c)) +#define ISALNUM(c) (isascii (c) && isalnum (c)) +#define ISALPHA(c) (isascii (c) && isalpha (c)) +#define ISCNTRL(c) (isascii (c) && iscntrl (c)) +#define ISLOWER(c) (isascii (c) && islower (c)) +#define ISPUNCT(c) (isascii (c) && ispunct (c)) +#define ISSPACE(c) (isascii (c) && isspace (c)) +#define ISUPPER(c) (isascii (c) && isupper (c)) +#define ISXDIGIT(c) (isascii (c) && isxdigit (c)) + +#ifndef NULL +#define NULL 0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +#define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +#define REGEX_ALLOCATE malloc +#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +#ifndef alloca + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if HAVE_ALLOCA_H +#include +#else /* not __GNUC__ or HAVE_ALLOCA_H */ +#ifndef _AIX /* Already did AIX, up at the top. */ +char *alloca (); +#endif /* not _AIX */ +#endif /* not HAVE_ALLOCA_H */ +#endif /* not __GNUC__ */ + +#endif /* not alloca */ + +#define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +#define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + bcopy (source, destination, osize), \ + destination) + +#endif /* not REGEX_MALLOC */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +#define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +#define BYTEWIDTH 8 /* In bits. */ + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +typedef char boolean; +#define false 0 +#define true 1 + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. + + The value of `exactn' is needed in search.c (search_buffer) in Emacs. + So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of + `exactn' we use here must also be 1. */ + +typedef enum +{ + no_op = 0, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn = 1, + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Same as jump, but marks the end of an alternative. */ + jump_past_alt, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ + pop_failure_jump, + + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ + maybe_pop_jump, + + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ + dummy_failure_jump, + + /* Push a dummy failure point and continue. Used at the end of + alternatives. */ + push_dummy_failure, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + set_number_at, + + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound /* Succeeds if not at a word boundary. */ + +#ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec +#endif /* emacs */ +} re_opcode_t; + +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ + +#define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ + +#define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += 2; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ + +#define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) + +#ifdef DEBUG +static void +extract_number (dest, source) + int *dest; + unsigned char *source; +{ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +} + +#ifndef EXTRACT_MACROS /* To debug the macros. */ +#undef EXTRACT_NUMBER +#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) +#endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += 2; \ + } while (0) + +#ifdef DEBUG +static void +extract_number_and_incr (destination, source) + int *destination; + unsigned char **source; +{ + extract_number (destination, *source); + *source += 2; +} + +#ifndef EXTRACT_MACROS +#undef EXTRACT_NUMBER_AND_INCR +#define EXTRACT_NUMBER_AND_INCR(dest, src) \ + extract_number_and_incr (&dest, &src) +#endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +#ifdef DEBUG + +/* We use standard I/O for debugging. */ +#include + +/* It is useful to test things that ``must'' be true when debugging. */ +#include + +static int debug = 0; + +#define DEBUG_STATEMENT(e) e +#define DEBUG_PRINT1(x) if (debug) printf (x) +#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) print_partial_compiled_pattern (s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) print_double_string (w, s1, sz1, s2, sz2) + + +extern void printchar (); + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + printchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + printchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + unsigned char *start; + unsigned char *end; +{ + int mcnt, mcnt2; + unsigned char *p = start; + unsigned char *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + printchar (*p++); + } + while (--mcnt); + break; + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%d", mcnt, *p++); + break; + + case duplicate: + printf ("/duplicate/%d", *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { + register int c; + + printf ("/charset%s", + (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); + + assert (p + *p < pend); + + for (c = 0; c < *p; c++) + { + unsigned bit; + unsigned char map_byte = p[1 + c]; + + putchar ('/'); + + for (bit = 0; bit < BYTEWIDTH; bit++) + if (map_byte & (1 << bit)) + printchar (c * BYTEWIDTH + bit); + } + p += 1 + *p; + break; + } + + case begline: + printf ("/begline"); + break; + + case endline: + printf ("/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump/0/%d", mcnt); + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump/0/%d", mcnt); + break; + + case dummy_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump/0/%d", mcnt); + break; + + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + + case maybe_pop_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/maybe_pop_jump/0/%d", mcnt); + break; + + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump/0/%d", mcnt); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt/0/%d", mcnt); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump/0/%d", mcnt); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); + break; + + case wordbound: + printf ("/wordbound"); + break; + + case notwordbound: + printf ("/notwordbound"); + break; + + case wordbeg: + printf ("/wordbeg"); + break; + + case wordend: + printf ("/wordend"); + +#ifdef emacs + case before_dot: + printf ("/before_dot"); + break; + + case at_dot: + printf ("/at_dot"); + break; + + case after_dot: + printf ("/after_dot"); + break; + + case syntaxspec: + printf ("/syntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; + + case notsyntaxspec: + printf ("/notsyntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; +#endif /* emacs */ + + case wordchar: + printf ("/wordchar"); + break; + + case notwordchar: + printf ("/notwordchar"); + break; + + case begbuf: + printf ("/begbuf"); + break; + + case endbuf: + printf ("/endbuf"); + break; + + default: + printf ("?%d", *(p-1)); + } + } + printf ("/\n"); +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + + printf ("re_nsub: %d\t", bufp->re_nsub); + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %d\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + const char *where; + const char *string1; + const char *string2; + int size1; + int size2; +{ + unsigned this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + printchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + printchar (string2[this_char]); + } +} + +#else /* not DEBUG */ + +#undef assert +#define assert(e) + +#define DEBUG_STATEMENT(e) +#define DEBUG_PRINT1(x) +#define DEBUG_PRINT2(x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; + return ret; +} + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. */ + +static const char *re_error_msg[] = + { NULL, /* REG_NOERROR */ + "No match", /* REG_NOMATCH */ + "Invalid regular expression", /* REG_BADPAT */ + "Invalid collation character", /* REG_ECOLLATE */ + "Invalid character class name", /* REG_ECTYPE */ + "Trailing backslash", /* REG_EESCAPE */ + "Invalid back reference", /* REG_ESUBREG */ + "Unmatched [ or [^", /* REG_EBRACK */ + "Unmatched ( or \\(", /* REG_EPAREN */ + "Unmatched \\{", /* REG_EBRACE */ + "Invalid content of \\{\\}", /* REG_BADBR */ + "Invalid range end", /* REG_ERANGE */ + "Memory exhausted", /* REG_ESPACE */ + "Invalid preceding regular expression", /* REG_BADRPT */ + "Premature end of regular expression", /* REG_EEND */ + "Regular expression too big", /* REG_ESIZE */ + "Unmatched ) or \\)", /* REG_ERPAREN */ + }; + +/* Subroutine declarations and macros for regex_compile. */ + +static void store_op1 (), store_op2 (); +static void insert_op1 (), insert_op2 (); +static boolean at_begline_loc_p (), at_endline_loc_p (); +static boolean group_in_compile_stack (); +static reg_errcode_t compile_range (); + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +#define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = translate[c]; \ + } while (0) + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +#define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d)) + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while (b - bufp->buffer + (n) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (to) - (loc) - 3) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (to) - (loc) - 3, arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (to) - (loc) - 3, b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (to) - (loc) - 3, arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +#define MAX_BUF_SIZE (1L << 16) + + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#define EXTEND_BUFFER() \ + do { \ + unsigned char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +typedef int pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (ISDIGIT (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +#define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + const char *pattern; + int size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register unsigned char c, c1; + + /* A random tempory spot in PATTERN. */ + const char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ + const char *p = pattern; + const char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + char *translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + const char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + printchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined (emacs) && !defined (SYNTAX_TABLE) + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) return REG_ESPACE; + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && zero_times_ok + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); + + /* We've added more stuff to the buffer. */ + b += 3; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; + + if (p == pend) return REG_EBRACK; + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) return REG_EBRACK; + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + return REG_ERANGE; + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) return REG_EBRACK; + + for (;;) + { + PATFETCH (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and:`]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) return REG_EBRACK; + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch)) + || (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch)) + || (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) return REG_EESCAPE; + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + return REG_ERPAREN; + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + return REG_ERPAREN; + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + beg_interval = p - 1; + + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_EBRACE; + } + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') return REG_EBRACE; + + PATFETCH (c); + } + + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + BUF_PUSH (wordbeg); + break; + + case '>': + BUF_PUSH (wordend); + break; + + case 'b': + BUF_PUSH (wordbound); + break; + + case 'B': + BUF_PUSH (notwordbound); + break; + + case '`': + BUF_PUSH (begbuf); + break; + + case '\'': + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + return REG_ESUBREG; + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + return REG_EPAREN; + + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: "); + print_compiled_pattern (bufp); + } +#endif /* DEBUG */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + const char *pattern, *p; + reg_syntax_t syntax; +{ + const char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + const char *p, *pend; + int syntax; +{ + const char *next = p; + boolean next_backslash = *next == '\\'; + const char *next_next = p + 1 < pend ? p + 1 : NULL; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + + +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +compile_range (p_ptr, pend, translate, syntax, b) + const char **p_ptr, *pend; + char *translate; + reg_syntax_t syntax; + unsigned char *b; +{ + unsigned this_char; + + const char *p = *p_ptr; + int range_start, range_end; + + if (p == pend) + return REG_ERANGE; + + /* Even though the pattern is a signed `char *', we need to fetch + with unsigned char *'s; if the high bit of the pattern character + is set, the range endpoints will be negative if we fetch using a + signed char *. + + We also want to fetch the endpoints without translating them; the + appropriate translation is done in the bit-setting loop below. */ + range_start = ((unsigned char *) p)[-2]; + range_end = ((unsigned char *) p)[0]; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* If the start is after the end, the range is empty. */ + if (range_start > range_end) + return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- the range is inclusive, so if `range_end' == 0xff + (assuming 8-bit characters), we would otherwise go into an infinite + loop, since all characters <= 0xff. */ + for (this_char = range_start; this_char <= range_end; this_char++) + { + SET_LIST_BIT (TRANSLATE (this_char)); + } + + return REG_NOERROR; +} + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +#define INIT_FAILURE_ALLOC 5 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_SPACE each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ +int re_max_failures = 2000; + +typedef const unsigned char *fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} fail_stack_type; + +#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) +#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) + + +/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */ + +#define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE requires `destination' be declared. */ + +#define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ + ? 0 \ + : ((fail_stack).stack = (fail_stack_elt_t *) \ + REGEX_REALLOCATE ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push PATTERN_OP on FAIL_STACK. + + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +#define PUSH_PATTERN_OP(pattern_op, fail_stack) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (fail_stack)) \ + ? 0 \ + : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \ + 1)) + +/* This pushes an item onto the failure stack. Must be a four-byte + value. Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ITEM(item) \ + fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item + +/* The complement operation. Assumes `fail_stack' is nonempty. */ +#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +#ifdef DEBUG +#define DEBUG_PUSH PUSH_FAILURE_ITEM +#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM () +#else +#define DEBUG_PUSH(item) +#define DEBUG_POP(item_addr) +#endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be + declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + int this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + PUSH_FAILURE_ITEM (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + PUSH_FAILURE_ITEM (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ + PUSH_FAILURE_ITEM (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\ + PUSH_FAILURE_ITEM (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_ITEM (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_ITEM (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +/* This is the number of items that are pushed and popped on the stack + for each register. */ +#define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +#ifdef DEBUG +#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +#else +#define NUM_NONREG_ITEMS 4 +#endif + +/* We push at most this many items on the stack. */ +#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +#define NUM_FAILURE_ITEMS \ + ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \ + int this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_ITEM (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string 0x%x: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \ + \ + low_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \ + \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + } \ + \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + int j, k; + fail_stack_type fail_stack; +#ifndef REGEX_MALLOC + char *destination; +#endif + /* We don't push any register information onto the failure stack. */ + unsigned num_regs = 0; + + register char *fastmap = bufp->fastmap; + unsigned char *pattern = bufp->buffer; + unsigned long size = bufp->used; + const unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (p != pend || !FAIL_STACK_EMPTY ()) + { + if (p == pend) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail]; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + return 0; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + fastmap[p[1]] = 1; + break; + + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + + + case anychar: + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = 0; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + return 0; + + /* Otherwise, have to check alternative paths. */ + break; + + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* not emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1] == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + return -2; + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += 2; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + return 0; +} /* re_compile_fastmap */ + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t) 0; + } +} + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + register char *fastmap = bufp->fastmap; + register char *translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. */ + if (endpos < -1) + range = -1 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register char c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2 (bufp, string1, size1, string2, size2, + startpos, regs, stop); + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} /* re_search_2 */ + +/* Declarations and macros for re_match_2. */ + +static int bcmp_translate (); +static boolean alt_match_null_string_p (), + common_op_match_null_string_p (), + group_match_null_string_p (); + +/* Structure for per-register (a.k.a. per-group) information. + This must not be longer than one word, because we push this value + onto the failure stack. Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ +typedef union +{ + fail_stack_elt_t word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +#define SET_REGS_MATCHED() \ + do \ + { \ + unsigned r; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + while (0) + + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1) + +/* Registers are set to a sentinel when they haven't yet matched. */ +#define REG_UNSET_VALUE ((char *) -1) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) + + +/* Free everything we malloc. */ +#ifdef REGEX_MALLOC +#define FREE_VAR(var) if (var) free (var); var = NULL +#define FREE_VARIABLES() \ + do { \ + FREE_VAR (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +#else /* not REGEX_MALLOC */ +/* Some MIPS systems (at least) want this to free alloca'd storage. */ +#define FREE_VARIABLES() alloca (0) +#endif /* not REGEX_MALLOC */ + + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; + { + return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); +} +#endif /* not emacs */ + + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + unsigned char *p1; + + /* Just past the end of the corresponding string. */ + const char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const char *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ + unsigned char *p = bufp->buffer; + register unsigned char *pend = p + bufp->used; + + /* We use this to map every character in the string. */ + char *translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ + fail_stack_type fail_stack; +#ifdef DEBUG + static unsigned failure_id = 0; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + unsigned num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; + unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ + const char **regstart, **regend; + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ + const char **old_regstart, **old_regend; + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ + register_info_type *reg_info; + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; + const char **best_regstart, **best_regend; + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const char *match_end = NULL; + + /* Used when we pop values we don't care about. */ + const char **reg_dummy; + register_info_type *reg_info_dummy; + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const char *); + regend = REGEX_TALLOC (num_regs, const char *); + old_regstart = REGEX_TALLOC (num_regs, const char *); + old_regend = REGEX_TALLOC (num_regs, const char *); + best_regstart = REGEX_TALLOC (num_regs, const char *); + best_regend = REGEX_TALLOC (num_regs, const char *); + reg_info = REGEX_TALLOC (num_regs, register_info_type); + reg_dummy = REGEX_TALLOC (num_regs, const char *); + reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } +#ifdef REGEX_MALLOC + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (register_info_type *) NULL; + } +#endif /* REGEX_MALLOC */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } + + DEBUG_PRINT1 ("The compiled pattern is: "); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { + DEBUG_PRINT2 ("\n0x%x: ", p); + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + + /* If exceeds best match so far, save it. */ + if (!best_regs_set + || (same_str_p && d > match_end) + || (!same_str_p && !MATCHING_IN_FIRST_STRING)) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + } + } + else + assert (bufp->regs_allocated == REGS_FIXED); + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 + : d - string2 + size1); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + FREE_VARIABLES (); + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + return mcnt; + } + + /* Otherwise match next pattern command. */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); + if (translate[(unsigned char) *d++] != (char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (char) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; + break; + + + case charset: + case charset_not: + { + register unsigned char c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ + + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || (re_opcode_t) p[-3] == start_memory) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += 2; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < *p + *(p + 1); r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if ((int) old_regend[r] >= (int) regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + register const char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : bcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register unsigned char *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. */ + while (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; /* Skip over args, too. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; + p1 = p + mcnt; + + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int not = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned char) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + } + p -= 2; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + unsigned dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + + /* Unconditionally jump (without popping any failure points). */ + case jump: + unconditional_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ + DEBUG_PRINT2 ("(to 0x%x).\n", p); + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (0, 0, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (0, 0, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); + } + else if (mcnt == 0) + { + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); + p[2] = (unsigned char) no_op; + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); + STORE_NUMBER (p1, mcnt); + break; + } + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + break; + goto fail; + +#ifdef emacs +#ifdef emacs19 + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; +#else /* not emacs19 */ + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) + goto fail; + break; +#endif /* not emacs19 */ + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); + + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + boolean ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate[*p1++] != translate[*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + int length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = regex_compile (pattern, length, re_syntax_options, bufp); + + return re_error_msg[(int) ret]; +} + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them if this is an Emacs or POSIX compilation. */ + +#if !defined (emacs) && !defined (_POSIX_SOURCE) + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return "Memory exhausted"; + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + /* Yes, we're discarding `const' here. */ + return (char *) re_error_msg[(int) ret]; +} + + +int +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} +#endif /* not emacs and not _POSIX_SOURCE */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' and `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *preg; + const char *pattern; + int cflags; +{ + reg_errcode_t ret; + unsigned syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + + /* Don't bother to use a fastmap when searching. This simplifies the + REG_NEWLINE case: if we used a fastmap, we'd have to put all the + characters after newlines into the fastmap. This way, we just try + every character. */ + preg->fastmap = 0; + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate = (char *) malloc (CHAR_SET_SIZE); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? tolower (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + return (int) ret; +} + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *preg; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch, regoff_t); + regs.end = TALLOC (nmatch, regoff_t); + if (regs.start == NULL || regs.end == NULL) + return (int) REG_NOMATCH; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + free (regs.end); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = re_error_msg[errcode]; + + /* POSIX doesn't require that we do anything in this case, but why + not be nice. */ + if (! msg) + msg = "Success"; + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { + strncpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + } + else + strcpy (errbuf, msg); + } + + return msg_size; +} + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} + +#endif /* not emacs */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/compat/regex.h b/compat/regex.h new file mode 100644 index 0000000000..408dd21034 --- /dev/null +++ b/compat/regex.h @@ -0,0 +1,490 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + + Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __REGEXP_LIBRARY_H__ +#define __REGEXP_LIBRARY_H__ + +/* POSIX says that must be included (by the caller) before + . */ + +#ifdef VMS +/* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ +#include +#endif + + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS (1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS 0 + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS + replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +#undef RE_DUP_MAX +#endif +#define RE_DUP_MAX ((1 << 15) - 1) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + unsigned long allocated; + + /* Number of bytes actually used in `buffer'. */ + unsigned long used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + char *translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + + /* If true, an anchor at a newline matches. */ + unsigned newline_anchor : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + + +/* search.c (search_buffer) in Emacs needs this one opcode value. It is + defined both in `regex.c' and here. */ +#define RE_EXACTN_VALUE 1 + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +#define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +#if __STDC__ + +#define _RE_ARGS(args) args + +#else /* not __STDC__ */ + +#define _RE_ARGS(args) () + +#endif /* not __STDC__ */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern + _RE_ARGS ((const char *pattern, int length, + struct re_pattern_buffer *buffer)); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern int re_search + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, struct re_registers *regs)); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern int re_search_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern int re_match + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs)); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern int re_match_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers + _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *ends)); + +/* 4.2 bsd compatibility. */ +extern char *re_comp _RE_ARGS ((const char *)); +extern int re_exec _RE_ARGS ((const char *)); + +/* POSIX compatibility. */ +extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); +extern int regexec + _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags)); +extern size_t regerror + _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, + size_t errbuf_size)); +extern void regfree _RE_ARGS ((regex_t *preg)); + +#endif /* not __REGEXP_LIBRARY_H__ */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ From 3724812944c65714216ecdb87835835cf12f8870 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 1 Mar 2007 15:00:20 +0100 Subject: [PATCH 097/781] Better contrast of text and background of selected lines. The color -selectbackground is commonly dark, but so is the text (black). -highlightbackground is a bit lighter, hence, it offers better contrast in the selected entries while the selected entry still clearly stands out from the other entries. Signed-off-by: Johannes Sixt --- gitk | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gitk b/gitk index 8ffc10a9e5..3909445d8a 100755 --- a/gitk +++ b/gitk @@ -667,7 +667,7 @@ proc makewindow {} { pack .bright.sb -side right -fill y pack $cflist -side left -fill both -expand 1 $cflist tag configure highlight \ - -background [$cflist cget -selectbackground] + -background [$cflist cget -highlightbackground] $cflist tag configure bold -font [concat $mainfont bold] .pwbottom add .bright @@ -1755,7 +1755,7 @@ proc bolden {row font} { $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv cget -selectbackground]] + -fill [$canv cget -highlightbackground]] $canv lower $t } } @@ -1769,7 +1769,7 @@ proc bolden_name {row font} { $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv2 cget -selectbackground]] + -fill [$canv2 cget -highlightbackground]] $canv2 lower $t } } @@ -3885,15 +3885,15 @@ proc selectline {l isnew} { if {![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ - -tags secsel -fill [$canv cget -selectbackground]] + -tags secsel -fill [$canv cget -highlightbackground]] $canv lower $t $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ - -tags secsel -fill [$canv2 cget -selectbackground]] + -tags secsel -fill [$canv2 cget -highlightbackground]] $canv2 lower $t $canv3 delete secsel set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ - -tags secsel -fill [$canv3 cget -selectbackground]] + -tags secsel -fill [$canv3 cget -highlightbackground]] $canv3 lower $t if {$isnew} { From a352bda010a148d563a40a939ded2c5f9e558af9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 1 Mar 2007 16:02:23 +0100 Subject: [PATCH 098/781] Increase the pipe buffer size. It commonly happens that git-fetch-pack and git-upload-pack hit a deadlock in the initial commit id exchange, such that both try to write to the other end, but do not succeed. I have the suspicion that the reason is that both ends fill the pipe, but don't read. Increasing the pipe buffer helps, but is this the real cure? --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index dbc13f0c8a..9222626d28 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -106,7 +106,7 @@ int pipe(int filedes[2]) int fd; HANDLE h[2], parent; - if (_pipe(filedes, 4096, 0) < 0) + if (_pipe(filedes, 8192, 0) < 0) return -1; parent = GetCurrentProcess(); From f16b0ec3bdf089d94ca7dac4f8da95b9154abbff Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Mar 2007 10:05:27 +0100 Subject: [PATCH 099/781] Let the fake readlink(2) and symlink(2) functions report ENOSYS. Now that some symbolic link support is coming soon, let those functions report a more correct error than EINVAL or EFAULT. --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9222626d28..595c9956e1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -7,13 +7,13 @@ unsigned int _CRT_fmode = _O_BINARY; int readlink(const char *path, char *buf, size_t bufsiz) { - errno = EINVAL; + errno = ENOSYS; return -1; } int symlink(const char *oldpath, const char *newpath) { - errno = EFAULT; + errno = ENOSYS; return -1; } From 3f6ad348ef80bb1143ac4ee27a7f16a9491f0e23 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Mar 2007 10:10:31 +0100 Subject: [PATCH 100/781] Provide the missing S_ISLNK and S_IFLNK macros. Even though the file systems on Windows do not support symbolic links, repositories can still contain information about symbolic links, which is interrogated at many occasions. Without the correct definitions S_ISLNK and S_IFLNK, symbolic link information in the repository is not recognized and treated as corruption. --- git-compat-util.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 8d444e8c5a..09bebab73d 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -298,8 +298,8 @@ static inline int prefixcmp(const char *str, const char *prefix) // MinGW #ifndef S_ISLNK -#define S_ISLNK(x) 0 -#define S_IFLNK 0 +#define S_IFLNK 0120000 /* Symbolic link */ +#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #endif #ifndef S_ISGRP From a1f4d20db83ed1bf24b0030e3f81dab497a1e00a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Mar 2007 15:27:32 +0100 Subject: [PATCH 101/781] Update README.MinGW: regex is now included; spaces in MSYS path are OK --- README.MinGW | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.MinGW b/README.MinGW index a8ad34bc4b..bf3b4648a0 100644 --- a/README.MinGW +++ b/README.MinGW @@ -26,17 +26,8 @@ In order to compile this code you need: - additional libraries: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz - regex-0.12.tar.gz (from the GNU site) - compile this into regex.o, ar it into libregex.a - and install it in /mingw/lib, include file into - /mingw/include tcltk-8.4.1-1.exe (for gitk, git-gui) -It is absolutely necessary that you install MSYS in a path that does not -contain special characters, like spaces. I have it in - - D:\MSYS\1.0 - D:\MSYS\1.0\mingw STATUS ------ From fa807fcb28e11e38ef25ec78494001b50e1caeec Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 12 Jan 2007 14:10:50 +0100 Subject: [PATCH 102/781] Revert "Makefile: remove $foo when $foo.exe is built/installed." This reverts commit 6fc301bbf68decbda369402a11ef215391bdd533. Appearently, MSYS's shell returns success for -f foo if foo.exe exists. Hence, this patch removes *all* .exe files - not quite what we want. --- Makefile | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 637ac3ed94..8fa827d879 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # The default target of this Makefile is... -all:: +all: # Define NO_OPENSSL environment variable if you do not have OpenSSL. # This also implies MOZILLA_SHA1. @@ -657,12 +657,9 @@ export prefix gitexecdir TAR INSTALL DESTDIR SHELL_PATH template_dir ### Build rules -all:: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi -ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$p';) -endif +all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi -all:: +all: $(MAKE) -C git-gui all $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all $(MAKE) -C templates NOEXECTEMPL='$(NOEXECTEMPL)' @@ -907,9 +904,6 @@ install: all '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) -ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) -endif install-doc: $(MAKE) -C Documentation install From 8217e459b13d79c1114828a0fc947f705f3e59cc Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Mar 2007 13:45:58 +0100 Subject: [PATCH 103/781] Make open(2) a macro that it replaces "/dev/null" by "nul" on MinGW. --- git-compat-util.h | 4 ++++ run-command.c | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 0d62dc8149..bf9dbe288a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -397,6 +397,10 @@ static inline int git_unlink(const char *pathname) { } #define unlink git_unlink +#define open(P, F, M...) \ + (__builtin_constant_p(*(P)) && !strcmp(P, "/dev/null") ? \ + open("nul", F, ## M) : open(P, F, ## M)) + #include struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); diff --git a/run-command.c b/run-command.c index 79ca6cc9df..0dcbcd2b8a 100644 --- a/run-command.c +++ b/run-command.c @@ -10,11 +10,7 @@ int run_command_v_opt(const char **argv, int flags) int fd_o[2] = { -1, -1 }; if (flags & RUN_COMMAND_NO_STDIN) { -#ifndef __MINGW32__ fd_i[0] = open("/dev/null", O_RDWR); -#else - fd_i[0] = open("nul", O_RDWR); -#endif } if (flags & RUN_COMMAND_STDOUT_TO_STDERR) fd_o[1] = dup(2); From 1d102315e550757a13d6a283223073182c358805 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Mar 2007 15:25:39 +0100 Subject: [PATCH 104/781] Adjust git diff invocation in t3100 since git diff is used instead of diff. --- t/t3100-ls-tree-restrict.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index e3da8508f4..8ca1a8a1d5 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -23,15 +23,9 @@ test "$no_symlinks" && { test "$1" = -s && shift date > "$2" } - DIFF=$(which diff) function diff () { - opt= - if test "$1" = -u; then - opt="$1" - shift - fi sed s/^120000/100644/ < "$1" > "$1".doof - $DIFF $opt "$1".doof "$2" + git diff "$1".doof "$2" } } @@ -53,7 +47,7 @@ _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" test_output () { sed -e "s/ $_x40 / X /" check - git diff expected check + diff expected check } test_expect_success \ From 520c945240da7dc74c5d04d6fa81bab42dcea38f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Mar 2007 19:51:16 +0100 Subject: [PATCH 105/781] Reindent run-command.c to bring it closer to the upstream version. Let's hope that this simplifies merging a bit. --- run-command.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/run-command.c b/run-command.c index 0dcbcd2b8a..00deab0264 100644 --- a/run-command.c +++ b/run-command.c @@ -9,16 +9,17 @@ int run_command_v_opt(const char **argv, int flags) int fd_i[2] = { -1, -1 }; int fd_o[2] = { -1, -1 }; - if (flags & RUN_COMMAND_NO_STDIN) { - fd_i[0] = open("/dev/null", O_RDWR); - } - if (flags & RUN_COMMAND_STDOUT_TO_STDERR) - fd_o[1] = dup(2); - - if (flags & RUN_GIT_CMD) { - pid = spawnv_git_cmd(argv, fd_i, fd_o); - } else { - pid = spawnvpe_pipe(argv[0], argv, environ, fd_i, fd_o); + { + if (flags & RUN_COMMAND_NO_STDIN) { + fd_i[0] = open("/dev/null", O_RDWR); + } + if (flags & RUN_COMMAND_STDOUT_TO_STDERR) + fd_o[1] = dup(2); + if (flags & RUN_GIT_CMD) { + pid = spawnv_git_cmd(argv, fd_i, fd_o); + } else { + pid = spawnvpe_pipe(argv[0], argv, environ, fd_i, fd_o); + } } if (pid < 0) return -ERR_RUN_COMMAND_FORK; From 69fdfa18b55fdf5a2245473ef01c656d4bced269 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Mar 2007 10:58:53 +0100 Subject: [PATCH 106/781] Work around missing stat(1) command. MinGW does not have the stat command. Use ls -l to find out the size of a file. --- t/t5300-pack-object.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index b985bc5db5..48c38cfb4d 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -26,6 +26,12 @@ corrupt() ) < $1 > $2 } +test "$no_symlinks" && { + stat() { + ls -l "$3" | tr -s ' ' ' ' | cut -d' ' -f5 + } +} + test_expect_success \ 'setup' \ 'rm -f .git/index* From bff909b88259160b50823f277ea8c1426e4f7aa0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Mar 2007 13:25:02 +0100 Subject: [PATCH 107/781] Protect {tree} from being expanded by the shell. Some shells seem to treat {tree} as the instruction to brace-expand the word even if the resulting word is not a valid file. During this process the braces {} are lost. To avoid this, the opening brace is escaped. --- t/t5515-fetch-merge-logic.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 6c9cc67508..59f65e60ac 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -20,7 +20,7 @@ test_expect_success setup ' git add file && git commit -a -m One && git tag tag-one && - git tag tag-one-tree HEAD^{tree} && + git-tag tag-one-tree HEAD^\{tree} && git branch one && echo two >> file && @@ -31,7 +31,7 @@ test_expect_success setup ' echo three >> file && git commit -a -m Three && git tag -a -m "Tag Three" tag-three && - git tag -a -m "Tag Three file" tag-three-file HEAD^{tree}:file && + git-tag -a -m "Tag Three file" tag-three-file HEAD^\{tree}:file && git branch three && echo master >> file && From 6b943f171b24e6eb2bf3827554d2536410ed7fe8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Mar 2007 10:57:05 +0100 Subject: [PATCH 108/781] Fix PRIuMAX definition for MinGW. Since MinGW calls into Microsoft's MSVCRT.DLL, it must use the printf format that this DLL uses for 64bit integers, which is %I64u instead of %llu. --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index bf9dbe288a..428f171379 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -74,7 +74,11 @@ #endif #ifndef PRIuMAX +#ifndef __MINGW32__ #define PRIuMAX "llu" +#else +#define PRIuMAX "I64u" +#endif #endif #ifdef __GNUC__ From c65b79715c07b588880c1b462cbabe980b162b78 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 13:23:22 +0100 Subject: [PATCH 109/781] Avoid Windows's find by using the full path of /usr/bin/find. --- git-clone.sh | 6 +++--- git-ls-remote.sh | 2 +- git-repack.sh | 2 +- t/t0000-basic.sh | 6 +++--- t/t1200-tutorial.sh | 2 +- t/t2001-checkout-cache-clash.sh | 2 +- t/t3100-ls-tree-restrict.sh | 2 +- t/t3101-ls-tree-dirname.sh | 2 +- t/t4112-apply-renames.sh | 2 +- t/t5000-tar-tree.sh | 14 +++++++------- t/t5300-pack-object.sh | 6 +++--- t/t9200-git-cvsexportcommit.sh | 2 +- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 513b574d13..1cbc2f5858 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -224,7 +224,7 @@ yes,yes) no) # See if we can hardlink and drop "l" if not. sample_file=$(cd "$repo" && \ - find objects -type f -print | sed -e 1q) + /usr/bin/find objects -type f -print | sed -e 1q) # objects directory should not be empty since we are cloning! test -f "$repo/$sample_file" || exit @@ -236,7 +236,7 @@ yes,yes) fi && rm -f "$GIT_DIR/objects/sample" && cd "$repo" && - find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 + /usr/bin/find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 ;; yes) mkdir -p "$GIT_DIR/objects/info" @@ -354,7 +354,7 @@ then ( test -f "$GIT_DIR/$remote_top/master" && echo "master" cd "$GIT_DIR/$remote_top" && - find . -type f -print | sed -e 's/^\.\///' + /usr/bin/find . -type f -print | sed -e 's/^\.\///' ) | ( done=f while read name diff --git a/git-ls-remote.sh b/git-ls-remote.sh index a6ed99a7c5..145fc38c79 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -79,7 +79,7 @@ rsync://* ) head=$(cat "$tmpdir/$head") || exit esac && echo "$head HEAD" - (cd $tmpdir && find refs -type f) | + (cd $tmpdir && /usr/bin/find refs -type f) | while read path do cat "$tmpdir/$path" | tr -d '\012' diff --git a/git-repack.sh b/git-repack.sh index ddfa8b44a1..bf0bdcf4ff 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -46,7 +46,7 @@ case ",$all_into_one," in ;; ,t,) if [ -d "$PACKDIR" ]; then - for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \ + for e in `cd "$PACKDIR" && /usr/bin/find . -type f -name '*.pack' \ | sed -e 's/^\.\///' -e 's/\.pack$//'` do if [ -e "$PACKDIR/$e.keep" ]; then diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 81ec70ff93..66898afc4f 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -50,14 +50,14 @@ test "$no_symlinks" && { # git-init has been done in an empty repository. # make sure it is empty. -find .git/objects -type f -print >should-be-empty +/usr/bin/find .git/objects -type f -print >should-be-empty test_expect_success \ '.git/objects should be empty after git-init in an empty repo.' \ 'cmp -s /dev/null should-be-empty' # also it should have 2 subdirectories; no fan-out anymore, pack, and info. # 3 is counting "objects" itself -find .git/objects -type d -print >full-of-directories +/usr/bin/find .git/objects -type d -print >full-of-directories test_expect_success \ '.git/objects should have 3 subdirectories.' \ 'test $(wc -l < full-of-directories) = 3' @@ -112,7 +112,7 @@ do done test_expect_success \ 'adding various types of objects with git-update-index --add.' \ - 'find path* ! -type d -print | xargs git-update-index --add' + '/usr/bin/find path* ! -type d -print | xargs git-update-index --add' # Show them and see that matches what we expect. test_expect_success \ diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index ca2c30f7af..97bf4dc517 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -156,7 +156,7 @@ test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.outp test_expect_success 'git repack' 'git repack' test_expect_success 'git prune-packed' 'git prune-packed' -test_expect_failure '-> only packed objects' 'find -type f .git/objects/[0-9a-f][0-9a-f]' +test_expect_failure '-> only packed objects' '/usr/bin/find -type f .git/objects/[0-9a-f][0-9a-f]' test_done diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index 825119b01c..05c2262466 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -23,7 +23,7 @@ the symlink path1 and create directory path1 and file path1/file1. show_files() { # show filesystem files, just [-dl] for type and name - find path? -ls | + /usr/bin/find path? -ls | sed -e 's/^[0-9]* * [0-9]* * \([-bcdl]\)[^ ]* *[0-9]* *[^ ]* *[^ ]* *[0-9]* [A-Z][a-z][a-z] [0-9][0-9] [^ ]* /fs: \1 /' # what's in the cache, just mode and name git-ls-files --stage | diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 8ca1a8a1d5..40501798d1 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -38,7 +38,7 @@ test_expect_success \ echo Lo >path2/foo && ln -s ../path1 path2/bazbo && echo Mi >path2/baz/b && - find path? \( -type f -o -type l \) -print | + /usr/bin/find path? \( -type f -o -type l \) -print | xargs git-update-index --add && tree=`git-write-tree` && echo $tree' diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh index 087929a4bf..eb3df85eff 100755 --- a/t/t3101-ls-tree-dirname.sh +++ b/t/t3101-ls-tree-dirname.sh @@ -34,7 +34,7 @@ test_expect_success \ mkdir path3 && echo 111 >path3/1.txt && echo 222 >path3/2.txt && - find *.txt path* \( -type f -o -type l \) -print | + /usr/bin/find *.txt path* \( -type f -o -type l \) -print | xargs git-update-index --add && tree=`git-write-tree` && echo $tree' diff --git a/t/t4112-apply-renames.sh b/t/t4112-apply-renames.sh index 69e9603c78..bfcb8821c8 100755 --- a/t/t4112-apply-renames.sh +++ b/t/t4112-apply-renames.sh @@ -115,7 +115,7 @@ rename to include/arch/m32r/klibc/archsetjmp.h +#endif /* _KLIBC_ARCHSETJMP_H */ EOF -find klibc -type f -print | xargs git-update-index --add -- +/usr/bin/find klibc -type f -print | xargs git-update-index --add -- test_expect_success 'check rename/copy patch' 'git-apply --check patch' diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index b00acafce0..f46ea1542e 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -45,12 +45,12 @@ test_expect_success \ (p=long_path_to_a_file && cd a && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && echo text >file_with_long_path) && - (cd a && find .) | sort >a.lst' + (cd a && /usr/bin/find .) | sort >a.lst' test_expect_success \ 'add files to repository' \ - 'find a -type f | xargs git-update-index --add && - find a -type l | xargs git-update-index --add && + '/usr/bin/find a -type f | xargs git-update-index --add && + /usr/bin/find a -type l | xargs git-update-index --add && treeid=`git-write-tree` && echo $treeid >treeid && git-update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ @@ -79,7 +79,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd b/a && find .) | sort >b.lst && + '(cd b/a && /usr/bin/find .) | sort >b.lst && diff a.lst b.lst' test_expect_success \ @@ -96,7 +96,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd c/prefix/a && find .) | sort >c.lst && + '(cd c/prefix/a && /usr/bin/find .) | sort >c.lst && diff a.lst c.lst' test_expect_success \ @@ -113,7 +113,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd d/a && find .) | sort >d.lst && + '(cd d/a && /usr/bin/find .) | sort >d.lst && diff a.lst d.lst' test_expect_success \ @@ -130,7 +130,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd e/prefix/a && find .) | sort >e.lst && + '(cd e/prefix/a && /usr/bin/find .) | sort >e.lst && diff a.lst e.lst' test_expect_success \ diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index aafb976a75..c1d34de954 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -75,7 +75,7 @@ cd "$TRASH/.git2" test_expect_success \ 'check unpack without delta' \ - '(cd ../.git && find objects -type f -print) | + '(cd ../.git && /usr/bin/find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -105,7 +105,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with REF_DELTA' \ - '(cd ../.git && find objects -type f -print) | + '(cd ../.git && /usr/bin/find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -135,7 +135,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with OFS_DELTA' \ - '(cd ../.git && find objects -type f -print) | + '(cd ../.git && /usr/bin/find objects -type f -print) | while read path do cmp $path ../.git/$path || { diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 4efa0c926c..e91b5a8437 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -174,7 +174,7 @@ test_expect_success \ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" && mkdir -p "tst/$p" && date >"tst/$p/day" && - found=$(find tst -type f -print) && + found=$(/usr/bin/find tst -type f -print) && test "z$found" = "ztst/$p/day" && rm -fr tst then From 70db4398cd3f4fb96b6100a28677d4f21116f19a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jan 2007 18:15:58 +0100 Subject: [PATCH 110/781] Avoid Windows's sort by using the full path of /usr/bin/sort. --- check-builtins.sh | 2 +- generate-cmdlist.sh | 2 +- git-ls-remote.sh | 2 +- git-mergetool.sh | 4 +-- git-tag.sh | 2 +- t/t0000-basic.sh | 2 +- t/t5000-tar-tree.sh | 10 +++---- t/t6003-rev-list-topo-order.sh | 2 +- t/t9107-git-svn-migrate.sh | 2 +- t/t9200-git-cvsexportcommit.sh | 50 +++++++++++++++++----------------- 10 files changed, 39 insertions(+), 39 deletions(-) diff --git a/check-builtins.sh b/check-builtins.sh index d6fe6cf174..cd09309838 100755 --- a/check-builtins.sh +++ b/check-builtins.sh @@ -9,7 +9,7 @@ EOF } | make -f - sayIt 2>/dev/null | sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p' | -sort | +/usr/bin/sort | { bad=0 while read builtin diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index 975777f05e..a0a938aa08 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -9,7 +9,7 @@ struct cmdname_help struct cmdname_help common_cmds[] = {" -sort <<\EOF | +/usr/bin/sort <<\EOF | add apply archive diff --git a/git-ls-remote.sh b/git-ls-remote.sh index 145fc38c79..7bc2ab884f 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -98,7 +98,7 @@ rsync://* ) fi ;; esac | -sort -t ' ' -k 2 | +/usr/bin/sort -t ' ' -k 2 | while read sha1 path do case "$sha1" in diff --git a/git-mergetool.sh b/git-mergetool.sh index e62351bcba..7d1df52ac7 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -344,13 +344,13 @@ case "$merge_tool" in esac if test $# -eq 0 ; then - files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u` + files=`git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u` if test -z "$files" ; then echo "No files need merging" exit 0 fi echo Merging the files: $files - git ls-files -u | sed -e 's/^[^ ]* //' | sort -u | while read i + git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u | while read i do printf "\n" merge_file "$i" < /dev/tty > /dev/tty diff --git a/git-tag.sh b/git-tag.sh index 4a0a7b6607..47d7c0bb16 100755 --- a/git-tag.sh +++ b/git-tag.sh @@ -32,7 +32,7 @@ do set x . ;; esac shift - git rev-parse --symbolic --tags | sort | grep "$@" + git rev-parse --symbolic --tags | /usr/bin/sort | grep "$@" exit $? ;; -m) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 66898afc4f..534cad51c8 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -289,7 +289,7 @@ test_expect_success \ 'commit2=$(echo NO | git-commit-tree $P -p $commit0 -p $commit0) && parent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | - sort -u) && + /usr/bin/sort -u) && test "z$commit0" = "z$parent" && numparent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index f46ea1542e..766ac165c2 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -45,7 +45,7 @@ test_expect_success \ (p=long_path_to_a_file && cd a && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && echo text >file_with_long_path) && - (cd a && /usr/bin/find .) | sort >a.lst' + (cd a && /usr/bin/find .) | /usr/bin/sort >a.lst' test_expect_success \ 'add files to repository' \ @@ -79,7 +79,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd b/a && /usr/bin/find .) | sort >b.lst && + '(cd b/a && /usr/bin/find .) | /usr/bin/sort >b.lst && diff a.lst b.lst' test_expect_success \ @@ -96,7 +96,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd c/prefix/a && /usr/bin/find .) | sort >c.lst && + '(cd c/prefix/a && /usr/bin/find .) | /usr/bin/sort >c.lst && diff a.lst c.lst' test_expect_success \ @@ -113,7 +113,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd d/a && /usr/bin/find .) | sort >d.lst && + '(cd d/a && /usr/bin/find .) | /usr/bin/sort >d.lst && diff a.lst d.lst' test_expect_success \ @@ -130,7 +130,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd e/prefix/a && /usr/bin/find .) | sort >e.lst && + '(cd e/prefix/a && /usr/bin/find .) | /usr/bin/sort >e.lst && diff a.lst e.lst' test_expect_success \ diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index d99a9ad39e..cbf46dec42 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -10,7 +10,7 @@ test_description='Tests git-rev-list --topo-order functionality' list_duplicates() { - "$@" | sort | uniq -d + "$@" | /usr/bin/sort | uniq -d } date >path0 diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index dc2afdaa45..2665b57de9 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -65,7 +65,7 @@ test_expect_success 'multi-fetch works on partial urls + paths' " for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do git rev-parse --verify refs/remotes/\$i^0 >> refs.out || exit 1; done && - test -z \"\`sort < refs.out | uniq -d\`\" && + test -z \"\`/usr/bin/sort < refs.out | uniq -d\`\" && for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do for j in trunk a b tags/0.1 tags/0.2 tags/0.3; do if test \$j != \$i; then continue; fi diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index e91b5a8437..8e5722245d 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -43,10 +43,10 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.1/" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "newfile2.txt/1.1/" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "newfile3.png/1.1/-kb" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.1/" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "newfile2.txt/1.1/" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "newfile3.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.1/-kb" && diff A/newfile1.txt ../A/newfile1.txt && diff B/newfile2.txt ../B/newfile2.txt && diff C/newfile3.png ../C/newfile3.png && @@ -67,12 +67,12 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.2/-kb" && - test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && - test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.2/-kb" && + test "$(echo $(/usr/bin/sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && + test "$(echo $(/usr/bin/sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && diff A/newfile1.txt ../A/newfile1.txt && diff D/newfile4.png ../D/newfile4.png && diff E/newfile5.txt ../E/newfile5.txt && @@ -115,12 +115,12 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && - test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && + test "$(echo $(/usr/bin/sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && diff A/newfile1.txt ../A/newfile1.txt && diff E/newfile5.txt ../E/newfile5.txt && diff F/newfile6.png ../F/newfile6.png @@ -133,12 +133,12 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git cvsexportcommit -c $id && - test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && - test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && - test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && + test "$(echo $(/usr/bin/sort A/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" && + test "$(echo $(/usr/bin/sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" && + test "$(echo $(/usr/bin/sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" && diff E/newfile5.txt ../E/newfile5.txt && diff F/newfile6.png ../F/newfile6.png )' @@ -154,7 +154,7 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git-cvsexportcommit -c $id && - test "$(echo $(sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.1/-kb with spaces.txt/1.1/" + test "$(echo $(/usr/bin/sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.1/-kb with spaces.txt/1.1/" )' test_expect_success \ @@ -166,7 +166,7 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git-cvsexportcommit -c $id - test "$(echo $(sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.2/-kb with spaces.txt/1.2/" + test "$(echo $(/usr/bin/sort "G g/CVS/Entries"|cut -d/ -f2,3,5))" = "with spaces.png/1.2/-kb with spaces.txt/1.2/" )' # Some filesystems mangle pathnames with UTF-8 characters -- @@ -191,7 +191,7 @@ test_expect_success \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && git-cvsexportcommit -v -c $id && - test "$(echo $(sort Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/CVS/Entries|cut -d/ -f2,3,5))" = "gårdetsågårdet.png/1.1/-kb gårdetsågårdet.txt/1.1/" + test "$(echo $(/usr/bin/sortsort Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/CVS/Entries|cut -d/ -f2,3,5))" = "gårdetsågårdet.png/1.1/-kb gårdetsågårdet.txt/1.1/" )' fi From e479ea2f911b8c70a269ba59372a4fef90f8907c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 11 Apr 2007 15:26:08 +0200 Subject: [PATCH 111/781] Turn builtin_exec_path into a function. builtin_exec_path returns the hard-coded installation path, which is used as the ultimate fallback to look for git commands. Making it into a function enables us to return a computed value instead of just a constant string. --- exec_cmd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 4e8125aab8..946a62c9e5 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -5,9 +5,13 @@ #define MAX_ARGS 32 extern char **environ; -static const char *builtin_exec_path = GIT_EXEC_PATH; static const char *current_exec_path; +static const char *builtin_exec_path(void) +{ + return GIT_EXEC_PATH; +} + void git_set_exec_path(const char *exec_path) { current_exec_path = exec_path; @@ -27,7 +31,7 @@ const char *git_exec_path(void) return env; } - return builtin_exec_path; + return builtin_exec_path(); } @@ -37,7 +41,7 @@ int execv_git_cmd(const char **argv) int i; const char *paths[] = { current_exec_path, getenv(EXEC_PATH_ENVIRONMENT), - builtin_exec_path }; + builtin_exec_path() }; for (i = 0; i < ARRAY_SIZE(paths); ++i) { size_t len; @@ -146,7 +150,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) pid_t pid; const char *paths[] = { current_exec_path, getenv(EXEC_PATH_ENVIRONMENT), - builtin_exec_path }; + builtin_exec_path() }; char p[3][PATH_MAX + 1]; char *usedpaths[4], **up = usedpaths; const char *tmp; From 00a4ff4f3f8ec7e6b3ac15456f00b22b03f438ae Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 11 Apr 2007 16:02:45 +0200 Subject: [PATCH 112/781] Compute the ultimate fallback for exec_path from the program invocation. Since on Windows the user is fairly free where to install programs, we cannot rely on a hard-coded path. We use the program name to derive the installation directory and use that as exec_path. The possiblity to have just the git wrapper in the PATH and let it invoke the toolset is sacrificed. --- exec_cmd.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/exec_cmd.c b/exec_cmd.c index 946a62c9e5..a9886b87fd 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,7 +9,36 @@ static const char *current_exec_path; static const char *builtin_exec_path(void) { +#ifndef __MINGW32__ return GIT_EXEC_PATH; +#else + int len; + char *p, *q, *sl; + static char *ep; + if (ep) + return ep; + + len = strlen(_pgmptr); + if (len < 2) + return ep = "."; + + p = ep = xmalloc(len+1); + q = _pgmptr; + sl = NULL; + /* copy program name, turn '\\' into '/', skip last part */ + while ((*p = *q)) { + if (*q == '\\' || *q == '/') { + *p = '/'; + sl = p; + } + p++, q++; + } + if (sl) + *sl = '\0'; + else + ep[0] = '.', ep[1] = '\0'; + return ep; +#endif } void git_set_exec_path(const char *exec_path) From 5cebf637374fdaa59c27f3732d3df140a23a7b59 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 12 Apr 2007 15:00:53 +0200 Subject: [PATCH 113/781] Turn backslashes in path specifiers into forward-slashes. --- setup.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/setup.c b/setup.c index b6a1c299a3..a66f479944 100644 --- a/setup.c +++ b/setup.c @@ -1,8 +1,15 @@ #include "cache.h" +#ifdef __MINGW32__ +static inline int is_dir_sep(char c) { return c == '/' || c == '\\'; } +#else +static inline int is_dir_sep(char c) { return c == '/'; } +#endif + const char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; + int do_pfx; for (;;) { char c; if (*path != '.') @@ -14,7 +21,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) break; } /* "./" */ - if (c == '/') { + if (is_dir_sep(c)) { path += 2; continue; } @@ -23,7 +30,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) c = path[2]; if (!c) path += 2; - else if (c == '/') + else if (is_dir_sep(c)) path += 3; else break; @@ -33,15 +40,31 @@ const char *prefix_path(const char *prefix, int len, const char *path) if (!len) die("'%s' is outside repository", orig); len--; - } while (len && prefix[len-1] != '/'); + } while (len && !is_dir_sep(prefix[len-1])); continue; } - if (len) { + do_pfx = len; +#ifdef __MINGW32__ + /* we want to convert '\' in path to '/' (prefix already has '/') */ + { + const char *p = path; + while (!do_pfx && *p) { + do_pfx = *p++ == '\\'; + } + } +#endif + if (do_pfx) { int speclen = strlen(path); char *n = xmalloc(speclen + len + 1); + char *p; memcpy(n, prefix, len); memcpy(n + len, path, speclen+1); +#ifdef __MINGW32__ + for (p = n + len; *p; p++) + if (*p == '\\') + *p = '/'; +#endif path = n; } return path; @@ -55,10 +78,24 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; +#ifndef __MINGW32__ if (!pfx || !*pfx || arg[0] == '/') return arg; +#else + char *p; + /* don't add prefix to absolute paths */ + const int is_absolute = + is_dir_sep(arg[0]) || + (arg[0] && arg[1] == ':' && is_dir_sep(arg[2])); + if (is_absolute) + pfx_len = 0; + else +#endif memcpy(path, pfx, pfx_len); strcpy(path + pfx_len, arg); + for (p = path + pfx_len; *p; p++) + if (*p == '\\') + *p = '/'; return path; } From 5009b5450d9b15293199d5c0131cccefc8a3df72 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 12 Apr 2007 13:46:23 +0200 Subject: [PATCH 114/781] Revert "git-gui: Don't create empty (same tree as parent) commits." This reverts commit 51bd9d7b8cf29e0e441531fb0a671cc7093f278b. It introduced a git invocation that involves ^{tree}. It seems that MSYS's wish does some quoting for Bourne shells, in particular, escape the first '{', but then it uses cmd.exe to run the command, which does not remove the backslash, so that the resulting ref expression ends up in git's guts as unrecognizable garbage. --- git-gui/git-gui.sh | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 60e79ca1b0..5e901b5ecc 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1269,24 +1269,6 @@ proc commit_committree {fd_wt curHEAD msg} { return } - # -- Verify this wasn't an empty change. - # - if {$commit_type eq {normal}} { - set old_tree [git rev-parse "$PARENT^{tree}"] - if {$tree_id eq $old_tree} { - info_popup {No changes to commit. - -No files were modified by this commit and it -was not a merge commit. - -A rescan will be automatically started now. -} - unlock_index - rescan {set ui_status_value {No changes to commit.}} - return - } - } - # -- Build the message. # set msg_p [gitdir COMMIT_EDITMSG] From 390b6df11cc5359679227fe29a6d251b042a3ed7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 13 Apr 2007 09:53:43 +0200 Subject: [PATCH 115/781] Quote the script name before invoking the interpreter. When the argument vector for the interpreter invocation is assembled, the original arguments were already quoted when necessary, but the script name was not. If the script lives in a directory whose names contains spaces, the interpreter would not find the script. --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 595c9956e1..14fabcbbc0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -279,7 +279,7 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) for (n = 0; argv[n];) n++; sh_argv = xmalloc((n+2)*sizeof(char*)); sh_argv[0] = interpr; - sh_argv[1] = cmd; + sh_argv[1] = quote_arg(cmd); quote_argv(&sh_argv[2], &argv[1]); n = spawnvpe(_P_WAIT, interpr, sh_argv, env); if (n == -1) From b953c77a5b55ff3b453c3500fbb42d97950fd8b4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Apr 2007 18:34:03 +0200 Subject: [PATCH 116/781] Allow a relative builtin template directory. In order to make git relocatable (i.e. not have the prefix compiled-in) the template directory must depend on the location where this git instance is found, which is GIT_EXEC_DIR. The exec path is prepended only to the compiled-in default directory if it is relative. Any relative directories that are specified via environment variable or the --exec-dir switch are taken as is. Signed-off-by: Johannes Sixt --- builtin-init-db.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 4df9fd0fad..ecf3db954a 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -130,10 +130,19 @@ static void copy_templates(const char *git_dir, int len, const char *template_di int template_len; DIR *dir; - if (!template_dir) { + if (!template_dir) template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); - if (!template_dir) - template_dir = DEFAULT_GIT_TEMPLATE_DIR; + if (!template_dir) { + /* + * if the hard-coded template is relative, it is + * interpreted relative to the exec_dir + */ + template_dir = DEFAULT_GIT_TEMPLATE_DIR; + if (template_dir[0] != '/' && template_dir[1] != ':') { + const char *exec_path = git_exec_path(); + template_dir = prefix_path(exec_path, strlen(exec_path), + template_dir); + } } strcpy(template_path, template_dir); template_len = strlen(template_path); From 2d84ffaf0da5f8ab0143b30cce254d7e6ea1e7a4 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Apr 2007 18:36:01 +0200 Subject: [PATCH 117/781] MinGW uses a relative default template_dir. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 87979807fb..5510ebac7b 100644 --- a/Makefile +++ b/Makefile @@ -455,6 +455,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec + template_dir = ../share/git-core/templates/ endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From 6433ce0f9648e5cce13defd83338e7b8e19b8d1b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Apr 2007 18:47:45 +0200 Subject: [PATCH 118/781] Mention bash 3.1 as requirement on MinGW. Signed-off-by: Johannes Sixt --- README.MinGW | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.MinGW b/README.MinGW index bf3b4648a0..89b7065aac 100644 --- a/README.MinGW +++ b/README.MinGW @@ -23,6 +23,7 @@ In order to compile this code you need: mingw32-make-3.80.0-3.tar.gz unzip-5.51-1-bin.zip (this is not from MinGW, iirc) msysDTK-1.0.1.exe (contains ssh, perl) + bash-3.1-MSYS-1.0.11-snapshot.tar.bz2 - additional libraries: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz @@ -57,3 +58,11 @@ Caveats (aka bugs): implemented *very* simplistic: It just watches out for whitespace and double quote `"' characters. This may become a problem if you have exotic characters in your file names. + +- It seems that MSYS's default bash, 2.05b, has a bug that breaks git-am + (and, hence, git-rebase). If you see this error: + + Patch is empty. Was is split wrong? + + you need bash 3.1: Just unpack bash-3.1*.tar.bz2 and copy its bash.exe + over $MSYS/bin/sh.exe. From d17b18abecd04a8fcb4682c5ca5e5b851aa8e6ce Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 20 May 2007 21:25:49 +0200 Subject: [PATCH 119/781] Make mingw branch compile on Linux again --- Makefile | 4 ++-- git-compat-util.h | 22 ++++++++++++++-------- setup.c | 2 +- spawn-pipe.c | 5 ++++- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 1470f29a7d..a85f7102fc 100644 --- a/Makefile +++ b/Makefile @@ -209,8 +209,7 @@ SCRIPT_SH = \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ git-merge-resolve.sh git-merge-ours.sh \ - git-lost-found.sh git-quiltimport.sh \ - cpio.sh + git-lost-found.sh git-quiltimport.sh SCRIPT_PERL = \ git-add--interactive.perl \ @@ -504,6 +503,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) X = .exe NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ + SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease diff --git a/git-compat-util.h b/git-compat-util.h index f88f851941..7ae57d6019 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -48,16 +48,20 @@ #include #include #include -//#include #include -//#include -//#include -//#include +#ifndef __MINGW32__ +#include +#include +#include +#include +#endif #include #include -//#include -//#include -//#include +#ifndef __MINGW32__ +#include +#include +#include +#endif #ifndef NO_ETC_PASSWD #include #include @@ -345,7 +349,7 @@ static inline int strtoul_ui(char const *s, int base, unsigned int *result) return 0; } -// MinGW +#ifdef __MINGW32__ #ifndef S_ISLNK #define S_IFLNK 0120000 /* Symbolic link */ @@ -459,4 +463,6 @@ int mingw_socket(int domain, int type, int protocol); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +#endif /* __MINGW32__ */ + #endif diff --git a/setup.c b/setup.c index a66f479944..a2903b9573 100644 --- a/setup.c +++ b/setup.c @@ -78,11 +78,11 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; + char *p; #ifndef __MINGW32__ if (!pfx || !*pfx || arg[0] == '/') return arg; #else - char *p; /* don't add prefix to absolute paths */ const int is_absolute = is_dir_sep(arg[0]) || diff --git a/spawn-pipe.c b/spawn-pipe.c index 7d8aa7d6c7..c8f0452823 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -106,12 +106,15 @@ static char *path_lookup(const char *cmd, char **path) int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) { +#ifdef __MINGW32__ char **path = get_path_split(); pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); free_path_split(path); - +#else + pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); +#endif return pid; } From 312749fc466b79984901fbf94c890a388c597e97 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 May 2007 19:37:30 +0200 Subject: [PATCH 120/781] Fix 'make install' of the repository templates. In 2d84ffaf0da5f8ab0143b30cce254d7e6ea1e7a4 the path to the template directory was modified to be relative. However, since this setting is passed down to templates/Makefile, it installed the templates in the build directory. This works around the problem by not allowing the installation directory to be overridable. --- templates/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/Makefile b/templates/Makefile index a55edcc202..a4e7075caa 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -7,7 +7,7 @@ endif INSTALL ?= install TAR ?= tar prefix ?= $(HOME) -template_dir ?= $(prefix)/share/git-core/templates/ +template_dir = $(prefix)/share/git-core/templates/ # DESTDIR= # set NOEXECTEMPL to non-empty to change the names of hook scripts # so that the tools will not find them From a37c540e0efd1509127587faa6a201e338a0f016 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 May 2007 19:33:19 +0200 Subject: [PATCH 121/781] Avoid an error message due to the lack of the 'sync' command. --- git-repack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-repack.sh b/git-repack.sh index bf0bdcf4ff..acb78ba86b 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -99,7 +99,7 @@ then # We know $existing are all redundant. if [ -n "$existing" ] then - sync + sync 2> /dev/null ( cd "$PACKDIR" && for e in $existing do From ddb51d3baf427a9c38ae1d297eb07daae338536f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 May 2007 19:19:33 +0200 Subject: [PATCH 122/781] Make the progress indicator work when the total runtime is unknown. In order to allow progress indication when the total runtime is unknown, as well as if the total runtime is so long that the progress indicator stays at the same percentage for more than a second, an update of the indicator is forced every second. On Unix a time signal is received, which forces the update. On Windows we don't have signals. For this reason, a thread is spawned that forces the update every second. --- progress.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/progress.c b/progress.c index 05f7890314..7a8510542f 100644 --- a/progress.c +++ b/progress.c @@ -3,13 +3,26 @@ static volatile sig_atomic_t progress_update; +#ifndef __MINGW32__ static void progress_interval(int signum) { progress_update = 1; } +#else +static HANDLE progress_event; +static HANDLE progress_thread; + +static __stdcall unsigned heartbeat(void *dummy) +{ + while (WaitForSingleObject(progress_event, 1000) == WAIT_TIMEOUT) + progress_update = 1; + return 0; +} +#endif static void set_progress_signal(void) { +#ifndef __MINGW32__ struct sigaction sa; struct itimerval v; @@ -25,13 +38,43 @@ static void set_progress_signal(void) v.it_interval.tv_usec = 0; v.it_value = v.it_interval; setitimer(ITIMER_REAL, &v, NULL); +#else + /* this is just eye candy: errors are not fatal */ + progress_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (progress_event) { + progress_thread = (HANDLE) _beginthreadex(NULL, 0, heartbeat, NULL, 0, NULL); + if (!progress_thread ) + error("cannot create progress indicator"); + } else + error("cannot allocate resources for progress indicator"); +#endif } static void clear_progress_signal(void) { +#ifndef __MINGW32__ struct itimerval v = {{0,},}; setitimer(ITIMER_REAL, &v, NULL); signal(SIGALRM, SIG_IGN); +#else + /* this is just eye candy: errors are not fatal */ + if (progress_event) + SetEvent(progress_event); /* tells thread to terminate */ + if (progress_thread) { + int rc = WaitForSingleObject(progress_thread, 1000); + if (rc == WAIT_TIMEOUT) + error("progress thread did not terminate timely"); + else if (rc != WAIT_OBJECT_0) + error("waiting for progress thread failed: %lu", + GetLastError()); + CloseHandle(progress_thread); + } + if (progress_event) + CloseHandle(progress_event); + progress_event = NULL; + progress_thread = NULL; +#endif + progress_update = 0; } From eba4aff8fec97cbce3bb4ead1ed5e9857ebb95ef Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 09:40:43 +0200 Subject: [PATCH 123/781] Remove now unused dummy functions related to timer signal handling. --- compat/mingw.c | 13 ------------- git-compat-util.h | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 14fabcbbc0..fa6f5f4504 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -51,19 +51,6 @@ int kill(pid_t pid, int sig) { return -1; } -int sigaction(int p1, const struct sigaction *p2, struct sigaction *p3) -{ - return -1; -} -int sigemptyset(sigset_t *p1) -{ - return -1; -} -int setitimer(int __which, const struct itimerval *__value, - struct itimerval *__ovalue) -{ - return -1; -} unsigned int sleep (unsigned int __seconds) { Sleep(__seconds*1000); diff --git a/git-compat-util.h b/git-compat-util.h index 7ae57d6019..515331d0b5 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -416,19 +416,6 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); #define POLLIN 1 #define POLLHUP 2 -typedef int siginfo_t; -struct sigaction { - void (*sa_handler)(int); - void (*sa_sigaction)(int, siginfo_t *, void *); - sigset_t sa_mask; - int sa_flags; - void (*sa_restorer)(void); -}; -#define SA_RESTART 0 -#define ITIMER_REAL 0 - -struct itimerval { struct timeval it_interval, it_value; }; - static inline int git_mkdir(const char *path, int mode) { return mkdir(path); From dafd0c5fece221379cf9f515e58c31dc1e44e339 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 10:54:08 +0200 Subject: [PATCH 124/781] Fix local clone on MinGW: absolute paths must use the drive letter. The default of pwd of MSYS's bash and /bin/pwd are to use /c/rest/of/path notation instead of c:/rest/of/path. But the former is not supported by programs that use the standard C runtime (instead of MinGW's own runtime). Hence, we must make sure that only drive letter notations are generated by using pwd's -W option. --- git-clone.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 8e087a4793..1ff9f2987b 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -19,11 +19,11 @@ usage() { get_repo_base() { ( - cd "`/bin/pwd`" && + cd "`/bin/pwd -W`" && cd "$1" && { cd .git - pwd + pwd -W } ) 2>/dev/null } From afd5e6acb2f7adf6a3dd6049dabcafcd4458a92e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 22:26:41 +0200 Subject: [PATCH 125/781] Accept trailing slashes in lstat() implementation. lstat() is sometimes invoked with a path that ends in a slash (in particular, when dealing with subprojects). Windows's stat() does not accept such paths and fails with ENOENT. In this case we try again with a cleaned-up path. --- compat/mingw.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index fa6f5f4504..ac8b8e0414 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -25,7 +25,27 @@ int fchmod(int fildes, mode_t mode) int lstat(const char *file_name, struct stat *buf) { - return stat(file_name, buf); + int namelen; + static char alt_name[PATH_MAX]; + + if (!stat(file_name, buf)) + return 0; + + /* if file_name ended in a '/', Windows returned ENOENT; + * try again without trailing slashes + */ + if (errno != ENOENT) + return -1; + namelen = strlen(file_name); + if (namelen && file_name[namelen-1] != '/') + return -1; + while (namelen && file_name[namelen-1] == '/') + --namelen; + if (!namelen || namelen >= PATH_MAX) + return -1; + memcpy(alt_name, file_name, namelen); + alt_name[namelen] = 0; + return stat(alt_name, buf); } /* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ From 4694606a42710234433aec3cedfe7cad3d387e25 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 22:28:41 +0200 Subject: [PATCH 126/781] Check TMP and TEMP environment variables in addition to TMPDIR. Windows uses TMP and TEMP, but we still check for TMPDIR, which some scripts may set. --- path.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/path.c b/path.c index ced3a7c586..29570ee52a 100644 --- a/path.c +++ b/path.c @@ -73,7 +73,10 @@ int git_mkstemp(char *path, size_t len, const char *template) { char *env, *pch = path; - if ((env = getenv("TMPDIR")) == NULL) { + if ((env = getenv("TMPDIR")) == NULL && + /* on Windows it is TMP and TEMP */ + (env = getenv("TMP")) == NULL && + (env = getenv("TEMP")) == NULL) { strcpy(pch, "/tmp/"); len -= 5; pch += 5; From 782c4e20196386eafa1dd0d29d09c78ecbc0fbb8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 22:31:11 +0200 Subject: [PATCH 127/781] Skip a test dealing with symbolic links. --- t/t4122-apply-symlink-inside.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh index 3ddfe64b02..9af8bcc9f6 100755 --- a/t/t4122-apply-symlink-inside.sh +++ b/t/t4122-apply-symlink-inside.sh @@ -3,6 +3,13 @@ test_description='apply to deeper directory without getting fooled with symlink' . ./test-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + lecho () { for l_ do From d681388621ce2e32ec1275a9edfea59bb0a4a0cb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 16:02:21 +0200 Subject: [PATCH 128/781] Avoid double-slash in path names that depend on $(sharedir). Recent git-gui has the ability to determine the location of its library files relative to the --exec-dir. Its Makefile enables this capability depending on the install paths that are specified. However, without this fix there is an extra slash in a path specification, so that the Makefile does not recognize the equivalence of two paths that it compares. As a side-effect, this avoids an ugly compiled-in double-slash in $(template_dir). Signed-off-by: Johannes Sixt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1ed09aca00..9592ab7f05 100644 --- a/Makefile +++ b/Makefile @@ -144,7 +144,7 @@ STRIP ?= strip prefix = $(HOME) bindir = $(prefix)/bin gitexecdir = $(bindir) -sharedir = $(prefix)/share/ +sharedir = $(prefix)/share template_dir = $(sharedir)/git-core/templates/ ifeq ($(prefix),/usr) sysconfdir = /etc From 77398b214dc6c9c1ffd169cae821b31405c0cfc7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 19:53:05 +0200 Subject: [PATCH 129/781] Introduce git_etc_gitconfig() that encapsulates access of ETC_GITCONFIG. In a subsequent patch the path to the system-wide config file will be computed. This is a preparation for that change. It turns all accesses of ETC_GITCONFIG into function calls. There is no change in behavior. As a consequence, config.c is the only file that needs the definition of ETC_GITCONFIG. Hence, -DETC_GITCONFIG is removed from the CFLAGS and a special build rule for config.c is introduced. As a side-effect, changing the defintion of ETC_GITCONFIG (e.g. in config.mak) does not trigger a complete rebuild anymore. Signed-off-by: Johannes Sixt --- Makefile | 5 ++++- builtin-config.c | 4 ++-- cache.h | 1 + config.c | 10 ++++++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 9592ab7f05..2b0e5ce536 100644 --- a/Makefile +++ b/Makefile @@ -731,7 +731,7 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) LIBS = $(GITLIBS) $(EXTLIBS) BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ - -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $(COMPAT_CFLAGS) + $(COMPAT_CFLAGS) LIB_OBJS += $(COMPAT_OBJS) ALL_CFLAGS += $(BASIC_CFLAGS) @@ -878,6 +878,9 @@ exec_cmd.o: exec_cmd.c GIT-CFLAGS builtin-init-db.o: builtin-init-db.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< +config.o: config.c GIT-CFLAGS + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $< + http.o: http.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $< diff --git a/builtin-config.c b/builtin-config.c index b2515f7e65..54c9885c32 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -74,7 +74,7 @@ static int get_value(const char* key_, const char* regex_) local = repo_config = xstrdup(git_path("config")); if (home) global = xstrdup(mkpath("%s/.gitconfig", home)); - system_wide = ETC_GITCONFIG; + system_wide = git_etc_gitconfig(); } key = xstrdup(key_); @@ -154,7 +154,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) } } else if (!strcmp(argv[1], "--system")) - setenv("GIT_CONFIG", ETC_GITCONFIG, 1); + setenv("GIT_CONFIG", git_etc_gitconfig(), 1); else if (!strcmp(argv[1], "--rename-section")) { int ret; if (argc != 4) diff --git a/cache.h b/cache.h index a5c8b717dc..6a8534e0aa 100644 --- a/cache.h +++ b/cache.h @@ -507,6 +507,7 @@ extern int git_config_bool(const char *, const char *); extern int git_config_set(const char *, const char *); extern int git_config_set_multivar(const char *, const char *, const char *, int); extern int git_config_rename_section(const char *, const char *); +extern const char *git_etc_gitconfig(void); extern int check_repository_format_version(const char *var, const char *value); #define MAX_GITNAME (1000) diff --git a/config.c b/config.c index 36e76da493..79c32a0338 100644 --- a/config.c +++ b/config.c @@ -6,6 +6,7 @@ * */ #include "cache.h" +#include "exec_cmd.h" #define MAXNAME (256) @@ -392,6 +393,11 @@ int git_config_from_file(config_fn_t fn, const char *filename) return ret; } +const char *git_etc_gitconfig(void) +{ + return ETC_GITCONFIG; +} + int git_config(config_fn_t fn) { int ret = 0; @@ -404,8 +410,8 @@ int git_config(config_fn_t fn) * config file otherwise. */ filename = getenv(CONFIG_ENVIRONMENT); if (!filename) { - if (!access(ETC_GITCONFIG, R_OK)) - ret += git_config_from_file(fn, ETC_GITCONFIG); + if (!access(git_etc_gitconfig(), R_OK)) + ret += git_config_from_file(fn, git_etc_gitconfig()); home = getenv("HOME"); filename = getenv(CONFIG_LOCAL_ENVIRONMENT); if (!filename) From 44bacc53bf8d5e0e7f526f6599ec0b9a9836ebc2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:14:53 +0200 Subject: [PATCH 130/781] Allow ETC_GITCONFIG to be a relative path. If ETC_GITCONFIG is not an absolute path, interpret it relative to --exec-dir. This makes the installed binaries relocatable because the prefix is not compiled-in. Signed-off-by: Johannes Sixt --- config.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index 79c32a0338..1c87e8e3f9 100644 --- a/config.c +++ b/config.c @@ -395,7 +395,17 @@ int git_config_from_file(config_fn_t fn, const char *filename) const char *git_etc_gitconfig(void) { - return ETC_GITCONFIG; + static const char *system_wide; + if (!system_wide) { + system_wide = ETC_GITCONFIG; + /* interpret path relative to exec-dir */ + if (system_wide[0] != '/' && system_wide[1] != ':') { + const char *exec_path = git_exec_path(); + system_wide = prefix_path(exec_path, strlen(exec_path), + system_wide); + } + } + return system_wide; } int git_config(config_fn_t fn) From 2a51de45cfc1270492d757b3bc14943a71ab6232 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:17:10 +0200 Subject: [PATCH 131/781] On MinGW the system-wide config file is a relative path. This is necessary because if the toolset is provided as a setup file, it is customary that the user can choose any location to install to. Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 2b0e5ce536..48fa6a1af2 100644 --- a/Makefile +++ b/Makefile @@ -503,6 +503,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) X = .exe NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ + ETC_GITCONFIG = ../etc/gitconfig SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) From 16c1568546fcb0ba04409d7b32326d66812e63c3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:18:28 +0200 Subject: [PATCH 132/781] Silence a warning about an undeclared git_exec_path(). Pull in its declaration. Signed-off-by: Johannes Sixt --- builtin-init-db.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-init-db.c b/builtin-init-db.c index ecf3db954a..0268ad2905 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -5,6 +5,7 @@ */ #include "cache.h" #include "builtin.h" +#include "exec_cmd.h" #ifndef DEFAULT_GIT_TEMPLATE_DIR #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/" From 24d0e15093c5e1814b28809814579e8c11f89588 Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Mon, 25 Jun 2007 22:43:19 -0400 Subject: [PATCH 133/781] gitk - Make selection highlight color configurable Cygwin's tk by default uses a very dark selection background color that makes the currently selected text almost unreadable. On linux, the default selection background is a light gray which is very usable. This makes the default a light gray everywhere but allows the user to configure the color as well. Signed-off-by: Mark Levedahl --- gitk | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/gitk b/gitk index c09ee9a5e5..b044914c1f 100755 --- a/gitk +++ b/gitk @@ -402,7 +402,7 @@ proc makewindow {} { global rowctxmenu mergemax wrapcomment global highlight_files gdttype global searchstring sstring - global bgcolor fgcolor bglist fglist diffcolors + global bgcolor fgcolor bglist fglist diffcolors selectbgcolor global headctxmenu menu .bar @@ -457,15 +457,18 @@ proc makewindow {} { set cscroll .tf.histframe.csb set canv .tf.histframe.pwclist.canv canvas $canv \ + -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 \ -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll" .tf.histframe.pwclist add $canv set canv2 .tf.histframe.pwclist.canv2 canvas $canv2 \ + -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 -yscrollincr $linespc .tf.histframe.pwclist add $canv2 set canv3 .tf.histframe.pwclist.canv3 canvas $canv3 \ + -selectbackground $selectbgcolor \ -background $bgcolor -bd 0 -yscrollincr $linespc .tf.histframe.pwclist add $canv3 eval .tf.histframe.pwclist sash place 0 $geometry(pwsash0) @@ -666,6 +669,7 @@ proc makewindow {} { set cflist .bright.cfiles set indent [font measure $mainfont "nn"] text $cflist \ + -selectbackground $selectbgcolor \ -background $bgcolor -foreground $fgcolor \ -font $mainfont \ -tabs [list $indent [expr {2 * $indent}]] \ @@ -825,7 +829,7 @@ proc savestuff {w} { global maxwidth showneartags global viewname viewfiles viewargs viewperm nextviewnum global cmitmode wrapcomment - global colors bgcolor fgcolor diffcolors + global colors bgcolor fgcolor diffcolors selectbgcolor if {$stuffsaved} return if {![winfo viewable .]} return @@ -844,6 +848,7 @@ proc savestuff {w} { puts $f [list set fgcolor $fgcolor] puts $f [list set colors $colors] puts $f [list set diffcolors $diffcolors] + puts $f [list set selectbgcolor $selectbgcolor] puts $f "set geometry(main) [wm geometry .]" puts $f "set geometry(topwidth) [winfo width .tf]" @@ -5846,7 +5851,7 @@ proc doquit {} { proc doprefs {} { global maxwidth maxgraphpct diffopts global oldprefs prefstop showneartags - global bgcolor fgcolor ctext diffcolors + global bgcolor fgcolor ctext diffcolors selectbgcolor global uifont set top .gitkprefs @@ -5913,6 +5918,10 @@ proc doprefs {} { "diff hunk header" \ [list $ctext tag conf hunksep -foreground]] grid x $top.hunksepbut $top.hunksep -sticky w + label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor + button $top.selbgbut -text "Select bg" -font optionfont \ + -command [list choosecolor selectbgcolor 0 $top.selbgsep background setselbg] + grid x $top.selbgbut $top.selbgsep -sticky w frame $top.buts button $top.buts.ok -text "OK" -command prefsok -default active @@ -5937,6 +5946,16 @@ proc choosecolor {v vi w x cmd} { eval $cmd $c } +proc setselbg {c} { + global bglist cflist + foreach w $bglist { + $w configure -selectbackground $c + } + $cflist tag configure highlight \ + -background [$cflist cget -selectbackground] + allcanvs itemconf secsel -fill $c +} + proc setbg {c} { global bglist @@ -6293,6 +6312,7 @@ set colors {green red blue magenta darkgrey brown orange} set bgcolor white set fgcolor black set diffcolors {red "#00a000" blue} +set selectbgcolor gray85 catch {source ~/.gitk} From 568785d5b13cdf06bd81b8e161a5405596f44197 Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Mon, 25 Jun 2007 22:43:20 -0400 Subject: [PATCH 134/781] gitk - Update fontsize in patch / tree list When adjusting fontsize (using ctrl+/-), all panes except the lower right were updated. This fixes that. Signed-off-by: Mark Levedahl --- gitk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitk b/gitk index b044914c1f..a7139b4033 100755 --- a/gitk +++ b/gitk @@ -4696,13 +4696,14 @@ proc redisplay {} { } proc incrfont {inc} { - global mainfont textfont ctext canv phase + global mainfont textfont ctext canv phase cflist global stopped entries unmarkmatches set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]] setcoords $ctext conf -font $textfont + $cflist conf -font $textfont $ctext tag conf filesep -font [concat $textfont bold] foreach e $entries { $e conf -font $mainfont From 5eecfa3becc25a6bf5bfc7e3657d77a40cbdd60a Mon Sep 17 00:00:00 2001 From: Mark Levedahl Date: Mon, 25 Jun 2007 22:43:21 -0400 Subject: [PATCH 135/781] gitk - Allow specifying tabstop as other than default 8 characters. Not all projects use the convention that one tabstop = 8 characters, and a common convention is to use one tabstop = on level of indent. For such projects, using 8 characters per tabstop often shows too much whitespace per indent. This allows the user to configure the number of characters to use per tabstop. Signed-off-by: Mark Levedahl --- gitk | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/gitk b/gitk index a7139b4033..1c9c9ccc78 100755 --- a/gitk +++ b/gitk @@ -395,7 +395,7 @@ proc confirm_popup msg { proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist - global textfont mainfont uifont + global textfont mainfont uifont tabstop global findtype findtypemenu findloc findstring fstring geometry global entries sha1entry sha1string sha1but global maincursor textcursor curtextcursor @@ -615,6 +615,7 @@ proc makewindow {} { pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left set ctext .bleft.ctext text $ctext -background $bgcolor -foreground $fgcolor \ + -tabs "[expr {$tabstop * $charspc}]" \ -state disabled -font $textfont \ -yscrollcommand scrolltext -wrap none scrollbar .bleft.sb -command "$ctext yview" @@ -824,7 +825,7 @@ proc click {w} { } proc savestuff {w} { - global canv canv2 canv3 ctext cflist mainfont textfont uifont + global canv canv2 canv3 ctext cflist mainfont textfont uifont tabstop global stuffsaved findmergefiles maxgraphpct global maxwidth showneartags global viewname viewfiles viewargs viewperm nextviewnum @@ -838,6 +839,7 @@ proc savestuff {w} { puts $f [list set mainfont $mainfont] puts $f [list set textfont $textfont] puts $f [list set uifont $uifont] + puts $f [list set tabstop $tabstop] puts $f [list set findmergefiles $findmergefiles] puts $f [list set maxgraphpct $maxgraphpct] puts $f [list set maxwidth $maxwidth] @@ -4697,12 +4699,13 @@ proc redisplay {} { proc incrfont {inc} { global mainfont textfont ctext canv phase cflist + global charspc tabstop global stopped entries unmarkmatches set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]] setcoords - $ctext conf -font $textfont + $ctext conf -font $textfont -tabs "[expr {$tabstop * $charspc}]" $cflist conf -font $textfont $ctext tag conf filesep -font [concat $textfont bold] foreach e $entries { @@ -5853,7 +5856,7 @@ proc doprefs {} { global maxwidth maxgraphpct diffopts global oldprefs prefstop showneartags global bgcolor fgcolor ctext diffcolors selectbgcolor - global uifont + global uifont tabstop set top .gitkprefs set prefstop $top @@ -5891,6 +5894,9 @@ proc doprefs {} { checkbutton $top.ntag.b -variable showneartags pack $top.ntag.b $top.ntag.l -side left grid x $top.ntag -sticky w + label $top.tabstopl -text "tabstop" -font optionfont + spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop + grid x $top.tabstopl $top.tabstop -sticky w label $top.cdisp -text "Colors: press to choose" $top.cdisp configure -font $uifont @@ -5989,9 +5995,11 @@ proc prefscan {} { proc prefsok {} { global maxwidth maxgraphpct global oldprefs prefstop showneartags + global charspc ctext tabstop catch {destroy $prefstop} unset prefstop + $ctext configure -tabs "[expr {$tabstop * $charspc}]" if {$maxwidth != $oldprefs(maxwidth) || $maxgraphpct != $oldprefs(maxgraphpct)} { redisplay @@ -6297,6 +6305,7 @@ if {$tclencoding == {}} { set mainfont {Helvetica 9} set textfont {Courier 9} set uifont {Helvetica 9 bold} +set tabstop 8 set findmergefiles 0 set maxgraphpct 50 set maxwidth 16 From 28edb31439f680718bd678a85ee4e805aa33c0d1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Jun 2007 09:07:17 +0200 Subject: [PATCH 136/781] Revert "Better contrast of text and background of selected lines." This reverts commit 3724812944c65714216ecdb87835835cf12f8870. We have now a better solution by Mark Levedahl, where the highlight color can be configured. --- gitk | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gitk b/gitk index 1c9c9ccc78..513fc2b8c9 100755 --- a/gitk +++ b/gitk @@ -683,7 +683,7 @@ proc makewindow {} { pack .bright.sb -side right -fill y pack $cflist -side left -fill both -expand 1 $cflist tag configure highlight \ - -background [$cflist cget -highlightbackground] + -background [$cflist cget -selectbackground] $cflist tag configure bold -font [concat $mainfont bold] .pwbottom add .bright @@ -1790,7 +1790,7 @@ proc bolden {row font} { $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv cget -highlightbackground]] + -fill [$canv cget -selectbackground]] $canv lower $t } } @@ -1804,7 +1804,7 @@ proc bolden_name {row font} { $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($row)] \ -outline {{}} -tags secsel \ - -fill [$canv2 cget -highlightbackground]] + -fill [$canv2 cget -selectbackground]] $canv2 lower $t } } @@ -3920,15 +3920,15 @@ proc selectline {l isnew} { if {![info exists linehtag($l)]} return $canv delete secsel set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ - -tags secsel -fill [$canv cget -highlightbackground]] + -tags secsel -fill [$canv cget -selectbackground]] $canv lower $t $canv2 delete secsel set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ - -tags secsel -fill [$canv2 cget -highlightbackground]] + -tags secsel -fill [$canv2 cget -selectbackground]] $canv2 lower $t $canv3 delete secsel set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ - -tags secsel -fill [$canv3 cget -highlightbackground]] + -tags secsel -fill [$canv3 cget -selectbackground]] $canv3 lower $t if {$isnew} { From 3ada7967dca3d26f88efcf23dfb7317e1ff603a1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 13 Jul 2007 09:27:40 +0200 Subject: [PATCH 137/781] Disable the new test, which covers only symbolic links. --- t/t2007-checkout-symlink.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh index 0526fce163..0bf1ddb94b 100755 --- a/t/t2007-checkout-symlink.sh +++ b/t/t2007-checkout-symlink.sh @@ -6,6 +6,13 @@ test_description='git checkout to switch between branches with symlink<->dir' . ./test-lib.sh +if test "$no_symlinks" +then + say 'Symbolic links not supported, skipping tests.' + test_done + exit +fi + test_expect_success setup ' mkdir frotz && From 91dd11cb86bed99c4d8332f34cb091946610d5f0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 16:03:46 +0200 Subject: [PATCH 138/781] Disarm .dir and .env support on MinGW. We do not yet support changing the directory of the spawned process (it would require a getwd(), chdir(new), chdir(back) sequence). Even though we can remove environment variables in the spawned process, we cannot yet add new ones. --- run-command.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/run-command.c b/run-command.c index d42aa1074e..5964e7d4dd 100644 --- a/run-command.c +++ b/run-command.c @@ -14,6 +14,7 @@ int start_command(struct child_process *cmd) int need_in, need_out; int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; + char **env = environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -55,21 +56,26 @@ int start_command(struct child_process *cmd) fdout[1] = cmd->out; } + if (cmd->dir) + die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { + if (cmd->git_cmd) + die("modifying environment for git_cmd in start_command() not implemented"); + env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - putenv((char*)*cmd->env); + die("setting environment in start_command() not implemented"); else - unsetenv(*cmd->env); + env_unsetenv(env, *cmd->env); } } if (cmd->git_cmd) { cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, environ, fdin, fdout); + cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); } } if (cmd->pid < 0) { From cef2e2635135ba148e853cacc9076e3595808b73 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 23:16:20 +0200 Subject: [PATCH 139/781] Add a fake S_ISSOCK() macro --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index dfaf5fff31..ddafec997f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -375,6 +375,7 @@ static inline int strtoul_ui(char const *s, int base, unsigned int *result) #ifndef S_ISLNK #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(x) 0 #endif #ifndef S_ISGRP From 2e435b2b21dce07ecd0ee12e148fd8b00345d228 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 23:18:41 +0200 Subject: [PATCH 140/781] Skip tests involving symbolic links. --- t/t3700-add.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t3700-add.sh b/t/t3700-add.sh index b52fde8577..b216a3ae88 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -30,6 +30,7 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac' +test "$no_symlinks" || { test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo1 && ln -s foo xfoo1 && @@ -39,6 +40,7 @@ test_expect_success 'git add: filemode=0 should not get confused by symlink' ' *) echo fail; git ls-files --stage xfoo1; (exit 1);; esac ' +} test_expect_success \ 'git update-index --add: Test that executable bit is not used...' \ @@ -51,6 +53,7 @@ test_expect_success \ *) echo fail; git ls-files --stage xfoo2; (exit 1);; esac' +test "$no_symlinks" || { test_expect_success 'git add: filemode=0 should not get confused by symlink' ' rm -f xfoo2 && ln -s foo xfoo2 && @@ -70,6 +73,7 @@ test_expect_success \ 120000" "*xfoo3) echo ok;; *) echo fail; git ls-files --stage xfoo3; (exit 1);; esac' +} test_expect_success '.gitignore test setup' ' echo "*.ig" >.gitignore && From 0c344bc22906f0e166f01c1b2075ecfba7dac40f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:11:54 +0200 Subject: [PATCH 141/781] Skip some git diff tests if the file system does not support funny names. Signed-off-by: Johannes Sixt --- t/t3902-quoted.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index 63f950b179..e8ad85afe4 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -14,6 +14,13 @@ LF=' ' DQ='"' +echo foo > "Name and an${HT}HT" +test -f "Name and an${HT}HT" || { + # since FAT/NTFS does not allow tabs in filenames, skip this test + say 'Your filesystem does not allow tabs in filenames, test skipped.' + test_done +} + for_each_name () { for name in \ Name "Name and a${LF}LF" "Name and an${HT}HT" "Name${DQ}" \ From 5c52dc4bf0d53c75b473fa60ffafa4e2e961dc55 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:18:36 +0200 Subject: [PATCH 142/781] update-server-info is not supported on MinGW. Skip tests. --- t/t1301-shared-repo.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index bb5f30220a..3bf78ae619 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -14,6 +14,10 @@ test_expect_success 'shared=all' ' test 2 = $(git config core.sharedrepository) ' +say "update-server-info not supported - skipping tests" +test_done +exit 0 + test_expect_success 'update-server-info honors core.sharedRepository' ' : > a1 && git add a1 && From f0ec63a99a4925804eecd69c792e0ee600871b73 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 10 Jun 2007 20:37:42 +0200 Subject: [PATCH 143/781] Install 'core.symlinks false' under MinGW. --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 760b5448be..47b1fdc326 100644 --- a/Makefile +++ b/Makefile @@ -722,6 +722,7 @@ bindir_SQ = $(subst ','\'',$(bindir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) template_dir_SQ = $(subst ','\'',$(template_dir)) prefix_SQ = $(subst ','\'',$(prefix)) +sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) @@ -1001,8 +1002,11 @@ remove-dashes: install: all $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(sysconfdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)' + GIT_CONFIG='$(DESTDIR_SQ)$(sysconfdir_SQ)/gitconfig' \ + $(DESTDIR_SQ)$(bindir_SQ)/git-config$X core.symlinks false $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' install ifndef NO_TCLTK From 631f6e62498bb0439be2718c04a4f5e76baaeec0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 12 Jan 2007 16:41:22 +0100 Subject: [PATCH 144/781] Fake reencoding success under NO_ICONV instead of returning NULL. git-am when invoked from git-rebase seems to rely on successful conversion. --- utf8.c | 7 +++++++ utf8.h | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/utf8.c b/utf8.c index 4efef6faf7..5949b4d2d4 100644 --- a/utf8.c +++ b/utf8.c @@ -353,4 +353,11 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e iconv_close(conv); return out; } +#else +char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding) +{ + if (!in_encoding) + return NULL; + return xstrdup(in); +} #endif diff --git a/utf8.h b/utf8.h index 15db6f1f27..a8b8c2f4da 100644 --- a/utf8.h +++ b/utf8.h @@ -7,10 +7,6 @@ int is_encoding_utf8(const char *name); int print_wrapped_text(const char *text, int indent, int indent2, int len); -#ifndef NO_ICONV char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding); -#else -#define reencode_string(a,b,c) NULL -#endif #endif From f5f46bfe24411ce8b4955df4cc5b2e0d78f0a0c5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 21 Jul 2007 23:21:54 +0200 Subject: [PATCH 145/781] Work around a CR being written by git-tag if it is redirected to a file. Where the heck does this come from? A useless use of cat helps. --- t/t7004-tag.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 17de2a90e6..99b417ada5 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -108,9 +108,9 @@ mytag EOF test_expect_success \ 'trying to delete tags without params should succeed and do nothing' ' - git tag -l > actual && git diff expect actual && + git tag -l | cat > actual && git diff expect actual && git-tag -d && - git tag -l > actual && git diff expect actual + git tag -l | cat > actual && git diff expect actual ' test_expect_success \ @@ -164,7 +164,7 @@ test_expect_success 'listing all tags should print them ordered' ' git tag a1 && git tag v1.0 && git tag t210 && - git tag -l > actual && + git tag -l | cat > actual && git diff expect actual ' From 64e9bd1483cea1fee0dd1b76ee988e20a0b997fb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:19:06 +0200 Subject: [PATCH 146/781] Skip some tests that depend on technology that we have not dealt with. --- t/t3900-i18n-commit.sh | 4 ++++ t/t3901-i18n-patch.sh | 4 ++++ t/t4121-apply-diffs.sh | 2 ++ t/t5100-mailinfo.sh | 4 ++++ t/t5302-pack-index.sh | 2 ++ t/t5502-quickfetch.sh | 3 +++ t/t6023-merge-file.sh | 3 +++ t/t7003-filter-branch.sh | 3 +++ t/t9001-send-email.sh | 4 ++++ t/t9200-git-cvsexportcommit.sh | 4 ++++ t/t9300-fast-import.sh | 4 ++++ 11 files changed, 37 insertions(+) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index fcbabe8ec3..4886d9f37b 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -7,6 +7,10 @@ test_description='commit and log output encodings' . ./test-lib.sh +say "iconv not supported, skipping tests." +test_done +exit 0 + compare_with () { git show -s $1 | sed -e '1,/^$/d' -e 's/^ //' -e '$d' >current && git diff current "$2" diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 28e9e372f3..41e0d42c62 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -7,6 +7,10 @@ test_description='i18n settings and format-patch | am pipe' . ./test-lib.sh +say "iconv not supported, skipping tests." +test_done +exit 0 + check_encoding () { # Make sure characters are not corrupted cnt="$1" header="$2" i=1 j=0 bad=0 diff --git a/t/t4121-apply-diffs.sh b/t/t4121-apply-diffs.sh index aff551a1d7..d93b61d8c4 100755 --- a/t/t4121-apply-diffs.sh +++ b/t/t4121-apply-diffs.sh @@ -3,6 +3,8 @@ test_description='git apply for contextually independent diffs' . ./test-lib.sh +test_done + echo '1 2 3 diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 9b1a74542a..0dcab1fbfe 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -7,6 +7,10 @@ test_description='git mailinfo and git mailsplit test' . ./test-lib.sh +say "git-mailinfo does not work yet; skipping tests." +test_done +exit 0 + test_expect_success 'split sample box' \ 'git mailsplit -o. ../t5100/sample.mbox >last && last=`cat last` && diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 4f58c4c3f9..06b2f38d75 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -59,6 +59,7 @@ test_expect_success \ 'cmp "test-1-${pack1}.idx" "1.idx" && cmp "test-2-${pack2}.idx" "2.idx"' +false && { test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 merge.err && grep "Cannot merge binary files" merge.err diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 4ddd656e84..7ec74172ae 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -3,6 +3,9 @@ test_description='git-filter-branch' . ./test-lib.sh +say "filter-branch has not been taken care of - skipping tests" +test_done + make_commit () { lower=$(echo $1 | tr A-Z a-z) echo $lower > $lower diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index e9ea33c18d..d58fccb522 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -3,6 +3,10 @@ test_description='git-send-email' . ./test-lib.sh +say "cannot invoke fake.sendmail; skipping test" +test_done +exit 0 + PROG='git send-email' test_expect_success \ 'prepare reference tree' \ diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 8e5722245d..f7936e87da 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -6,6 +6,10 @@ test_description='CVS export comit. ' . ./test-lib.sh +say "CVS does not work on MinGW, skipping tests." +test_done +exit 0 + cvs >/dev/null 2>&1 if test $? -ne 1 then diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 4b920be331..902b5f5f7f 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -7,6 +7,10 @@ test_description='test git-fast-import utility' . ./test-lib.sh . ../diff-lib.sh ;# test-lib chdir's into trash +say "git-fast-import has not been taken care of, skipping test." +test_done +exit 0 + file2_data='file2 second line of EOF' From c10900175c37827e1c53a30e07df843b4ac94a8c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:17:16 +0200 Subject: [PATCH 147/781] Work around failures due to bogus quoting of ^ and {}. --- t/t3404-rebase-interactive.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 43a6675caa..48dc6d6b41 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -150,7 +150,7 @@ test_expect_success 'retain authorship' ' test_tick && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && git tag twerp && - git rebase -i --onto master HEAD^ && + git rebase -i --onto master HEAD~1 && git show HEAD | grep "^Author: Twerp Snog" ' @@ -194,7 +194,7 @@ test_expect_success 'preserve merges with -p' ' test_expect_success '--continue tries to commit' ' test_tick && - ! git rebase -i --onto new-branch1 HEAD^ && + ! git rebase -i --onto new-branch1 HEAD~1 && echo resolved > file1 && git add file1 && FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue && @@ -203,9 +203,9 @@ test_expect_success '--continue tries to commit' ' ' test_expect_success 'verbose flag is heeded, even after --continue' ' - git reset --hard HEAD@{1} && + git reset --hard $(git rev-parse HEAD@{1}) && test_tick && - ! git rebase -v -i --onto new-branch1 HEAD^ && + ! git rebase -v -i --onto new-branch1 HEAD~1 && echo resolved > file1 && git add file1 && git rebase --continue > output && From 382210f715c0e1ef7a19eb10977dae4265a2c88f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 14 Feb 2007 15:53:54 +0100 Subject: [PATCH 148/781] Remove the symbolic link to simplify bootstrapping this version. The MinGW port does have partial support for symbolic links now. But in order to allow others who still do not have this version to use their old version on Windows to pull and checkout this version we better drop the symbolic link. --- RelNotes | 1 - 1 file changed, 1 deletion(-) delete mode 120000 RelNotes diff --git a/RelNotes b/RelNotes deleted file mode 120000 index 1f6c16e1dc..0000000000 --- a/RelNotes +++ /dev/null @@ -1 +0,0 @@ -Documentation/RelNotes-1.5.2.4.txt \ No newline at end of file From daf422895c9b00255b5e79be5c1c30bdebcb19a9 Mon Sep 17 00:00:00 2001 From: Nguyen Thai Ngoc Duy Date: Tue, 31 Jul 2007 11:09:48 -0400 Subject: [PATCH 149/781] Mention libiconv as a requirement for git-am --- README.MinGW | 1 + 1 file changed, 1 insertion(+) diff --git a/README.MinGW b/README.MinGW index 89b7065aac..c0b8f66b93 100644 --- a/README.MinGW +++ b/README.MinGW @@ -28,6 +28,7 @@ In order to compile this code you need: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz tcltk-8.4.1-1.exe (for gitk, git-gui) + libiconv-1.9.2-1-{lib,bin}.zip (for git-am, from http://gnuwin32.sourceforge.net/packages/libiconv.htm) STATUS From 2e2f5df3c1433a6f1bd6943dbec1b0b631759499 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 6 Aug 2007 21:39:06 +0200 Subject: [PATCH 150/781] Link with libiconv (1.9.2). --- Makefile | 3 ++- README.MinGW | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 760b5448be..f45f0e6179 100644 --- a/Makefile +++ b/Makefile @@ -482,7 +482,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_UNSETENV=YesPlease NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease - NO_ICONV=YesPlease + NEEDS_LIBICONV = YesPlease + OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_SYMLINKS=YesPlease diff --git a/README.MinGW b/README.MinGW index c0b8f66b93..436d7b7849 100644 --- a/README.MinGW +++ b/README.MinGW @@ -28,7 +28,8 @@ In order to compile this code you need: zlib-1.2.3-mingwPORT-1.tar w32api-3.6.tar.gz tcltk-8.4.1-1.exe (for gitk, git-gui) - libiconv-1.9.2-1-{lib,bin}.zip (for git-am, from http://gnuwin32.sourceforge.net/packages/libiconv.htm) + libiconv-1.9.2-1-{lib,bin,lib}.zip (for git-am, + from http://gnuwin32.sourceforge.net/packages/libiconv.htm) STATUS From 2d5d2c84f18762a50ddc843b560b2b0b53ee1426 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 22:54:41 +0100 Subject: [PATCH 151/781] Fix inifinite loop In setup_git_directory_gently(), there is a hack to allow for stopping the search at the drive letter. Only that the patch was incomplete; we really have to stop there, instead of looping infinitely. Signed-off-by: Johannes Schindelin --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index a1aa5a3076..e921013926 100644 --- a/setup.c +++ b/setup.c @@ -260,7 +260,7 @@ const char *setup_git_directory_gently(int *nongit_ok) for (;;) { if (is_git_directory(".git")) break; - if (offset == 0) { + if (offset == minoffset) { offset = -1; break; } From bf788d7e65eeaebb65ddb330c32aac0d7bd5e325 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 22:31:42 +0100 Subject: [PATCH 152/781] Makefile: be nice when running in a path containing spaces Without this patch, GIT-VERSION-GEN is not able to run. Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 47b1fdc326..d42734aeef 100644 --- a/Makefile +++ b/Makefile @@ -124,7 +124,7 @@ all: # GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE - @$(SHELL_PATH) ./GIT-VERSION-GEN + @"$(SHELL_PATH)" ./GIT-VERSION-GEN -include GIT-VERSION-FILE uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') From 70cff4144391c83bdac5c98c99642d29181aa67a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 23:01:57 +0100 Subject: [PATCH 153/781] Fix some compiler settings/paths for MinGW It seems that you have to jump through hoops to make trivial things such as "install.exe" do the right thing on Windows... Also, it seems that Windows Vista deliberately broke "access()". Apparently, they used that name in their runtime, but that function does something completely different than POSIX access(). So define __USE_MINGW_ACCESS to work around that. Signed-off-by: Johannes Schindelin --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d42734aeef..85df9a5c67 100644 --- a/Makefile +++ b/Makefile @@ -176,7 +176,7 @@ CC = gcc AR = ar RM = rm -f TAR = tar -INSTALL = install +INSTALL = /bin/install RPMBUILD = rpmbuild TCL_PATH = tclsh TCLTK_PATH = wish @@ -373,7 +373,7 @@ BUILTIN_OBJS = \ builtin-pack-refs.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) -EXTLIBS = -lz +EXTLIBS = /mingw/lib/libz.a # # Platform specific tweaks @@ -488,7 +488,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From 7999f434d70dd1c4849c874d1767b24fb77a33df Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 23:12:03 +0100 Subject: [PATCH 154/781] For the time being, set prefix= On MinGW, we want to install git in /bin. Signed-off-by: Johannes Schindelin --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 85df9a5c67..24bf460a1d 100644 --- a/Makefile +++ b/Makefile @@ -493,8 +493,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig + prefix = SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) From 0e2bdc35afa484b521b7af2e74ad661b732d92eb Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Fri, 3 Aug 2007 19:27:53 -0400 Subject: [PATCH 155/781] Add and use expat and curl to enable http://. The expat build was added and the pieces of curl that seemed missing. The default NO_CURL was removed so that curl is used by default. Signed-off-by: Mike Pape --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24bf460a1d..4103eca01b 100644 --- a/Makefile +++ b/Makefile @@ -474,7 +474,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease - NO_CURL=YesPlease NO_SYMLINK_HEAD=YesPlease NO_IPV6=YesPlease NO_ETC_PASSWD=YesPlease @@ -488,6 +487,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease + NO_R_TO_GCC_LINKER = YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 From ef5af72062ef0e0c0b5d8a7a3dda89b0609050bc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 4 Aug 2007 15:28:24 +0100 Subject: [PATCH 156/781] Minimal changes to allow for GIT_TRACE=/trace.txt (is_absolute_path()) This imitates what is currently in git.git's master: a function to determine if a path is absolute. msysgit.git is not really the proper place to fix this, but Hannes is still on holiday. Signed-off-by: Johannes Schindelin --- cache.h | 4 ++++ trace.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cache.h b/cache.h index e0a5f6decd..91e9f7109f 100644 --- a/cache.h +++ b/cache.h @@ -359,6 +359,10 @@ int git_config_perm(const char *var, const char *value); int adjust_shared_perm(const char *path); int safe_create_leading_directories(char *path); char *enter_repo(char *path, int strict); +static inline int is_absolute_path(const char *path) +{ + return path[0] == '/' || (isalpha(path[0]) && path[1] == ':'); +} /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/trace.c b/trace.c index 7961a27a2e..344066e88b 100644 --- a/trace.c +++ b/trace.c @@ -64,7 +64,7 @@ static int get_trace_fd(int *need_close) return STDERR_FILENO; if (strlen(trace) == 1 && isdigit(*trace)) return atoi(trace); - if (*trace == '/') { + if (is_absolute_path(trace)) { int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd == -1) { fprintf(stderr, From 4a66a6c4c236827c3ea89c75f908bf8019b3758c Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Sat, 4 Aug 2007 04:38:13 -0700 Subject: [PATCH 157/781] Correctly test for absolute path This fix (while correct) actually avoids another nasty bug that must be fixed later: environment.c caches results of many getenv calls. Under MinGW setenv(X) invalidates all previous values returned by getenv(X) so cached values become dangling pointers. Signed-off-by: Dmitry Kakurin Signed-off-by: Johannes Schindelin --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index e921013926..4d14541bcc 100644 --- a/setup.c +++ b/setup.c @@ -332,7 +332,7 @@ const char *setup_git_directory_gently(int *nongit_ok) * In case there is a work tree we may change the directory, * therefore make GIT_DIR an absolute path. */ - if (gitdirenv[0] != '/') { + if (!is_absolute_path(gitdirenv)) { setenv(GIT_DIR_ENVIRONMENT, gitdir, 1); gitdirenv = getenv(GIT_DIR_ENVIRONMENT); if (!gitdirenv) From 13e33743145fced9306fc7594bc84514fbd5883c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 5 Aug 2007 05:49:59 +0100 Subject: [PATCH 158/781] Trace ssh connections when GIT_TRACE is set This is really a patch for mingw.git. Signed-off-by: Johannes Schindelin --- rsh.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rsh.c b/rsh.c index 5754a230e2..9bb03d12c6 100644 --- a/rsh.c +++ b/rsh.c @@ -71,6 +71,8 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, ssh_basename = ssh; else ssh_basename++; + trace_printf("Calling '%s' '%s' '%s' '%s'\n", + ssh, ssh_basename, host, command); close(sv[1]); dup2(sv[0], 0); dup2(sv[0], 1); From 60096146d67d408837b80c6b720bee722f35cf72 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 6 Aug 2007 16:49:51 +0100 Subject: [PATCH 159/781] Work around MinGW mangling of "host:/path" The common way to specify an ssh remote is to say "host:/path", but MinGW decides for us that this is probably a path list, and path lists are separated by a semicolon on Windows. So before passing this to git-peek-remote.exe, it transforms that to "host;C:/msysGit/path". Avoid that by expanding it to "ssh://host/path", but take extra care not to convert absolute paths to that syntax! Signed-off-by: Johannes Schindelin --- git-parse-remote.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100755 => 100644 git-parse-remote.sh diff --git a/git-parse-remote.sh b/git-parse-remote.sh old mode 100755 new mode 100644 index 695a4094bb..7c0d242eec --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -51,7 +51,8 @@ get_remote_url () { ;; *) die "internal error: get-remote-url $1" ;; - esac + esac | sed "s|^\(.[^:][^:]*\):\(/[^/]\)|ssh://\1\2|" + # work around MinGW path mangling } get_default_remote () { From 3d9012418c93b5e5f0ada041e1fc071cac48cbfa Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Mon, 6 Aug 2007 16:11:19 -0400 Subject: [PATCH 160/781] Added is_dev_null check because Windows /dev/null is nul. This function should be called to test for /dev/null when nul on Windows can also be accepted. The is_dev_null function in builtin-apply.c was renamed. Signed-off-by: Mike Pape --- builtin-apply.c | 8 ++++---- cache.h | 9 +++++++++ diff-lib.c | 6 +++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index 0a0b4a9e3f..f8cde7f3f5 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -222,7 +222,7 @@ static unsigned long linelen(const char *buffer, unsigned long size) return len; } -static int is_dev_null(const char *str) +static int is_dev_null_line(const char *str) { return !memcmp("/dev/null", str, 9) && isspace(str[9]); } @@ -333,7 +333,7 @@ static int guess_p_value(const char *nameline) char *name, *cp; int val = -1; - if (is_dev_null(nameline)) + if (is_dev_null_line(nameline)) return -1; name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB); if (!name) @@ -381,12 +381,12 @@ static void parse_traditional_patch(const char *first, const char *second, struc p_value_known = 1; } } - if (is_dev_null(first)) { + if (is_dev_null_line(first)) { patch->is_new = 1; patch->is_delete = 0; name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB); patch->new_name = name; - } else if (is_dev_null(second)) { + } else if (is_dev_null_line(second)) { patch->is_new = 0; patch->is_delete = 1; name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB); diff --git a/cache.h b/cache.h index 91e9f7109f..f13e1b74a1 100644 --- a/cache.h +++ b/cache.h @@ -364,6 +364,15 @@ static inline int is_absolute_path(const char *path) return path[0] == '/' || (isalpha(path[0]) && path[1] == ':'); } +static inline int is_dev_null(const char *str) +{ +#ifdef __MINGW32__ + if (!strcmp(str, "nul")) + return 1; +#endif + return !strcmp(str, "/dev/null"); +} + /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size); diff --git a/diff-lib.c b/diff-lib.c index 92c0e39ad6..9a424621ed 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -34,7 +34,7 @@ static int get_mode(const char *path, int *mode) { struct stat st; - if (!path || !strcmp(path, "/dev/null")) + if (!path || is_dev_null(path)) *mode = 0; else if (!strcmp(path, "-")) *mode = ntohl(create_ce_mode(0666)); @@ -229,6 +229,10 @@ static int is_outside_repo(const char *path, int nongit, const char *prefix) int i; if (nongit || !strcmp(path, "-") || path[0] == '/') return 1; +#ifdef __MINGW32__ + if (!strcmp(path, "nul")) + return 1; +#endif if (prefixcmp(path, "../")) return 0; if (!prefix) From f1e1dc5119bd9862bb4d2a975c8ca6362ea43af5 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Tue, 7 Aug 2007 07:58:08 +0200 Subject: [PATCH 161/781] Use builtin config function when installing. As the symlink for git-config is not set up yet at this point, we use the builtin instead. Signed-off-by: Marius Storm-Olsen --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4103eca01b..2f83c432bc 100644 --- a/Makefile +++ b/Makefile @@ -1005,7 +1005,7 @@ install: all $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)' GIT_CONFIG='$(DESTDIR_SQ)$(sysconfdir_SQ)/gitconfig' \ - $(DESTDIR_SQ)$(bindir_SQ)/git-config$X core.symlinks false + $(DESTDIR_SQ)$(bindir_SQ)/git$X config core.symlinks false $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' install ifndef NO_TCLTK From 8ca1f6af8c343172ca885076b8e581137ac05faf Mon Sep 17 00:00:00 2001 From: Julian Phillips Date: Tue, 17 Jul 2007 22:14:06 +0100 Subject: [PATCH 162/781] git-gui: Handle git versions of the form n.n.n.GIT The git-gui version check doesn't handle versions of the form n.n.n.GIT which you can get by installing from an tarball produced by git-archive. Without this change you get an error of the form: 'Error in startup script: expected version number but got "1.5.3.GIT"' Signed-off-by: Julian Phillips Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 2077261e64..f8b1f10187 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -546,6 +546,7 @@ if {![regsub {^git version } $_git_version {} _git_version]} { } regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version regsub {\.rc[0-9]+$} $_git_version {} _git_version +regsub {\.GIT$} $_git_version {} _git_version proc git-version {args} { global _git_version From 637fc51696dc067c006b1651689b2f0aac26ec04 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 20:50:42 +0200 Subject: [PATCH 163/781] Implement is_absolute_path() on Windows. To keep the brief, we don't check that there must be a letter before the colon and a slash or backslash after the colon - we just assume that we don't have to work with drive-relative paths. --- cache.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cache.h b/cache.h index d9598bb685..a701139fd8 100644 --- a/cache.h +++ b/cache.h @@ -364,7 +364,11 @@ int safe_create_leading_directories(char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { +#ifndef __MINGW32__ return path[0] == '/'; +#else + return path[0] == '/' || (path[0] && path[1] == ':'); +#endif } const char *make_absolute_path(const char *path); From ab793ce23595a1d7b4891646dc5d9a04af720211 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 22:24:03 +0200 Subject: [PATCH 164/781] Work around misbehaved rename() on Windows. Windows's rename() is based on the MoveFile() API, which fails if the destination exists. Here we work around the problem by using MoveFileEx(). Furthermore, the posixly correct error is returned if the destination is a directory. The implementation is still slightly incomplete, however, because of the missing error code translation: We assume that the failure is due to permissions. --- builtin-reflog.c | 6 ------ compat/mingw.c | 25 +++++++++++++++++++++++++ git-compat-util.h | 3 +++ lockfile.c | 1 - refs.c | 10 ---------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/builtin-reflog.c b/builtin-reflog.c index 27e251ff6d..ce093cad78 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -269,12 +269,6 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, if (fclose(cb.newlog)) status |= error("%s: %s", strerror(errno), newlog_path); -#ifdef __MINGW32__ - /* rename fails if the destination exists */ - if (unlink(log_file)) - status |= error("cannot remove %s", log_file); - else -#endif if (rename(newlog_path, log_file)) { status |= error("cannot rename %s to %s", newlog_path, log_file); diff --git a/compat/mingw.c b/compat/mingw.c index ac8b8e0414..7711a3fb39 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -322,3 +322,28 @@ int mingw_socket(int domain, int type, int protocol) } return s; } + +#undef rename +int mingw_rename(const char *pold, const char *pnew) +{ + /* + * Try native rename() first to get errno right. + * It is based on MoveFile(), which cannot overwrite existing files. + */ + if (!rename(pold, pnew)) + return 0; + if (errno != EEXIST) + return -1; + if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + return 0; + /* TODO: translate more errors */ + if (GetLastError() == ERROR_ACCESS_DENIED) { + struct stat st; + if (!stat(pnew, &st) && S_ISDIR(st.st_mode)) { + errno = EISDIR; + return -1; + } + } + errno = EACCES; + return -1; +} diff --git a/git-compat-util.h b/git-compat-util.h index ddafec997f..98ad78d571 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -466,6 +466,9 @@ char *mingw_getcwd(char *pointer, int len); int mingw_socket(int domain, int type, int protocol); #define socket mingw_socket +int mingw_rename(const char*, const char*); +#define rename mingw_rename + #define setlinebuf(x) #define fsync(x) 0 diff --git a/lockfile.c b/lockfile.c index 84a6aa33bd..258fb3f5ef 100644 --- a/lockfile.c +++ b/lockfile.c @@ -167,7 +167,6 @@ int commit_lock_file(struct lock_file *lk) strcpy(result_file, lk->filename); i = strlen(result_file) - 5; /* .lock */ result_file[i] = 0; - unlink(result_file); i = rename(lk->filename, result_file); lk->filename[0] = 0; return i; diff --git a/refs.c b/refs.c index 3c477309bb..9c07f83b72 100644 --- a/refs.c +++ b/refs.c @@ -963,15 +963,6 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) retry: if (log && rename(git_path("tmp-renamed-log"), git_path("logs/%s", newref))) { -#ifdef __MINGW32__ - if (errno == EEXIST) { - struct stat st; - if (stat(git_path("logs/%s", newref), &st) == 0 && S_ISDIR(st.st_mode)) - errno = EISDIR; - else - errno = EEXIST; - } -#endif if (errno==EISDIR || errno==ENOTDIR) { /* * rename(a, b) when b is an existing @@ -1237,7 +1228,6 @@ int create_symref(const char *ref_target, const char *refs_heads_master, error("Unable to write to %s", lockpath); goto error_unlink_return; } - unlink(git_HEAD); if (rename(lockpath, git_HEAD) < 0) { error("Unable to create %s", git_HEAD); goto error_unlink_return; From 1c32cf28d70781ebb843d436558e0b328b438ec6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 22:25:13 +0200 Subject: [PATCH 165/781] Skip again some tests involving symbolic links. --- t/t0000-basic.sh | 1 + t/t1300-repo-config.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 2c3b6b797c..a213268cd6 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -305,6 +305,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' +test "$no_symlinks" || test_expect_success 'absolute path works as expected' ' mkdir first && ln -s ../.git first/.git && diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 1d2bf2c060..12285d674b 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -601,6 +601,7 @@ echo >>result test_expect_success '--null --get-regexp' 'cmp result expect' +test "$no_symlinks" || test_expect_success 'symlinked configuration' ' ln -s notyet myconfig && From 52b4f704fd0d3f1ced8419cbcb460dd8374d8220 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 7 Aug 2007 22:26:45 +0200 Subject: [PATCH 166/781] builtin run_command: do not exit with -1. The shell does not correctly detect an exit code of -1 as a failure. We simply truncate the status code to the lower 8 bits. --- git.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git.c b/git.c index fd604b51fc..adbc188d86 100644 --- a/git.c +++ b/git.c @@ -288,7 +288,7 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv) status = p->fn(argc, argv, prefix); if (status) - return status; + return status & 0xff; /* Somebody closed stdout? */ if (fstat(fileno(stdout), &st)) From c603988c10c1d897e6f15e18b7727ec1bb1711b9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 8 Aug 2007 21:35:02 +0200 Subject: [PATCH 167/781] t/test-lib.sh: Automatically detect whether symbolic links are supported. This reverts the part of commit cb0ad0c0af084b52a72791feeca7c70bd8ed855a that hands down the explicit NO_SYMLINKS setting from the top-level Makefile. --- Makefile | 2 -- t/Makefile | 4 ---- t/test-lib.sh | 6 ++++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index f94bf01450..8127a5569d 100644 --- a/Makefile +++ b/Makefile @@ -492,7 +492,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease - NO_SYMLINKS=YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat @@ -987,7 +986,6 @@ all: $(TEST_PROGRAMS) # However, the environment gets quite big, and some programs have problems # with that. -export NO_SYMLINKS export NO_SVN_TESTS test: all diff --git a/t/Makefile b/t/Makefile index f8e396c108..72d7884232 100644 --- a/t/Makefile +++ b/t/Makefile @@ -14,10 +14,6 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) -ifdef NO_SYMLINKS - GIT_TEST_OPTS += --no-symlinks -endif - all: $(T) clean $(T): diff --git a/t/test-lib.sh b/t/test-lib.sh index 6081d172ab..a3f3d7c922 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -87,8 +87,6 @@ do --no-python) # noop now... shift ;; - --no-symlinks) - no_symlinks=t; shift ;; *) break ;; esac @@ -285,6 +283,10 @@ rm -fr "$test" test_create_repo $test cd "$test" +# test for symbolic link capability +ln -s x y 2> /dev/null && test -l y 2> /dev/null || no_symlinks=1 +rm -f y + this_test=$(expr "./$0" : '.*/\(t[0-9]*\)-[^/]*$') for skp in $GIT_SKIP_TESTS do From 7e6ad42588fb341f1328acb072f0720a4c411705 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jul 2007 22:11:54 +0200 Subject: [PATCH 168/781] Skip some git diff tests if the file system does not support funny names. Signed-off-by: Johannes Sixt --- t/t3902-quoted.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index 63f950b179..e8ad85afe4 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -14,6 +14,13 @@ LF=' ' DQ='"' +echo foo > "Name and an${HT}HT" +test -f "Name and an${HT}HT" || { + # since FAT/NTFS does not allow tabs in filenames, skip this test + say 'Your filesystem does not allow tabs in filenames, test skipped.' + test_done +} + for_each_name () { for name in \ Name "Name and a${LF}LF" "Name and an${HT}HT" "Name${DQ}" \ From 6bb4b679d6fcee5104c46c3a5750cbe1d1dc06ce Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 9 Aug 2007 01:54:12 +0100 Subject: [PATCH 169/781] Fix new tests which ignored --no-symlinks Signed-off-by: Johannes Schindelin --- t/t0000-basic.sh | 2 ++ t/t1300-repo-config.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 2c3b6b797c..b42b1e6948 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -305,6 +305,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' +test "$no_symlinks" || { test_expect_success 'absolute path works as expected' ' mkdir first && ln -s ../.git first/.git && @@ -320,5 +321,6 @@ test_expect_success 'absolute path works as expected' ' sym="$(cd first; pwd -P)"/file && test "$sym" = "$(test-absolute-path $dir2/syml)" ' +} test_done diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 1d2bf2c060..a59f1f3aed 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -601,6 +601,7 @@ echo >>result test_expect_success '--null --get-regexp' 'cmp result expect' +test "$no_symlinks" || { test_expect_success 'symlinked configuration' ' ln -s notyet myconfig && @@ -615,5 +616,6 @@ test_expect_success 'symlinked configuration' ' test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov ' +} test_done From 327005a9ef9c3b784e4742cece0710de6a549313 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 8 Aug 2007 22:19:49 -0400 Subject: [PATCH 170/781] Returning -1 does not fail like it should in MSys. We need to return 1 rather than -1 on failure since -1 does not seem to signal an error in MSys. Signed-off-by: Mike Pape --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.c b/config.c index bbc5d34e5a..977115a6e9 100644 --- a/config.c +++ b/config.c @@ -436,7 +436,7 @@ int git_config_from_file(config_fn_t fn, const char *filename) int ret; FILE *f = fopen(filename, "r"); - ret = -1; + ret = 1; if (f) { config_file = f; config_file_name = filename; From cfbeb65f6e9a2a990a4feaaf0475b226acda44c0 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 13:29:48 -0400 Subject: [PATCH 171/781] Added a sleep to the test for MSys so commits happen. When committing, git thought there were no changes. Signed-off-by: Mike Pape --- t/t6200-fmt-merge-msg.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 526d7d1c44..878f51a8d9 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -9,6 +9,7 @@ test_description='fmt-merge-msg test' datestamp=1151939923 setdate () { + sleep 1 GIT_COMMITTER_DATE="$datestamp +0200" GIT_AUTHOR_DATE="$datestamp +0200" datestamp=`expr "$datestamp" + 1` From e11db787dc8e680b379303393949da6ee2c45f0b Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 14:30:18 -0400 Subject: [PATCH 172/781] We need to check for msys as well as Windows in add--interactive. Signed-off-by: Mike Pape --- git-add--interactive.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-add--interactive.perl b/git-add--interactive.perl index 7921cde8cb..717960037c 100755 --- a/git-add--interactive.perl +++ b/git-add--interactive.perl @@ -3,7 +3,7 @@ use strict; sub run_cmd_pipe { - if ($^O eq 'MSWin32') { + if ($^O eq 'MSWin32' || $^O eq 'msys') { my @invalid = grep {m/[":*]/} @_; die "$^O does not support: @invalid\n" if @invalid; my @args = map { m/ /o ? "\"$_\"": $_ } @_; From a917ddbacf11b1f2280134bd8bc5c248fbf77a5d Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 14:35:43 -0400 Subject: [PATCH 173/781] sed does not accept -i on msys. We use a temporary .new file instead. Signed-off-by: Mike Pape --- t/t7501-commit.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 6bd3c9e3e0..cfa67227e5 100644 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -69,7 +69,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/a file/an amend commit/g" $1 +sed -e "s/a file/an amend commit/g" $1 > $1.new +mv $1.new $1 EOF chmod 755 editor @@ -88,7 +89,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/amend/older/g" $1 +sed -e "s/amend/older/g" $1 > $1.new +mv $1.new $1 EOF chmod 755 editor From 96f438b98a7b8b3fec062ed6064d74074e5e1ff0 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 16:18:50 -0400 Subject: [PATCH 174/781] In msys, chmod does not work. Using the shebang makes it "executable". Thanks to Dscho for figuring out the work around. Signed-off-by: Mike Pape --- t/t7005-editor.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh index 28643b0da4..b21ced1bc2 100755 --- a/t/t7005-editor.sh +++ b/t/t7005-editor.sh @@ -7,6 +7,7 @@ test_description='GIT_EDITOR, core.editor, and stuff' for i in GIT_EDITOR core_editor EDITOR VISUAL vi do cat >e-$i.sh <<-EOF + #!/bin/sh echo "Edited by $i" >"\$1" EOF chmod +x e-$i.sh From 733bd67d92a3dfa0a10a4c17ebbe82195891bd3e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 9 Aug 2007 22:32:09 +0200 Subject: [PATCH 175/781] Fix mode of shell scripts. These are the result of mismerges by old Windows versions of git. --- git-clone.sh | 0 git-rebase.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 git-clone.sh mode change 100644 => 100755 git-rebase.sh diff --git a/git-clone.sh b/git-clone.sh old mode 100644 new mode 100755 diff --git a/git-rebase.sh b/git-rebase.sh old mode 100644 new mode 100755 From 37ebf62c74202db267d2eb33283555d614edc70b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 9 Aug 2007 22:33:20 +0200 Subject: [PATCH 176/781] Revert style breakage. The breakage is a result of editing and incomplete reversal. --- builtin-prune-packed.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 6473d327e6..977730064b 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -25,10 +25,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) printf("rm -f %s\n", pathname); - else { - if (unlink(pathname) < 0) - error("unable to unlink %s", pathname); - } + else if (unlink(pathname) < 0) + error("unable to unlink %s", pathname); } pathname[len] = 0; rmdir(pathname); From decd70079244e8daa16eb49c95f82c407629b540 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 9 Aug 2007 23:07:30 +0200 Subject: [PATCH 177/781] Use is_absolute_path() in more places. --- builtin-init-db.c | 2 +- config.c | 2 +- exec_cmd.c | 12 ++---------- git.c | 14 ++++---------- setup.c | 5 +---- 5 files changed, 9 insertions(+), 26 deletions(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 2a20737249..c51c586141 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -140,7 +140,7 @@ static void copy_templates(const char *git_dir, int len, const char *template_di * interpreted relative to the exec_dir */ template_dir = DEFAULT_GIT_TEMPLATE_DIR; - if (template_dir[0] != '/' && template_dir[1] != ':') { + if (!is_absolute_path(template_dir)) { const char *exec_path = git_exec_path(); template_dir = prefix_path(exec_path, strlen(exec_path), template_dir); diff --git a/config.c b/config.c index fb4576f87f..78bd267070 100644 --- a/config.c +++ b/config.c @@ -454,7 +454,7 @@ const char *git_etc_gitconfig(void) if (!system_wide) { system_wide = ETC_GITCONFIG; /* interpret path relative to exec-dir */ - if (system_wide[0] != '/' && system_wide[1] != ':') { + if (!is_absolute_path(system_wide)) { const char *exec_path = git_exec_path(); system_wide = prefix_path(exec_path, strlen(exec_path), system_wide); diff --git a/exec_cmd.c b/exec_cmd.c index a9886b87fd..bad4843113 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -80,11 +80,7 @@ int execv_git_cmd(const char **argv) if (!exec_dir || !*exec_dir) continue; -#ifdef __MINGW32__ - if (*exec_dir != '/' && exec_dir[1] != ':') { -#else - if (*exec_dir != '/') { -#endif + if (!is_absolute_path(exec_dir)) { if (!getcwd(git_command, sizeof(git_command))) { fprintf(stderr, "git: cannot determine " "current directory: %s\n", @@ -190,11 +186,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) if (!exec_dir || !*exec_dir) continue; -#ifdef __MINGW32__ - if (*exec_dir != '/' && exec_dir[1] != ':') { -#else - if (*exec_dir != '/') { -#endif + if (!is_absolute_path(exec_dir)) { if (!getcwd(p[i], sizeof(p[i]))) { fprintf(stderr, "git: cannot determine " "current directory: %s\n", diff --git a/git.c b/git.c index adbc188d86..9908a60007 100644 --- a/git.c +++ b/git.c @@ -422,22 +422,16 @@ int main(int argc, const char **argv) * if it's an absolute path and we don't have * anything better. */ - if (slash) { - *slash++ = 0; - if (*cmd == '/') - exec_path = cmd; - cmd = slash; - } - #ifdef __MINGW32__ - slash = strrchr(cmd, '\\'); + if (!slash) + slash = strrchr(cmd, '\\'); +#endif if (slash) { *slash++ = 0; - if (cmd[1] == ':') + if (is_absolute_path(cmd)) exec_path = cmd; cmd = slash; } -#endif /* * "git-xxxx" is the same as "git xxxx", but we obviously: diff --git a/setup.c b/setup.c index fa5f724d21..15100bc1b7 100644 --- a/setup.c +++ b/setup.c @@ -88,10 +88,7 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) return arg; #else /* don't add prefix to absolute paths */ - const int is_absolute = - is_dir_sep(arg[0]) || - (arg[0] && arg[1] == ':' && is_dir_sep(arg[2])); - if (is_absolute) + if (is_absolute_path(arg)) pfx_len = 0; else #endif From dfcdb3d9fc34a6a6f50e00934af014e0fc62f0c6 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Thu, 9 Aug 2007 20:05:38 -0400 Subject: [PATCH 178/781] Fixed INSTALL set in Makefile from the merge with git.git. INSTALL was set to /bin/install but then set to install right after that from the merge. MSys needs to have the explicit path so it doesn't use Windows install. Signed-off-by: Mike Pape --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 36d7bebbad..f3f08dbcc4 100644 --- a/Makefile +++ b/Makefile @@ -179,7 +179,6 @@ RM = rm -f TAR = tar FIND = find INSTALL = /bin/install -INSTALL = install RPMBUILD = rpmbuild TCL_PATH = tclsh TCLTK_PATH = wish From 855f254b2b5b083a63fc8d7709a42e2cbdc5a136 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Thu, 9 Aug 2007 13:41:02 -0700 Subject: [PATCH 179/781] git clone was failing with 'invalid object name HEAD' if ran from cmd.exe directly environment.c caches results of many getenv calls. Under MinGW setenv(X) invalidates all previous values returned by getenv(X) so cached values become dangling pointers. Replaced all setenv(GIT_DIR, ...) with set_git_dir Signed-off-by: Dmitry Kakurin --- builtin-init-db.c | 4 +--- git.c | 6 +++--- path.c | 2 +- setup.c | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 2a20737249..31427c571d 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -318,9 +318,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) /* * Set up the default .git directory contents */ - git_dir = getenv(GIT_DIR_ENVIRONMENT); - if (!git_dir) - git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; + git_dir = get_git_dir(); safe_create_dir(git_dir, 0); /* Check to see if the repository version is right. diff --git a/git.c b/git.c index 1f7f595653..5fc277c895 100644 --- a/git.c +++ b/git.c @@ -67,14 +67,14 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) fprintf(stderr, "No directory given for --git-dir.\n" ); usage(git_usage_string); } - setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1); + set_git_dir( (*argv)[1] ); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; handled++; } else if (!prefixcmp(cmd, "--git-dir=")) { - setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); + set_git_dir(cmd + 10); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@ -93,7 +93,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; - setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1); + set_git_dir(getcwd(git_dir, sizeof(git_dir))); if (envchanged) *envchanged = 1; } else { diff --git a/path.c b/path.c index a1139d483b..7a5ac5b067 100644 --- a/path.c +++ b/path.c @@ -265,7 +265,7 @@ char *enter_repo(char *path, int strict) if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 && validate_headref("HEAD") == 0) { - setenv(GIT_DIR_ENVIRONMENT, ".", 1); + set_git_dir("."); check_repository_format(); return path; } diff --git a/setup.c b/setup.c index 5a8e7b6b52..0de8dcd61b 100644 --- a/setup.c +++ b/setup.c @@ -332,7 +332,7 @@ const char *setup_git_directory_gently(int *nongit_ok) inside_git_dir = 1; if (!work_tree_env) inside_work_tree = 0; - setenv(GIT_DIR_ENVIRONMENT, ".", 1); + set_git_dir("."); return NULL; } chdir(".."); From 5e5619bd48dab2c8a32c604001ffaae6f807b1af Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Fri, 10 Aug 2007 01:09:34 -0700 Subject: [PATCH 180/781] Applied settings from config.mak to Makefile so we don't need config.mak anymore Signed-off-by: Dmitry Kakurin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f3f08dbcc4..dd31119098 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ ALL_CFLAGS = $(CFLAGS) ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip -prefix = $(HOME) +prefix = bindir = $(prefix)/bin gitexecdir = $(bindir) sharedir = $(prefix)/share From a8c36f3212670a10d71203e91f97089f8954f624 Mon Sep 17 00:00:00 2001 From: Torgil Svensson Date: Fri, 10 Aug 2007 10:02:51 +0200 Subject: [PATCH 181/781] Make sane shell- and perl-scripts magic paths Make the magic paths absolute to msys instead of absolute to Windows. Signed-off-by: Torgil Svensson Acked-by: Johannes Schindelin Acked-by: Marius Storm-Olsen --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index dd31119098..0eada9d4c8 100644 --- a/Makefile +++ b/Makefile @@ -475,8 +475,8 @@ ifeq ($(uname_S),IRIX64) BASIC_LDFLAGS += -L/usr/lib32 endif ifneq (,$(findstring MINGW,$(uname_S))) - SHELL_PATH = $(shell cd /bin && pwd -W)/sh - PERL_PATH = $(shell cd /bin && pwd -W)/perl + SHELL_PATH = /bin/sh + PERL_PATH = /bin/perl NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease From 8e78bd571071805ca9f34a6bc93846f6e5b15f4e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 10 Aug 2007 11:33:40 +0100 Subject: [PATCH 182/781] verify_path(): do not allow absolute paths Signed-off-by: Johannes Schindelin --- read-cache.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/read-cache.c b/read-cache.c index e060392d1d..abc41561df 100644 --- a/read-cache.c +++ b/read-cache.c @@ -507,6 +507,11 @@ int verify_path(const char *path) { char c; +#ifdef __MINGW32__ + if (is_absolute_path(path)) + return error("Cannot handle absolute path: %s", path); +#endif + goto inside; for (;;) { if (!c) From ec33dd4c530319fc95f5481d057b2ad940e91694 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 11 Aug 2007 22:14:34 +0200 Subject: [PATCH 183/781] t7501-commit.sh: Not all seds understand option -i Use mv instead. Signed-off-by: Johannes Sixt --- t/t7501-commit.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 6bd3c9e3e0..d1284140d7 100644 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -69,7 +69,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/a file/an amend commit/g" $1 +sed -e "s/a file/an amend commit/g" < $1 > $1- +mv $1- $1 EOF chmod 755 editor @@ -88,7 +89,8 @@ test_expect_success \ cat >editor <<\EOF #!/bin/sh -sed -i -e "s/amend/older/g" $1 +sed -e "s/amend/older/g" < $1 > $1- +mv $1- $1 EOF chmod 755 editor From 89697a4c152c798205c9af4782e4053274e54b3f Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Sun, 12 Aug 2007 05:30:07 -0700 Subject: [PATCH 184/781] Issue 20: Fix all build warnings Fixed all warnings. Code compiles cleanly now. Full test pass: OK Signed-off-by: Dmitry Kakurin --- builtin-ls-files.c | 2 +- builtin-prune-packed.c | 2 ++ builtin-prune.c | 2 ++ builtin-unpack-objects.c | 2 +- compat/mingw.c | 4 ++-- compat/pread.c | 2 ++ compat/regex.c | 26 ++++++++++++++++---------- config.c | 2 ++ connect.c | 2 +- diff.c | 2 +- exec_cmd.c | 5 ++--- fetch-pack.c | 2 +- index-pack.c | 2 +- merge-index.c | 2 +- pager.c | 2 +- read-cache.c | 2 +- receive-pack.c | 2 +- run-command.c | 4 ++-- sha1_file.c | 16 +++++++++------- show-index.c | 2 +- spawn-pipe.c | 6 ++---- unpack-trees.c | 2 +- 22 files changed, 53 insertions(+), 40 deletions(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index d36181a755..e83b145b5c 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -211,7 +211,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) putchar(line_terminator); } else { - printf("%s%06o %s %d\t", + printf("%s%06lo %s %u\t", tag, ntohl(ce->ce_mode), abbrev ? find_unique_abbrev(ce->sha1,abbrev) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 6473d327e6..fa9ad7bfdf 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -7,6 +7,8 @@ static const char prune_packed_usage[] = #define DRY_RUN 01 #define VERBOSE 02 +void sync(void); + static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) { struct dirent *de; diff --git a/builtin-prune.c b/builtin-prune.c index 44df59e4a7..02e4c09b0e 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -8,6 +8,8 @@ static const char prune_usage[] = "git-prune [-n]"; static int show_only; +void sync(void); + static int prune_object(char *path, const char *filename, const unsigned char *sha1) { if (show_only) { diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index a6ff62fd8c..1500be5761 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -318,7 +318,7 @@ static void unpack_all(void) if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE) die("bad pack file"); if (!pack_version_ok(hdr->hdr_version)) - die("unknown pack file version %d", ntohl(hdr->hdr_version)); + die("unknown pack file version %lu", ntohl(hdr->hdr_version)); use(sizeof(struct pack_header)); if (!quiet) diff --git a/compat/mingw.c b/compat/mingw.c index ac8b8e0414..ca3ae4cb06 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -131,7 +131,7 @@ int pipe(int filedes[2]) CloseHandle(h[0]); return -1; } - fd = _open_osfhandle(h[0], O_NOINHERIT); + fd = _open_osfhandle( (int) h[0], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); @@ -141,7 +141,7 @@ int pipe(int filedes[2]) } close(filedes[0]); filedes[0] = fd; - fd = _open_osfhandle(h[1], O_NOINHERIT); + fd = _open_osfhandle( (int) h[1], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); diff --git a/compat/pread.c b/compat/pread.c index 978cac4ec9..ce29997724 100644 --- a/compat/pread.c +++ b/compat/pread.c @@ -1,5 +1,7 @@ #include "../git-compat-util.h" +int read_in_full(int fd, void *buf, size_t count); + ssize_t git_pread(int fd, void *buf, size_t count, off_t offset) { off_t current_offset; diff --git a/compat/regex.c b/compat/regex.c index 2d57c70b9c..1d39e08d47 100644 --- a/compat/regex.c +++ b/compat/regex.c @@ -1597,10 +1597,12 @@ regex_compile (pattern, size, syntax, bufp) if (syntax & RE_NO_BK_PARENS) goto normal_backslash; if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_backslash; else return REG_ERPAREN; + } handle_close: if (fixup_alt_jump) @@ -1617,10 +1619,12 @@ regex_compile (pattern, size, syntax, bufp) /* See similar code for backslashed left paren above. */ if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_char; else return REG_ERPAREN; + } /* Since we just checked for an empty stack above, this ``can't happen''. */ @@ -3191,14 +3195,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matching and the regnum-th regend points to right after where we stopped matching the regnum-th subexpression. (The zeroth register keeps track of what the whole pattern matches.) */ - const char **regstart, **regend; + const char **regstart = NULL, **regend = NULL; /* If a group that's operated upon by a repetition operator fails to match anything, then the register for its start will need to be restored because it will have been set to wherever in the string we are when we last see its open-group operator. Similarly for a register's end. */ - const char **old_regstart, **old_regend; + const char **old_regstart = NULL, **old_regend = NULL; /* The is_active field of reg_info helps us keep track of which (possibly nested) subexpressions we are currently in. The matched_something @@ -3206,14 +3210,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matched any of the pattern so far this time through the reg_num-th subexpression. These two fields get reset each time through any loop their register is in. */ - register_info_type *reg_info; + register_info_type *reg_info = NULL; /* The following record the register info as found in the above variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; - const char **best_regstart, **best_regend; + const char **best_regstart = NULL, **best_regend = NULL; /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything @@ -3226,8 +3230,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) const char *match_end = NULL; /* Used when we pop values we don't care about. */ - const char **reg_dummy; - register_info_type *reg_info_dummy; + const char **reg_dummy = NULL; + register_info_type *reg_info_dummy = NULL; #ifdef DEBUG /* Counts the total number of registers pushed. */ @@ -4561,10 +4565,12 @@ common_op_match_null_string_p (p, end, reg_info) bytes; nonzero otherwise. */ static int -bcmp_translate (s1, s2, len, translate) - unsigned char *s1, *s2; - register int len; - char *translate; +bcmp_translate( + unsigned char *s1, + unsigned char *s2, + int len, + char *translate +) { register unsigned char *p1 = s1, *p2 = s2; while (len) diff --git a/config.c b/config.c index 977115a6e9..98ae20d551 100644 --- a/config.c +++ b/config.c @@ -15,6 +15,8 @@ static const char *config_file_name; static int config_linenr; static int zlib_compression_seen; +extern int getpagesize(); + static int get_next_char(void) { int c; diff --git a/connect.c b/connect.c index f50db639a4..dcae813b58 100644 --- a/connect.c +++ b/connect.c @@ -585,7 +585,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) const char *argv[] = { NULL, host, command, NULL }; const char *ssh = getenv("GIT_SSH"); if (!ssh) ssh = "ssh"; - pid = spawnvpe_pipe(ssh, argv, environ, pipefd[1], pipefd[0]); + pid = spawnvpe_pipe(ssh, argv, (const char**) environ, pipefd[1], pipefd[0]); } else { const char *argv[] = { NULL, "-c", command, NULL }; diff --git a/diff.c b/diff.c index e64625129d..462d1e8563 100644 --- a/diff.c +++ b/diff.c @@ -1793,7 +1793,7 @@ static int spawn_prog(const char *pgm, const char **arg) int status; fflush(NULL); - pid = spawnvpe_pipe(pgm, arg, environ, NULL, NULL); + pid = spawnvpe_pipe(pgm, arg, (const char**) environ, NULL, NULL); if (pid < 0) die("unable to fork"); diff --git a/exec_cmd.c b/exec_cmd.c index a9886b87fd..2a8e48b048 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -4,7 +4,6 @@ #include "spawn-pipe.h" #define MAX_ARGS 32 -extern char **environ; static const char *current_exec_path; static const char *builtin_exec_path(void) @@ -138,7 +137,7 @@ int execv_git_cmd(const char **argv) trace_argv_printf(argv, -1, "trace: exec:"); /* execve() can only ever return if it fails */ - execve(git_command, (char **)argv, environ); + execve(git_command, (const char **) argv, (const char **) environ); trace_printf("trace: exec failed: %s\n", strerror(errno)); @@ -247,7 +246,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) trace_argv_printf(argv, -1, "trace: exec:"); - pid = spawnvppe_pipe(cmd, argv, environ, usedpaths, + pid = spawnvppe_pipe(cmd, argv, (const char**) environ, usedpaths, pin, pout); argv[0] = tmp; diff --git a/fetch-pack.c b/fetch-pack.c index e6abf1625a..b6470932fb 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -512,7 +512,7 @@ static int get_pack(int xd[2]) if (read_pack_header(fd[0], &header)) die("protocol error: bad pack header"); - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", ntohl(header.hdr_version), ntohl(header.hdr_entries)); if (ntohl(header.hdr_entries) < unpack_limit) do_keep = 0; diff --git a/index-pack.c b/index-pack.c index 8403c36b63..32e9dd99df 100644 --- a/index-pack.c +++ b/index-pack.c @@ -141,7 +141,7 @@ static void parse_pack_header(void) if (hdr->hdr_signature != htonl(PACK_SIGNATURE)) die("pack signature mismatch"); if (!pack_version_ok(hdr->hdr_version)) - die("pack version %d unsupported", ntohl(hdr->hdr_version)); + die("pack version %lu unsupported", ntohl(hdr->hdr_version)); nr_objects = ntohl(hdr->hdr_entries); use(sizeof(struct pack_header)); diff --git a/merge-index.c b/merge-index.c index fa719cb0b1..1cf4cb5b3f 100644 --- a/merge-index.c +++ b/merge-index.c @@ -48,7 +48,7 @@ static int merge_entry(int pos, const char *path) break; found++; strcpy(hexbuf[stage], sha1_to_hex(ce->sha1)); - sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode)); + sprintf(ownbuf[stage], "%lo", ntohl(ce->ce_mode)); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); diff --git a/pager.c b/pager.c index a55f4e9d1e..4048894734 100644 --- a/pager.c +++ b/pager.c @@ -88,7 +88,7 @@ void setup_pager(void) #else /* spawn the pager */ pager_argv[2] = pager; - pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL); + pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, (const char**) environ, fd, NULL); if (pager_pid < 0) return; diff --git a/read-cache.c b/read-cache.c index abc41561df..849e8d6b0f 100644 --- a/read-cache.c +++ b/read-cache.c @@ -149,7 +149,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) changed |= DATA_CHANGED; return changed; default: - die("internal error: ce_mode is %o", ntohl(ce->ce_mode)); + die("internal error: ce_mode is %lo", ntohl(ce->ce_mode)); } if (ce->ce_mtime.sec != htonl(st->st_mtime)) changed |= MTIME_CHANGED; diff --git a/receive-pack.c b/receive-pack.c index d3c422be58..94bc99b40d 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -352,7 +352,7 @@ static const char *unpack(void) hdr_err = parse_pack_header(&hdr); if (hdr_err) return hdr_err; - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { diff --git a/run-command.c b/run-command.c index 5964e7d4dd..f208ed45fa 100644 --- a/run-command.c +++ b/run-command.c @@ -14,7 +14,7 @@ int start_command(struct child_process *cmd) int need_in, need_out; int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; - char **env = environ; + const char **env = (const char **) environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -75,7 +75,7 @@ int start_command(struct child_process *cmd) if (cmd->git_cmd) { cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); + cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, (const char**) env, fdin, fdout); } } if (cmd->pid < 0) { diff --git a/sha1_file.c b/sha1_file.c index 4629fe81a4..1e3cf60ca0 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -425,15 +425,17 @@ static size_t peak_pack_mapped; static size_t pack_mapped; struct packed_git *packed_git; +extern size_t getpagesize(); + void pack_report(void) { fprintf(stderr, "pack_report: getpagesize() = %10" SZ_FMT "\n" "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" "pack_report: core.packedGitLimit = %10" SZ_FMT "\n", - (size_t) getpagesize(), - packed_git_window_size, - packed_git_limit); + (unsigned long) getpagesize(), + (unsigned long) packed_git_window_size, + (unsigned long) packed_git_limit); fprintf(stderr, "pack_report: pack_used_ctr = %10u\n" "pack_report: pack_mmap_calls = %10u\n" @@ -443,7 +445,8 @@ void pack_report(void) pack_used_ctr, pack_mmap_calls, pack_open_windows, peak_pack_open_windows, - pack_mapped, peak_pack_mapped); + (unsigned long) pack_mapped, + (unsigned long) peak_pack_mapped); } static int check_packed_git_idx(const char *path, struct packed_git *p) @@ -634,7 +637,6 @@ static int open_packed_git_1(struct packed_git *p) struct pack_header hdr; unsigned char sha1[20]; unsigned char *idx_sha1; - long fd_flag; if (!p->index_data && open_pack_index(p)) return error("packfile %s index unavailable", p->pack_name); @@ -669,13 +671,13 @@ static int open_packed_git_1(struct packed_git *p) if (hdr.hdr_signature != htonl(PACK_SIGNATURE)) return error("file %s is not a GIT packfile", p->pack_name); if (!pack_version_ok(hdr.hdr_version)) - return error("packfile %s is version %u and not supported" + return error("packfile %s is version %lu and not supported" " (try upgrading GIT to a newer version)", p->pack_name, ntohl(hdr.hdr_version)); /* Verify the pack matches its index. */ if (p->num_objects != ntohl(hdr.hdr_entries)) - return error("packfile %s claims to have %u objects" + return error("packfile %s claims to have %lu objects" " while index indicates %u objects", p->pack_name, ntohl(hdr.hdr_entries), p->num_objects); diff --git a/show-index.c b/show-index.c index 57ed9e87b7..6943e4bbb3 100644 --- a/show-index.c +++ b/show-index.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) ntohl(off64[1]); off64_nr++; } - printf("%llu %s (%08x)\n", (unsigned long long) offset, + printf("%llu %s (%08lx)\n", (unsigned long long) offset, sha1_to_hex(entries[i].sha1), ntohl(entries[i].crc)); } diff --git a/spawn-pipe.c b/spawn-pipe.c index c8f0452823..e8872dc0ff 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -1,8 +1,6 @@ #include "git-compat-util.h" #include "spawn-pipe.h" -extern char **environ; - #ifdef __MINGW32__ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) { @@ -193,7 +191,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, qargv = xmalloc((argc+2)*sizeof(char*)); if (!interpr) { quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, env); + pid = spawnve(_P_NOWAIT, prog, qargv, (const char**) env); } else { qargv[0] = interpr; argv[0] = prog; @@ -219,7 +217,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, const char **copy_environ() { - return copy_env(environ); + return copy_env( (const char**)environ); } const char **copy_env(const char **env) diff --git a/unpack-trees.c b/unpack-trees.c index dfd985b0ef..d017f667ce 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -638,7 +638,7 @@ static void show_stage_entry(FILE *o, if (!ce) fprintf(o, "%s (missing)\n", label); else - fprintf(o, "%s%06o %s %d\t%s\n", + fprintf(o, "%s%06lo %s %d\t%s\n", label, ntohl(ce->ce_mode), sha1_to_hex(ce->sha1), From 57bab054a9f7cd82f8889ef4fad58653d89f38fc Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 11 Aug 2007 22:15:39 +0200 Subject: [PATCH 185/781] help (msysgit): teach git help to open html from /doc/git/html/ Html pages will be opened using the default Windows application configured for html. This code path is taken for msysgit (mingw). It is assumed that html pages are installed at /doc/git/html. This needs to be ensured by the msysgit superproject to make this patch useful. html pages should be cloned from git.git's main repo. This is the easiest way to get up-to-date documentation, without requiring the complete tool chain to generate them locally. If html pages are not yet there, you can use the following commands to get them: mkdir -p /doc/git/html cd /doc/git/html/ git init git config remote.origin.url git://git.kernel.org/pub/scm/git/git.git git config remote.origin.fetch refs/heads/html:refs/remotes/origin/html git fetch git checkout --track -b html origin/html and update the html documentation with git pull Signed-off-by: Steffen Prohaska --- help.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/help.c b/help.c index 7d59efa50b..e7da8ae430 100644 --- a/help.c +++ b/help.c @@ -180,7 +180,25 @@ static void show_man_page(const char *git_cmd) page = p; } +#ifdef __MINGW32__ + { + char* prefix = "/doc/git/html/"; + int prefix_len = strlen (prefix); + char* suffix = ".html"; + int suffix_len = strlen (suffix); + int page_len = strlen (page); + int htmlpath_len = prefix_len + page_len + suffix_len; + char* htmlpath = xmalloc (htmlpath_len + 1); + strcpy (htmlpath, prefix); + strcpy (htmlpath + prefix_len, page); + strcpy (htmlpath + prefix_len + page_len, suffix); + htmlpath[htmlpath_len] = 0; + /* We need sh here to run shell script /bin/start. */ + execlp("sh", "start", "/bin/start", htmlpath, NULL ); + } +#else execlp("man", "man", page, NULL); +#endif } void help_unknown_cmd(const char *cmd) From fefe8db81717b895dcc10977dc10827c6eaa045f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 11 Aug 2007 00:10:13 +0200 Subject: [PATCH 186/781] mergetool: refactored kdiff3 -> KDIFF3 Use shell variable KDIFF3 instead of kdiff3 to call kdiff3. This will be used in detection of the absolute absolute path. --- git-mergetool.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index e6bbb6bbd6..90a69b3465 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -13,6 +13,8 @@ SUBDIRECTORY_OK=Yes . git-sh-setup require_work_tree +KDIFF3=kdiff3 + # Returns true if the mode reflects a symlink is_symlink () { test "$1" = 120000 @@ -191,10 +193,10 @@ merge_file () { case "$merge_tool" in kdiff3) if base_present ; then - (kdiff3 --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \ + ("$KDIFF3" --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \ -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) else - (kdiff3 --auto -L1 "$path (Local)" --L2 "$path (Remote)" \ + ("$KDIFF3" --auto -L1 "$path (Local)" --L2 "$path (Remote)" \ -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1) fi status=$? From 3318ad905e53243dbd59002e4c95106268f763cb Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 11 Aug 2007 00:34:34 +0200 Subject: [PATCH 187/781] mergetool: added support for kdiff3 on windows kdiff3's homepage is http://kdiff3.sourceforge.net/. kdiff3 is automatically added to the available mergetools if its path is found in the Windows Registry. The path is taken from the registry. Be sure to set git config core.autocrlf true because kdiff3 seems to follow Windows crlf convention. --- git-mergetool.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index 90a69b3465..ac23891980 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -14,6 +14,7 @@ SUBDIRECTORY_OK=Yes require_work_tree KDIFF3=kdiff3 +KDIFF3SEPARATOR=-- # Returns true if the mode reflects a symlink is_symlink () { @@ -194,10 +195,10 @@ merge_file () { kdiff3) if base_present ; then ("$KDIFF3" --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \ - -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) + -o "$path" $KDIFF3SEPERATOR "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1) else ("$KDIFF3" --auto -L1 "$path (Local)" --L2 "$path (Remote)" \ - -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1) + -o "$path" $KDIFF3SEPERATOR "$LOCAL" "$REMOTE" > /dev/null 2>&1) fi status=$? remove_backup @@ -321,6 +322,11 @@ if test -z "$merge_tool" ; then merge_tool_candidates="kdiff3 $merge_tool_candidates" fi fi + regentry="$(REG QUERY 'HKEY_LOCAL_MACHINE\SOFTWARE\KDiff3\diff-ext' 2>/dev/null)" && { + KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3) + KDIFF3SEPARATOR= + merge_tool_candidates="$merge_tool_candidates kdiff3" + } if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then merge_tool_candidates="$merge_tool_candidates emerge" fi @@ -332,10 +338,12 @@ if test -z "$merge_tool" ; then for i in $merge_tool_candidates; do if test $i = emerge ; then cmd=emacs + elif test $i = kdiff3 ; then + cmd="$KDIFF3" else cmd=$i fi - if type $cmd > /dev/null 2>&1; then + if type "$cmd" > /dev/null 2>&1; then merge_tool=$i break fi @@ -347,7 +355,13 @@ if test -z "$merge_tool" ; then fi case "$merge_tool" in - kdiff3|tkdiff|meld|xxdiff|vimdiff|gvimdiff|opendiff) + kdiff3) + if ! type "$KDIFF3" > /dev/null 2>&1; then + echo "The merge tool $merge_tool is not available" + exit 1 + fi + ;; + tkdiff|meld|xxdiff|vimdiff|gvimdiff|opendiff) if ! type "$merge_tool" > /dev/null 2>&1; then echo "The merge tool $merge_tool is not available" exit 1 From 56be985fe902a4af8c7f0bbe4541ef783ead827f Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Tue, 14 Aug 2007 09:48:39 +0200 Subject: [PATCH 188/781] Avoid calling signal(SIGPIPE, ..) for MinGW builds. SIGPIPE isn't supported in MinGW. Signed-off-by: Marius Storm-Olsen --- builtin-verify-tag.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index dfcfcd0455..5c1314d071 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -100,9 +100,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) i++; } +#ifndef __MINGW32__ /* sometimes the program was terminated because this signal * was received in the process of writing the gpg input: */ signal(SIGPIPE, SIG_IGN); +#endif while (i < argc) if (verify_tag(argv[i++], verbose)) had_error = 1; From 65b356f555a716d9f753e58911da2017f3d1c2fc Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 13 Aug 2007 08:04:14 +0200 Subject: [PATCH 189/781] mergetool: converting backslashes in kdiff3 path from Windows registry Backslashes are converted to slashes right after the Windows registry returned a path. This is needed to avoid problems with shell expansion. Signed-off-by: Steffen Prohaska --- git-mergetool.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index ac23891980..e7d745062b 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -323,7 +323,7 @@ if test -z "$merge_tool" ; then fi fi regentry="$(REG QUERY 'HKEY_LOCAL_MACHINE\SOFTWARE\KDiff3\diff-ext' 2>/dev/null)" && { - KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3) + KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3 | sed -e 's@\\@/@g') KDIFF3SEPARATOR= merge_tool_candidates="$merge_tool_candidates kdiff3" } From 1a896a59003da71410fe34cf5687832d1f2a6797 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Tue, 14 Aug 2007 13:48:56 -0400 Subject: [PATCH 190/781] Correct logic from merge to fix t1020-subdirectory.sh. Some logic was lost from the merge from git.git. Signed-off-by: Mike Pape --- connect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index 9f51e8dcc8..ea810c4df9 100644 --- a/connect.c +++ b/connect.c @@ -525,7 +525,8 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) ) { protocol = PROTO_SSH; *path++ = '\0'; - } + } else + path = host; } else path = end; From d1f83218dce62affd1d7a82a9e654cca08dade9c Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 15 Aug 2007 13:18:20 -0400 Subject: [PATCH 191/781] Hardlinks are not supported in MSys so we disable them. We do not want the default to be hardlinks for local clones and we show a warning if the user tries to use -l. Signed-off-by: Mike Pape --- Makefile | 9 +++++++++ git-clone.sh | 5 ++++- t/Makefile | 4 ++++ t/t5701-clone-local.sh | 7 +++++++ t/test-lib.sh | 2 ++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 36fa094462..456681b27c 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,9 @@ all: # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. # Enable it on Windows. By default, symrefs are still used. # +# Define NO_HARDLINKS if you want to disable hard linking in git clone. +# Enable it on Windows. +# # Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability # tests. These tests take up a significant amount of the total test time # but are not needed unless you plan to talk to SVN repos. @@ -482,6 +485,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD=YesPlease NO_OPENSSL=YesPlease NO_SYMLINK_HEAD=YesPlease + NO_HARDLINKS=YesPlease NO_IPV6=YesPlease NO_ETC_PASSWD=YesPlease NO_SETENV=YesPlease @@ -724,6 +728,10 @@ ifdef ASCIIDOC8 export ASCIIDOC8 endif +ifdef NO_HARDLINKS + export NO_HARDLINKS +endif + # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@ -799,6 +807,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ + -e 's/@@NO_HARDLINKS@@/$(NO_HARDLINKS)/g' \ $@.sh >$@+ && \ chmod +x $@+ && \ mv $@+ $@ diff --git a/git-clone.sh b/git-clone.sh index 2c0164aafe..72435b03aa 100644 --- a/git-clone.sh +++ b/git-clone.sh @@ -99,6 +99,7 @@ origin_override= use_separate_remote=t depth= no_progress= +test "@@NO_HARDLINKS@@" && use_local_hardlink=no test -t 1 || no_progress=--no-progress while case "$#,$1" in @@ -109,7 +110,9 @@ while *,--na|*,--nak|*,--nake|*,--naked|\ *,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;; *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) - use_local_hardlink=yes ;; + (test "@@NO_HARDLINKS@@" && + echo >&2 "Warning: -l asked but hardlinks are not supported") || + use_local_hardlink=yes ;; *,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\ *,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks) use_local_hardlink=no ;; diff --git a/t/Makefile b/t/Makefile index f8e396c108..2b808f96bb 100644 --- a/t/Makefile +++ b/t/Makefile @@ -18,6 +18,10 @@ ifdef NO_SYMLINKS GIT_TEST_OPTS += --no-symlinks endif +ifdef NO_HARDLINKS + GIT_TEST_OPTS += --no-hardlinks +endif + all: $(T) clean $(T): diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index a3026ec4fc..d2f55ebfbc 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -3,6 +3,13 @@ test_description='test local clone' . ./test-lib.sh +if test "$no_hardlinks" +then + say 'Hard links not supported, skipping tests.' + test_done + exit +fi + D=`pwd` test_expect_success 'preparing origin repository' ' diff --git a/t/test-lib.sh b/t/test-lib.sh index 6081d172ab..143d95daca 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -89,6 +89,8 @@ do shift ;; --no-symlinks) no_symlinks=t; shift ;; + --no-hardlinks) + no_hardlinks=t; shift ;; *) break ;; esac From a0b4827288741c7939e40e269aa8298454a56eff Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 16 Aug 2007 21:16:48 +0200 Subject: [PATCH 192/781] Revert "Correct logic from merge to fix t1020-subdirectory.sh." This reverts commit 1a896a59003da71410fe34cf5687832d1f2a6797. The patch had an adverse effect on fetching with the git+ssh protocol, giving me the following errors Pseudo-terminal will not be allocated because stdin is not a terminal. ssh: ': no address associated with hostname. fatal: The remote end hung up unexpectedly Cannot get the repository state from git+ssh:// and [0: 172.20.1.78]: errno=Invalid argument [1: 192.168.1.3]: errno=Bad file descriptor [2: 192.168.35.1]: errno=Bad file descriptor [3: 192.168.150.1]: errno=Bad file descriptor fatal: unable to connect a socket (Bad file descriptor) Cannot get the repository state from git:// Signed-off-by: Marius Storm-Olsen --- connect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/connect.c b/connect.c index ea810c4df9..9f51e8dcc8 100644 --- a/connect.c +++ b/connect.c @@ -525,8 +525,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) ) { protocol = PROTO_SSH; *path++ = '\0'; - } else - path = host; + } } else path = end; From 6c75a2449182af7153d00c06bcda853258a10b21 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 11:53:24 +0200 Subject: [PATCH 193/781] Do not hard-code paths for the shell and perl. The reason to set SHELL_PATH and PERL_PATH was that 'make' failed to execute /bin/sh some-script It turns out that different MinGW/MSYS environments have different levels of support for this construct, so use the default and let the user override the settings in config.mak if the defaults don't work. --- Makefile | 2 -- README.MinGW | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8127a5569d..bd25c8abf6 100644 --- a/Makefile +++ b/Makefile @@ -475,8 +475,6 @@ ifeq ($(uname_S),IRIX64) BASIC_LDFLAGS += -L/usr/lib32 endif ifneq (,$(findstring MINGW,$(uname_S))) - SHELL_PATH = $(shell cd /bin && pwd -W)/sh - PERL_PATH = $(shell cd /bin && pwd -W)/perl NO_MMAP=YesPlease NO_PREAD=YesPlease NO_OPENSSL=YesPlease diff --git a/README.MinGW b/README.MinGW index 436d7b7849..74eb104c2c 100644 --- a/README.MinGW +++ b/README.MinGW @@ -31,6 +31,13 @@ In order to compile this code you need: libiconv-1.9.2-1-{lib,bin,lib}.zip (for git-am, from http://gnuwin32.sourceforge.net/packages/libiconv.htm) +I am using these settings in config.mak to have pointers to the right tools: + +TCL_PATH=tclsh84 +TCLTK_PATH=wish84 +SHELL_PATH=D:/MSYS/1.0/bin/sh +PERL_PATH=D:/MSYS/1.0/bin/perl + STATUS ------ From a9601507cf0bc6d987117dfcd0e3d98873f4ab61 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 12:27:54 +0200 Subject: [PATCH 194/781] Move MinGW specific declaration of mkstmp() up to avoid warnings. The declaration is needed in the xmkstmp() implementation. --- git-compat-util.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index 219ac871b4..75b2a4bc9b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -54,6 +54,8 @@ #include #include #include +#else +int mkstemp (char *__template); #endif #include #include @@ -435,7 +437,6 @@ int kill(pid_t pid, int sig); unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); -int mkstemp (char *__template); int gettimeofday(struct timeval *tv, void *tz); int pipe(int filedes[2]); From 94be0afa317c2cd54456652970cfefa7767b464f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 13:16:01 +0200 Subject: [PATCH 195/781] Provide a definition of SIGPIPE. --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index 75b2a4bc9b..22a53d3668 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -431,6 +431,7 @@ typedef int pid_t; #define SIGKILL 0 #define SIGCHLD 0 #define SIGALRM 0 +#define SIGPIPE 0 #define ECONNABORTED 0 int kill(pid_t pid, int sig); From 94e7a6b7b4d2b8901b836a398e1d3733c64112e1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 17 Aug 2007 14:50:29 +0200 Subject: [PATCH 196/781] Revert fa807fcb: 'Revert "Makefile: remove $foo when $foo.exe...' It works in msysgit, so there is no reason why we should not remove the scripted versions. Especially since some tests were failing for the sole reason that _not_ the builtin, but the script was executed. Signed-off-by: Johannes Schindelin --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 456681b27c..62407ad0be 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # The default target of this Makefile is... -all: +all:: # Define V=1 to have a more verbose compile. # @@ -762,9 +762,12 @@ export TAR INSTALL DESTDIR SHELL_PATH ### Build rules -all: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';) +endif -all: +all:: ifndef NO_TCLTK $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all endif @@ -993,7 +996,7 @@ endif TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X -all: $(TEST_PROGRAMS) +all:: $(TEST_PROGRAMS) # GNU make supports exporting all variables by "export" without parameters. # However, the environment gets quite big, and some programs have problems @@ -1045,6 +1048,9 @@ endif '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) +endif install-doc: $(MAKE) -C Documentation install From 009ab81675846be538bd337d9addd9965d2925aa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 15:14:57 +0200 Subject: [PATCH 197/781] Avoid spawning 'ls' for each directory that is passed to the cpio emulator. We assume that the file names are passed in using find -depth so that a directory is listed after its contents. --- cpio.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cpio.sh b/cpio.sh index 2816e34851..df5f64c14c 100644 --- a/cpio.sh +++ b/cpio.sh @@ -24,16 +24,24 @@ while test $# -gt 0; do shift done +prev= + filterdirs() { while read f; do if test -d "$f"; then # list only empty directories - if test -z "$(ls -A "$f")"; then - echo "$f" - fi + # here we assume that directories are listed after + # its files (aka 'find -depth'), hence, a directory + # that is not empty will be a leading sub-string + # of the preceding entry + case "$prev" in + "$f"/* ) ;; + *) echo "$f";; + esac else echo "$f" fi + prev="$f" done } From 942afeb88b16e1be0b653114491668b2140ca5e1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 18:40:36 +0200 Subject: [PATCH 198/781] Work around a Windows oddity when a pipe with no reader is written to. The first WriteFile() returns ERROR_BROKEN_PIPE, subsequent WriteFile()s return ERROR_NO_DATA, which is not translated to EPIPE, but EINVAL. Hmpf! --- write_or_die.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/write_or_die.c b/write_or_die.c index e125e11d3b..40b046acb0 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -34,7 +34,16 @@ void maybe_flush_or_die(FILE *f, const char *desc) return; } if (fflush(f)) { +#ifndef __MINGW32__ if (errno == EPIPE) +#else + /* + * On Windows, EPIPE is returned only by the first write() + * after the reading end has closed its handle; subsequent + * write()s return EINVAL. + */ + if (errno == EPIPE || errno == EINVAL) +#endif exit(0); die("write failure on %s: %s", desc, strerror(errno)); } From 331406ad302671f696f4c624737acfede7bf1d04 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Fri, 17 Aug 2007 19:18:09 -0400 Subject: [PATCH 199/781] Correct connect logic to allow for Windows C: paths. We need to add logic for windows to allow C: and not assume the : means it's another protocol. Signed-off-by: Mike Pape --- connect.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/connect.c b/connect.c index 9f51e8dcc8..1c92df0f21 100644 --- a/connect.c +++ b/connect.c @@ -518,13 +518,18 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) path = strchr(end, c); if (path) { - if (c == ':' + if (c == ':') { #ifdef __MINGW32__ - && path - end > 1 /* host must have at least 2 chars to catch DOS C:/path */ + /* host must have at least 2 chars to + * catch DOS C:/path */ + if (path - end > 1) { +#endif + protocol = PROTO_SSH; + *path++ = '\0'; +#ifdef __MINGW32__ + } else + path = end; #endif - ) { - protocol = PROTO_SSH; - *path++ = '\0'; } } else path = end; From 20e93f53e3a220018c62e0055a083af6079b8a2c Mon Sep 17 00:00:00 2001 From: Johannes Schmidt-Ehrenberg Date: Mon, 13 Aug 2007 19:00:39 +0200 Subject: [PATCH 200/781] mergetool: fixed parsing of registry entry for kdiff3 The old code failed on Windows Vista. The output of reg.exe or something else may be a bit different. This patch improves the parsing code to be more robust. Signed-off-by: Steffen Prohaska --- git-mergetool.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-mergetool.sh b/git-mergetool.sh index e7d745062b..54f6d58a84 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -323,7 +323,7 @@ if test -z "$merge_tool" ; then fi fi regentry="$(REG QUERY 'HKEY_LOCAL_MACHINE\SOFTWARE\KDiff3\diff-ext' 2>/dev/null)" && { - KDIFF3=$(echo "$regentry" | grep diffcommand | cut -f 3 | sed -e 's@\\@/@g') + KDIFF3=$(echo "$regentry" | grep diffcommand | awk -F 'REG_SZ' '{ print $2 }' | sed -e 's/^ *//'| sed -e 's@\\@/@g') KDIFF3SEPARATOR= merge_tool_candidates="$merge_tool_candidates kdiff3" } From fce4254719a628b469c7a8c1a2ceb025e630bf2a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 20 Aug 2007 16:36:58 +0200 Subject: [PATCH 201/781] Fix an infinite loop in setup_git_directory_gently(). When a git command was invoked outside any git directory, it would not terminate. --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index d575529ac9..404191ab8f 100644 --- a/setup.c +++ b/setup.c @@ -302,7 +302,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } chdir(".."); do { - if (!offset) { + if (offset <= minoffset) { if (nongit_ok) { if (chdir(cwd)) die("Cannot come back to cwd"); From ae3d370abf6ae61f5b15d3ad5703023080124872 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Fri, 24 Aug 2007 08:36:30 +0200 Subject: [PATCH 202/781] Add patch from Linus, to make write-tree read the configuration, in case it datestamps are so close that it needs to ce_smudge_racily_clean_entry(), thus read the content of the file and compare. The core.autocrlf value is needed in this case. Signed-off-by: Marius Storm-Olsen --- builtin-write-tree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin-write-tree.c b/builtin-write-tree.c index 88f34ba7d6..b89d02efec 100644 --- a/builtin-write-tree.c +++ b/builtin-write-tree.c @@ -72,6 +72,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) const char *prefix = NULL; unsigned char sha1[20]; + git_config(git_default_config); while (1 < argc) { const char *arg = argv[1]; if (!strcmp(arg, "--missing-ok")) From dd56555ea5cd03958dc2f987f2776efbab571452 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 23 Aug 2007 22:03:35 +0200 Subject: [PATCH 203/781] Add a trace to more easily show that the index has been smudged. Signed-off-by: Marius Storm-Olsen --- read-cache.c | 1 + 1 file changed, 1 insertion(+) diff --git a/read-cache.c b/read-cache.c index 84c6b47eb8..23d16a40ef 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1104,6 +1104,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) * for "frotz" stays 6 which does not match the filesystem. */ ce->ce_size = htonl(0); + trace_printf("trace: index: Index object for '%s' smudged due to being racily clean\n", ce->name); } } From 6e6b01d5d308a9bbb5d73cd9272d8736039d83a2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 29 Aug 2007 13:34:54 +0200 Subject: [PATCH 204/781] Add a primitive implementation for getppid(). --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index 22a53d3668..1ba499f750 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -483,6 +483,7 @@ int mingw_rename(const char*, const char*); #define setlinebuf(x) #define fsync(x) 0 +#define getppid() 1 extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From 14e86ec37e13f6018513c630f4b8b54096e794f0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 29 Aug 2007 14:49:47 +0200 Subject: [PATCH 205/781] Use 'pwd -W' as reference directory. git does not know about the notation /x/dir/ec/tory that MSYS uses instead of x:/dir/ec/tory; hence, when git's notion of an absolute path is compared to the shell's notion, the shell must produce the x:/ kind of path. --- t/t0001-init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index b14b3ec394..ca5b631012 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -97,7 +97,7 @@ test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' ' mkdir git-dir-wt-1.git && GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init ) && - check_config git-dir-wt-1.git false "$(pwd)" + check_config git-dir-wt-1.git false "$(pwd -W)" ' test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' ' From 205d0cb456f7d253f6fcd0566528c1d2796f0be5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 29 Aug 2007 14:50:58 +0200 Subject: [PATCH 206/781] Use /usr/bin/find instead of plain find. --- t/t9300-fast-import.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 0595041af5..a64f78f5a0 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -880,7 +880,7 @@ INPUT_END test_expect_success \ 'O: blank lines not necessary after other commands' \ 'git-fast-import actual && git diff expect actual' From 194c1dbb5a04e29937b87d477a16927fa2c3be62 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Aug 2007 14:16:46 +0100 Subject: [PATCH 207/781] Provide git_exit() for MinGW Apparently, MinGW's exit function has problems with negative exit codes. Substitute them by 1. This fixes at least t1300, which failed because the exit code of git-config with an invalid file was 0. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 9 +++++++++ git-compat-util.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index ca3ae4cb06..6632192690 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -322,3 +322,12 @@ int mingw_socket(int domain, int type, int protocol) } return s; } + +#undef exit +int git_exit(int code) +{ + if (code < 0) + exit(1); + exit(code); +} + diff --git a/git-compat-util.h b/git-compat-util.h index ddafec997f..9e075b715c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -472,6 +472,9 @@ int mingw_socket(int domain, int type, int protocol); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +extern __attribute__((noreturn)) int git_exit(int code); +#define exit git_exit + #endif /* __MINGW32__ */ #endif From b01b123d9dea5658a5e8eb8d392c5cdbe23256a5 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Wed, 29 Aug 2007 15:35:00 +0200 Subject: [PATCH 208/781] Fix error 'fatal: Not a git repository' on Vista Define __USE_MINGW_ACCESS, which changes access( ..., X_OK ) into F_OK. Signed-off-by: Dmitry Kakurin gmail.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f828f6cd12..9669817bf4 100644 --- a/Makefile +++ b/Makefile @@ -493,7 +493,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRTOUMAX = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -I compat + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From fce2bf8842e8224822619afabff1bfcfc3546436 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 17 Aug 2007 14:50:29 +0200 Subject: [PATCH 209/781] Revert fa807fcb: 'Revert "Makefile: remove $foo when $foo.exe...' It works in msysgit, so there is no reason why we should not remove the scripted versions. Especially since some tests were failing for the sole reason that _not_ the builtin, but the script was executed. Signed-off-by: Johannes Schindelin --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 9669817bf4..bc8e9d2125 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # The default target of this Makefile is... -all: +all:: # Define V=1 to have a more verbose compile. # @@ -752,9 +752,12 @@ export TAR INSTALL DESTDIR SHELL_PATH ### Build rules -all: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';) +endif -all: +all:: ifndef NO_TCLTK $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all endif @@ -982,7 +985,7 @@ endif TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X -all: $(TEST_PROGRAMS) +all:: $(TEST_PROGRAMS) # GNU make supports exporting all variables by "export" without parameters. # However, the environment gets quite big, and some programs have problems @@ -1030,6 +1033,9 @@ endif '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \ fi $(foreach p,$(BUILT_INS), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';) +endif install-doc: $(MAKE) -C Documentation install From 5464a3f4b7fdc844253b5d64b0b311fde31ee1b2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Aug 2007 17:43:02 +0100 Subject: [PATCH 210/781] t5701: "wc -l" may add whitespace Signed-off-by: Johannes Schindelin --- t/t5701-clone-local.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index d2f55ebfbc..7e7019fa31 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -54,8 +54,7 @@ test_expect_success 'With -no-hardlinks, local will make a copy' ' cd "$D" && git clone --bare --no-hardlinks x w && cd w && - linked=$(find objects -type f ! -links 1 | wc -l) && - test "$linked" = 0 + test $(find objects -type f ! -links 1 | wc -l) = 0 ' test_expect_success 'Even without -l, local will make a hardlink' ' @@ -63,8 +62,7 @@ test_expect_success 'Even without -l, local will make a hardlink' ' rm -fr w && git clone -l --bare x w && cd w && - copied=$(find objects -type f -links 1 | wc -l) && - test "$copied" = 0 + test $(find objects -type f -links 1 | wc -l) = 0 ' test_done From 685268d9a1d4db52c62e022a7543a5c092ac8fec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Aug 2007 17:57:08 +0100 Subject: [PATCH 211/781] t5701: skip hardlink test Signed-off-by: Johannes Schindelin --- t/t5701-clone-local.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index 7e7019fa31..e97f435fec 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -57,6 +57,10 @@ test_expect_success 'With -no-hardlinks, local will make a copy' ' test $(find objects -type f ! -links 1 | wc -l) = 0 ' +say "hardlinks not supported, skipping tests." +test_done +exit 0 + test_expect_success 'Even without -l, local will make a hardlink' ' cd "$D" && rm -fr w && From a19cff248ece3693f5dc6ad75a70a3e68606a1f9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 17:42:54 +0100 Subject: [PATCH 212/781] verify-tag: also grok CR/LFs in the tag signature On some people's favorite platform, gpg outputs signatures with CR/LF line endings. So verify-tag has to play nice with them. Signed-off-by: Johannes Schindelin --- builtin-verify-tag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index 5c1314d071..8cfefcf523 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -35,7 +35,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose) /* find the length without signature */ len = 0; - while (len < size && prefixcmp(buf + len, PGP_SIGNATURE "\n")) { + while (len < size && prefixcmp(buf + len, PGP_SIGNATURE)) { eol = memchr(buf + len, '\n', size - len); len += eol ? eol - (buf + len) + 1 : size - len; } From 7734ad404c48ea376fed1ce5e9e04f72ec4cb0bd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 17:36:47 +0100 Subject: [PATCH 213/781] MinGW: Convert CR/LF to LF in tag signatures On Windows, gpg outputs CR/LF signatures. But since the tag messages are already stripped of the CR by stripspace(), it is arguably nicer to do the same for the tag signature. Actually, this patch does not look for CR/LF, but strips all CRs from the signature. Signed-off-by: Johannes Schindelin --- builtin-tag.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/builtin-tag.c b/builtin-tag.c index d6d38ad123..547f0ba224 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -229,6 +229,20 @@ static ssize_t do_sign(char *buffer, size_t size, size_t max) if (len == max - size) return error("could not read the entire signature from gpg."); +#ifdef __MINGW32__ + /* strip CR from the line endings */ + { + int i, j; + for (i = j = 0; i < len; i++) + if (buffer[size + i] != '\r') { + if (i != j) + buffer[size + j] = buffer[size + i]; + j++; + } + len = j; + } +#endif + return size + len; } From b9dcb2cbe55afa21af7eed9f49e319b183954748 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 19:55:09 +0100 Subject: [PATCH 214/781] Fix cpio for CR/LF line endings Under certain circumstances (I did not find out the complete details, but it happens when running the tests), the filterdirs() function in cpio outputs CR/LF. Since tar does not like that, the command failed. So strip out all CRs when filtering the directories. Signed-off-by: Johannes Schindelin --- cpio.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cpio.sh b/cpio.sh index 2816e34851..432903813b 100644 --- a/cpio.sh +++ b/cpio.sh @@ -44,6 +44,7 @@ o) p) test -z "$null" || die "cpio: cannot use -0 in pass-through mode" filterdirs | + tr -d '\r' | tar --create --file=- --files-from=- | tar --extract --directory="$dir" --file=- ;; From 59f8c189a5d582d5eef28ca4021d04087dff2eff Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Aug 2007 10:18:54 -0700 Subject: [PATCH 215/781] Fix racy-git handling in git-write-tree. After git-write-tree finishes computing the tree, it updates the index so that later operations can take advantage of fully populated cache tree. However, anybody writing the index file has to mark the entries that are racily clean. For each entry whose cached lstat(3) data in the index exactly matches what is obtained from the filesystem, if the timestamp on the index file was the same or older than the modification timestamp of the file, the blob contents and the work tree file, after convert_to_git(), need to be compared, and if they are different, its index entry needs to be marked not to match the lstat(3) data from the filesystem. In order for this to work, convert_to_git() needs to work correctly, which in turn means you need to read the config file to get the settings of core.crlf and friends. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- t/t0023-crlf-am.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 t/t0023-crlf-am.sh diff --git a/t/t0023-crlf-am.sh b/t/t0023-crlf-am.sh new file mode 100755 index 0000000000..6f8a4347d5 --- /dev/null +++ b/t/t0023-crlf-am.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +test_description='Test am with auto.crlf' + +. ./test-lib.sh + +cat >patchfile <<\EOF +From 38be10072e45dd6b08ce40851e3fca60a31a340b Mon Sep 17 00:00:00 2001 +From: Marius Storm-Olsen +Date: Thu, 23 Aug 2007 13:00:00 +0200 +Subject: test1 + +--- + foo | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + create mode 100644 foo + +diff --git a/foo b/foo +new file mode 100644 +index 0000000000000000000000000000000000000000..5716ca5987cbf97d6bb54920bea6adde242d87e6 +--- /dev/null ++++ b/foo +@@ -0,0 +1 @@ ++bar +EOF + +test_expect_success 'setup' ' + + git config core.autocrlf true && + echo foo >bar && + git add bar && + test_tick && + git commit -m initial + +' + +test_expect_success 'am' ' + + git am --binary -3 Date: Tue, 4 Sep 2007 02:00:46 +0100 Subject: [PATCH 216/781] t7004: work around weird quoting issue with MSys It seems to be impossible to pass the _string_ '*a*' if there is _any_ file in the current directory whose name contains the letter 'a'. So remove all such files for the test that needs to pass that string. Signed-off-by: Johannes Schindelin --- t/t7004-tag.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 2ac0003f9e..2aa663e622 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -185,8 +185,9 @@ cba EOF test_expect_success \ 'listing tags with substring as pattern must print those matching' ' - git-tag -l "*a*" > actual && - git diff expect actual + rm *a* && + git-tag -l "*a*" > current && + git diff expect current ' cat >expect < Date: Tue, 4 Sep 2007 02:01:52 +0100 Subject: [PATCH 217/781] t0001: fix test on MinGW Another instance where we need the "-W" parameter to "pwd". Signed-off-by: Johannes Schindelin --- t/t0001-init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index b14b3ec394..ca5b631012 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -97,7 +97,7 @@ test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' ' mkdir git-dir-wt-1.git && GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init ) && - check_config git-dir-wt-1.git false "$(pwd)" + check_config git-dir-wt-1.git false "$(pwd -W)" ' test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' ' From 54d99a7724a0c7fb53bcdc7d850034e9890a0138 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:02:27 +0100 Subject: [PATCH 218/781] fast-import: fix compilation on MinGW MinGW does not have getppid(). So do not print it. Signed-off-by: Johannes Schindelin --- fast-import.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fast-import.c b/fast-import.c index 078079d404..1d116e7878 100644 --- a/fast-import.c +++ b/fast-import.c @@ -392,7 +392,9 @@ static void write_crash_report(const char *err) fprintf(rpt, "fast-import crash report:\n"); fprintf(rpt, " fast-import process: %d\n", getpid()); +#ifndef __MINGW32__ fprintf(rpt, " parent process : %d\n", getppid()); +#endif fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL)); fputc('\n', rpt); From d23130a5fb430c54bb928dcd4446fd98a2a9173d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:03:55 +0100 Subject: [PATCH 219/781] git-compat-util.h: declare mkstemp() before use On MinGW, we roll our own version of mkstemp(). Since xmkstemp() uses it, we need to declare it before that. Signed-off-by: Johannes Schindelin --- git-compat-util.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index f817c28164..ba5a1a1018 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -314,6 +314,9 @@ static inline FILE *xfdopen(int fd, const char *mode) return stream; } +#ifdef __MINGW32__ +int mkstemp (char *__template); +#endif static inline int xmkstemp(char *template) { int fd; @@ -435,7 +438,6 @@ int kill(pid_t pid, int sig); unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); -int mkstemp (char *__template); int gettimeofday(struct timeval *tv, void *tz); int pipe(int filedes[2]); From 9c792c5545415dfcbb60f819b9555bbe874a508c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:18:52 +0100 Subject: [PATCH 220/781] Fix t3200 on MinGW Since we try to launch the webbrowser with "git --help", one test in t3200 would always try to open a window with the man page for git-branch. Suppress that test for now. Signed-off-by: Johannes Schindelin --- t/t3200-branch.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index a891fa47d3..029f19d6fa 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -17,6 +17,7 @@ test_expect_success \ git-commit -m "Initial commit." && HEAD=$(git rev-parse --verify HEAD)' +true || test_expect_failure \ 'git branch --help should not have created a bogus branch' \ 'git branch --help /dev/null 2>/dev/null || : From 0cce83445cb03b9ae93c2f7f3427e0ca2063dc73 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Mon, 3 Sep 2007 20:40:26 +0200 Subject: [PATCH 221/781] Add a new lstat and fstat implementation based on Win32 API This gives us a significant speedup when adding, committing and stat'ing files. Also, since Windows doesn't really handle symlinks, we let stat just uses lstat. We also need to replace fstat, since our implementation and the standard stat() functions report slightly different timestamps, possibly due to timezones. We simply report UTC in our implementation, and do our FILETIME to time_t conversion based on the document at http://support.microsoft.com/kb/167296. With Moe's repo structure (100K files in 100 dirs, containing 2-4 bytes) mkdir bummer && cd bummer; for ((i=0;i<100;i++)); do mkdir $i && pushd $i; for ((j=0;j<1000;j++)); do echo "$j" >$j; done; popd; done We get the following performance boost: With normal lstat & stat Custom lstat/fstat ------------------------ ------------------------ Command: git init Command: git init ------------------------ ------------------------ real 0m 0.047s real 0m 0.063s user 0m 0.031s user 0m 0.015s sys 0m 0.000s sys 0m 0.015s ------------------------ ------------------------ Command: git add . Command: git add . ------------------------ ------------------------ real 0m19.390s real 0m12.031s 1.6x user 0m 0.015s user 0m 0.031s sys 0m 0.030s sys 0m 0.000s ------------------------ ------------------------ Command: git commit -a.. Command: git commit -a.. ------------------------ ------------------------ real 0m30.812s real 0m16.875s 1.8x user 0m 0.015s user 0m 0.015s sys 0m 0.000s sys 0m 0.015s ------------------------ ------------------------ 3x Command: git-status 3x Command: git-status ------------------------ ------------------------ real 0m11.860s real 0m 5.266s 2.2x user 0m 0.015s user 0m 0.015s sys 0m 0.015s sys 0m 0.015s real 0m11.703s real 0m 5.234s user 0m 0.015s user 0m 0.015s sys 0m 0.000s sys 0m 0.000s real 0m11.672s real 0m 5.250s user 0m 0.031s user 0m 0.015s sys 0m 0.000s sys 0m 0.000s ------------------------ ------------------------ Command: git commit... Command: git commit... (single file) (single file) ------------------------ ------------------------ real 0m14.234s real 0m 7.735s 1.8x user 0m 0.015s user 0m 0.031s sys 0m 0.000s sys 0m 0.000s Signed-off-by: Marius Storm-Olsen --- compat/mingw.c | 107 ++++++++++++++++++++++++++++++++++++++++++++-- git-compat-util.h | 8 ++++ 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7711a3fb39..20eadd2334 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -23,12 +23,81 @@ int fchmod(int fildes, mode_t mode) return -1; } -int lstat(const char *file_name, struct stat *buf) +static inline time_t filetime_to_time_t(const FILETIME *ft) +{ + long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; + winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ + winTime /= 10000000; /* Nano to seconds resolution */ + return (time_t)winTime; +} + +extern int _getdrive( void ); +/* We keep the do_lstat code in a separate function to avoid recursion. + * When a path ends with a slash, the stat will fail with ENOENT. In + * this case, we strip the trailing slashes and stat again. + */ +static int do_lstat(const char *file_name, struct stat *buf) +{ + WIN32_FILE_ATTRIBUTE_DATA fdata; + + if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) { + int fMode = S_IREAD; + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + fMode |= S_IFDIR; + else + fMode |= S_IFREG; + if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWRITE; + + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = fMode; + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + errno = 0; + return 0; + } + + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_SHARING_BUFFER_EXCEEDED: + errno = EACCES; + break; + case ERROR_BUFFER_OVERFLOW: + errno = ENAMETOOLONG; + break; + case ERROR_NOT_ENOUGH_MEMORY: + errno = ENOMEM; + break; + case ERROR_INVALID_NAME: + errno = EFAULT; + break; + default: + errno = ENOENT; + break; + } + return -1; +} + +/* We provide our own lstat/fstat functions, since the provided + * lstat/fstat functions are so slow. These stat functions are + * tailored for Git's usage (read: fast), and are not meant to be + * complete. Note that Git stat()s are redirected to git_lstat() + * too, since Windows doesn't really handle symlinks that well. + */ +int git_lstat(const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; - if (!stat(file_name, buf)) + if (!do_lstat(file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -36,6 +105,7 @@ int lstat(const char *file_name, struct stat *buf) */ if (errno != ENOENT) return -1; + namelen = strlen(file_name); if (namelen && file_name[namelen-1] != '/') return -1; @@ -43,9 +113,40 @@ int lstat(const char *file_name, struct stat *buf) --namelen; if (!namelen || namelen >= PATH_MAX) return -1; + memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return stat(alt_name, buf); + return do_lstat(alt_name, buf); +} + +int git_fstat(int fd, struct stat *buf) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + BY_HANDLE_FILE_INFORMATION fdata; + + if (fh != INVALID_HANDLE_VALUE && GetFileInformationByHandle(fh, &fdata)) { + int fMode = S_IREAD; + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + fMode |= S_IFDIR; + else + fMode |= S_IFREG; + if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWRITE; + + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = fMode; + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + return 0; + } + errno = EBADF; + return -1; } /* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ diff --git a/git-compat-util.h b/git-compat-util.h index 1ba499f750..bdc2e3f5fc 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -488,6 +488,14 @@ int mingw_rename(const char*, const char*); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +/* Use git_lstat() instead of lstat()/stat() and + * git_fstat() instead of fstat() on Windows + */ +int git_lstat(const char *file_name, struct stat *buf); +int git_fstat(int fd, struct stat *buf); +#define lstat(x,y) git_lstat(x,y) +#define stat(x,y) git_lstat(x,y) +#define fstat(x,y) git_fstat(x,y) #endif /* __MINGW32__ */ #endif From 01e3a15dd29ccbb1bca252c0da6b37a3f2dce958 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Wed, 5 Sep 2007 04:32:50 -0700 Subject: [PATCH 222/781] Fixed text file auto-detection: treat EOF character 032 at the end of file as printable Signed-off-by: Dmitry Kakurin --- convert.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/convert.c b/convert.c index 21908b1039..b288552280 100644 --- a/convert.c +++ b/convert.c @@ -58,6 +58,10 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * else stats->printable++; } + + // If file ends with EOF then don't count this EOF as non-printable + if ( size >= 1 && buf[size-1] == '\032' ) + stats->nonprintable--; } /* From ade2a2dba35b2ee97e7a46bbc57a9bd1e3b24348 Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 12 Sep 2007 11:46:39 -0400 Subject: [PATCH 223/781] git-gui: Correct error of not finding /share/git-gui/lib/tclIndex. Where the Makefile tests for Cygwin, it also needs to test for MINGW. Signed-off-by: Mike Pape --- git-gui/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index 1bac6fed46..d8c5e65370 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -8,6 +8,7 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE -include GIT-VERSION-FILE uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') SCRIPT_SH = git-gui.sh GITGUI_BUILT_INS = git-citool @@ -86,7 +87,8 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)rm -f $@ $@+ && \ GITGUI_RELATIVE= && \ if test '$(exedir_SQ)' = '$(libdir_SQ)'; then \ - if test "$(uname_O)" = Cygwin; \ + if test "$(uname_O)" = Cygwin \ + -o "$(findstring MINGW,$(uname_S))" = MINGW; \ then GITGUI_RELATIVE= ; \ else GITGUI_RELATIVE=1; \ fi; \ From 6a561a80d5e02cd6364c577b8fc628bf8090ebff Mon Sep 17 00:00:00 2001 From: Mike Pape Date: Wed, 12 Sep 2007 18:46:39 -0400 Subject: [PATCH 224/781] Revert "git-gui: Correct error of not finding /share/git-gui/lib/tclIndex." This reverts commit ade2a2dba35b2ee97e7a46bbc57a9bd1e3b24348. --- git-gui/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index d8c5e65370..1bac6fed46 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -8,7 +8,6 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE -include GIT-VERSION-FILE uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') SCRIPT_SH = git-gui.sh GITGUI_BUILT_INS = git-citool @@ -87,8 +86,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)rm -f $@ $@+ && \ GITGUI_RELATIVE= && \ if test '$(exedir_SQ)' = '$(libdir_SQ)'; then \ - if test "$(uname_O)" = Cygwin \ - -o "$(findstring MINGW,$(uname_S))" = MINGW; \ + if test "$(uname_O)" = Cygwin; \ then GITGUI_RELATIVE= ; \ else GITGUI_RELATIVE=1; \ fi; \ From 3b9b1450636df0ceeb791e1f3837b5f711ae391e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 15:22:13 +0100 Subject: [PATCH 225/781] gitk: force focus to main window On msysGit, the focus is first on the (Tk) console. This console is then hidden, but keeps the focus. Work around that by forcing the focus onto the gitk window. This fixes issue 14. Signed-off-by: Johannes Schindelin --- gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk b/gitk index b3ca704bf7..89b6398963 100755 --- a/gitk +++ b/gitk @@ -8005,4 +8005,5 @@ if {[info exists permviews]} { addviewmenu $n } } +focus -force . getcommits From 416488563ef2f68c7ceaec016c4e96ab2fd45ba7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 15:54:53 +0100 Subject: [PATCH 226/781] Revert bd2f73a6(Support the tools scripted in perl.) This is not needed in msysGit, since we call Perl from inside MSys, and therefore paths are handled gracefully. Incidentally, it fixes issue 46 (msysGit fails to install in paths beginning with C). This reverts bd2f73a6ba6daf6158112874414d338c7b0e528d. Signed-off-by: Johannes Schindelin --- perl/Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/perl/Makefile b/perl/Makefile index f7dbfca616..5e079ad011 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -20,11 +20,7 @@ clean: $(RM) $(makfile).old ifdef NO_PERL_MAKEMAKER -# We exploit that /bin/sh transforms the DOS-Stype path in TEMP into -# the MSYS style pseudo-mount form. -# This colon-free from is needed because our perl scripts look at -# $(instdir_SQ) and split it at colons. -instdir_SQ = $(subst ','\'',$(shell cmd /x/d/c "set TEMP=$(prefix)/lib && sh -c 'echo \$$TEMP'")) +instdir_SQ = $(subst ','\'',$(prefix)/lib) $(makfile): ../GIT-CFLAGS Makefile echo all: > $@ echo ' :' >> $@ From 74c2a08ef9ec16ce4cb3daef0b65fad439448538 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 16:22:00 +0100 Subject: [PATCH 227/781] Do not complain about "no common commits" in an empty repo If the repo is empty, we know that already, thank you very much. So shut fetch-pack up about that case. Fixes issue 3, too. Signed-off-by: Johannes Schindelin --- fetch-pack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fetch-pack.c b/fetch-pack.c index b6470932fb..ff79e56ac4 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -289,7 +289,8 @@ done: } flushes--; } - return retval; + /* it is no error to fetch into a completely empty repo */ + return count ? retval : 0; } static struct commit_list *complete; From b49fa05b92a7a369beca1de67fded5a6da500f9c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 20 Sep 2007 14:58:00 +0200 Subject: [PATCH 228/781] Handle fstat() of a socket descriptor. GetFileInformationByHandle() fails if it is passed a WinSock handle. Fortunately, the failure can be distinguished by the error code, and we can in this case pretend that the fstat() was actually successful. This is a valid thing to do: Calling fstat() on a descriptor makes only sense if either the caller needs information on the file (in which case we would not reach this error condition), or if it wants to distinguish a socket from a file (which implies that the caller will have to test st_mode, which happens to be the only field that we can fill in). Signed-off-by: Johannes Sixt --- compat/mingw.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 20eadd2334..166e2ad5f0 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -123,8 +123,14 @@ int git_fstat(int fd, struct stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; + char dummy[sizeof(void*)]; + int s = sizeof(void*); - if (fh != INVALID_HANDLE_VALUE && GetFileInformationByHandle(fh, &fdata)) { + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) fMode |= S_IFDIR; @@ -145,7 +151,22 @@ int git_fstat(int fd, struct stat *buf) buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); return 0; } - errno = EBADF; + switch (GetLastError()) { + case ERROR_INVALID_FUNCTION: + /* check for socket */ + if (getsockopt((int)fh, SOL_SOCKET, SO_KEEPALIVE, dummy, &s) && + WSAGetLastError() == WSAENOTSOCK) + goto badf; + memset(buf, sizeof(*buf), 0); + buf->st_mode = S_IREAD|S_IWRITE; + buf->st_mode |= 0x140000; /* S_IFSOCK */ + return 0; + default: + case ERROR_INVALID_HANDLE: + badf: + errno = EBADF; + break; + } return -1; } From a64e23954fc617019354a929dcefaa6049c2f744 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 21 Sep 2007 21:31:51 +0200 Subject: [PATCH 229/781] git-commit: Implement racy-safe save_index() with ln instead of cp -p. git-commit must allocate a copy of the current index if only a subset of files is to be commited in save_index(). It uses 'cp -p' because the index may contain racily-clean entries, which will be detected only if the timestamp of the index remains unaltered. In general, it is safe to create a hardlink instead of copying the index because all writers use the lock_file infrastructure that writes a new file and moves it into the destination, breaking the hardlink. On Windows, in particular, 'cp -p' suffers from a mysterious inability to accurately preserve the timestamp under some circumstances. (This was detected by the test suite, where some racily clean files were not recognized.) 'ln' does create a hardlink on Windows on NTFS, and makes a copy with the correctly preserved timestamp on FAT. Signed-off-by: Johannes Sixt --- git-commit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-commit.sh b/git-commit.sh index 1d04f1ff31..427b48dd8b 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -29,7 +29,7 @@ THIS_INDEX="$GIT_DIR/index" NEXT_INDEX="$GIT_DIR/next-index$$" rm -f "$NEXT_INDEX" save_index () { - cp -p "$THIS_INDEX" "$NEXT_INDEX" + ln "$THIS_INDEX" "$NEXT_INDEX" } run_status () { From cd4ce16f0fa35828ce33cc2fa90b4ab6528a28ea Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 9 Sep 2007 21:00:47 +0200 Subject: [PATCH 230/781] Work around incompatible sort and find on windows. If the PATH lists the Windows system directories before the MSYS directories, Windows's own incompatible sort and find commands would be picked up. We implement these commands as functions and call the real tools by absolute path. Also add a dummy implementation of sync to avoid an error in git-repack. Signed-off-by: Johannes Sixt --- git-clone.sh | 10 ++++++++++ git-ls-remote.sh | 13 +++++++++++++ git-sh-setup.sh | 17 +++++++++++++++++ t/test-lib.sh | 13 +++++++++++++ 4 files changed, 53 insertions(+) diff --git a/git-clone.sh b/git-clone.sh index 7796201ada..e262f77136 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -13,6 +13,16 @@ die() { exit 1 } +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) find + find () { + /usr/bin/find "$@" + } + ;; +esac + usage() { die "Usage: $0 [--template=] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [--depth ] [-n] []" } diff --git a/git-ls-remote.sh b/git-ls-remote.sh index 4d37934f62..0d7508407b 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -12,6 +12,19 @@ die () { exit 1 } +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) sort and find + sort () { + /usr/bin/sort "$@" + } + find () { + /usr/bin/find "$@" + } + ;; +esac + exec= while case "$#" in 0) break;; esac do diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 185c5c6c95..74b2389d9a 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -129,3 +129,20 @@ test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || { } : ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"} + +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) sort and find + sort () { + /usr/bin/sort "$@" + } + find () { + /usr/bin/find "$@" + } + # sync is missing + sync () { + : # no implementation + } + ;; +esac diff --git a/t/test-lib.sh b/t/test-lib.sh index a3f3d7c922..fed377fc1c 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -305,3 +305,16 @@ do test_done esac done + +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # Windows has its own (incompatible) sort and find + sort () { + /usr/bin/sort "$@" + } + find () { + /usr/bin/find "$@" + } + ;; +esac From b14adeb12da86dcea9dc683ab5970f176471ca36 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 9 Sep 2007 21:01:15 +0200 Subject: [PATCH 231/781] Undo /usr/bin/sort and /usr/bin/find workarounds. --- contrib/examples/git-tag.sh | 2 +- git-clone.sh | 6 +++--- git-ls-remote.sh | 4 ++-- git-mergetool.sh | 4 ++-- git-repack.sh | 4 ++-- t/t0000-basic.sh | 8 ++++---- t/t1200-tutorial.sh | 2 +- t/t2001-checkout-cache-clash.sh | 2 +- t/t3100-ls-tree-restrict.sh | 2 +- t/t3101-ls-tree-dirname.sh | 2 +- t/t4112-apply-renames.sh | 2 +- t/t5000-tar-tree.sh | 14 +++++++------- t/t5300-pack-object.sh | 6 +++--- t/t6003-rev-list-topo-order.sh | 2 +- t/t9107-git-svn-migrate.sh | 2 +- t/t9200-git-cvsexportcommit.sh | 4 ++-- t/t9300-fast-import.sh | 2 +- 17 files changed, 34 insertions(+), 34 deletions(-) diff --git a/contrib/examples/git-tag.sh b/contrib/examples/git-tag.sh index 181b9a7e97..5ee3f50a3c 100755 --- a/contrib/examples/git-tag.sh +++ b/contrib/examples/git-tag.sh @@ -53,7 +53,7 @@ do shift ;; esac - git rev-parse --symbolic --tags | /usr/bin/sort | + git rev-parse --symbolic --tags | sort | while read TAG do case "$TAG" in diff --git a/git-clone.sh b/git-clone.sh index e262f77136..6de44cde1f 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -285,7 +285,7 @@ yes) then # See if we can hardlink and drop "l" if not. sample_file=$(cd "$repo" && \ - /usr/bin/find objects -type f -print | sed -e 1q) + find objects -type f -print | sed -e 1q) # objects directory should not be empty because # we are cloning! test -f "$repo/$sample_file" || exit @@ -299,7 +299,7 @@ yes) fi fi && cd "$repo" && - /usr/bin/find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 + find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1 fi git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 ;; @@ -416,7 +416,7 @@ then ( test -f "$GIT_DIR/$remote_top/master" && echo "master" cd "$GIT_DIR/$remote_top" && - /usr/bin/find . -type f -print | sed -e 's/^\.\///' + find . -type f -print | sed -e 's/^\.\///' ) | ( done=f while read name diff --git a/git-ls-remote.sh b/git-ls-remote.sh index 0d7508407b..984cef4dd0 100755 --- a/git-ls-remote.sh +++ b/git-ls-remote.sh @@ -92,7 +92,7 @@ rsync://* ) head=$(cat "$tmpdir/$head") || exit esac && echo "$head HEAD" - (cd $tmpdir && /usr/bin/find refs -type f) | + (cd $tmpdir && find refs -type f) | while read path do tr -d '\012' <"$tmpdir/$path" @@ -111,7 +111,7 @@ rsync://* ) fi ;; esac | -/usr/bin/sort -t ' ' -k 2 | +sort -t ' ' -k 2 | while read sha1 path do case "$sha1" in diff --git a/git-mergetool.sh b/git-mergetool.sh index e6bbb6bbd6..47a80553ad 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -364,13 +364,13 @@ case "$merge_tool" in esac if test $# -eq 0 ; then - files=`git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u` + files=`git ls-files -u | sed -e 's/^[^ ]* //' | sort -u` if test -z "$files" ; then echo "No files need merging" exit 0 fi echo Merging the files: $files - git ls-files -u | sed -e 's/^[^ ]* //' | /usr/bin/sort -u | while read i + git ls-files -u | sed -e 's/^[^ ]* //' | sort -u | while read i do printf "\n" merge_file "$i" < /dev/tty > /dev/tty diff --git a/git-repack.sh b/git-repack.sh index a8f44097e0..156c5e8f4a 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -48,7 +48,7 @@ case ",$all_into_one," in ;; ,t,) if [ -d "$PACKDIR" ]; then - for e in `cd "$PACKDIR" && /usr/bin/find . -type f -name '*.pack' \ + for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \ | sed -e 's/^\.\///' -e 's/\.pack$//'` do if [ -e "$PACKDIR/$e.keep" ]; then @@ -105,7 +105,7 @@ then # We know $existing are all redundant. if [ -n "$existing" ] then - sync 2> /dev/null + sync ( cd "$PACKDIR" && for e in $existing do diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index a213268cd6..0d8c4b18ba 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -50,14 +50,14 @@ test "$no_symlinks" && { # git init has been done in an empty repository. # make sure it is empty. -/usr/bin/find .git/objects -type f -print >should-be-empty +find .git/objects -type f -print >should-be-empty test_expect_success \ '.git/objects should be empty after git init in an empty repo.' \ 'cmp -s /dev/null should-be-empty' # also it should have 2 subdirectories; no fan-out anymore, pack, and info. # 3 is counting "objects" itself -/usr/bin/find .git/objects -type d -print >full-of-directories +find .git/objects -type d -print >full-of-directories test_expect_success \ '.git/objects should have 3 subdirectories.' \ 'test $(wc -l < full-of-directories) = 3' @@ -112,7 +112,7 @@ do done test_expect_success \ 'adding various types of objects with git update-index --add.' \ - '/usr/bin/find path* ! -type d -print | xargs git update-index --add' + 'find path* ! -type d -print | xargs git update-index --add' # Show them and see that matches what we expect. test_expect_success \ @@ -289,7 +289,7 @@ test_expect_success \ 'commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && parent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | - /usr/bin/sort -u) && + sort -u) && test "z$commit0" = "z$parent" && numparent=$(git show --pretty=raw $commit2 | sed -n -e "s/^parent //p" -e "/^author /q" | diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index 5cd9c48ddf..991d3c5e9c 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -156,6 +156,6 @@ test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.outp test_expect_success 'git repack' 'git repack' test_expect_success 'git prune-packed' 'git prune-packed' -test_expect_failure '-> only packed objects' '/usr/bin/find -type f .git/objects/[0-9a-f][0-9a-f]' +test_expect_failure '-> only packed objects' 'find -type f .git/objects/[0-9a-f][0-9a-f]' test_done diff --git a/t/t2001-checkout-cache-clash.sh b/t/t2001-checkout-cache-clash.sh index 45b4bc47d6..c1e236e932 100755 --- a/t/t2001-checkout-cache-clash.sh +++ b/t/t2001-checkout-cache-clash.sh @@ -23,7 +23,7 @@ the symlink path1 and create directory path1 and file path1/file1. show_files() { # show filesystem files, just [-dl] for type and name - /usr/bin/find path? -ls | + find path? -ls | sed -e 's/^[0-9]* * [0-9]* * \([-bcdl]\)[^ ]* *[0-9]* *[^ ]* *[^ ]* *[0-9]* [A-Z][a-z][a-z] [0-9][0-9] [^ ]* /fs: \1 /' # what's in the cache, just mode and name git ls-files --stage | diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh index 4794fdd9eb..40c6f1d31f 100755 --- a/t/t3100-ls-tree-restrict.sh +++ b/t/t3100-ls-tree-restrict.sh @@ -38,7 +38,7 @@ test_expect_success \ echo Lo >path2/foo && ln -s ../path1 path2/bazbo && echo Mi >path2/baz/b && - /usr/bin/find path? \( -type f -o -type l \) -print | + find path? \( -type f -o -type l \) -print | xargs git update-index --add && tree=`git write-tree` && echo $tree' diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh index e6ebe51d1d..39fe2676dc 100755 --- a/t/t3101-ls-tree-dirname.sh +++ b/t/t3101-ls-tree-dirname.sh @@ -34,7 +34,7 @@ test_expect_success \ mkdir path3 && echo 111 >path3/1.txt && echo 222 >path3/2.txt && - /usr/bin/find *.txt path* \( -type f -o -type l \) -print | + find *.txt path* \( -type f -o -type l \) -print | xargs git update-index --add && tree=`git write-tree` && echo $tree' diff --git a/t/t4112-apply-renames.sh b/t/t4112-apply-renames.sh index fcdf99d65a..70a1859503 100755 --- a/t/t4112-apply-renames.sh +++ b/t/t4112-apply-renames.sh @@ -115,7 +115,7 @@ rename to include/arch/m32r/klibc/archsetjmp.h +#endif /* _KLIBC_ARCHSETJMP_H */ EOF -/usr/bin/find klibc -type f -print | xargs git update-index --add -- +find klibc -type f -print | xargs git update-index --add -- test_expect_success 'check rename/copy patch' 'git apply --check patch' diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index a76c0f632b..f17bc3ac0b 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -45,12 +45,12 @@ test_expect_success \ (p=long_path_to_a_file && cd a && for depth in 1 2 3 4 5; do mkdir $p && cd $p; done && echo text >file_with_long_path) && - (cd a && /usr/bin/find .) | /usr/bin/sort >a.lst' + (cd a && find .) | sort >a.lst' test_expect_success \ 'add files to repository' \ - '/usr/bin/find a -type f | xargs git update-index --add && - /usr/bin/find a -type l | xargs git update-index --add && + 'find a -type f | xargs git update-index --add && + find a -type l | xargs git update-index --add && treeid=`git write-tree` && echo $treeid >treeid && git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \ @@ -87,7 +87,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd b/a && /usr/bin/find .) | /usr/bin/sort >b.lst && + '(cd b/a && find .) | sort >b.lst && diff a.lst b.lst' test_expect_success \ @@ -104,7 +104,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd c/prefix/a && /usr/bin/find .) | /usr/bin/sort >c.lst && + '(cd c/prefix/a && find .) | sort >c.lst && diff a.lst c.lst' test_expect_success \ @@ -128,7 +128,7 @@ test_expect_success \ test_expect_success \ 'validate filenames' \ - '(cd d/a && /usr/bin/find .) | /usr/bin/sort >d.lst && + '(cd d/a && find .) | sort >d.lst && diff a.lst d.lst' test_expect_success \ @@ -145,7 +145,7 @@ test_expect_success \ test_expect_success \ 'validate filenames with prefix' \ - '(cd e/prefix/a && /usr/bin/find .) | /usr/bin/sort >e.lst && + '(cd e/prefix/a && find .) | sort >e.lst && diff a.lst e.lst' test_expect_success \ diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index a232f41edf..9a81d84106 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -75,7 +75,7 @@ cd "$TRASH/.git2" test_expect_success \ 'check unpack without delta' \ - '(cd ../.git && /usr/bin/find objects -type f -print) | + '(cd ../.git && find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -105,7 +105,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with REF_DELTA' \ - '(cd ../.git && /usr/bin/find objects -type f -print) | + '(cd ../.git && find objects -type f -print) | while read path do cmp $path ../.git/$path || { @@ -135,7 +135,7 @@ unset GIT_OBJECT_DIRECTORY cd "$TRASH/.git2" test_expect_success \ 'check unpack with OFS_DELTA' \ - '(cd ../.git && /usr/bin/find objects -type f -print) | + '(cd ../.git && find objects -type f -print) | while read path do cmp $path ../.git/$path || { diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index b507bd8078..5daa0be8cc 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -10,7 +10,7 @@ test_description='Tests git rev-list --topo-order functionality' list_duplicates() { - "$@" | /usr/bin/sort | uniq -d + "$@" | sort | uniq -d } date >path0 diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index e4b030b93e..67fdf7023f 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -65,7 +65,7 @@ test_expect_success 'multi-fetch works on partial urls + paths' " for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do git rev-parse --verify refs/remotes/\$i^0 >> refs.out || exit 1; done && - test -z \"\`/usr/bin/sort < refs.out | uniq -d\`\" && + test -z \"\`sort < refs.out | uniq -d\`\" && for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do for j in trunk a b tags/0.1 tags/0.2 tags/0.3; do if test \$j != \$i; then continue; fi diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 9b271f2729..910c584f24 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -30,7 +30,7 @@ exit 1 check_entries () { # $1 == directory, $2 == expected - grep '^/' "$1/CVS/Entries" | /usr/bin/sort | cut -d/ -f2,3,5 >actual + grep '^/' "$1/CVS/Entries" | sort | cut -d/ -f2,3,5 >actual if test -z "$2" then >expected @@ -186,7 +186,7 @@ test_expect_success \ if p="Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" && mkdir -p "tst/$p" && date >"tst/$p/day" && - found=$(/usr/bin/find tst -type f -print) && + found=$(find tst -type f -print) && test "z$found" = "ztst/$p/day" && rm -fr tst then diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index a64f78f5a0..0595041af5 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -880,7 +880,7 @@ INPUT_END test_expect_success \ 'O: blank lines not necessary after other commands' \ 'git-fast-import actual && git diff expect actual' From 3b06d6b12bc0576a908964625399cd3749fa0d04 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 22 Sep 2007 20:08:21 +0200 Subject: [PATCH 232/781] t5302-pack-index: Skip tests of 64-bit offsets if necessary. There are platforms where off_t is not 64 bits wide. In this case many tests are doomed to fail. Let's skip them. Signed-off-by: Johannes Sixt --- t/t5302-pack-index.sh | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 4f58c4c3f9..d93abc4c75 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -61,17 +61,33 @@ test_expect_success \ test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ - 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 &1) || + ! echo "$msg" | grep "pack too large .* off_t" +then + have_64bits=t +else + say "skipping tests concerning 64-bit offsets" +fi + +test "$have_64bits" && +test_expect_success \ + 'index v2: verify a pack with some 64-bit offsets' \ + 'git verify-pack -v "test-3-${pack3}.pack"' + +test "$have_64bits" && test_expect_failure \ '64-bit offsets: should be different from previous index v2 results' \ 'cmp "test-2-${pack2}.idx" "test-3-${pack3}.idx"' +test "$have_64bits" && test_expect_success \ 'index v2: force some 64-bit offsets with index-pack' \ 'git-index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"' +test "$have_64bits" && test_expect_success \ '64-bit offsets: index-pack result should match pack-objects one' \ 'cmp "test-3-${pack3}.idx" "3.idx"' @@ -113,6 +129,7 @@ test_expect_failure \ '[index v1] 6) newly created pack is BAD !' \ 'git verify-pack -v "test-4-${pack1}.pack"' +test "$have_64bits" && test_expect_success \ '[index v2] 1) stream pack to repository' \ 'rm -f .git/objects/pack/* && @@ -122,6 +139,7 @@ test_expect_success \ cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" && cmp "test-3-${pack1}.idx" ".git/objects/pack/pack-${pack1}.idx"' +test "$have_64bits" && test_expect_success \ '[index v2] 2) create a stealth corruption in a delta base reference' \ '# this test assumes a delta smaller than 16 bytes at the end of the pack @@ -134,14 +152,17 @@ test_expect_success \ bs=1 count=20 conv=notrunc && git cat-file blob "$delta_sha1" > blob_4 )' +test "$have_64bits" && test_expect_failure \ '[index v2] 3) corrupted delta happily returned wrong data' \ 'cmp blob_3 blob_4' +test "$have_64bits" && test_expect_failure \ '[index v2] 4) confirm that the pack is actually corrupted' \ 'git fsck --full $commit' +test "$have_64bits" && test_expect_failure \ '[index v2] 5) pack-objects refuses to reuse corrupted data' \ 'git pack-objects test-5 Date: Mon, 3 Sep 2007 18:15:39 +0200 Subject: [PATCH 233/781] Avoid /dev/null on the command line. The shell turns it into 'nul' (which we can't understand as an existing file). --- t/t4116-apply-reverse.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 9ae2b3a8ef..359f347b2c 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -42,7 +42,8 @@ test_expect_success 'apply in reverse' ' git reset --hard second && git apply --reverse --binary --index patch && git diff >diff && - git diff /dev/null diff + : > empty && + git diff empty diff ' From f3370bd1919751a28c206b19a743783a7c78c6da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 Sep 2007 02:00:46 +0100 Subject: [PATCH 234/781] t7004: work around weird quoting issue with MSys It seems to be impossible to pass the _string_ '*a*' if there is _any_ file in the current directory whose name contains the letter 'a'. So remove all such files for the test that needs to pass that string. Signed-off-by: Johannes Schindelin --- t/t7004-tag.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 606d4f2a2c..a1a69c0380 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -185,8 +185,9 @@ cba EOF test_expect_success \ 'listing tags with substring as pattern must print those matching' ' - git-tag -l "*a*" > actual && - git diff expect actual + rm *a* && + git-tag -l "*a*" > current && + git diff expect current ' cat >expect < Date: Fri, 7 Sep 2007 13:05:00 +0200 Subject: [PATCH 235/781] MinGW: Add a custom implementation for utime(). There seems to be a problem with Microsoft's utime() implementation. With this implementation we ensure that the files times written are UTC. Signed-off-by: Johannes Sixt --- test-chmtime.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test-chmtime.c b/test-chmtime.c index 90da448ebe..b6dc548a2a 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -3,6 +3,38 @@ static const char usage_str[] = "(+|=|=+|=-|-) ..."; +#ifdef __MINGW32__ +static inline void time_t_to_filetime(time_t t, FILETIME *ft) +{ + long long winTime = t * 10000000LL + 116444736000000000LL; + ft->dwLowDateTime = winTime; + ft->dwHighDateTime = winTime >> 32; +} + +int git_utime (const char *file_name, const struct utimbuf *times) +{ + FILETIME mft, aft; + int fh, rc; + + /* must have write permission */ + if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) + return -1; + + time_t_to_filetime(times->modtime, &mft); + time_t_to_filetime(times->actime, &aft); + if (!SetFileTime(_get_osfhandle(fh), NULL, &aft, &mft)) { + errno = EINVAL; + rc = -1; + } else + rc = 0; + close(fh); + return rc; +} + +int git_utime(const char *file_name, const struct utimbuf *times); +#define utime git_utime +#endif /* __MINGW32__ */ + int main(int argc, const char *argv[]) { int i; From 4ff71c309b1454f6ec7381306449017fd686944b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 23 Sep 2007 14:39:21 +0100 Subject: [PATCH 236/781] Quick 'n dirty compile fix for missing msgfmt I only wanted to see the latest and greatest in terms of running git-gui in a directory that is not a git directory. We'll fix that missing msgfmt issue later. Signed-off-by: Johannes Schindelin --- git-gui/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index 6236dd6ad3..065a090c91 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -141,7 +141,7 @@ $(PO_TEMPLATE): $(SCRIPT_SH) $(ALL_LIBFILES) update-po:: $(PO_TEMPLATE) $(foreach p, $(ALL_POFILES), echo Updating $p ; msgmerge -U $p $(PO_TEMPLATE) ; ) $(ALL_MSGFILES): %.msg : %.po - $(QUIET_MSGFMT0)$(MSGFMT) --statistics --tcl $< -l $(basename $(notdir $<)) -d $(dir $@) $(QUIET_MSGFMT1) + $(QUIET_MSGFMT0)touch $@ $(QUIET_MSGFMT1) lib/tclIndex: $(ALL_LIBFILES) $(QUIET_INDEX)if echo \ From 3be4fa22e9e50839cfb3fb50970b8a247774c592 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 23 Sep 2007 14:42:46 +0100 Subject: [PATCH 237/781] git-gui: actually show the choose repository dialog For some reason, "." was withdrawn, I think. Therefore we have to deiconify it, so the user sees something. Signed-off-by: Johannes Schindelin --- git-gui/lib/choose_repository.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 1bec8bd0a8..5f2d12fd07 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -123,6 +123,7 @@ constructor pick {} { grab $top focus $top " + wm deiconify $top tkwait variable @done if {$top eq {.}} { From 071ba61874592b990aded3f61bb444354985d765 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 24 Sep 2007 13:46:42 +0100 Subject: [PATCH 238/781] Revert "Quick 'n dirty compile fix for missing msgfmt" This reverts commit 4ff71c309b1454f6ec7381306449017fd686944b. --- git-gui/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/Makefile b/git-gui/Makefile index 065a090c91..6236dd6ad3 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -141,7 +141,7 @@ $(PO_TEMPLATE): $(SCRIPT_SH) $(ALL_LIBFILES) update-po:: $(PO_TEMPLATE) $(foreach p, $(ALL_POFILES), echo Updating $p ; msgmerge -U $p $(PO_TEMPLATE) ; ) $(ALL_MSGFILES): %.msg : %.po - $(QUIET_MSGFMT0)touch $@ $(QUIET_MSGFMT1) + $(QUIET_MSGFMT0)$(MSGFMT) --statistics --tcl $< -l $(basename $(notdir $<)) -d $(dir $@) $(QUIET_MSGFMT1) lib/tclIndex: $(ALL_LIBFILES) $(QUIET_INDEX)if echo \ From f98e862b3105ba14891c71bbe6dfb9ea677f84cc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 24 Sep 2007 13:51:57 +0100 Subject: [PATCH 239/781] git-gui: add a simple msgfmt replacement The program "msgfmt" was our only dependency on gettext. Since it is more than just a hassle to compile gettext on MinGW, here is a (very simple) drop-in replacement, which Works For Us. Signed-off-by: Johannes Schindelin --- git-gui/Makefile | 2 +- git-gui/po/po2msg.sh | 103 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 git-gui/po/po2msg.sh diff --git a/git-gui/Makefile b/git-gui/Makefile index 6236dd6ad3..b9affa4d7c 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -129,7 +129,7 @@ $(GITGUI_BUILT_INS): git-gui $(QUIET_BUILT_IN)rm -f $@ && ln git-gui $@ XGETTEXT ?= xgettext -MSGFMT ?= msgfmt +MSGFMT ?= po/po2msg.sh msgsdir = $(gg_libdir)/msgs msgsdir_SQ = $(subst ','\'',$(msgsdir)) PO_TEMPLATE = po/git-gui.pot diff --git a/git-gui/po/po2msg.sh b/git-gui/po/po2msg.sh new file mode 100644 index 0000000000..da0765dd80 --- /dev/null +++ b/git-gui/po/po2msg.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec tclsh "$0" -- "$@" + +# This is a really stupid program, which serves as an alternative to +# msgfmt. It _only_ translates to Tcl mode, does _not_ validate the +# input, and does _not_ output any statistics. + +proc u2a {s} { + set res "" + foreach i [split $s ""] { + scan $i %c c + if {$c<128} { + # escape '[', '\' and ']' + if {$c == 0x5b || $c == 0x5d} { + append res "\\" + } + append res $i + } else { + append res \\u[format %04.4x $c] + } + } + return $res +} + +set output_directory "." +set lang "dummy" +set files [list] + +# parse options +for {set i 1} {$i < $argc} {incr i} { + set arg [lindex $argv $i] + if {$arg == "--statistics" || $arg == "--tcl"} { + continue + } + if {$arg == "-l"} { + incr i + set lang [lindex $argv $i] + continue + } + if {$arg == "-d"} { + incr i + set tmp [lindex $argv $i] + regsub "\[^/\]$" $tmp "&/" output_directory + continue + } + lappend files $arg +} + +proc flush_msg {} { + global msgid msgstr mode lang out + + if {![info exists msgid] || $mode == ""} { + return + } + set mode "" + + if {$msgid == ""} { + set prefix "set ::msgcat::header" + } else { + set prefix "::msgcat::mcset $lang \"[u2a $msgid]\"" + } + + puts $out "$prefix \"[u2a $msgstr]\"" +} + +foreach file $files { + regsub "^.*/\(\[^/\]*\)\.po$" $file "$output_directory\\1.msg" outfile + set in [open $file "r"] + fconfigure $in -encoding utf-8 + set out [open $outfile "w"] + + set mode "" + while {[gets $in line] >= 0} { + if {[regexp "^#" $line]} { + flush_msg + continue + } elseif {[regexp "^msgid \"(.*)\"$" $line dummy match]} { + flush_msg + set msgid $match + set mode "msgid" + } elseif {[regexp "^msgstr \"(.*)\"$" $line dummy match]} { + set msgstr $match + set mode "msgstr" + } elseif {$line == ""} { + flush_msg + } elseif {[regexp "^\"(.*)\"$" $line dummy match]} { + if {$mode == "msgid"} { + append msgid $match + } elseif {$mode == "msgstr"} { + append msgstr $match + } else { + puts stderr "I do not know what to do: $match" + } + } else { + puts stderr "Cannot handle $line" + } + } + flush_msg + close $in + close $out +} + From b0eef9af247c5e06451b82e2ada82351158f5f5f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 24 Sep 2007 21:13:50 +0200 Subject: [PATCH 240/781] Do not return EFAULT for ERROR_INVALID_NAME. A file name that contains a colon will be rejected by GeFileInformation() with ERROR_INVALID_NAME. This must be treated as ENOENT. Such a file name ends up in do_lstat() when the rev:path notation is used (eg. in 'git show'). --- compat/mingw.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 166e2ad5f0..af522f1666 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -76,9 +76,6 @@ static int do_lstat(const char *file_name, struct stat *buf) case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; - case ERROR_INVALID_NAME: - errno = EFAULT; - break; default: errno = ENOENT; break; From 56dc8fc47aa94fb74f824d8994f0b5340cd0228a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 25 Sep 2007 12:32:27 +0200 Subject: [PATCH 241/781] Fix fstat() implementation for pipes and sockets again. It turns out that GetFileInformationByHandle() succeeds even for pipes and sockets. Hence, we fall back to Windows's own fstat() implementation for everything except files. This also takes care of any error codes (again, except for files - but we don't expect any errors here). --- compat/mingw.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index af522f1666..8bb0dba16c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -116,17 +116,20 @@ int git_lstat(const char *file_name, struct stat *buf) return do_lstat(alt_name, buf); } +#undef fstat int git_fstat(int fd, struct stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; - char dummy[sizeof(void*)]; - int s = sizeof(void*); if (fh == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } + /* direct non-file handles to MS's fstat() */ + if (GetFileType(fh) != FILE_TYPE_DISK) + return fstat(fd, buf); + if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) @@ -148,22 +151,7 @@ int git_fstat(int fd, struct stat *buf) buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); return 0; } - switch (GetLastError()) { - case ERROR_INVALID_FUNCTION: - /* check for socket */ - if (getsockopt((int)fh, SOL_SOCKET, SO_KEEPALIVE, dummy, &s) && - WSAGetLastError() == WSAENOTSOCK) - goto badf; - memset(buf, sizeof(*buf), 0); - buf->st_mode = S_IREAD|S_IWRITE; - buf->st_mode |= 0x140000; /* S_IFSOCK */ - return 0; - default: - case ERROR_INVALID_HANDLE: - badf: - errno = EBADF; - break; - } + errno = EBADF; return -1; } From 803d403a7393ab267b4da1e0d57d7ee8782f2128 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 29 Sep 2007 17:40:06 +0200 Subject: [PATCH 242/781] help (msysgit): print message telling the user that browser is launched git doesn't wait until the browser is launched but returns immediatly. A user may feel more comfortable if he knows that eventually the help will appear. Signed-off-by: Steffen Prohaska --- help.c | 1 + 1 file changed, 1 insertion(+) diff --git a/help.c b/help.c index e7da8ae430..98d00cc4d9 100644 --- a/help.c +++ b/help.c @@ -193,6 +193,7 @@ static void show_man_page(const char *git_cmd) strcpy (htmlpath + prefix_len, page); strcpy (htmlpath + prefix_len + page_len, suffix); htmlpath[htmlpath_len] = 0; + printf("Launching default browser to display html help...\n"); /* We need sh here to run shell script /bin/start. */ execlp("sh", "start", "/bin/start", htmlpath, NULL ); } From 65230e232c91527c16724a665e5d5f2ea670f9b6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 1 Oct 2007 22:56:45 +0200 Subject: [PATCH 243/781] help (msysgit): fix locating html help for paths with spaces Derive the git installation dir from the executable path and directly use the Win32 API to open the HTML file. This avoids the mingw layer and command line escaping problems, which caused the previous implementation to fail if spaces were contained in the path to git. Signed-off-by: Steffen Prohaska --- help.c | 60 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/help.c b/help.c index 98d00cc4d9..a5ada18c76 100644 --- a/help.c +++ b/help.c @@ -165,6 +165,32 @@ static void list_common_cmds_help(void) puts("(use 'git help -a' to get a list of all installed git commands)"); } +#ifdef __MINGW32__ +char* get_install_dir() +{ + static char* pgm = 0; + if (pgm) { + return pgm; + } else { + char* p; + int pgm_len = strlen(_pgmptr); + pgm = xmalloc(pgm_len + 1); + strcpy(pgm, _pgmptr); + p = strrchr(pgm, '\\'); /* \bin\ <- p */ + if (p) { + *p = '\0'; + p = strrchr(pgm, '\\'); /* \ <- p */ + if (p) { + *p = '\0'; + return pgm; + } + } + } + fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); + exit(1); +} +#endif + static void show_man_page(const char *git_cmd) { const char *page; @@ -181,22 +207,24 @@ static void show_man_page(const char *git_cmd) } #ifdef __MINGW32__ - { - char* prefix = "/doc/git/html/"; - int prefix_len = strlen (prefix); - char* suffix = ".html"; - int suffix_len = strlen (suffix); - int page_len = strlen (page); - int htmlpath_len = prefix_len + page_len + suffix_len; - char* htmlpath = xmalloc (htmlpath_len + 1); - strcpy (htmlpath, prefix); - strcpy (htmlpath + prefix_len, page); - strcpy (htmlpath + prefix_len + page_len, suffix); - htmlpath[htmlpath_len] = 0; - printf("Launching default browser to display html help...\n"); - /* We need sh here to run shell script /bin/start. */ - execlp("sh", "start", "/bin/start", htmlpath, NULL ); - } + { + char* install_dir = get_install_dir(); + int install_dir_len = strlen(install_dir); + char* html_dir = "\\doc\\git\\html\\"; + int html_dir_len = strlen(html_dir); + char* suffix = ".html"; + int suffix_len = strlen(suffix); + int page_len = strlen(page); + int htmlpath_len = install_dir_len + html_dir_len + page_len + suffix_len; + char* htmlpath = xmalloc(htmlpath_len + 1); + strcpy (htmlpath, install_dir); + strcpy (htmlpath + install_dir_len, html_dir); + strcpy (htmlpath + install_dir_len + html_dir_len, page); + strcpy (htmlpath + install_dir_len + html_dir_len + page_len, suffix); + htmlpath[htmlpath_len] = 0; + printf("Launching default browser to display html help...\n"); + ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); + } #else execlp("man", "man", page, NULL); #endif From fc98ff08304caa36420028f1b5cfaa6cfdccf3d6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 2 Oct 2007 15:25:15 +0200 Subject: [PATCH 244/781] help (msysgit): beautify message telling user that HTML will be display Signed-off-by: Steffen Prohaska --- help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help.c b/help.c index a5ada18c76..f4a0208ff3 100644 --- a/help.c +++ b/help.c @@ -222,7 +222,7 @@ static void show_man_page(const char *git_cmd) strcpy (htmlpath + install_dir_len + html_dir_len, page); strcpy (htmlpath + install_dir_len + html_dir_len + page_len, suffix); htmlpath[htmlpath_len] = 0; - printf("Launching default browser to display html help...\n"); + printf("Launching default browser to display HTML help ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); } #else From ded3d5f4962928feec8060cab0bbd96e7443a3dd Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 4 Oct 2007 07:45:31 +0200 Subject: [PATCH 245/781] help (msysgit): add comment about assumption on _pgmptr --- help.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/help.c b/help.c index f4a0208ff3..1c0946c649 100644 --- a/help.c +++ b/help.c @@ -186,6 +186,8 @@ char* get_install_dir() } } } + /* Note, according to the msdn documentation we have a full path + if started through the shell and this error should never happen. */ fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); exit(1); } From 524344cdf5b16871f027bf029eeee7774d337c37 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 10 Oct 2007 09:00:19 +0200 Subject: [PATCH 246/781] Fix invocation of external git commands with arguments with spaces. If an external git command (not a shell script) was invoked with arguments that contain spaces, these arguments would be split into separate arguments. They must be quoted. This also affected installations where $prefix contained a space, as in "C:\Program Files\GIT". Both errors can be triggered by invoking git hash-object "a b" where "a b" is an existing file. --- compat/mingw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8bb0dba16c..2554f19765 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -405,7 +405,12 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { - int ret = spawnve(_P_WAIT, cmd, argv, env); + const char **qargv; + int n; + for (n = 0; argv[n];) n++; + qargv = xmalloc((n+1)*sizeof(char*)); + quote_argv(qargv, argv); + int ret = spawnve(_P_WAIT, cmd, qargv, env); if (ret != -1) exit(ret); } From 73b51e93d2927af2fa9f332f31c25ca2319bd0dd Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 17 Aug 2007 18:40:36 +0200 Subject: [PATCH 247/781] Work around a Windows oddity when a pipe with no reader is written to. The first WriteFile() returns ERROR_BROKEN_PIPE, subsequent WriteFile()s return ERROR_NO_DATA, which is not translated to EPIPE, but EINVAL. Hmpf! --- write_or_die.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/write_or_die.c b/write_or_die.c index e125e11d3b..40b046acb0 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -34,7 +34,16 @@ void maybe_flush_or_die(FILE *f, const char *desc) return; } if (fflush(f)) { +#ifndef __MINGW32__ if (errno == EPIPE) +#else + /* + * On Windows, EPIPE is returned only by the first write() + * after the reading end has closed its handle; subsequent + * write()s return EINVAL. + */ + if (errno == EPIPE || errno == EINVAL) +#endif exit(0); die("write failure on %s: %s", desc, strerror(errno)); } From fbb7b31c456f4c950a744a93d8521e8ef0145038 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 10 Oct 2007 09:00:12 +0200 Subject: [PATCH 248/781] Fix invocation of external git commands with arguments with spaces. If an external git command (not a shell script) was invoked with arguments that contain spaces, these arguments would be split into separate arguments. They must be quoted. This also affected installations where $prefix contained a space, as in "C:\Program Files\GIT". Both errors can be triggered by invoking git hash-object "a b" where "a b" is an existing file. --- compat/mingw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6632192690..f2b0ad3428 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -298,7 +298,12 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { - int ret = spawnve(_P_WAIT, cmd, argv, env); + const char **qargv; + int n; + for (n = 0; argv[n];) n++; + qargv = xmalloc((n+1)*sizeof(char*)); + quote_argv(qargv, argv); + int ret = spawnve(_P_WAIT, cmd, qargv, env); if (ret != -1) exit(ret); } From b171dc19ec37692d0791bc0d84866399fc42da94 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 16 Oct 2007 22:52:12 +0200 Subject: [PATCH 249/781] Implement a cpio emulation inside git-clone.sh for Windows. We use 'xargs cp' to emulate 'cpio -pumd'. cpio is fed from the output of 'find --depth' without filtering out directories. We don't need to copy directories except the empty ones, so we need to filter out non-empty directories. Then we can use 'cp -r' and it will not actually recurse anything. Signed-off-by: Johannes Sixt --- git-clone.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/git-clone.sh b/git-clone.sh index cb6f2daef0..0154a4a381 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -20,6 +20,33 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + # need an emulation of cpio + cpio() { + case "$1" in + -pumd) cp_arg=-pr;; + -pumdl) cp_arg=-lr;; + *) die "cpio $1 unexpected";; + esac + # copy only files and empty directories + prev= + while read f; do + if test -d "$f"; then + # here we assume that directories are listed after + # its files (aka 'find -depth'), hence, a directory + # that is not empty will be a leading sub-string + # of the preceding entry + case "$prev" in + "$f"/* ) ;; + *) echo "$f";; + esac + else + echo "$f" + fi + prev="$f" + done | + xargs --no-run-if-empty \ + cp $cp_arg --target-directory="$2" --parents + } ;; esac From 8b9de093190e6b1d6066efaf4afd9dc988096987 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 17 Oct 2007 14:35:10 +0200 Subject: [PATCH 250/781] Implement a cpio emulation in git-merge.sh for Windows. GNU tar is used as the archiver. It doesn't matter that the archive has a different format because it is only a temporary stash that is consumed by the emulation itself. Signed-off-by: Johannes Sixt --- git-merge.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/git-merge.sh b/git-merge.sh index cde09d4d60..0f15884b54 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -26,6 +26,24 @@ use_strategies= allow_fast_forward=t allow_trivial_merge=t +# Fix some commands on Windows +case $(uname -s) in +*MINGW*) + # there's no cpio; emulate with tar + cpio () { + case "$*" in + "-0 -o") + tar --create --file=- --null --files-from=- + ;; + "-iuv") + tar xvf - + ;; + *) die "internal error: unexpected cpio $*";; + esac + } + ;; +esac + dropsave() { rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \ "$GIT_DIR/MERGE_SAVE" || exit 1 From 4a7c98dbaf129f2546f8b8780650b4041c336228 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 17 Oct 2007 14:38:39 +0200 Subject: [PATCH 251/781] Remove the cpio emulator script. The users of cpio have their own emulation by now. --- .gitignore | 1 - Makefile | 1 - cpio.sh | 60 ------------------------------------------------------ 3 files changed, 62 deletions(-) delete mode 100644 cpio.sh diff --git a/.gitignore b/.gitignore index 2cb4002ba8..63c918c667 100644 --- a/.gitignore +++ b/.gitignore @@ -172,4 +172,3 @@ config.status config.mak.autogen config.mak.append configure -cpio diff --git a/Makefile b/Makefile index ea00d44337..5171a69425 100644 --- a/Makefile +++ b/Makefile @@ -500,7 +500,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig - SCRIPT_SH += cpio.sh endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease diff --git a/cpio.sh b/cpio.sh deleted file mode 100644 index df5f64c14c..0000000000 --- a/cpio.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh -# -# Emulates some cpio behavior using GNU tar - -die() { - echo >&2 "$@" - exit 1 -} - -null= - -while test $# -gt 0; do - case "$1" in - -0) null=--null;; - -o) mode=o;; - -iuv) ;; - -pumd|-pumdl) - mode=p - dir="$2" - shift - ;; - *) die "cpio emulation supports only -0, -o, -iuv, -pumdl";; - esac - shift -done - -prev= - -filterdirs() { - while read f; do - if test -d "$f"; then - # list only empty directories - # here we assume that directories are listed after - # its files (aka 'find -depth'), hence, a directory - # that is not empty will be a leading sub-string - # of the preceding entry - case "$prev" in - "$f"/* ) ;; - *) echo "$f";; - esac - else - echo "$f" - fi - prev="$f" - done -} - -case $mode in -o) - tar --create --file=- $null --files-from=- - ;; -p) - test -z "$null" || die "cpio: cannot use -0 in pass-through mode" - filterdirs | - tar --create --file=- --files-from=- | - tar --extract --directory="$dir" --file=- - ;; -*) - tar xvf - -esac From 2f346edb63d87f5c196f6254ce05e411548da04f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 18 Oct 2007 21:27:46 +0200 Subject: [PATCH 252/781] attr: fix segfault in gitattributes parsing code git may segfault if gitattributes contains an invalid entry. A test is added to t0020 that triggers the segfault. The parsing code is fixed to avoid the crash. Signed-off-by: Steffen Prohaska --- attr.c | 5 ++++- t/t0020-crlf.sh | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/attr.c b/attr.c index 129399310a..6e82507be7 100644 --- a/attr.c +++ b/attr.c @@ -214,8 +214,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, num_attr = 0; cp = name + namelen; cp = cp + strspn(cp, blank); - while (*cp) + while (*cp) { cp = parse_attr(src, lineno, cp, &num_attr, res); + if (!cp) + return NULL; + } if (pass) break; res = xcalloc(1, diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh index 0807d9f01a..62bc4bb077 100755 --- a/t/t0020-crlf.sh +++ b/t/t0020-crlf.sh @@ -371,4 +371,11 @@ test_expect_success 'in-tree .gitattributes (4)' ' } ' +test_expect_success 'invalid .gitattributes (must not crash)' ' + + echo "three +crlf" >>.gitattributes && + git diff + +' + test_done From 2671981e99996146c5624fb6005265805d29bfce Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 19 Oct 2007 22:51:50 +0200 Subject: [PATCH 253/781] Windows does not have memmem(). Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 9fa72a8a07..a048c061fa 100644 --- a/Makefile +++ b/Makefile @@ -501,6 +501,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_UNSETENV=YesPlease NO_STRCASESTR=YesPlease NO_STRLCPY=YesPlease + NO_MEMMEM = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease From 5fd41ffacdef5454acbe51f5e23a97eb5158226d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Oct 2007 14:01:27 +0200 Subject: [PATCH 254/781] Implement a work-around for a mis-behaved vsnprintf on Windows. On Windows, vsnprintf returns -1 if the buffer is too small instead of the number of characters needed. This wrapper computes the needed buffer size by trying various sizes with exponential growth. A large growth factor is used so as only few trials are required if a really large result needs to be stored. Signed-off-by: Johannes Sixt --- compat/mingw.c | 26 ++++++++++++++++++++++++++ git-compat-util.h | 4 ++++ 2 files changed, 30 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 2554f19765..43eda9e174 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -459,3 +459,29 @@ int mingw_rename(const char *pold, const char *pnew) errno = EACCES; return -1; } + +#undef vsnprintf +/* this is out of line because it uses alloca() behind the scenes, + * which must not be called in a loop (alloca() reclaims the allocations + * only at function exit) + */ +static int try_vsnprintf(size_t size, const char *fmt, va_list args) +{ + char buf[size]; /* gcc-ism */ + return vsnprintf(buf, size, fmt, args); +} + +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int len = vsnprintf(buf, size, fmt, args); + if (len >= 0) + return len; + /* ouch, buffer too small; need to compute the size */ + if (size < 250) + size = 250; + do { + size *= 4; + len = try_vsnprintf(size, fmt, args); + } while (len < 0); + return len; +} diff --git a/git-compat-util.h b/git-compat-util.h index f52ced3763..e4f643d70b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -503,6 +503,10 @@ int git_fstat(int fd, struct stat *buf); #define lstat(x,y) git_lstat(x,y) #define stat(x,y) git_lstat(x,y) #define fstat(x,y) git_fstat(x,y) + +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); +#define vsnprintf mingw_vsnprintf + #endif /* __MINGW32__ */ #endif From e88aa8cbe816526bb0a7d37eaf2f5eb40ff36ae1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Oct 2007 16:34:09 +0200 Subject: [PATCH 255/781] Fix off-by-one error in the vsnprintf wrapper. Windows's vsnprintf() receives the number of characters to write, which does not include the trailing NUL byte. But our vsnprintf() users pass the available space, including the trailing NUL. --- compat/mingw.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 43eda9e174..22b5e1072e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -461,21 +461,29 @@ int mingw_rename(const char *pold, const char *pnew) } #undef vsnprintf -/* this is out of line because it uses alloca() behind the scenes, +/* Note that the size parameter specifies the available space, i.e. + * includes the trailing NUL byte; but Windows's vsnprintf expects the + * number of characters to write without the trailing NUL. + */ + +/* This is out of line because it uses alloca() behind the scenes, * which must not be called in a loop (alloca() reclaims the allocations - * only at function exit) + * only at function exit). */ static int try_vsnprintf(size_t size, const char *fmt, va_list args) { char buf[size]; /* gcc-ism */ - return vsnprintf(buf, size, fmt, args); + return vsnprintf(buf, size-1, fmt, args); } int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { - int len = vsnprintf(buf, size, fmt, args); - if (len >= 0) - return len; + int len; + if (size > 0) { + len = vsnprintf(buf, size-1, fmt, args); + if (len >= 0) + return len; + } /* ouch, buffer too small; need to compute the size */ if (size < 250) size = 250; From 4e8904080d62be07a139436aa44044e05e380a2c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 24 Oct 2007 22:47:14 +0200 Subject: [PATCH 256/781] Makefile: avoid absolute Windows path in built executables MINGW converts an intial '/' in paths to the full Windows path of MINGW's rootdir. Therefore, the result of the build cannot be installed in another directory. This is fixed by replacing the initial '/' by its octal escape sequence that represents '/' in C strings. This sequence avoids the path conversion. Note, the Makefile contains the full path and can not be used any longer to build git with a different prefix. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 77a011f4a9..8f2f0300f2 100644 --- a/Makefile +++ b/Makefile @@ -735,12 +735,12 @@ endif # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) -ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) +ETC_GITCONFIG_SQ = \057etc/gitconfig DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) -template_dir_SQ = $(subst ','\'',$(template_dir)) +template_dir_SQ = \057share/git-core/templates prefix_SQ = $(subst ','\'',$(prefix)) sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) From 334cf5f96d18d4c97cb4f653cd5e9f14a85997ca Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 25 Oct 2007 00:15:21 +0200 Subject: [PATCH 257/781] git-gui: Protect against bad translation strings If a translation string uses a format character we don't have an argument for then it may throw an error when we attempt to format the translation. In this case switch back to the default format that comes with the program (aka the English translation). Signed-off-by: Shawn O. Pearce Signed-off-by: Steffen Prohaska --- git-gui/git-gui.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 9bc5626286..0547c3a624 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -88,13 +88,20 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { package require msgcat -proc mc {fmt args} { - set fmt [::msgcat::mc $fmt] +proc _mc_trim {fmt} { set cmk [string first @@ $fmt] if {$cmk > 0} { - set fmt [string range $fmt 0 [expr {$cmk - 1}]] + return [string range $fmt 0 [expr {$cmk - 1}]] } - return [eval [list format $fmt] $args] + return $fmt +} + +proc mc {en_fmt args} { + set fmt [_mc_trim [::msgcat::mc $en_fmt]] + if {[catch {set msg [eval [list format $fmt] $args]} err]} { + set msg [eval [list format [_mc_trim $en_fmt]] $args] + } + return $msg } proc strcat {args} { From 4d2a9e8f6059753c549680e0b6f30a2dcbc73c08 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 25 Oct 2007 19:11:06 +0200 Subject: [PATCH 258/781] refactor help.c to git_install_prefix() and make_native_separator() git_install_prefix() returns the install prefix of msysgit. For all other architectures it returns "". The path returned contains slashes. make_native_separator() takes a unix path (slashes) and converts the separators in place. On Windows slashes are converted to backslashes. All the code was available in help.c and is now moved to path.c. The new function will be used to located the templates and /etc/gitconfig. Signed-off-by: Steffen Prohaska --- cache.h | 3 +++ help.c | 47 +++++------------------------------------------ path.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/cache.h b/cache.h index b7f57fdc2e..e87d0a350b 100644 --- a/cache.h +++ b/cache.h @@ -381,6 +381,9 @@ static inline int is_dev_null(const char *str) return !strcmp(str, "/dev/null"); } const char *make_absolute_path(const char *path); +/* Convert slashes in place. On Windows to backslashes. */ +char *make_native_separator(char *path); +const char *git_install_prefix(); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/help.c b/help.c index 1c0946c649..e59b856d9f 100644 --- a/help.c +++ b/help.c @@ -165,34 +165,6 @@ static void list_common_cmds_help(void) puts("(use 'git help -a' to get a list of all installed git commands)"); } -#ifdef __MINGW32__ -char* get_install_dir() -{ - static char* pgm = 0; - if (pgm) { - return pgm; - } else { - char* p; - int pgm_len = strlen(_pgmptr); - pgm = xmalloc(pgm_len + 1); - strcpy(pgm, _pgmptr); - p = strrchr(pgm, '\\'); /* \bin\ <- p */ - if (p) { - *p = '\0'; - p = strrchr(pgm, '\\'); /* \ <- p */ - if (p) { - *p = '\0'; - return pgm; - } - } - } - /* Note, according to the msdn documentation we have a full path - if started through the shell and this error should never happen. */ - fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); - exit(1); -} -#endif - static void show_man_page(const char *git_cmd) { const char *page; @@ -210,20 +182,11 @@ static void show_man_page(const char *git_cmd) #ifdef __MINGW32__ { - char* install_dir = get_install_dir(); - int install_dir_len = strlen(install_dir); - char* html_dir = "\\doc\\git\\html\\"; - int html_dir_len = strlen(html_dir); - char* suffix = ".html"; - int suffix_len = strlen(suffix); - int page_len = strlen(page); - int htmlpath_len = install_dir_len + html_dir_len + page_len + suffix_len; - char* htmlpath = xmalloc(htmlpath_len + 1); - strcpy (htmlpath, install_dir); - strcpy (htmlpath + install_dir_len, html_dir); - strcpy (htmlpath + install_dir_len + html_dir_len, page); - strcpy (htmlpath + install_dir_len + html_dir_len + page_len, suffix); - htmlpath[htmlpath_len] = 0; + const char *htmlpath = make_native_separator( + mkpath("%s/doc/git/html/%s.html" + , git_install_prefix() + , page) + ); printf("Launching default browser to display HTML help ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); } diff --git a/path.c b/path.c index 7a5ac5b067..e42b234fa1 100644 --- a/path.c +++ b/path.c @@ -370,3 +370,51 @@ const char *make_absolute_path(const char *path) return buf; } + +const char* git_install_prefix() +{ +#ifdef __MINGW32__ + static char* prefix; + + if (prefix) { + return prefix; + } + + char* p; + int pgm_len = strlen(_pgmptr); + prefix = xmalloc(pgm_len + 1); + strcpy(prefix, _pgmptr); + p = strrchr(prefix, '\\'); /* \bin\ <- p */ + if (p) { + *p = '\0'; + p = strrchr(prefix, '\\'); /* \ <- p */ + if (p) { + *p = '\0'; + for (p = prefix; *p; p++) + if (*p == '\\') + *p = '/'; + return prefix; + } + } + + /* Note, according to the msdn documentation we have a full path + if started through the shell and this error should never happen. */ + fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); + exit(1); +#else + return ""; +#endif +} + +char *make_native_separator(char* path) { +#ifdef __MINGW32__ + char* c; + for (c = path; *c; c++) { + if (*c == '/') + *c = '\\'; + } + return path; +#else + return path; +#endif +} From 0fbe22da392f39e1d144f78ef08b2dbdb882c164 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 25 Oct 2007 19:14:56 +0200 Subject: [PATCH 259/781] init: find template directory on Windows (msys) The template directory must be searched for using the full Windows path. But internally a Unix path starting with '/' is used. The internal Unix path is now prefixed with git_install_prefix() before accessing the file system Only absolute Unix paths are converted. Relative paths can be used as is. Signed-off-by: Steffen Prohaska --- builtin-init-db.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/builtin-init-db.c b/builtin-init-db.c index 5da2515f85..117fedd586 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -145,6 +145,17 @@ static void copy_templates(const char *git_dir, int len, const char *template_di template_dir = prefix_path(exec_path, strlen(exec_path), template_dir); } +#if __MINGW32__ + /* + * If it is an absolute Unix path it is prefixed with + * the git_install_prefix(). + */ + else if (template_dir[0] == '/') { + const char* prefix = git_install_prefix(); + template_dir = prefix_path(prefix, strlen(prefix), + template_dir); + } +#endif } strcpy(template_path, template_dir); template_len = strlen(template_path); From 636116b8a79c7c810afe8ae8e4c37e0a1de6f7b7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 25 Oct 2007 19:16:11 +0200 Subject: [PATCH 260/781] config.c: find /etc/gitconfig on Windows (msys) /etc/gitconfig must be searched for using the full Windows path. But internally a Unix path starting with '/' is used. An absolute Unix path is now prefixed with git_install_prefix(). Signed-off-by: Steffen Prohaska --- config.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config.c b/config.c index da2d1c1667..be0b1f0ed2 100644 --- a/config.c +++ b/config.c @@ -466,6 +466,17 @@ const char *git_etc_gitconfig(void) system_wide = prefix_path(exec_path, strlen(exec_path), system_wide); } +#if __MINGW32__ + /* + * If it is an absolute Unix path it is prefixed with + * the git_install_prefix(). + */ + else if (system_wide[0] == '/') { + const char* prefix = git_install_prefix(); + system_wide = prefix_path(prefix, strlen(prefix), + system_wide); + } +#endif } return system_wide; } From 1e65313ceb6bc5bf1574ae93335ec62a94d9ed7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 27 Oct 2007 20:26:31 +0700 Subject: [PATCH 261/781] spawnvppe_pipe: Don't overwrite argv[0] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because caller expects it so Signed-off-by: Nguyễn Thái Ngọc Duy --- spawn-pipe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spawn-pipe.c b/spawn-pipe.c index c8f0452823..3df7e22ed9 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -123,6 +123,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) { const char *cmd_basename = strrchr(cmd, '/'); + const char *argv0 = argv[0]; pid_t pid; #ifdef __MINGW32__ @@ -214,6 +215,8 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, } #endif + argv[0] = argv0; + return pid; } From ee05d117627de156a70c9ff6c16341d0d2a42efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 27 Oct 2007 20:30:40 +0700 Subject: [PATCH 262/781] Rework quote_arg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MS Windows command line is handled in a weird way. This patch addresses: - Quote empty arguments - Only escape backslashes and double quotation marks inside quoted arguments - Quote arguments if they have asterisk or question marks to prevent expansion The last one is not documented in the link provided in the patch. I encountered that behavior on cmd.exe, Windows XP. MSYS not tested. Signed-off-by: Nguyễn Thái Ngọc Duy --- compat/mingw.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 22b5e1072e..90dc0805ae 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -303,6 +303,7 @@ void openlog(const char *ident, int option, int facility) { } +/* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx (Parsing C++ Command-Line Arguments */ static const char *quote_arg(const char *arg) { /* count chars to quote */ @@ -310,11 +311,23 @@ static const char *quote_arg(const char *arg) int force_quotes = 0; char *q, *d; const char *p = arg; + if (!*p) force_quotes = 1; while (*p) { - if (isspace(*p)) + if (isspace(*p) || *p == '*' || *p == '?') force_quotes = 1; - else if (*p == '"' || *p == '\\') + else if (*p == '"') n++; + else if (*p == '\\') { + int count = 0; + while (*p == '\\') { + count++; + p++; + len++; + } + if (*p == '"') + n += count*2 + 1; + continue; + } len++; p++; } @@ -325,8 +338,20 @@ static const char *quote_arg(const char *arg) d = q = xmalloc(len+n+3); *d++ = '"'; while (*arg) { - if (*arg == '"' || *arg == '\\') + if (*arg == '"') *d++ = '\\'; + else if (*arg == '\\') { + int count = 0; + while (*arg == '\\') { + count++; + *d++ = *arg++; + } + if (*arg == '"') { + while (count-- > 0) + *d++ = '\\'; + *d++ = '\\'; + } + } *d++ = *arg++; } *d++ = '"'; From eafce5ce148c553b2512ec87577cc43c15ea8ef8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 26 Oct 2007 22:27:45 +0200 Subject: [PATCH 263/781] Windows does not have mkdtemp. Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 7787607d49..97add19472 100644 --- a/Makefile +++ b/Makefile @@ -509,6 +509,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease + NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat From d3d5d0c2e55532839b1d0ad9e8b0c7d353fc51a7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 27 Oct 2007 23:21:20 +0200 Subject: [PATCH 264/781] Implement asynchronous functions using threads on Windows. A kill(2) is removed from upload-pack.c because we cannot assume that rev-list is run as a process. Signed-off-by: Johannes Sixt --- run-command.c | 29 ++++++++++++++++++++++++++++- run-command.h | 5 +++++ upload-pack.c | 5 +---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/run-command.c b/run-command.c index dca8626e22..d2e5f183d2 100644 --- a/run-command.c +++ b/run-command.c @@ -186,13 +186,23 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const return run_command(&cmd); } +#ifdef __MINGW32__ +static __stdcall unsigned run_thread(void *data) +{ + struct async *async = data; + return async->proc(async->fd_for_proc, async->data); +} +#endif + int start_async(struct async *async) { int pipe_out[2]; if (pipe(pipe_out) < 0) return error("cannot create pipe: %s", strerror(errno)); + async->out = pipe_out[0]; +#ifndef __MINGW32__ async->pid = fork(); if (async->pid < 0) { error("fork (async) failed: %s", strerror(errno)); @@ -203,16 +213,33 @@ int start_async(struct async *async) close(pipe_out[0]); exit(!!async->proc(pipe_out[1], async->data)); } - async->out = pipe_out[0]; close(pipe_out[1]); +#else + async->fd_for_proc = pipe_out[1]; + async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL); + if (!async->tid) { + error("cannot create thread: %s", strerror(errno)); + close_pair(pipe_out); + return -1; + } +#endif return 0; } int finish_async(struct async *async) { +#ifndef __MINGW32__ int ret = 0; if (wait_or_whine(async->pid)) ret = error("waitpid (async) failed"); +#else + DWORD ret = 0; + if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0) + ret = error("waiting for thread failed: %lu", GetLastError()); + else if (!GetExitCodeThread(async->tid, &ret)) + ret = error("cannot get thread exit code: %lu", GetLastError()); + CloseHandle(async->tid); +#endif return ret; } diff --git a/run-command.h b/run-command.h index 94e1e9d516..407d3c3bc3 100644 --- a/run-command.h +++ b/run-command.h @@ -59,7 +59,12 @@ struct async { int (*proc)(int fd, void *data); void *data; int out; /* caller reads from here and closes it */ +#ifndef __MINGW32__ pid_t pid; +#else + HANDLE tid; + int fd_for_proc; +#endif }; int start_async(struct async *async); diff --git a/upload-pack.c b/upload-pack.c index 369cb1f77c..0d7aa18bfe 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -170,11 +170,8 @@ static void create_pack_file(void) pack_objects.git_cmd = 1; pack_objects.argv = argv; - if (start_command(&pack_objects)) { - /* daemon sets things up to ignore TERM */ - kill(rev_list.pid, SIGKILL); + if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); - } #ifndef __MINGW32__ /* We read from pack_objects.err to capture stderr output for From 36e0147fe5e941efb7f34f3d59845dbc9383ecd5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 Nov 2007 21:34:56 +0100 Subject: [PATCH 265/781] Move path handling functions from spawn-pipe.c to compat/mingw.c. Since these functions are MinGW-specific, they better belong into this compatibility file. They will be needed there in a follow-up change that reimplements execvp(). --- compat/mingw.c | 88 +++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 3 ++ spawn-pipe.c | 96 ++--------------------------------------------- 3 files changed, 94 insertions(+), 93 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 90dc0805ae..4b05718f03 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -441,6 +441,94 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) } } +static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +{ + char path[MAX_PATH]; + snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); + + if (tryexe && access(path, 0) == 0) + return xstrdup(path); + path[strlen(path)-4] = '\0'; + if (access(path, 0) == 0) + return xstrdup(path); + return NULL; +} + +/* + * Determines the absolute path of cmd using the the split path in path. + * If cmd contains a slash or backslash, no lookup is performed. + */ +char *mingw_path_lookup(const char *cmd, char **path) +{ + char **p = path; + char *prog = NULL; + int len = strlen(cmd); + int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + + if (strchr(cmd, '/') || strchr(cmd, '\\')) + prog = xstrdup(cmd); + + while (!prog && *p) { + prog = lookup_prog(*p++, cmd, tryexe); + } + if (!prog) { + prog = lookup_prog(".", cmd, tryexe); + if (!prog) + prog = xstrdup(cmd); + } + return prog; +} + +/* + * Splits the PATH into parts. + */ +char **mingw_get_path_split(void) +{ + char *p, **path, *envpath = getenv("PATH"); + int i, n = 0; + + if (!envpath || !*envpath) + return NULL; + + envpath = xstrdup(envpath); + p = envpath; + while (p) { + char *dir = p; + p = strchr(p, ';'); + if (p) *p++ = '\0'; + if (*dir) { /* not earlier, catches series of ; */ + ++n; + } + } + if (!n) + return NULL; + + path = xmalloc((n+1)*sizeof(char*)); + p = envpath; + i = 0; + do { + if (*p) + path[i++] = xstrdup(p); + p = p+strlen(p)+1; + } while (i < n); + path[i] = NULL; + + free(envpath); + + return path; +} + +void mingw_free_path_split(char **path) +{ + if (!path) + return; + + char **p = path; + while (*p) + free(*p++); + free(path); +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); diff --git a/git-compat-util.h b/git-compat-util.h index c6406d4379..f6deba520b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -499,6 +499,9 @@ int mingw_rename(const char*, const char*); extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); +extern char *mingw_path_lookup(const char *cmd, char **path); +extern char **mingw_get_path_split(void); +extern void mingw_free_path_split(char **path); /* Use git_lstat() instead of lstat()/stat() and * git_fstat() instead of fstat() on Windows diff --git a/spawn-pipe.c b/spawn-pipe.c index 3df7e22ed9..71232066c5 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -3,96 +3,6 @@ extern char **environ; -#ifdef __MINGW32__ -static char *lookup_prog(const char *dir, const char *cmd, int tryexe) -{ - char path[MAX_PATH]; - snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); - - if (tryexe && access(path, 0) == 0) - return xstrdup(path); - path[strlen(path)-4] = '\0'; - if (access(path, 0) == 0) - return xstrdup(path); - return NULL; -} - -/* - * Splits the PATH into parts. - */ -char **get_path_split() -{ - char *p, **path, *envpath = getenv("PATH"); - int i, n = 0; - - if (!envpath || !*envpath) - return NULL; - - envpath = xstrdup(envpath); - p = envpath; - while (p) { - char *dir = p; - p = strchr(p, ';'); - if (p) *p++ = '\0'; - if (*dir) { /* not earlier, catches series of ; */ - ++n; - } - } - if (!n) - return NULL; - - path = xmalloc((n+1)*sizeof(char*)); - p = envpath; - i = 0; - do { - if (*p) - path[i++] = xstrdup(p); - p = p+strlen(p)+1; - } while (i < n); - path[i] = NULL; - - free(envpath); - - return path; -} - -void free_path_split(char **path) -{ - if (!path) - return; - - char **p = path; - while (*p) - free(*p++); - free(path); -} - -/* - * Determines the absolute path of cmd using the the split path in path. - * If cmd contains a slash or backslash, no lookup is performed. - */ -static char *path_lookup(const char *cmd, char **path) -{ - char **p = path; - char *prog = NULL; - int len = strlen(cmd); - int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); - - if (strchr(cmd, '/') || strchr(cmd, '\\')) - prog = xstrdup(cmd); - - while (!prog && *p) { - prog = lookup_prog(*p++, cmd, tryexe); - } - if (!prog) { - prog = lookup_prog(".", cmd, tryexe); - if (!prog) - prog = xstrdup(cmd); - } - return prog; -} -#endif - /* cmd specifies the command to invoke. * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. * env specifies the environment. @@ -107,11 +17,11 @@ int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]) { #ifdef __MINGW32__ - char **path = get_path_split(); + char **path = mingw_get_path_split(); pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); - free_path_split(path); + mingw_free_path_split(path); #else pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); #endif @@ -187,7 +97,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, } } - prog = path_lookup(cmd, path); + prog = mingw_path_lookup(cmd, path); interpr = parse_interpreter(prog); for (argc = 0; argv[argc];) argc++; From 2952476e8e9e4b0f455e1569a29e0d3930ee84b2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 Nov 2007 21:38:57 +0100 Subject: [PATCH 266/781] Reimplement execvp() such that it can invoke shell scripts. We conveniently reuse mingw_execve(), which does the shbang interpretation as well as other painful Windows compatibility stuff. --- compat/mingw.c | 14 ++++++++++++++ git-compat-util.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4b05718f03..4e1003442d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -529,6 +529,20 @@ void mingw_free_path_split(char **path) free(path); } +void mingw_execvp(const char *cmd, const char **argv) +{ + char **path = mingw_get_path_split(); + char *prog = mingw_path_lookup(cmd, path); + + if (prog) { + mingw_execve(prog, argv, (const char **) environ); + free(prog); + } else + errno = ENOENT; + + mingw_free_path_split(path); +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); diff --git a/git-compat-util.h b/git-compat-util.h index f6deba520b..148b64ab04 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -430,6 +430,8 @@ unsigned int alarm(unsigned int seconds); #include void mingw_execve(const char *cmd, const char **argv, const char **env); #define execve mingw_execve +extern void mingw_execvp(const char *cmd, const char **argv); +#define execvp mingw_execvp int fork(); typedef int pid_t; #define waitpid(pid, status, options) \ From 5f50b3edfa54d04fb751dc847687541a4c611f7c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:01:31 +0100 Subject: [PATCH 267/781] Revert "Returning -1 does not fail like it should in MSys." This reverts commit 327005a9ef9c3b784e4742cece0710de6a549313. git-config should print a message and exit with error if --file is used and the file provided does not exist. This was not the case. The problem was introduced by the reverted commit. Signed-off-by: Steffen Prohaska --- config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.c b/config.c index 0badbeb62e..edea061892 100644 --- a/config.c +++ b/config.c @@ -443,7 +443,7 @@ int git_config_from_file(config_fn_t fn, const char *filename) int ret; FILE *f = fopen(filename, "r"); - ret = 1; + ret = -1; if (f) { config_file = f; config_file_name = filename; From c1561567eff8ae46e88aadc51c7f5062cca34776 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:14:27 +0100 Subject: [PATCH 268/781] fix warning (printf format) Signed-off-by: Steffen Prohaska --- builtin-ls-files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index b70da1863b..b55c79ec1a 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -208,7 +208,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) if (!show_stage) { fputs(tag, stdout); } else { - printf("%s%06o %s %d\t", + printf("%s%06lo %s %d\t", tag, ntohl(ce->ce_mode), abbrev ? find_unique_abbrev(ce->sha1,abbrev) From 156d5a32ad4dc70460a62980547bcfda788ace58 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:17:31 +0100 Subject: [PATCH 269/781] fix warning (const ptr) Signed-off-by: Steffen Prohaska --- exec_cmd.c | 4 ++-- run-command.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 6aa842bb4f..a2d82d3311 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -121,7 +121,7 @@ int execv_git_cmd(const char **argv) trace_argv_printf(argv, -1, "trace: exec:"); /* execvp() can only ever return if it fails */ - execvp(cmd.buf, (char **)argv); + execvp(cmd.buf, argv); trace_printf("trace: exec failed: %s\n", strerror(errno)); @@ -175,7 +175,7 @@ int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) trace_argv_printf(argv, -1, "trace: exec:"); - pid = spawnvpe_pipe(cmd.buf, argv, environ, + pid = spawnvpe_pipe(cmd.buf, argv, (const char **)environ, pin, pout); argv[0] = tmp; diff --git a/run-command.c b/run-command.c index d2e5f183d2..822449c5f5 100644 --- a/run-command.c +++ b/run-command.c @@ -15,7 +15,7 @@ int start_command(struct child_process *cmd) int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; int fderr[2] = { -1, -1 }; - char **env = environ; + const char **env = (const char **)environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { From e169a6e89f8b9affc8131e3b3b0752064c1dbc86 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:24:08 +0100 Subject: [PATCH 270/781] fix warning (unitialized variable) Signed-off-by: Steffen Prohaska --- transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transport.c b/transport.c index 5132d289da..d44fe7cee7 100644 --- a/transport.c +++ b/transport.c @@ -107,7 +107,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list) return; for (;;) { - int cmp, len; + int cmp = cmp, len; if (!fgets(buffer, sizeof(buffer), f)) { fclose(f); From 0f2bc7c7d28274ba2e130a03817c9ca2d677901e Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:27:12 +0100 Subject: [PATCH 271/781] fix warning (unused variable) --- upload-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upload-pack.c b/upload-pack.c index 0d7aa18bfe..e004c024cd 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -142,7 +142,7 @@ static void create_pack_file(void) struct async rev_list; struct child_process pack_objects; int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); - char data[8193], progress[128]; + char data[8193]; char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; int buffered = -1; From e176f0fb1519dc1a9c3e55aa00f03ffb85fc3143 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 3 Nov 2007 18:32:18 +0100 Subject: [PATCH 272/781] fix warning (int used as pointer) Signed-off-by: Steffen Prohaska --- test-chmtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-chmtime.c b/test-chmtime.c index b6dc548a2a..8a1e6b8479 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -22,7 +22,7 @@ int git_utime (const char *file_name, const struct utimbuf *times) time_t_to_filetime(times->modtime, &mft); time_t_to_filetime(times->actime, &aft); - if (!SetFileTime(_get_osfhandle(fh), NULL, &aft, &mft)) { + if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { errno = EINVAL; rc = -1; } else From 0ed5d28283854fc47f130d65f6b658398eef80d8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 Sep 2007 17:36:47 +0100 Subject: [PATCH 273/781] MinGW: Convert CR/LF to LF in tag signatures On Windows, gpg outputs CR/LF signatures. But since the tag messages are already stripped of the CR by stripspace(), it is arguably nicer to do the same for the tag signature. Actually, this patch does not look for CR/LF, but strips all CRs from the signature. [ sp: ported code to use strbuf ] Signed-off-by: Johannes Schindelin Signed-off-by: Steffen Prohaska --- builtin-tag.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/builtin-tag.c b/builtin-tag.c index 66e5a58307..ae8538897b 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -224,6 +224,20 @@ static int do_sign(struct strbuf *buffer) if (len < 0) return error("could not read the entire signature from gpg."); +#ifdef __MINGW32__ + /* strip CR from the line endings */ + { + int i, j; + for (i = j = 0; i < buffer->len; i++) + if (buffer->buf[i] != '\r') { + if (i != j) + buffer->buf[j] = buffer->buf[i]; + j++; + } + strbuf_setlen(buffer, j); + } +#endif + return 0; } From 24737fec8695e6c4aa569fbb39d83c950a276844 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 20 Oct 2007 21:59:28 +0200 Subject: [PATCH 274/781] git remote does not work from the t/ directory - skip the test. --- t/t5505-remote.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 636aec2f71..a56e5a32c2 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -4,6 +4,9 @@ test_description='git remote porcelain-ish' . ./test-lib.sh +say "git remote does not work in t/ - skipping" +test_done + GIT_CONFIG=.git/config export GIT_CONFIG From c2822f9d935cb75e759de0039840570cb91c1c08 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 6 Nov 2007 08:26:42 +0100 Subject: [PATCH 275/781] Exclude some stuff from Windows header files. There happens to be a name clash on 'boolean' in test-parse-options.c with a type defined one of Windows's OLE header files (rpcndr.h). Since we don't need that anyway, -DNOGDI does not pull those headers in. Signed-off-by: Johannes Sixt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e1fe7779ac..5cb6a31743 100644 --- a/Makefile +++ b/Makefile @@ -511,7 +511,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -I compat + COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From a67246dc8aa004c6aaa0060f04e6fda427099079 Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Sun, 4 Nov 2007 10:31:26 -0500 Subject: [PATCH 276/781] t3502: Disambiguate between file and rev by adding -- On a case insensitive file system, this test fails because git-diff doesn't know if it is asking for the file "A" or the tag "a". Adding "--" at the end of the ambiguous commands allows the test to finish properly. Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- t/t3502-cherry-pick-merge.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t3502-cherry-pick-merge.sh b/t/t3502-cherry-pick-merge.sh index 3274c6141b..7c92e261fc 100755 --- a/t/t3502-cherry-pick-merge.sh +++ b/t/t3502-cherry-pick-merge.sh @@ -36,7 +36,7 @@ test_expect_success 'cherry-pick a non-merge with -m should fail' ' git reset --hard && git checkout a^0 && ! git cherry-pick -m 1 b && - git diff --exit-code a + git diff --exit-code a -- ' @@ -45,7 +45,7 @@ test_expect_success 'cherry pick a merge without -m should fail' ' git reset --hard && git checkout a^0 && ! git cherry-pick c && - git diff --exit-code a + git diff --exit-code a -- ' @@ -98,7 +98,7 @@ test_expect_success 'revert a merge (1)' ' git reset --hard && git checkout c^0 && git revert -m 1 c && - git diff --exit-code a + git diff --exit-code a -- ' @@ -107,7 +107,7 @@ test_expect_success 'revert a merge (2)' ' git reset --hard && git checkout c^0 && git revert -m 2 c && - git diff --exit-code b + git diff --exit-code b -- ' From 9dcfde61ed7334e925fca7e62dbb5791547a5f5b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 4 Nov 2007 23:50:23 +0100 Subject: [PATCH 277/781] help: Teach help to try harder to locate help Help now tries to takes the argument as is and prefixed with "git-". If no html page is found an error is reported. With this change you can run "git help user-manual". Signed-off-by: Steffen Prohaska --- help.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/help.c b/help.c index b81ddf0fb5..02e59b75e0 100644 --- a/help.c +++ b/help.c @@ -7,6 +7,7 @@ #include "builtin.h" #include "exec_cmd.h" #include "common-cmds.h" +#include "dir.h" //#include /* most GUI terminals set COLUMNS (although some don't export it) */ @@ -242,6 +243,29 @@ void list_common_cmds_help(void) static void show_man_page(const char *git_cmd) { +#ifdef __MINGW32__ + { + char *htmlpath = make_native_separator( + mkpath("%s/doc/git/html/%s.html" + , git_install_prefix() + , git_cmd) + ); + if (!file_exists(htmlpath)) { + htmlpath = make_native_separator( + mkpath("%s/doc/git/html/git-%s.html" + , git_install_prefix() + , git_cmd) + ); + if (!file_exists(htmlpath)) { + fprintf(stderr, "Can't find help for '%s'.\n" + , git_cmd); + exit(1); + } + } + printf("Launching default browser to display HTML help ...\n"); + ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); + } +#else const char *page; if (!prefixcmp(git_cmd, "git")) @@ -255,17 +279,6 @@ static void show_man_page(const char *git_cmd) page = p; } -#ifdef __MINGW32__ - { - const char *htmlpath = make_native_separator( - mkpath("%s/doc/git/html/%s.html" - , git_install_prefix() - , page) - ); - printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); - } -#else execlp("man", "man", page, NULL); #endif } From 89e51c31058fde41a9bdf7ed4e3aa6dd50caca3b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 11 Nov 2007 21:36:19 +0100 Subject: [PATCH 278/781] Revert NO_ETC_PASSWD hack. This hack was introduced to work around missing Unix-like user database. But it turns out that the functionality required can easily be faked, Which happens in a follow-up patch. --- Makefile | 3 +-- git-compat-util.h | 3 --- ident.c | 13 ------------- path.c | 11 ----------- 4 files changed, 1 insertion(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 7add7b4fb8..0dc4200561 100644 --- a/Makefile +++ b/Makefile @@ -500,7 +500,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_CURL=YesPlease NO_SYMLINK_HEAD=YesPlease NO_IPV6=YesPlease - NO_ETC_PASSWD=YesPlease NO_SETENV=YesPlease NO_UNSETENV=YesPlease NO_STRCASESTR=YesPlease @@ -513,7 +512,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ETC_PASSWD -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat + COMPAT_CFLAGS += -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe diff --git a/git-compat-util.h b/git-compat-util.h index 7cf6269c42..66c4fb37a5 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -63,8 +63,6 @@ int mkstemp (char *__template); #include #include #include -#endif -#ifndef NO_ETC_PASSWD #include #include #include @@ -431,7 +429,6 @@ int symlink(const char *oldpath, const char *newpath); int fchmod(int fildes, mode_t mode); int lstat(const char *file_name, struct stat *buf); -/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ int socketpair(int d, int type, int protocol, int sv[2]); #define AF_UNIX 0 #define SOCK_STREAM 0 diff --git a/ident.c b/ident.c index 1f99984d76..9b2a852cb0 100644 --- a/ident.c +++ b/ident.c @@ -9,8 +9,6 @@ static char git_default_date[50]; -#ifndef NO_ETC_PASSWD - static void copy_gecos(const struct passwd *w, char *name, size_t sz) { char *src, *dst; @@ -72,11 +70,8 @@ static void copy_email(const struct passwd *pw) } } -#endif - static void setup_ident(void) { -#ifndef NO_ETC_PASSWD struct passwd *pw = NULL; /* Get the name ("gecos") */ @@ -101,7 +96,6 @@ static void setup_ident(void) copy_email(pw); } } -#endif /* And set the default date */ if (!git_default_date[0]) @@ -212,9 +206,7 @@ const char *fmt_ident(const char *name, const char *email, email = git_default_email; if (!*name) { -#ifndef NO_ETC_PASSWD struct passwd *pw; -#endif if (0 <= error_on_no_name && name == git_default_name && env_hint) { @@ -223,16 +215,11 @@ const char *fmt_ident(const char *name, const char *email, } if (0 < error_on_no_name) die("empty ident %s <%s> not allowed", name, email); -#ifndef NO_ETC_PASSWD pw = getpwuid(getuid()); if (!pw) die("You don't exist. Go away!"); strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name)); -#else - strlcpy(git_default_name, "unknown", - sizeof(git_default_name)); -#endif name = git_default_name; } diff --git a/path.c b/path.c index 2c5ebfb922..e264bb34a9 100644 --- a/path.c +++ b/path.c @@ -141,8 +141,6 @@ int validate_headref(const char *path) return -1; } -#ifndef NO_ETC_PASSWD - static char *user_path(char *buf, char *path, int sz) { struct passwd *pw; @@ -182,15 +180,6 @@ static char *user_path(char *buf, char *path, int sz) return buf; } -#else - -static char *user_path(char *buf, char *path, int sz) -{ - return getenv("HOME"); -} - -#endif - /* * First, one directory to try is determined by the following algorithm. * From 50d1c4c74552c97464536a17a45aba2f12facbec Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 08:07:00 +0100 Subject: [PATCH 279/781] Fake implementions of getpwuid(), getuid(), and getpwnam(). getpwuid() is kept as simple as possible so that no errors are generated. Since the information that it returns is not very useful, users are still required to set up user.name and user.email configuration. All uses of getpwuid() are like getpwuid(getuid()), hence, the return value of getpwuid() is irrelevant. getpwnam() is only used to resolve '~' and '~username' paths, which is an idiom not known on Windows, hence, we don't implement it, either. Signed-off-by: Johannes Sixt --- compat/mingw.c | 14 ++++++++++++++ git-compat-util.h | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4e1003442d..152915fd21 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -620,3 +620,17 @@ int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) } while (len < 0); return len; } + +struct passwd *mingw_getpwuid(int uid) +{ + static char user_name[100]; + static struct passwd p; + + DWORD len = sizeof(user_name); + if (!GetUserName(user_name, &len)) + return NULL; + p.pw_name = user_name; + p.pw_gecos = "unknown"; + p.pw_dir = NULL; + return &p; +} diff --git a/git-compat-util.h b/git-compat-util.h index 66c4fb37a5..79ce4e0c2f 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -527,6 +527,16 @@ int git_fstat(int fd, struct stat *buf); int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vsnprintf mingw_vsnprintf +struct passwd { + char *pw_name; + char *pw_gecos; + char *pw_dir; +}; +struct passwd *mingw_getpwuid(int uid); +#define getpwuid mingw_getpwuid +static inline int getuid() { return 1; } +static inline struct passwd *getpwnam(const char *name) { return NULL; } + #endif /* __MINGW32__ */ #endif From a23a15abc656e26e9f75c7943f7be9d64f6c801f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 12:41:53 +0100 Subject: [PATCH 280/781] Use Windows's native API instead of stat() in rename()'s error path. Since we are only interested whether the named entry is a directory, it is sufficient to use GetFileAttributes() instead of a full stat() call. --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 152915fd21..412cdd6f5a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -577,8 +577,8 @@ int mingw_rename(const char *pold, const char *pnew) return 0; /* TODO: translate more errors */ if (GetLastError() == ERROR_ACCESS_DENIED) { - struct stat st; - if (!stat(pnew, &st) && S_ISDIR(st.st_mode)) { + DWORD attrs = GetFileAttributes(pnew); + if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { errno = EISDIR; return -1; } From e569ab2ae74ed3b87196e26d8b9ac08296734225 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 12:52:41 +0100 Subject: [PATCH 281/781] Use a customized struct stat that also has the st_blocks member. Windows's struct stat does not have a st_blocks member. Since we already have our own stat/lstat/fstat implementations, we can just as well use a customized struct stat. This patch introduces just that, and also fills in the st_blocks member. On the other hand, we don't provide members that are never used. Signed-off-by: Johannes Sixt --- compat/mingw.c | 38 +++++++++++++++++++++++++++++--------- git-compat-util.h | 24 +++++++++++++++++------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 412cdd6f5a..f464fdb63d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -31,6 +31,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } +static inline size_t size_to_blocks(size_t s) +{ + return (s+511)/512; +} + extern int _getdrive( void ); /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In @@ -52,10 +57,10 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; - buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_blocks = size_to_blocks(buf->st_size); + buf->st_dev = _getdrive() - 1; buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); @@ -86,10 +91,10 @@ static int do_lstat(const char *file_name, struct stat *buf) /* We provide our own lstat/fstat functions, since the provided * lstat/fstat functions are so slow. These stat functions are * tailored for Git's usage (read: fast), and are not meant to be - * complete. Note that Git stat()s are redirected to git_lstat() + * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int git_lstat(const char *file_name, struct stat *buf) +int mingw_lstat(const char *file_name, struct mingw_stat *buf) { int namelen; static char alt_name[PATH_MAX]; @@ -117,7 +122,8 @@ int git_lstat(const char *file_name, struct stat *buf) } #undef fstat -int git_fstat(int fd, struct stat *buf) +#undef stat +int mingw_fstat(int fd, struct mingw_stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; @@ -127,8 +133,22 @@ int git_fstat(int fd, struct stat *buf) return -1; } /* direct non-file handles to MS's fstat() */ - if (GetFileType(fh) != FILE_TYPE_DISK) - return fstat(fd, buf); + if (GetFileType(fh) != FILE_TYPE_DISK) { + struct stat st; + if (fstat(fd, &st)) + return -1; + buf->st_ino = st.st_ino; + buf->st_gid = st.st_gid; + buf->st_uid = st.st_uid; + buf->st_mode = st.st_mode; + buf->st_size = st.st_size; + buf->st_blocks = size_to_blocks(buf->st_size); + buf->st_dev = st.st_dev; + buf->st_atime = st.st_atime; + buf->st_mtime = st.st_mtime; + buf->st_ctime = st.st_ctime; + return 0; + } if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; @@ -142,10 +162,10 @@ int git_fstat(int fd, struct stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; - buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = (_getdrive() - 1); + buf->st_blocks = size_to_blocks(buf->st_size); + buf->st_dev = _getdrive() - 1; buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); diff --git a/git-compat-util.h b/git-compat-util.h index 79ce4e0c2f..71887ee6ae 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -515,14 +515,24 @@ extern char *mingw_path_lookup(const char *cmd, char **path); extern char **mingw_get_path_split(void); extern void mingw_free_path_split(char **path); -/* Use git_lstat() instead of lstat()/stat() and - * git_fstat() instead of fstat() on Windows +/* Use mingw_lstat() instead of lstat()/stat() and + * mingw_fstat() instead of fstat() on Windows. + * struct stat is redefined because it lacks the st_blocks member. */ -int git_lstat(const char *file_name, struct stat *buf); -int git_fstat(int fd, struct stat *buf); -#define lstat(x,y) git_lstat(x,y) -#define stat(x,y) git_lstat(x,y) -#define fstat(x,y) git_fstat(x,y) +struct mingw_stat { + unsigned st_mode; + time_t st_mtime, st_atime, st_ctime; + unsigned st_dev, st_ino, st_uid, st_gid; + size_t st_size; + size_t st_blocks; +}; +int mingw_lstat(const char *file_name, struct mingw_stat *buf); +int mingw_fstat(int fd, struct mingw_stat *buf); +#define fstat mingw_fstat +#define lstat mingw_lstat +#define stat mingw_stat +static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) +{ return mingw_lstat(file_name, buf); } int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vsnprintf mingw_vsnprintf From dbdc65fe2db3ec5137081bc4d72d518bb65cffd3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 12:51:35 +0100 Subject: [PATCH 282/781] Revert the NO_ST_BLOCKS hack. This conditional was needed to work around the missing st_blocks member in Windows's struct stat. --- Makefile | 2 +- builtin-count-objects.c | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 0dc4200561..ff2a5ed787 100644 --- a/Makefile +++ b/Makefile @@ -512,7 +512,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS=YesPlease NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DNO_ST_BLOCKS -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat + COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe diff --git a/builtin-count-objects.c b/builtin-count-objects.c index 762c024279..f00306fb67 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -43,11 +43,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, if (lstat(path, &st) || !S_ISREG(st.st_mode)) bad = 1; else -#ifndef NO_ST_BLOCKS (*loose_size) += xsize_t(st.st_blocks); -#else - (*loose_size) += xsize_t((st.st_size+511)/512); -#endif } if (bad) { if (verbose) { From e0c9a54e11e1acf965b43c6abfac7a883a8565ed Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 13:00:06 +0100 Subject: [PATCH 283/781] Clean up some dummy compatibility implementations. In particular, sync() was never declared and caused a warning. --- compat/mingw.c | 4 ---- git-compat-util.h | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f464fdb63d..befdb147ca 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -315,10 +315,6 @@ char *mingw_getcwd(char *pointer, int len) return ret; } -void sync(void) -{ -} - void openlog(const char *ident, int option, int facility) { } diff --git a/git-compat-util.h b/git-compat-util.h index 71887ee6ae..d0c0884fc9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -505,9 +505,9 @@ int mingw_socket(int domain, int type, int protocol); int mingw_rename(const char*, const char*); #define rename mingw_rename -#define setlinebuf(x) -#define fsync(x) 0 -#define getppid() 1 +static inline int fsync(int fd) { return 0; } +static inline int getppid(void) { return 1; } +static inline void sync(void) {} extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From 73c1250e77f52dfe1b0bddb6eaf20532d1de58b2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 15:08:18 +0100 Subject: [PATCH 284/781] Declare getpagesize() - gcc provides it for us. It is in MinGW's libgcc.a, which appearently is always linked in. Signed-off-by: Johannes Sixt --- git-compat-util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/git-compat-util.h b/git-compat-util.h index d0c0884fc9..d85fdf5415 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -508,6 +508,7 @@ int mingw_rename(const char*, const char*); static inline int fsync(int fd) { return 0; } static inline int getppid(void) { return 1; } static inline void sync(void) {} +extern int getpagesize(void); /* defined in MinGW's libgcc.a */ extern void quote_argv(const char **dst, const char **src); extern const char *parse_interpreter(const char *cmd); From 6d305e33413451a26a38e82a863685fb11bc6cba Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 10:14:45 +0100 Subject: [PATCH 285/781] Implement setitimer() and sigaction(). The timer is implemented using a thread. Signed-off-by: Johannes Sixt --- compat/mingw.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 19 +++++++- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index befdb147ca..eaf6267025 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -650,3 +650,119 @@ struct passwd *mingw_getpwuid(int uid) p.pw_dir = NULL; return &p; } + + +static HANDLE timer_event; +static HANDLE timer_thread; +static int timer_interval; +static int one_shot; +static sig_handler_t timer_fn = SIG_DFL; + +/* The timer works like this: + * The thread, ticktack(), is basically a trivial routine that most of the + * time only waits to receive the signal to terminate. The main thread + * tells the thread to terminate by setting the timer_event to the signalled + * state. + * But ticktack() does not wait indefinitely; instead, it interrupts the + * wait state every now and then, namely exactly after timer's interval + * length. At these opportunities it calls the signal handler. + */ + +static __stdcall unsigned ticktack(void *dummy) +{ + while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { + if (timer_fn == SIG_DFL) + die("Alarm"); + if (timer_fn != SIG_IGN) + timer_fn(SIGALRM); + if (one_shot) + break; + } + return 0; +} + +static int start_timer_thread(void) +{ + timer_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (timer_event) { + timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); + if (!timer_thread ) + return errno = ENOMEM, + error("cannot create progress indicator"); + } else + return errno = ENOMEM, + error("cannot allocate resources for progress indicator"); + return 0; +} + +static void stop_timer_thread(void) +{ + if (timer_event) + SetEvent(timer_event); /* tell thread to terminate */ + if (timer_thread) { + int rc = WaitForSingleObject(timer_thread, 1000); + if (rc == WAIT_TIMEOUT) + error("timer thread did not terminate timely"); + else if (rc != WAIT_OBJECT_0) + error("waiting for timer thread failed: %lu", + GetLastError()); + CloseHandle(timer_thread); + } + if (timer_event) + CloseHandle(timer_event); + timer_event = NULL; + timer_thread = NULL; +} + +static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2) +{ + return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec; +} + +int setitimer(int type, struct itimerval *in, struct itimerval *out) +{ + static const struct timeval zero; + + if (out != NULL) + return errno = EINVAL, + error("setitmer param 3 != NULL not implemented"); + if (!is_timeval_eq(&in->it_interval, &zero) && + !is_timeval_eq(&in->it_interval, &in->it_value)) + return errno = EINVAL, + error("setitmer: it_interval must be zero or eq it_value"); + + if (timer_thread) + stop_timer_thread(); + + if (is_timeval_eq(&in->it_value, &zero) && + is_timeval_eq(&in->it_interval, &zero)) + return 0; + + timer_interval = in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000; + one_shot = is_timeval_eq(&in->it_value, &zero); + atexit(stop_timer_thread); + return start_timer_thread(); +} + +int sigaction(int sig, struct sigaction *in, struct sigaction *out) +{ + if (sig != SIGALRM) + return errno = EINVAL, + error("sigaction only implemented for SIGALRM"); + if (out != NULL) + return errno = EINVAL, + error("sigaction: param 3 != NULL not implemented"); + + timer_fn = in->sa_handler; + return 0; +} + +#undef signal +sig_handler_t mingw_signal(int sig, sig_handler_t handler) +{ + if (sig != SIGALRM) + return signal(sig, handler); + sig_handler_t old = timer_fn; + timer_fn = handler; + return old; +} diff --git a/git-compat-util.h b/git-compat-util.h index d85fdf5415..bdda57221a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -454,7 +454,6 @@ typedef int pid_t; #define WNOHANG 1 #define SIGKILL 0 #define SIGCHLD 0 -#define SIGALRM 0 #define SIGPIPE 0 #define ECONNABORTED 0 @@ -548,6 +547,24 @@ struct passwd *mingw_getpwuid(int uid); static inline int getuid() { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } +struct itimerval { + struct timeval it_value, it_interval; +}; +int setitimer(int type, struct itimerval *in, struct itimerval *out); +#define ITIMER_REAL 0 + +typedef void (__cdecl *sig_handler_t)(int); +struct sigaction { + sig_handler_t sa_handler; + unsigned sa_flags; +}; +int sigaction(int sig, struct sigaction *in, struct sigaction *out); +#define sigemptyset(x) (void)0 +#define SA_RESTART 0 +#define SIGALRM 100 +sig_handler_t mingw_signal(int sig, sig_handler_t handler); +#define signal mingw_signal + #endif /* __MINGW32__ */ #endif From 2b3d05218b6184c655507673b03d923e0c9ae4d6 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 12 Nov 2007 22:27:06 +0100 Subject: [PATCH 286/781] Revert "Make the progress indicator work when the total runtime is unknown." This reverts commit ddb51d3baf427a9c38ae1d297eb07daae338536f, we don't need it anymore, now that we have an implementation for timers. --- progress.c | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/progress.c b/progress.c index 0e57fe705c..3f6a602a53 100644 --- a/progress.c +++ b/progress.c @@ -37,26 +37,13 @@ struct progress { static volatile sig_atomic_t progress_update; -#ifndef __MINGW32__ static void progress_interval(int signum) { progress_update = 1; } -#else -static HANDLE progress_event; -static HANDLE progress_thread; - -static __stdcall unsigned heartbeat(void *dummy) -{ - while (WaitForSingleObject(progress_event, 1000) == WAIT_TIMEOUT) - progress_update = 1; - return 0; -} -#endif static void set_progress_signal(void) { -#ifndef __MINGW32__ struct sigaction sa; struct itimerval v; @@ -72,43 +59,13 @@ static void set_progress_signal(void) v.it_interval.tv_usec = 0; v.it_value = v.it_interval; setitimer(ITIMER_REAL, &v, NULL); -#else - /* this is just eye candy: errors are not fatal */ - progress_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (progress_event) { - progress_thread = (HANDLE) _beginthreadex(NULL, 0, heartbeat, NULL, 0, NULL); - if (!progress_thread ) - error("cannot create progress indicator"); - } else - error("cannot allocate resources for progress indicator"); -#endif } static void clear_progress_signal(void) { -#ifndef __MINGW32__ struct itimerval v = {{0,},}; setitimer(ITIMER_REAL, &v, NULL); signal(SIGALRM, SIG_IGN); -#else - /* this is just eye candy: errors are not fatal */ - if (progress_event) - SetEvent(progress_event); /* tells thread to terminate */ - if (progress_thread) { - int rc = WaitForSingleObject(progress_thread, 1000); - if (rc == WAIT_TIMEOUT) - error("progress thread did not terminate timely"); - else if (rc != WAIT_OBJECT_0) - error("waiting for progress thread failed: %lu", - GetLastError()); - CloseHandle(progress_thread); - } - if (progress_event) - CloseHandle(progress_event); - progress_event = NULL; - progress_thread = NULL; -#endif - progress_update = 0; } From 3e0ba4ccdc1f4058a31eacb2f6ccca1ffa094e5a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 15:44:48 +0100 Subject: [PATCH 287/781] Clean up cruft from the MINGW32 section of git-compat-util.h Quite a lot of stuff has accumulated or is now obsolete. The stubs of POSIX functions that are not implemented or that always fail are now implemented as inline functions so that they exist in only one place. --- compat/mingw.c | 43 ---------------------------------------- git-compat-util.h | 50 +++++++++++++++++++++++------------------------ 2 files changed, 24 insertions(+), 69 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index eaf6267025..63c632adaf 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,28 +1,8 @@ #include -#include -#include #include "../git-compat-util.h" unsigned int _CRT_fmode = _O_BINARY; -int readlink(const char *path, char *buf, size_t bufsiz) -{ - errno = ENOSYS; - return -1; -} - -int symlink(const char *oldpath, const char *newpath) -{ - errno = ENOSYS; - return -1; -} - -int fchmod(int fildes, mode_t mode) -{ - errno = EBADF; - return -1; -} - static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; @@ -175,29 +155,6 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } -/* missing: link, mkstemp, fchmod, getuid (?), gettimeofday */ -int socketpair(int d, int type, int protocol, int sv[2]) -{ - return -1; -} -int syslog(int type, char *bufp, ...) -{ - return -1; -} -unsigned int alarm(unsigned int seconds) -{ - return 0; -} -#include -int fork() -{ - return -1; -} - -int kill(pid_t pid, int sig) -{ - return -1; -} unsigned int sleep (unsigned int __seconds) { Sleep(__seconds*1000); diff --git a/git-compat-util.h b/git-compat-util.h index bdda57221a..bfdee76749 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -407,46 +407,46 @@ static inline int strtol_i(char const *s, int base, int *result) #ifdef __MINGW32__ -#ifndef S_ISLNK +#include + #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 -#endif - -#ifndef S_ISGRP -#define S_ISGRP(x) 0 #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 #define S_ISGID 0 #define S_IROTH 0 #define S_IXOTH 0 -#endif -int readlink(const char *path, char *buf, size_t bufsiz); -int symlink(const char *oldpath, const char *newpath); -#define link symlink -int fchmod(int fildes, mode_t mode); -int lstat(const char *file_name, struct stat *buf); +static inline int readlink(const char *path, char *buf, size_t bufsiz) +{ errno = ENOSYS; return -1; } +static inline int symlink(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int link(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int fchmod(int fildes, mode_t mode) +{ errno = ENOSYS; return -1; } +static inline int fork(void) +{ errno = ENOSYS; return -1; } +static inline int kill(pid_t pid, int sig) +{ errno = ENOSYS; return -1; } +static inline unsigned int alarm(unsigned int seconds) +{ return 0; } -int socketpair(int d, int type, int protocol, int sv[2]); -#define AF_UNIX 0 -#define SOCK_STREAM 0 -int syslog(int type, char *bufp, ...); -#define LOG_ERR 1 -#define LOG_INFO 2 -#define LOG_DAEMON 4 -unsigned int alarm(unsigned int seconds); -#include void mingw_execve(const char *cmd, const char **argv, const char **env); #define execve mingw_execve extern void mingw_execvp(const char *cmd, const char **argv); #define execvp mingw_execvp -int fork(); typedef int pid_t; -#define waitpid(pid, status, options) \ - ((options == 0) ? _cwait((status), (pid), 0) \ - : (errno = EINVAL, -1)) +static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +{ + if (options == 0) + return _cwait(status, pid, 0); + else + return errno = EINVAL, -1; +} + #define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ #define WEXITSTATUS(x) ((x) & 0xff) #define WIFSIGNALED(x) ((unsigned)(x) > 259) @@ -455,9 +455,7 @@ typedef int pid_t; #define SIGKILL 0 #define SIGCHLD 0 #define SIGPIPE 0 -#define ECONNABORTED 0 -int kill(pid_t pid, int sig); unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); From cf1fd675d2fb05c46ea472bbb3266985b63fbf01 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 16:57:47 +0100 Subject: [PATCH 288/781] Implement a stub for fcntl(). This stub does nothing for F_GETFD and F_SETFD, and fails for all other commands. Signed-off-by: Johannes Sixt --- git-compat-util.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index bfdee76749..85b5d8806a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -563,6 +563,13 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out); sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +#define F_GETFD 1 +#define F_SETFD 2 +#define FD_CLOEXEC 0x1 +static inline int mingw_fcntl(int fd, int cmd, long arg) +{ return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } +#define fcntl mingw_fcntl + #endif /* __MINGW32__ */ #endif From 0102b1b02ea59cafbfa72fb16f4359387154094a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 17:02:09 +0100 Subject: [PATCH 289/781] Revert "Windows does not have the close-on-exec flag." This reverts commit e7a70c5ddfa0f925760c131c2c60c25b814df222. We now have a fcntl stub that makes the bracketed piece of code a no-op. --- sha1_file.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index 0e527f7c6f..1df56aa417 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -653,7 +653,6 @@ static int open_packed_git_1(struct packed_git *p) } else if (p->pack_size != st.st_size) return error("packfile %s size changed", p->pack_name); -#ifndef __MINGW32__ /* We leave these file descriptors open with sliding mmap; * there is no point keeping them open across exec(), though. */ @@ -663,7 +662,6 @@ static int open_packed_git_1(struct packed_git *p) fd_flag |= FD_CLOEXEC; if (fcntl(p->pack_fd, F_SETFD, fd_flag) == -1) return error("cannot set FD_CLOEXEC"); -#endif /* Verify we recognize this pack file format. */ if (read_in_full(p->pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) From 155e6d080b57b968f853b0076ea3de0f24f4975d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 17:44:08 +0100 Subject: [PATCH 290/781] Fix setitimer implementation to register only one cleanup with atexit. Signed-off-by: Johannes Sixt --- compat/mingw.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 63c632adaf..9b503a0eec 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -679,6 +679,7 @@ static inline int is_timeval_eq(const struct timeval *i1, const struct timeval * int setitimer(int type, struct itimerval *in, struct itimerval *out) { static const struct timeval zero; + static int atexit_done; if (out != NULL) return errno = EINVAL, @@ -697,7 +698,10 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out) timer_interval = in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000; one_shot = is_timeval_eq(&in->it_value, &zero); - atexit(stop_timer_thread); + if (!atexit_done) { + atexit(stop_timer_thread); + atexit_done = 1; + } return start_timer_thread(); } From a5ac001accd3566b910008cb5068802f7968b711 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 3 Nov 2007 22:35:03 +0100 Subject: [PATCH 291/781] upload-pack: rely on finish_command() and finish_async() We don't need explicitly handle the processes anymore. --- upload-pack.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 38b774fa34..34299308f8 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -265,29 +265,6 @@ static void create_pack_file(void) goto fail; } } - - if (finish_command(&pack_objects)) { - error("git-upload-pack: git-pack-objects died with error."); - goto fail; - } - if (finish_async(&rev_list)) - goto fail; /* error was already reported */ - - /* flush the data */ - if (0 <= buffered) { - data[0] = buffered; - sz = send_client_data(1, data, 1); - if (sz < 0) - goto fail; - fprintf(stderr, "flushed.\n"); - } - if (use_sideband) - packet_flush(1); - return; - - fail: - send_client_data(3, abort_msg, sizeof(abort_msg)); - die("git-upload-pack: %s", abort_msg); #else char *cp; @@ -322,6 +299,14 @@ static void create_pack_file(void) } else goto fail; +#endif + + if (finish_command(&pack_objects)) { + error("git-upload-pack: git-pack-objects died with error."); + goto fail; + } + if (finish_async(&rev_list)) + goto fail; /* error was already reported */ /* flush the data */ if (0 <= buffered) { @@ -333,16 +318,11 @@ static void create_pack_file(void) } if (use_sideband) packet_flush(1); - if (waitpid(pack_objects.pid, NULL, 0) < 0) - die("git-upload-pack: waiting for pack-objects: %s", - strerror(errno)); return; fail: - kill(pack_objects.pid, SIGKILL); send_client_data(3, abort_msg, sizeof(abort_msg)); die("git-upload-pack: %s", abort_msg); -#endif } static int got_sha1(char *hex, unsigned char *sha1) From fab21181f4b096a5f2b4f144353a0e22d35c5f7a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 15 Nov 2007 22:22:47 +0100 Subject: [PATCH 292/781] Implement a wrapper of the open() function. The wrapper does two things: - Requests to open /dev/null are redirected to open the nul pseudo file. - A request to open a file that currently exists as a directory, then Windows's open fails with EACCES; this is changed to EISDIR. Signed-off-by: Johannes Sixt --- compat/mingw.c | 20 ++++++++++++++++++++ git-compat-util.h | 5 ++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9b503a0eec..384b3b67a1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,26 @@ unsigned int _CRT_fmode = _O_BINARY; +#undef open +int mingw_open (const char *filename, int oflags, ...) +{ + va_list args; + unsigned mode; + va_start(args, oflags); + mode = va_arg(args, int); + va_end(args); + + if (!strcmp(filename, "/dev/null")) + filename = "nul"; + int fd = open(filename, oflags, mode); + if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { + DWORD attrs = GetFileAttributes(filename); + if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) + errno = EISDIR; + } + return fd; +} + static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; diff --git a/git-compat-util.h b/git-compat-util.h index 1bbdb2f2fb..bfab97d057 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -500,9 +500,8 @@ static inline int git_unlink(const char *pathname) { } #define unlink git_unlink -#define open(P, F, M...) \ - (__builtin_constant_p(*(P)) && !strcmp(P, "/dev/null") ? \ - open("nul", F, ## M) : open(P, F, ## M)) +int mingw_open (const char *filename, int oflags, ...); +#define open mingw_open #include struct tm *gmtime_r(const time_t *timep, struct tm *result); From e8586bac156301508f66c0644d6614a003229e2c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 15 Nov 2007 22:26:49 +0100 Subject: [PATCH 293/781] Revert "Work around missing EISDIR errno values." This reverts the remaining part of commit ff61d9fc99a60a7c0320538a278d5f58680e120d. --- refs.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/refs.c b/refs.c index aa8045d89d..aff02cd09d 100644 --- a/refs.c +++ b/refs.c @@ -1059,15 +1059,6 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, if (!(oflags & O_CREAT) && errno == ENOENT) return 0; -#ifdef __MINGW32__ - if ((oflags & O_CREAT) && errno == EACCES) { - struct stat st; - if (stat(log_file, &st) == 0 && S_ISDIR(st.st_mode)) - errno = EISDIR; - else - errno = EACCES; - } -#endif if ((oflags & O_CREAT) && errno == EISDIR) { if (remove_empty_directories(log_file)) { return error("There are still logs under '%s'", From a8cf9a4ac19e9a2e01eb333144ef3bcef465a78b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:59:29 +0100 Subject: [PATCH 294/781] Remove unnecessary dd function. The test now uses test-genrandom instead of dd if=/dev/random. --- t/t5301-sliding-window.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh index 9a6d6aceac..073ac0c6f9 100755 --- a/t/t5301-sliding-window.sh +++ b/t/t5301-sliding-window.sh @@ -6,10 +6,6 @@ test_description='mmap sliding window tests' . ./test-lib.sh -dd () { - perl -e 'print pack("C", rand(256)) foreach 0 .. 32767' -} - test_expect_success \ 'setup' \ 'rm -f .git/index* From efe7309073bcb56b5de0d2f71cf02013c8a179fe Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:53:41 +0100 Subject: [PATCH 295/781] sum.exe is available from GNUWin32 (CoreUtils). --- t/t1002-read-tree-m-u-2way.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index 36642d4119..42e5cf8181 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,12 +10,6 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh -sum ./test-lib.sh >/dev/null 2>&1 || { - function sum () { - md5sum "$@" - } -} - _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { From 157737a3d92d067c09908a345ab595fb2b3d89bf Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:55:58 +0100 Subject: [PATCH 296/781] stat.exe is available from GNUWin32 (CoreUtils). --- t/t5300-pack-object.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 9a81d84106..169f60e33a 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -26,12 +26,6 @@ corrupt() ) < $1 > $2 } -test "$no_symlinks" && { - stat() { - ls -l "$3" | tr -s ' ' ' ' | cut -d' ' -f5 - } -} - test_expect_success \ 'setup' \ 'rm -f .git/index* From ff1c27fb4e28c253de43b6ca3e8ab00d594fb9c5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 08:58:13 +0100 Subject: [PATCH 297/781] Revert "Protect {tree} from being expanded by the shell." This reverts commit bff909b88259160b50823f277ea8c1426e4f7aa0. git-tag is now a builtin and does not need the extra escaping anymore. --- t/t5515-fetch-merge-logic.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 483a554d94..31c1081617 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -20,7 +20,7 @@ test_expect_success setup ' git add file && git commit -a -m One && git tag tag-one && - git-tag tag-one-tree HEAD^\{tree} && + git tag tag-one-tree HEAD^{tree} && git branch one && echo two >> file && @@ -31,7 +31,7 @@ test_expect_success setup ' echo three >> file && git commit -a -m Three && git tag -a -m "Tag Three" tag-three && - git-tag -a -m "Tag Three file" tag-three-file HEAD^\{tree}:file && + git tag -a -m "Tag Three file" tag-three-file HEAD^{tree}:file && git branch three && echo master >> file && From 3dffb74b2c118b1eb58aab27b7bbf76cee7974bb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 22:53:18 +0100 Subject: [PATCH 298/781] Use start_command() and finish_command() to run the pager. This gets rid of a call to spawnvpe_pipe() (and Windows-specific cwait()). --- pager.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pager.c b/pager.c index a55f4e9d1e..de1bc799f5 100644 --- a/pager.c +++ b/pager.c @@ -1,5 +1,4 @@ #include "cache.h" -#include "spawn-pipe.h" /* * This is split up from the rest of git so that we might do @@ -23,12 +22,18 @@ static void run_pager(const char *pager) execl("/bin/sh", "sh", "-c", pager, NULL); } #else -static pid_t pager_pid; +#include "run-command.h" + +const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +static struct child_process pager_process = { + .argv = pager_argv, + .in = -1 +}; static void collect_pager(void) { fflush(stdout); close(1); /* signals EOF to pager */ - cwait(NULL, pager_pid, 0); + finish_command(&pager_process); } #endif @@ -36,10 +41,8 @@ void setup_pager(void) { #ifndef __MINGW32__ pid_t pid; -#else - const char *pager_argv[] = { "sh", "-c", NULL, NULL }; -#endif int fd[2]; +#endif const char *pager = getenv("GIT_PAGER"); if (!isatty(1)) @@ -58,9 +61,9 @@ void setup_pager(void) pager_in_use = 1; /* means we are emitting to terminal */ +#ifndef __MINGW32__ if (pipe(fd) < 0) return; -#ifndef __MINGW32__ pid = fork(); if (pid < 0) { close(fd[0]); @@ -88,13 +91,12 @@ void setup_pager(void) #else /* spawn the pager */ pager_argv[2] = pager; - pager_pid = spawnvpe_pipe(pager_argv[0], pager_argv, environ, fd, NULL); - if (pager_pid < 0) + if (start_command(&pager_process)) return; /* original process continues, but writes to the pipe */ - dup2(fd[1], 1); - close(fd[1]); + dup2(pager_process.in, 1); + close(pager_process.in); /* this makes sure that the parent terminates after the pager */ atexit(collect_pager); From 7828980b8c727d85e189400fbd21c59ddaa3c666 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 23:35:32 +0100 Subject: [PATCH 299/781] Revert "sum.exe is available from GNUWin32 (CoreUtils)." This reverts commit efe7309073bcb56b5de0d2f71cf02013c8a179fe. This "sum.exe" knows it better and writes CRLF line endings. Hmpf. --- t/t1002-read-tree-m-u-2way.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index 42e5cf8181..36642d4119 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,6 +10,12 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh +sum ./test-lib.sh >/dev/null 2>&1 || { + function sum () { + md5sum "$@" + } +} + _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { From 3deda759198c2a69f280135c0af67e51518cce51 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 17 Nov 2007 22:41:11 +0100 Subject: [PATCH 300/781] upload-pack: Do not announce sideband support when it is not supported On Windows we currently don't support sideband communicaton. The protocol implementation is already disabled, but it was still announced in the server capabilities. --- upload-pack.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 34299308f8..84569a3aad 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -596,8 +596,11 @@ static void receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack side-band" - " side-band-64k ofs-delta shallow no-progress"; + static const char *capabilities = "multi_ack thin-pack" +#ifndef __MINGW32__ + " side-band side-band-64k" +#endif + " ofs-delta shallow no-progress"; struct object *o = parse_object(sha1); if (!o) From 069930410211632f2f8beea303771088226b523f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 16:09:26 +0100 Subject: [PATCH 301/781] Use relative paths to make installation relocatable mingw uses relative paths for template_dir and ETC_GITCONFIG to make an installation relocatable. Relative paths will be expanded relative to git_exec_dir(). This mechanism is now included in official git.git. We used a different mechanism to create a relocatable installation. We used to prefix absolute Unix paths with the installation prefix, derived from the path of git.exe. This commit reverts our implementation to match mingw. Part of the change are reverts of the following commits, which are no longer needed: 4e8904080d62be07a139436aa44044e05e380a2c 0fbe22da392f39e1d144f78ef08b2dbdb882c164. 636116b8a79c7c810afe8ae8e4c37e0a1de6f7b7. Signed-off-by: Steffen Prohaska --- Makefile | 7 ++++--- builtin-init-db.c | 11 ----------- config.c | 11 ----------- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 4c749a0357..8586fcd397 100644 --- a/Makefile +++ b/Makefile @@ -523,7 +523,8 @@ ifneq (,$(findstring MINGW,$(uname_S))) EXTLIBS += -lws2_32 X = .exe NOEXECTEMPL = .noexec - prefix = + template_dir = ../share/git-core/templates/ + ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease @@ -774,12 +775,12 @@ endif # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) -ETC_GITCONFIG_SQ = \057etc/gitconfig +ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) -template_dir_SQ = \057share/git-core/templates +template_dir_SQ = $(subst ','\'',$(template_dir)) prefix_SQ = $(subst ','\'',$(prefix)) sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) diff --git a/builtin-init-db.c b/builtin-init-db.c index 2feec40eb6..bb132ec086 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -145,17 +145,6 @@ static void copy_templates(const char *git_dir, int len, const char *template_di template_dir = prefix_path(exec_path, strlen(exec_path), template_dir); } -#if __MINGW32__ - /* - * If it is an absolute Unix path it is prefixed with - * the git_install_prefix(). - */ - else if (template_dir[0] == '/') { - const char* prefix = git_install_prefix(); - template_dir = prefix_path(prefix, strlen(prefix), - template_dir); - } -#endif } strcpy(template_path, template_dir); template_len = strlen(template_path); diff --git a/config.c b/config.c index 0b167ceb75..7b9ded1655 100644 --- a/config.c +++ b/config.c @@ -473,17 +473,6 @@ const char *git_etc_gitconfig(void) system_wide = prefix_path(exec_path, strlen(exec_path), system_wide); } -#if __MINGW32__ - /* - * If it is an absolute Unix path it is prefixed with - * the git_install_prefix(). - */ - else if (system_wide[0] == '/') { - const char* prefix = git_install_prefix(); - system_wide = prefix_path(prefix, strlen(prefix), - system_wide); - } -#endif } return system_wide; } From e9d8b9207e7ae7be0cf33a7cdc18d0e14c12c02a Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 16:43:13 +0100 Subject: [PATCH 302/781] help: search html documentation relativ to git_exec_dir() Global gitconfig and templates are searched relativ to git_exec_dir() to make the installation relocatable. This commit changes help to do the same for finding the html documentation. Signed-off-by: Steffen Prohaska --- help.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/help.c b/help.c index 90d5a03345..f89164a760 100644 --- a/help.c +++ b/help.c @@ -245,15 +245,16 @@ static void show_man_page(const char *git_cmd) { #ifdef __MINGW32__ { + const char* exec_path = git_exec_path(); char *htmlpath = make_native_separator( - mkpath("%s/doc/git/html/%s.html" - , git_install_prefix() - , git_cmd) + mkpath("%s/../doc/git/html/%s.html" + , exec_path + , git_cmd) ); if (!file_exists(htmlpath)) { htmlpath = make_native_separator( - mkpath("%s/doc/git/html/git-%s.html" - , git_install_prefix() + mkpath("%s/../doc/git/html/git-%s.html" + , exec_path , git_cmd) ); if (!file_exists(htmlpath)) { From 51355b1ede40a910bf4a62f9a8d0cbd7abcdecf7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 16:45:19 +0100 Subject: [PATCH 303/781] remove git_install_prefix() git_install_prefix() is no longer needed. Relocatable paths are searched relative to git_exec_dir(). This commit removes git_install_prefix(). Signed-off-by: Steffen Prohaska --- cache.h | 1 - path.c | 35 ----------------------------------- 2 files changed, 36 deletions(-) diff --git a/cache.h b/cache.h index 1fbc9a1987..550e8ad192 100644 --- a/cache.h +++ b/cache.h @@ -391,7 +391,6 @@ static inline int is_dev_null(const char *str) const char *make_absolute_path(const char *path); /* Convert slashes in place. On Windows to backslashes. */ char *make_native_separator(char *path); -const char *git_install_prefix(); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/path.c b/path.c index 01f35d5e7d..2a76269705 100644 --- a/path.c +++ b/path.c @@ -359,41 +359,6 @@ const char *make_absolute_path(const char *path) return buf; } -const char* git_install_prefix() -{ -#ifdef __MINGW32__ - static char* prefix; - - if (prefix) { - return prefix; - } - - char* p; - int pgm_len = strlen(_pgmptr); - prefix = xmalloc(pgm_len + 1); - strcpy(prefix, _pgmptr); - p = strrchr(prefix, '\\'); /* \bin\ <- p */ - if (p) { - *p = '\0'; - p = strrchr(prefix, '\\'); /* \ <- p */ - if (p) { - *p = '\0'; - for (p = prefix; *p; p++) - if (*p == '\\') - *p = '/'; - return prefix; - } - } - - /* Note, according to the msdn documentation we have a full path - if started through the shell and this error should never happen. */ - fprintf(stderr, "Fatal Error: failed to locate installation root.\n"); - exit(1); -#else - return ""; -#endif -} - char *make_native_separator(char* path) { #ifdef __MINGW32__ char* c; From 5e23af17e42294bae625713c754ad98838b5e9bc Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:40:12 +0100 Subject: [PATCH 304/781] Remove unnecessary decl of sync() Signed-off-by: Steffen Prohaska --- builtin-prune-packed.c | 2 -- builtin-prune.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index b61b73a900..23faf3129f 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -8,8 +8,6 @@ static const char prune_packed_usage[] = #define DRY_RUN 01 #define VERBOSE 02 -void sync(void); - static struct progress *progress; static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) diff --git a/builtin-prune.c b/builtin-prune.c index 02e4c09b0e..44df59e4a7 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -8,8 +8,6 @@ static const char prune_usage[] = "git-prune [-n]"; static int show_only; -void sync(void); - static int prune_object(char *path, const char *filename, const unsigned char *sha1) { if (show_only) { From 32dead9686779b65214c688bbe23eebdae2980f5 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:51:40 +0100 Subject: [PATCH 305/781] Use getpagesize() from git-compat-util.h Signed-off-by: Steffen Prohaska --- config.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/config.c b/config.c index 7b9ded1655..ed96213c44 100644 --- a/config.c +++ b/config.c @@ -15,8 +15,6 @@ static const char *config_file_name; static int config_linenr; static int zlib_compression_seen; -extern int getpagesize(); - static int get_next_char(void) { int c; From f8fd915d0c397c59ccf2f0cb96552e19b440dde8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:22:04 +0100 Subject: [PATCH 306/781] Move environment functions from spawn-pipe.c to compat/mingw.c We want to get rid of spawn-pipe.*, but these functions will be needed. On the way, the function signature was changed to avoid warnings about incompatible pointer types when the argument is the global variable "environ". --- compat/mingw.c | 39 +++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 4 ++++ spawn-pipe.c | 39 --------------------------------------- spawn-pipe.h | 3 --- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 384b3b67a1..0456319ba6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -536,6 +536,45 @@ void mingw_execvp(const char *cmd, const char **argv) mingw_free_path_split(path); } +char **copy_environ() +{ + return copy_env(environ); +} + +char **copy_env(char **env) +{ + char **s; + int n = 1; + for (s = env; *s; s++) + n++; + s = xmalloc(n*sizeof(char *)); + memcpy(s, env, n*sizeof(char *)); + return s; +} + +void env_unsetenv(char **env, const char *name) +{ + int src, dst; + size_t nmln; + + nmln = strlen(name); + + for (src = dst = 0; env[src]; ++src) { + size_t enln; + enln = strlen(env[src]); + if (enln > nmln) { + /* might match, and can test for '=' safely */ + if (0 == strncmp (env[src], name, nmln) + && '=' == env[src][nmln]) + /* matches, so skip */ + continue; + } + env[dst] = env[src]; + ++dst; + } + env[dst] = NULL; +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); diff --git a/git-compat-util.h b/git-compat-util.h index a259da5eeb..768e7fc696 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -473,6 +473,10 @@ static inline int waitpid(pid_t pid, unsigned *status, unsigned options) #define SIGCHLD 0 #define SIGPIPE 0 +char **copy_environ(); +char **copy_env(char **env); +void env_unsetenv(char **env, const char *name); + unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); diff --git a/spawn-pipe.c b/spawn-pipe.c index 71232066c5..9cb0cf5b70 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -129,42 +129,3 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, return pid; } - -const char **copy_environ() -{ - return copy_env(environ); -} - -const char **copy_env(const char **env) -{ - const char **s; - int n = 1; - for (s = env; *s; s++) - n++; - s = xmalloc(n*sizeof(const char *)); - memcpy(s, env, n*sizeof(const char *)); - return s; -} - -void env_unsetenv(const char **env, const char *name) -{ - int src, dst; - size_t nmln; - - nmln = strlen(name); - - for (src = dst = 0; env[src]; ++src) { - size_t enln; - enln = strlen(env[src]); - if (enln > nmln) { - /* might match, and can test for '=' safely */ - if (0 == strncmp (env[src], name, nmln) - && '=' == env[src][nmln]) - /* matches, so skip */ - continue; - } - env[dst] = env[src]; - ++dst; - } - env[dst] = NULL; -} diff --git a/spawn-pipe.h b/spawn-pipe.h index 3807819ae8..9bf387e411 100644 --- a/spawn-pipe.h +++ b/spawn-pipe.h @@ -1,5 +1,2 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); -const char **copy_environ(); -const char **copy_env(const char **env); -void env_unsetenv(const char **env, const char *name); From 3393222e4877c26a4d6ac8f43b7584efa4c571d3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:25:03 +0100 Subject: [PATCH 307/781] Reimplement start_command() to work just like the old spawnvpe_pipe(). The idea is to duplicate the handles that we want to pass to the child to stdin, stdout, or stderr after making a backup duplicate, then spawn the child program, then duplicate the backups back in place. --- run-command.c | 161 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 137 insertions(+), 24 deletions(-) diff --git a/run-command.c b/run-command.c index e5d029f7a2..05934f708f 100644 --- a/run-command.c +++ b/run-command.c @@ -1,7 +1,6 @@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" -#include "spawn-pipe.h" static inline void close_pair(int fd[2]) { @@ -9,13 +8,17 @@ static inline void close_pair(int fd[2]) close(fd[1]); } +static inline void dup_devnull(int to) +{ + int fd = open("/dev/null", O_RDWR); + dup2(fd, to); + close(fd); +} + int start_command(struct child_process *cmd) { int need_in, need_out, need_err; - int fdin[2] = { -1, -1 }; - int fdout[2] = { -1, -1 }; - int fderr[2] = { -1, -1 }; - char **env = environ; + int fdin[2], fdout[2], fderr[2]; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -50,53 +53,150 @@ int start_command(struct child_process *cmd) cmd->err = fderr[0]; } - { +#ifndef __MINGW32__ + cmd->pid = fork(); + if (!cmd->pid) { if (cmd->no_stdin) - fdin[0] = open("/dev/null", O_RDWR); + dup_devnull(0); else if (need_in) { - /* nothing */ + dup2(fdin[0], 0); + close_pair(fdin); } else if (cmd->in) { - fdin[0] = cmd->in; + dup2(cmd->in, 0); + close(cmd->in); } if (cmd->no_stdout) - fdout[1] = open("/dev/null", O_RDWR); + dup_devnull(1); else if (cmd->stdout_to_stderr) - fdout[1] = dup(2); + dup2(2, 1); else if (need_out) { - /* nothing */ + dup2(fdout[1], 1); + close_pair(fdout); } else if (cmd->out > 1) { - fdout[1] = cmd->out; + dup2(cmd->out, 1); + close(cmd->out); } if (cmd->no_stderr) - fderr[1] = open("/dev/null", O_RDWR); + dup_devnull(2); else if (need_err) { - /* nothing */ + dup2(fderr[1], 2); + close_pair(fderr); } - if (cmd->dir) - die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { - if (cmd->git_cmd) - die("modifying environment for git_cmd in start_command() not implemented"); - env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - die("setting environment in start_command() not implemented"); + putenv((char*)*cmd->env); else - env_unsetenv(env, *cmd->env); + unsetenv(*cmd->env); } } if (cmd->git_cmd) { - cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); + execv_git_cmd(cmd->argv); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); + execvp(cmd->argv[0], (char *const*) cmd->argv); + } + die("exec %s failed.", cmd->argv[0]); + } +#else + int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ + const char *sargv0 = cmd->argv[0]; + char **env = environ; + struct strbuf git_cmd; + + if (cmd->no_stdin) { + s0 = dup(0); + dup_devnull(0); + } else if (need_in) { + s0 = dup(0); + dup2(fdin[0], 0); + } else if (cmd->in) { + s0 = dup(0); + dup2(cmd->in, 0); + } + + if (cmd->no_stdout) { + s1 = dup(1); + dup_devnull(1); + } else if (cmd->stdout_to_stderr) { + s1 = dup(1); + dup2(2, 1); + } else if (need_out) { + s1 = dup(1); + dup2(fdout[1], 1); + } else if (cmd->out > 1) { + s1 = dup(1); + dup2(cmd->out, 1); + } + + if (cmd->no_stderr) { + s2 = dup(2); + dup_devnull(2); + } else if (need_err) { + s2 = dup(2); + dup2(fderr[1], 2); + } + + if (cmd->dir) + die("chdir in start_command() not implemented"); + if (cmd->env) { + env = copy_environ(); + for (; *cmd->env; cmd->env++) { + if (strchr(*cmd->env, '=')) + die("setting environment in start_command() not implemented"); + else + env_unsetenv(env, *cmd->env); } } + + if (cmd->git_cmd) { + strbuf_init(&git_cmd, 0); + strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]); + cmd->argv[0] = git_cmd.buf; + } + + char **path = mingw_get_path_split(); + const char *argv0 = cmd->argv[0]; + const char **qargv; + char *prog = mingw_path_lookup(argv0, path); + const char *interpr = parse_interpreter(prog); + int argc; + + for (argc = 0; cmd->argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + if (!interpr) { + quote_argv(qargv, cmd->argv); + cmd->pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); + } else { + qargv[0] = interpr; + cmd->argv[0] = prog; + quote_argv(&qargv[1], cmd->argv); + cmd->pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + } + + free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); + + mingw_free_path_split(path); + /* TODO: if (cmd->env) free env; */ + + if (cmd->git_cmd) + strbuf_release(&git_cmd); + + cmd->argv[0] = sargv0; + if (s0 >= 0) + dup2(s0, 0), close(s0); + if (s1 >= 0) + dup2(s1, 1), close(s1); + if (s2 >= 0) + dup2(s2, 2), close(s2); +#endif + if (cmd->pid < 0) { if (need_in) close_pair(fdin); @@ -107,6 +207,19 @@ int start_command(struct child_process *cmd) return -ERR_RUN_COMMAND_FORK; } + if (need_in) + close(fdin[0]); + else if (cmd->in) + close(cmd->in); + + if (need_out) + close(fdout[1]); + else if (cmd->out > 1) + close(cmd->out); + + if (need_err) + close(fderr[1]); + return 0; } From 855cdbbc3b3bb8975687ddfbe63cd10bf44e1410 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:30:15 +0100 Subject: [PATCH 308/781] Remove now unused spawnv_git_cmd(). --- exec_cmd.c | 28 ---------------------------- exec_cmd.h | 1 - 2 files changed, 29 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 6aa842bb4f..9d22e78eb0 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,7 +1,6 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" -#include "spawn-pipe.h" #define MAX_ARGS 32 extern char **environ; @@ -155,30 +154,3 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } - -int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) -{ - pid_t pid; - struct strbuf cmd; - const char *tmp; - - strbuf_init(&cmd, 0); - strbuf_addf(&cmd, "git-%s", argv[0]); - - /* argv[0] must be the git command, but the argv array - * belongs to the caller. Save argv[0] and - * restore it later. - */ - - tmp = argv[0]; - argv[0] = cmd.buf; - - trace_argv_printf(argv, -1, "trace: exec:"); - - pid = spawnvpe_pipe(cmd.buf, argv, environ, - pin, pout); - - argv[0] = tmp; - return pid; - -} diff --git a/exec_cmd.h b/exec_cmd.h index 9e8a28489e..a892355c82 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -6,7 +6,6 @@ extern const char* git_exec_path(void); extern void setup_path(const char *); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); -extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]); #endif /* GIT_EXEC_CMD_H */ From d51703c66552023b930724fcdd9e6324b0f42f5e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 18 Nov 2007 20:33:36 +0100 Subject: [PATCH 309/781] Remove now unused spawn-pipe.c with spawnvpe_pipe() function. --- Makefile | 2 - connect.c | 1 - spawn-pipe.c | 131 --------------------------------------------------- spawn-pipe.h | 2 - 4 files changed, 136 deletions(-) delete mode 100644 spawn-pipe.c delete mode 100644 spawn-pipe.h diff --git a/Makefile b/Makefile index e8058c3f19..7f5a2e4f4b 100644 --- a/Makefile +++ b/Makefile @@ -291,7 +291,6 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - spawn-pipe.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h @@ -305,7 +304,6 @@ LIB_OBJS = \ date.o diff-delta.o entry.o exec_cmd.o ident.o \ pretty.o interpolate.o hash.o \ lockfile.o \ - spawn-pipe.o \ patch-ids.o \ object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \ sideband.o reachable.o reflog-walk.o \ diff --git a/connect.c b/connect.c index e11cf32321..0f10c40652 100644 --- a/connect.c +++ b/connect.c @@ -5,7 +5,6 @@ #include "refs.h" #include "run-command.h" #include "remote.h" -#include "spawn-pipe.h" static char *server_capabilities; diff --git a/spawn-pipe.c b/spawn-pipe.c deleted file mode 100644 index 9cb0cf5b70..0000000000 --- a/spawn-pipe.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "git-compat-util.h" -#include "spawn-pipe.h" - -extern char **environ; - -/* cmd specifies the command to invoke. - * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. - * env specifies the environment. - * pin and pout specify pipes; the read end of pin is made the standard input - * of the spawned process, and the write end of pout is mad the standard output. - * The respective unused ends of the pipes are closed both in the parent - * process as well as in the child process. - * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to - * indicate that no processing shall occur. - */ -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, - int pin[], int pout[]) -{ -#ifdef __MINGW32__ - char **path = mingw_get_path_split(); - - pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); - - mingw_free_path_split(path); -#else - pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); -#endif - return pid; -} - -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, - char **path, - int pin[], int pout[]) -{ - const char *cmd_basename = strrchr(cmd, '/'); - const char *argv0 = argv[0]; - pid_t pid; - -#ifdef __MINGW32__ - int s0 = -1, s1 = -1, argc; - char *prog; - const char **qargv, *interpr; - - if (!cmd_basename) - cmd_basename = strrchr(cmd, '\\'); -#endif - - if (!cmd_basename) - cmd_basename = cmd; - else - cmd_basename++; - argv[0] = cmd_basename; - -#ifndef __MINGW32__ - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - if (pin) { - if (pin[0] >= 0) { - dup2(pin[0], 0); - close(pin[0]); - } - if (pin[1] >= 0) - close(pin[1]); - } - if (pout) { - if (pout[1] >= 0) { - dup2(pout[1], 1); - close(pout[1]); - } - if (pout[0] >= 0) - close(pout[0]); - } - environ = env; - execvp(cmd, argv); - die("exec failed"); - } - - if (pin && pin[0] >= 0) - close(pin[0]); - if (pout && pout[1] >= 1) - close(pout[1]); -#else - if (pin) { - if (pin[0] >= 0) { - s0 = dup(0); - dup2(pin[0], 0); - close(pin[0]); - } - } - if (pout) { - if (pout[1] >= 0) { - s1 = dup(1); - dup2(pout[1], 1); - close(pout[1]); - } - } - - prog = mingw_path_lookup(cmd, path); - interpr = parse_interpreter(prog); - - for (argc = 0; argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, env); - } else { - qargv[0] = interpr; - argv[0] = prog; - quote_argv(&qargv[1], argv); - pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); - } - - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - - if (s0 >= 0) { - dup2(s0, 0); - close(s0); - } - if (s1 >= 0) { - dup2(s1, 1); - close(s1); - } -#endif - - argv[0] = argv0; - - return pid; -} diff --git a/spawn-pipe.h b/spawn-pipe.h deleted file mode 100644 index 9bf387e411..0000000000 --- a/spawn-pipe.h +++ /dev/null @@ -1,2 +0,0 @@ -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); From 8ddaf895a80c1d42bd0e923cb0f1f041d00a27ea Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:27:40 +0100 Subject: [PATCH 310/781] compat/mingw.c: Add cast of handle to fix warning [js: whitespace removed] Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0456319ba6..b18231e903 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -235,7 +235,7 @@ int pipe(int filedes[2]) CloseHandle(h[0]); return -1; } - fd = _open_osfhandle(h[0], O_NOINHERIT); + fd = _open_osfhandle((int)h[0], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); @@ -245,7 +245,7 @@ int pipe(int filedes[2]) } close(filedes[0]); filedes[0] = fd; - fd = _open_osfhandle(h[1], O_NOINHERIT); + fd = _open_osfhandle((int)h[1], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); From f593be04806654aaff987f660e1998b0e19a9b8b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:43:30 +0100 Subject: [PATCH 311/781] test-chmtime.c: Cast HANDLE to fix warning Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- test-chmtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-chmtime.c b/test-chmtime.c index b6dc548a2a..8a1e6b8479 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -22,7 +22,7 @@ int git_utime (const char *file_name, const struct utimbuf *times) time_t_to_filetime(times->modtime, &mft); time_t_to_filetime(times->actime, &aft); - if (!SetFileTime(_get_osfhandle(fh), NULL, &aft, &mft)) { + if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { errno = EINVAL; rc = -1; } else From a8d8425ec6f2b75c59562b6e9a7508ab623a2cd4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 21:07:32 +0100 Subject: [PATCH 312/781] Fix prototypes for mingw_execve and mingw_execvp to match Posix This changes the prototypes to match http://www.opengroup.org/onlinepubs/7990989775/xsh/exec.html [js: updated message] Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Sixt --- compat/mingw.c | 19 ++++++++++--------- git-compat-util.h | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index b18231e903..ad44c86a98 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -352,7 +352,7 @@ static const char *quote_arg(const char *arg) return q; } -void quote_argv(const char **dst, const char **src) +void quote_argv(const char **dst, const char *const *src) { while (*src) *dst++ = quote_arg(*src++); @@ -394,7 +394,7 @@ const char *parse_interpreter(const char *cmd) return p+1; } -static int try_shell_exec(const char *cmd, const char **argv, const char **env) +static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) { const char **sh_argv; int n; @@ -412,14 +412,14 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) sh_argv = xmalloc((n+2)*sizeof(char*)); sh_argv[0] = interpr; sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], &argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, env); + quote_argv(&sh_argv[2], (const char *const *)&argv[1]); + n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); if (n == -1) return 1; /* indicate that we tried but failed */ exit(n); } -void mingw_execve(const char *cmd, const char **argv, const char **env) +void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { @@ -427,8 +427,9 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) int n; for (n = 0; argv[n];) n++; qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, argv); - int ret = spawnve(_P_WAIT, cmd, qargv, env); + quote_argv(qargv, (const char *const *)argv); + int ret = spawnve(_P_WAIT, cmd, qargv, + (const char *const *)env); if (ret != -1) exit(ret); } @@ -522,13 +523,13 @@ void mingw_free_path_split(char **path) free(path); } -void mingw_execvp(const char *cmd, const char **argv) +void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); char *prog = mingw_path_lookup(cmd, path); if (prog) { - mingw_execve(prog, argv, (const char **) environ); + mingw_execve(prog, argv, environ); free(prog); } else errno = ENOENT; diff --git a/git-compat-util.h b/git-compat-util.h index 768e7fc696..c88186d685 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -451,9 +451,9 @@ static inline int kill(pid_t pid, int sig) static inline unsigned int alarm(unsigned int seconds) { return 0; } -void mingw_execve(const char *cmd, const char **argv, const char **env); +void mingw_execve(const char *cmd, char *const *argv, char * const *env); #define execve mingw_execve -extern void mingw_execvp(const char *cmd, const char **argv); +extern void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp typedef int pid_t; static inline int waitpid(pid_t pid, unsigned *status, unsigned options) @@ -527,7 +527,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} extern int getpagesize(void); /* defined in MinGW's libgcc.a */ -extern void quote_argv(const char **dst, const char **src); +extern void quote_argv(const char **dst, const char *const *src); extern const char *parse_interpreter(const char *cmd); extern char *mingw_path_lookup(const char *cmd, char **path); extern char **mingw_get_path_split(void); From f801325ed5fd9d3f4732dbef18f4270c4ea89654 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 19 Nov 2007 12:34:22 +0100 Subject: [PATCH 313/781] Implement a rudimentary poll() emulation for Windows. This emulation of poll() is by far not general. It assumes that the fds that are to be waited for are connected to pipes. The pipes are polled in a loop until data becomes available in at least one of them. If only a single fd is waited for, the implementation actually does not wait at all, but assumes that a subsequent read() will block. In order to not burn CPU time, it is yielded to other processes before the next round in the poll loop using Sleep(0). Note that any sleep timeout greater than zero will reduce the efficiency by a magnitude. Signed-off-by: Johannes Sixt --- compat/mingw.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ad44c86a98..676aae573e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -259,7 +259,62 @@ int pipe(int filedes[2]) int poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - return -1; + int i, pending; + + if (timeout != -1) + return errno = EINVAL, error("poll timeout not supported"); + + /* When there is only one fd to wait for, then we pretend that + * input is available and let the actual wait happen when the + * caller invokes read(). + */ + if (nfds == 1) { + if (!(ufds[0].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + ufds[0].revents = POLLIN; + return 0; + } + +repeat: + pending = 0; + for (i = 0; i < nfds; i++) { + DWORD avail = 0; + HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd); + if (h == INVALID_HANDLE_VALUE) + return -1; /* errno was set */ + + if (!(ufds[i].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + + /* this emulation works only for pipes */ + if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) { + int err = GetLastError(); + if (err == ERROR_BROKEN_PIPE) { + ufds[i].revents = POLLHUP; + pending++; + } else { + errno = EINVAL; + return error("PeekNamedPipe failed," + " GetLastError: %u", err); + } + } else if (avail) { + ufds[i].revents = POLLIN; + pending++; + } else + ufds[i].revents = 0; + } + if (!pending) { + /* The only times that we spin here is when the process + * that is connected through the pipes is waiting for + * its own input data to become available. But since + * the process (pack-objects) is itself CPU intensive, + * it will happily pick up the time slice that we are + * relinguishing here. + */ + Sleep(0); + goto repeat; + } + return 0; } #include From 40c18e8ee6fcb5128719ee6e1b5aabee689da436 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 19 Nov 2007 12:39:57 +0100 Subject: [PATCH 314/781] upload-pack: Remove MinGW specific code. Now that a poll() implementation is available, upload-pack also offers side-band communication. --- upload-pack.c | 45 ++------------------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index 84569a3aad..75e2acb29e 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -174,7 +174,6 @@ static void create_pack_file(void) if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); -#ifndef __MINGW32__ /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. */ @@ -265,41 +264,6 @@ static void create_pack_file(void) goto fail; } } -#else - char *cp; - - /* We read from pack_objects.out to capture the pack data. */ - - while ((sz = xread(pack_objects.out, data+1, sizeof(data)-1)) > 0) { - cp = data+1; - /* Data ready; we keep the last byte to ourselves in case we - * detect broken rev-list, so that we can leave the stream - * corrupted. This is unfortunate -- unpack-objects would - * happily accept a valid pack data with trailing garbage, so - * appending garbage after we pass all the pack data is not - * good enough to signal breakage to downstream. - */ - if (0 <= buffered) { - *--cp = buffered; - sz++; - } - if (1 < sz) { - buffered = cp[sz-1] & 0xFF; - sz--; - } - else - buffered = -1; - sz = send_client_data(1, cp, sz); - if (sz < 0) - goto fail; - } - if (sz == 0) { - close(pack_objects.out); - pack_objects.out = -1; - } - else - goto fail; -#endif if (finish_command(&pack_objects)) { error("git-upload-pack: git-pack-objects died with error."); @@ -521,12 +485,10 @@ static void receive_needs(void) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) use_ofs_delta = 1; -#ifndef __MINGW32__ if (strstr(line+45, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (strstr(line+45, "side-band")) use_sideband = DEFAULT_PACKET_MAX; -#endif if (strstr(line+45, "no-progress")) no_progress = 1; @@ -596,11 +558,8 @@ static void receive_needs(void) static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack" -#ifndef __MINGW32__ - " side-band side-band-64k" -#endif - " ofs-delta shallow no-progress"; + static const char *capabilities = "multi_ack thin-pack side-band" + " side-band-64k ofs-delta shallow no-progress"; struct object *o = parse_object(sha1); if (!o) From ad0b9993f9e21199cca77c0f04770e4013090d26 Mon Sep 17 00:00:00 2001 From: Dmitry Kakurin Date: Sat, 17 Nov 2007 20:32:08 +0100 Subject: [PATCH 315/781] compat/regex.c: Fix warnings In general, we don't add unnecessary braces. But in this case gcc warns about them. So this commit adds a few braces. The commit suppresses warnings about unitialized variables by initializing them to NULL. The change of bcmp_translate()'s parameter declaration is needed to avoid warnings about "discards qualifiers from pointer target type". [sp: split original commit; more detailed commit message. ] Signed-off-by: Dmitry Kakurin Signed-off-by: Steffen Prohaska --- compat/regex.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compat/regex.c b/compat/regex.c index 2d57c70b9c..1d39e08d47 100644 --- a/compat/regex.c +++ b/compat/regex.c @@ -1597,10 +1597,12 @@ regex_compile (pattern, size, syntax, bufp) if (syntax & RE_NO_BK_PARENS) goto normal_backslash; if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_backslash; else return REG_ERPAREN; + } handle_close: if (fixup_alt_jump) @@ -1617,10 +1619,12 @@ regex_compile (pattern, size, syntax, bufp) /* See similar code for backslashed left paren above. */ if (COMPILE_STACK_EMPTY) + { if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) goto normal_char; else return REG_ERPAREN; + } /* Since we just checked for an empty stack above, this ``can't happen''. */ @@ -3191,14 +3195,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matching and the regnum-th regend points to right after where we stopped matching the regnum-th subexpression. (The zeroth register keeps track of what the whole pattern matches.) */ - const char **regstart, **regend; + const char **regstart = NULL, **regend = NULL; /* If a group that's operated upon by a repetition operator fails to match anything, then the register for its start will need to be restored because it will have been set to wherever in the string we are when we last see its open-group operator. Similarly for a register's end. */ - const char **old_regstart, **old_regend; + const char **old_regstart = NULL, **old_regend = NULL; /* The is_active field of reg_info helps us keep track of which (possibly nested) subexpressions we are currently in. The matched_something @@ -3206,14 +3210,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) matched any of the pattern so far this time through the reg_num-th subexpression. These two fields get reset each time through any loop their register is in. */ - register_info_type *reg_info; + register_info_type *reg_info = NULL; /* The following record the register info as found in the above variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; - const char **best_regstart, **best_regend; + const char **best_regstart = NULL, **best_regend = NULL; /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything @@ -3226,8 +3230,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) const char *match_end = NULL; /* Used when we pop values we don't care about. */ - const char **reg_dummy; - register_info_type *reg_info_dummy; + const char **reg_dummy = NULL; + register_info_type *reg_info_dummy = NULL; #ifdef DEBUG /* Counts the total number of registers pushed. */ @@ -4561,10 +4565,12 @@ common_op_match_null_string_p (p, end, reg_info) bytes; nonzero otherwise. */ static int -bcmp_translate (s1, s2, len, translate) - unsigned char *s1, *s2; - register int len; - char *translate; +bcmp_translate( + unsigned char *s1, + unsigned char *s2, + int len, + char *translate +) { register unsigned char *p1 = s1, *p2 = s2; while (len) From 5a09d6a3ac8f4fa39e059ad61ece1aabd5a861e1 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:48:14 +0100 Subject: [PATCH 316/781] compat/pread.c: Add foward decl to fix warning read_in_full()'s is used in compat/pread.c. read_in_full() is declared in cache.h. But we can't include cache.h because too many macros are defined there. Using read_in_full() without including cache.h is dangerous because we wouldn't recognize if its prototyp changed. gcc issues a warning about that. This commit adds a forward decl to git-compat-util.h. git-compat-util.h is included by compat/pread.c _and_ cache.h. Hence, changes in cache.h would be detected. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index c88186d685..b76f94fc05 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -153,6 +153,10 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif +/* Forward decl that will remind us if its twin in cache.h changes. + This function in used in compat/pread.c. But we can't include + cache.h there. */ +extern int read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv From c2849fc4b1a4618f2d81ef2597d7e40d7b2e048c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:16:53 +0100 Subject: [PATCH 317/781] Fix ntohl() related warnings about printf formatting On Windows, ntohl() returns unsinged long. On Unix it returns uint32_t. This makes choosing a suitable printf format string hard. This commit introduces a mingw specific helper function git_ntohl() that casts to unsigned int before returning. This makes gcc's printf format check happy. It should be safe because we expect ntohl to use 32-bit numbers. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index b76f94fc05..74412331d8 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -594,6 +594,10 @@ static inline int mingw_fcntl(int fd, int cmd, long arg) { return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } #define fcntl mingw_fcntl +static inline unsigned int git_ntohl(unsigned int x) +{ return (unsigned int)ntohl(x); } +#define ntohl git_ntohl + #endif /* __MINGW32__ */ #endif From a6ed49cf52589d26235dc2461ebaf8b38446b061 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Nov 2007 09:21:12 +0100 Subject: [PATCH 318/781] Fix error messages in timer implementation. There were some references to the progress indicator, where this implementation originally appeared. Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 676aae573e..aa730e9bc1 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -760,10 +760,10 @@ static int start_timer_thread(void) timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); if (!timer_thread ) return errno = ENOMEM, - error("cannot create progress indicator"); + error("cannot start timer thread"); } else return errno = ENOMEM, - error("cannot allocate resources for progress indicator"); + error("cannot allocate resources timer"); return 0; } From 726fb5ed5ded96f6a60a7adf41e50b6c00b4f246 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 17 Nov 2007 22:42:12 +0100 Subject: [PATCH 319/781] fetch-pack: Enable sideband communication. --- builtin-fetch-pack.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 2f37b5cd24..807fa93b53 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -563,7 +563,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } -#ifndef __MINGW32__ if (server_supports("side-band-64k")) { if (args.verbose) fprintf(stderr, "Server supports side-band-64k\n"); @@ -574,7 +573,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } -#endif if (!ref) { packet_flush(fd[1]); die("no matching remote head"); From 66417d164e18193aef3bd935ab6e7755f5161f73 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:00:39 +0100 Subject: [PATCH 320/781] Add ifdef __MINGW32__ to avoid warning about unused "progress" Signed-off-by: Steffen Prohaska --- upload-pack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/upload-pack.c b/upload-pack.c index 97ffa879f3..115f7a1e56 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -143,6 +143,9 @@ static void create_pack_file(void) struct child_process pack_objects; int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); char data[8193]; +#ifndef __MINGW32__ + char progress[128]; +#endif char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; int buffered = -1; From af18e7d9d3abad0e42477a3c15c0e3f0bdc9ae15 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 21:07:32 +0100 Subject: [PATCH 321/781] Fix prototypes for mingw_execve and mingw_execvp to match Posix This changes the prototypes to match http://www.opengroup.org/onlinepubs/7990989775/xsh/exec.html Note, spawnvpe uses a different type for argv and envp than execve. So at some point we need to cast. This commit shifts the cast into the compat functions. From the outside, execve and execvp match Posix. Signed-off-by: Steffen Prohaska --- compat/mingw.c | 19 ++++++++++--------- git-compat-util.h | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index b905673a40..b841f6d0ca 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -352,7 +352,7 @@ static const char *quote_arg(const char *arg) return q; } -void quote_argv(const char **dst, const char **src) +void quote_argv(const char **dst, const char *const *src) { while (*src) *dst++ = quote_arg(*src++); @@ -394,7 +394,7 @@ const char *parse_interpreter(const char *cmd) return p+1; } -static int try_shell_exec(const char *cmd, const char **argv, const char **env) +static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) { const char **sh_argv; int n; @@ -412,14 +412,14 @@ static int try_shell_exec(const char *cmd, const char **argv, const char **env) sh_argv = xmalloc((n+2)*sizeof(char*)); sh_argv[0] = interpr; sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], &argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, env); + quote_argv(&sh_argv[2], (const char *const *)&argv[1]); + n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); if (n == -1) return 1; /* indicate that we tried but failed */ exit(n); } -void mingw_execve(const char *cmd, const char **argv, const char **env) +void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { @@ -427,8 +427,9 @@ void mingw_execve(const char *cmd, const char **argv, const char **env) int n; for (n = 0; argv[n];) n++; qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, argv); - int ret = spawnve(_P_WAIT, cmd, qargv, env); + quote_argv(qargv, (const char *const *)argv); + int ret = spawnve(_P_WAIT, cmd, qargv, + (const char *const *)env); if (ret != -1) exit(ret); } @@ -522,13 +523,13 @@ void mingw_free_path_split(char **path) free(path); } -void mingw_execvp(const char *cmd, const char **argv) +void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); char *prog = mingw_path_lookup(cmd, path); if (prog) { - mingw_execve(prog, argv, (const char **) environ); + mingw_execve(prog, argv, environ); free(prog); } else errno = ENOENT; diff --git a/git-compat-util.h b/git-compat-util.h index 921a6c08b4..eb4d96944e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -454,9 +454,9 @@ static inline int kill(pid_t pid, int sig) static inline unsigned int alarm(unsigned int seconds) { return 0; } -void mingw_execve(const char *cmd, const char **argv, const char **env); +void mingw_execve(const char *cmd, char *const *argv, char * const *env); #define execve mingw_execve -extern void mingw_execvp(const char *cmd, const char **argv); +extern void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp typedef int pid_t; static inline int waitpid(pid_t pid, unsigned *status, unsigned options) @@ -526,7 +526,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} extern int getpagesize(void); /* defined in MinGW's libgcc.a */ -extern void quote_argv(const char **dst, const char **src); +extern void quote_argv(const char **dst, const char *const *src); extern const char *parse_interpreter(const char *cmd); extern char *mingw_path_lookup(const char *cmd, char **path); extern char **mingw_get_path_split(void); From ad941f23363d2f37cef8dd6a59b61be2b740997c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 22:43:26 +0100 Subject: [PATCH 322/781] exec_cmd.c: Add cast that is needed for Posix execvp Signed-off-by: Steffen Prohaska --- exec_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec_cmd.c b/exec_cmd.c index a2d82d3311..de4c174b68 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -121,7 +121,7 @@ int execv_git_cmd(const char **argv) trace_argv_printf(argv, -1, "trace: exec:"); /* execvp() can only ever return if it fails */ - execvp(cmd.buf, argv); + execvp(cmd.buf, (char **)argv); trace_printf("trace: exec failed: %s\n", strerror(errno)); From 565861de3b6357339fdcd087fa52fc4c14b6de24 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 23:01:56 +0100 Subject: [PATCH 323/781] spawn-pipe.c: Remove unnecessary cast Signed-off-by: Steffen Prohaska --- spawn-pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spawn-pipe.c b/spawn-pipe.c index 04146d5631..e685eff643 100644 --- a/spawn-pipe.c +++ b/spawn-pipe.c @@ -103,7 +103,7 @@ int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, qargv = xmalloc((argc+2)*sizeof(char*)); if (!interpr) { quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, (const char**) env); + pid = spawnve(_P_NOWAIT, prog, qargv, env); } else { qargv[0] = interpr; argv[0] = prog; From d3dcd107758907e38751fb50631e9acf315a6bad Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Nov 2007 12:23:52 +0100 Subject: [PATCH 324/781] git.c: Take '--bare' handling from mingw master Merge commit 53009e47c2b55d6c23925bb77116545f2308cef9 introduced an if() statement that is not present in mingw's master. This commit changes the code to match mingw's master. Signed-off-by: Steffen Prohaska --- git.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/git.c b/git.c index 615093453b..e2c79a1efc 100644 --- a/git.c +++ b/git.c @@ -72,11 +72,9 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; is_bare_repository_cfg = 1; - if (!getenv(GIT_DIR_ENVIRONMENT)) { - set_git_dir(getcwd(git_dir, sizeof(git_dir))); - if (envchanged) - *envchanged = 1; - } + set_git_dir(getcwd(git_dir, sizeof(git_dir))); + if (envchanged) + *envchanged = 1; } else { fprintf(stderr, "Unknown option: %s\n", cmd); usage(git_usage_string); From 31023be9997d657dc653fe3358be50d1e7268a31 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 20:48:14 +0100 Subject: [PATCH 325/781] compat/pread.c: Add foward decl to fix warning read_in_full()'s is used in compat/pread.c. read_in_full() is declared in cache.h. But we can't include cache.h because too many macros are defined there. Using read_in_full() without including cache.h is dangerous because we wouldn't recognize if its prototyp changed. gcc issues a warning about that. This commit adds a forward decl to git-compat-util.h. git-compat-util.h is included by compat/pread.c _and_ cache.h. Hence, changes in cache.h would be detected. Signed-off-by: Steffen Prohaska --- compat/pread.c | 2 -- git-compat-util.h | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compat/pread.c b/compat/pread.c index ce29997724..978cac4ec9 100644 --- a/compat/pread.c +++ b/compat/pread.c @@ -1,7 +1,5 @@ #include "../git-compat-util.h" -int read_in_full(int fd, void *buf, size_t count); - ssize_t git_pread(int fd, void *buf, size_t count, off_t offset) { off_t current_offset; diff --git a/git-compat-util.h b/git-compat-util.h index eb4d96944e..f4e0d08357 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -153,6 +153,10 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif +/* Forward decl that will remind us if its twin in cache.h changes. + This function in used in compat/pread.c. But we can't include + cache.h there. */ +extern int read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv From 43664aa169b6efeb80245772f7ad9ff1c6e5edb0 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:16:53 +0100 Subject: [PATCH 326/781] Revert ntohl()/printf format to Junio's git This commits reverts printf format strings to the original version from Juion's git. This is a preparation for the mingw specific fix that follows in the next commit. Signed-off-by: Steffen Prohaska --- builtin-fetch-pack.c | 2 +- builtin-ls-files.c | 2 +- builtin-unpack-objects.c | 2 +- index-pack.c | 2 +- merge-index.c | 2 +- read-cache.c | 2 +- receive-pack.c | 2 +- sha1_file.c | 4 ++-- show-index.c | 2 +- unpack-trees.c | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 3510bfd089..a2ca746dd0 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -509,7 +509,7 @@ static int get_pack(int xd[2], char **pack_lockfile) if (read_pack_header(fd[0], &header)) die("protocol error: bad pack header"); - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", ntohl(header.hdr_version), ntohl(header.hdr_entries)); if (ntohl(header.hdr_entries) < unpack_limit) do_keep = 0; diff --git a/builtin-ls-files.c b/builtin-ls-files.c index dde79545e2..e0b856f432 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -208,7 +208,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) if (!show_stage) { fputs(tag, stdout); } else { - printf("%s%06lo %s %d\t", + printf("%s%06o %s %d\t", tag, ntohl(ce->ce_mode), abbrev ? find_unique_abbrev(ce->sha1,abbrev) diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 948e4bec51..1e51865c52 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -318,7 +318,7 @@ static void unpack_all(void) if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE) die("bad pack file"); if (!pack_version_ok(hdr->hdr_version)) - die("unknown pack file version %lu", ntohl(hdr->hdr_version)); + die("unknown pack file version %d", ntohl(hdr->hdr_version)); use(sizeof(struct pack_header)); if (!quiet) diff --git a/index-pack.c b/index-pack.c index 6268da94b8..9fd6982a97 100644 --- a/index-pack.c +++ b/index-pack.c @@ -143,7 +143,7 @@ static void parse_pack_header(void) if (hdr->hdr_signature != htonl(PACK_SIGNATURE)) die("pack signature mismatch"); if (!pack_version_ok(hdr->hdr_version)) - die("pack version %lu unsupported", ntohl(hdr->hdr_version)); + die("pack version %d unsupported", ntohl(hdr->hdr_version)); nr_objects = ntohl(hdr->hdr_entries); use(sizeof(struct pack_header)); diff --git a/merge-index.c b/merge-index.c index 1cf4cb5b3f..fa719cb0b1 100644 --- a/merge-index.c +++ b/merge-index.c @@ -48,7 +48,7 @@ static int merge_entry(int pos, const char *path) break; found++; strcpy(hexbuf[stage], sha1_to_hex(ce->sha1)); - sprintf(ownbuf[stage], "%lo", ntohl(ce->ce_mode)); + sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode)); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); diff --git a/read-cache.c b/read-cache.c index 128835b684..7748c3ece7 100644 --- a/read-cache.c +++ b/read-cache.c @@ -152,7 +152,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) case 0: /* Special case: unmerged file in index */ return MODE_CHANGED | DATA_CHANGED | TYPE_CHANGED; default: - die("internal error: ce_mode is %lo", ntohl(ce->ce_mode)); + die("internal error: ce_mode is %o", ntohl(ce->ce_mode)); } if (ce->ce_mtime.sec != htonl(st->st_mtime)) changed |= MTIME_CHANGED; diff --git a/receive-pack.c b/receive-pack.c index a66a6e45d2..38e35c06b9 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -352,7 +352,7 @@ static const char *unpack(void) hdr_err = parse_pack_header(&hdr); if (hdr_err) return hdr_err; - snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%lu,%lu", + snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { diff --git a/sha1_file.c b/sha1_file.c index 6b0e4c1d02..bd0e7cd21c 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -670,13 +670,13 @@ static int open_packed_git_1(struct packed_git *p) if (hdr.hdr_signature != htonl(PACK_SIGNATURE)) return error("file %s is not a GIT packfile", p->pack_name); if (!pack_version_ok(hdr.hdr_version)) - return error("packfile %s is version %lu and not supported" + return error("packfile %s is version %u and not supported" " (try upgrading GIT to a newer version)", p->pack_name, ntohl(hdr.hdr_version)); /* Verify the pack matches its index. */ if (p->num_objects != ntohl(hdr.hdr_entries)) - return error("packfile %s claims to have %lu objects" + return error("packfile %s claims to have %u objects" " while index indicates %u objects", p->pack_name, ntohl(hdr.hdr_entries), p->num_objects); diff --git a/show-index.c b/show-index.c index 9749e2da48..7253991fff 100644 --- a/show-index.c +++ b/show-index.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) ntohl(off64[1]); off64_nr++; } - printf("%" PRIuMAX " %s (%08lx)\n", (uintmax_t) offset, + printf("%" PRIuMAX " %s (%08x)\n", (uintmax_t) offset, sha1_to_hex(entries[i].sha1), ntohl(entries[i].crc)); } diff --git a/unpack-trees.c b/unpack-trees.c index 18f586cefc..aea16adde8 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -638,7 +638,7 @@ static void show_stage_entry(FILE *o, if (!ce) fprintf(o, "%s (missing)\n", label); else - fprintf(o, "%s%06lo %s %d\t%s\n", + fprintf(o, "%s%06o %s %d\t%s\n", label, ntohl(ce->ce_mode), sha1_to_hex(ce->sha1), From 329bdf025be694c6944c63550af1cd30b84612ab Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:16:53 +0100 Subject: [PATCH 327/781] Fix ntohl() related warnings about printf formatting On Windows, ntohl() returns unsinged long. On Unix it returns uint32_t. This makes choosing a suitable printf format string hard. This commit introduces a mingw specific helper function git_ntohl() that casts to unsigned int before returning. This makes gcc's printf format check happy. It should be safe because we expect ntohl to use 32-bit numbers. Signed-off-by: Steffen Prohaska --- git-compat-util.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git-compat-util.h b/git-compat-util.h index f4e0d08357..42564918de 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -593,6 +593,10 @@ static inline int mingw_fcntl(int fd, int cmd, long arg) { return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } #define fcntl mingw_fcntl +static inline unsigned int git_ntohl(unsigned int x) +{ return (unsigned int)ntohl(x); } +#define ntohl git_ntohl + extern __attribute__((noreturn)) int git_exit(int code); #define exit git_exit From 60db5000ab3307def85fd8e4618e661a565c1750 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Nov 2007 22:47:00 +0100 Subject: [PATCH 328/781] Implement wrappers for gethostbyname(), socket(), and connect(). gethostbyname() is the first function that calls into the Winsock library, and it is wrapped only to initialize the library. socket() is wrapped for two reasons: - Windows's socket() creates things that are like low-level file handles, and they must be converted into file descriptors first. - And these handles cannot be used with plain ReadFile()/WriteFile() because they are opened for "overlapped IO". We have to use WSASocket() to create non-overlapped IO sockets. connect() must be wrapped because Windows's connect() expects the low-level sockets, not file descriptors, and we must first unwrap the file descriptor before we can pass it on to Windows's connect(). Signed-off-by: Johannes Sixt --- compat/mingw.c | 29 ++++++++++++++++++++++++++++- git-compat-util.h | 6 ++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index aa730e9bc1..f2d18a7410 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -631,8 +631,22 @@ void env_unsetenv(char **env, const char *name) env[dst] = NULL; } +/* this is the first function to call into WS_32; initialize it */ +#undef gethostbyname +struct hostent *mingw_gethostbyname(const char *host) +{ + WSADATA wsa; + + if (WSAStartup(MAKEWORD(2,2), &wsa)) + die("unable to initialize winsock subsystem, error %d", + WSAGetLastError()); + atexit((void(*)(void)) WSACleanup); + return gethostbyname(host); +} + int mingw_socket(int domain, int type, int protocol) { + int sockfd; SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); if (s == INVALID_SOCKET) { /* @@ -647,7 +661,20 @@ int mingw_socket(int domain, int type, int protocol) errno = WSAGetLastError(); return -1; } - return s; + /* convert into a file descriptor */ + if ((sockfd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) { + closesocket(s); + return error("unable to make a socket file descriptor: %s", + strerror(errno)); + } + return sockfd; +} + +#undef connect +int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) +{ + SOCKET s = (SOCKET)_get_osfhandle(sockfd); + return connect(s, sa, sz); } #undef rename diff --git a/git-compat-util.h b/git-compat-util.h index 74412331d8..1d147af906 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -520,9 +520,15 @@ struct tm *localtime_r(const time_t *timep, struct tm *result); char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd +struct hostent *mingw_gethostbyname(const char *host); +#define gethostbyname mingw_gethostbyname + int mingw_socket(int domain, int type, int protocol); #define socket mingw_socket +int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); +#define connect mingw_connect + int mingw_rename(const char*, const char*); #define rename mingw_rename From d0d5661addd02d3aca9e543457f962eacae704a2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 21 Nov 2007 22:48:07 +0100 Subject: [PATCH 329/781] Revert Windows specific code related to Winsock. These things are now hidden behind a compatibility layer. --- connect.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/connect.c b/connect.c index 0f10c40652..82fb62b080 100644 --- a/connect.c +++ b/connect.c @@ -345,23 +345,7 @@ static int git_tcp_connect_sock(char *host, int flags) static void git_tcp_connect(int fd[2], char *host, int flags) { -#ifndef __MINGW32__ int sockfd = git_tcp_connect_sock(host, flags); -#else - int sockfd; - WSADATA wsa; - - if (WSAStartup(MAKEWORD(2,2), &wsa)) - die("unable to initialize winsock subsystem, error %d", - WSAGetLastError()); - atexit((void(*)(void)) WSACleanup); - - sockfd = git_tcp_connect_sock(host, flags); - /* convert into a file descriptor */ - if ((sockfd = _open_osfhandle(sockfd, O_RDWR|O_BINARY)) < 0) - die("unable to make a socket file descriptor: %s", - strerror(errno)); -#endif fd[0] = sockfd; fd[1] = dup(sockfd); From 9c906c8e6c49b0bfa66580a35bcf013ee122970c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Nov 2007 22:24:56 +0100 Subject: [PATCH 330/781] Be more careful in splitting the program name from the path. A git program can be invoked using with such a full path name: C:\Src\mingw-git\t\trash/..\..\git-fetch-pack.exe i.e. it can contain both types of path separators. We must pick the one that comes last. Signed-off-by: Johannes Sixt --- git.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git.c b/git.c index e5fdd04057..04ef05fcf5 100644 --- a/git.c +++ b/git.c @@ -399,8 +399,9 @@ int main(int argc, const char **argv) * if we don't have anything better. */ #ifdef __MINGW32__ - if (!slash) - slash = strrchr(cmd, '\\'); + char *bslash = strrchr(cmd, '\\'); + if (!slash || (bslash && bslash > slash)) + slash = bslash; #endif if (slash) { *slash++ = 0; From 64529de34e408212bcb5e0b44573ddc2081bf84c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 24 Nov 2007 11:53:06 +0100 Subject: [PATCH 331/781] Enable some disabled tests, remove workarounds msysgit learnt to handle more tests. This commit enables some tests that were disabled before and reverts some workarounds that are no longer needed. Signed-off-by: Steffen Prohaska --- t/t3200-branch.sh | 1 - t/t3404-rebase-interactive.sh | 8 ++++---- t/t3900-i18n-commit.sh | 4 ---- t/t4121-apply-diffs.sh | 2 -- t/t5100-mailinfo.sh | 4 ---- t/t5302-pack-index.sh | 2 -- t/t6023-merge-file.sh | 3 --- t/t6200-fmt-merge-msg.sh | 1 - t/t7003-filter-branch.sh | 3 --- t/t7004-tag.sh | 4 ++-- t/t9300-fast-import.sh | 4 ---- 11 files changed, 6 insertions(+), 30 deletions(-) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 029f19d6fa..a891fa47d3 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -17,7 +17,6 @@ test_expect_success \ git-commit -m "Initial commit." && HEAD=$(git rev-parse --verify HEAD)' -true || test_expect_failure \ 'git branch --help should not have created a bogus branch' \ 'git branch --help /dev/null 2>/dev/null || : diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index c031d31698..f1039d1a21 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -164,7 +164,7 @@ test_expect_success 'retain authorship' ' test_tick && GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && git tag twerp && - git rebase -i --onto master HEAD~1 && + git rebase -i --onto master HEAD^ && git show HEAD | grep "^Author: Twerp Snog" ' @@ -208,7 +208,7 @@ test_expect_success 'preserve merges with -p' ' test_expect_success '--continue tries to commit' ' test_tick && - ! git rebase -i --onto new-branch1 HEAD~1 && + ! git rebase -i --onto new-branch1 HEAD^ && echo resolved > file1 && git add file1 && FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue && @@ -217,9 +217,9 @@ test_expect_success '--continue tries to commit' ' ' test_expect_success 'verbose flag is heeded, even after --continue' ' - git reset --hard $(git rev-parse HEAD@{1}) && + git reset --hard HEAD@{1} && test_tick && - ! git rebase -v -i --onto new-branch1 HEAD~1 && + ! git rebase -v -i --onto new-branch1 HEAD^ && echo resolved > file1 && git add file1 && git rebase --continue > output && diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 12812f924a..94b1c24b0a 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -7,10 +7,6 @@ test_description='commit and log output encodings' . ./test-lib.sh -say "iconv not supported, skipping tests." -test_done -exit 0 - compare_with () { git show -s $1 | sed -e '1,/^$/d' -e 's/^ //' >current && git diff current "$2" diff --git a/t/t4121-apply-diffs.sh b/t/t4121-apply-diffs.sh index d93b61d8c4..aff551a1d7 100755 --- a/t/t4121-apply-diffs.sh +++ b/t/t4121-apply-diffs.sh @@ -3,8 +3,6 @@ test_description='git apply for contextually independent diffs' . ./test-lib.sh -test_done - echo '1 2 3 diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 0dcab1fbfe..9b1a74542a 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -7,10 +7,6 @@ test_description='git mailinfo and git mailsplit test' . ./test-lib.sh -say "git-mailinfo does not work yet; skipping tests." -test_done -exit 0 - test_expect_success 'split sample box' \ 'git mailsplit -o. ../t5100/sample.mbox >last && last=`cat last` && diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 8f62429306..2a2878b572 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -59,7 +59,6 @@ test_expect_success \ 'cmp "test-1-${pack1}.idx" "1.idx" && cmp "test-2-${pack2}.idx" "2.idx"' -false && { test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 merge.err && grep "Cannot merge binary files" merge.err diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 878f51a8d9..526d7d1c44 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -9,7 +9,6 @@ test_description='fmt-merge-msg test' datestamp=1151939923 setdate () { - sleep 1 GIT_COMMITTER_DATE="$datestamp +0200" GIT_AUTHOR_DATE="$datestamp +0200" datestamp=`expr "$datestamp" + 1` diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index ed467c7009..2089351f7d 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -3,9 +3,6 @@ test_description='git-filter-branch' . ./test-lib.sh -say "filter-branch has not been taken care of - skipping tests" -test_done - make_commit () { lower=$(echo $1 | tr A-Z a-z) echo $lower > $lower diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 42d4e42dec..b9ac9e3eb3 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -116,9 +116,9 @@ mytag EOF test_expect_success \ 'trying to delete tags without params should succeed and do nothing' ' - git tag -l | cat > actual && git diff expect actual && + git tag -l > actual && git diff expect actual && git-tag -d && - git tag -l | cat > actual && git diff expect actual + git tag -l > actual && git diff expect actual ' test_expect_success \ diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index d92bf36f9c..0595041af5 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -7,10 +7,6 @@ test_description='test git-fast-import utility' . ./test-lib.sh . ../diff-lib.sh ;# test-lib chdir's into trash -say "git-fast-import has not been taken care of, skipping test." -test_done -exit 0 - file2_data='file2 second line of EOF' From 68c35c48f0db379e8138ba21b294ad04c3ca8b3b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 24 Nov 2007 20:04:30 +0100 Subject: [PATCH 332/781] Disable test of output of failing git-upload-pack More work is needed in mingw before the output of git-upload-pack is identical to the output on Unix. This commit disables verification of the output. Signed-off-by: Steffen Prohaska --- t/t5530-upload-pack-error.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index cc8949e3ef..014064a3bd 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -55,6 +55,7 @@ test_expect_success 'upload-pack fails due to error in rev-list' ' ! echo "0032want $(git rev-parse HEAD) 00000009done 0000" | git-upload-pack . > /dev/null 2> output.err && + true || grep "waitpid (async) failed" output.err ' From ec848b1965f29eda62f389bfcd653540fe58ca12 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 24 Nov 2007 22:53:20 +0100 Subject: [PATCH 333/781] Shuffle path lookup functions. We want to make them static later, and we need them in the proper order for this. There is otherwise no code change. Signed-off-by: Johannes Sixt --- compat/mingw.c | 158 ++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index f2d18a7410..850ee2ad5c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -449,85 +449,6 @@ const char *parse_interpreter(const char *cmd) return p+1; } -static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) -{ - const char **sh_argv; - int n; - const char *interpr = parse_interpreter(cmd); - if (!interpr) - return 0; - - /* - * expand - * git-foo args... - * into - * sh git-foo args... - */ - for (n = 0; argv[n];) n++; - sh_argv = xmalloc((n+2)*sizeof(char*)); - sh_argv[0] = interpr; - sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], (const char *const *)&argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); - if (n == -1) - return 1; /* indicate that we tried but failed */ - exit(n); -} - -void mingw_execve(const char *cmd, char *const *argv, char *const *env) -{ - /* check if git_command is a shell script */ - if (!try_shell_exec(cmd, argv, env)) { - const char **qargv; - int n; - for (n = 0; argv[n];) n++; - qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, (const char *const *)argv); - int ret = spawnve(_P_WAIT, cmd, qargv, - (const char *const *)env); - if (ret != -1) - exit(ret); - } -} - -static char *lookup_prog(const char *dir, const char *cmd, int tryexe) -{ - char path[MAX_PATH]; - snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); - - if (tryexe && access(path, 0) == 0) - return xstrdup(path); - path[strlen(path)-4] = '\0'; - if (access(path, 0) == 0) - return xstrdup(path); - return NULL; -} - -/* - * Determines the absolute path of cmd using the the split path in path. - * If cmd contains a slash or backslash, no lookup is performed. - */ -char *mingw_path_lookup(const char *cmd, char **path) -{ - char **p = path; - char *prog = NULL; - int len = strlen(cmd); - int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); - - if (strchr(cmd, '/') || strchr(cmd, '\\')) - prog = xstrdup(cmd); - - while (!prog && *p) { - prog = lookup_prog(*p++, cmd, tryexe); - } - if (!prog) { - prog = lookup_prog(".", cmd, tryexe); - if (!prog) - prog = xstrdup(cmd); - } - return prog; -} - /* * Splits the PATH into parts. */ @@ -578,6 +499,85 @@ void mingw_free_path_split(char **path) free(path); } +static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +{ + char path[MAX_PATH]; + snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); + + if (tryexe && access(path, 0) == 0) + return xstrdup(path); + path[strlen(path)-4] = '\0'; + if (access(path, 0) == 0) + return xstrdup(path); + return NULL; +} + +/* + * Determines the absolute path of cmd using the the split path in path. + * If cmd contains a slash or backslash, no lookup is performed. + */ +char *mingw_path_lookup(const char *cmd, char **path) +{ + char **p = path; + char *prog = NULL; + int len = strlen(cmd); + int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + + if (strchr(cmd, '/') || strchr(cmd, '\\')) + prog = xstrdup(cmd); + + while (!prog && *p) { + prog = lookup_prog(*p++, cmd, tryexe); + } + if (!prog) { + prog = lookup_prog(".", cmd, tryexe); + if (!prog) + prog = xstrdup(cmd); + } + return prog; +} + +static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) +{ + const char **sh_argv; + int n; + const char *interpr = parse_interpreter(cmd); + if (!interpr) + return 0; + + /* + * expand + * git-foo args... + * into + * sh git-foo args... + */ + for (n = 0; argv[n];) n++; + sh_argv = xmalloc((n+2)*sizeof(char*)); + sh_argv[0] = interpr; + sh_argv[1] = quote_arg(cmd); + quote_argv(&sh_argv[2], (const char *const *)&argv[1]); + n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); + if (n == -1) + return 1; /* indicate that we tried but failed */ + exit(n); +} + +void mingw_execve(const char *cmd, char *const *argv, char *const *env) +{ + /* check if git_command is a shell script */ + if (!try_shell_exec(cmd, argv, env)) { + const char **qargv; + int n; + for (n = 0; argv[n];) n++; + qargv = xmalloc((n+1)*sizeof(char*)); + quote_argv(qargv, (const char *const *)argv); + int ret = spawnve(_P_WAIT, cmd, qargv, + (const char *const *)env); + if (ret != -1) + exit(ret); + } +} + void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); From 424e2045aa0b07071780fa0a97c75962b779256e Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 25 Nov 2007 17:48:17 +0100 Subject: [PATCH 334/781] help (mingw): Avoid current working directory when displaying html help We should specify a working directory to ShellExecute for the following reason. ShellExecute uses the current working directory if not told otherwise. html.c did not override this default. Therefore the current working directory was in use as long as the browser displaying the HTML help was open. As long as a directory is in use, it can't be deleted. This commit changes help.c to avoid this problem. The HTML browser is launched in the root directory "\\". Signed-off-by: Steffen Prohaska --- help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help.c b/help.c index f89164a760..a9ec6a77e7 100644 --- a/help.c +++ b/help.c @@ -264,7 +264,7 @@ static void show_man_page(const char *git_cmd) } } printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, NULL, 0); + ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } #else const char *page; From a020210cc8edd757b6e0f6d2ac1ba767f9d662ed Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 24 Nov 2007 21:32:48 +0100 Subject: [PATCH 335/781] Move MinGW specific path lookup into compat/mingw.c. By doing so the only external user of the path handling and functions is removed, and these functions can be made static. Signed-off-by: Johannes Sixt --- compat/mingw.c | 41 +++++++++++++++++++++++++++++++++++------ git-compat-util.h | 11 ++--------- run-command.c | 23 +---------------------- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 850ee2ad5c..6d2e518256 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -407,14 +407,14 @@ static const char *quote_arg(const char *arg) return q; } -void quote_argv(const char **dst, const char *const *src) +static void quote_argv(const char **dst, const char *const *src) { while (*src) *dst++ = quote_arg(*src++); *dst = NULL; } -const char *parse_interpreter(const char *cmd) +static const char *parse_interpreter(const char *cmd) { static char buf[100]; char *p, *opt; @@ -452,7 +452,7 @@ const char *parse_interpreter(const char *cmd) /* * Splits the PATH into parts. */ -char **mingw_get_path_split(void) +static char **mingw_get_path_split(void) { char *p, **path, *envpath = getenv("PATH"); int i, n = 0; @@ -488,7 +488,7 @@ char **mingw_get_path_split(void) return path; } -void mingw_free_path_split(char **path) +static void mingw_free_path_split(char **path) { if (!path) return; @@ -516,7 +516,7 @@ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -char *mingw_path_lookup(const char *cmd, char **path) +static char *mingw_path_lookup(const char *cmd, char **path) { char **p = path; char *prog = NULL; @@ -537,6 +537,35 @@ char *mingw_path_lookup(const char *cmd, char **path) return prog; } +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) +{ + pid_t pid; + char **path = mingw_get_path_split(); + const char **qargv; + char *prog = mingw_path_lookup(cmd, path); + const char *interpr = parse_interpreter(prog); + int argc; + + for (argc = 0; argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + if (!interpr) { + quote_argv(qargv, argv); + pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); + } else { + qargv[0] = interpr; + qargv[1] = quote_arg(prog); + quote_argv(&qargv[2], &argv[1]); + pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + } + + free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); + + mingw_free_path_split(path); + + return pid; +} + static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) { const char **sh_argv; @@ -562,7 +591,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) exit(n); } -void mingw_execve(const char *cmd, char *const *argv, char *const *env) +static void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ if (!try_shell_exec(cmd, argv, env)) { diff --git a/git-compat-util.h b/git-compat-util.h index 31d43152d2..5235d31f27 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -470,11 +470,10 @@ static inline int kill(pid_t pid, int sig) static inline unsigned int alarm(unsigned int seconds) { return 0; } -void mingw_execve(const char *cmd, char *const *argv, char * const *env); -#define execve mingw_execve +typedef int pid_t; +extern pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); extern void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp -typedef int pid_t; static inline int waitpid(pid_t pid, unsigned *status, unsigned options) { if (options == 0) @@ -552,12 +551,6 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} extern int getpagesize(void); /* defined in MinGW's libgcc.a */ -extern void quote_argv(const char **dst, const char *const *src); -extern const char *parse_interpreter(const char *cmd); -extern char *mingw_path_lookup(const char *cmd, char **path); -extern char **mingw_get_path_split(void); -extern void mingw_free_path_split(char **path); - /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. * struct stat is redefined because it lacks the st_blocks member. diff --git a/run-command.c b/run-command.c index 05934f708f..cf1377de64 100644 --- a/run-command.c +++ b/run-command.c @@ -160,29 +160,8 @@ int start_command(struct child_process *cmd) cmd->argv[0] = git_cmd.buf; } - char **path = mingw_get_path_split(); - const char *argv0 = cmd->argv[0]; - const char **qargv; - char *prog = mingw_path_lookup(argv0, path); - const char *interpr = parse_interpreter(prog); - int argc; + cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); - for (argc = 0; cmd->argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, cmd->argv); - cmd->pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); - } else { - qargv[0] = interpr; - cmd->argv[0] = prog; - quote_argv(&qargv[1], cmd->argv); - cmd->pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); - } - - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - - mingw_free_path_split(path); /* TODO: if (cmd->env) free env; */ if (cmd->git_cmd) From 72d58fde995f38454069a9be80a747f0f1a844cc Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 24 Nov 2007 22:49:16 +0100 Subject: [PATCH 336/781] Implement a custom spawnve() on Windows. The problem with Windows's own implementation is that it tries to be clever when a console program is invoked from a GUI application: In this case it sometimes automatically allocates a new console windows. As a consequence, the IO channels of the spawned program are directed to the console, but the invoking application listens on channels that are now directed to nowhere. In this implementation we use the lowlevel facilities of CreateProcess(), which offers a flag to tell the system not to open a console. As a side effect, only stdin, stdout, and stderr channels will be accessible from C programs that are spawned. Other channels (file handles, pipe handles, etc.) are still inherited by the spawned program, but it doesn't get enough information to access them. Johannes Schindelin integrated path quoting and unified the various *execv* and *spawnv* helpers. Signed-off-by: Johannes Sixt --- compat/mingw.c | 215 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 161 insertions(+), 54 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6d2e518256..432e56ccd5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,5 +1,6 @@ #include #include "../git-compat-util.h" +#include "../strbuf.h" unsigned int _CRT_fmode = _O_BINARY; @@ -351,7 +352,10 @@ void openlog(const char *ident, int option, int facility) { } -/* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx (Parsing C++ Command-Line Arguments */ +/* + * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx + * (Parsing C++ Command-Line Arguments) + */ static const char *quote_arg(const char *arg) { /* count chars to quote */ @@ -407,13 +411,6 @@ static const char *quote_arg(const char *arg) return q; } -static void quote_argv(const char **dst, const char *const *src) -{ - while (*src) - *dst++ = quote_arg(*src++); - *dst = NULL; -} - static const char *parse_interpreter(const char *cmd) { static char buf[100]; @@ -537,73 +534,183 @@ static char *mingw_path_lookup(const char *cmd, char **path) return prog; } +static int env_compare(const void *a, const void *b) +{ + char *const *ea = a; + char *const *eb = b; + return strcasecmp(*ea, *eb); +} + +static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, + int prepend_cmd) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + struct strbuf envblk, args; + unsigned flags; + BOOL ret; + + /* Determine whether or not we are associated to a console */ + HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE, + FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (cons == INVALID_HANDLE_VALUE) { + /* There is no console associated with this process. + * Since the child is a console process, Windows + * would normally create a console window. But + * since we'll be redirecting std streams, we do + * not need the console. + */ + flags = CREATE_NO_WINDOW; + } else { + /* There is already a console. If we specified + * CREATE_NO_WINDOW here, too, Windows would + * disassociate the child from the console. + * Go figure! + */ + flags = 0; + CloseHandle(cons); + } + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = (HANDLE) _get_osfhandle(0); + si.hStdOutput = (HANDLE) _get_osfhandle(1); + si.hStdError = (HANDLE) _get_osfhandle(2); + + /* concatenate argv, quoting args as we go */ + strbuf_init(&args, 0); + if (prepend_cmd) { + char *quoted = (char *)quote_arg(cmd); + strbuf_addstr(&args, quoted); + if (quoted != cmd) + free(quoted); + } + for (; *argv; argv++) { + char *quoted = (char *)quote_arg(*argv); + if (*args.buf) + strbuf_addch(&args, ' '); + strbuf_addstr(&args, quoted); + if (quoted != *argv) + free(quoted); + } + + if (env) { + int count = 0; + char **e, **sorted_env; + + for (e = env; *e; e++) + count++; + + /* environment must be sorted */ + sorted_env = xmalloc(sizeof(*sorted_env) * (count + 1)); + memcpy(sorted_env, env, sizeof(*sorted_env) * (count + 1)); + qsort(sorted_env, count, sizeof(*sorted_env), env_compare); + + strbuf_init(&envblk, 0); + for (e = sorted_env; *e; e++) { + strbuf_addstr(&envblk, *e); + strbuf_addch(&envblk, '\0'); + } + free(sorted_env); + } + + memset(&pi, 0, sizeof(pi)); + ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags, + env ? envblk.buf : NULL, NULL, &si, &pi); + + if (env) + strbuf_release(&envblk); + strbuf_release(&args); + + if (!ret) { + errno = ENOENT; + return -1; + } + CloseHandle(pi.hThread); + return (pid_t)pi.hProcess; +} + pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) { pid_t pid; char **path = mingw_get_path_split(); - const char **qargv; char *prog = mingw_path_lookup(cmd, path); - const char *interpr = parse_interpreter(prog); - int argc; - for (argc = 0; argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); - } else { - qargv[0] = interpr; - qargv[1] = quote_arg(prog); - quote_argv(&qargv[2], &argv[1]); - pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + if (!prog) { + errno = ENOENT; + pid = -1; } + else { + const char *interpr = parse_interpreter(prog); - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - + if (interpr) { + const char *argv0 = argv[0]; + char *iprog = mingw_path_lookup(interpr, path); + argv[0] = prog; + if (!iprog) { + errno = ENOENT; + pid = -1; + } + else { + pid = mingw_spawnve(iprog, argv, env, 1); + free(iprog); + } + argv[0] = argv0; + } + else + pid = mingw_spawnve(prog, argv, env, 0); + free(prog); + } mingw_free_path_split(path); - return pid; } -static int try_shell_exec(const char *cmd, char *const *argv, char *const *env) +static int try_shell_exec(const char *cmd, char *const *argv, char **env) { - const char **sh_argv; - int n; const char *interpr = parse_interpreter(cmd); + char **path; + char *prog; + int pid = 0; + if (!interpr) return 0; - - /* - * expand - * git-foo args... - * into - * sh git-foo args... - */ - for (n = 0; argv[n];) n++; - sh_argv = xmalloc((n+2)*sizeof(char*)); - sh_argv[0] = interpr; - sh_argv[1] = quote_arg(cmd); - quote_argv(&sh_argv[2], (const char *const *)&argv[1]); - n = spawnvpe(_P_WAIT, interpr, sh_argv, (const char *const *)env); - if (n == -1) - return 1; /* indicate that we tried but failed */ - exit(n); + path = mingw_get_path_split(); + prog = mingw_path_lookup(interpr, path); + if (prog) { + int argc = 0; + const char **argv2; + while (argv[argc]) argc++; + 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); + if (pid >= 0) { + int status; + if (waitpid(pid, &status, 0) < 0) + status = 255; + exit(status); + } + pid = 1; /* indicate that we tried but failed */ + free(prog); + free(argv2); + } + mingw_free_path_split(path); + return pid; } static void mingw_execve(const char *cmd, char *const *argv, char *const *env) { /* check if git_command is a shell script */ - if (!try_shell_exec(cmd, argv, env)) { - const char **qargv; - int n; - for (n = 0; argv[n];) n++; - qargv = xmalloc((n+1)*sizeof(char*)); - quote_argv(qargv, (const char *const *)argv); - int ret = spawnve(_P_WAIT, cmd, qargv, - (const char *const *)env); - if (ret != -1) - exit(ret); + if (!try_shell_exec(cmd, argv, (char **)env)) { + int pid, status; + + pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0); + if (pid < 0) + return; + if (waitpid(pid, &status, 0) < 0) + status = 255; + exit(status); } } From 3920a6b76b8be1a405d5e30c69e3d0ba63ce5a5d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 23 Nov 2007 23:23:39 +0100 Subject: [PATCH 337/781] Look up interpreters only as .exe files. After a program was determined to be a script (which implies that it did not have a file extension), then the interpreter is looked up. This change makes sure that we will only find .exe files when we are looking for an interpreter. Otherwise, we could find a directory 'perl' that is somewhere earlier in the path than 'perl.exe'. Signed-off-by: Johannes Sixt --- compat/mingw.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 432e56ccd5..a25063b7f7 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -496,15 +496,19 @@ static void mingw_free_path_split(char **path) free(path); } -static char *lookup_prog(const char *dir, const char *cmd, int tryexe) +/* + * exe_only means that we only want to detect .exe files, but not scripts + * (which do not have an extension) + */ +static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only) { char path[MAX_PATH]; snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd); - if (tryexe && access(path, 0) == 0) + if (!isexe && access(path, F_OK) == 0) return xstrdup(path); path[strlen(path)-4] = '\0'; - if (access(path, 0) == 0) + if ((!exe_only || isexe) && access(path, F_OK) == 0) return xstrdup(path); return NULL; } @@ -513,21 +517,21 @@ static char *lookup_prog(const char *dir, const char *cmd, int tryexe) * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -static char *mingw_path_lookup(const char *cmd, char **path) +static char *mingw_path_lookup(const char *cmd, char **path, int exe_only) { char **p = path; char *prog = NULL; int len = strlen(cmd); - int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe"); + int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe"); if (strchr(cmd, '/') || strchr(cmd, '\\')) prog = xstrdup(cmd); while (!prog && *p) { - prog = lookup_prog(*p++, cmd, tryexe); + prog = lookup_prog(*p++, cmd, isexe, exe_only); } if (!prog) { - prog = lookup_prog(".", cmd, tryexe); + prog = lookup_prog(".", cmd, isexe, exe_only); if (!prog) prog = xstrdup(cmd); } @@ -635,7 +639,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) { pid_t pid; char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path); + char *prog = mingw_path_lookup(cmd, path, 0); if (!prog) { errno = ENOENT; @@ -646,7 +650,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) if (interpr) { const char *argv0 = argv[0]; - char *iprog = mingw_path_lookup(interpr, path); + char *iprog = mingw_path_lookup(interpr, path, 1); argv[0] = prog; if (!iprog) { errno = ENOENT; @@ -676,7 +680,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) if (!interpr) return 0; path = mingw_get_path_split(); - prog = mingw_path_lookup(interpr, path); + prog = mingw_path_lookup(interpr, path, 1); if (prog) { int argc = 0; const char **argv2; @@ -717,7 +721,7 @@ static void mingw_execve(const char *cmd, char *const *argv, char *const *env) void mingw_execvp(const char *cmd, char *const *argv) { char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path); + char *prog = mingw_path_lookup(cmd, path, 0); if (prog) { mingw_execve(prog, argv, environ); From bfe13b635738de33368a5ce297a981438dfc955b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 26 Nov 2007 13:14:34 +0100 Subject: [PATCH 338/781] Fix setitimer implementation. Although we made sure that in->it_interval is either zero or equal to in->it_value, we were still using in->it_interval to compute the timeout, which could be zero, for example, with git-log's --early-output flag. Use in->it_value instead. On the otherhand, we used in->it_value to check for a single-shot timer. Use in->it_interval instead. Signed-off-by: Johannes Sixt --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a25063b7f7..e57c74e0ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -978,8 +978,8 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out) is_timeval_eq(&in->it_interval, &zero)) return 0; - timer_interval = in->it_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000; - one_shot = is_timeval_eq(&in->it_value, &zero); + timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000; + one_shot = is_timeval_eq(&in->it_interval, &zero); if (!atexit_done) { atexit(stop_timer_thread); atexit_done = 1; From 79fba817db0dad5f4c4bd3982b20d5d7f5accd9d Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 17 Nov 2007 19:10:18 +0100 Subject: [PATCH 339/781] sha1_file.c: Fix size_t related printf format warnings The old way of fixing warnings did not succeed on MinGW. MinGW does not support C99 printf format strings for size_t [1]. But gcc on MinGW issues warnings if C99 printf format is not used. Hence, the old stragegy to avoid warnings fails. [1] http://www.mingw.org/MinGWiki/index.php/C99 This commits passes arguments of type size_t through a tiny helper functions that casts to the type expected by the format string. Signed-off-by: Steffen Prohaska --- sha1_file.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index bd0e7cd21c..1984e35823 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -25,8 +25,10 @@ #ifdef NO_C99_FORMAT #define SZ_FMT "lu" +static unsigned long sz_fmt(size_t s) { return (unsigned long)s; } #else #define SZ_FMT "zu" +static size_t sz_fmt(size_t s) { return s; } #endif const unsigned char null_sha1[20]; @@ -431,9 +433,9 @@ void pack_report(void) "pack_report: getpagesize() = %10" SZ_FMT "\n" "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" "pack_report: core.packedGitLimit = %10" SZ_FMT "\n", - (unsigned long) getpagesize(), - (unsigned long) packed_git_window_size, - (unsigned long) packed_git_limit); + sz_fmt(getpagesize()), + sz_fmt(packed_git_window_size), + sz_fmt(packed_git_limit)); fprintf(stderr, "pack_report: pack_used_ctr = %10u\n" "pack_report: pack_mmap_calls = %10u\n" @@ -443,8 +445,7 @@ void pack_report(void) pack_used_ctr, pack_mmap_calls, pack_open_windows, peak_pack_open_windows, - (unsigned long) pack_mapped, - (unsigned long) peak_pack_mapped); + sz_fmt(pack_mapped), sz_fmt(peak_pack_mapped)); } static int check_packed_git_idx(const char *path, struct packed_git *p) From 98603195e96615b491384724bfff6564d31ad067 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 1 Dec 2007 17:49:10 +0100 Subject: [PATCH 340/781] skip t5512 because remote does not yet work Signed-off-by: Steffen Prohaska --- t/t5512-ls-remote.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 6ec5f7c48b..b3a6d6f341 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -4,6 +4,9 @@ test_description='git ls-remote' . ./test-lib.sh +say "git remote does not work in t/ - skipping" +test_done + test_expect_success setup ' >file && From 7ce819b333256b4ff1e1f2f72796b6f34d3c70d0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 1 Dec 2007 20:50:09 +0100 Subject: [PATCH 341/781] Clean up the MINGW section in the Makefile. We want to use whitespace around '=' consistently before we ask for inclusion in upstream. Signed-off-by: Johannes Sixt --- Makefile | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 39dbd2a142..32b6c0292a 100644 --- a/Makefile +++ b/Makefile @@ -496,25 +496,26 @@ ifeq ($(uname_S),IRIX64) BASIC_LDFLAGS += -L/usr/lib32 endif ifneq (,$(findstring MINGW,$(uname_S))) - NO_MMAP=YesPlease - NO_PREAD=YesPlease - NO_OPENSSL=YesPlease - NO_CURL=YesPlease - NO_SYMLINK_HEAD=YesPlease - NO_IPV6=YesPlease - NO_SETENV=YesPlease - NO_UNSETENV=YesPlease - NO_STRCASESTR=YesPlease - NO_STRLCPY=YesPlease + NO_MMAP = YesPlease + NO_PREAD = YesPlease + NO_OPENSSL = YesPlease + NO_CURL = YesPlease + NO_SYMLINK_HEAD = YesPlease + NO_IPV6 = YesPlease + NO_SETENV = YesPlease + NO_UNSETENV = YesPlease + NO_STRCASESTR = YesPlease + NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_MKDTEMP = YesPlease - NO_SVN_TESTS=YesPlease - NO_PERL_MAKEMAKER=YesPlease - COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" -D__USE_MINGW_ACCESS -DNOGDI -I compat + NO_SVN_TESTS = YesPlease + NO_PERL_MAKEMAKER = YesPlease + COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe From 2bd3a118a7e1bb6c047300ca3e3c9c890175e22c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 1 Dec 2007 21:36:07 +0100 Subject: [PATCH 342/781] Clean up the MINGW section in git-compat-util.h. The entries are now arranged in categories. inet_ntop(), kill(), and openlog() are unused and, hence, removed. Signed-off-by: Johannes Sixt --- Makefile | 6 ++ compat/mingw.c | 12 +-- git-compat-util.h | 216 ++++++++++++++++++++++++++-------------------- 3 files changed, 130 insertions(+), 104 deletions(-) diff --git a/Makefile b/Makefile index 32b6c0292a..c1e58a63ff 100644 --- a/Makefile +++ b/Makefile @@ -514,6 +514,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + NO_EXTRA_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o @@ -583,6 +584,11 @@ ifdef ZLIB_PATH endif EXTLIBS += -lz +ifndef NO_EXTRA_PROGRAMS + EXTRA_PROGRAMS += \ + git-daemon$X \ + git-imap-send$X +endif ifndef NO_OPENSSL OPENSSL_LIBSSL = -lssl ifdef OPENSSLDIR diff --git a/compat/mingw.c b/compat/mingw.c index e57c74e0ce..e74f148b27 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -181,11 +181,7 @@ unsigned int sleep (unsigned int __seconds) Sleep(__seconds*1000); return 0; } -const char *inet_ntop(int af, const void *src, - char *dst, size_t cnt) -{ - return NULL; -} + int mkstemp (char *__template) { char *filename = mktemp(__template); @@ -348,10 +344,6 @@ char *mingw_getcwd(char *pointer, int len) return ret; } -void openlog(const char *ident, int option, int facility) -{ -} - /* * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx * (Parsing C++ Command-Line Arguments) @@ -876,7 +868,7 @@ int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) return len; } -struct passwd *mingw_getpwuid(int uid) +struct passwd *getpwuid(int uid) { static char user_name[100]; static struct passwd p; diff --git a/git-compat-util.h b/git-compat-util.h index 5235d31f27..e2aebfb375 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -64,18 +64,14 @@ #include #include #include +#include +#include #ifndef __MINGW32__ #include #include #include #include #include -#else -int mkstemp (char *__template); -#endif -#include -#include -#ifndef __MINGW32__ #include #include #include @@ -91,7 +87,7 @@ int mkstemp (char *__template); #include #define _ALL_SOURCE 1 #endif -#endif +#endif /* !__MINGW32__ */ #ifndef NO_ICONV #include @@ -362,6 +358,10 @@ static inline FILE *xfdopen(int fd, const char *mode) return stream; } +#ifdef __MINGW32__ +int mkstemp(char *template); +#endif + static inline int xmkstemp(char *template) { int fd; @@ -445,6 +445,13 @@ static inline int strtol_i(char const *s, int base, int *result) #include +/* + * things that are not available in header files + */ + +typedef int pid_t; +#define hstrerror strerror + #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 @@ -455,6 +462,50 @@ static inline int strtol_i(char const *s, int base, int *result) #define S_IROTH 0 #define S_IXOTH 0 +#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ +#define WEXITSTATUS(x) ((x) & 0xff) +#define WIFSIGNALED(x) ((unsigned)(x) > 259) + +#define SIGKILL 0 +#define SIGCHLD 0 +#define SIGPIPE 0 +#define SIGALRM 100 + +#define F_GETFD 1 +#define F_SETFD 2 +#define FD_CLOEXEC 0x1 + +struct passwd { + char *pw_name; + char *pw_gecos; + char *pw_dir; +}; + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; +#define POLLIN 1 +#define POLLHUP 2 + +typedef void (__cdecl *sig_handler_t)(int); +struct sigaction { + sig_handler_t sa_handler; + unsigned sa_flags; +}; +#define sigemptyset(x) (void)0 +#define SA_RESTART 0 + +struct itimerval { + struct timeval it_value, it_interval; +}; +#define ITIMER_REAL 0 + +/* + * trivial stubs + */ + static inline int readlink(const char *path, char *buf, size_t bufsiz) { errno = ENOSYS; return -1; } static inline int symlink(const char *oldpath, const char *newpath) @@ -465,72 +516,74 @@ static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) { errno = ENOSYS; return -1; } -static inline int kill(pid_t pid, int sig) -{ errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } - -typedef int pid_t; -extern pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); -extern void mingw_execvp(const char *cmd, char *const *argv); -#define execvp mingw_execvp -static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +static inline int fsync(int fd) +{ return 0; } +static inline int getppid(void) +{ return 1; } +static inline void sync(void) +{} +static inline int getuid() +{ return 1; } +static inline struct passwd *getpwnam(const char *name) +{ return NULL; } +static inline int fcntl(int fd, int cmd, long arg) { - if (options == 0) - return _cwait(status, pid, 0); - else - return errno = EINVAL, -1; + if (cmd == F_GETFD || cmd == F_SETFD) + return 0; + errno = EINVAL; + return -1; } -#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ -#define WEXITSTATUS(x) ((x) & 0xff) -#define WIFSIGNALED(x) ((unsigned)(x) > 259) -#define WTERMSIG(x) (x) -#define WNOHANG 1 -#define SIGKILL 0 -#define SIGCHLD 0 -#define SIGPIPE 0 +/* + * simple adaptors + */ -char **copy_environ(); -char **copy_env(char **env); -void env_unsetenv(char **env, const char *name); - -unsigned int sleep (unsigned int __seconds); -const char *inet_ntop(int af, const void *src, - char *dst, size_t cnt); -int gettimeofday(struct timeval *tv, void *tz); -int pipe(int filedes[2]); - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; -int poll(struct pollfd *ufds, unsigned int nfds, int timeout); -#define POLLIN 1 -#define POLLHUP 2 - -static inline int git_mkdir(const char *path, int mode) +static inline int mingw_mkdir(const char *path, int mode) { return mkdir(path); } -#define mkdir git_mkdir +#define mkdir mingw_mkdir -static inline int git_unlink(const char *pathname) { +static inline int mingw_unlink(const char *pathname) +{ /* read-only files cannot be removed */ chmod(pathname, 0666); return unlink(pathname); } -#define unlink git_unlink +#define unlink mingw_unlink + +static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +{ + if (options == 0) + return _cwait(status, pid, 0); + errno = EINVAL; + return -1; +} + +/* + * implementations of missing functions + */ + +int pipe(int filedes[2]); +unsigned int sleep (unsigned int seconds); +int gettimeofday(struct timeval *tv, void *tz); +int poll(struct pollfd *ufds, unsigned int nfds, int timeout); +struct tm *gmtime_r(const time_t *timep, struct tm *result); +struct tm *localtime_r(const time_t *timep, struct tm *result); +int getpagesize(void); /* defined in MinGW's libgcc.a */ +struct passwd *getpwuid(int uid); +int setitimer(int type, struct itimerval *in, struct itimerval *out); +int sigaction(int sig, struct sigaction *in, struct sigaction *out); + +/* + * replacements of existing functions + */ int mingw_open (const char *filename, int oflags, ...); #define open mingw_open -#include -struct tm *gmtime_r(const time_t *timep, struct tm *result); -struct tm *localtime_r(const time_t *timep, struct tm *result); -#define hstrerror strerror - char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd @@ -546,11 +599,6 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); int mingw_rename(const char*, const char*); #define rename mingw_rename -static inline int fsync(int fd) { return 0; } -static inline int getppid(void) { return 1; } -static inline void sync(void) {} -extern int getpagesize(void); /* defined in MinGW's libgcc.a */ - /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. * struct stat is redefined because it lacks the st_blocks member. @@ -573,45 +621,25 @@ static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vsnprintf mingw_vsnprintf -struct passwd { - char *pw_name; - char *pw_gecos; - char *pw_dir; -}; -struct passwd *mingw_getpwuid(int uid); -#define getpwuid mingw_getpwuid -static inline int getuid() { return 1; } -static inline struct passwd *getpwnam(const char *name) { return NULL; } - -struct itimerval { - struct timeval it_value, it_interval; -}; -int setitimer(int type, struct itimerval *in, struct itimerval *out); -#define ITIMER_REAL 0 - -typedef void (__cdecl *sig_handler_t)(int); -struct sigaction { - sig_handler_t sa_handler; - unsigned sa_flags; -}; -int sigaction(int sig, struct sigaction *in, struct sigaction *out); -#define sigemptyset(x) (void)0 -#define SA_RESTART 0 -#define SIGALRM 100 -sig_handler_t mingw_signal(int sig, sig_handler_t handler); -#define signal mingw_signal - -#define F_GETFD 1 -#define F_SETFD 2 -#define FD_CLOEXEC 0x1 -static inline int mingw_fcntl(int fd, int cmd, long arg) -{ return cmd == F_GETFD || cmd == F_SETFD ? 0 : (errno = EINVAL, -1); } -#define fcntl mingw_fcntl +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); +void mingw_execvp(const char *cmd, char *const *argv); +#define execvp mingw_execvp static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); } #define ntohl git_ntohl +sig_handler_t mingw_signal(int sig, sig_handler_t handler); +#define signal mingw_signal + +/* + * helpers + */ + +char **copy_environ(); +char **copy_env(char **env); +void env_unsetenv(char **env, const char *name); + #endif /* __MINGW32__ */ #endif From dfc991a98a22c8f440345ced7a906d90edf410dc Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 19:35:00 +0100 Subject: [PATCH 343/781] Clean up compat/mingw.c. The PATH related functions are now static and can lose the mingw_ prefix. path_lookup() no longer looks in the current directory, and it will now actually return NULL. Previously, it returned the input program name as a fallback. Signed-off-by: Johannes Sixt --- compat/mingw.c | 50 ++++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index e74f148b27..d32722ee26 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,4 +1,3 @@ -#include #include "../git-compat-util.h" #include "../strbuf.h" @@ -176,15 +175,15 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } -unsigned int sleep (unsigned int __seconds) +unsigned int sleep (unsigned int seconds) { - Sleep(__seconds*1000); + Sleep(seconds*1000); return 0; } -int mkstemp (char *__template) +int mkstemp(char *template) { - char *filename = mktemp(__template); + char *filename = mktemp(template); if (filename == NULL) return -1; return open(filename, O_RDWR | O_CREAT, 0600); @@ -314,8 +313,6 @@ repeat: return 0; } -#include - struct tm *gmtime_r(const time_t *timep, struct tm *result) { memcpy(result, gmtime(timep), sizeof(struct tm)); @@ -441,7 +438,7 @@ static const char *parse_interpreter(const char *cmd) /* * Splits the PATH into parts. */ -static char **mingw_get_path_split(void) +static char **get_path_split(void) { char *p, **path, *envpath = getenv("PATH"); int i, n = 0; @@ -477,7 +474,7 @@ static char **mingw_get_path_split(void) return path; } -static void mingw_free_path_split(char **path) +static void free_path_split(char **path) { if (!path) return; @@ -509,9 +506,8 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on * Determines the absolute path of cmd using the the split path in path. * If cmd contains a slash or backslash, no lookup is performed. */ -static char *mingw_path_lookup(const char *cmd, char **path, int exe_only) +static char *path_lookup(const char *cmd, char **path, int exe_only) { - char **p = path; char *prog = NULL; int len = strlen(cmd); int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe"); @@ -519,14 +515,9 @@ static char *mingw_path_lookup(const char *cmd, char **path, int exe_only) if (strchr(cmd, '/') || strchr(cmd, '\\')) prog = xstrdup(cmd); - while (!prog && *p) { - prog = lookup_prog(*p++, cmd, isexe, exe_only); - } - if (!prog) { - prog = lookup_prog(".", cmd, isexe, exe_only); - if (!prog) - prog = xstrdup(cmd); - } + while (!prog && *path) + prog = lookup_prog(*path++, cmd, isexe, exe_only); + return prog; } @@ -630,8 +621,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) { pid_t pid; - char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path, 0); + char **path = get_path_split(); + char *prog = path_lookup(cmd, path, 0); if (!prog) { errno = ENOENT; @@ -642,7 +633,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) if (interpr) { const char *argv0 = argv[0]; - char *iprog = mingw_path_lookup(interpr, path, 1); + char *iprog = path_lookup(interpr, path, 1); argv[0] = prog; if (!iprog) { errno = ENOENT; @@ -658,7 +649,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) pid = mingw_spawnve(prog, argv, env, 0); free(prog); } - mingw_free_path_split(path); + free_path_split(path); return pid; } @@ -671,8 +662,8 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) if (!interpr) return 0; - path = mingw_get_path_split(); - prog = mingw_path_lookup(interpr, path, 1); + path = get_path_split(); + prog = path_lookup(interpr, path, 1); if (prog) { int argc = 0; const char **argv2; @@ -691,7 +682,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env) free(prog); free(argv2); } - mingw_free_path_split(path); + free_path_split(path); return pid; } @@ -712,8 +703,8 @@ static void mingw_execve(const char *cmd, char *const *argv, char *const *env) void mingw_execvp(const char *cmd, char *const *argv) { - char **path = mingw_get_path_split(); - char *prog = mingw_path_lookup(cmd, path, 0); + char **path = get_path_split(); + char *prog = path_lookup(cmd, path, 0); if (prog) { mingw_execve(prog, argv, environ); @@ -721,7 +712,7 @@ void mingw_execvp(const char *cmd, char *const *argv) } else errno = ENOENT; - mingw_free_path_split(path); + free_path_split(path); } char **copy_environ() @@ -882,7 +873,6 @@ struct passwd *getpwuid(int uid) return &p; } - static HANDLE timer_event; static HANDLE timer_thread; static int timer_interval; From f6df056f6cda03bdb102ab2e2d928872456135da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 20:26:24 +0100 Subject: [PATCH 344/781] Rework environment manipulation. A lookup routine is extracted from env_unsetenv() because we will need it for env_setenv(). The environment data is now released, too. Signed-off-by: Johannes Sixt --- compat/mingw.c | 61 ++++++++++++++++++++++++++--------------------- git-compat-util.h | 4 ++-- run-command.c | 4 ++-- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index d32722ee26..fa5b9cd379 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -717,41 +717,48 @@ void mingw_execvp(const char *cmd, char *const *argv) char **copy_environ() { - return copy_env(environ); + char **env; + int i = 0; + while (environ[i]) + i++; + env = xmalloc((i+1)*sizeof(*env)); + for (i = 0; environ[i]; i++) + env[i] = xstrdup(environ[i]); + env[i] = NULL; + return env; } -char **copy_env(char **env) +void free_env(char **env) { - char **s; - int n = 1; - for (s = env; *s; s++) - n++; - s = xmalloc(n*sizeof(char *)); - memcpy(s, env, n*sizeof(char *)); - return s; + int i; + for (i = 0; env[i]; i++) + free(env[i]); + free(env); +} + +static int lookup_env(char **env, const char *name) +{ + int i; + size_t nmln = strlen(name); + + for (i = 0; env[i]; i++) { + if (0 == strncmp(env[i], name, nmln) + && '=' == env[i][nmln]) + /* matches */ + return i; + } + return -1; } void env_unsetenv(char **env, const char *name) { - int src, dst; - size_t nmln; + int i = lookup_env(env, name); + if (i < 0) + return; - nmln = strlen(name); - - for (src = dst = 0; env[src]; ++src) { - size_t enln; - enln = strlen(env[src]); - if (enln > nmln) { - /* might match, and can test for '=' safely */ - if (0 == strncmp (env[src], name, nmln) - && '=' == env[src][nmln]) - /* matches, so skip */ - continue; - } - env[dst] = env[src]; - ++dst; - } - env[dst] = NULL; + free(env[i]); + for (; env[i]; i++) + env[i] = env[i+1]; } /* this is the first function to call into WS_32; initialize it */ diff --git a/git-compat-util.h b/git-compat-util.h index e2aebfb375..12426951fa 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -636,8 +636,8 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); * helpers */ -char **copy_environ(); -char **copy_env(char **env); +char **copy_environ(void); +void free_environ(void); void env_unsetenv(char **env, const char *name); #endif /* __MINGW32__ */ diff --git a/run-command.c b/run-command.c index cf1377de64..8e0daab62a 100644 --- a/run-command.c +++ b/run-command.c @@ -162,8 +162,8 @@ int start_command(struct child_process *cmd) cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); - /* TODO: if (cmd->env) free env; */ - + if (cmd->env) + free(env); if (cmd->git_cmd) strbuf_release(&git_cmd); From 9a930a2ecb95030b0b3b1ec651c1307c5e57073c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 21:39:19 +0100 Subject: [PATCH 345/781] Implement setting of environment variables in spawned programs. Signed-off-by: Johannes Sixt --- compat/mingw.c | 34 +++++++++++++++++++++++++--------- git-compat-util.h | 2 +- run-command.c | 8 ++------ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index fa5b9cd379..553e8f3ac4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -736,10 +736,9 @@ void free_env(char **env) free(env); } -static int lookup_env(char **env, const char *name) +static int lookup_env(char **env, const char *name, size_t nmln) { int i; - size_t nmln = strlen(name); for (i = 0; env[i]; i++) { if (0 == strncmp(env[i], name, nmln) @@ -750,15 +749,32 @@ static int lookup_env(char **env, const char *name) return -1; } -void env_unsetenv(char **env, const char *name) +/* + * If name contains '=', then sets the variable, otherwise it unsets it + */ +char **env_setenv(char **env, const char *name) { - int i = lookup_env(env, name); - if (i < 0) - return; + char *eq = strchrnul(name, '='); + int i = lookup_env(env, name, eq-name); - free(env[i]); - for (; env[i]; i++) - env[i] = env[i+1]; + if (i < 0) { + if (*eq) { + for (i = 0; env[i]; i++) + ; + env = xrealloc(env, (i+2)*sizeof(*env)); + env[i] = xstrdup(name); + env[i+1] = NULL; + } + } + else { + free(env[i]); + if (*eq) + env[i] = xstrdup(name); + else + for (; env[i]; i++) + env[i] = env[i+1]; + } + return env; } /* this is the first function to call into WS_32; initialize it */ diff --git a/git-compat-util.h b/git-compat-util.h index 12426951fa..120f88c943 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -638,7 +638,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); char **copy_environ(void); void free_environ(void); -void env_unsetenv(char **env, const char *name); +char **env_setenv(char **env, const char *name); #endif /* __MINGW32__ */ diff --git a/run-command.c b/run-command.c index 8e0daab62a..37d4d7fafc 100644 --- a/run-command.c +++ b/run-command.c @@ -146,12 +146,8 @@ int start_command(struct child_process *cmd) die("chdir in start_command() not implemented"); if (cmd->env) { env = copy_environ(); - for (; *cmd->env; cmd->env++) { - if (strchr(*cmd->env, '=')) - die("setting environment in start_command() not implemented"); - else - env_unsetenv(env, *cmd->env); - } + for (; *cmd->env; cmd->env++) + env = env_setenv(env, *cmd->env); } if (cmd->git_cmd) { From 864e1c96c242174e4345c2443f7ab34fb9102619 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 5 Dec 2007 21:39:59 +0100 Subject: [PATCH 346/781] Exclude t4023-diff-rename-typechange - symbolic links are not available. Signed-off-by: Johannes Sixt --- t/t4023-diff-rename-typechange.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 255604effd..7a2a05ae20 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -4,6 +4,11 @@ test_description='typechange rename detection' . ./test-lib.sh +if test "$no_symlinks"; then + say "symbolic links not supported - skipping test" + test_done; +fi + test_expect_success setup ' rm -f foo bar && From d63abd8dc5e63c0d174d1ddfe34dd1957e5a692b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 7 Dec 2007 22:45:20 +0100 Subject: [PATCH 347/781] Fixup the clean-up of environment handling. Signed-off-by: Johannes Sixt --- compat/mingw.c | 2 +- git-compat-util.h | 2 +- run-command.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 553e8f3ac4..8bbe21bb67 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -728,7 +728,7 @@ char **copy_environ() return env; } -void free_env(char **env) +void free_environ(char **env) { int i; for (i = 0; env[i]; i++) diff --git a/git-compat-util.h b/git-compat-util.h index 120f88c943..ab7b668124 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -637,7 +637,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); */ char **copy_environ(void); -void free_environ(void); +void free_environ(char **env); char **env_setenv(char **env, const char *name); #endif /* __MINGW32__ */ diff --git a/run-command.c b/run-command.c index 37d4d7fafc..5ed338c0cb 100644 --- a/run-command.c +++ b/run-command.c @@ -159,7 +159,7 @@ int start_command(struct child_process *cmd) cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); if (cmd->env) - free(env); + free_environ(env); if (cmd->git_cmd) strbuf_release(&git_cmd); From a1e84247e94e39fd8ff5dace0cfb9fa35c562a61 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 8 Dec 2007 15:33:04 +0100 Subject: [PATCH 348/781] t7501-commit: Skip testing '--interactive' msysgit does not yet support Git.pm, which is required by git commit --interactive. This commit modifies t7501 to skip testing git commit --interactive. Signed-off-by: Steffen Prohaska --- t/t7501-commit.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 19c4b2c556..dd4bf28526 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -119,6 +119,7 @@ test_expect_success \ "echo 'gak' >file && \ git-commit -m 'author' --author 'Rubber Duck ' -a" +echo "SKIP because msysgit does not support Git.pm" || test_expect_success \ "interactive add" \ "echo 7 | git-commit --interactive | grep 'What now'" From 4a8d948eaccda45f1afded4dc545e35207a0847f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 20:51:36 +0100 Subject: [PATCH 349/781] Fix prefix_filename() function. The previous implementation translated '\' to '/' on non-Windows, too (in those cases where the prefix was actually prepended to the path). Signed-off-by: Johannes Sixt --- setup.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/setup.c b/setup.c index a89152d630..2cbe8733a5 100644 --- a/setup.c +++ b/setup.c @@ -82,21 +82,23 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; - char *p; #ifndef __MINGW32__ if (!pfx || !*pfx || is_absolute_path(arg)) return arg; + memcpy(path, pfx, pfx_len); + strcpy(path + pfx_len, arg); #else - /* don't add prefix to absolute paths */ + char *p; + /* don't add prefix to absolute paths, but still replace '\' by '/' */ if (is_absolute_path(arg)) pfx_len = 0; else -#endif - memcpy(path, pfx, pfx_len); + memcpy(path, pfx, pfx_len); strcpy(path + pfx_len, arg); for (p = path + pfx_len; *p; p++) if (*p == '\\') *p = '/'; +#endif return path; } From 31cda4934813255c319e0f10791903ead783bbba Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 21:47:19 +0100 Subject: [PATCH 350/781] Clean up pager.c (Windows specific part). Signed-off-by: Johannes Sixt --- pager.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pager.c b/pager.c index de1bc799f5..c9f7e62534 100644 --- a/pager.c +++ b/pager.c @@ -1,8 +1,8 @@ #include "cache.h" /* - * This is split up from the rest of git so that we might do - * something different on Windows, for example. + * This is split up from the rest of git so that we can do + * something different on Windows. */ #ifndef __MINGW32__ @@ -24,12 +24,12 @@ static void run_pager(const char *pager) #else #include "run-command.h" -const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; static struct child_process pager_process = { .argv = pager_argv, .in = -1 }; -static void collect_pager(void) +static void wait_for_pager(void) { fflush(stdout); close(1); /* signals EOF to pager */ @@ -99,6 +99,6 @@ void setup_pager(void) close(pager_process.in); /* this makes sure that the parent terminates after the pager */ - atexit(collect_pager); + atexit(wait_for_pager); #endif } From 71d36f430104ac845093cf91e79b1b31952ac314 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 23:09:34 +0100 Subject: [PATCH 351/781] Add #ifdef __MINGW32__ in two places Signed-off-by: Johannes Sixt --- connect.c | 7 ++++++- path.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index c1483bf4f8..12903986f3 100644 --- a/connect.c +++ b/connect.c @@ -523,8 +523,13 @@ struct child_process *git_connect(int fd[2], const char *url_orig, end = host; path = strchr(end, c); +#ifdef __MINGW32__ /* host must have at least 2 chars to catch DOS C:/path */ - if (path && path - end > 1) { + if (path && path - end > 1) +#else + if (path) +#endif + { if (c == ':') { protocol = PROTO_SSH; *path++ = '\0'; diff --git a/path.c b/path.c index e264bb34a9..7f1853939d 100644 --- a/path.c +++ b/path.c @@ -75,11 +75,13 @@ int git_mkstemp(char *path, size_t len, const char *template) size_t n; tmp = getenv("TMPDIR"); +#ifdef __MINGW32__ /* on Windows it is TMP and TEMP */ if (!tmp) tmp = getenv("TMP"); if (!tmp) tmp = getenv("TEMP"); +#endif if (!tmp) tmp = "/tmp"; n = snprintf(path, len, "%s/%s", tmp, template); From b54486636e4f7ef7758e4cc0158c1446d263b253 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 23:12:41 +0100 Subject: [PATCH 352/781] Rename is_path_absolute() in sha1_file.c to offset_1st_component(). This better describes the purpose of the function. Signed-off-by: Johannes Sixt --- sha1_file.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index 1984e35823..e7deefc769 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -83,20 +83,18 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) return 0; } -/* returns the number of chars to skip to first component */ -static inline int is_path_absolute(const char *path) +static inline int offset_1st_component(const char *path) { #ifdef __MINGW32__ if (isalpha(path[0]) && path[1] == ':') return 2 + (path[2] == '/'); - /* TODO: C:dir/file 'relative' paths are not catered for */ #endif return *path == '/'; } int safe_create_leading_directories(char *path) { - char *pos = path + is_path_absolute(path); + char *pos = path + offset_1st_component(path); struct stat st; while (pos) { From 370a1dad18129837c95188f91edef6e3e12cd9d0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 8 Dec 2007 23:15:32 +0100 Subject: [PATCH 353/781] Don't make the extra check for errno == EINVAL MinGW specific. This saves an #ifdef. There is precedent for an extra check without #ifdef brackets already in refs.c (Solaris). The check for EINVAL shouldn't hurt. Signed-off-by: Johannes Sixt --- write_or_die.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/write_or_die.c b/write_or_die.c index 40b046acb0..f3b8566ab8 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -34,16 +34,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) return; } if (fflush(f)) { -#ifndef __MINGW32__ - if (errno == EPIPE) -#else /* * On Windows, EPIPE is returned only by the first write() * after the reading end has closed its handle; subsequent * write()s return EINVAL. */ if (errno == EPIPE || errno == EINVAL) -#endif exit(0); die("write failure on %s: %s", desc, strerror(errno)); } From 06bb831308532f7bc5bd00f634e60586e998c518 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Dec 2007 21:47:44 +0100 Subject: [PATCH 354/781] t7201-co: Work around whitespace damaged messages.expect Signed-off-by: Johannes Sixt --- t/t7201-co.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 73d8a00e2c..be9271543b 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -185,7 +185,7 @@ If you want to create a new branch from this checkout, you may do so HEAD is now at 7329388... Initial A one, A two EOF ) && - git diff messages.expect messages && + git diff -w messages.expect messages && H=$(git rev-parse --verify HEAD) && M=$(git show-ref -s --verify refs/heads/master) && test "z$H" = "z$M" && From 0574f944567faf0d0129e28a57705c931441b1d8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Dec 2007 22:09:18 +0100 Subject: [PATCH 355/781] t7503, t7504: Skip tests of non-executable hook if execute bit doesn't work Signed-off-by: Johannes Sixt --- t/t7503-pre-commit-hook.sh | 6 ++++++ t/t7504-commit-msg-hook.sh | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh index d787cac2f7..5c13097bda 100755 --- a/t/t7503-pre-commit-hook.sh +++ b/t/t7503-pre-commit-hook.sh @@ -69,6 +69,10 @@ test_expect_success '--no-verify with failing hook' ' ' chmod -x "$HOOK" +if test "$(git config --bool core.filemode)" = false; then + say "executable bit not honored - skipping tests of non-executable hook" +else + test_expect_success 'with non-executable hook' ' echo "content" >> file && @@ -85,4 +89,6 @@ test_expect_success '--no-verify with non-executable hook' ' ' +fi # non-executable hooks + test_done diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh index 751b11300b..12ed793a48 100755 --- a/t/t7504-commit-msg-hook.sh +++ b/t/t7504-commit-msg-hook.sh @@ -133,6 +133,10 @@ test_expect_success '--no-verify with failing hook (editor)' ' ' chmod -x "$HOOK" +if test "$(git config --bool core.filemode)" = false; then + say "executable bit not honored - skipping tests of non-executable hook" +else + test_expect_success 'with non-executable hook' ' echo "content" >> file && @@ -167,6 +171,8 @@ test_expect_success '--no-verify with non-executable hook (editor)' ' ' +fi # non-executable hooks + # now a hook that edits the commit message cat > "$HOOK" <<'EOF' #!/bin/sh From 3805d587572fd50b2e8bb6af6b1dbccffb6807e5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 10 Dec 2007 12:55:35 +0100 Subject: [PATCH 356/781] Avoid the "dup dance" in wt_status_print_verbose() when possible. If the status output already goes to stdout, then it is not necessary to redirect stdout for the diff machinery. (This case hangs on Windows for unknown reasons.) Signed-off-by: Johannes Sixt --- wt-status.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/wt-status.c b/wt-status.c index 51c1879691..9a2d3c65b7 100644 --- a/wt-status.c +++ b/wt-status.c @@ -321,15 +321,17 @@ static void wt_status_print_untracked(struct wt_status *s) static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; - int saved_stdout; + int saved_stdout = -1; fflush(s->fp); /* Sigh, the entire diff machinery is hardcoded to output to * stdout. Do the dup-dance...*/ - saved_stdout = dup(STDOUT_FILENO); - if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) - die("couldn't redirect stdout\n"); + if (fileno(s->fp) != STDOUT_FILENO) { + saved_stdout = dup(STDOUT_FILENO); + if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) + die("couldn't redirect stdout\n"); + } init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->reference); @@ -340,7 +342,7 @@ static void wt_status_print_verbose(struct wt_status *s) fflush(stdout); - if (dup2(saved_stdout, STDOUT_FILENO) < 0) + if (saved_stdout >= 0 && dup2(saved_stdout, STDOUT_FILENO) < 0) die("couldn't restore stdout\n"); close(saved_stdout); } From 8f4e9dca13aba080505aa95897de2833b1f421d6 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Dec 2007 15:40:11 +0100 Subject: [PATCH 357/781] Enhance the dup-dance in wt-status to work around t7502-commit.sh hang Seems like Windows has some problems if you do too much dup()ing around. Work around these problems by dup()ing yet one more time. Signed-off-by: Johannes Schindelin --- wt-status.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wt-status.c b/wt-status.c index 51c1879691..0b8a73fd44 100644 --- a/wt-status.c +++ b/wt-status.c @@ -321,15 +321,17 @@ static void wt_status_print_untracked(struct wt_status *s) static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; - int saved_stdout; + int saved_stdout, redirected_stdout; fflush(s->fp); /* Sigh, the entire diff machinery is hardcoded to output to * stdout. Do the dup-dance...*/ saved_stdout = dup(STDOUT_FILENO); - if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) + redirected_stdout = dup(fileno(s->fp)); + if (saved_stdout < 0 || dup2(redirected_stdout, STDOUT_FILENO) < 0) die("couldn't redirect stdout\n"); + close(redirected_stdout); init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->reference); From 28456eeb0e887f87d6029fd49d7b4ad1e04b4e99 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 16 Dec 2007 23:01:37 +0100 Subject: [PATCH 358/781] Revert "Enhance the dup-dance in wt-status to work around t7502-commit.sh hang" This reverts commit 8f4e9dca13aba080505aa95897de2833b1f421d6. We'll instead take the solution from mingw/master with the next merge. --- wt-status.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wt-status.c b/wt-status.c index 0b8a73fd44..51c1879691 100644 --- a/wt-status.c +++ b/wt-status.c @@ -321,17 +321,15 @@ static void wt_status_print_untracked(struct wt_status *s) static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; - int saved_stdout, redirected_stdout; + int saved_stdout; fflush(s->fp); /* Sigh, the entire diff machinery is hardcoded to output to * stdout. Do the dup-dance...*/ saved_stdout = dup(STDOUT_FILENO); - redirected_stdout = dup(fileno(s->fp)); - if (saved_stdout < 0 || dup2(redirected_stdout, STDOUT_FILENO) < 0) + if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) die("couldn't redirect stdout\n"); - close(redirected_stdout); init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->reference); From 5877600179068559e592bc0ab907e47fff26dcaa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 24 May 2007 10:54:08 +0200 Subject: [PATCH 359/781] MSYS: local clone must use the drive letter in absolute paths. The default of pwd of MSYS's bash and /bin/pwd are to use /c/rest/of/path notation instead of c:/rest/of/path. But the former is not supported by programs that use the standard C runtime (instead of MSYS's runtime). Hence, we must make sure that only drive letter notations are generated by using pwd's -W option. Signed-off-by: Johannes Sixt --- git-clone.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/git-clone.sh b/git-clone.sh index 557c72f127..b62fd24d21 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -66,6 +66,19 @@ case $(uname -s) in xargs --no-run-if-empty \ cp $cp_arg --target-directory="$2" --parents } + # pwd must return a path with a drive letter + bin_pwd() { + # there are no symlinks to resolve: /bin/pwd is not needed + builtin pwd -W + } + pwd() { + builtin pwd -W + } + ;; +*) + bin_pwd() { + /bin/pwd + } ;; esac @@ -77,11 +90,11 @@ eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?) get_repo_base() { ( - cd "`/bin/pwd -W`" && + cd "$(bin_pwd)" && cd "$1" || cd "$1.git" && { cd .git - pwd -W + pwd } ) 2>/dev/null } From 40c7f8a61c569cef9caf258c8c1d2663627384d3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 26 Dec 2007 20:35:45 +0100 Subject: [PATCH 360/781] Revert "Strip \r from the input." This reverts commit 5bc08ee66f49beedb5327446ff147e92345df65c, which is no longer needed since git-ls-remote is built-in. --- builtin-fmt-merge-msg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index c7de27c849..6163bd4975 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -95,8 +95,6 @@ static int handle_line(char *line) return 3; if (line[len - 1] == '\n') - line[len - 1] = 0, --len; - if (line[len - 1] == '\r') line[len - 1] = 0; line += 42; From 301de2ab75f77c4be6f3d83ff2b4201b6b3bd25c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 16 Dec 2007 22:46:49 +0100 Subject: [PATCH 361/781] help (mingw): Cleaned up whitespace indentation The separate block for the ShellExecute code is no longer needed and therefore cleand up. Also included is minor rewording of the error message if the HTML page is not found. Signed-off-by: Steffen Prohaska --- help.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/help.c b/help.c index dcb6a3f6c5..146d131820 100644 --- a/help.c +++ b/help.c @@ -336,28 +336,26 @@ static void show_info_page(const char *git_cmd) static void show_html_page(const char *git_cmd) { #ifdef __MINGW32__ - { - const char* exec_path = git_exec_path(); - char *htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/%s.html" - , exec_path - , git_cmd) - ); + const char* exec_path = git_exec_path(); + char *htmlpath = make_native_separator( + mkpath("%s/../doc/git/html/%s.html" + , exec_path + , git_cmd) + ); + if (!file_exists(htmlpath)) { + htmlpath = make_native_separator( + mkpath("%s/../doc/git/html/git-%s.html" + , exec_path + , git_cmd) + ); if (!file_exists(htmlpath)) { - htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/git-%s.html" - , exec_path - , git_cmd) - ); - if (!file_exists(htmlpath)) { - fprintf(stderr, "Can't find help for '%s'.\n" - , git_cmd); - exit(1); - } + fprintf(stderr, "Can't find HTML help for '%s'.\n" + , git_cmd); + exit(1); } - printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } + printf("Launching default browser to display HTML help ...\n"); + ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); #else const char *page = cmd_to_page(git_cmd); execl_git_cmd("help--browse", page, NULL); From bc8e453867b6ae950ae4333647f7f5e368ba7b15 Mon Sep 17 00:00:00 2001 From: Brian Downing Date: Fri, 16 Nov 2007 22:28:13 -0600 Subject: [PATCH 362/781] mingw-compat: Add simplified merge sort implementation from glibc qsort in Windows 2000 (and possibly other older Windows' C libraries) is a Quicksort with the usual O(n^2) worst case. Unfortunately, sorting Git trees seems to get very close to that worst case quite often: $ /git/gitbad runstatus # On branch master qsort, nmemb = 30842 done, 237838087 comparisons. This patch adds a simplified version of the merge sort that is glibc's qsort(3). As a merge sort, this needs a temporary array equal in size to the array that is to be sorted. The complexity that was removed is: * Doing direct stores for word-size and -aligned data. * Falling back to quicksort if the allocation required to perform the merge sort would likely push the machine into swap. Even with these simplifications, this seems to outperform the Windows qsort(3) implementation, even in Windows XP (where it is "fixed" and doesn't trigger O(n^2) complexity on trees). [jes: moved into compat/qsort.c, as per Johannes Sixt's suggestion] Signed-off-by: Brian Downing Signed-off-by: Steffen Prohaska Signed-off-by: Johannes Schindelin --- Makefile | 8 +++++++ compat/qsort.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 6 +++++ 3 files changed, 74 insertions(+) create mode 100644 compat/qsort.c diff --git a/Makefile b/Makefile index a40e71c30d..448a22e123 100644 --- a/Makefile +++ b/Makefile @@ -136,6 +136,9 @@ all:: # Define THREADED_DELTA_SEARCH if you have pthreads and wish to exploit # parallel delta searching when packing objects. # +# Define NEEDS_QUICK_QSORT if your qsort() implementation has O(n^2) +# worst case complexity. +# GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @"$(SHELL_PATH)" ./GIT-VERSION-GEN @@ -523,6 +526,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_R_TO_GCC_LINKER = YesPlease + NEEDS_QUICK_QSORT = YesPlease NO_EXTRA_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -741,6 +745,10 @@ ifdef NO_MEMMEM COMPAT_CFLAGS += -DNO_MEMMEM COMPAT_OBJS += compat/memmem.o endif +ifdef NEEDS_QUICK_QSORT + COMPAT_CFLAGS += -DNEEDS_QUICK_QSORT + COMPAT_OBJS += compat/qsort.o +endif ifdef THREADED_DELTA_SEARCH BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH diff --git a/compat/qsort.c b/compat/qsort.c new file mode 100644 index 0000000000..734866e5bc --- /dev/null +++ b/compat/qsort.c @@ -0,0 +1,60 @@ +#include "../git-compat-util.h" + +/* This merge sort implementation is simplified from glibc's. */ +static void msort_with_tmp(void *b, size_t n, size_t s, + int (*cmp)(const void *, const void *), + char *t) +{ + char *tmp; + char *b1, *b2; + size_t n1, n2; + + if (n <= 1) + return; + + n1 = n / 2; + n2 = n - n1; + b1 = b; + b2 = (char *)b + (n1 * s); + + msort_with_tmp(b1, n1, s, cmp, t); + msort_with_tmp(b2, n2, s, cmp, t); + + tmp = t; + + while (n1 > 0 && n2 > 0) { + if (cmp(b1, b2) <= 0) { + memcpy(tmp, b1, s); + tmp += s; + b1 += s; + --n1; + } else { + memcpy(tmp, b2, s); + tmp += s; + b2 += s; + --n2; + } + } + if (n1 > 0) + memcpy(tmp, b1, n1 * s); + memcpy(b, t, (n - n2) * s); +} + +void git_qsort(void *b, size_t n, size_t s, + int (*cmp)(const void *, const void *)) +{ + const size_t size = n * s; + + if (size < 1024) { + char buf[size]; /* gcc-ism */ + + /* The temporary array is small, so put it on + the stack. */ + msort_with_tmp(b, n, s, cmp, buf); + } else { + /* It's somewhat large, so malloc it. */ + char *tmp = malloc(size); + msort_with_tmp(b, n, s, cmp, tmp); + free(tmp); + } +} diff --git a/git-compat-util.h b/git-compat-util.h index 5a81bc9e76..0f92d1d570 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -645,4 +645,10 @@ extern __attribute__((noreturn)) int git_exit(int code); #endif /* __MINGW32__ */ +#ifdef NEEDS_QUICK_QSORT +void git_qsort(void *base, size_t nmemb, size_t size, + int(*compar)(const void *, const void *)); +#define qsort git_qsort +#endif + #endif From d3f72ce4f0c2d5aac2e27df4e866dac628994b2d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 1 Jan 2008 22:15:21 +0100 Subject: [PATCH 363/781] When installing, be prepared that template_dir may be relative. Since the Makefile in the template/ subdirectory is only used to install the templates, we do not simply pass down the setting of template_dir when it is relative, but construct the intended destination in a new variable: A relative template_dir is relative to gitexecdir. Signed-off-by: Johannes Sixt --- Makefile | 9 ++++++++- templates/Makefile | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 0029b5032a..3ad839eaa4 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ GITWEB_FAVICON = git-favicon.png GITWEB_SITE_HEADER = GITWEB_SITE_FOOTER = -export prefix bindir gitexecdir sharedir template_dir htmldir sysconfdir +export prefix bindir gitexecdir sharedir htmldir sysconfdir CC = gcc AR = ar @@ -1061,6 +1061,13 @@ remove-dashes: ### Installation rules +ifeq ($(firstword $(subst /, ,$(template_dir))),..) +template_instdir = $(gitexecdir)/$(template_dir) +else +template_instdir = $template_dir +endif +export template_instdir + install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' diff --git a/templates/Makefile b/templates/Makefile index e274eb3efa..0ed2f35003 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -8,14 +8,14 @@ INSTALL ?= install TAR ?= tar RM ?= rm -f prefix ?= $(HOME) -template_dir = $(prefix)/share/git-core/templates +template_instdir ?= $(prefix)/share/git-core/templates # DESTDIR= # set NOEXECTEMPL to non-empty to change the names of hook scripts # so that the tools will not find them # Shell quote (do not use $(call) to accommodate ancient setups); DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) -template_dir_SQ = $(subst ','\'',$(template_dir)) +template_instdir_SQ = $(subst ','\'',$(template_instdir)) all: boilerplates.made custom @@ -52,6 +52,6 @@ clean: $(RM) -r blt boilerplates.made install: all - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_dir_SQ)' + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_instdir_SQ)' (cd blt && $(TAR) cf - .) | \ - (cd '$(DESTDIR_SQ)$(template_dir_SQ)' && $(TAR) xf -) + (cd '$(DESTDIR_SQ)$(template_instdir_SQ)' && $(TAR) xf -) From 4c8f8c86e11caa7a1cb1c035a9181ed31ffb253e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 12 Jan 2008 20:42:55 +0100 Subject: [PATCH 364/781] gitk: Disable msgfmt on MinGW. This auto-detects whether the build takes place for the MinGW port, which does not have msgfmt. Signed-off-by: Johannes Sixt --- gitk-git/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gitk-git/Makefile b/gitk-git/Makefile index ae2b80b108..a25e5a12a1 100644 --- a/gitk-git/Makefile +++ b/gitk-git/Makefile @@ -18,6 +18,10 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) ## po-file creation rules XGETTEXT ?= xgettext +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +ifneq (,$(findstring MINGW,$(uname_S))) + NO_MSGFMT=1 +endif ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else From 9b4b9da619e4bcb25eb581ddb73ff628cc97ac95 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 14 Jan 2008 13:03:34 +0100 Subject: [PATCH 365/781] Windows: Fix path separator of GIT_ALTERNATE_OBJECT_DIRECTORIES. For consistency and technical reasons on Windows (':' is usually part of directory names), we must use ';' as path separator. Signed-off-by: Johannes Sixt --- Documentation/git.txt | 6 +++--- sha1_file.c | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index 4ece40d1eb..6e0540d0e6 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -375,9 +375,9 @@ git so take care if using Cogito etc. 'GIT_ALTERNATE_OBJECT_DIRECTORIES':: Due to the immutable nature of git objects, old objects can be archived into shared, read-only directories. This variable - specifies a ":" separated list of git object directories which - can be used to search for git objects. New objects will not be - written to these directories. + specifies a ":" separated (on Windows ";" separated) list + of git object directories which can be used to search for git + objects. New objects will not be written to these directories. 'GIT_DIR':: If the 'GIT_DIR' environment variable is set then it diff --git a/sha1_file.c b/sha1_file.c index 08cebe1fae..93a34271e6 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -395,7 +395,11 @@ void prepare_alt_odb(void) if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; +#ifdef __MINGW32__ + link_alt_odb_entries(alt, alt + strlen(alt), ';', NULL, 0); +#else link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0); +#endif read_info_alternates(get_object_directory(), 0); } From dfd188ababfd634c4cc2a18f6ed38c3829e5058c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 14 Jan 2008 14:05:33 +0100 Subject: [PATCH 366/781] Windows: Make 'git help -a' work. git help -a scans the PATH for git commands. On Windows it failed for two reasons: - The PATH separator is ';', not ':' on Windows. - stat() does not set the executabe bit. We now open the file and guess whether it is executable. The result of the guess is good enough for the list of git commands, but it is of no use for a general stat() implementation because (1) it is a guess, (2) the user has no way to influence the outcome (via chmod or similar), and (3) it would reduce stat() performance by an unacceptable amount. Therefore, this strategy is a special-case local to help.c. Signed-off-by: Johannes Sixt --- help.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/help.c b/help.c index 1302a61c83..15a67dec35 100644 --- a/help.c +++ b/help.c @@ -165,6 +165,32 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest) } } +static int is_executable(const char *name) +{ + struct stat st; + + if (stat(name, &st) || /* stat, not lstat */ + !S_ISREG(st.st_mode)) + return 0; + +#ifdef __MINGW32__ + /* cannot trust the executable bit, peek into the file instead */ + char buf[3] = { 0 }; + int n; + int fd = open(name, O_RDONLY); + st.st_mode &= ~S_IXUSR; + if (fd >= 0) { + n = read(fd, buf, 2); + if (n == 2) + /* DOS executables start with "MZ" */ + if (!strcmp(buf, "#!") || !strcmp(buf, "MZ")) + st.st_mode |= S_IXUSR; + close(fd); + } +#endif + return st.st_mode & S_IXUSR; +} + static unsigned int list_commands_in_dir(struct cmdnames *cmds, const char *path) { @@ -178,15 +204,12 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds, return 0; while ((de = readdir(dir)) != NULL) { - struct stat st; int entlen; if (prefixcmp(de->d_name, prefix)) continue; - if (stat(de->d_name, &st) || /* stat, not lstat */ - !S_ISREG(st.st_mode) || - !(st.st_mode & S_IXUSR)) + if (!is_executable(de->d_name)) continue; entlen = strlen(de->d_name) - prefix_len; @@ -210,6 +233,11 @@ static void list_commands(void) const char *env_path = getenv("PATH"); char *paths, *path, *colon; const char *exec_path = git_exec_path(); +#ifdef __MINGW32__ + char sep = ';'; +#else + char sep = ':'; +#endif if (exec_path) longest = list_commands_in_dir(&main_cmds, exec_path); @@ -221,7 +249,7 @@ static void list_commands(void) path = paths = xstrdup(env_path); while (1) { - if ((colon = strchr(path, ':'))) + if ((colon = strchr(path, sep))) *colon = 0; len = list_commands_in_dir(&other_cmds, path); From aeb782846ebff9c3c8abf835ab7406e2a5a685ae Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 29 Jan 2008 06:45:36 +0100 Subject: [PATCH 367/781] t5520: Skip '--rebase rebased upstream' on msys (remote doesn't work) We know that git remote does not work in t/. Therefore, we skip this test. Signed-off-by: Steffen Prohaska --- t/t5520-pull.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 9484129ca5..ca83768e05 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -76,6 +76,7 @@ test_expect_success 'branch.to-rebase.rebase' ' test new = $(git show HEAD:file2) ' +say "Remote does not work in t/ - skipping." || test_expect_success '--rebase with rebased upstream' ' git remote add -f me . && From aca4f38d924e0e82f9870babe73c8ada63aadae3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 7 Feb 2008 21:23:32 +0100 Subject: [PATCH 368/781] Revert "Implement a cpio emulation in git-merge.sh for Windows." This reverts commit 8b9de093190e6b1d6066efaf4afd9dc988096987. git-merge does not use cpio anymore. --- git-merge.sh | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/git-merge.sh b/git-merge.sh index ca7cb30d6c..1c123a37e6 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -38,24 +38,6 @@ use_strategies= allow_fast_forward=t allow_trivial_merge=t -# Fix some commands on Windows -case $(uname -s) in -*MINGW*) - # there's no cpio; emulate with tar - cpio () { - case "$*" in - "-0 -o") - tar --create --file=- --null --files-from=- - ;; - "-iuv") - tar xvf - - ;; - *) die "internal error: unexpected cpio $*";; - esac - } - ;; -esac - dropsave() { rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \ "$GIT_DIR/MERGE_STASH" || exit 1 From 304601534df0b1eeee0865d55bb3b4da063702e3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 19 Feb 2008 22:11:12 +0100 Subject: [PATCH 369/781] prefix_path: use is_absolute_path() instead of *orig == '/' Signed-off-by: Johannes Sixt --- setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.c b/setup.c index 5e4cecb893..18ddfae04f 100644 --- a/setup.c +++ b/setup.c @@ -91,7 +91,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; char *sanitized = xmalloc(len + strlen(path) + 1); - if (*orig == '/') + if (is_absolute_path(orig)) strcpy(sanitized, path); else { if (len) @@ -100,7 +100,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) } if (sanitary_path_copy(sanitized, sanitized)) goto error_out; - if (*orig == '/') { + if (is_absolute_path(orig)) { const char *work_tree = get_git_work_tree(); size_t len = strlen(work_tree); size_t total = strlen(sanitized) + 1; From 6b17197be450fd67d3fde7208bbb1ea0160b73f9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 19 Feb 2008 22:15:17 +0100 Subject: [PATCH 370/781] Windows: convert '\\' to '/' in sanitary_path_copy(). sanitary_path_copy() is only used by prefix_path(). A helper function is_dir_sep() is introduced that checks for both '/' and '\\' on Windows. Note that the remaining checks for '/' in prefix_path() don't need to to be converted to is_dir_sep() since they operate on the sanitized path. Signed-off-by: Johannes Sixt --- setup.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/setup.c b/setup.c index 18ddfae04f..b80653c32b 100644 --- a/setup.c +++ b/setup.c @@ -4,13 +4,26 @@ static int inside_git_dir = -1; static int inside_work_tree = -1; +#ifdef __MINGW32__ +static inline int is_dir_sep(char c) { return c == '/' || c == '\\'; } +#else +static inline int is_dir_sep(char c) { return c == '/'; } +#endif + static int sanitary_path_copy(char *dst, const char *src) { char *dst0 = dst; - if (*src == '/') { +#ifdef __MINGW32__ + if (isalpha(*src) && src[1] == ':') { + src += 2; + dst += 2; + dst0 += 2; + } +#endif + if (is_dir_sep(*src)) { *dst++ = '/'; - while (*src == '/') + while (is_dir_sep(*src)) src++; } @@ -32,9 +45,12 @@ static int sanitary_path_copy(char *dst, const char *src) src++; break; case '/': +#ifdef __MINGW32__ + case '\\': +#endif /* (2) */ src += 2; - while (*src == '/') + while (is_dir_sep(*src)) src++; continue; case '.': @@ -44,9 +60,12 @@ static int sanitary_path_copy(char *dst, const char *src) src += 2; goto up_one; case '/': +#ifdef __MINGW32__ + case '\\': +#endif /* (4) */ src += 3; - while (*src == '/') + while (is_dir_sep(*src)) src++; goto up_one; } @@ -54,11 +73,11 @@ static int sanitary_path_copy(char *dst, const char *src) } /* copy up to the next '/', and eat all '/' */ - while ((c = *src++) != '\0' && c != '/') + while ((c = *src++) != '\0' && !is_dir_sep(c)) *dst++ = c; - if (c == '/') { - *dst++ = c; - while (c == '/') + if (is_dir_sep(c)) { + *dst++ = '/'; + while (is_dir_sep(c)) c = *src++; src--; } else if (!c) @@ -77,7 +96,7 @@ static int sanitary_path_copy(char *dst, const char *src) if (dst <= dst0) break; c = *dst--; - if (c == '/') { + if (c == '/') { /* MinGW: cannot be '\\' anymore */ dst += 2; break; } From a0e491d36a4bf1c19b68be90d82f79a3da95b2f0 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 24 Feb 2008 16:01:14 +0100 Subject: [PATCH 371/781] Makefile(msysgit): Do no longer set symlinks=false during installation We track /etc/gitconfig in msysgit and therefore do no longer need to set symlinks=false during installation. This commit removes the unnecessary command from the install target and thus reduces the differences to official git's Makefile. Signed-off-by: Steffen Prohaska --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 1272b474b4..1b6081782d 100644 --- a/Makefile +++ b/Makefile @@ -1111,8 +1111,6 @@ install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)' - GIT_CONFIG='$(DESTDIR_SQ)$(sysconfdir_SQ)/gitconfig' \ - $(DESTDIR_SQ)$(bindir_SQ)/git$X config core.symlinks false $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install ifndef NO_TCLTK From dbe5a3424bb8ff239b896ab0e888ef402dffa915 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 24 Feb 2008 17:01:54 +0100 Subject: [PATCH 372/781] Skip t9500 because we do not support gitweb in msysgit. Signed-off-by: Steffen Prohaska --- t/t9500-gitweb-standalone-no-errors.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 796cd7dba0..72d8e74927 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -68,6 +68,9 @@ safe_chmod () { . ./test-lib.sh +say 'gitweb not supported, skipping tests.' +test_done + perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { test_expect_success 'skipping gitweb tests, perl version is too old' : test_done From d4af30b7c7a9060246fe9d77a9747ed5fa99653b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 24 Feb 2008 17:35:39 +0100 Subject: [PATCH 373/781] Fix sanitary_path_copy() for absolute Windows style paths. We recognized the drive letter and colon, but we did not copy them. So far this was not a problem since the only call site used the same pointer for source and destination. But better safe than sorry. Signed-off-by: Johannes Sixt --- setup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.c b/setup.c index b80653c32b..77cc461bd2 100644 --- a/setup.c +++ b/setup.c @@ -16,9 +16,9 @@ static int sanitary_path_copy(char *dst, const char *src) #ifdef __MINGW32__ if (isalpha(*src) && src[1] == ':') { - src += 2; - dst += 2; - dst0 += 2; + *dst++ = *src++; + *dst++ = *src++; + dst0 = dst; } #endif if (is_dir_sep(*src)) { From 792d7e9b0ef778c33d7b1f58d85c17eb7da24a3c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Feb 2008 10:42:01 +0100 Subject: [PATCH 374/781] A bit of comment and whitespace cleanup in compat/mingw.c. Signed-off-by: Johannes Sixt --- compat/mingw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 8bbe21bb67..0888288b5c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -315,12 +315,14 @@ repeat: struct tm *gmtime_r(const time_t *timep, struct tm *result) { + /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */ memcpy(result, gmtime(timep), sizeof(struct tm)); return result; } struct tm *localtime_r(const time_t *timep, struct tm *result) { + /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */ memcpy(result, localtime(timep), sizeof(struct tm)); return result; } @@ -778,7 +780,7 @@ char **env_setenv(char **env, const char *name) } /* this is the first function to call into WS_32; initialize it */ -#undef gethostbyname +#undef gethostbyname struct hostent *mingw_gethostbyname(const char *host) { WSADATA wsa; @@ -911,7 +913,7 @@ static sig_handler_t timer_fn = SIG_DFL; * wait state every now and then, namely exactly after timer's interval * length. At these opportunities it calls the signal handler. */ - + static __stdcall unsigned ticktack(void *dummy) { while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { From bdb6d4ec8eaac4d01ace50bd521c79f8d4b2d8d5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Feb 2008 10:42:54 +0100 Subject: [PATCH 375/781] Replace head -1 | grep by sed. Signed-off-by: Johannes Sixt --- templates/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/Makefile b/templates/Makefile index 0ed2f35003..eb0870235d 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -34,10 +34,10 @@ boilerplates.made : $(bpsrc) mkdir -p blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - *) if head -1 $$boilerplate | grep -q '^#!/'; then \ - cp $$boilerplate blt/$${dst}$(NOEXECTEMPL); \ + *) if test -n "$$(sed -ne '/^#!\//p' -e '1q' < "$$boilerplate")"; then \ + cp "$$boilerplate" "blt/$${dst}$(NOEXECTEMPL)"; \ else \ - cp $$boilerplate blt/$$dst; \ + cp "$$boilerplate" "blt/$$dst"; \ fi ;; \ esac || exit; \ done && \ From 43d0446323028d7879167a2d3a3c71b4ec2b8a90 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Feb 2008 10:43:45 +0100 Subject: [PATCH 376/781] Send stderr of commands to the pager. This is a follow-up to 61b80509e3323c262ed5c45d5340cfa278521a71. Signed-off-by: Johannes Sixt --- pager.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pager.c b/pager.c index bcb3d7f69d..3f7f8c123e 100644 --- a/pager.c +++ b/pager.c @@ -34,7 +34,10 @@ static struct child_process pager_process = { static void wait_for_pager(void) { fflush(stdout); - close(1); /* signals EOF to pager */ + fflush(stderr); + /* signal EOF to pager */ + close(1); + close(2); finish_command(&pager_process); } #endif @@ -99,6 +102,7 @@ void setup_pager(void) /* original process continues, but writes to the pipe */ dup2(pager_process.in, 1); + dup2(pager_process.in, 2); close(pager_process.in); /* this makes sure that the parent terminates after the pager */ From 3031522444582ac57f851986774ca79560acc33b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 2 Mar 2008 21:54:30 +0100 Subject: [PATCH 377/781] Introduce has_dos_drive_prefix() and use it. This function tests whether there is a C: style prefix in the argument. It returns always 0 on Unix. With this functions a number of conditionals #ifdef __MINGW32__/#endif can be removed. The getcwd() replacement was simplified: It tried to elide the translation of backslashes to slashes if there was no drive prfix, but this optimization is wrong: We could be looking at an UNC path, which we also want to translate. Signed-off-by: Johannes Sixt --- cache.h | 6 +----- compat/mingw.c | 11 ++++------- connect.c | 8 +------- git-compat-util.h | 12 ++++++++++++ setup.c | 4 +--- sha1_file.c | 4 +--- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/cache.h b/cache.h index e17bb6f4f5..53b4e44873 100644 --- a/cache.h +++ b/cache.h @@ -484,11 +484,7 @@ int safe_create_leading_directories(char *path); char *enter_repo(char *path, int strict); static inline int is_absolute_path(const char *path) { -#ifndef __MINGW32__ - return path[0] == '/'; -#else - return path[0] == '/' || (path[0] && path[1] == ':'); -#endif + return path[0] == '/' || has_dos_drive_prefix(path); } const char *make_absolute_path(const char *path); diff --git a/compat/mingw.c b/compat/mingw.c index 0888288b5c..6733727380 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -330,16 +330,13 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) #undef getcwd char *mingw_getcwd(char *pointer, int len) { + int i; char *ret = getcwd(pointer, len); if (!ret) return ret; - if (pointer[0] != 0 && pointer[1] == ':') { - int i; - for (i = 2; pointer[i]; i++) - /* Thanks, Bill. You'll burn in hell for that. */ - if (pointer[i] == '\\') - pointer[i] = '/'; - } + for (i = 0; pointer[i]; i++) + if (pointer[i] == '\\') + pointer[i] = '/'; return ret; } diff --git a/connect.c b/connect.c index 92a2829f04..8d600c9ddf 100644 --- a/connect.c +++ b/connect.c @@ -528,13 +528,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, end = host; path = strchr(end, c); -#ifdef __MINGW32__ - /* host must have at least 2 chars to catch DOS C:/path */ - if (path && path - end > 1) -#else - if (path) -#endif - { + if (path && !has_dos_drive_prefix(end)) { if (c == ':') { protocol = PROTO_SSH; *path++ = '\0'; diff --git a/git-compat-util.h b/git-compat-util.h index 4a8df8e038..e9fcffd125 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -650,6 +650,18 @@ char **copy_environ(void); void free_environ(char **env); char **env_setenv(char **env, const char *name); +static inline int has_dos_drive_prefix(const char *path) +{ + return isalpha(*path) && path[1] == ':'; +} + +#else /* __MINGW32__ */ + +static inline int has_dos_drive_prefix(const char *path) +{ + return 0; +} + #endif /* __MINGW32__ */ #endif diff --git a/setup.c b/setup.c index e2e2e21d15..d184d4d5e5 100644 --- a/setup.c +++ b/setup.c @@ -397,10 +397,8 @@ const char *setup_git_directory_gently(int *nongit_ok) if (!getcwd(cwd, sizeof(cwd)-1)) die("Unable to read current working directory"); -#ifdef __MINGW32__ - if (cwd[1] == ':') + if (has_dos_drive_prefix(cwd)) minoffset = 2; -#endif /* * Test in the following order (relative to the cwd): diff --git a/sha1_file.c b/sha1_file.c index 0c608492c7..9a7fac9d5b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -85,10 +85,8 @@ int get_sha1_hex(const char *hex, unsigned char *sha1) static inline int offset_1st_component(const char *path) { -#ifdef __MINGW32__ - if (isalpha(path[0]) && path[1] == ':') + if (has_dos_drive_prefix(path)) return 2 + (path[2] == '/'); -#endif return *path == '/'; } From 7e9987da41172f831f2d900f0304f05d0543319a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 2 Mar 2008 21:56:47 +0100 Subject: [PATCH 378/781] Fix clone from bundle if the URL is actually an absolute Windows path. This URL was mistaken as an SSH connection. Signed-off-by: Johannes Sixt --- transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/transport.c b/transport.c index 0a5cf0a9c2..74fa9eef28 100644 --- a/transport.c +++ b/transport.c @@ -693,7 +693,8 @@ static int is_local(const char *url) { const char *colon = strchr(url, ':'); const char *slash = strchr(url, '/'); - return !colon || (slash && slash < colon); + return !colon || (slash && slash < colon) || + has_dos_drive_prefix(url); } static int is_file(const char *url) From 74ea7c5841045e5a66715f705748d9f0f275245b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:45:26 +0100 Subject: [PATCH 379/781] Move MinGW specific code from git-compat-util.h to compat/mingw.h. This was proposed by Dscho, and I agree it makes sense because it really clutters git-compat-util.h. This is the first step of this cleanup and is a mere code move. Signed-off-by: Johannes Sixt --- Makefile | 2 +- compat/mingw.h | 196 +++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 197 +--------------------------------------------- 3 files changed, 198 insertions(+), 197 deletions(-) create mode 100644 compat/mingw.h diff --git a/Makefile b/Makefile index b7627587c1..cb64a43091 100644 --- a/Makefile +++ b/Makefile @@ -308,7 +308,7 @@ LIB_H = \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h ll-merge.h fsck.h \ - pack-revindex.h + pack-revindex.h compat/mingw.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ diff --git a/compat/mingw.h b/compat/mingw.h new file mode 100644 index 0000000000..50973bc193 --- /dev/null +++ b/compat/mingw.h @@ -0,0 +1,196 @@ +#include + +/* + * things that are not available in header files + */ + +typedef int pid_t; +#define hstrerror strerror + +#define S_IFLNK 0120000 /* Symbolic link */ +#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(x) 0 +#define S_IRGRP 0 +#define S_IWGRP 0 +#define S_IXGRP 0 +#define S_ISGID 0 +#define S_IROTH 0 +#define S_IXOTH 0 + +#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ +#define WEXITSTATUS(x) ((x) & 0xff) +#define WIFSIGNALED(x) ((unsigned)(x) > 259) + +#define SIGKILL 0 +#define SIGCHLD 0 +#define SIGPIPE 0 +#define SIGALRM 100 + +#define F_GETFD 1 +#define F_SETFD 2 +#define FD_CLOEXEC 0x1 + +struct passwd { + char *pw_name; + char *pw_gecos; + char *pw_dir; +}; + +struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; +#define POLLIN 1 +#define POLLHUP 2 + +typedef void (__cdecl *sig_handler_t)(int); +struct sigaction { + sig_handler_t sa_handler; + unsigned sa_flags; +}; +#define sigemptyset(x) (void)0 +#define SA_RESTART 0 + +struct itimerval { + struct timeval it_value, it_interval; +}; +#define ITIMER_REAL 0 + +/* + * trivial stubs + */ + +static inline int readlink(const char *path, char *buf, size_t bufsiz) +{ errno = ENOSYS; return -1; } +static inline int symlink(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int link(const char *oldpath, const char *newpath) +{ errno = ENOSYS; return -1; } +static inline int fchmod(int fildes, mode_t mode) +{ errno = ENOSYS; return -1; } +static inline int fork(void) +{ errno = ENOSYS; return -1; } +static inline unsigned int alarm(unsigned int seconds) +{ return 0; } +static inline int fsync(int fd) +{ return 0; } +static inline int getppid(void) +{ return 1; } +static inline void sync(void) +{} +static inline int getuid() +{ return 1; } +static inline struct passwd *getpwnam(const char *name) +{ return NULL; } +static inline int fcntl(int fd, int cmd, long arg) +{ + if (cmd == F_GETFD || cmd == F_SETFD) + return 0; + errno = EINVAL; + return -1; +} + +/* + * simple adaptors + */ + +static inline int mingw_mkdir(const char *path, int mode) +{ + return mkdir(path); +} +#define mkdir mingw_mkdir + +static inline int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} +#define unlink mingw_unlink + +static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +{ + if (options == 0) + return _cwait(status, pid, 0); + errno = EINVAL; + return -1; +} + +/* + * implementations of missing functions + */ + +int pipe(int filedes[2]); +unsigned int sleep (unsigned int seconds); +int gettimeofday(struct timeval *tv, void *tz); +int poll(struct pollfd *ufds, unsigned int nfds, int timeout); +struct tm *gmtime_r(const time_t *timep, struct tm *result); +struct tm *localtime_r(const time_t *timep, struct tm *result); +int getpagesize(void); /* defined in MinGW's libgcc.a */ +struct passwd *getpwuid(int uid); +int setitimer(int type, struct itimerval *in, struct itimerval *out); +int sigaction(int sig, struct sigaction *in, struct sigaction *out); + +/* + * replacements of existing functions + */ + +int mingw_open (const char *filename, int oflags, ...); +#define open mingw_open + +char *mingw_getcwd(char *pointer, int len); +#define getcwd mingw_getcwd + +struct hostent *mingw_gethostbyname(const char *host); +#define gethostbyname mingw_gethostbyname + +int mingw_socket(int domain, int type, int protocol); +#define socket mingw_socket + +int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); +#define connect mingw_connect + +int mingw_rename(const char*, const char*); +#define rename mingw_rename + +/* Use mingw_lstat() instead of lstat()/stat() and + * mingw_fstat() instead of fstat() on Windows. + * struct stat is redefined because it lacks the st_blocks member. + */ +struct mingw_stat { + unsigned st_mode; + time_t st_mtime, st_atime, st_ctime; + unsigned st_dev, st_ino, st_uid, st_gid; + size_t st_size; + size_t st_blocks; +}; +int mingw_lstat(const char *file_name, struct mingw_stat *buf); +int mingw_fstat(int fd, struct mingw_stat *buf); +#define fstat mingw_fstat +#define lstat mingw_lstat +#define stat mingw_stat +static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) +{ return mingw_lstat(file_name, buf); } + +int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); +#define vsnprintf mingw_vsnprintf + +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); +void mingw_execvp(const char *cmd, char *const *argv); +#define execvp mingw_execvp + +static inline unsigned int git_ntohl(unsigned int x) +{ return (unsigned int)ntohl(x); } +#define ntohl git_ntohl + +sig_handler_t mingw_signal(int sig, sig_handler_t handler); +#define signal mingw_signal + +/* + * helpers + */ + +char **copy_environ(void); +void free_environ(char **env); +char **env_setenv(char **env, const char *name); diff --git a/git-compat-util.h b/git-compat-util.h index 2daec68c6c..6d22739eac 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -468,202 +468,7 @@ void git_qsort(void *base, size_t nmemb, size_t size, #ifdef __MINGW32__ -#include - -/* - * things that are not available in header files - */ - -typedef int pid_t; -#define hstrerror strerror - -#define S_IFLNK 0120000 /* Symbolic link */ -#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) -#define S_ISSOCK(x) 0 -#define S_IRGRP 0 -#define S_IWGRP 0 -#define S_IXGRP 0 -#define S_ISGID 0 -#define S_IROTH 0 -#define S_IXOTH 0 - -#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */ -#define WEXITSTATUS(x) ((x) & 0xff) -#define WIFSIGNALED(x) ((unsigned)(x) > 259) - -#define SIGKILL 0 -#define SIGCHLD 0 -#define SIGPIPE 0 -#define SIGALRM 100 - -#define F_GETFD 1 -#define F_SETFD 2 -#define FD_CLOEXEC 0x1 - -struct passwd { - char *pw_name; - char *pw_gecos; - char *pw_dir; -}; - -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; -#define POLLIN 1 -#define POLLHUP 2 - -typedef void (__cdecl *sig_handler_t)(int); -struct sigaction { - sig_handler_t sa_handler; - unsigned sa_flags; -}; -#define sigemptyset(x) (void)0 -#define SA_RESTART 0 - -struct itimerval { - struct timeval it_value, it_interval; -}; -#define ITIMER_REAL 0 - -/* - * trivial stubs - */ - -static inline int readlink(const char *path, char *buf, size_t bufsiz) -{ errno = ENOSYS; return -1; } -static inline int symlink(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } -static inline int link(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } -static inline int fchmod(int fildes, mode_t mode) -{ errno = ENOSYS; return -1; } -static inline int fork(void) -{ errno = ENOSYS; return -1; } -static inline unsigned int alarm(unsigned int seconds) -{ return 0; } -static inline int fsync(int fd) -{ return 0; } -static inline int getppid(void) -{ return 1; } -static inline void sync(void) -{} -static inline int getuid() -{ return 1; } -static inline struct passwd *getpwnam(const char *name) -{ return NULL; } -static inline int fcntl(int fd, int cmd, long arg) -{ - if (cmd == F_GETFD || cmd == F_SETFD) - return 0; - errno = EINVAL; - return -1; -} - -/* - * simple adaptors - */ - -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} -#define mkdir mingw_mkdir - -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - -static inline int waitpid(pid_t pid, unsigned *status, unsigned options) -{ - if (options == 0) - return _cwait(status, pid, 0); - errno = EINVAL; - return -1; -} - -/* - * implementations of missing functions - */ - -int pipe(int filedes[2]); -unsigned int sleep (unsigned int seconds); -int gettimeofday(struct timeval *tv, void *tz); -int poll(struct pollfd *ufds, unsigned int nfds, int timeout); -struct tm *gmtime_r(const time_t *timep, struct tm *result); -struct tm *localtime_r(const time_t *timep, struct tm *result); -int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); -int setitimer(int type, struct itimerval *in, struct itimerval *out); -int sigaction(int sig, struct sigaction *in, struct sigaction *out); - -/* - * replacements of existing functions - */ - -int mingw_open (const char *filename, int oflags, ...); -#define open mingw_open - -char *mingw_getcwd(char *pointer, int len); -#define getcwd mingw_getcwd - -struct hostent *mingw_gethostbyname(const char *host); -#define gethostbyname mingw_gethostbyname - -int mingw_socket(int domain, int type, int protocol); -#define socket mingw_socket - -int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); -#define connect mingw_connect - -int mingw_rename(const char*, const char*); -#define rename mingw_rename - -/* Use mingw_lstat() instead of lstat()/stat() and - * mingw_fstat() instead of fstat() on Windows. - * struct stat is redefined because it lacks the st_blocks member. - */ -struct mingw_stat { - unsigned st_mode; - time_t st_mtime, st_atime, st_ctime; - unsigned st_dev, st_ino, st_uid, st_gid; - size_t st_size; - size_t st_blocks; -}; -int mingw_lstat(const char *file_name, struct mingw_stat *buf); -int mingw_fstat(int fd, struct mingw_stat *buf); -#define fstat mingw_fstat -#define lstat mingw_lstat -#define stat mingw_stat -static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) -{ return mingw_lstat(file_name, buf); } - -int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); -#define vsnprintf mingw_vsnprintf - -pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); -void mingw_execvp(const char *cmd, char *const *argv); -#define execvp mingw_execvp - -static inline unsigned int git_ntohl(unsigned int x) -{ return (unsigned int)ntohl(x); } -#define ntohl git_ntohl - -sig_handler_t mingw_signal(int sig, sig_handler_t handler); -#define signal mingw_signal - -/* - * helpers - */ - -char **copy_environ(void); -void free_environ(char **env); -char **env_setenv(char **env, const char *name); +#include "compat/mingw.h" static inline int has_dos_drive_prefix(const char *path) { From 4bb6564bcb3fd7731af67c79ce443a60409b8d17 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:49:13 +0100 Subject: [PATCH 380/781] Do not abuse $(EXTRA_PROGRAMS). We don't want to compile some programs on Windows. There was already a Makefile variable EXTRA_PROGRAMS, which we used to achieve this. But this is not exactly self-explanatory. So we name the variable POSIX_ONLY_PROGRAMS and reinstate the old EXTRA_PROGRAMS. Signed-off-by: Johannes Sixt --- Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index cb64a43091..9023eff0bb 100644 --- a/Makefile +++ b/Makefile @@ -268,6 +268,7 @@ PROGRAMS = \ git-upload-pack$X \ git-pack-redundant$X git-var$X \ git-merge-tree$X \ + $(POSIX_ONLY_PROGRAMS) \ $(EXTRA_PROGRAMS) # Empty... @@ -551,7 +552,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_MKDTEMP = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease - NO_EXTRA_PROGRAMS = YesPlease + NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o @@ -621,8 +622,8 @@ ifdef ZLIB_PATH endif EXTLIBS += -lz -ifndef NO_EXTRA_PROGRAMS - EXTRA_PROGRAMS += \ +ifndef NO_POSIX_ONLY_PROGRAMS + POSIX_ONLY_PROGRAMS = \ git-daemon$X \ git-imap-send$X endif From 9ce71e6df09e4b215f639083edb28fadd12a1bf3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:52:54 +0100 Subject: [PATCH 381/781] Remove executable mode from compat/fnmatch.c Signed-off-by: Johannes Sixt --- compat/fnmatch.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 compat/fnmatch.c diff --git a/compat/fnmatch.c b/compat/fnmatch.c old mode 100755 new mode 100644 From e69e2c6838a84ced873e456e4a48c6d36d950a0e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 12:57:19 +0100 Subject: [PATCH 382/781] Include compat/mingw.h early in git-compat-util.h. By doing so we can make the rest of git-compat-util.h believe that some functionality is actually available. Signed-off-by: Johannes Sixt --- git-compat-util.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 6d22739eac..73b08397c9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -89,7 +89,10 @@ #include #define _ALL_SOURCE 1 #endif -#endif /* !__MINGW32__ */ +#else /* __MINGW32__ */ +/* pull in Windows compatibility stuff */ +#include "compat/mingw.h" +#endif /* __MINGW32__ */ #ifndef NO_ICONV #include @@ -468,8 +471,6 @@ void git_qsort(void *base, size_t nmemb, size_t size, #ifdef __MINGW32__ -#include "compat/mingw.h" - static inline int has_dos_drive_prefix(const char *path) { return isalpha(*path) && path[1] == ':'; From 9151da6b3bd05c40d25310f3bb4589b5778bfed3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:01:01 +0100 Subject: [PATCH 383/781] Move mkstemp and PRIuMAX to compat/mingw.h. Signed-off-by: Johannes Sixt --- compat/mingw.h | 7 +++++++ git-compat-util.h | 16 +++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 50973bc193..64e0ac79e3 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -123,6 +123,7 @@ static inline int waitpid(pid_t pid, unsigned *status, unsigned options) int pipe(int filedes[2]); unsigned int sleep (unsigned int seconds); +int mkstemp(char *template); int gettimeofday(struct timeval *tv, void *tz); int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); @@ -187,6 +188,12 @@ static inline unsigned int git_ntohl(unsigned int x) sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +/* + * git specific compatibility + */ + +#define PRIuMAX "I64u" + /* * helpers */ diff --git a/git-compat-util.h b/git-compat-util.h index 73b08397c9..aac06bfefe 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -106,11 +106,7 @@ #endif #ifndef PRIuMAX -#ifndef __MINGW32__ #define PRIuMAX "llu" -#else -#define PRIuMAX "I64u" -#endif #endif #ifdef __GNUC__ @@ -171,9 +167,11 @@ extern int git_munmap(void *start, size_t length); #define pread git_pread extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); #endif -/* Forward decl that will remind us if its twin in cache.h changes. - This function in used in compat/pread.c. But we can't include - cache.h there. */ +/* + * Forward decl that will remind us if its twin in cache.h changes. + * This function is used in compat/pread.c. But we can't include + * cache.h there. + */ extern int read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV @@ -379,10 +377,6 @@ static inline FILE *xfdopen(int fd, const char *mode) return stream; } -#ifdef __MINGW32__ -int mkstemp(char *template); -#endif - static inline int xmkstemp(char *template) { int fd; From 70aa4faf57b62c52e61bc9cd866dd3392bd4db93 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:06:20 +0100 Subject: [PATCH 384/781] Define PATH_SEP to ':' or ';' as needed. This reduces the number of conditionals in the code. Signed-off-by: Johannes Sixt --- compat/mingw.h | 1 + exec_cmd.c | 6 +----- git-compat-util.h | 4 ++++ help.c | 7 +------ sha1_file.c | 6 +----- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 64e0ac79e3..93ef42b9cf 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -192,6 +192,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); * git specific compatibility */ +#define PATH_SEP ';' #define PRIuMAX "I64u" /* diff --git a/exec_cmd.c b/exec_cmd.c index 6d2f740949..84db7ee664 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -70,11 +70,7 @@ static void add_path(struct strbuf *out, const char *path) else strbuf_addstr(out, make_absolute_path(path)); -#ifdef __MINGW32__ - strbuf_addch(out, ';'); -#else - strbuf_addch(out, ':'); -#endif + strbuf_addch(out, PATH_SEP); } } diff --git a/git-compat-util.h b/git-compat-util.h index aac06bfefe..4144605725 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -109,6 +109,10 @@ #define PRIuMAX "llu" #endif +#ifndef PATH_SEP +#define PATH_SEP ':' +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else diff --git a/help.c b/help.c index 8d83df5466..04ceed8efd 100644 --- a/help.c +++ b/help.c @@ -240,11 +240,6 @@ static unsigned int load_command_list(void) const char *env_path = getenv("PATH"); char *paths, *path, *colon; const char *exec_path = git_exec_path(); -#ifdef __MINGW32__ - char sep = ';'; -#else - char sep = ':'; -#endif if (exec_path) longest = list_commands_in_dir(&main_cmds, exec_path); @@ -256,7 +251,7 @@ static unsigned int load_command_list(void) path = paths = xstrdup(env_path); while (1) { - if ((colon = strchr(path, sep))) + if ((colon = strchr(path, PATH_SEP))) *colon = 0; len = list_commands_in_dir(&other_cmds, path); diff --git a/sha1_file.c b/sha1_file.c index 2192407494..45231593c7 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -394,11 +394,7 @@ void prepare_alt_odb(void) if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; -#ifdef __MINGW32__ - link_alt_odb_entries(alt, alt + strlen(alt), ';', NULL, 0); -#else - link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0); -#endif + link_alt_odb_entries(alt, alt + strlen(alt), PATH_SEP, NULL, 0); read_info_alternates(get_object_directory(), 0); } From 1881ab8876fe580fd04efd559de54388b8cf8346 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:10:54 +0100 Subject: [PATCH 385/781] Move the definition of has_dos_drive_prefix to compat/mingw.c This cannot easily be an inline function because it uses isalpha(), which is not yet declared when compat/mingw.c is parsed and so would give a compiler warning. Signed-off-by: Johannes Sixt --- compat/mingw.h | 1 + git-compat-util.h | 20 ++++---------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 93ef42b9cf..bf3843272b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -192,6 +192,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); * git specific compatibility */ +#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 4144605725..08f764ef9e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -113,6 +113,10 @@ #define PATH_SEP ':' #endif +#ifndef has_dos_drive_prefix +#define has_dos_drive_prefix(path) 0 +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else @@ -467,20 +471,4 @@ void git_qsort(void *base, size_t nmemb, size_t size, # define FORCE_DIR_SET_GID 0 #endif -#ifdef __MINGW32__ - -static inline int has_dos_drive_prefix(const char *path) -{ - return isalpha(*path) && path[1] == ':'; -} - -#else /* __MINGW32__ */ - -static inline int has_dos_drive_prefix(const char *path) -{ - return 0; -} - -#endif /* __MINGW32__ */ - #endif From a76ef1f443951642616cf313926c6ebd3d7172a7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:12:18 +0100 Subject: [PATCH 386/781] Define is_dir_sep conditionally in compat/mingw.h and git-compat-util.h. By doing it there we can reduce yet another bunch of conditionals from setup.c. Signed-off-by: Johannes Sixt --- compat/mingw.h | 1 + git-compat-util.h | 4 ++++ setup.c | 33 +++++++++------------------------ 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index bf3843272b..abac3f2caf 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -193,6 +193,7 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler); */ #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') +#define is_dir_sep(c) ((c) == '/' || (c) == '\\') #define PATH_SEP ';' #define PRIuMAX "I64u" diff --git a/git-compat-util.h b/git-compat-util.h index 08f764ef9e..2889146e89 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -117,6 +117,10 @@ #define has_dos_drive_prefix(path) 0 #endif +#ifndef is_dir_sep +#define is_dir_sep(c) ((c) == '/') +#endif + #ifdef __GNUC__ #define NORETURN __attribute__((__noreturn__)) #else diff --git a/setup.c b/setup.c index 0ee0ae4f31..eea103807f 100644 --- a/setup.c +++ b/setup.c @@ -4,23 +4,16 @@ static int inside_git_dir = -1; static int inside_work_tree = -1; -#ifdef __MINGW32__ -static inline int is_dir_sep(char c) { return c == '/' || c == '\\'; } -#else -static inline int is_dir_sep(char c) { return c == '/'; } -#endif - static int sanitary_path_copy(char *dst, const char *src) { - char *dst0 = dst; + char *dst0; -#ifdef __MINGW32__ - if (isalpha(*src) && src[1] == ':') { + if (has_dos_drive_prefix(src)) { *dst++ = *src++; *dst++ = *src++; - dst0 = dst; } -#endif + dst0 = dst; + if (is_dir_sep(*src)) { *dst++ = '/'; while (is_dir_sep(*src)) @@ -39,30 +32,22 @@ static int sanitary_path_copy(char *dst, const char *src) * (4) "../" -- strip one, eat slash and continue. */ if (c == '.') { - switch (src[1]) { - case '\0': + if (!src[1]) { /* (1) */ src++; break; - case '/': -#ifdef __MINGW32__ - case '\\': -#endif + } else if (is_dir_sep(src[1])) { /* (2) */ src += 2; while (is_dir_sep(*src)) src++; continue; - case '.': - switch (src[2]) { - case '\0': + } else if (src[1] == '.') { + if (!src[2]) { /* (3) */ src += 2; goto up_one; - case '/': -#ifdef __MINGW32__ - case '\\': -#endif + } else if (is_dir_sep(src[2])) { /* (4) */ src += 3; while (is_dir_sep(*src)) From 13cae476a6ebb4239531b578109b7130d620ae42 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:16:37 +0100 Subject: [PATCH 387/781] templates: Mark only hooks as not-executable. Previously all files in the template directory were investigated whether they are scripts. But actually, we only want to disable the hooks, not any other scripts (but currently there are no others anyway). Signed-off-by: Johannes Sixt --- templates/Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/templates/Makefile b/templates/Makefile index 90bb91d6d7..ab2c823ae0 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -34,11 +34,8 @@ boilerplates.made : $(bpsrc) $(INSTALL) -d -m 755 blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - *) if test -n "$$(sed -ne '/^#!\//p' -e '1q' < "$$boilerplate")"; then \ - cp -p "$$boilerplate" "blt/$${dst}$(NOEXECTEMPL)"; \ - else \ - cp -p "$$boilerplate" "blt/$$dst"; \ - fi ;; \ + hooks--*) cp -p $$boilerplate blt/$${dst}$(NOEXECTEMPL) ;; \ + *) cp -p $$boilerplate blt/$$dst ;; \ esac || exit; \ done && \ date >$@ From d0e8078ae5fe00e29df772050a2c62fa5845e286 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:17:42 +0100 Subject: [PATCH 388/781] Setup stderr before stdout on Windows as well. This implements what ce2cf27adc does on Unix. Signed-off-by: Johannes Sixt --- run-command.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/run-command.c b/run-command.c index aba2bf2c0f..2ce8c2b2f0 100644 --- a/run-command.c +++ b/run-command.c @@ -132,6 +132,14 @@ int start_command(struct child_process *cmd) dup2(cmd->in, 0); } + if (cmd->no_stderr) { + s2 = dup(2); + dup_devnull(2); + } else if (need_err) { + s2 = dup(2); + dup2(fderr[1], 2); + } + if (cmd->no_stdout) { s1 = dup(1); dup_devnull(1); @@ -146,14 +154,6 @@ int start_command(struct child_process *cmd) dup2(cmd->out, 1); } - if (cmd->no_stderr) { - s2 = dup(2); - dup_devnull(2); - } else if (need_err) { - s2 = dup(2); - dup2(fderr[1], 2); - } - if (cmd->dir) die("chdir in start_command() not implemented"); if (cmd->env) { From c9df829f07533c26c41c2faebc0465a788b08aef Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 13 Mar 2008 13:18:45 +0100 Subject: [PATCH 389/781] Use the available vsnprintf replacement instead of rolling our own. But we still have to cater for the strangeness that on Windows the size parameter is the number of characters to write, not the size of the buffer. Signed-off-by: Johannes Sixt --- Makefile | 2 ++ compat/mingw.c | 34 ---------------------------------- compat/mingw.h | 3 --- compat/snprintf.c | 13 +++++++++++-- 4 files changed, 13 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 9023eff0bb..ea59a15989 100644 --- a/Makefile +++ b/Makefile @@ -550,10 +550,12 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease NO_MKDTEMP = YesPlease + SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 diff --git a/compat/mingw.c b/compat/mingw.c index 6733727380..7c8fd0e158 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -847,40 +847,6 @@ int mingw_rename(const char *pold, const char *pnew) return -1; } -#undef vsnprintf -/* Note that the size parameter specifies the available space, i.e. - * includes the trailing NUL byte; but Windows's vsnprintf expects the - * number of characters to write without the trailing NUL. - */ - -/* This is out of line because it uses alloca() behind the scenes, - * which must not be called in a loop (alloca() reclaims the allocations - * only at function exit). - */ -static int try_vsnprintf(size_t size, const char *fmt, va_list args) -{ - char buf[size]; /* gcc-ism */ - return vsnprintf(buf, size-1, fmt, args); -} - -int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - int len; - if (size > 0) { - len = vsnprintf(buf, size-1, fmt, args); - if (len >= 0) - return len; - } - /* ouch, buffer too small; need to compute the size */ - if (size < 250) - size = 250; - do { - size *= 4; - len = try_vsnprintf(size, fmt, args); - } while (len < 0); - return len; -} - struct passwd *getpwuid(int uid) { static char user_name[100]; diff --git a/compat/mingw.h b/compat/mingw.h index abac3f2caf..c7db345d58 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -174,9 +174,6 @@ int mingw_fstat(int fd, struct mingw_stat *buf); static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) { return mingw_lstat(file_name, buf); } -int mingw_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); -#define vsnprintf mingw_vsnprintf - pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp diff --git a/compat/snprintf.c b/compat/snprintf.c index dbfc2d6b6e..480b66f94e 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -1,12 +1,21 @@ #include "../git-compat-util.h" +/* + * The size parameter specifies the available space, i.e. includes + * the trailing NUL byte; but Windows's vsnprintf expects the + * number of characters to write without the trailing NUL. + */ +#ifndef SNPRINTF_SIZE_CORR +#define SNPRINTF_SIZE_CORR 0 +#endif + #undef vsnprintf int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; int ret; - ret = vsnprintf(str, maxsize, format, ap); + ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); if (ret != -1) return ret; @@ -20,7 +29,7 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) if (! str) break; s = str; - ret = vsnprintf(str, maxsize, format, ap); + ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); } free(s); return ret; From 2fa62b7f9d40cdd1d617410cab3597f3dac9ddd0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 16 Mar 2008 20:42:55 +0100 Subject: [PATCH 390/781] Fix compile error due to utime.h being in a conditional section. Signed-off-by: Johannes Sixt --- git-compat-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index af39f009da..0482fcc1c6 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -66,12 +66,12 @@ #include #include #include +#include #ifndef __MINGW32__ #include #include #include #include -#include #ifndef NO_SYS_SELECT_H #include #endif From 239cf481835368d6aa1a9af9a22980f18ded7e1a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 16 Mar 2008 21:22:01 +0100 Subject: [PATCH 391/781] t7401-submodule-summary: Use test_cmp instead of plain diff Signed-off-by: Johannes Sixt --- t/t7401-submodule-summary.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 0f3c42ab35..86ed2a2a2d 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -37,7 +37,7 @@ head1=$(add_file sm1 foo1 foo2) test_expect_success 'added submodule' " git add sm1 && git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 0000000...$head1 (2): > Add foo2 @@ -49,7 +49,7 @@ head2=$(add_file sm1 foo3) test_expect_success 'modified submodule(forward)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head1...$head2 (1): > Add foo3 @@ -64,7 +64,7 @@ cd .. test_expect_success 'modified submodule(backward)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head2...$head3 (2): < Add foo3 < Add foo2 @@ -76,7 +76,7 @@ head4=$(add_file sm1 foo4 foo5) && head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD) test_expect_success 'modified submodule(backward and forward)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head2...$head4 (4): > Add foo5 > Add foo4 @@ -88,7 +88,7 @@ EOF test_expect_success '--summary-limit' " git submodule summary -n 3 >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head2...$head4 (4): > Add foo5 > Add foo4 @@ -107,7 +107,7 @@ mv sm1-bak sm1 test_expect_success 'typechanged submodule(submodule->blob), --cached' " git submodule summary --cached >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head4(submodule)->$head5(blob) (3): < Add foo5 @@ -118,7 +118,7 @@ rm -rf sm1 && git checkout-index sm1 test_expect_success 'typechanged submodule(submodule->blob)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head4(submodule)->$head5(blob): EOF @@ -129,7 +129,7 @@ test_create_repo sm1 && head6=$(add_file sm1 foo6 foo7) test_expect_success 'nonexistent commit' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head4...$head6: Warn: sm1 doesn't contain commit $head4_full @@ -139,7 +139,7 @@ EOF commit_file test_expect_success 'typechanged submodule(blob->submodule)' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head5(blob)->$head6(submodule) (2): > Add foo7 @@ -150,7 +150,7 @@ commit_file sm1 && rm -rf sm1 test_expect_success 'deleted submodule' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head6...0000000: EOF @@ -162,7 +162,7 @@ git add sm2 test_expect_success 'multiple submodules' " git submodule summary >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head6...0000000: * sm2 0000000...$head7 (2): @@ -173,7 +173,7 @@ EOF test_expect_success 'path filter' " git submodule summary sm2 >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm2 0000000...$head7 (2): > Add foo9 @@ -183,7 +183,7 @@ EOF commit_file sm2 test_expect_success 'given commit' " git submodule summary HEAD^ >actual && - diff actual - <<-EOF + test_cmp actual - <<-EOF * sm1 $head6...0000000: * sm2 0000000...$head7 (2): From 3400af9e38925a8ae3a9c619c542e55d258b6f3c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 12:54:28 +0100 Subject: [PATCH 392/781] Revert "Added is_dev_null check because Windows /dev/null is nul." This reverts commit 3d9012418c93b5e5f0ada041e1fc071cac48cbfa, which is no longer needed as discussed in http://article.gmane.org/gmane.comp.version-control.msysgit/1134 From Mike Pape's mail: The problem was test t4116-apply-reverse was failing because /dev/null was passed to git diff. This gets converted to nul on Windows, so I added the patch to test for this. However, it looks like Hannes just changed the test in 1f25f36fec4dd895cc6fb73e9cfdecb41e34d155 to not use /dev/null. Not sure if there are other patches that deal with the /dev/null -> nul issue (or if it's even an issue). Conflicts: cache.h Signed-off-by: Steffen Prohaska --- builtin-apply.c | 8 ++++---- cache.h | 9 --------- diff-lib.c | 6 +----- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/builtin-apply.c b/builtin-apply.c index ac12628f31..a3f075df4b 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -285,7 +285,7 @@ static unsigned long linelen(const char *buffer, unsigned long size) return len; } -static int is_dev_null_line(const char *str) +static int is_dev_null(const char *str) { return !memcmp("/dev/null", str, 9) && isspace(str[9]); } @@ -392,7 +392,7 @@ static int guess_p_value(const char *nameline) char *name, *cp; int val = -1; - if (is_dev_null_line(nameline)) + if (is_dev_null(nameline)) return -1; name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB); if (!name) @@ -440,12 +440,12 @@ static void parse_traditional_patch(const char *first, const char *second, struc p_value_known = 1; } } - if (is_dev_null_line(first)) { + if (is_dev_null(first)) { patch->is_new = 1; patch->is_delete = 0; name = find_name(second, NULL, p_value, TERM_SPACE | TERM_TAB); patch->new_name = name; - } else if (is_dev_null_line(second)) { + } else if (is_dev_null(second)) { patch->is_new = 0; patch->is_delete = 1; name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB); diff --git a/cache.h b/cache.h index 1b48cfbece..b169900431 100644 --- a/cache.h +++ b/cache.h @@ -487,15 +487,6 @@ static inline int is_absolute_path(const char *path) { return path[0] == '/' || has_dos_drive_prefix(path); } - -static inline int is_dev_null(const char *str) -{ -#ifdef __MINGW32__ - if (!strcmp(str, "nul")) - return 1; -#endif - return !strcmp(str, "/dev/null"); -} const char *make_absolute_path(const char *path); /* Convert slashes in place. On Windows to backslashes. */ char *make_native_separator(char *path); diff --git a/diff-lib.c b/diff-lib.c index 3b0a6c4351..52dbac34a4 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -35,7 +35,7 @@ static int get_mode(const char *path, int *mode) { struct stat st; - if (!path || is_dev_null(path)) + if (!path || !strcmp(path, "/dev/null")) *mode = 0; else if (!strcmp(path, "-")) *mode = create_ce_mode(0666); @@ -234,10 +234,6 @@ static int is_outside_repo(const char *path, int nongit, const char *prefix) int i; if (nongit || !strcmp(path, "-") || is_absolute_path(path)) return 1; -#ifdef __MINGW32__ - if (!strcmp(path, "nul")) - return 1; -#endif if (prefixcmp(path, "../")) return 0; if (!prefix) From 997c13c3898451e1299f0ef2da8b457b1902f2c6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 14:39:06 +0100 Subject: [PATCH 393/781] Revert "Provide git_exit() for MinGW" This reverts commit 194c1dbb5a04e29937b87d477a16927fa2c3be62. Instead of mapping exit values < 0 to 1, the original exit code should be fixed. For example, commit 2488df84a28b5eaae5495a59e390b51874d60a03 fixes this for run_command. All tests still pass after this revert. The git_exit() workaround seems no longer necessary. Signed-off-by: Steffen Prohaska --- compat/mingw.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index ff2fc832d3..7c8fd0e158 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -979,12 +979,3 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler) timer_fn = handler; return old; } - -#undef exit -int git_exit(int code) -{ - if (code < 0) - exit(1); - exit(code); -} - From 9ef5c15d66da91360eeca7e89d512a6b506f6d57 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 20:31:30 +0100 Subject: [PATCH 394/781] Revert replacing getenv() with get_git_dir() This partially reverts commit 855f254b2b5b083a63fc8d7709a42e2cbdc5a136. All tests still pass after this revert. The original commit seems unnecessary. Signed-off-by: Steffen Prohaska --- builtin-init-db.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/builtin-init-db.c b/builtin-init-db.c index 6c46af9228..79eaf8d6ed 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -367,7 +367,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) /* * Set up the default .git directory contents */ - git_dir = get_git_dir(); + git_dir = getenv(GIT_DIR_ENVIRONMENT); + if (!git_dir) + git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; safe_create_dir(git_dir, 0); /* Check to see if the repository version is right. From 24fcae02c33ca0fb05b088d55d12bf97fa2c23f3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 1 Jan 2008 20:34:52 +0100 Subject: [PATCH 395/781] Revert replacing setenv() with set_git_dir() This partially reverts commit 855f254b2b5b083a63fc8d7709a42e2cbdc5a136. All tests still pass after this revert. The original commit seems unnecessary. Signed-off-by: Steffen Prohaska --- git.c | 6 +++--- path.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/git.c b/git.c index 5ae18e926f..327215cc91 100644 --- a/git.c +++ b/git.c @@ -45,14 +45,14 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) fprintf(stderr, "No directory given for --git-dir.\n" ); usage(git_usage_string); } - set_git_dir( (*argv)[1] ); + setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; handled++; } else if (!prefixcmp(cmd, "--git-dir=")) { - set_git_dir(cmd + 10); + setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@ -72,7 +72,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged) } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; is_bare_repository_cfg = 1; - set_git_dir(getcwd(git_dir, sizeof(git_dir))); + setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0); if (envchanged) *envchanged = 1; } else { diff --git a/path.c b/path.c index 4e19c4cdaa..fe0361aab4 100644 --- a/path.c +++ b/path.c @@ -255,7 +255,7 @@ char *enter_repo(char *path, int strict) if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 && validate_headref("HEAD") == 0) { - set_git_dir("."); + setenv(GIT_DIR_ENVIRONMENT, ".", 1); check_repository_format(); return path; } From 96ddc42f70dd1b080c51af5a50929f2b5811e415 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 30 Dec 2007 16:04:05 +0100 Subject: [PATCH 396/781] Revert "Hardlinks are not supported in MSys so we disable them." This reverts commit d1f83218dce62affd1d7a82a9e654cca08dade9c. Hardlinks are supported by MSYS (on NTFS). Conflicts: Makefile git-clone.sh t/Makefile t/test-lib.sh Signed-off-by: Steffen Prohaska --- Makefile | 10 +--------- git-clone.sh | 4 +--- t/Makefile | 4 ---- t/t5701-clone-local.sh | 11 ----------- t/test-lib.sh | 2 -- 5 files changed, 2 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 095e820415..fa5956736c 100644 --- a/Makefile +++ b/Makefile @@ -54,9 +54,6 @@ all:: # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. # Enable it on Windows. By default, symrefs are still used. # -# Define NO_HARDLINKS if you want to disable hard linking in git clone. -# Enable it on Windows. -# # Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability # tests. These tests take up a significant amount of the total test time # but are not needed unless you plan to talk to SVN repos. @@ -544,7 +541,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease - NO_HARDLINKS = YesPlease NO_IPV6 = YesPlease NO_SETENV = YesPlease NO_UNSETENV = YesPlease @@ -841,10 +837,6 @@ ifdef ASCIIDOC8 export ASCIIDOC8 endif -ifdef NO_HARDLINKS - export NO_HARDLINKS -endif - # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@ -923,7 +915,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - -e 's/@@NO_HARDLINKS@@/$(NO_HARDLINKS)/g' \ + -e 's|@@HTMLDIR@@|$(htmldir_SQ)|g' \ $@.sh >$@+ && \ chmod +x $@+ && \ mv $@+ $@ diff --git a/git-clone.sh b/git-clone.sh index edfa1529bc..b783de4300 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -176,7 +176,7 @@ origin_override= use_separate_remote=t depth= no_progress= -test "@@NO_HARDLINKS@@" && use_local_hardlink=no +local_explicitly_asked_for= test -t 1 || no_progress=--no-progress while test $# != 0 @@ -188,8 +188,6 @@ do bare=yes ;; -l|--local) local_explicitly_asked_for=yes - (test "@@NO_HARDLINKS@@" && - echo >&2 "Warning: -l asked but hardlinks are not supported") || use_local_hardlink=yes ;; --no-hardlinks) diff --git a/t/Makefile b/t/Makefile index 4f884466dd..72d7884232 100644 --- a/t/Makefile +++ b/t/Makefile @@ -14,10 +14,6 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) -ifdef NO_HARDLINKS - GIT_TEST_OPTS += --no-hardlinks -endif - all: $(T) clean $(T): diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index 0bf36a67a0..8dfaaa456e 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -3,13 +3,6 @@ test_description='test local clone' . ./test-lib.sh -if test "$no_hardlinks" -then - say 'Hard links not supported, skipping tests.' - test_done - exit -fi - D=`pwd` test_expect_success 'preparing origin repository' ' @@ -66,10 +59,6 @@ test_expect_success 'With -no-hardlinks, local will make a copy' ' test 0 = $linked ' -say "hardlinks not supported, skipping tests." -test_done -exit 0 - test_expect_success 'Even without -l, local will make a hardlink' ' cd "$D" && rm -fr w && diff --git a/t/test-lib.sh b/t/test-lib.sh index fc4a45323e..0815190a2f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -91,8 +91,6 @@ do --no-python) # noop now... shift ;; - --no-hardlinks) - no_hardlinks=t; shift ;; *) break ;; esac From 46a2df8d4fec1798bb807bf14c28f398d606219b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Mar 2008 09:05:17 +0100 Subject: [PATCH 397/781] Skip t6031 if executable bit does not work. Signed-off-by: Johannes Sixt --- t/t6031-merge-recursive.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index c8310aee4f..a8ce5569cb 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -3,6 +3,11 @@ test_description='merge-recursive: handle file mode' . ./test-lib.sh +if test "$(git config --bool core.filemode)" = false; then + say "executable bit not honored - skipping tests" + test_done +fi + test_expect_success 'mode change in one branch: keep changed version' ' : >file1 && git add file1 && From 49133c8b09736ea681d6bcfd31ffecf915137698 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Mar 2008 09:09:52 +0100 Subject: [PATCH 398/781] t4150 is broken on Windows. git-am does not recognize Windows style absolute path names. Signed-off-by: Johannes Sixt --- t/t4150-am-subdir.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t4150-am-subdir.sh b/t/t4150-am-subdir.sh index 52069b469b..3cb7965644 100755 --- a/t/t4150-am-subdir.sh +++ b/t/t4150-am-subdir.sh @@ -56,7 +56,11 @@ test_expect_success 'am regularly from file in subdirectory' ' test_cmp expect actual ' -test_expect_success 'am regularly from file in subdirectory with full path' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'am regularly from file in subdirectory with full path' ' rm -fr subdir && git checkout initial && P=$(pwd) && From 04d11973432ed449c196d6f2cc02177f51e01824 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 18 Mar 2008 09:18:53 +0100 Subject: [PATCH 399/781] Move the utime() wrapper from test-chmtime.c to mingw.c. The recent commit f746bae84e4746a861d9ebed29fd9255e5cd929f uses utime() to adjust time stamps of pack files. We better make sure that we have an implementation of utime that sets time stamps in a fashion that works with our stat() implementation. (The system's utime() implemenation has issues with daylight saving time changes.) Signed-off-by: Johannes Sixt --- compat/mingw.c | 27 +++++++++++++++++++++++++++ compat/mingw.h | 3 +++ test-chmtime.c | 32 -------------------------------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7c8fd0e158..a5b43bcf6f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,6 +175,33 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } +static inline void time_t_to_filetime(time_t t, FILETIME *ft) +{ + long long winTime = t * 10000000LL + 116444736000000000LL; + ft->dwLowDateTime = winTime; + ft->dwHighDateTime = winTime >> 32; +} + +int mingw_utime (const char *file_name, const struct utimbuf *times) +{ + FILETIME mft, aft; + int fh, rc; + + /* must have write permission */ + if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) + return -1; + + time_t_to_filetime(times->modtime, &mft); + time_t_to_filetime(times->actime, &aft); + if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { + errno = EINVAL; + rc = -1; + } else + rc = 0; + close(fh); + return rc; +} + unsigned int sleep (unsigned int seconds) { Sleep(seconds*1000); diff --git a/compat/mingw.h b/compat/mingw.h index c7db345d58..0e18b78b14 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -174,6 +174,9 @@ int mingw_fstat(int fd, struct mingw_stat *buf); static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) { return mingw_lstat(file_name, buf); } +int mingw_utime(const char *file_name, const struct utimbuf *times); +#define utime mingw_utime + pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); void mingw_execvp(const char *cmd, char *const *argv); #define execvp mingw_execvp diff --git a/test-chmtime.c b/test-chmtime.c index 8a1e6b8479..90da448ebe 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -3,38 +3,6 @@ static const char usage_str[] = "(+|=|=+|=-|-) ..."; -#ifdef __MINGW32__ -static inline void time_t_to_filetime(time_t t, FILETIME *ft) -{ - long long winTime = t * 10000000LL + 116444736000000000LL; - ft->dwLowDateTime = winTime; - ft->dwHighDateTime = winTime >> 32; -} - -int git_utime (const char *file_name, const struct utimbuf *times) -{ - FILETIME mft, aft; - int fh, rc; - - /* must have write permission */ - if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) - return -1; - - time_t_to_filetime(times->modtime, &mft); - time_t_to_filetime(times->actime, &aft); - if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) { - errno = EINVAL; - rc = -1; - } else - rc = 0; - close(fh); - return rc; -} - -int git_utime(const char *file_name, const struct utimbuf *times); -#define utime git_utime -#endif /* __MINGW32__ */ - int main(int argc, const char *argv[]) { int i; From 75de7fcca12a911449c966c1dfb7dfc47a23cbaa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 19 Mar 2008 12:57:59 +0100 Subject: [PATCH 400/781] t1004: Exclude tests that involve symbolic links. Signed-off-by: Johannes Sixt --- t/t1004-read-tree-m-u-wf.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh index 570d3729bd..bc6dc95e9c 100755 --- a/t/t1004-read-tree-m-u-wf.sh +++ b/t/t1004-read-tree-m-u-wf.sh @@ -157,6 +157,7 @@ test_expect_success '3-way not overwriting local changes (their side)' ' ' +test "$no_symlinks" || { test_expect_success 'funny symlink in work tree' ' git reset --hard && @@ -191,6 +192,7 @@ test_expect_success 'funny symlink in work tree, un-unlink-able' ' # clean-up from the above test chmod a+w a rm -fr a b +} # $no_symlinks test_expect_success 'D/F setup' ' From f32edf6b14ae405b9e7a4842f18990de6bb4a322 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 28 Mar 2008 16:00:17 +0100 Subject: [PATCH 401/781] snprintf replacement: Make sure the result is NUL terminated. On Windows, if the resulting string fits exactly in the provided buffer, but not the terminating NUL, then the return value of the system's vsnprintf is the number of characters written. But since we had reserved an extra byte anyway, we only need to make sure that the result is NUL terminated. Signed-off-by: Johannes Sixt --- compat/snprintf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index 480b66f94e..bddfa5cdde 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -16,8 +16,11 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) int ret; ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); - if (ret != -1) + if (ret != -1) { + /* Windows does not NUL-terminate if result fits exactly */ + str[ret] = 0; return ret; + } s = NULL; if (maxsize < 128) From c1241918459260db1f02eec2dcf27d5002cead43 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 3 Apr 2008 10:14:35 +0200 Subject: [PATCH 402/781] Another fix to allow tests on symlink challenged file systems to pass Signed-off-by: Johannes Sixt --- t/t2201-add-update-typechange.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh index e15e3eb81b..69ac97e648 100755 --- a/t/t2201-add-update-typechange.sh +++ b/t/t2201-add-update-typechange.sh @@ -4,6 +4,15 @@ test_description='more git add -u' . ./test-lib.sh +symlink_change=T +if test "$no_symlinks" +then + ln () { + echo -n "$2" > "$3" + } + symlink_change=M +fi + _z40=0000000000000000000000000000000000000000 test_expect_success setup ' @@ -71,7 +80,7 @@ test_expect_success modify ' s/blob/000000/ } / nitfol/{ - s/ nitfol/ $_z40 T&/ + s/ nitfol/ $_z40 $symlink_change&/ s/blob/100644/ } / rezrov.bozbar/{ From 0c75c2ff5c78ae7fcba2bc1a5928c7aa2d522986 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 403/781] t3903: Mark tests as broken on MinGW MinGW's bash eats curly braces in "git stash drop stash@{1}". This causes two tests in t3903 to fail. Those breakages are marked expected. You can work around the breakage by escaping the curly braces as "git stash drop stash@\\{1\\}". Signed-off-by: Steffen Prohaska --- t/t3903-stash.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 2d3ee3b78c..d717a02b54 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -88,7 +88,11 @@ test_expect_success 'drop top stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'drop middle stash' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && @@ -108,7 +112,7 @@ test_expect_success 'drop middle stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'stash pop' ' +$test_expect 'stash pop' ' git reset --hard && git stash pop && test 3 = $(cat file) && From 0b4d5c6b39bb6e3dfeeddc71d1c86c30f25196bd Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:52:29 +0200 Subject: [PATCH 404/781] t7201: Mark tests as broken on MinGW MinGW's path conversion mangles ":/". This breakages is marked expected. Unfortunately, the heuristic in msys_p2w() does not allow for a workaround. Signed-off-by: Steffen Prohaska --- t/t7201-co.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 3111baa9e3..5dd79bd018 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -207,7 +207,11 @@ test_expect_success 'checkout to detach HEAD with branchname^' ' fi ' -test_expect_success 'checkout to detach HEAD with :/message' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'checkout to detach HEAD with :/message' ' git checkout -f master && git clean -f && git checkout ":/Initial" && From e1d3b40b7e7addc8adc065c99d7affa7611e2428 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:18:32 +0200 Subject: [PATCH 405/781] test-lib: Set is_mingw on MinGW We need to skip some tests on MinGW because they test features that are not available on Windows. This commit adds a shell variable is_mingw. You can test is_mingw to skip a test only on MinGW. Signed-off-by: Steffen Prohaska --- t/test-lib.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/test-lib.sh b/t/test-lib.sh index 30a181d548..11ef041335 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -438,5 +438,6 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + is_mingw=t ;; esac From e0203e1029f45b506a67a5815065fc78d6c1c078 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:20:46 +0200 Subject: [PATCH 406/781] t5503: Skip four tests on MinGW The tests fail on MinGW because GIT_DEBUG_SEND_PACK is not supported. See http://article.gmane.org/gmane.comp.version-control.msysgit/1992 Signed-off-by: Steffen Prohaska --- t/t5503-tagfollow.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 86e5b9bc26..398b13184c 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -41,6 +41,7 @@ cat - <expect want $A #E EOF +test "$is_mingw" || test_expect_success 'fetch A (new commit : 1 connection)' ' rm -f $U ( @@ -71,6 +72,7 @@ want $C want $T #E EOF +test "$is_mingw" || test_expect_success 'fetch C, T (new branch, tag : 1 connection)' ' rm -f $U ( @@ -107,6 +109,7 @@ want $B want $S #E EOF +test "$is_mingw" || test_expect_success 'fetch B, S (commit and tag : 1 connection)' ' rm -f $U ( @@ -127,6 +130,7 @@ want $B want $S #E EOF +test "$is_mingw" || test_expect_success 'new clone fetch master and tags' ' git branch -D cat rm -f $U From 1a14b8acccc659eb63e1e18309c356910b0eed95 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:31:32 +0200 Subject: [PATCH 407/781] t5505: On MinGW, use Windows path in expected output of "git remote show" "git remote show" prints the Windows path. This commit modifies the expected output to also use the Windows path, instead of the Unix path. Signed-off-by: Steffen Prohaska --- t/t5505-remote.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0a7fea865d..ddfa4740ed 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -97,9 +97,13 @@ test_expect_success 'remove remote' ' ) ' +case $(uname -s) in +*MINGW*) PWD="pwd -W";; +*) PWD=pwd;; +esac cat > test/expect << EOF * remote origin - URL: $(pwd)/one/.git + URL: $($PWD)/one/.git Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) From b4078242a7b03c967c2829205b5461afb82d19b4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:43:44 +0200 Subject: [PATCH 408/781] t7401: Tell diff to ignore whitespace on MinGW "git submodule" prints CRLF lineendings, which break the comparison with expected outputs. This commit sets the diff command to ignore whitespace changes. Signed-off-by: Steffen Prohaska --- t/t7401-submodule-summary.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 86ed2a2a2d..f34d8f0bb2 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -8,6 +8,10 @@ test_description='Summary support for submodules This test tries to verify the sanity of summary subcommand of git-submodule. ' +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + . ./test-lib.sh add_file () { From 90fba70984a429aa21972932c0775638d15a44d6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 13:48:24 +0200 Subject: [PATCH 409/781] t5511: Disable test with "::" on MinGW We must not use arguments with "::" on MinGW. MSYS' path conversion heuristic mangles such arguments. The heuristic considers them path lists and converts ":" to ";". This commit disables a test that uses "::". Signed-off-by: Steffen Prohaska --- t/t5511-refspec.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 670a8f1c99..d061f6a4c2 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -46,6 +46,7 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' +test "$is_mingw" || test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid From a1fca27d1ee3fd7af09e702a326a8897ee4c0a13 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 19 Apr 2008 11:21:16 +0200 Subject: [PATCH 410/781] MinGW: Mark some tests as "still broken" instead of skipping them --- t/t3903-stash.sh | 4 ++++ t/t5503-tagfollow.sh | 29 +++++++++++++++++++++-------- t/t5511-refspec.sh | 12 ++++++++++-- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index d717a02b54..0858aadb87 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -112,6 +112,10 @@ $test_expect 'drop middle stash' ' test 1 = $(git show HEAD:file) ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac $test_expect 'stash pop' ' git reset --hard && git stash pop && diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 398b13184c..f6828281bd 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -41,8 +41,12 @@ cat - <expect want $A #E EOF -test "$is_mingw" || -test_expect_success 'fetch A (new commit : 1 connection)' ' + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch A (new commit : 1 connection)' ' rm -f $U ( cd cloned && @@ -72,8 +76,11 @@ want $C want $T #E EOF -test "$is_mingw" || -test_expect_success 'fetch C, T (new branch, tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch C, T (new branch, tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -109,8 +116,11 @@ want $B want $S #E EOF -test "$is_mingw" || -test_expect_success 'fetch B, S (commit and tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch B, S (commit and tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -130,8 +140,11 @@ want $B want $S #E EOF -test "$is_mingw" || -test_expect_success 'new clone fetch master and tags' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'new clone fetch master and tags' ' git branch -D cat rm -f $U ( diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index d061f6a4c2..e773b5d7bd 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -4,6 +4,8 @@ test_description='refspec parsing' . ./test-lib.sh +test_expect=test_expect_success + test_refspec () { kind=$1 refspec=$2 expect=$3 @@ -19,7 +21,7 @@ test_refspec () { title="$kind $refspec (invalid)" test='test_must_fail git ls-remote frotz' fi - test_expect_success "$title" "$test" + $test_expect "$title" "$test" } test_refspec push '' invalid @@ -46,8 +48,14 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' -test "$is_mingw" || + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid +test_expect=test_expect_success + test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid test_refspec push 'master~1:refs/remotes/frotz/backup' From 6c22598c24c822c6911b272d196e72cda6e79ebf Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Fri, 2 May 2008 09:40:40 +0200 Subject: [PATCH 411/781] Revert "test-lib: Set is_mingw on MinGW" This reverts commit e1d3b40b7e7addc8adc065c99d7affa7611e2428. --- t/test-lib.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/t/test-lib.sh b/t/test-lib.sh index 11ef041335..30a181d548 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -438,6 +438,5 @@ case $(uname -s) in find () { /usr/bin/find "$@" } - is_mingw=t ;; esac From f3ffa502270e78a3ceac5d249a5569052d0f5624 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:52:29 +0200 Subject: [PATCH 412/781] t7201: Mark tests as broken on MinGW MinGW's path conversion mangles ":/". This breakages is marked expected. Unfortunately, the heuristic in msys_p2w() does not allow for a workaround. Signed-off-by: Steffen Prohaska --- t/t7201-co.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 3111baa9e3..5dd79bd018 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -207,7 +207,11 @@ test_expect_success 'checkout to detach HEAD with branchname^' ' fi ' -test_expect_success 'checkout to detach HEAD with :/message' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'checkout to detach HEAD with :/message' ' git checkout -f master && git clean -f && git checkout ":/Initial" && From b74e70b3671b129016beb7ad0a241ecc0590d22e Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:31:32 +0200 Subject: [PATCH 413/781] t5505: On MinGW, use Windows path in expected output of "git remote show" "git remote show" prints the Windows path. This commit modifies the expected output to also use the Windows path, instead of the Unix path. Signed-off-by: Steffen Prohaska --- t/t5505-remote.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0a7fea865d..ddfa4740ed 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -97,9 +97,13 @@ test_expect_success 'remove remote' ' ) ' +case $(uname -s) in +*MINGW*) PWD="pwd -W";; +*) PWD=pwd;; +esac cat > test/expect << EOF * remote origin - URL: $(pwd)/one/.git + URL: $($PWD)/one/.git Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) From ab8a9f21c410ebbeab3d94625a13ba738efdbac5 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 12:43:44 +0200 Subject: [PATCH 414/781] t7401: Tell diff to ignore whitespace on MinGW "git submodule" prints CRLF lineendings, which break the comparison with expected outputs. This commit sets the diff command to ignore whitespace changes. Signed-off-by: Steffen Prohaska --- t/t7401-submodule-summary.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 86ed2a2a2d..f34d8f0bb2 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -8,6 +8,10 @@ test_description='Summary support for submodules This test tries to verify the sanity of summary subcommand of git-submodule. ' +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + . ./test-lib.sh add_file () { From fe3238dc4c870cb865bd2862f317afeb35018267 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 415/781] t3903: Mark tests as broken on MinGW MinGW's bash eats curly braces in "git stash drop stash@{1}". This causes two tests in t3903 to fail. Those breakages are marked expected. You can work around the breakage by escaping the curly braces as "git stash drop stash@\\{1\\}". A check for MINGW is added in front of each test marked, although the first check would be sufficient. Adding the check multiple times, however, allows to remove the checks independently of each other. Signed-off-by: Steffen Prohaska --- t/t3903-stash.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 2d3ee3b78c..0858aadb87 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -88,7 +88,11 @@ test_expect_success 'drop top stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'drop middle stash' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && @@ -108,7 +112,11 @@ test_expect_success 'drop middle stash' ' test 1 = $(git show HEAD:file) ' -test_expect_success 'stash pop' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'stash pop' ' git reset --hard && git stash pop && test 3 = $(cat file) && From f94ce3a59d2c0433282b7c794a2a034a74d6586c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 416/781] t5503: Mark tests as broken on MinGW The tests fail on MinGW because GIT_DEBUG_SEND_PACK is not supported. See http://article.gmane.org/gmane.comp.version-control.msysgit/1992 These failures are marked known breakages. A check for MINGW is added in front of each test marked, although the first check would be sufficient. Adding the check multiple times, however, allows to remove the checks independently of each other. Signed-off-by: Steffen Prohaska --- t/t5503-tagfollow.sh | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh index 86e5b9bc26..f6828281bd 100755 --- a/t/t5503-tagfollow.sh +++ b/t/t5503-tagfollow.sh @@ -41,7 +41,12 @@ cat - <expect want $A #E EOF -test_expect_success 'fetch A (new commit : 1 connection)' ' + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch A (new commit : 1 connection)' ' rm -f $U ( cd cloned && @@ -71,7 +76,11 @@ want $C want $T #E EOF -test_expect_success 'fetch C, T (new branch, tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch C, T (new branch, tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -107,7 +116,11 @@ want $B want $S #E EOF -test_expect_success 'fetch B, S (commit and tag : 1 connection)' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'fetch B, S (commit and tag : 1 connection)' ' rm -f $U ( cd cloned && @@ -127,7 +140,11 @@ want $B want $S #E EOF -test_expect_success 'new clone fetch master and tags' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'new clone fetch master and tags' ' git branch -D cat rm -f $U ( From ed697a2400d95fc565bdd740e894722d2ae7f35b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 13 Apr 2008 11:21:54 +0200 Subject: [PATCH 417/781] t5511: Mark test with "::" as broken on MinGW We must not use arguments with "::" on MinGW. MSYS' path conversion heuristic mangles such arguments. The heuristic considers them path lists and converts ":" to ";". This commit marks a test that uses "::" as broken. Signed-off-by: Steffen Prohaska --- t/t5511-refspec.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 670a8f1c99..e773b5d7bd 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -4,6 +4,8 @@ test_description='refspec parsing' . ./test-lib.sh +test_expect=test_expect_success + test_refspec () { kind=$1 refspec=$2 expect=$3 @@ -19,7 +21,7 @@ test_refspec () { title="$kind $refspec (invalid)" test='test_must_fail git ls-remote frotz' fi - test_expect_success "$title" "$test" + $test_expect "$title" "$test" } test_refspec push '' invalid @@ -46,7 +48,14 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' + +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid +test_expect=test_expect_success + test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid test_refspec push 'master~1:refs/remotes/frotz/backup' From e81573e4720b69b109062493b505d01b1c6acb1c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 May 2008 21:43:58 +0200 Subject: [PATCH 418/781] Update read_in_full() declaration in git-compat-util.h. Commit 0104ca09e3abf48ab26fd0599c4b686fcff60ffc changed the prototype. Signed-off-by: Johannes Sixt --- git-compat-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-compat-util.h b/git-compat-util.h index 6ae14562b7..11f6c4ab9c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -185,7 +185,7 @@ extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset); * This function is used in compat/pread.c. But we can't include * cache.h there. */ -extern int read_in_full(int fd, void *buf, size_t count); +extern ssize_t read_in_full(int fd, void *buf, size_t count); #ifdef NO_SETENV #define setenv gitsetenv From 3c81b4476c964cfaa8a3f5dc349d82765e66b060 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Apr 2008 12:07:12 +0200 Subject: [PATCH 419/781] Skip more symbolic link tests. Signed-off-by: Johannes Sixt --- t/t4114-apply-typechange.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh index 55334927ab..33c71ad38d 100755 --- a/t/t4114-apply-typechange.sh +++ b/t/t4114-apply-typechange.sh @@ -9,6 +9,11 @@ test_description='git apply should not get confused with type changes. . ./test-lib.sh +test "$no_symlinks" && { + say "Symbolic links not supported - skipping tests" + test_done +} + test_expect_success 'setup repository and commits' ' echo "hello world" > foo && echo "hi planet" > bar && From 60248c8c59512036e93d9dce89a0b7408afc01f9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Apr 2008 12:07:59 +0200 Subject: [PATCH 420/781] Use diff -w on Windows to ignore CRLF. Signed-off-by: Johannes Sixt --- t/t7502-status.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7502-status.sh b/t/t7502-status.sh index e4bfcaece0..ededff28ad 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -5,6 +5,10 @@ test_description='git-status' +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + . ./test-lib.sh test_expect_success 'setup' ' From dfd702ef0be17937651e925f8c0367b4b9d3de2f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 27 May 2008 00:15:06 +0100 Subject: [PATCH 421/781] Fix t5100 for Windows On Windows, "nul" is not allowed as a file name. So bend over for that platform even more than we do already. Signed-off-by: Johannes Schindelin --- t/t5100-mailinfo.sh | 4 ++-- t/t5100/{nul => nul-plain} | Bin 2 files changed, 2 insertions(+), 2 deletions(-) rename t/t5100/{nul => nul-plain} (100%) diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index a8b78ebf7d..577ecc210a 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -27,8 +27,8 @@ done test_expect_success 'respect NULs' ' - git mailsplit -d3 -o. ../t5100/nul && - cmp ../t5100/nul 001 && + git mailsplit -d3 -o. ../t5100/nul-plain && + cmp ../t5100/nul-plain 001 && (cat 001 | git mailinfo msg patch) && test 4 = $(wc -l < patch) diff --git a/t/t5100/nul b/t/t5100/nul-plain similarity index 100% rename from t/t5100/nul rename to t/t5100/nul-plain From e2829542f8d63138abe19ef638a0845d18695d5b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 27 May 2008 08:55:25 +0200 Subject: [PATCH 422/781] Fix reference to $(template_dir) in Makefile. The brackets were missing, so that 'make install' would install into the directory template/emplate_dir. Signed-off-by: Johannes Sixt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d8edd42a23..3fd53e4e03 100644 --- a/Makefile +++ b/Makefile @@ -1260,7 +1260,7 @@ remove-dashes: ifeq ($(firstword $(subst /, ,$(template_dir))),..) template_instdir = $(gitexecdir)/$(template_dir) else -template_instdir = $template_dir +template_instdir = $(template_dir) endif export template_instdir From 9ea874f89a6a90970364630ed8e80e1909ded409 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 27 May 2008 09:38:07 +0200 Subject: [PATCH 423/781] Skip tests that use chmod 0 - it does not make files unreadable on Windows. Signed-off-by: Johannes Sixt --- t/t3700-add.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 79cb00d1e8..55e6425a29 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -183,6 +183,10 @@ test_expect_success 'git add --refresh' ' test -z "`git diff-index HEAD -- foo`" ' +if case $(uname -s) in *MINGW*) :;; *) false;; esac then + say "chmod 0 does not make files unreadable - skipping tests" +else + test_expect_success 'git add should fail atomically upon an unreadable file' ' git reset --hard && date >foo1 && @@ -226,4 +230,6 @@ test_expect_success 'git add (add.ignore-errors = false)' ' ! ( git ls-files foo1 | grep foo1 ) ' +fi # skip chmod 0 tests + test_done From e00e4b2ef41c6622a4afcbdb8dc0725b6f1b459a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 2 May 2008 21:46:54 +0200 Subject: [PATCH 424/781] Skip unwritable object directory tests. chmod a-w does not make a directory unwritable on Windows. Signed-off-by: Johannes Sixt --- t/t0004-unwritable.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh index 9255c63c08..f1385d6ded 100755 --- a/t/t0004-unwritable.sh +++ b/t/t0004-unwritable.sh @@ -4,6 +4,13 @@ test_description='detect unwritable repository and fail correctly' . ./test-lib.sh +case "$(uname -s)" in +*MINGW*) + say "chmod a-w .git/objects does not make directory unwritable - skipping tests" + test_done + ;; +esac + test_expect_success setup ' >file && From df177fba3c2da3e69780b7a56628a8a7a1de024d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Apr 2008 12:15:15 +0200 Subject: [PATCH 425/781] t5300-pack-object: Set up the objects for --strict tests only once. The two --strict tests use the exact same sequence to set up the repository. This factores the setup step into a test of its own. Signed-off-by: Johannes Sixt --- t/t5300-pack-object.sh | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 83c67c4a5a..49817f1ce7 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -286,7 +286,7 @@ test_expect_success \ packname_4=$(git pack-objects test-4 LIST && - rm -f .git/index && - git update-index --index-info Date: Mon, 2 Jun 2008 10:14:29 +0200 Subject: [PATCH 426/781] Add #defines for SIGHUP and SIGQUIT. Signed-off-by: Johannes Sixt --- compat/mingw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 0e18b78b14..6965e3f2df 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -24,6 +24,8 @@ typedef int pid_t; #define SIGKILL 0 #define SIGCHLD 0 #define SIGPIPE 0 +#define SIGHUP 0 +#define SIGQUIT 0 #define SIGALRM 100 #define F_GETFD 1 From f01c16a4bbb417160dca721aa732b179cd40a98c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 4 Jun 2008 19:29:25 +0200 Subject: [PATCH 427/781] Remove the fake 'sync' command. It was added to silence git-repack, but it is no longer used there. Signed-off-by: Johannes Sixt --- git-sh-setup.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 822aa6f83a..9cceb21a82 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -153,9 +153,5 @@ case $(uname -s) in find () { /usr/bin/find "$@" } - # sync is missing - sync () { - : # no implementation - } ;; esac From b1013825f97b4f5a8097c25ee2a3cd4679f38f24 Mon Sep 17 00:00:00 2001 From: raible Date: Sun, 8 Jun 2008 09:51:32 +0200 Subject: [PATCH 428/781] mingw: Quote '{}' to work around an error in MSYS' glob() MSYS expands '{}' in paths even if the pattern between the braces does not contain a comma. See http://article.gmane.org/gmane.comp.version-control.msysgit/2341 for a detailed discussion. This commit fixes (at least) the case of "git stash apply stash@{1}". Note that "git-stash apply stash@{1}" works even without this patch (because it is executed directly by /bin/sh). Note that git-stash still has a bug whereby it doesn't validate its final argument ("stash@{1}" in this case). This commit does nothing to fix that problem. Signed-off-by: Steffen Prohaska --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index a5b43bcf6f..95ba563a27 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -380,7 +380,7 @@ static const char *quote_arg(const char *arg) const char *p = arg; if (!*p) force_quotes = 1; while (*p) { - if (isspace(*p) || *p == '*' || *p == '?') + if (isspace(*p) || *p == '*' || *p == '?' || *p == '{') force_quotes = 1; else if (*p == '"') n++; From 54b9e8917c44c456c445dece61389f0478505352 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Thu, 5 Jun 2008 01:49:03 -0400 Subject: [PATCH 429/781] connect.c: Fix custom port SSH with PuTTY plink on Windows OpenSSH uses -p to specify custom ports, while PuTTY uses -P. Git should detect if plink is in GIT_SSH and modify its flags as necessary. Also fixed is a possible hang due to faulty stdin forwarding to plink when plink attempts to be interactive. Signed-off-by: Edward Z. Yang Signed-off-by: Steffen Prohaska --- connect.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index 574f42fa47..6bd7ec9117 100644 --- a/connect.c +++ b/connect.c @@ -596,14 +596,24 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; - conn->argv = arg = xcalloc(6, sizeof(*arg)); + /* be sure to increase this size if you add more args */ + conn->argv = arg = xcalloc(8, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); + int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; + if (putty) { + /* stdin forwarding doesn't work, so give informative error messages + * (-v) and don't hang (-batch). + */ + *arg++ = "-batch"; + *arg++ = "-v"; + } if (port) { - *arg++ = "-p"; + /* P is for PuTTY, p is for OpenSSH */ + *arg++ = putty ? "-P" : "-p"; *arg++ = port; } *arg++ = host; From 3ad18f2446748cb3b2d21454c01f917315fcd806 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Sun, 2 Mar 2008 16:30:29 -0500 Subject: [PATCH 430/781] Scan for \r in addition to \n when reading shbang lines Signed-off-by: Steffen Prohaska --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index a5b43bcf6f..f036b3383c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -448,8 +448,8 @@ static const char *parse_interpreter(const char *cmd) if (buf[0] != '#' || buf[1] != '!') return NULL; buf[n] = '\0'; - p = strchr(buf, '\n'); - if (!p) + p = buf + strcspn(buf, "\r\n"); + if (!*p) return NULL; *p = '\0'; From 3ec8d36fbf055f40bb5639221a260ae9a37d62e0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 11 Jun 2008 15:15:08 +0200 Subject: [PATCH 431/781] Fix vsnprintf() emulation again. On Windows, if the native vsnprintf() fills the buffer, it does not add the terminating NUL. The earlier commit f32edf6b tried to fix the emulation, but the fix worked only if the formatted string fitted into the buffer exactly. However, there are callers that do not try to resize the buffer if it overflows, and in these cases the resulting string remained without the trailing NUL. This patch adds the NUL in all cases. Signed-off-by: Johannes Sixt --- compat/snprintf.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index bddfa5cdde..580966e56a 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -13,14 +13,15 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; - int ret; + int ret = -1; - ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); - if (ret != -1) { - /* Windows does not NUL-terminate if result fits exactly */ - str[ret] = 0; - return ret; + if (maxsize > 0) { + ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap); + /* Windows does not NUL-terminate if result fills buffer */ + str[maxsize-1] = 0; } + if (ret != -1) + return ret; s = NULL; if (maxsize < 128) From e77b5a4f7c0d3fef4b0f3d0996baaadf2529b440 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 1 Mar 2008 19:48:40 -0500 Subject: [PATCH 432/781] Add ANSI control code emulation for the Windows console This adds only the minimum necessary to keep git pull/merge's diffstat from wrapping. Notably absent is support for the K (erase) operation, and support for POSIX write. Cygwin does not need the WIN_ANSI define, since it has its own (more complete) ANSI emulation. Signed-off-by: Peter Harris --- Makefile | 6 + compat/winansi.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 7 ++ 3 files changed, 322 insertions(+) create mode 100644 compat/winansi.c diff --git a/Makefile b/Makefile index 0248759e9a..ea7f0418a1 100644 --- a/Makefile +++ b/Makefile @@ -695,6 +695,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_R_TO_GCC_LINKER = YesPlease INTERNAL_QSORT = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease + WIN_ANSI = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -940,6 +941,11 @@ ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif +ifdef WIN_ANSI + COMPAT_CFLAGS += -DWIN_ANSI + COMPAT_OBJS += compat/winansi.o +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif diff --git a/compat/winansi.c b/compat/winansi.c new file mode 100644 index 0000000000..86c3fd2db3 --- /dev/null +++ b/compat/winansi.c @@ -0,0 +1,309 @@ +#include +#include "../git-compat-util.h" + +/* + Functions to be wrapped: +*/ +#undef printf +#undef fputs + +/* + ANSI codes to implement: m, K +*/ + +static HANDLE console; +static WORD plain_attr; +static WORD attr; +static int negative; + +static void init(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + static int initialized = 0; + if (initialized) + return; + + console = GetStdHandle(STD_OUTPUT_HANDLE); + if (console == INVALID_HANDLE_VALUE) + console = NULL; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + attr = plain_attr = sbi.wAttributes; + negative = 0; + + initialized = 1; +} + + +#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) + +static void set_console_attr(void) +{ + WORD attributes = attr; + if (negative) { + attributes &= ~FOREGROUND_ALL; + attributes &= ~BACKGROUND_ALL; + + /* This could probably use a bitmask instead of a series of ifs */ + if (attr & FOREGROUND_RED) + attributes |= BACKGROUND_RED; + if (attr & FOREGROUND_GREEN) + attributes |= BACKGROUND_GREEN; + if (attr & FOREGROUND_BLUE) + attributes |= BACKGROUND_BLUE; + + if (attr & BACKGROUND_RED) + attributes |= FOREGROUND_RED; + if (attr & BACKGROUND_GREEN) + attributes |= FOREGROUND_GREEN; + if (attr & BACKGROUND_BLUE) + attributes |= FOREGROUND_BLUE; + } + SetConsoleTextAttribute(console, attributes); +} + +static const char *set_attr(const char *str) +{ + const char *func; + size_t len = strspn(str, "0123456789;"); + func = str + len; + + switch (*func) { + case 'm': + do { + long val = strtol(str, (char **)&str, 10); + switch (val) { + case 0: /* reset */ + attr = plain_attr; + negative = 0; + break; + case 1: /* bold */ + attr |= FOREGROUND_INTENSITY; + break; + case 2: /* faint */ + case 22: /* normal */ + attr &= ~FOREGROUND_INTENSITY; + break; + case 3: /* italic */ + /* Unsupported */ + break; + case 4: /* underline */ + case 21: /* double underline */ + /* Wikipedia says this flag does nothing */ + /* Furthermore, mingw doesn't define this flag + attr |= COMMON_LVB_UNDERSCORE; */ + break; + case 24: /* no underline */ + /* attr &= ~COMMON_LVB_UNDERSCORE; */ + break; + case 5: /* slow blink */ + case 6: /* fast blink */ + /* We don't have blink, but we do have background intensity */ + attr |= BACKGROUND_INTENSITY; + break; + case 25: /* no blink */ + attr &= ~BACKGROUND_INTENSITY; + break; + case 7: /* negative */ + negative = 1; + break; + case 27: /* positive */ + negative = 0; + break; + case 8: /* conceal */ + case 28: /* reveal */ + /* Unsupported */ + break; + case 30: /* Black */ + attr &= ~FOREGROUND_ALL; + break; + case 31: /* Red */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED; + break; + case 32: /* Green */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN; + break; + case 33: /* Yellow */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case 34: /* Blue */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_BLUE; + break; + case 35: /* Magenta */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case 36: /* Cyan */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 37: /* White */ + attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 38: /* Unknown */ + break; + case 39: /* reset */ + attr &= ~FOREGROUND_ALL; + attr |= (plain_attr & FOREGROUND_ALL); + break; + case 40: /* Black */ + attr &= ~BACKGROUND_ALL; + break; + case 41: /* Red */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED; + break; + case 42: /* Green */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN; + break; + case 43: /* Yellow */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case 44: /* Blue */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_BLUE; + break; + case 45: /* Magenta */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case 46: /* Cyan */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 47: /* White */ + attr |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 48: /* Unknown */ + break; + case 49: /* reset */ + attr &= ~BACKGROUND_ALL; + attr |= (plain_attr & BACKGROUND_ALL); + break; + default: + /* Unsupported code */ + break; + } + str++; + } while (*(str-1) == ';'); + + set_console_attr(); + break; + case 'K': + /* TODO */ + break; + default: + /* Unsupported code */ + break; + } + + return func + 1; +} + +static int ansi_emulate(const char *str, FILE *stream) +{ + int rv = 0; + const char *pos = str; + + while (*pos) { + pos = strstr(str, "\033["); + if (pos) { + size_t len = pos - str; + + if (len) { + size_t output_len = fwrite(str, 1, len, stream); + rv += output_len; + if (output_len < len) + return rv; + } + + str = pos + 2; + rv += 2; + + fflush(stream); + + pos = set_attr(str); + rv += pos - str; + str = pos; + } else { + rv += strlen(str); + fputs(str, stream); + return rv; + } + } + return rv; +} + +int git_fputs(const char *str, FILE *stream) +{ + int rv; + + init(); + + if (!console) + return fputs(str, stream); + + if (!isatty(fileno(stream))) + return fputs(str, stream); + + rv = ansi_emulate(str, stream); + + if (rv >= 0) + return 0; + else + return EOF; +} + +int git_printf(const char *format, ...) +{ + va_list list; + + char small_buf[256]; + char *buf = small_buf; + int len, rv; + + init(); + + if (!console) + goto abort; + + if (!isatty(fileno(stdout))) + goto abort; + + va_start(list, format); + len = vsnprintf(small_buf, sizeof(small_buf), format, list); + va_end(list); + + if (len > sizeof(small_buf) - 1) { + buf = malloc(len + 1); + if (!buf) + goto abort; + + va_start(list, format); + len = vsnprintf(buf, len + 1, format, list); + va_end(list); + } + + rv = ansi_emulate(buf, stdout); + + if (buf != small_buf) + free(buf); + return rv; + +abort: + va_start(list, format); + rv = vprintf(format, list); + va_end(list); + return rv; +} diff --git a/git-compat-util.h b/git-compat-util.h index 625e5e9c80..b810d710d7 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -495,4 +495,11 @@ void git_qsort(void *base, size_t nmemb, size_t size, # define FORCE_DIR_SET_GID 0 #endif +#ifdef WIN_ANSI +extern int git_fputs(const char *str, FILE *stream); +extern int git_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); +#define fputs git_fputs +#define printf(...) git_printf(__VA_ARGS__) +#endif + #endif From 3bff7cd86131f6fd39fa3918bdc2682bbfb74717 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 17 Jun 2008 14:42:25 +0200 Subject: [PATCH 433/781] t5505: fix pwd on Windows again The earlier commit b74e70b3 set $PWD to the particular 'pwd' form to use on Windows and *nix platforms. But this is not good for two reasons: $PWD has a predefined meaning to the shell (it influences pwd itself), and all occurrences of 'pwd' must be replaced by $PWD. This new fix now simply replaces 'pwd' by a shell function on Windows only, where we can be reasonably certain that 'bash' is in use, so that the function can call the builtin 'pwd' explicitly. Signed-off-by: Johannes Sixt --- t/t5505-remote.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 0c1cd17388..881efabd2b 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -108,12 +108,11 @@ test_expect_success 'remove remote' ' ' case $(uname -s) in -*MINGW*) PWD="pwd -W";; -*) PWD=pwd;; +*MINGW*) pwd() { builtin pwd -W; } ;; esac cat > test/expect << EOF * remote origin - URL: $($PWD)/one/.git + URL: $(pwd)/one/.git Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) From a58901c9bd2de40f6409a77a3f638106bdffaacd Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Sun, 15 Jun 2008 15:53:57 -0400 Subject: [PATCH 434/781] Fix custom ports with plink PuTTY requires -P while OpenSSH requires -p; if plink is detected as GIT_SSH, use the alternate flag. Signed-off-by: Edward Z. Yang Signed-off-by: Steffen Prohaska --- connect.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index 574f42fa47..11fa151eb3 100644 --- a/connect.c +++ b/connect.c @@ -596,14 +596,17 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; + /* be sure to increase this size if you add more args */ conn->argv = arg = xcalloc(6, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); + int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; if (port) { - *arg++ = "-p"; + /* P is for PuTTY, p is for OpenSSH */ + *arg++ = putty ? "-P" : "-p"; *arg++ = port; } *arg++ = host; From 33227548ba69857102b928e373a0e023ee59c7da Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Sun, 15 Jun 2008 15:53:57 -0400 Subject: [PATCH 435/781] Fix custom ports with plink (without debugging output) PuTTY requires -P while OpenSSH requires -p; if plink is detected as GIT_SSH, use the alternate flag. [spr: This commit switched off plink's debugging output, which was enabled by the previous commit. ] Signed-off-by: Edward Z. Yang Signed-off-by: Steffen Prohaska --- connect.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/connect.c b/connect.c index 6bd7ec9117..11fa151eb3 100644 --- a/connect.c +++ b/connect.c @@ -597,20 +597,13 @@ struct child_process *git_connect(int fd[2], const char *url_orig, conn->in = conn->out = -1; /* be sure to increase this size if you add more args */ - conn->argv = arg = xcalloc(8, sizeof(*arg)); + conn->argv = arg = xcalloc(6, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; - if (putty) { - /* stdin forwarding doesn't work, so give informative error messages - * (-v) and don't hang (-batch). - */ - *arg++ = "-batch"; - *arg++ = "-v"; - } if (port) { /* P is for PuTTY, p is for OpenSSH */ *arg++ = putty ? "-P" : "-p"; From 0720c64e569b173dc8d399fe868614be036c05f1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:50:01 +0200 Subject: [PATCH 436/781] Fixup whitespace in compat/regex.[ch] Signed-off-by: Johannes Sixt --- compat/regex.c | 3832 ++++++++++++++++++++++++------------------------ compat/regex.h | 102 +- 2 files changed, 1967 insertions(+), 1967 deletions(-) diff --git a/compat/regex.c b/compat/regex.c index 1d39e08d47..87b33e4669 100644 --- a/compat/regex.c +++ b/compat/regex.c @@ -49,7 +49,7 @@ /* This must be nonzero for the wordchar and notwordchar pattern commands in re_match_2. */ -#ifndef Sword +#ifndef Sword #define Sword 1 #endif @@ -146,8 +146,8 @@ init_syntax_once () use `alloca' instead of `malloc'. This is because using malloc in re_search* or re_match* could cause memory leaks when C-g is used in Emacs; also, malloc is slower and causes storage fragmentation. On - the other hand, malloc is more portable, and easier to debug. - + the other hand, malloc is more portable, and easier to debug. + Because we sometimes use alloca, some routines have to be macros, not functions -- `alloca'-allocated space disappears at the end of the function it is called in. */ @@ -172,7 +172,7 @@ init_syntax_once () #ifndef _AIX /* Already did AIX, up at the top. */ char *alloca (); #endif /* not _AIX */ -#endif /* not HAVE_ALLOCA_H */ +#endif /* not HAVE_ALLOCA_H */ #endif /* not __GNUC__ */ #endif /* not alloca */ @@ -223,108 +223,108 @@ typedef enum { no_op = 0, - /* Followed by one byte giving n, then by n literal bytes. */ + /* Followed by one byte giving n, then by n literal bytes. */ exactn = 1, - /* Matches any (more or less) character. */ + /* Matches any (more or less) character. */ anychar, - /* Matches any one char belonging to specified set. First - following byte is number of bitmap bytes. Then come bytes - for a bitmap saying which chars are in. Bits in each byte - are ordered low-bit-first. A character is in the set if its - bit is 1. A character too large to have a bit in the map is - automatically not in the set. */ + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ charset, - /* Same parameters as charset, but match any character that is - not one of those specified. */ + /* Same parameters as charset, but match any character that is + not one of those specified. */ charset_not, - /* Start remembering the text that is matched, for storing in a - register. Followed by one byte with the register number, in - the range 0 to one less than the pattern buffer's re_nsub - field. Then followed by one byte with the number of groups - inner to this one. (This last has to be part of the - start_memory only because we need it in the on_failure_jump - of re_match_2.) */ + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ start_memory, - /* Stop remembering the text that is matched and store it in a - memory register. Followed by one byte with the register - number, in the range 0 to one less than `re_nsub' in the - pattern buffer, and one byte with the number of inner groups, - just like `start_memory'. (We need the number of inner - groups here because we don't have any easy way of finding the - corresponding start_memory when we're at a stop_memory.) */ + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ stop_memory, - /* Match a duplicate of something remembered. Followed by one - byte containing the register number. */ + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ duplicate, - /* Fail unless at beginning of line. */ + /* Fail unless at beginning of line. */ begline, - /* Fail unless at end of line. */ + /* Fail unless at end of line. */ endline, - /* Succeeds if at beginning of buffer (if emacs) or at beginning - of string to be matched (if not). */ + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ begbuf, - /* Analogously, for end of buffer/string. */ + /* Analogously, for end of buffer/string. */ endbuf, - - /* Followed by two byte relative address to which to jump. */ - jump, + + /* Followed by two byte relative address to which to jump. */ + jump, /* Same as jump, but marks the end of an alternative. */ jump_past_alt, - /* Followed by two-byte relative address of place to resume at - in case of failure. */ + /* Followed by two-byte relative address of place to resume at + in case of failure. */ on_failure_jump, - - /* Like on_failure_jump, but pushes a placeholder instead of the - current string position when executed. */ + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ on_failure_keep_string_jump, - - /* Throw away latest failure point and then jump to following - two-byte relative address. */ + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ pop_failure_jump, - /* Change to pop_failure_jump if know won't have to backtrack to - match; otherwise change to jump. This is used to jump - back to the beginning of a repeat. If what follows this jump - clearly won't match what the repeat does, such that we can be - sure that there is no use backtracking out of repetitions - already matched, then we change it to a pop_failure_jump. - Followed by two-byte address. */ + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ maybe_pop_jump, - /* Jump to following two-byte address, and push a dummy failure - point. This failure point will be thrown away if an attempt - is made to use it for a failure. A `+' construct makes this - before the first repeat. Also used as an intermediary kind - of jump when compiling an alternative. */ + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ dummy_failure_jump, /* Push a dummy failure point and continue. Used at the end of alternatives. */ push_dummy_failure, - /* Followed by two-byte relative address and two-byte number n. - After matching N times, jump to the address upon failure. */ + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ succeed_n, - /* Followed by two-byte relative address, and two-byte number n. - Jump to the address N times, then fail. */ + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ jump_n, - /* Set the following two-byte relative address to the - subsequent two-byte number. The address *includes* the two - bytes of number. */ + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ set_number_at, wordchar, /* Matches any word-constituent character. */ @@ -342,7 +342,7 @@ typedef enum after_dot, /* Succeeds if after point. */ /* Matches any character whose syntax is specified. Followed by - a byte which contains a syntax code, e.g., Sword. */ + a byte which contains a syntax code, e.g., Sword. */ syntaxspec, /* Matches any character whose syntax is not that specified. */ @@ -385,7 +385,7 @@ extract_number (dest, source) int *dest; unsigned char *source; { - int temp = SIGN_EXTEND_CHAR (*(source + 1)); + int temp = SIGN_EXTEND_CHAR (*(source + 1)); *dest = *source & 0377; *dest += temp << 8; } @@ -411,7 +411,7 @@ static void extract_number_and_incr (destination, source) int *destination; unsigned char **source; -{ +{ extract_number (destination, *source); *source += 2; } @@ -460,27 +460,27 @@ print_fastmap (fastmap) char *fastmap; { unsigned was_a_range = 0; - unsigned i = 0; - + unsigned i = 0; + while (i < (1 << BYTEWIDTH)) { if (fastmap[i++]) { was_a_range = 0; - printchar (i - 1); - while (i < (1 << BYTEWIDTH) && fastmap[i]) - { - was_a_range = 1; - i++; - } + printchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } if (was_a_range) - { - printf ("-"); - printchar (i - 1); - } - } + { + printf ("-"); + printchar (i - 1); + } + } } - putchar ('\n'); + putchar ('\n'); } @@ -501,36 +501,36 @@ print_partial_compiled_pattern (start, end) printf ("(null)\n"); return; } - + /* Loop over pattern commands. */ while (p < pend) { switch ((re_opcode_t) *p++) { - case no_op: - printf ("/no_op"); - break; + case no_op: + printf ("/no_op"); + break; case exactn: mcnt = *p++; - printf ("/exactn/%d", mcnt); - do + printf ("/exactn/%d", mcnt); + do { - putchar ('/'); + putchar ('/'); printchar (*p++); - } - while (--mcnt); - break; + } + while (--mcnt); + break; case start_memory: - mcnt = *p++; - printf ("/start_memory/%d/%d", mcnt, *p++); - break; + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; case stop_memory: - mcnt = *p++; + mcnt = *p++; printf ("/stop_memory/%d/%d", mcnt, *p++); - break; + break; case duplicate: printf ("/duplicate/%d", *p++); @@ -541,131 +541,131 @@ print_partial_compiled_pattern (start, end) break; case charset: - case charset_not: - { - register int c; + case charset_not: + { + register int c; - printf ("/charset%s", - (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); - - assert (p + *p < pend); + printf ("/charset%s", + (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); - for (c = 0; c < *p; c++) - { - unsigned bit; - unsigned char map_byte = p[1 + c]; - - putchar ('/'); + assert (p + *p < pend); + + for (c = 0; c < *p; c++) + { + unsigned bit; + unsigned char map_byte = p[1 + c]; + + putchar ('/'); for (bit = 0; bit < BYTEWIDTH; bit++) - if (map_byte & (1 << bit)) - printchar (c * BYTEWIDTH + bit); - } + if (map_byte & (1 << bit)) + printchar (c * BYTEWIDTH + bit); + } p += 1 + *p; break; } case begline: printf ("/begline"); - break; + break; case endline: - printf ("/endline"); - break; + printf ("/endline"); + break; case on_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_jump/0/%d", mcnt); - break; + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump/0/%d", mcnt); + break; case on_failure_keep_string_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_keep_string_jump/0/%d", mcnt); - break; + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump/0/%d", mcnt); + break; case dummy_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/dummy_failure_jump/0/%d", mcnt); - break; + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump/0/%d", mcnt); + break; case push_dummy_failure: - printf ("/push_dummy_failure"); - break; - - case maybe_pop_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/maybe_pop_jump/0/%d", mcnt); + printf ("/push_dummy_failure"); break; - case pop_failure_jump: + case maybe_pop_jump: extract_number_and_incr (&mcnt, &p); - printf ("/pop_failure_jump/0/%d", mcnt); - break; - - case jump_past_alt: - extract_number_and_incr (&mcnt, &p); - printf ("/jump_past_alt/0/%d", mcnt); - break; - - case jump: - extract_number_and_incr (&mcnt, &p); - printf ("/jump/0/%d", mcnt); + printf ("/maybe_pop_jump/0/%d", mcnt); break; - case succeed_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); - break; - - case jump_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); - break; - - case set_number_at: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); - break; - - case wordbound: + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump/0/%d", mcnt); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt/0/%d", mcnt); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump/0/%d", mcnt); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); + break; + + case wordbound: printf ("/wordbound"); break; case notwordbound: printf ("/notwordbound"); - break; + break; case wordbeg: printf ("/wordbeg"); break; - + case wordend: printf ("/wordend"); - + #ifdef emacs case before_dot: printf ("/before_dot"); - break; + break; case at_dot: printf ("/at_dot"); - break; + break; case after_dot: printf ("/after_dot"); - break; + break; case syntaxspec: - printf ("/syntaxspec"); + printf ("/syntaxspec"); mcnt = *p++; printf ("/%d", mcnt); - break; - + break; + case notsyntaxspec: - printf ("/notsyntaxspec"); + printf ("/notsyntaxspec"); mcnt = *p++; printf ("/%d", mcnt); break; @@ -673,22 +673,22 @@ print_partial_compiled_pattern (start, end) case wordchar: printf ("/wordchar"); - break; - + break; + case notwordchar: printf ("/notwordchar"); - break; + break; case begbuf: printf ("/begbuf"); - break; + break; case endbuf: printf ("/endbuf"); - break; + break; - default: - printf ("?%d", *(p-1)); + default: + printf ("?%d", *(p-1)); } } printf ("/\n"); @@ -731,21 +731,21 @@ print_double_string (where, string1, size1, string2, size2) int size2; { unsigned this_char; - + if (where == NULL) printf ("(null)"); else { if (FIRST_STRING_P (where)) - { - for (this_char = where - string1; this_char < size1; this_char++) - printchar (string1[this_char]); + { + for (this_char = where - string1; this_char < size1; this_char++) + printchar (string1[this_char]); - where = string2; - } + where = string2; + } for (this_char = where - string2; this_char < size2; this_char++) - printchar (string2[this_char]); + printchar (string2[this_char]); } } @@ -782,7 +782,7 @@ re_set_syntax (syntax) reg_syntax_t syntax; { reg_syntax_t ret = re_syntax_options; - + re_syntax_options = syntax; return ret; } @@ -818,7 +818,7 @@ static boolean at_begline_loc_p (), at_endline_loc_p (); static boolean group_in_compile_stack (); static reg_errcode_t compile_range (); -/* Fetch the next character in the uncompiled pattern---translating it +/* Fetch the next character in the uncompiled pattern---translating it if necessary. Also cast from a signed character in the constant string passed to us by the user to an unsigned char that we can use as an array index (in, e.g., `translate'). */ @@ -925,14 +925,14 @@ static reg_errcode_t compile_range (); /* If the buffer moved, move all the pointers into it. */ \ if (old_buffer != bufp->buffer) \ { \ - b = (b - old_buffer) + bufp->buffer; \ - begalt = (begalt - old_buffer) + bufp->buffer; \ - if (fixup_alt_jump) \ - fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ - if (laststart) \ - laststart = (laststart - old_buffer) + bufp->buffer; \ - if (pending_exact) \ - pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ } \ } while (0) @@ -958,7 +958,7 @@ typedef struct pattern_offset_t begalt_offset; pattern_offset_t fixup_alt_jump; pattern_offset_t inner_group_offset; - pattern_offset_t laststart_offset; + pattern_offset_t laststart_offset; regnum_t regnum; } compile_stack_elt_t; @@ -992,16 +992,16 @@ typedef struct { \ PATFETCH (c); \ while (ISDIGIT (c)) \ - { \ - if (num < 0) \ - num = 0; \ - num = num * 10 + c - '0'; \ - if (p == pend) \ - break; \ - PATFETCH (c); \ - } \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ } \ - } + } #define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ @@ -1027,7 +1027,7 @@ typedef struct `fastmap_accurate' is zero; `re_nsub' is the number of subexpressions in PATTERN; `not_bol' and `not_eol' are zero; - + The `fastmap' and `newline_anchor' fields are neither examined nor set. */ @@ -1042,20 +1042,20 @@ regex_compile (pattern, size, syntax, bufp) `char *' (i.e., signed), we declare these variables as unsigned, so they can be reliably used as array indices. */ register unsigned char c, c1; - + /* A random tempory spot in PATTERN. */ const char *p1; /* Points to the end of the buffer, where we should append. */ register unsigned char *b; - + /* Keeps track of unclosed groups. */ compile_stack_type compile_stack; /* Points to the current (ending) position in the pattern. */ const char *p = pattern; const char *pend = pattern + size; - + /* How to translate the characters in the pattern. */ char *translate = bufp->translate; @@ -1076,7 +1076,7 @@ regex_compile (pattern, size, syntax, bufp) /* Place in the uncompiled pattern (i.e., the {) to which to go back if the interval is invalid. */ const char *beg_interval; - + /* Address of the place where a forward jump should go to the end of the containing expression. Each alternative of an `or' -- except the last -- ends with a forward jump of this sort. */ @@ -1092,9 +1092,9 @@ regex_compile (pattern, size, syntax, bufp) if (debug) { unsigned debug_count; - + for (debug_count = 0; debug_count < size; debug_count++) - printchar (pattern[debug_count]); + printchar (pattern[debug_count]); putchar ('\n'); } #endif /* DEBUG */ @@ -1116,9 +1116,9 @@ regex_compile (pattern, size, syntax, bufp) printer (for debugging) will think there's no pattern. We reset it at the end. */ bufp->used = 0; - + /* Always count groups, whether or not bufp->no_sub is set. */ - bufp->re_nsub = 0; + bufp->re_nsub = 0; #if !defined (emacs) && !defined (SYNTAX_TABLE) /* Initialize the syntax table. */ @@ -1129,14 +1129,14 @@ regex_compile (pattern, size, syntax, bufp) { if (bufp->buffer) { /* If zero allocated, but buffer is non-null, try to realloc - enough space. This loses if buffer's address is bogus, but - that is the user's responsibility. */ - RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); - } + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } else - { /* Caller did not allocate a buffer. Do it for them. */ - bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); - } + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } if (!bufp->buffer) return REG_ESPACE; bufp->allocated = INIT_BUF_SIZE; @@ -1150,870 +1150,870 @@ regex_compile (pattern, size, syntax, bufp) PATFETCH (c); switch (c) - { - case '^': - { - if ( /* If at start of pattern, it's an operator. */ - p == pattern + 1 - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's come before. */ - || at_begline_loc_p (pattern, p, syntax)) - BUF_PUSH (begline); - else - goto normal_char; - } - break; + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; - case '$': - { - if ( /* If at end of pattern, it's an operator. */ - p == pend - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's next. */ - || at_endline_loc_p (p, pend, syntax)) - BUF_PUSH (endline); - else - goto normal_char; - } - break; + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; case '+': - case '?': - if ((syntax & RE_BK_PLUS_QM) - || (syntax & RE_LIMITED_OPS)) - goto normal_char; - handle_plus: - case '*': - /* If there is no previous pattern... */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - return REG_BADRPT; - else if (!(syntax & RE_CONTEXT_INDEP_OPS)) - goto normal_char; - } + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } - { - /* Are we optimizing this jump? */ - boolean keep_string_p = false; - - /* 1 means zero (many) matches is allowed. */ - char zero_times_ok = 0, many_times_ok = 0; + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; - /* If there is a sequence of repetition chars, collapse it - down to just one (the right one). We can't combine - interval operators with these because of, e.g., `a{2}*', - which should only match an even number of `a's. */ + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; - for (;;) - { - zero_times_ok |= c != '+'; - many_times_ok |= c != '?'; + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ - if (p == pend) - break; + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; - PATFETCH (c); + if (p == pend) + break; - if (c == '*' - || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) - ; + PATFETCH (c); - else if (syntax & RE_BK_PLUS_QM && c == '\\') - { - if (p == pend) return REG_EESCAPE; + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; - PATFETCH (c1); - if (!(c1 == '+' || c1 == '?')) - { - PATUNFETCH; - PATUNFETCH; - break; - } + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) return REG_EESCAPE; - c = c1; - } - else - { - PATUNFETCH; - break; - } + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } - /* If we get here, we found another repeat character. */ - } + c = c1; + } + else + { + PATUNFETCH; + break; + } - /* Star, etc. applied to an empty pattern is equivalent - to an empty pattern. */ - if (!laststart) - break; + /* If we get here, we found another repeat character. */ + } - /* Now we know whether or not zero matches is allowed - and also whether or not two or more matches is allowed. */ - if (many_times_ok) - { /* More than one repetition is allowed, so put in at the - end a backward relative jump from `b' to before the next - jump we're going to put in below (which jumps from - laststart to after this jump). + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; - But if we are at the `*' in the exact sequence `.*\n', - insert an unconditional jump backwards to the ., - instead of the beginning of the loop. This way we only - push a failure point once, instead of every time - through the loop. */ - assert (p - 1 > pattern); + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). - /* Allocate the space for the jump. */ - GET_BUFFER_SPACE (3); + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); - /* We know we are not at the first character of the pattern, - because laststart was nonzero. And we've already - incremented `p', by the way, to be the character after - the `*'. Do we have to do something analogous here - for null bytes, because of RE_DOT_NOT_NULL? */ - if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') && zero_times_ok - && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') - && !(syntax & RE_DOT_NEWLINE)) - { /* We have .*\n. */ - STORE_JUMP (jump, b, laststart); - keep_string_p = true; - } - else - /* Anything else. */ - STORE_JUMP (maybe_pop_jump, b, laststart - 3); + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); - /* We've added more stuff to the buffer. */ - b += 3; - } + /* We've added more stuff to the buffer. */ + b += 3; + } - /* On failure, jump from laststart to b + 3, which will be the - end of the buffer after this jump is inserted. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump - : on_failure_jump, - laststart, b + 3); - pending_exact = 0; - b += 3; + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; - if (!zero_times_ok) - { - /* At least one repetition is required, so insert a - `dummy_failure_jump' before the initial - `on_failure_jump' instruction of the loop. This - effects a skip over that instruction the first time - we hit that loop. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); - b += 3; - } - } + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } break; case '.': - laststart = b; - BUF_PUSH (anychar); - break; + laststart = b; + BUF_PUSH (anychar); + break; - case '[': - { - boolean had_char_class = false; + case '[': + { + boolean had_char_class = false; - if (p == pend) return REG_EBRACK; + if (p == pend) return REG_EBRACK; - /* Ensure that we have enough space to push a charset: the - opcode, the length count, and the bitset; 34 bytes in all. */ + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ GET_BUFFER_SPACE (34); - laststart = b; + laststart = b; - /* We test `*p == '^' twice, instead of using an if - statement, so we only need one BUF_PUSH. */ - BUF_PUSH (*p == '^' ? charset_not : charset); - if (*p == '^') - p++; + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; - /* Remember the first position in the bracket expression. */ - p1 = p; + /* Remember the first position in the bracket expression. */ + p1 = p; - /* Push the number of bytes in the bitmap. */ - BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); - /* Clear the whole map. */ - bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); - /* charset_not matches newline according to a syntax bit. */ - if ((re_opcode_t) b[-2] == charset_not - && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) - SET_LIST_BIT ('\n'); + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); - /* Read in characters and ranges, setting map bits. */ - for (;;) - { - if (p == pend) return REG_EBRACK; + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) return REG_EBRACK; - PATFETCH (c); + PATFETCH (c); - /* \ might escape characters inside [...] and [^...]. */ - if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') - { - if (p == pend) return REG_EESCAPE; + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) return REG_EESCAPE; - PATFETCH (c1); - SET_LIST_BIT (c1); - continue; - } + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } - /* Could be the end of the bracket expression. If it's - not (i.e., when the bracket expression is `[]' so - far), the ']' character bit gets set way below. */ - if (c == ']' && p != p1 + 1) - break; + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; - /* Look ahead to see if it's a range when the last thing - was a character class. */ - if (had_char_class && c == '-' && *p != ']') - return REG_ERANGE; + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + return REG_ERANGE; - /* Look ahead to see if it's a range when the last thing - was a character: if this is a hyphen not at the - beginning or the end of a list, then it's the range - operator. */ - if (c == '-' - && !(p - 2 >= pattern && p[-2] == '[') - && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') - && *p != ']') - { - reg_errcode_t ret - = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) return ret; - } + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } - else if (p[0] == '-' && p[1] != ']') - { /* This handles ranges made up of characters only. */ - reg_errcode_t ret; + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; /* Move past the `-'. */ - PATFETCH (c1); - - ret = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) return ret; - } + PATFETCH (c1); - /* See if we're at the beginning of a possible character - class. */ + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } - else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') - { /* Leave room for the null. */ - char str[CHAR_CLASS_MAX_LENGTH + 1]; + /* See if we're at the beginning of a possible character + class. */ - PATFETCH (c); - c1 = 0; + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; - /* If pattern is `[[:'. */ - if (p == pend) return REG_EBRACK; + PATFETCH (c); + c1 = 0; - for (;;) - { - PATFETCH (c); - if (c == ':' || c == ']' || p == pend - || c1 == CHAR_CLASS_MAX_LENGTH) - break; - str[c1++] = c; - } - str[c1] = '\0'; + /* If pattern is `[[:'. */ + if (p == pend) return REG_EBRACK; - /* If isn't a word bracketed by `[:' and:`]': - undo the ending character, the letters, and leave - the leading `:' and `[' (but set bits for them). */ - if (c == ':' && *p == ']') - { - int ch; - boolean is_alnum = STREQ (str, "alnum"); - boolean is_alpha = STREQ (str, "alpha"); - boolean is_blank = STREQ (str, "blank"); - boolean is_cntrl = STREQ (str, "cntrl"); - boolean is_digit = STREQ (str, "digit"); - boolean is_graph = STREQ (str, "graph"); - boolean is_lower = STREQ (str, "lower"); - boolean is_print = STREQ (str, "print"); - boolean is_punct = STREQ (str, "punct"); - boolean is_space = STREQ (str, "space"); - boolean is_upper = STREQ (str, "upper"); - boolean is_xdigit = STREQ (str, "xdigit"); - - if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; + for (;;) + { + PATFETCH (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; - /* Throw away the ] at the end of the character - class. */ - PATFETCH (c); + /* If isn't a word bracketed by `[:' and:`]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); - if (p == pend) return REG_EBRACK; + if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; - for (ch = 0; ch < 1 << BYTEWIDTH; ch++) - { - if ( (is_alnum && ISALNUM (ch)) - || (is_alpha && ISALPHA (ch)) - || (is_blank && ISBLANK (ch)) - || (is_cntrl && ISCNTRL (ch)) - || (is_digit && ISDIGIT (ch)) - || (is_graph && ISGRAPH (ch)) - || (is_lower && ISLOWER (ch)) - || (is_print && ISPRINT (ch)) - || (is_punct && ISPUNCT (ch)) - || (is_space && ISSPACE (ch)) - || (is_upper && ISUPPER (ch)) - || (is_xdigit && ISXDIGIT (ch))) - SET_LIST_BIT (ch); - } - had_char_class = true; - } - else - { - c1++; - while (c1--) - PATUNFETCH; - SET_LIST_BIT ('['); - SET_LIST_BIT (':'); - had_char_class = false; - } - } - else - { - had_char_class = false; - SET_LIST_BIT (c); - } - } + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); - /* Discard any (non)matching list bytes that are all 0 at the - end of the map. Decrease the map-length byte too. */ - while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) - b[-1]--; - b += b[-1]; - } - break; + if (p == pend) return REG_EBRACK; + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch)) + || (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch)) + || (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; case '(': - if (syntax & RE_NO_BK_PARENS) - goto handle_open; - else - goto normal_char; + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; - case ')': - if (syntax & RE_NO_BK_PARENS) - goto handle_close; - else - goto normal_char; + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; - case '\n': - if (syntax & RE_NEWLINE_ALT) - goto handle_alt; - else - goto normal_char; + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; case '|': - if (syntax & RE_NO_BK_VBAR) - goto handle_alt; - else - goto normal_char; + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; - case '{': - if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) - goto handle_interval; - else - goto normal_char; + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; - case '\\': - if (p == pend) return REG_EESCAPE; + case '\\': + if (p == pend) return REG_EESCAPE; - /* Do not translate the character after the \, so that we can - distinguish, e.g., \B from \b, even if we normally would - translate, e.g., B to b. */ - PATFETCH_RAW (c); + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); - switch (c) - { - case '(': - if (syntax & RE_NO_BK_PARENS) - goto normal_backslash; + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; - handle_open: - bufp->re_nsub++; - regnum++; + handle_open: + bufp->re_nsub++; + regnum++; - if (COMPILE_STACK_FULL) - { - RETALLOC (compile_stack.stack, compile_stack.size << 1, - compile_stack_elt_t); - if (compile_stack.stack == NULL) return REG_ESPACE; + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; - compile_stack.size <<= 1; - } + compile_stack.size <<= 1; + } - /* These are the values to restore when we hit end of this - group. They are all relative offsets, so that if the - whole pattern moves because of realloc, they will still - be valid. */ - COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; - COMPILE_STACK_TOP.fixup_alt_jump - = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; - COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; - COMPILE_STACK_TOP.regnum = regnum; + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; - /* We will eventually replace the 0 with the number of - groups inner to this one. But do not push a - start_memory for groups beyond the last one we can - represent in the compiled pattern. */ - if (regnum <= MAX_REGNUM) - { - COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; - BUF_PUSH_3 (start_memory, regnum, 0); - } - - compile_stack.avail++; + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } - fixup_alt_jump = 0; - laststart = 0; - begalt = b; + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; /* If we've reached MAX_REGNUM groups, then this open won't actually generate any code, so we'll have to clear pending_exact explicitly. */ pending_exact = 0; - break; + break; - case ')': - if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; - if (COMPILE_STACK_EMPTY) - { - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_backslash; - else - return REG_ERPAREN; - } + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + return REG_ERPAREN; + } - handle_close: - if (fixup_alt_jump) - { /* Push a dummy failure point at the end of the - alternative for a possible future - `pop_failure_jump' to pop. See comments at - `push_dummy_failure' in `re_match_2'. */ - BUF_PUSH (push_dummy_failure); - - /* We allocated space for this jump when we assigned - to `fixup_alt_jump', in the `handle_alt' case below. */ - STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); - } + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); - /* See similar code for backslashed left paren above. */ - if (COMPILE_STACK_EMPTY) - { - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_char; - else - return REG_ERPAREN; - } + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } - /* Since we just checked for an empty stack above, this - ``can't happen''. */ - assert (compile_stack.avail != 0); - { - /* We don't just want to restore into `regnum', because - later groups should continue to be numbered higher, - as in `(ab)c(de)' -- the second group is #2. */ - regnum_t this_group_regnum; + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + return REG_ERPAREN; + } - compile_stack.avail--; - begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; - fixup_alt_jump - = COMPILE_STACK_TOP.fixup_alt_jump - ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 - : 0; - laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; - this_group_regnum = COMPILE_STACK_TOP.regnum; + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; /* If we've reached MAX_REGNUM groups, then this open won't actually generate any code, so we'll have to clear pending_exact explicitly. */ pending_exact = 0; - /* We're at the end of the group, so now we know how many - groups were inside this one. */ - if (this_group_regnum <= MAX_REGNUM) - { - unsigned char *inner_group_loc - = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; - - *inner_group_loc = regnum - this_group_regnum; - BUF_PUSH_3 (stop_memory, this_group_regnum, - regnum - this_group_regnum); - } - } - break; + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; - case '|': /* `\|'. */ - if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) - goto normal_backslash; - handle_alt: - if (syntax & RE_LIMITED_OPS) - goto normal_char; + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; - /* Insert before the previous alternative a jump which - jumps to this alternative if the former fails. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (on_failure_jump, begalt, b + 6); - pending_exact = 0; - b += 3; + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; - /* The alternative before this one has a jump after it - which gets executed if it gets matched. Adjust that - jump so it will jump to this alternative's analogous - jump (put in below, which in turn will jump to the next - (if any) alternative's such jump, etc.). The last such - jump jumps to the correct final destination. A picture: - _____ _____ - | | | | - | v | v - a | b | c + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c - If we are at `b', then fixup_alt_jump right now points to a - three-byte space after `a'. We'll put in the jump, set - fixup_alt_jump to right after `b', and leave behind three - bytes which we'll fill in when we get to after `c'. */ + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ - if (fixup_alt_jump) - STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - /* Mark and leave space for a jump after this alternative, - to be filled in later either by next alternative or - when know we're at the end of a series of alternatives. */ - fixup_alt_jump = b; - GET_BUFFER_SPACE (3); - b += 3; + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; - laststart = 0; - begalt = b; - break; + laststart = 0; + begalt = b; + break; - case '{': - /* If \{ is a literal. */ - if (!(syntax & RE_INTERVALS) - /* If we're at `\{' and it's not the open-interval - operator. */ - || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - || (p - 2 == pattern && p == pend)) - goto normal_backslash; + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; - handle_interval: - { - /* If got here, then the syntax allows intervals. */ + handle_interval: + { + /* If got here, then the syntax allows intervals. */ - /* At least (most) this many matches must be made. */ - int lower_bound = -1, upper_bound = -1; + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; - beg_interval = p - 1; + beg_interval = p - 1; - if (p == pend) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_EBRACE; - } + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_EBRACE; + } - GET_UNSIGNED_NUMBER (lower_bound); + GET_UNSIGNED_NUMBER (lower_bound); - if (c == ',') - { - GET_UNSIGNED_NUMBER (upper_bound); - if (upper_bound < 0) upper_bound = RE_DUP_MAX; - } - else - /* Interval such as `{1}' => match exactly once. */ - upper_bound = lower_bound; + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; - if (lower_bound < 0 || upper_bound > RE_DUP_MAX - || lower_bound > upper_bound) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_BADBR; - } + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } - if (!(syntax & RE_NO_BK_BRACES)) - { - if (c != '\\') return REG_EBRACE; + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') return REG_EBRACE; - PATFETCH (c); - } + PATFETCH (c); + } - if (c != '}') - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - return REG_BADBR; - } + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } - /* We just parsed a valid interval. */ + /* We just parsed a valid interval. */ - /* If it's invalid to have no preceding re. */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - return REG_BADRPT; - else if (syntax & RE_CONTEXT_INDEP_OPS) - laststart = b; - else - goto unfetch_interval; - } + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } - /* If the upper bound is zero, don't want to succeed at - all; jump from `laststart' to `b + 3', which will be - the end of the buffer after we insert the jump. */ - if (upper_bound == 0) - { - GET_BUFFER_SPACE (3); - INSERT_JUMP (jump, laststart, b + 3); - b += 3; - } + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } - /* Otherwise, we have a nontrivial interval. When - we're all done, the pattern will look like: - set_number_at - set_number_at - succeed_n - - jump_n - (The upper bound and `jump_n' are omitted if - `upper_bound' is 1, though.) */ - else - { /* If the upper bound is > 1, we need to insert - more at the end of the loop. */ - unsigned nbytes = 10 + (upper_bound > 1) * 10; + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; - GET_BUFFER_SPACE (nbytes); + GET_BUFFER_SPACE (nbytes); - /* Initialize lower bound of the `succeed_n', even - though it will be set during matching by its - attendant `set_number_at' (inserted next), - because `re_compile_fastmap' needs to know. - Jump to the `jump_n' we might insert below. */ - INSERT_JUMP2 (succeed_n, laststart, - b + 5 + (upper_bound > 1) * 5, - lower_bound); - b += 5; + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; - /* Code to initialize the lower bound. Insert - before the `succeed_n'. The `5' is the last two - bytes of this `set_number_at', plus 3 bytes of - the following `succeed_n'. */ - insert_op2 (set_number_at, laststart, 5, lower_bound, b); - b += 5; + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; - if (upper_bound > 1) - { /* More than one repetition is allowed, so - append a backward jump to the `succeed_n' - that starts this interval. - - When we've reached this during matching, - we'll have matched the interval once, so - jump back only `upper_bound - 1' times. */ - STORE_JUMP2 (jump_n, b, laststart + 5, - upper_bound - 1); - b += 5; + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. - /* The location we want to set is the second - parameter of the `jump_n'; that is `b-2' as - an absolute address. `laststart' will be - the `set_number_at' we're about to insert; - `laststart+3' the number to set, the source - for the relative address. But we are - inserting into the middle of the pattern -- - so everything is getting moved up by 5. - Conclusion: (b - 2) - (laststart + 3) + 5, - i.e., b - laststart. - - We insert this at the beginning of the loop - so that if we fail during matching, we'll - reinitialize the bounds. */ - insert_op2 (set_number_at, laststart, b - laststart, - upper_bound - 1, b); - b += 5; - } - } - pending_exact = 0; - beg_interval = NULL; - } - break; + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; - unfetch_interval: - /* If an invalid interval, match the characters as literals. */ - assert (beg_interval); - p = beg_interval; - beg_interval = NULL; + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. - /* normal_char and normal_backslash need `c'. */ - PATFETCH (c); + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; - if (!(syntax & RE_NO_BK_BRACES)) - { - if (p > pattern && p[-1] == '\\') - goto normal_backslash; - } - goto normal_char; + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; #ifdef emacs - /* There is no way to specify the before_dot and after_dot - operators. rms says this is ok. --karl */ - case '=': - BUF_PUSH (at_dot); - break; + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; - case 's': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); - break; + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; - case 'S': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); - break; + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; #endif /* emacs */ - case 'w': - laststart = b; - BUF_PUSH (wordchar); - break; + case 'w': + laststart = b; + BUF_PUSH (wordchar); + break; - case 'W': - laststart = b; - BUF_PUSH (notwordchar); - break; + case 'W': + laststart = b; + BUF_PUSH (notwordchar); + break; - case '<': - BUF_PUSH (wordbeg); - break; + case '<': + BUF_PUSH (wordbeg); + break; - case '>': - BUF_PUSH (wordend); - break; + case '>': + BUF_PUSH (wordend); + break; - case 'b': - BUF_PUSH (wordbound); - break; + case 'b': + BUF_PUSH (wordbound); + break; - case 'B': - BUF_PUSH (notwordbound); - break; + case 'B': + BUF_PUSH (notwordbound); + break; - case '`': - BUF_PUSH (begbuf); - break; + case '`': + BUF_PUSH (begbuf); + break; - case '\'': - BUF_PUSH (endbuf); - break; + case '\'': + BUF_PUSH (endbuf); + break; - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - if (syntax & RE_NO_BK_REFS) - goto normal_char; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; - c1 = c - '0'; + c1 = c - '0'; - if (c1 > regnum) - return REG_ESUBREG; + if (c1 > regnum) + return REG_ESUBREG; - /* Can't back reference to a subexpression if inside of it. */ - if (group_in_compile_stack (compile_stack, c1)) - goto normal_char; + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, c1)) + goto normal_char; - laststart = b; - BUF_PUSH_2 (duplicate, c1); - break; + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; - case '+': - case '?': - if (syntax & RE_BK_PLUS_QM) - goto handle_plus; - else - goto normal_backslash; + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; - default: - normal_backslash: - /* You might think it would be useful for \ to mean - not to translate; but if we don't translate it - it will never match anything. */ - c = TRANSLATE (c); - goto normal_char; - } - break; + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; default: - /* Expects the character in `c'. */ + /* Expects the character in `c'. */ normal_char: /* If no exactn currently being built. */ - if (!pending_exact + if (!pending_exact - /* If last exactn not at current position. */ - || pending_exact + *pending_exact + 1 != b - - /* We have only one byte following the exactn for the count. */ + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ || *pending_exact == (1 << BYTEWIDTH) - 1 - /* If followed by a repetition operator. */ - || *p == '*' || *p == '^' + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' || ((syntax & RE_BK_PLUS_QM) ? *p == '\\' && (p[1] == '+' || p[1] == '?') : (*p == '+' || *p == '?')) || ((syntax & RE_INTERVALS) - && ((syntax & RE_NO_BK_BRACES) + && ((syntax & RE_NO_BK_BRACES) ? *p == '{' - : (p[0] == '\\' && p[1] == '{')))) + : (p[0] == '\\' && p[1] == '{')))) { /* Start building a new exactn. */ - - laststart = b; + + laststart = b; BUF_PUSH_2 (exactn, 0); pending_exact = b - 1; - } - + } + BUF_PUSH (c); - (*pending_exact)++; + (*pending_exact)++; break; - } /* switch (c) */ + } /* switch (c) */ } /* while p != pend */ - + /* Through the pattern now. */ - + if (fixup_alt_jump) STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - if (!COMPILE_STACK_EMPTY) + if (!COMPILE_STACK_EMPTY) return REG_EPAREN; free (compile_stack.stack); @@ -2069,14 +2069,14 @@ insert_op1 (op, loc, arg, end) re_opcode_t op; unsigned char *loc; int arg; - unsigned char *end; + unsigned char *end; { register unsigned char *pfrom = end; register unsigned char *pto = end + 3; while (pfrom != loc) *--pto = *--pfrom; - + store_op1 (op, loc, arg); } @@ -2088,14 +2088,14 @@ insert_op2 (op, loc, arg1, arg2, end) re_opcode_t op; unsigned char *loc; int arg1, arg2; - unsigned char *end; + unsigned char *end; { register unsigned char *pfrom = end; register unsigned char *pto = end + 5; while (pfrom != loc) *--pto = *--pfrom; - + store_op2 (op, loc, arg1, arg2); } @@ -2111,7 +2111,7 @@ at_begline_loc_p (pattern, p, syntax) { const char *prev = p - 2; boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; - + return /* After a subexpression? */ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) @@ -2131,18 +2131,18 @@ at_endline_loc_p (p, pend, syntax) const char *next = p; boolean next_backslash = *next == '\\'; const char *next_next = p + 1 < pend ? p + 1 : NULL; - + return /* Before a subexpression? */ (syntax & RE_NO_BK_PARENS ? *next == ')' - : next_backslash && next_next && *next_next == ')') + : next_backslash && next_next && *next_next == ')') /* Before an alternative? */ || (syntax & RE_NO_BK_VBAR ? *next == '|' - : next_backslash && next_next && *next_next == '|'); + : next_backslash && next_next && *next_next == '|'); } -/* Returns true if REGNUM is in one of COMPILE_STACK's elements and +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and false if it's not. */ static boolean @@ -2152,8 +2152,8 @@ group_in_compile_stack (compile_stack, regnum) { int this_element; - for (this_element = compile_stack.avail - 1; - this_element >= 0; + for (this_element = compile_stack.avail - 1; + this_element >= 0; this_element--) if (compile_stack.stack[this_element].regnum == regnum) return true; @@ -2167,9 +2167,9 @@ group_in_compile_stack (compile_stack, regnum) starting character is in `P[-2]'. (`P[-1]' is the character `-'.) Then we set the translation of all bits between the starting and ending characters (inclusive) in the compiled pattern B. - + Return an error code. - + We use these short variable names so we can use the same macros as `regex_compile' itself. */ @@ -2184,7 +2184,7 @@ compile_range (p_ptr, pend, translate, syntax, b) const char *p = *p_ptr; int range_start, range_end; - + if (p == pend) return REG_ERANGE; @@ -2193,7 +2193,7 @@ compile_range (p_ptr, pend, translate, syntax, b) is set, the range endpoints will be negative if we fetch using a signed char *. - We also want to fetch the endpoints without translating them; the + We also want to fetch the endpoints without translating them; the appropriate translation is done in the bit-setting loop below. */ range_start = ((unsigned char *) p)[-2]; range_end = ((unsigned char *) p)[0]; @@ -2214,14 +2214,14 @@ compile_range (p_ptr, pend, translate, syntax, b) { SET_LIST_BIT (TRANSLATE (this_char)); } - + return REG_NOERROR; } /* Failure stack declarations and macros; both re_compile_fastmap and re_match_2 use a failure stack. These have to be macros because of REGEX_ALLOCATE. */ - + /* Number of failure points for which to initially allocate space when matching. If this number is exceeded, we allocate more @@ -2269,25 +2269,25 @@ typedef struct /* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. Return 1 if succeeds, and 0 if either ran out of memory - allocating space for it or it was already too large. - + allocating space for it or it was already too large. + REGEX_REALLOCATE requires `destination' be declared. */ #define DOUBLE_FAIL_STACK(fail_stack) \ ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ ? 0 \ : ((fail_stack).stack = (fail_stack_elt_t *) \ - REGEX_REALLOCATE ((fail_stack).stack, \ - (fail_stack).size * sizeof (fail_stack_elt_t), \ - ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + REGEX_REALLOCATE ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ \ (fail_stack).stack == NULL \ ? 0 \ : ((fail_stack).size <<= 1, \ - 1))) + 1))) -/* Push PATTERN_OP on FAIL_STACK. +/* Push PATTERN_OP on FAIL_STACK. Return 1 if was able to do so and 0 if ran out of memory allocating space to do so. */ @@ -2318,12 +2318,12 @@ typedef struct /* Push the information about the state we will need - if we ever fail back to it. - + if we ever fail back to it. + Requires variables fail_stack, regstart, regend, reg_info, and num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be declared. - + Does `return FAILURE_CODE' if runs out of memory. */ #define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ @@ -2332,7 +2332,7 @@ typedef struct /* Must be int, so when we don't save any registers, the arithmetic \ of 0 + -1 isn't done as unsigned. */ \ int this_reg; \ - \ + \ DEBUG_STATEMENT (failure_id++); \ DEBUG_STATEMENT (nfailure_points_pushed++); \ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ @@ -2345,39 +2345,39 @@ typedef struct /* Ensure we have enough space allocated for what we will push. */ \ while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ { \ - if (!DOUBLE_FAIL_STACK (fail_stack)) \ - return failure_code; \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ \ - DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ (fail_stack).size); \ - DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ } \ \ /* Push the info, starting with the registers. */ \ DEBUG_PRINT1 ("\n"); \ \ for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ - this_reg++) \ + this_reg++) \ { \ DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ - DEBUG_STATEMENT (num_regs_pushed++); \ + DEBUG_STATEMENT (num_regs_pushed++); \ \ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ - PUSH_FAILURE_ITEM (regstart[this_reg]); \ - \ + PUSH_FAILURE_ITEM (regstart[this_reg]); \ + \ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ - PUSH_FAILURE_ITEM (regend[this_reg]); \ + PUSH_FAILURE_ITEM (regend[this_reg]); \ \ DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ - DEBUG_PRINT2 (" match_null=%d", \ - REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ - DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ - DEBUG_PRINT2 (" matched_something=%d", \ - MATCHED_SOMETHING (reg_info[this_reg])); \ - DEBUG_PRINT2 (" ever_matched=%d", \ - EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ DEBUG_PRINT1 ("\n"); \ - PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ + PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ } \ \ DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ @@ -2431,7 +2431,7 @@ typedef struct LOW_REG, HIGH_REG -- the highest and lowest active registers. REGSTART, REGEND -- arrays of string positions. REG_INFO -- array of information about each subexpression. - + Also assumes the variables `fail_stack' and (if debugging), `bufp', `pend', `string1', `size1', `string2', and `size2'. */ @@ -2499,7 +2499,7 @@ typedef struct The caller must supply the address of a (1 << BYTEWIDTH)-byte data area as BUFP->fastmap. - + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in the pattern buffer. @@ -2516,7 +2516,7 @@ re_compile_fastmap (bufp) #endif /* We don't push any register information onto the failure stack. */ unsigned num_regs = 0; - + register char *fastmap = bufp->fastmap; unsigned char *pattern = bufp->buffer; unsigned long size = bufp->used; @@ -2533,27 +2533,27 @@ re_compile_fastmap (bufp) boolean succeed_n_p = false; assert (fastmap != NULL && p != NULL); - + INIT_FAIL_STACK (); bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ bufp->fastmap_accurate = 1; /* It will be when we're done. */ bufp->can_be_null = 0; - + while (p != pend || !FAIL_STACK_EMPTY ()) { if (p == pend) - { - bufp->can_be_null |= path_can_be_null; - - /* Reset for next path. */ - path_can_be_null = true; - - p = fail_stack.stack[--fail_stack.avail]; + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail]; } /* We should never be about to go beyond the end of the pattern. */ assert (p < pend); - + #ifdef SWITCH_ENUM_BUG switch ((int) ((re_opcode_t) *p++)) #else @@ -2561,40 +2561,40 @@ re_compile_fastmap (bufp) #endif { - /* I guess the idea here is to simply not bother with a fastmap - if a backreference is used, since it's too hard to figure out - the fastmap for the corresponding group. Setting - `can_be_null' stops `re_search_2' from using the fastmap, so - that is all we do. */ + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ case duplicate: bufp->can_be_null = 1; - return 0; + return 0; /* Following are the cases which match a character. These end - with `break'. */ + with `break'. */ case exactn: - fastmap[p[1]] = 1; + fastmap[p[1]] = 1; break; - case charset: - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) - fastmap[j] = 1; + fastmap[j] = 1; break; case charset_not: /* Chars beyond end of map must be allowed. */ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; + fastmap[j] = 1; for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) - fastmap[j] = 1; - break; + fastmap[j] = 1; + break; case wordchar: @@ -2611,26 +2611,26 @@ re_compile_fastmap (bufp) break; - case anychar: - /* `.' matches anything ... */ + case anychar: + /* `.' matches anything ... */ for (j = 0; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; + fastmap[j] = 1; - /* ... except perhaps newline. */ - if (!(bufp->syntax & RE_DOT_NEWLINE)) - fastmap['\n'] = 0; + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = 0; - /* Return if we have already set `can_be_null'; if we have, - then the fastmap is irrelevant. Something's wrong here. */ + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ else if (bufp->can_be_null) return 0; - /* Otherwise, have to check alternative paths. */ + /* Otherwise, have to check alternative paths. */ break; #ifdef emacs - case syntaxspec: + case syntaxspec: k = *p++; for (j = 0; j < (1 << BYTEWIDTH); j++) if (SYNTAX (j) == (enum syntaxcode) k) @@ -2647,126 +2647,126 @@ re_compile_fastmap (bufp) /* All cases after this match the empty string. These end with - `continue'. */ + `continue'. */ case before_dot: case at_dot: case after_dot: - continue; + continue; #endif /* not emacs */ - case no_op: - case begline: - case endline: + case no_op: + case begline: + case endline: case begbuf: case endbuf: case wordbound: case notwordbound: case wordbeg: case wordend: - case push_dummy_failure: - continue; + case push_dummy_failure: + continue; case jump_n: - case pop_failure_jump: + case pop_failure_jump: case maybe_pop_jump: case jump: - case jump_past_alt: + case jump_past_alt: case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; if (j > 0) continue; - - /* Jump backward implies we just went through the body of a - loop and matched nothing. Opcode jumped to should be - `on_failure_jump' or `succeed_n'. Just treat it like an - ordinary jump. For a * loop, it has pushed its failure - point already; if so, discard that as redundant. */ - if ((re_opcode_t) *p != on_failure_jump + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump && (re_opcode_t) *p != succeed_n) continue; - p++; - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; - - /* If what's on the stack is where we are now, pop it. */ - if (!FAIL_STACK_EMPTY () + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () && fail_stack.stack[fail_stack.avail - 1] == p) - fail_stack.avail--; + fail_stack.avail--; - continue; + continue; - case on_failure_jump: - case on_failure_keep_string_jump: + case on_failure_jump: + case on_failure_keep_string_jump: handle_on_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); + EXTRACT_NUMBER_AND_INCR (j, p); - /* For some patterns, e.g., `(a?)?', `p+j' here points to the - end of the pattern. We don't want to push such a point, - since when we restore it above, entering the switch will - increment `p' past the end of the pattern. We don't need - to push such a point since we obviously won't find any more - fastmap entries beyond `pend'. Such a pattern can match - the null string, though. */ - if (p + j < pend) - { - if (!PUSH_PATTERN_OP (p + j, fail_stack)) - return -2; - } - else - bufp->can_be_null = 1; + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + return -2; + } + else + bufp->can_be_null = 1; - if (succeed_n_p) - { - EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ - succeed_n_p = false; + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; } - continue; + continue; case succeed_n: - /* Get to the number of times to succeed. */ - p += 2; + /* Get to the number of times to succeed. */ + p += 2; - /* Increment p past the n for when k != 0. */ - EXTRACT_NUMBER_AND_INCR (k, p); - if (k == 0) + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) { - p -= 4; - succeed_n_p = true; /* Spaghetti code alert. */ - goto handle_on_failure_jump; - } - continue; + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; case set_number_at: - p += 4; - continue; + p += 4; + continue; case start_memory: - case stop_memory: + case stop_memory: p += 2; continue; default: - abort (); /* We have listed all the cases. */ - } /* switch *p++ */ + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ /* Getting here means we have found the possible starting - characters for one path of the pattern -- and that the empty - string does not match. We need not follow this path further. - Instead, look at the next alternative (remembered on the - stack), or quit if no more. The test at the top of the loop - does these things. */ + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ path_can_be_null = false; p = pend; } /* while p */ @@ -2824,7 +2824,7 @@ re_search (bufp, string, size, startpos, range, regs) int size, startpos, range; struct re_registers *regs; { - return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, regs, size); } @@ -2832,17 +2832,17 @@ re_search (bufp, string, size, startpos, range, regs) /* Using the compiled pattern in BUFP->buffer, first tries to match the virtual concatenation of STRING1 and STRING2, starting first at index STARTPOS, then at STARTPOS + 1, and so on. - + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. - + RANGE is how far to scan while trying to match. RANGE = 0 means try only at STARTPOS; in general, the last start tried is STARTPOS + RANGE. - + In REGS, return the indices of the virtual concatenation of STRING1 and STRING2 that matched the entire BUFP->buffer and its contained subexpressions. - + Do not consider matching one past the index STOP in the virtual concatenation of STRING1 and STRING2. @@ -2869,7 +2869,7 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) /* Check for out-of-range STARTPOS. */ if (startpos < 0 || startpos > total_size) return -1; - + /* Fix up RANGE if it might eventually take us outside the virtual concatenation of STRING1 and STRING2. */ if (endpos < -1) @@ -2891,14 +2891,14 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) if (fastmap && !bufp->fastmap_accurate) if (re_compile_fastmap (bufp) == -2) return -2; - + /* Loop through the string, looking for a place to start matching. */ for (;;) - { + { /* If a fastmap is supplied, skip quickly over characters that - cannot be the start of a match. If the pattern can match the - null string, however, we don't need to skip characters; we want - the first null string. */ + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ if (fastmap && startpos < total_size && !bufp->can_be_null) { if (range > 0) /* Searching forwards. */ @@ -2907,29 +2907,29 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) register int lim = 0; int irange = range; - if (startpos < size1 && startpos + range >= size1) - lim = range - (size1 - startpos); + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); d = (startpos >= size1 ? string2 - size1 : string1) + startpos; - - /* Written out as an if-else to avoid testing `translate' - inside the loop. */ + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ if (translate) - while (range > lim - && !fastmap[(unsigned char) + while (range > lim + && !fastmap[(unsigned char) translate[(unsigned char) *d++]]) - range--; + range--; else - while (range > lim && !fastmap[(unsigned char) *d++]) - range--; + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; startpos += irange - range; } else /* Searching backwards. */ { register char c = (size1 == 0 || startpos >= size1 - ? string2[startpos - size1] - : string1[startpos]); + ? string2[startpos - size1] + : string1[startpos]); if (!fastmap[(unsigned char) TRANSLATE (c)]) goto advance; @@ -2938,30 +2938,30 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) /* If can't match the null string, and that's all we have left, fail. */ if (range >= 0 && startpos == total_size && fastmap - && !bufp->can_be_null) + && !bufp->can_be_null) return -1; val = re_match_2 (bufp, string1, size1, string2, size2, - startpos, regs, stop); + startpos, regs, stop); if (val >= 0) return startpos; - + if (val == -2) return -2; advance: - if (!range) - break; - else if (range > 0) - { - range--; - startpos++; - } + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } else - { - range++; - startpos--; - } + { + range++; + startpos--; + } } return -1; } /* re_search_2 */ @@ -2970,16 +2970,16 @@ re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) static int bcmp_translate (); static boolean alt_match_null_string_p (), - common_op_match_null_string_p (), - group_match_null_string_p (); + common_op_match_null_string_p (), + group_match_null_string_p (); /* Structure for per-register (a.k.a. per-group) information. This must not be longer than one word, because we push this value onto the failure stack. Other register information, such as the starting and ending positions (which are addresses), and the list of inner groups (which is a bits list) are maintained in separate - variables. - + variables. + We are making a (strictly speaking) nonportable assumption here: that the compiler will pack our bit fields into something that fits into the type of `word', i.e., is something that fits into one item on the @@ -2990,7 +2990,7 @@ typedef union struct { /* This field is one if this group can match the empty string, - zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ #define MATCH_NULL_UNSET_VALUE 3 unsigned match_null_string_p : 2; unsigned is_active : 1; @@ -3013,11 +3013,11 @@ typedef union { \ unsigned r; \ for (r = lowest_active_reg; r <= highest_active_reg; r++) \ - { \ - MATCHED_SOMETHING (reg_info[r]) \ - = EVER_MATCHED_SOMETHING (reg_info[r]) \ - = 1; \ - } \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ } \ while (0) @@ -3043,7 +3043,7 @@ typedef union { \ /* End of string2 => fail. */ \ if (dend == end_match_2) \ - goto fail; \ + goto fail; \ /* End of string1 => advance to string2. */ \ d = string2; \ dend = end_match_2; \ @@ -3053,7 +3053,7 @@ typedef union /* Test if at very beginning or at very end of the virtual concatenation of `string1' and `string2'. If only one string, it's `string2'. */ #define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) -#define AT_STRINGS_END(d) ((d) == end2) +#define AT_STRINGS_END(d) ((d) == end2) /* Test if D points to a character which is word-constituent. We have @@ -3062,7 +3062,7 @@ typedef union string2, look at the last character in string1. */ #define WORDCHAR_P(d) \ (SYNTAX ((d) == end1 ? *string2 \ - : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ == Sword) /* Test if the character before D and the one at D differ with respect @@ -3116,7 +3116,7 @@ re_match (bufp, string, size, pos, regs) int size, pos; struct re_registers *regs; { - return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); + return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); } #endif /* not emacs */ @@ -3125,7 +3125,7 @@ re_match (bufp, string, size, pos, regs) the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 and SIZE2, respectively). We start matching at POS, and stop matching at STOP. - + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we store offsets for the substring each group matched in REGS. See the documentation for exactly how many groups we fill. @@ -3156,7 +3156,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) /* Where we are in the data, and the end of the current string. */ const char *d, *dend; - + /* Where we are in the pattern, and the end of the pattern. */ unsigned char *p = bufp->buffer; register unsigned char *pend = p + bufp->used; @@ -3183,7 +3183,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) return, for use in backreferences. The number here includes an element for register zero. */ unsigned num_regs = bufp->re_nsub + 1; - + /* The currently active registers. */ unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; @@ -3213,12 +3213,12 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) register_info_type *reg_info = NULL; /* The following record the register info as found in the above - variables when we find a match better than any we've seen before. + variables when we find a match better than any we've seen before. This happens as we backtrack through the failure points, which in turn happens only if we have not yet matched the entire string. */ unsigned best_regs_set = false; const char **best_regstart = NULL, **best_regend = NULL; - + /* Logically, this is `best_regend[0]'. But we don't want to have to allocate space for that if we're not allocating space for anything else (see below). Also, we never need info about register 0 for @@ -3235,13 +3235,13 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) #ifdef DEBUG /* Counts the total number of registers pushed. */ - unsigned num_regs_pushed = 0; + unsigned num_regs_pushed = 0; #endif DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); - + INIT_FAIL_STACK (); - + /* Do not bother to initialize all the register variables if there are no groups in the pattern, as it takes a fair amount of time. If there are groups, we include space for register 0 (the whole @@ -3259,20 +3259,20 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) reg_dummy = REGEX_TALLOC (num_regs, const char *); reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); - if (!(regstart && regend && old_regstart && old_regend && reg_info - && best_regstart && best_regend && reg_dummy && reg_info_dummy)) - { - FREE_VARIABLES (); - return -2; - } + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } } #ifdef REGEX_MALLOC else { /* We must initialize all our variables to NULL, so that - `FREE_VARIABLES' doesn't try to free them. */ + `FREE_VARIABLES' doesn't try to free them. */ regstart = regend = old_regstart = old_regend = best_regstart - = best_regend = reg_dummy = NULL; + = best_regend = reg_dummy = NULL; reg_info = reg_info_dummy = (register_info_type *) NULL; } #endif /* REGEX_MALLOC */ @@ -3283,21 +3283,21 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) FREE_VARIABLES (); return -1; } - + /* Initialize subexpression text positions to -1 to mark ones that no start_memory/stop_memory has been seen for. Also initialize the register information struct. */ for (mcnt = 1; mcnt < num_regs; mcnt++) { - regstart[mcnt] = regend[mcnt] - = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; - + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; IS_ACTIVE (reg_info[mcnt]) = 0; MATCHED_SOMETHING (reg_info[mcnt]) = 0; EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; } - + /* We move `string1' into `string2' if the latter's empty -- but not if `string1' is null. */ if (size2 == 0 && string1 != NULL) @@ -3322,7 +3322,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) end_match_2 = string2 + stop - size1; } - /* `p' scans through the pattern as `d' scans through the data. + /* `p' scans through the pattern as `d' scans through the data. `dend' is the end of the input string that `d' points within. `d' is advanced into the following input string whenever necessary, but this happens before fetching; therefore, at the beginning of the @@ -3344,7 +3344,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) DEBUG_PRINT1 ("The string to match is: `"); DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); DEBUG_PRINT1 ("'\n"); - + /* This loops over pattern commands. It exits by returning from the function if the match is complete, or it drops through if the match fails at this starting point in the input data. */ @@ -3354,140 +3354,140 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) if (p == pend) { /* End of pattern means we might have succeeded. */ - DEBUG_PRINT1 ("end of pattern ... "); - + DEBUG_PRINT1 ("end of pattern ... "); + /* If we haven't matched the entire string, and we want the - longest match, try backtracking. */ - if (d != end_match_2) + longest match, try backtracking. */ + if (d != end_match_2) { - DEBUG_PRINT1 ("backtracking.\n"); - - if (!FAIL_STACK_EMPTY ()) - { /* More failure points to try. */ - boolean same_str_p = (FIRST_STRING_P (match_end) - == MATCHING_IN_FIRST_STRING); + DEBUG_PRINT1 ("backtracking.\n"); - /* If exceeds best match so far, save it. */ - if (!best_regs_set - || (same_str_p && d > match_end) - || (!same_str_p && !MATCHING_IN_FIRST_STRING)) - { - best_regs_set = true; - match_end = d; - - DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); - - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - best_regstart[mcnt] = regstart[mcnt]; - best_regend[mcnt] = regend[mcnt]; - } - } - goto fail; - } + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); - /* If no failure points, don't restore garbage. */ - else if (best_regs_set) - { - restore_best_regs: - /* Restore best match. It may happen that `dend == - end_match_1' while the restored d is in string2. - For example, the pattern `x.*y.*z' against the - strings `x-' and `y-z-', if the two strings are - not consecutive in memory. */ - DEBUG_PRINT1 ("Restoring best registers.\n"); - - d = match_end; - dend = ((d >= string1 && d <= end1) - ? end_match_1 : end_match_2); + /* If exceeds best match so far, save it. */ + if (!best_regs_set + || (same_str_p && d > match_end) + || (!same_str_p && !MATCHING_IN_FIRST_STRING)) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); for (mcnt = 1; mcnt < num_regs; mcnt++) { regstart[mcnt] = best_regstart[mcnt]; regend[mcnt] = best_regend[mcnt]; } - } - } /* d != end_match_2 */ + } + } /* d != end_match_2 */ - DEBUG_PRINT1 ("Accepting match.\n"); + DEBUG_PRINT1 ("Accepting match.\n"); - /* If caller wants register contents data back, do it. */ - if (regs && !bufp->no_sub) + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) { - /* Have the register data arrays been allocated? */ - if (bufp->regs_allocated == REGS_UNALLOCATED) - { /* No. So allocate them with malloc. We need one - extra element beyond `num_regs' for the `-1' marker - GNU code uses. */ - regs->num_regs = MAX (RE_NREGS, num_regs + 1); - regs->start = TALLOC (regs->num_regs, regoff_t); - regs->end = TALLOC (regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - bufp->regs_allocated = REGS_REALLOCATE; - } - else if (bufp->regs_allocated == REGS_REALLOCATE) - { /* Yes. If we need more elements than were already - allocated, reallocate them. If we need fewer, just - leave it alone. */ - if (regs->num_regs < num_regs + 1) - { - regs->num_regs = num_regs + 1; - RETALLOC (regs->start, regs->num_regs, regoff_t); - RETALLOC (regs->end, regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - } - } - else - assert (bufp->regs_allocated == REGS_FIXED); + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + } + } + else + assert (bufp->regs_allocated == REGS_FIXED); - /* Convert the pointer data in `regstart' and `regend' to - indices. Register zero has to be set differently, - since we haven't kept track of any info for it. */ - if (regs->num_regs > 0) - { - regs->start[0] = pos; - regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 - : d - string2 + size1); - } - - /* Go through the first `min (num_regs, regs->num_regs)' - registers, since that is all we initialized. */ + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 + : d - string2 + size1); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) { - if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) - regs->start[mcnt] = regs->end[mcnt] = -1; - else - { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]); - regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); - } + regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); + } } - - /* If the regs structure we return has more elements than - were in the pattern, set the extra elements to -1. If - we (re)allocated the registers, this is the case, - because we always allocate enough to have at least one - -1 at the end. */ - for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) - regs->start[mcnt] = regs->end[mcnt] = -1; + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; } /* regs && !bufp->no_sub */ - FREE_VARIABLES (); - DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", - nfailure_points_pushed, nfailure_points_popped, - nfailure_points_pushed - nfailure_points_popped); - DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + FREE_VARIABLES (); + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); - mcnt = d - pos - (MATCHING_IN_FIRST_STRING - ? string1 + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 : string2 - size1); - DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); - return mcnt; - } + return mcnt; + } /* Otherwise match next pattern command. */ #ifdef SWITCH_ENUM_BUG @@ -3496,29 +3496,29 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) switch ((re_opcode_t) *p++) #endif { - /* Ignore these. Used to ignore the n of succeed_n's which - currently have n == 0. */ - case no_op: - DEBUG_PRINT1 ("EXECUTING no_op.\n"); - break; + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; - /* Match the next n pattern characters exactly. The following - byte in the pattern defines n, and the n bytes after that - are the characters to match. */ + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ case exactn: mcnt = *p++; - DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); - /* This is written out as an if-else so we don't waste time - testing `translate' inside the loop. */ - if (translate) + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) { do { PREFETCH (); if (translate[(unsigned char) *d++] != (char) *p++) - goto fail; + goto fail; } while (--mcnt); } @@ -3532,22 +3532,22 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) while (--mcnt); } SET_REGS_MATCHED (); - break; + break; - /* Match any character except possibly a newline or a null. */ + /* Match any character except possibly a newline or a null. */ case anychar: - DEBUG_PRINT1 ("EXECUTING anychar.\n"); + DEBUG_PRINT1 ("EXECUTING anychar.\n"); - PREFETCH (); + PREFETCH (); - if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') - || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) goto fail; - SET_REGS_MATCHED (); - DEBUG_PRINT2 (" Matched `%d'.\n", *d); - d++; + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; break; @@ -3557,13 +3557,13 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) register unsigned char c; boolean not = (re_opcode_t) *(p - 1) == charset_not; - DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); PREFETCH (); c = TRANSLATE (*d); /* The character to match. */ - /* Cast to `unsigned' instead of `unsigned char' in case the - bit list is a full 32 bytes long. */ + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ if (c < (unsigned) (*p * BYTEWIDTH) && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) not = !not; @@ -3571,226 +3571,226 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) p += 1 + *p; if (!not) goto fail; - + SET_REGS_MATCHED (); - d++; + d++; break; } - /* The beginning of a group is represented by start_memory. - The arguments are the register number in the next byte, and the - number of groups inner to this one in the next. The text - matched within the group is recorded (in the internal - registers data structure) under the register number. */ - case start_memory: + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); - /* Find out if this group can match the empty string. */ + /* Find out if this group can match the empty string. */ p1 = p; /* To send to group_match_null_string_p. */ - - if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[*p]) - = group_match_null_string_p (&p1, pend, reg_info); - /* Save the position in the string where we were the last time - we were at this open-group operator in case the group is - operated upon by a repetition operator, e.g., with `(a*)*b' - against `ab'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regstart[*p]) ? d : regstart[*p] - : regstart[*p]; - DEBUG_PRINT2 (" old_regstart: %d\n", + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", POINTER_TO_OFFSET (old_regstart[*p])); - regstart[*p] = d; + regstart[*p] = d; DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); - IS_ACTIVE (reg_info[*p]) = 1; - MATCHED_SOMETHING (reg_info[*p]) = 0; - - /* This is the new highest active register. */ - highest_active_reg = *p; - - /* If nothing was active before, this is the new lowest active - register. */ - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *p; + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; - /* Move past the register number and inner group count. */ - p += 2; - break; + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + break; - /* The stop_memory opcode represents the end of a group. Its - arguments are the same as start_memory's: the register - number, and the number of inner groups. */ + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ case stop_memory: DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); - - /* We need to save the string position the last time we were at - this close-group operator in case the group is operated - upon by a repetition operator, e.g., with `((a*)*(b*)*)*' - against `aba'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regend[*p]) ? d : regend[*p] + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] : regend[*p]; - DEBUG_PRINT2 (" old_regend: %d\n", + DEBUG_PRINT2 (" old_regend: %d\n", POINTER_TO_OFFSET (old_regend[*p])); - regend[*p] = d; + regend[*p] = d; DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); - /* This register isn't active anymore. */ - IS_ACTIVE (reg_info[*p]) = 0; - - /* If this was the only register active, nothing is active - anymore. */ - if (lowest_active_reg == highest_active_reg) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - { /* We must scan for the new highest active register, since - it isn't necessarily one less than now: consider - (a(b)c(d(e)f)g). When group 3 ends, after the f), the - new highest active register is 1. */ - unsigned char r = *p - 1; - while (r > 0 && !IS_ACTIVE (reg_info[r])) - r--; - - /* If we end up at register zero, that means that we saved - the registers as the result of an `on_failure_jump', not - a `start_memory', and we jumped to past the innermost - `stop_memory'. For example, in ((.)*) we save - registers 1 and 2 as a result of the *, but when we pop - back to the second ), we are at the stop_memory 1. - Thus, nothing is active. */ + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ if (r == 0) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - highest_active_reg = r; - } - - /* If just failed to match something this time around with a - group that's operated on by a repetition operator, try to - force exit from the ``loop'', and restore the register - information for this group that we had before trying this - last match. */ - if ((!MATCHED_SOMETHING (reg_info[*p]) - || (re_opcode_t) p[-3] == start_memory) - && (p + 2) < pend) - { - boolean is_a_jump_n = false; - - p1 = p + 2; - mcnt = 0; - switch ((re_opcode_t) *p1++) - { - case jump_n: + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || (re_opcode_t) p[-3] == start_memory) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: is_a_jump_n = true; - case pop_failure_jump: + case pop_failure_jump: case maybe_pop_jump: case jump: case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p1); + EXTRACT_NUMBER_AND_INCR (mcnt, p1); if (is_a_jump_n) p1 += 2; - break; - - default: - /* do nothing */ ; - } + break; + + default: + /* do nothing */ ; + } p1 += mcnt; - - /* If the next operation is a jump backwards in the pattern - to an on_failure_jump right before the start_memory - corresponding to this stop_memory, exit from the loop - by forcing a failure after pushing on the stack the - on_failure_jump's jump in the pattern, and d. */ - if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump - && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) { - /* If this group ever matched anything, then restore - what its registers were before trying this last - failed match, e.g., with `(a*)*b' against `ab' for - regstart[1], and, e.g., with `((a*)*(b*)*)*' - against `aba' for regend[3]. - - Also restore the registers for inner groups for, - e.g., `((a*)(b*))*' against `aba' (register 3 would - otherwise get trashed). */ - - if (EVER_MATCHED_SOMETHING (reg_info[*p])) + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) { - unsigned r; - - EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; - + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + /* Restore this and inner groups' (if any) registers. */ - for (r = *p; r < *p + *(p + 1); r++) - { - regstart[r] = old_regstart[r]; + for (r = *p; r < *p + *(p + 1); r++) + { + regstart[r] = old_regstart[r]; - /* xx why this test? */ - if ((int) old_regend[r] >= (int) regstart[r]) - regend[r] = old_regend[r]; - } - } + /* xx why this test? */ + if ((int) old_regend[r] >= (int) regstart[r]) + regend[r] = old_regend[r]; + } + } p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); - goto fail; - } - } - - /* Move past the register number and the inner group count. */ - p += 2; - break; + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; /* \ has been turned into a `duplicate' command which is - followed by the numeric value of as the register number. */ - case duplicate: + followed by the numeric value of as the register number. */ + case duplicate: { register const char *d2, *dend2; int regno = *p++; /* Get which register to match against. */ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); /* Can't back reference a group which we've never matched. */ - if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) - goto fail; - - /* Where in input to try to start matching. */ - d2 = regstart[regno]; - - /* Where to stop matching; if both the place to start and - the place to stop matching are in the same string, then - set to the place to stop, otherwise, for now have to use - the end of the first string. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; - dend2 = ((FIRST_STRING_P (regstart[regno]) + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) == FIRST_STRING_P (regend[regno])) ? regend[regno] : end_match_1); for (;;) { /* If necessary, advance to next segment in register - contents. */ + contents. */ while (d2 == dend2) { if (dend2 == end_match_2) break; if (dend2 == regend[regno]) break; - /* End of string1 => advance to string2. */ - d2 = string2; - dend2 = regend[regno]; + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; } /* At end of register contents => success */ if (d2 == dend2) break; @@ -3800,17 +3800,17 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) /* How many characters left in this segment to match. */ mcnt = dend - d; - + /* Want how many consecutive characters we can match in - one shot, so, if necessary, adjust the count. */ - if (mcnt > dend2 - d2) + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) mcnt = dend2 - d2; - + /* Compare that many; failure if mismatch, else move - past them. */ - if (translate - ? bcmp_translate (d, d2, mcnt, translate) - : bcmp (d, d2, mcnt)) + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : bcmp (d, d2, mcnt)) goto fail; d += mcnt, d2 += mcnt; } @@ -3818,157 +3818,157 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) break; - /* begline matches the empty string at the beginning of the string - (unless `not_bol' is set in `bufp'), and, if - `newline_anchor' is set, after newlines. */ + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ case begline: - DEBUG_PRINT1 ("EXECUTING begline.\n"); - - if (AT_STRINGS_BEG (d)) - { - if (!bufp->not_bol) break; - } - else if (d[-1] == '\n' && bufp->newline_anchor) - { - break; - } - /* In all other cases, we fail. */ - goto fail; + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; - /* endline is the dual of begline. */ + /* endline is the dual of begline. */ case endline: - DEBUG_PRINT1 ("EXECUTING endline.\n"); + DEBUG_PRINT1 ("EXECUTING endline.\n"); - if (AT_STRINGS_END (d)) - { - if (!bufp->not_eol) break; - } - - /* We have to ``prefetch'' the next character. */ - else if ((d == end1 ? *string2 : *d) == '\n' - && bufp->newline_anchor) - { - break; - } - goto fail; + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; /* Match at the very beginning of the data. */ - case begbuf: - DEBUG_PRINT1 ("EXECUTING begbuf.\n"); - if (AT_STRINGS_BEG (d)) - break; - goto fail; + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; /* Match at the very end of the data. */ - case endbuf: - DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); if (AT_STRINGS_END (d)) break; - goto fail; + goto fail; - /* on_failure_keep_string_jump is used to optimize `.*\n'. It - pushes NULL as the value for the string on the stack. Then - `pop_failure_point' will keep the current value for the - string, instead of restoring it. To see why, consider - matching `foo\nbar' against `.*\n'. The .* matches the foo; - then the . fails against the \n. But the next thing we want - to do is match the \n against the \n; if we restored the - string value, we would be back at the foo. - - Because this is used only in specific cases, we don't need to - check all the things that `on_failure_jump' does, to make - sure the right things get saved on the stack. Hence we don't - share its code. The only reason to push anything on the - stack at all is that otherwise we would have to change - `anychar's code to do something besides goto fail in this - case; that seems worse than this. */ - case on_failure_keep_string_jump: - DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. - PUSH_FAILURE_POINT (p + mcnt, NULL, -2); - break; + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; /* Uses of on_failure_jump: - - Each alternative starts with an on_failure_jump that points - to the beginning of the next alternative. Each alternative - except the last ends with a jump that in effect jumps past - the rest of the alternatives. (They really jump to the - ending jump of the following alternative, because tensioning - these jumps is a hassle.) - Repeats start with an on_failure_jump that points past both - the repetition text and either the following jump or - pop_failure_jump back to this on_failure_jump. */ + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ case on_failure_jump: - on_failure: - DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); - /* If this on_failure_jump comes right before a group (i.e., - the original * applied to a group), save the information - for that group and all inner ones, so that if we fail back - to this point, the group's information will be correct. - For example, in \(a*\)*\1, we need the preceding group, - and in \(\(a*\)b*\)\2, we need the inner group. */ + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(\(a*\)b*\)\2, we need the inner group. */ - /* We can't use `p' to check ahead because we push - a failure point to `p + mcnt' after we do this. */ - p1 = p; + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; - /* We need to skip no_op's before we look for the - start_memory in case this on_failure_jump is happening as - the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 - against aba. */ - while (p1 < pend && (re_opcode_t) *p1 == no_op) - p1++; + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; - if (p1 < pend && (re_opcode_t) *p1 == start_memory) - { - /* We have a new highest active register now. This will - get reset at the start_memory we are about to get to, - but we will have saved all the registers relevant to - this repetition op, as described above. */ - highest_active_reg = *(p1 + 1) + *(p1 + 2); - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *(p1 + 1); - } + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } - DEBUG_PRINT1 (":\n"); - PUSH_FAILURE_POINT (p + mcnt, d, -2); - break; + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; - /* A smart repeat ends with `maybe_pop_jump'. + /* A smart repeat ends with `maybe_pop_jump'. We change it to either `pop_failure_jump' or `jump'. */ - case maybe_pop_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); - { + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { register unsigned char *p2 = p; - /* Compare the beginning of the repeat with what in the - pattern follows its end. If we can establish that there - is nothing that they would both match, i.e., that we - would have to backtrack because of (as in, e.g., `a*a') - then we can change to pop_failure_jump, because we'll - never have to backtrack. - - This is not true in the case of alternatives: in - `(a|ab)*' we do need to backtrack to the `ab' alternative - (e.g., if the string was `ab'). But instead of trying to - detect that here, the alternative has put on a dummy - failure point which is what we will end up popping. */ + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ /* Skip over open/close-group commands. */ while (p2 + 2 < pend @@ -3976,50 +3976,50 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) || (re_opcode_t) *p2 == start_memory)) p2 += 3; /* Skip over args, too. */ - /* If we're at the end of the pattern, we can change. */ - if (p2 == pend) + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) { /* Consider what happens when matching ":\(.*\)" against ":/". I don't really understand this code yet. */ - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 - (" End of pattern: change to `pop_failure_jump'.\n"); - } + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } - else if ((re_opcode_t) *p2 == exactn + else if ((re_opcode_t) *p2 == exactn || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) { register unsigned char c - = *p2 == (unsigned char) endline ? '\n' : p2[2]; + = *p2 == (unsigned char) endline ? '\n' : p2[2]; p1 = p + mcnt; - /* p1[0] ... p1[2] are the `on_failure_jump' corresponding - to the `maybe_finalize_jump' of this case. Examine what - follows. */ - if ((re_opcode_t) p1[3] == exactn && p1[5] != c) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", - c, p1[5]); - } - + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + else if ((re_opcode_t) p1[3] == charset || (re_opcode_t) p1[3] == charset_not) { int not = (re_opcode_t) p1[3] == charset_not; - + if (c < (unsigned char) (p1[4] * BYTEWIDTH) && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) not = !not; - /* `not' is equal to 1 if c would match, which means - that we can't change to pop_failure_jump. */ + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ if (!not) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); - } + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } } } } @@ -4027,235 +4027,235 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) if ((re_opcode_t) p[-1] != pop_failure_jump) { p[-1] = (unsigned char) jump; - DEBUG_PRINT1 (" Match => jump.\n"); + DEBUG_PRINT1 (" Match => jump.\n"); goto unconditional_jump; } - /* Note fall through. */ + /* Note fall through. */ /* The end of a simple repeat has a pop_failure_jump back to - its matching on_failure_jump, where the latter will push a - failure point. The pop_failure_jump takes off failure - points put on by this pop_failure_jump's matching - on_failure_jump; we got through the pattern to here from the - matching on_failure_jump, so didn't fail. */ - case pop_failure_jump: - { - /* We need to pass separate storage for the lowest and - highest registers, even though we don't care about the - actual values. Otherwise, we will restore only one - register from the stack, since lowest will == highest in - `pop_failure_point'. */ - unsigned dummy_low_reg, dummy_high_reg; - unsigned char *pdummy; - const char *sdummy; + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + unsigned dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; - DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); - POP_FAILURE_POINT (sdummy, pdummy, - dummy_low_reg, dummy_high_reg, - reg_dummy, reg_dummy, reg_info_dummy); - } - /* Note fall through. */ + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ - - /* Unconditionally jump (without popping any failure points). */ - case jump: + + /* Unconditionally jump (without popping any failure points). */ + case jump: unconditional_jump: EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ - DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); p += mcnt; /* Do the jump. */ - DEBUG_PRINT2 ("(to 0x%x).\n", p); + DEBUG_PRINT2 ("(to 0x%x).\n", p); break; - - /* We need this opcode so we can detect where alternatives end - in `group_match_null_string_p' et al. */ - case jump_past_alt: - DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); - goto unconditional_jump; + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; - /* Normally, the on_failure_jump pushes a failure point, which - then gets popped at pop_failure_jump. We will end up at - pop_failure_jump, also, and with a pattern of, say, `a+', we - are skipping over the on_failure_jump, so we have to push - something meaningless for pop_failure_jump to pop. */ - case dummy_failure_jump: - DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); - /* It doesn't matter what we push for the string here. What - the code at `fail' tests is the value for the pattern. */ - PUSH_FAILURE_POINT (0, 0, -2); - goto unconditional_jump; + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (0, 0, -2); + goto unconditional_jump; - /* At the end of an alternative, we need to push a dummy failure - point in case we are followed by a `pop_failure_jump', because - we don't want the failure point for the alternative to be - popped. For example, matching `(a|ab)*' against `aab' - requires that we match the `ab' alternative. */ - case push_dummy_failure: - DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); - /* See comments just above at `dummy_failure_jump' about the - two zeroes. */ - PUSH_FAILURE_POINT (0, 0, -2); - break; + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (0, 0, -2); + break; - /* Have to succeed matching what follows at least n times. - After that, handle like `on_failure_jump'. */ - case succeed_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); - assert (mcnt >= 0); - /* Originally, this is how many times we HAVE to succeed. */ - if (mcnt > 0) - { - mcnt--; + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; p += 2; - STORE_NUMBER_AND_INCR (p, mcnt); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); - } + STORE_NUMBER_AND_INCR (p, mcnt); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); + } else if (mcnt == 0) - { - DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); + { + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); p[2] = (unsigned char) no_op; - p[3] = (unsigned char) no_op; - goto on_failure; - } - break; - - case jump_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; - /* Originally, this is how many times we CAN jump. */ - if (mcnt) - { - mcnt--; - STORE_NUMBER (p + 2, mcnt); - goto unconditional_jump; - } - /* If don't have to jump any more, skip over the rest of command. */ - else - p += 4; - break; - case set_number_at: { - DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); - EXTRACT_NUMBER_AND_INCR (mcnt, p); - p1 = p + mcnt; - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); STORE_NUMBER (p1, mcnt); - break; - } - - case wordbound: - DEBUG_PRINT1 ("EXECUTING wordbound.\n"); - if (AT_WORD_BOUNDARY (d)) break; - goto fail; + } + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; case notwordbound: - DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); if (AT_WORD_BOUNDARY (d)) goto fail; - break; + break; case wordbeg: - DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) break; - goto fail; + goto fail; case wordend: - DEBUG_PRINT1 ("EXECUTING wordend.\n"); + DEBUG_PRINT1 ("EXECUTING wordend.\n"); if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) - && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) break; - goto fail; + goto fail; #ifdef emacs #ifdef emacs19 - case before_dot: - DEBUG_PRINT1 ("EXECUTING before_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) >= point) - goto fail; - break; - - case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) != point) - goto fail; - break; - - case after_dot: - DEBUG_PRINT1 ("EXECUTING after_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) <= point) - goto fail; - break; + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; #else /* not emacs19 */ case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) goto fail; break; #endif /* not emacs19 */ case syntaxspec: - DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); mcnt = *p++; goto matchsyntax; - case wordchar: - DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); mcnt = (int) Sword; - matchsyntax: + matchsyntax: PREFETCH (); if (SYNTAX (*d++) != (enum syntaxcode) mcnt) - goto fail; - SET_REGS_MATCHED (); + goto fail; + SET_REGS_MATCHED (); break; case notsyntaxspec: - DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); mcnt = *p++; goto matchnotsyntax; - case notwordchar: - DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); mcnt = (int) Sword; - matchnotsyntax: + matchnotsyntax: PREFETCH (); if (SYNTAX (*d++) == (enum syntaxcode) mcnt) - goto fail; + goto fail; SET_REGS_MATCHED (); - break; + break; #else /* not emacs */ case wordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); PREFETCH (); - if (!WORDCHAR_P (d)) - goto fail; + if (!WORDCHAR_P (d)) + goto fail; SET_REGS_MATCHED (); - d++; + d++; break; - + case notwordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); PREFETCH (); if (WORDCHAR_P (d)) - goto fail; - SET_REGS_MATCHED (); - d++; + goto fail; + SET_REGS_MATCHED (); + d++; break; #endif /* not emacs */ - - default: - abort (); + + default: + abort (); } continue; /* Successfully executed one pattern command; keep going. */ @@ -4264,49 +4264,49 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) fail: if (!FAIL_STACK_EMPTY ()) { /* A restart point is known. Restore to that state. */ - DEBUG_PRINT1 ("\nFAIL:\n"); - POP_FAILURE_POINT (d, p, - lowest_active_reg, highest_active_reg, - regstart, regend, reg_info); + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); - /* If this failure point is a dummy, try the next one. */ - if (!p) + /* If this failure point is a dummy, try the next one. */ + if (!p) goto fail; - /* If we failed to the end of the pattern, don't examine *p. */ + /* If we failed to the end of the pattern, don't examine *p. */ assert (p <= pend); - if (p < pend) - { - boolean is_a_jump_n = false; - - /* If failed to a backwards jump that's part of a repetition - loop, need to pop this failure point and use the next one. */ - switch ((re_opcode_t) *p) - { - case jump_n: - is_a_jump_n = true; - case maybe_pop_jump: - case pop_failure_jump: - case jump: - p1 = p + 1; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; + if (p < pend) + { + boolean is_a_jump_n = false; - if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) - || (!is_a_jump_n - && (re_opcode_t) *p1 == on_failure_jump)) - goto fail; - break; - default: - /* do nothing */ ; - } - } + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; - if (d >= string1 && d <= end1) + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) dend = end_match_1; - } + } else - break; /* Matching at this starting point really fails. */ + break; /* Matching at this starting point really fails. */ } /* for (;;) */ if (best_regs_set) @@ -4321,10 +4321,10 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) /* We are passed P pointing to a register number after a start_memory. - + Return true if the pattern up to the corresponding stop_memory can match the empty string, and false otherwise. - + If we find the matching stop_memory, sets P to point to one past its number. Otherwise, sets P to an undefined byte less than or equal to END. @@ -4338,97 +4338,97 @@ group_match_null_string_p (p, end, reg_info) int mcnt; /* Point to after the args to the start_memory. */ unsigned char *p1 = *p + 2; - + while (p1 < end) { /* Skip over opcodes that can match nothing, and return true or false, as appropriate, when we get to one that can't, or to the - matching stop_memory. */ - + matching stop_memory. */ + switch ((re_opcode_t) *p1) - { - /* Could be either a loop or a series of alternatives. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - - /* If the next operation is not a jump backwards in the + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the pattern. */ if (mcnt >= 0) { - /* Go through the on_failure_jumps of the alternatives, - seeing if any of the alternatives cannot match nothing. - The last alternative starts with only a jump, - whereas the rest start with on_failure_jump and end - with a jump, e.g., here is the pattern for `a|b|c': + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': - /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 - /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 - /exactn/1/c + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c - So, we have to first go through the first (n-1) - alternatives and then deal with the last one separately. */ + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ - /* Deal with the first (n-1) alternatives, which start - with an on_failure_jump (see above) that jumps to right - past a jump_past_alt. */ + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ - while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) - { - /* `mcnt' holds how many bytes long the alternative - is, including the ending `jump_past_alt' and - its number. */ + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ - if (!alt_match_null_string_p (p1, p1 + mcnt - 3, - reg_info)) - return false; + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; - /* Move to right after this alternative, including the + /* Move to right after this alternative, including the jump_past_alt. */ - p1 += mcnt; + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; - /* Break if it's the beginning of an n-th alternative - that doesn't begin with an on_failure_jump. */ - if ((re_opcode_t) *p1 != on_failure_jump) - break; - /* Still have to check that it's not an n-th alternative that starts with an on_failure_jump. */ p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) - { + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { /* Get to the beginning of the n-th alternative. */ - p1 -= 3; - break; - } - } + p1 -= 3; + break; + } + } - /* Deal with the last alternative: go back and get number - of the `jump_past_alt' just before it. `mcnt' contains - the length of the alternative. */ - EXTRACT_NUMBER (mcnt, p1 - 2); + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); - if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) - return false; + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; - p1 += mcnt; /* Get past the n-th alternative. */ - } /* if mcnt > 0 */ - break; + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; - - case stop_memory: + + case stop_memory: assert (p1[1] == **p); - *p = p1 + 2; - return true; + *p = p1 + 2; + return true; - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } } /* while p1 < end */ return false; @@ -4438,7 +4438,7 @@ group_match_null_string_p (p, end, reg_info) /* Similar to group_match_null_string_p, but doesn't deal with alternatives: It expects P to be the first byte of a single alternative and END one byte past the last. The alternative can contain groups. */ - + static boolean alt_match_null_string_p (p, end, reg_info) unsigned char *p, *end; @@ -4446,25 +4446,25 @@ alt_match_null_string_p (p, end, reg_info) { int mcnt; unsigned char *p1 = p; - + while (p1 < end) { - /* Skip over opcodes that can match nothing, and break when we get - to one that can't. */ - + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + switch ((re_opcode_t) *p1) - { + { /* It's a loop. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - break; - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } } /* while p1 < end */ return true; @@ -4472,8 +4472,8 @@ alt_match_null_string_p (p, end, reg_info) /* Deals with the ops common to group_match_null_string_p and - alt_match_null_string_p. - + alt_match_null_string_p. + Sets P to one after the op and its arguments, if any. */ static boolean @@ -4508,44 +4508,44 @@ common_op_match_null_string_p (p, end, reg_info) reg_no = *p1; assert (reg_no > 0 && reg_no <= MAX_REGNUM); ret = group_match_null_string_p (&p1, end, reg_info); - + /* Have to set this here in case we're checking a group which - contains a group and a back reference to it. */ + contains a group and a back reference to it. */ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; if (!ret) - return false; + return false; break; - + /* If this is an optimized succeed_n for zero times, make the jump. */ case jump: EXTRACT_NUMBER_AND_INCR (mcnt, p1); if (mcnt >= 0) - p1 += mcnt; + p1 += mcnt; else - return false; + return false; break; case succeed_n: /* Get to the number of times to succeed. */ - p1 += 2; + p1 += 2; EXTRACT_NUMBER_AND_INCR (mcnt, p1); if (mcnt == 0) - { - p1 -= 4; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - } + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } else - return false; + return false; break; - case duplicate: + case duplicate: if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) - return false; + return false; break; case set_number_at: @@ -4563,7 +4563,7 @@ common_op_match_null_string_p (p, end, reg_info) /* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN bytes; nonzero otherwise. */ - + static int bcmp_translate( unsigned char *s1, @@ -4586,10 +4586,10 @@ bcmp_translate( /* re_compile_pattern is the GNU regular expression compiler: it compiles PATTERN (of length SIZE) and puts the result in BUFP. Returns 0 if the pattern was valid, otherwise an error string. - + Assumes the `allocated' (and perhaps `buffer') and `translate' fields are set in BUFP on entry. - + We call regex_compile to do the actual compilation. */ const char * @@ -4599,23 +4599,23 @@ re_compile_pattern (pattern, length, bufp) struct re_pattern_buffer *bufp; { reg_errcode_t ret; - + /* GNU code is written to assume at least RE_NREGS registers will be set (and at least one extra will be -1). */ bufp->regs_allocated = REGS_UNALLOCATED; - + /* And GNU code determines whether or not to get register information by passing null for the REGS argument to re_match, etc., not by setting no_sub. */ bufp->no_sub = 0; - + /* Match anchors at newline. */ bufp->newline_anchor = 1; - + ret = regex_compile (pattern, length, re_syntax_options, bufp); return re_error_msg[(int) ret]; -} +} /* Entry points compatible with 4.2 BSD regex library. We don't define them if this is an Emacs or POSIX compilation. */ @@ -4630,7 +4630,7 @@ re_comp (s) const char *s; { reg_errcode_t ret; - + if (!s) { if (!re_comp_buf.buffer) @@ -4642,7 +4642,7 @@ re_comp (s) { re_comp_buf.buffer = (unsigned char *) malloc (200); if (re_comp_buf.buffer == NULL) - return "Memory exhausted"; + return "Memory exhausted"; re_comp_buf.allocated = 200; re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); @@ -4657,7 +4657,7 @@ re_comp (s) re_comp_buf.newline_anchor = 1; ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); - + /* Yes, we're discarding `const' here. */ return (char *) re_error_msg[(int) ret]; } @@ -4714,7 +4714,7 @@ re_exec (s) int regcomp (preg, pattern, cflags) regex_t *preg; - const char *pattern; + const char *pattern; int cflags; { reg_errcode_t ret; @@ -4725,24 +4725,24 @@ regcomp (preg, pattern, cflags) /* regex_compile will allocate the space for the compiled pattern. */ preg->buffer = 0; preg->allocated = 0; - + /* Don't bother to use a fastmap when searching. This simplifies the REG_NEWLINE case: if we used a fastmap, we'd have to put all the characters after newlines into the fastmap. This way, we just try every character. */ preg->fastmap = 0; - + if (cflags & REG_ICASE) { unsigned i; - + preg->translate = (char *) malloc (CHAR_SET_SIZE); if (preg->translate == NULL) - return (int) REG_ESPACE; + return (int) REG_ESPACE; /* Map uppercase characters to corresponding lowercase ones. */ for (i = 0; i < CHAR_SET_SIZE; i++) - preg->translate[i] = ISUPPER (i) ? tolower (i) : i; + preg->translate[i] = ISUPPER (i) ? tolower (i) : i; } else preg->translate = NULL; @@ -4760,38 +4760,38 @@ regcomp (preg, pattern, cflags) preg->no_sub = !!(cflags & REG_NOSUB); - /* POSIX says a null character in the pattern terminates it, so we + /* POSIX says a null character in the pattern terminates it, so we can use strlen here in compiling the pattern. */ ret = regex_compile (pattern, strlen (pattern), syntax, preg); - + /* POSIX doesn't distinguish between an unmatched open-group and an unmatched close-group: both are REG_EPAREN. */ if (ret == REG_ERPAREN) ret = REG_EPAREN; - + return (int) ret; } /* regexec searches for a given pattern, specified by PREG, in the string STRING. - + If NMATCH is zero or REG_NOSUB was set in the cflags argument to `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at least NMATCH elements, and we set them to the offsets of the corresponding matched substrings. - + EFLAGS specifies `execution flags' which affect matching: if REG_NOTBOL is set, then ^ does not match at the beginning of the string; if REG_NOTEOL is set, then $ does not match at the end. - + We return 0 if we find a match and REG_NOMATCH if not. */ int regexec (preg, string, nmatch, pmatch, eflags) const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; int eflags; { int ret; @@ -4801,42 +4801,42 @@ regexec (preg, string, nmatch, pmatch, eflags) boolean want_reg_info = !preg->no_sub && nmatch > 0; private_preg = *preg; - + private_preg.not_bol = !!(eflags & REG_NOTBOL); private_preg.not_eol = !!(eflags & REG_NOTEOL); - + /* The user has told us exactly how many registers to return information about, via `nmatch'. We have to pass that on to the matching routines. */ private_preg.regs_allocated = REGS_FIXED; - + if (want_reg_info) { regs.num_regs = nmatch; regs.start = TALLOC (nmatch, regoff_t); regs.end = TALLOC (nmatch, regoff_t); if (regs.start == NULL || regs.end == NULL) - return (int) REG_NOMATCH; + return (int) REG_NOMATCH; } /* Perform the searching operation. */ ret = re_search (&private_preg, string, len, - /* start: */ 0, /* range: */ len, - want_reg_info ? ®s : (struct re_registers *) 0); - + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + /* Copy the register information to the POSIX structure. */ if (want_reg_info) { if (ret >= 0) - { - unsigned r; + { + unsigned r; - for (r = 0; r < nmatch; r++) - { - pmatch[r].rm_so = regs.start[r]; - pmatch[r].rm_eo = regs.end[r]; - } - } + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } /* If we needed the temporary register info, free the space now. */ free (regs.start); @@ -4863,7 +4863,7 @@ regerror (errcode, preg, errbuf, errbuf_size) if (errcode < 0 || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) - /* Only error codes returned by the rest of the code should be passed + /* Only error codes returned by the rest of the code should be passed to this routine. If we are given anything else, or if other regex code generates an invalid error code, then the program has a bug. Dump core so we can fix it. */ @@ -4877,16 +4877,16 @@ regerror (errcode, preg, errbuf, errbuf_size) msg = "Success"; msg_size = strlen (msg) + 1; /* Includes the null. */ - + if (errbuf_size != 0) { if (msg_size > errbuf_size) - { - strncpy (errbuf, msg, errbuf_size - 1); - errbuf[errbuf_size - 1] = 0; - } + { + strncpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + } else - strcpy (errbuf, msg); + strcpy (errbuf, msg); } return msg_size; @@ -4902,7 +4902,7 @@ regfree (preg) if (preg->buffer != NULL) free (preg->buffer); preg->buffer = NULL; - + preg->allocated = 0; preg->used = 0; diff --git a/compat/regex.h b/compat/regex.h index 408dd21034..6eb64f1402 100644 --- a/compat/regex.h +++ b/compat/regex.h @@ -42,7 +42,7 @@ typedef unsigned reg_syntax_t; #define RE_BACKSLASH_ESCAPE_IN_LISTS (1) /* If this bit is not set, then + and ? are operators, and \+ and \? are - literals. + literals. If set, then \+ and \? are operators and + and ? are literals. */ #define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) @@ -55,10 +55,10 @@ typedef unsigned reg_syntax_t; /* If this bit is set, then ^ and $ are always anchors (outside bracket expressions, of course). If this bit is not set, then it depends: - ^ is an anchor if it is at the beginning of a regular - expression or after an open-group or an alternation operator; - $ is an anchor if it is at the end of a regular expression, or - before a close-group or an alternation operator. + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because POSIX draft 11.2 says that * etc. in leading positions is undefined. @@ -69,7 +69,7 @@ typedef unsigned reg_syntax_t; /* If this bit is set, then special characters are always special regardless of where they are in the pattern. If this bit is not set, then special characters are special only in - some contexts; otherwise they are ordinary. Specifically, + some contexts; otherwise they are ordinary. Specifically, * + ? and intervals are only special when not after the beginning, open-group, or alternation operator. */ #define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) @@ -91,7 +91,7 @@ typedef unsigned reg_syntax_t; #define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) /* If this bit is set, either \{...\} or {...} defines an - interval, depending on RE_NO_BK_BRACES. + interval, depending on RE_NO_BK_BRACES. If not set, \{, \}, {, and } are literals. */ #define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) @@ -116,7 +116,7 @@ typedef unsigned reg_syntax_t; If not set, then \ is a back-reference. */ #define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) -/* If this bit is set, then | is an alternation operator, and \| is literal. +/* If this bit is set, then | is an alternation operator, and \| is literal. If not set, then \| is an alternation operator, and | is literal. */ #define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) @@ -138,7 +138,7 @@ extern reg_syntax_t re_syntax_options; /* Define combinations of the above bits for the standard possibilities. (The [[[ comments delimit what gets put into the Texinfo file, so - don't delete them!) */ + don't delete them!) */ /* [[[begin syntaxes]]] */ #define RE_SYNTAX_EMACS 0 @@ -205,7 +205,7 @@ extern reg_syntax_t re_syntax_options; #ifdef RE_DUP_MAX #undef RE_DUP_MAX #endif -#define RE_DUP_MAX ((1 << 15) - 1) +#define RE_DUP_MAX ((1 << 15) - 1) /* POSIX `cflags' bits (i.e., information for `regcomp'). */ @@ -217,7 +217,7 @@ extern reg_syntax_t re_syntax_options; /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ #define REG_ICASE (REG_EXTENDED << 1) - + /* If this bit is set, then anchors do not match at newline characters in the string. If not set, then anchors do match at newlines. */ @@ -256,7 +256,7 @@ typedef enum REG_EESCAPE, /* Trailing backslash. */ REG_ESUBREG, /* Invalid back reference. */ REG_EBRACK, /* Unmatched left bracket. */ - REG_EPAREN, /* Parenthesis imbalance. */ + REG_EPAREN, /* Parenthesis imbalance. */ REG_EBRACE, /* Unmatched \{. */ REG_BADBR, /* Invalid contents of \{\}. */ REG_ERANGE, /* Invalid range end. */ @@ -279,65 +279,65 @@ struct re_pattern_buffer { /* [[[begin pattern_buffer]]] */ /* Space that holds the compiled pattern. It is declared as - `unsigned char *' because its elements are - sometimes used as array indexes. */ + `unsigned char *' because its elements are + sometimes used as array indexes. */ unsigned char *buffer; /* Number of bytes to which `buffer' points. */ unsigned long allocated; /* Number of bytes actually used in `buffer'. */ - unsigned long used; + unsigned long used; - /* Syntax setting with which the pattern was compiled. */ + /* Syntax setting with which the pattern was compiled. */ reg_syntax_t syntax; - /* Pointer to a fastmap, if any, otherwise zero. re_search uses - the fastmap, if there is one, to skip over impossible - starting points for matches. */ + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ char *fastmap; - /* Either a translate table to apply to all characters before - comparing them, or zero for no translation. The translation - is applied to a pattern when it is compiled and to a string - when it is matched. */ + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ char *translate; /* Number of subexpressions found by the compiler. */ size_t re_nsub; - /* Zero if this pattern cannot match the empty string, one else. - Well, in truth it's used only in `re_search_2', to see - whether or not we should use the fastmap, so we don't set - this absolutely perfectly; see `re_compile_fastmap' (the - `duplicate' case). */ + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ unsigned can_be_null : 1; - /* If REGS_UNALLOCATED, allocate space in the `regs' structure - for `max (RE_NREGS, re_nsub + 1)' groups. - If REGS_REALLOCATE, reallocate space if necessary. - If REGS_FIXED, use what's there. */ + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ #define REGS_UNALLOCATED 0 #define REGS_REALLOCATE 1 #define REGS_FIXED 2 unsigned regs_allocated : 2; - /* Set to zero when `regex_compile' compiles a pattern; set to one - by `re_compile_fastmap' if it updates the fastmap. */ + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ unsigned fastmap_accurate : 1; - /* If set, `re_match_2' does not return information about - subexpressions. */ + /* If set, `re_match_2' does not return information about + subexpressions. */ unsigned no_sub : 1; - /* If set, a beginning-of-line anchor doesn't match at the - beginning of the string. */ + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ unsigned not_bol : 1; - /* Similarly for an end-of-line anchor. */ + /* Similarly for an end-of-line anchor. */ unsigned not_eol : 1; - /* If true, an anchor at a newline matches. */ + /* If true, an anchor at a newline matches. */ unsigned newline_anchor : 1; /* [[[end pattern_buffer]]] */ @@ -408,7 +408,7 @@ extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); BUFFER. Return NULL if successful, and an error string if not. */ extern const char *re_compile_pattern _RE_ARGS ((const char *pattern, int length, - struct re_pattern_buffer *buffer)); + struct re_pattern_buffer *buffer)); /* Compile a fastmap for the compiled pattern in BUFFER; used to @@ -424,29 +424,29 @@ extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); information in REGS (if REGS and BUFFER->no_sub are nonzero). */ extern int re_search _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, int range, struct re_registers *regs)); + int length, int start, int range, struct re_registers *regs)); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ extern int re_search_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, int range, struct re_registers *regs, int stop)); + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ extern int re_match _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, struct re_registers *regs)); + int length, int start, struct re_registers *regs)); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ -extern int re_match_2 +extern int re_match_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, struct re_registers *regs, int stop)); + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and @@ -463,7 +463,7 @@ extern int re_match_2 freeing the old data. */ extern void re_set_registers _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, - unsigned num_regs, regoff_t *starts, regoff_t *ends)); + unsigned num_regs, regoff_t *starts, regoff_t *ends)); /* 4.2 bsd compatibility. */ extern char *re_comp _RE_ARGS ((const char *)); @@ -473,10 +473,10 @@ extern int re_exec _RE_ARGS ((const char *)); extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); extern int regexec _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, - regmatch_t pmatch[], int eflags)); + regmatch_t pmatch[], int eflags)); extern size_t regerror _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, - size_t errbuf_size)); + size_t errbuf_size)); extern void regfree _RE_ARGS ((regex_t *preg)); #endif /* not __REGEXP_LIBRARY_H__ */ From 185fbb49c9bebc622602bc478d1ff2cb601cfcdd Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:51:19 +0200 Subject: [PATCH 437/781] Rename my_mktime() to tm_to_time_t() and make it officially extern. Signed-off-by: Johannes Sixt --- compat/mingw.c | 3 +-- date.c | 13 ++++++++----- git-compat-util.h | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 95ba563a27..488ff404ce 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -218,7 +218,6 @@ int mkstemp(char *template) int gettimeofday(struct timeval *tv, void *tz) { - extern time_t my_mktime(struct tm *tm); SYSTEMTIME st; struct tm tm; GetSystemTime(&st); @@ -228,7 +227,7 @@ int gettimeofday(struct timeval *tv, void *tz) tm.tm_hour = st.wHour; tm.tm_min = st.wMinute; tm.tm_sec = st.wSecond; - tv->tv_sec = my_mktime(&tm); + tv->tv_sec = tm_to_time_t(&tm); if (tv->tv_sec < 0) return -1; tv->tv_usec = st.wMilliseconds*1000; diff --git a/date.c b/date.c index d6f8bf61c3..35a52576c5 100644 --- a/date.c +++ b/date.c @@ -6,7 +6,10 @@ #include "cache.h" -time_t my_mktime(struct tm *tm) +/* + * This is like mktime, but without normalization of tm_wday and tm_yday. + */ +time_t tm_to_time_t(const struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 @@ -67,7 +70,7 @@ static int local_tzoffset(unsigned long time) t = time; localtime_r(&t, &tm); - t_local = my_mktime(&tm); + t_local = tm_to_time_t(&tm); if (t_local < t) { eastwest = -1; @@ -322,7 +325,7 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, if (!now_tm) return 1; - specified = my_mktime(r); + specified = tm_to_time_t(r); /* Be it commit time or author time, it does not make * sense to specify timestamp way into the future. Make @@ -572,7 +575,7 @@ int parse_date(const char *date, char *result, int maxlen) } /* mktime uses local timezone */ - then = my_mktime(&tm); + then = tm_to_time_t(&tm); if (offset == -1) offset = (then - mktime(&tm)) / 60; @@ -611,7 +614,7 @@ void datestamp(char *buf, int bufsize) time(&now); - offset = my_mktime(localtime(&now)) - now; + offset = tm_to_time_t(localtime(&now)) - now; offset /= 60; date_string(now, offset, buf, bufsize); diff --git a/git-compat-util.h b/git-compat-util.h index 46fc2d3cfc..2699db5a99 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -143,6 +143,7 @@ extern void set_error_routine(void (*routine)(const char *err, va_list params)); extern void set_warn_routine(void (*routine)(const char *warn, va_list params)); extern int prefixcmp(const char *str, const char *prefix); +extern time_t tm_to_time_t(const struct tm *tm); #ifdef NO_MMAP From 3c965bf3715bce76e69ad8fecee99dca4678d676 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:53:04 +0200 Subject: [PATCH 438/781] Handle getenv("TMPDIR") in a getenv() wrapper. This removes an #ifdef MINGW in path.c. Signed-off-by: Johannes Sixt --- compat/mingw.c | 13 +++++++++++++ compat/mingw.h | 3 +++ path.c | 7 ------- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 488ff404ce..116b4ca970 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -366,6 +366,19 @@ char *mingw_getcwd(char *pointer, int len) return ret; } +#undef getenv +char *mingw_getenv(const char *name) +{ + char *result = getenv(name); + if (!result && !strcmp(name, "TMPDIR")) { + /* on Windows it is TMP and TEMP */ + result = getenv("TMP"); + if (!result) + result = getenv("TEMP"); + } + return result; +} + /* * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx * (Parsing C++ Command-Line Arguments) diff --git a/compat/mingw.h b/compat/mingw.h index 6965e3f2df..6bc049ad99 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -145,6 +145,9 @@ int mingw_open (const char *filename, int oflags, ...); char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd +char *mingw_getenv(const char *name); +#define getenv mingw_getenv + struct hostent *mingw_gethostbyname(const char *host); #define gethostbyname mingw_gethostbyname diff --git a/path.c b/path.c index 5da41c709d..7a35a26a16 100644 --- a/path.c +++ b/path.c @@ -75,13 +75,6 @@ int git_mkstemp(char *path, size_t len, const char *template) size_t n; tmp = getenv("TMPDIR"); -#ifdef __MINGW32__ - /* on Windows it is TMP and TEMP */ - if (!tmp) - tmp = getenv("TMP"); - if (!tmp) - tmp = getenv("TEMP"); -#endif if (!tmp) tmp = "/tmp"; n = snprintf(path, len, "%s/%s", tmp, template); From cc81aaa17e0594f7ed9a84557d013f594c9c1ce1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:56:06 +0200 Subject: [PATCH 439/781] Remove #ifdef STRIP_EXTENSION from git.c Instead, we use a condition that is known at compile-time to have the compiler optimize away the code if it is not needed. Signed-off-by: Johannes Sixt --- git-compat-util.h | 4 ++++ git.c | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 2699db5a99..51823ae7af 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -114,6 +114,10 @@ #define PATH_SEP ':' #endif +#ifndef STRIP_EXTENSION +#define STRIP_EXTENSION "" +#endif + #ifndef has_dos_drive_prefix #define has_dos_drive_prefix(path) 0 #endif diff --git a/git.c b/git.c index a4b0a5e807..39db13a202 100644 --- a/git.c +++ b/git.c @@ -369,15 +369,16 @@ static void handle_internal_command(int argc, const char **argv) { "pack-refs", cmd_pack_refs, RUN_SETUP }, }; int i; + static const char ext[] = STRIP_EXTENSION; -#ifdef STRIP_EXTENSION - i = strlen(argv[0]) - strlen(STRIP_EXTENSION); - if (i > 0 && !strcmp(argv[0] + i, STRIP_EXTENSION)) { - char *argv0 = strdup(argv[0]); - argv[0] = cmd = argv0; - argv0[i] = '\0'; + if (sizeof(ext) > 1) { + i = strlen(argv[0]) - strlen(ext); + if (i > 0 && !strcmp(argv[0] + i, ext)) { + char *argv0 = strdup(argv[0]); + argv[0] = cmd = argv0; + argv0[i] = '\0'; + } } -#endif /* Turn "git cmd --help" into "git help cmd" */ if (argc > 1 && !strcmp(argv[1], "--help")) { From ab87ad4c62eaa6d415346676ad7d5457d739ebd3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:56:39 +0200 Subject: [PATCH 440/781] Touch-ups in comments and error strings in compat/mingw.c Signed-off-by: Johannes Sixt --- compat/mingw.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 116b4ca970..3a05fe7da6 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -189,7 +189,7 @@ int mingw_utime (const char *file_name, const struct utimbuf *times) /* must have write permission */ if ((fh = open(file_name, O_RDWR | O_BINARY)) < 0) - return -1; + return -1; time_t_to_filetime(times->modtime, &mft); time_t_to_filetime(times->actime, &aft); @@ -907,13 +907,12 @@ static int one_shot; static sig_handler_t timer_fn = SIG_DFL; /* The timer works like this: - * The thread, ticktack(), is basically a trivial routine that most of the - * time only waits to receive the signal to terminate. The main thread - * tells the thread to terminate by setting the timer_event to the signalled + * The thread, ticktack(), is a trivial routine that most of the time + * only waits to receive the signal to terminate. The main thread tells + * the thread to terminate by setting the timer_event to the signalled * state. - * But ticktack() does not wait indefinitely; instead, it interrupts the - * wait state every now and then, namely exactly after timer's interval - * length. At these opportunities it calls the signal handler. + * But ticktack() interrupts the wait state after the timer's interval + * length to call the signal handler. */ static __stdcall unsigned ticktack(void *dummy) @@ -939,7 +938,7 @@ static int start_timer_thread(void) error("cannot start timer thread"); } else return errno = ENOMEM, - error("cannot allocate resources timer"); + error("cannot allocate resources for timer"); return 0; } @@ -974,11 +973,11 @@ int setitimer(int type, struct itimerval *in, struct itimerval *out) if (out != NULL) return errno = EINVAL, - error("setitmer param 3 != NULL not implemented"); + error("setitimer param 3 != NULL not implemented"); if (!is_timeval_eq(&in->it_interval, &zero) && !is_timeval_eq(&in->it_interval, &in->it_value)) return errno = EINVAL, - error("setitmer: it_interval must be zero or eq it_value"); + error("setitimer: it_interval must be zero or eq it_value"); if (timer_thread) stop_timer_thread(); From b0115de33336cda96cb3c0637a7985c7c5b436ac Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:57:56 +0200 Subject: [PATCH 441/781] Remove a 'break' that was accidentally left over The conversion of the 'switch' statement to an 'if' cascade forgot to remove the break. Signed-off-by: Johannes Sixt --- setup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.c b/setup.c index ec33147ad8..8bb7b10174 100644 --- a/setup.c +++ b/setup.c @@ -35,7 +35,6 @@ static int sanitary_path_copy(char *dst, const char *src) if (!src[1]) { /* (1) */ src++; - break; } else if (is_dir_sep(src[1])) { /* (2) */ src += 2; From 16502c915ff3bc148c53eaae773eb0dbe895caa9 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Jun 2008 10:59:12 +0200 Subject: [PATCH 442/781] Hand-roll the search for the program name to remove #ifdef MINGW. We now use is_dir_sep() to scan argv[0] for the program name. Signed-off-by: Johannes Sixt --- git.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/git.c b/git.c index 39db13a202..871b93ca7e 100644 --- a/git.c +++ b/git.c @@ -396,8 +396,8 @@ static void handle_internal_command(int argc, const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] ? argv[0] : "git-help"; - char *slash = strrchr(cmd, '/'); + const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; + char *slash = (char *)cmd + strlen(cmd); const char *cmd_path = NULL; int done_alias = 0; @@ -406,12 +406,10 @@ int main(int argc, const char **argv) * name, and the dirname as the default exec_path * if we don't have anything better. */ -#ifdef __MINGW32__ - char *bslash = strrchr(cmd, '\\'); - if (!slash || (bslash && bslash > slash)) - slash = bslash; -#endif - if (slash) { + do + --slash; + while (cmd <= slash && !is_dir_sep(*slash)); + if (cmd <= slash) { *slash++ = 0; cmd_path = cmd; cmd = slash; From dcaceb0a278ca1293cb0b50cc60cdde721dc0de0 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Jul 2008 09:03:53 +0200 Subject: [PATCH 443/781] Revert "Change the name of hook scripts to make them not executable by default." This reverts commits 13cae476, bdb6d4ec, daabe66f. They are not necessary anymore, because the sample hooks now have a .sample postfix. --- Makefile | 3 +-- templates/Makefile | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Makefile b/Makefile index bc7256d170..78e08d3745 100644 --- a/Makefile +++ b/Makefile @@ -743,7 +743,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o EXTLIBS += -lws2_32 X = .exe - NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig endif @@ -1058,7 +1057,7 @@ ifndef NO_TCLTK $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all endif $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all - $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) NOEXECTEMPL='$(NOEXECTEMPL)' + $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X diff --git a/templates/Makefile b/templates/Makefile index ab2c823ae0..9f3f1fc352 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -10,8 +10,6 @@ RM ?= rm -f prefix ?= $(HOME) template_instdir ?= $(prefix)/share/git-core/templates # DESTDIR= -# set NOEXECTEMPL to non-empty to change the names of hook scripts -# so that the tools will not find them # Shell quote (do not use $(call) to accommodate ancient setups); DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) @@ -34,7 +32,6 @@ boilerplates.made : $(bpsrc) $(INSTALL) -d -m 755 blt/$$dir && \ case "$$boilerplate" in \ *--) ;; \ - hooks--*) cp -p $$boilerplate blt/$${dst}$(NOEXECTEMPL) ;; \ *) cp -p $$boilerplate blt/$$dst ;; \ esac || exit; \ done && \ From a3fb126011ff47be25b194f80b74e851ef3c7482 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Jul 2008 09:29:45 +0200 Subject: [PATCH 444/781] t4127-apply-same-fn: Avoid sed -i Signed-off-by: Johannes Sixt --- t/t4127-apply-same-fn.sh | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/t/t4127-apply-same-fn.sh b/t/t4127-apply-same-fn.sh index 2a6ed77c65..1f859dd908 100755 --- a/t/t4127-apply-same-fn.sh +++ b/t/t4127-apply-same-fn.sh @@ -4,6 +4,11 @@ test_description='apply same filename' . ./test-lib.sh +modify () { + sed -e "$1" < "$2" > "$2".x && + mv "$2".x "$2" +} + test_expect_success setup ' for i in a b c d e f g h i j k l m do @@ -14,10 +19,10 @@ test_expect_success setup ' git commit -m initial ' test_expect_success 'apply same filename with independent changes' ' - sed -i -e "s/^d/z/" same_fn && + modify "s/^d/z/" same_fn && git diff > patch0 && git add same_fn && - sed -i -e "s/^i/y/" same_fn && + modify "s/^i/y/" same_fn && git diff >> patch0 && cp same_fn same_fn2 && git reset --hard && @@ -27,10 +32,10 @@ test_expect_success 'apply same filename with independent changes' ' test_expect_success 'apply same filename with overlapping changes' ' git reset --hard - sed -i -e "s/^d/z/" same_fn && + modify "s/^d/z/" same_fn && git diff > patch0 && git add same_fn && - sed -i -e "s/^e/y/" same_fn && + modify "s/^e/y/" same_fn && git diff >> patch0 && cp same_fn same_fn2 && git reset --hard && @@ -41,10 +46,10 @@ test_expect_success 'apply same filename with overlapping changes' ' test_expect_success 'apply same new filename after rename' ' git reset --hard git mv same_fn new_fn - sed -i -e "s/^d/z/" new_fn && + modify "s/^d/z/" new_fn && git add new_fn && git diff -M --cached > patch1 && - sed -i -e "s/^e/y/" new_fn && + modify "s/^e/y/" new_fn && git diff >> patch1 && cp new_fn new_fn2 && git reset --hard && @@ -55,11 +60,11 @@ test_expect_success 'apply same new filename after rename' ' test_expect_success 'apply same old filename after rename -- should fail.' ' git reset --hard git mv same_fn new_fn - sed -i -e "s/^d/z/" new_fn && + modify "s/^d/z/" new_fn && git add new_fn && git diff -M --cached > patch1 && git mv new_fn same_fn - sed -i -e "s/^e/y/" same_fn && + modify "s/^e/y/" same_fn && git diff >> patch1 && git reset --hard && test_must_fail git apply patch1 @@ -68,15 +73,15 @@ test_expect_success 'apply same old filename after rename -- should fail.' ' test_expect_success 'apply A->B (rename), C->A (rename), A->A -- should pass.' ' git reset --hard git mv same_fn new_fn - sed -i -e "s/^d/z/" new_fn && + modify "s/^d/z/" new_fn && git add new_fn && git diff -M --cached > patch1 && git commit -m "a rename" && git mv other_fn same_fn - sed -i -e "s/^e/y/" same_fn && + modify "s/^e/y/" same_fn && git add same_fn && git diff -M --cached >> patch1 && - sed -i -e "s/^g/x/" same_fn && + modify "s/^g/x/" same_fn && git diff >> patch1 && git reset --hard HEAD^ && git apply patch1 From 56cfc88a46842653218c1575d63068a0b1b8bb66 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 2 Jul 2008 11:07:38 +0200 Subject: [PATCH 445/781] Avoid /dev/zero in tests. On Windows, we do not have /dev/zero or an equivalent. Work around this using a shell loop that produces zero bytes. Signed-off-by: Johannes Sixt --- t/t5302-pack-index.sh | 8 +++++++- t/t5303-pack-corruption-resilience.sh | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index ecec591634..74e10aaf09 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -6,6 +6,12 @@ test_description='pack index with 64-bit offsets and object CRC' . ./test-lib.sh +zeros () { + while :; do + echo -n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + done | tr x '\0' +} + test_expect_success \ 'setup' \ 'rm -rf .git @@ -168,7 +174,7 @@ test_expect_success \ git-index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && git verify-pack ".git/objects/pack/pack-${pack1}.pack" && chmod +w ".git/objects/pack/pack-${pack1}.idx" && - dd if=/dev/zero of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ + zeros | dd of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ bs=1 count=4 seek=$((8 + 256 * 4 + `wc -l /dev/null || exit 1 diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 31b20b21d2..874c6fe705 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -41,11 +41,17 @@ create_new_pack() { git verify-pack -v ${pack}.pack } +zeros () { + while :; do + echo -n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + done | tr x '\0' +} + do_corrupt_object() { ofs=`git show-index < ${pack}.idx | grep $1 | cut -f1 -d" "` && ofs=$(($ofs + $2)) && chmod +w ${pack}.pack && - dd if=/dev/zero of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs && + zeros | dd of=${pack}.pack count=1 bs=1 conv=notrunc seek=$ofs && test_must_fail git verify-pack ${pack}.pack } From 17e3d3f605ce39dd85dcded65cd6ba08ccf7ee73 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 16:18:12 +0200 Subject: [PATCH 446/781] Revert "fast-import: fix compilation on MinGW" This reverts commit 54d99a7724a0c7fb53bcdc7d850034e9890a0138. A dummy implementation of getppid was added to the compat layer, so this ifdef is no longer needed. --- fast-import.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fast-import.c b/fast-import.c index 271b93cf76..e72b286794 100644 --- a/fast-import.c +++ b/fast-import.c @@ -391,9 +391,7 @@ static void write_crash_report(const char *err) fprintf(rpt, "fast-import crash report:\n"); fprintf(rpt, " fast-import process: %d\n", getpid()); -#ifndef __MINGW32__ fprintf(rpt, " parent process : %d\n", getppid()); -#endif fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL)); fputc('\n', rpt); From 5278ad45e345e4e7f0418b4733f54823b7199801 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 16:27:40 +0200 Subject: [PATCH 447/781] Revert "Avoid calling signal(SIGPIPE, ..) for MinGW builds." This reverts commit 56be985fe902a4af8c7f0bbe4541ef783ead827f. SIGPIPE is defined in the compat layer, so this ifdef is no longer needed. --- builtin-verify-tag.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index 540e3b9b75..92eaa89a45 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -100,11 +100,9 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) i++; } -#ifndef __MINGW32__ /* sometimes the program was terminated because this signal * was received in the process of writing the gpg input: */ signal(SIGPIPE, SIG_IGN); -#endif while (i < argc) if (verify_tag(argv[i++], verbose)) had_error = 1; From c00ce6091514f55931cb15d8dec014767ad918b4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 16:32:48 +0200 Subject: [PATCH 448/781] convert.c: Fix style (no functional changes) --- convert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/convert.c b/convert.c index f24ac25c49..1d3e8b02f1 100644 --- a/convert.c +++ b/convert.c @@ -63,7 +63,7 @@ static void gather_stats(const char *buf, unsigned long size, struct text_stat * } // If file ends with EOF then don't count this EOF as non-printable - if ( size >= 1 && buf[size-1] == '\032' ) + if (size >= 1 && buf[size-1] == '\032') stats->nonprintable--; } From adf63bc4e33d9fc5b2e7079aec484d6563788db3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Wed, 2 Jul 2008 19:11:11 +0200 Subject: [PATCH 449/781] Revert "verify_path(): do not allow absolute paths" This reverts commit 8e78bd571071805ca9f34a6bc93846f6e5b15f4e. We do support absolute paths on Windows now. --- read-cache.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/read-cache.c b/read-cache.c index 5b109606e0..8e5fbb6192 100644 --- a/read-cache.c +++ b/read-cache.c @@ -634,11 +634,6 @@ int verify_path(const char *path) { char c; -#ifdef __MINGW32__ - if (is_absolute_path(path)) - return error("Cannot handle absolute path: %s", path); -#endif - goto inside; for (;;) { if (!c) From 861bebb42573c2812db44ff5a5dcfa4b7cd28224 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 3 Jul 2008 07:56:21 +0200 Subject: [PATCH 450/781] Revert "Fake reencoding success under NO_ICONV instead of returning NULL." We have a working iconv now, so this workaround is no longer needed. --- utf8.c | 7 ------- utf8.h | 4 ++++ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/utf8.c b/utf8.c index b07d43e580..dc3735364f 100644 --- a/utf8.c +++ b/utf8.c @@ -388,11 +388,4 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e iconv_close(conv); return out; } -#else -char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding) -{ - if (!in_encoding) - return NULL; - return xstrdup(in); -} #endif diff --git a/utf8.h b/utf8.h index f22ef3133c..98cce1b038 100644 --- a/utf8.h +++ b/utf8.h @@ -10,6 +10,10 @@ int is_encoding_utf8(const char *name); int print_wrapped_text(const char *text, int indent, int indent2, int len); +#ifndef NO_ICONV char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding); +#else +#define reencode_string(a,b,c) NULL +#endif #endif From 065eb05f3fca2b9a2a7a1fb39ca7dffd7f932f45 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 3 Jul 2008 08:18:47 +0200 Subject: [PATCH 451/781] connect.c: Remove comment that will not be sent upstream --- connect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/connect.c b/connect.c index 11fa151eb3..0d007f366f 100644 --- a/connect.c +++ b/connect.c @@ -596,7 +596,6 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; - /* be sure to increase this size if you add more args */ conn->argv = arg = xcalloc(6, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); From 3f3d496f8b8bf0bb2e74b0bf8268d3a19cbf553d Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Thu, 3 Jul 2008 08:21:43 +0200 Subject: [PATCH 452/781] help.c: Fix line endings (CRLF -> LF) --- help.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/help.c b/help.c index 2ed68389fe..fc45f463e3 100644 --- a/help.c +++ b/help.c @@ -28,12 +28,12 @@ enum help_format { HELP_FORMAT_WEB, }; -static int show_all = 0; -#ifdef __MINGW32__ -static enum help_format help_format = HELP_FORMAT_WEB; +static int show_all = 0; +#ifdef __MINGW32__ +static enum help_format help_format = HELP_FORMAT_WEB; #else static enum help_format help_format = HELP_FORMAT_MAN; -#endif +#endif static struct option builtin_help_options[] = { OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), From 2d556c22398cc4b76edce448a8f24239eb0e8631 Mon Sep 17 00:00:00 2001 From: Eric Raible Date: Thu, 26 Jun 2008 22:04:47 +0000 Subject: [PATCH 453/781] Teach lookup_prog not to select directories Without this simple fix "git gui" in the git source directory finds the git-gui directory instead of the tcl script in /usr/bin. Signed-off-by: Eric Raible Signed-off-by: Johannes Sixt --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 3a05fe7da6..bb33c8dfa2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -536,7 +536,8 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on return xstrdup(path); path[strlen(path)-4] = '\0'; if ((!exe_only || isexe) && access(path, F_OK) == 0) - return xstrdup(path); + if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY)) + return xstrdup(path); return NULL; } From 2a337eda67f4e62520fb38a48c51577f572065da Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 7 Jul 2008 11:10:20 +0200 Subject: [PATCH 454/781] builtin-clone: Use is_dir_sep() instead of '/' Signed-off-by: Johannes Sixt --- builtin-clone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-clone.c b/builtin-clone.c index 643c7d4169..fddf47fabf 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -115,7 +115,7 @@ static char *guess_dir_name(const char *repo, int is_bundle) if (!after_slash_or_colon) end = p; p += 7; - } else if (*p == '/' || *p == ':') { + } else if (is_dir_sep(*p) || *p == ':') { if (end == limit) end = p; after_slash_or_colon = 1; From 14c8eef4e02f9c2f7955c435467f42fa3aeac072 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Wed, 9 Jul 2008 17:34:20 -0400 Subject: [PATCH 455/781] Add ANSI control code emulation for the Windows console This adds only the minimum necessary to keep git pull/merge's diffstat from wrapping. Notably absent is support for the K (erase) operation, and support for POSIX write. Signed-off-by: Peter Harris Signed-off-by: Johannes Sixt --- Makefile | 2 +- compat/mingw.h | 11 ++ compat/winansi.c | 345 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 compat/winansi.c diff --git a/Makefile b/Makefile index 78e08d3745..2c6cc9d196 100644 --- a/Makefile +++ b/Makefile @@ -740,7 +740,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe template_dir = ../share/git-core/templates/ diff --git a/compat/mingw.h b/compat/mingw.h index 6bc049ad99..5f11114890 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -193,6 +193,17 @@ static inline unsigned int git_ntohl(unsigned int x) sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +/* + * 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__) + /* * git specific compatibility */ diff --git a/compat/winansi.c b/compat/winansi.c new file mode 100644 index 0000000000..e2d96dfe6f --- /dev/null +++ b/compat/winansi.c @@ -0,0 +1,345 @@ +/* + * Copyright 2008 Peter Harris + */ + +#include +#include "../git-compat-util.h" + +/* + Functions to be wrapped: +*/ +#undef printf +#undef fprintf +#undef fputs +/* TODO: write */ + +/* + ANSI codes used by git: m, K + + This file is git-specific. Therefore, this file does not attempt + to implement any codes that are not used by git. + + TODO: K +*/ + +static HANDLE console; +static WORD plain_attr; +static WORD attr; +static int negative; + +static void init(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + static int initialized = 0; + if (initialized) + return; + + console = GetStdHandle(STD_OUTPUT_HANDLE); + if (console == INVALID_HANDLE_VALUE) + console = NULL; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + attr = plain_attr = sbi.wAttributes; + negative = 0; + + initialized = 1; +} + + +#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) + +static void set_console_attr(void) +{ + WORD attributes = attr; + if (negative) { + attributes &= ~FOREGROUND_ALL; + attributes &= ~BACKGROUND_ALL; + + /* This could probably use a bitmask + instead of a series of ifs */ + if (attr & FOREGROUND_RED) + attributes |= BACKGROUND_RED; + if (attr & FOREGROUND_GREEN) + attributes |= BACKGROUND_GREEN; + if (attr & FOREGROUND_BLUE) + attributes |= BACKGROUND_BLUE; + + if (attr & BACKGROUND_RED) + attributes |= FOREGROUND_RED; + if (attr & BACKGROUND_GREEN) + attributes |= FOREGROUND_GREEN; + if (attr & BACKGROUND_BLUE) + attributes |= FOREGROUND_BLUE; + } + SetConsoleTextAttribute(console, attributes); +} + +static const char *set_attr(const char *str) +{ + const char *func; + size_t len = strspn(str, "0123456789;"); + func = str + len; + + switch (*func) { + case 'm': + do { + long val = strtol(str, (char **)&str, 10); + switch (val) { + case 0: /* reset */ + attr = plain_attr; + negative = 0; + break; + case 1: /* bold */ + attr |= FOREGROUND_INTENSITY; + break; + case 2: /* faint */ + case 22: /* normal */ + attr &= ~FOREGROUND_INTENSITY; + break; + case 3: /* italic */ + /* Unsupported */ + break; + case 4: /* underline */ + case 21: /* double underline */ + /* Wikipedia says this flag does nothing */ + /* Furthermore, mingw doesn't define this flag + attr |= COMMON_LVB_UNDERSCORE; */ + break; + case 24: /* no underline */ + /* attr &= ~COMMON_LVB_UNDERSCORE; */ + break; + case 5: /* slow blink */ + case 6: /* fast blink */ + /* We don't have blink, but we do have + background intensity */ + attr |= BACKGROUND_INTENSITY; + break; + case 25: /* no blink */ + attr &= ~BACKGROUND_INTENSITY; + break; + case 7: /* negative */ + negative = 1; + break; + case 27: /* positive */ + negative = 0; + break; + case 8: /* conceal */ + case 28: /* reveal */ + /* Unsupported */ + break; + case 30: /* Black */ + attr &= ~FOREGROUND_ALL; + break; + case 31: /* Red */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED; + break; + case 32: /* Green */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN; + break; + case 33: /* Yellow */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case 34: /* Blue */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_BLUE; + break; + case 35: /* Magenta */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case 36: /* Cyan */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 37: /* White */ + attr |= FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_BLUE; + break; + case 38: /* Unknown */ + break; + case 39: /* reset */ + attr &= ~FOREGROUND_ALL; + attr |= (plain_attr & FOREGROUND_ALL); + break; + case 40: /* Black */ + attr &= ~BACKGROUND_ALL; + break; + case 41: /* Red */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED; + break; + case 42: /* Green */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN; + break; + case 43: /* Yellow */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case 44: /* Blue */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_BLUE; + break; + case 45: /* Magenta */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case 46: /* Cyan */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 47: /* White */ + attr |= BACKGROUND_RED | + BACKGROUND_GREEN | + BACKGROUND_BLUE; + break; + case 48: /* Unknown */ + break; + case 49: /* reset */ + attr &= ~BACKGROUND_ALL; + attr |= (plain_attr & BACKGROUND_ALL); + break; + default: + /* Unsupported code */ + break; + } + str++; + } while (*(str-1) == ';'); + + set_console_attr(); + break; + case 'K': + /* TODO */ + break; + default: + /* Unsupported code */ + break; + } + + return func + 1; +} + +static int ansi_emulate(const char *str, FILE *stream) +{ + 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; + } + + str = pos + 2; + rv += 2; + + fflush(stream); + + pos = set_attr(str); + rv += pos - str; + str = pos; + } else { + rv += strlen(str); + fputs(str, stream); + return rv; + } + } + return rv; +} + +int winansi_fputs(const char *str, FILE *stream) +{ + int rv; + + if (!isatty(fileno(stream))) + return fputs(str, stream); + + init(); + + if (!console) + return fputs(str, stream); + + rv = ansi_emulate(str, stream); + + if (rv >= 0) + return 0; + else + return EOF; +} + +static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +{ + int len, rv; + char small_buf[256]; + char *buf = small_buf; + va_list cp; + + if (!isatty(fileno(stream))) + goto abort; + + init(); + + if (!console) + goto abort; + + va_copy(cp, list); + len = vsnprintf(small_buf, sizeof(small_buf), format, cp); + va_end(cp); + + if (len > sizeof(small_buf) - 1) { + buf = malloc(len + 1); + if (!buf) + goto abort; + + len = vsnprintf(buf, len + 1, format, list); + } + + rv = ansi_emulate(buf, stream); + + if (buf != small_buf) + free(buf); + return rv; + +abort: + rv = vfprintf(stream, format, list); + return rv; +} + +int winansi_fprintf(FILE *stream, const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stream, format, list); + va_end(list); + + return rv; +} + +int winansi_printf(const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stdout, format, list); + va_end(list); + + return rv; +} From a31c17daf43e67020d3a1d7a39d1e251709e0633 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 07:16:21 +0200 Subject: [PATCH 456/781] help.c (Windows): Revert help.c in preparation for merge of better solution --- help.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/help.c b/help.c index 811f8dbb11..ca9632b6c5 100644 --- a/help.c +++ b/help.c @@ -9,7 +9,6 @@ #include "common-cmds.h" #include "parse-options.h" #include "run-command.h" -#include "dir.h" static struct man_viewer_list { struct man_viewer_list *next; @@ -29,11 +28,7 @@ enum help_format { }; static int show_all = 0; -#ifdef __MINGW32__ -static enum help_format help_format = HELP_FORMAT_WEB; -#else static enum help_format help_format = HELP_FORMAT_MAN; -#endif static struct option builtin_help_options[] = { OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), @@ -649,35 +644,12 @@ static void get_html_page_path(struct strbuf *page_path, const char *page) static void show_html_page(const char *git_cmd) { -#ifdef __MINGW32__ - const char* exec_path = git_exec_path(); - char *htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/%s.html" - , exec_path - , git_cmd) - ); - if (!file_exists(htmlpath)) { - htmlpath = make_native_separator( - mkpath("%s/../doc/git/html/git-%s.html" - , exec_path - , git_cmd) - ); - if (!file_exists(htmlpath)) { - fprintf(stderr, "Can't find HTML help for '%s'.\n" - , git_cmd); - exit(1); - } - } - printf("Launching default browser to display HTML help ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); -#else const char *page = cmd_to_page(git_cmd); struct strbuf page_path; /* it leaks but we exec bellow */ get_html_page_path(&page_path, page); execl_git_cmd("web--browse", "-c", "help.browser", page_path.buf, NULL); -#endif } void help_unknown_cmd(const char *cmd) From 04bad247702047dcf53c87247d72c07513cb90a6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 07:23:02 +0200 Subject: [PATCH 457/781] help (Windows): Use msysgit-specific relative path to htmldir --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 06df0ba5be..5b5f1603f1 100644 --- a/Makefile +++ b/Makefile @@ -747,6 +747,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NOEXECTEMPL = .noexec template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig + htmldir=../doc/git/html/ endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From 9b096dc9bb239309ba87456b7e2af56f436f91a3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 07:28:49 +0200 Subject: [PATCH 458/781] help (Windows): Revert leftovers of old implementation --- cache.h | 2 -- path.c | 13 ------------- 2 files changed, 15 deletions(-) diff --git a/cache.h b/cache.h index 2c4d9b3776..0d8eddac77 100644 --- a/cache.h +++ b/cache.h @@ -527,8 +527,6 @@ static inline int is_absolute_path(const char *path) const char *make_absolute_path(const char *path); const char *make_nonrelative_path(const char *path); const char *make_relative_path(const char *abs, const char *base); -/* Convert slashes in place. On Windows to backslashes. */ -char *make_native_separator(char *path); int normalize_absolute_path(char *buf, const char *path); int longest_ancestor_length(const char *path, const char *prefix_list); diff --git a/path.c b/path.c index 96503d96cd..504eae061f 100644 --- a/path.c +++ b/path.c @@ -439,16 +439,3 @@ int longest_ancestor_length(const char *path, const char *prefix_list) return max_len; } - -char *make_native_separator(char* path) { -#ifdef __MINGW32__ - char* c; - for (c = path; *c; c++) { - if (*c == '/') - *c = '\\'; - } - return path; -#else - return path; -#endif -} From 5d54e5d4f2c0ccd3670fc12eaa86047fd0822cf4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 14 Jul 2008 08:00:16 +0200 Subject: [PATCH 459/781] setup (Windows): Revert leftovers of old implementation The handling of paths was resolved differently in the MinGW port that is merged to official git. This commit takes this implementation. Signed-off-by: Steffen Prohaska --- setup.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/setup.c b/setup.c index 1fd30c4b43..6cf909463d 100644 --- a/setup.c +++ b/setup.c @@ -381,7 +381,6 @@ const char *setup_git_directory_gently(int *nongit_ok) const char *gitdirenv; const char *gitfile_dir; int len, offset, ceil_offset; - int minoffset = 0; /* * Let's assume that we are in a git repository. @@ -432,8 +431,6 @@ const char *setup_git_directory_gently(int *nongit_ok) if (!getcwd(cwd, sizeof(cwd)-1)) die("Unable to read current working directory"); - if (has_dos_drive_prefix(cwd)) - minoffset = 2; ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) @@ -464,11 +461,11 @@ const char *setup_git_directory_gently(int *nongit_ok) inside_git_dir = 1; if (!work_tree_env) inside_work_tree = 0; - set_git_dir("."); + setenv(GIT_DIR_ENVIRONMENT, ".", 1); check_repository_format_gently(nongit_ok); return NULL; } - while (offset > minoffset && --offset > ceil_offset && cwd[offset] != '/'); + while (--offset > ceil_offset && cwd[offset] != '/'); if (offset <= ceil_offset) { if (nongit_ok) { if (chdir(cwd)) From e0e7163c215a6e74940cc1b66c7f4461359a7dc1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 15 Jul 2008 10:02:57 +0200 Subject: [PATCH 460/781] Windows: set gitexecdir = $(bindir) The "dash-less" change aims to remove git commands from $PATH. It does so by defining a GIT_EXEC_PATH that is different from $(bindir). On Windows we want a relocatable installation of the git tool, so we cannot use an absolute GIT_EXEC_PATH. Therefore, the implementation of builtin_exec_path() on Windows derives the exec-path from the command invocation, and disregards GIT_EXEC_PATH. But this broke when $(gitexecdir) became different from $(bindir), so we restore the earlier behavior here. This counteracts the aims of the "dash-less" change on Windows, but better this way than having no working git at all. Signed-off-by: Johannes Sixt --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 36339d3aff..7d466b3c3b 100644 --- a/Makefile +++ b/Makefile @@ -742,6 +742,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe + gitexecdir = $(bindir) template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig endif From a79b6908829b5804dbfab78050fa9991f59597f9 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Tue, 22 Jul 2008 22:07:23 +0200 Subject: [PATCH 461/781] Makefile: cleanup leftovers from old winansi implementation --- Makefile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile b/Makefile index f7da7e7870..0cdfcd2762 100644 --- a/Makefile +++ b/Makefile @@ -739,7 +739,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_R_TO_GCC_LINKER = YesPlease INTERNAL_QSORT = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease - WIN_ANSI = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" @@ -987,11 +986,6 @@ ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif -ifdef WIN_ANSI - COMPAT_CFLAGS += -DWIN_ANSI - COMPAT_OBJS += compat/winansi.o -endif - ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif From 1ddfb58a5edcbdaf7371fe0036026c57aeed6a2c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 26 Jul 2008 11:27:43 +0200 Subject: [PATCH 462/781] Modify mingw_main() workaround to avoid link errors With MinGW's gcc.exe (GCC) 3.4.5 (mingw special) GNU ld version 2.17.50 20060824 the old define caused link errors: git.o: In function `main': C:/msysgit/git/git.c:500: undefined reference to `mingw_main' collect2: ld returned 1 exit status The modified define works. Signed-off-by: Steffen Prohaska --- compat/mingw.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 290a9e6f82..a52e657c51 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -228,9 +228,10 @@ char **env_setenv(char **env, const char *name); * A replacement of main() that ensures that argv[0] has a path */ -#define main(c,v) main(int argc, const char **argv) \ +#define main(c,v) dummy_decl_mingw_main(); \ +static int mingw_main(); \ +int main(int argc, const char **argv) \ { \ - static int mingw_main(); \ argv[0] = xstrdup(_pgmptr); \ return mingw_main(argc, argv); \ } \ From 6cfef43abe77633e8e42389747d406fae87a91f2 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 21 Jul 2008 11:17:26 +0200 Subject: [PATCH 463/781] Revert "Windows: set gitexecdir = $(bindir)" This reverts commit e0e7163c215a6e74940cc1b66c7f4461359a7dc1. --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 5e3d48183c..b01cf1c993 100644 --- a/Makefile +++ b/Makefile @@ -745,7 +745,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = $(bindir) template_dir = ../share/git-core/templates/ ETC_GITCONFIG = ../etc/gitconfig endif From 01d9b2d0d678204761b2869b5f9ab28f26674fec Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 26 Jul 2008 23:04:41 +0200 Subject: [PATCH 464/781] Fix t5602-clone-remote-exec on MSYS MSYS rewrites /something/bin/... into a Windows path that is somewhere inside the MSYS installation directory. We make the path relative so that this rewriting is not triggered. Signed-off-by: Johannes Sixt --- t/t5602-clone-remote-exec.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh index 8367a6845f..ce64449c0b 100755 --- a/t/t5602-clone-remote-exec.sh +++ b/t/t5602-clone-remote-exec.sh @@ -18,8 +18,8 @@ test_expect_success 'clone calls git-upload-pack unqualified with no -u option' ' test_expect_success 'clone calls specified git-upload-pack with -u option' ' - GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk - echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected + GIT_SSH=./not_ssh git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk + echo "localhost ./something/bin/git-upload-pack '\''/path/to/repo'\''" >expected test_cmp expected not_ssh_output ' From 967b742f714410e2cf4d14fb3a0522000ec1d4a7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 27 Jul 2008 09:53:02 +0200 Subject: [PATCH 465/781] Makefile: Fix crlf newline Signed-off-by: Steffen Prohaska --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0797e070f6..b2bc0efe10 100644 --- a/Makefile +++ b/Makefile @@ -755,7 +755,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 - X = .exe + X = .exe NOEXECTEMPL = .noexec gitexecdir = ../libexec/git-core template_dir = ../share/git-core/templates/ From dd487dc5c3daae2466dd7ec539259d96f08917de Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 29 Jul 2008 22:29:15 +0200 Subject: [PATCH 466/781] t7001-mv: skip symlink tests Signed-off-by: Johannes Sixt --- t/t7001-mv.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 910a28c7e2..da5d22bd44 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -173,6 +173,7 @@ test_expect_success 'git mv should not change sha1 of moved cache entry' ' rm -f dirty dirty2 +test "$no_symlinks" || test_expect_success 'git mv should overwrite symlink to a file' ' rm -fr .git && @@ -192,6 +193,7 @@ test_expect_success 'git mv should overwrite symlink to a file' ' rm -f moved symlink +test "$no_symlinks" || test_expect_success 'git mv should overwrite file with a symlink' ' rm -fr .git && From 7c2ca986515e2009ab29080e57ae8b38c921ba4d Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:11:28 +0200 Subject: [PATCH 467/781] gitk: Fix wrong merge This fixes the wrong conflict resolution of merge 5673e9999d7e120f4b68c2c5a61c5ec48ec38cad --- gitk-git/gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index c6b06df56b..9636d15115 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9993,4 +9993,4 @@ if {[info exists permviews]} { } } focus -force . -getcommits +getcommits {} From a55f5a7b8c73cf4f70110ececcf56e5ebe84702c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 18 Aug 2008 08:59:08 +0200 Subject: [PATCH 468/781] MinGW: t3700: skip file-globbing test The test adds a file that has backslashes in the basename. This is not possible on Windows. Signed-off-by: Johannes Sixt --- t/t3700-add.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 22519dd101..93b9ac08ab 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -185,6 +185,7 @@ test_expect_success 'git add --refresh' ' if case $(uname -s) in *MINGW*) :;; *) false;; esac then say "chmod 0 does not make files unreadable - skipping tests" + say "cannot have backslashes in file names - skipping test" else test_expect_success 'git add should fail atomically upon an unreadable file' ' @@ -230,8 +231,6 @@ test_expect_success 'git add (add.ignore-errors = false)' ' ! ( git ls-files foo1 | grep foo1 ) ' -fi # skip chmod 0 tests - test_expect_success 'git add '\''fo\[ou\]bar'\'' ignores foobar' ' git reset --hard && touch fo\[ou\]bar foobar && @@ -240,4 +239,6 @@ test_expect_success 'git add '\''fo\[ou\]bar'\'' ignores foobar' ' ! ( git ls-files foobar | grep foobar ) ' +fi # skip chmod 0 and bslash-in-filename tests + test_done From 43e10bb31a816d8fd435536650cf902ecdc70939 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 28 Aug 2008 12:53:51 +0200 Subject: [PATCH 469/781] Skip a test related to symbolic links. --- t/t0055-beyond-symlinks.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh index b29c37a5a4..fabfaf3578 100755 --- a/t/t0055-beyond-symlinks.sh +++ b/t/t0055-beyond-symlinks.sh @@ -4,6 +4,11 @@ test_description='update-index and add refuse to add beyond symlinks' . ./test-lib.sh +if test "$no_symlinks"; then + say "symbolic links not supported - skipping tests" + test_done +fi + test_expect_success setup ' >a && mkdir b && From fa7fbeb525b11c21a5caa2ee4d8a027405f2be6f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:39:25 +0200 Subject: [PATCH 470/781] Windows: Add workaround for MSYS' path conversion MSYS' automatic path conversion causes problems when passing paths as defines ('-D' arguments to the compiler). MSYS tries to be smart and converts absolute paths to native Windows paths, e.g. if MSYS sees "/bin" it converts it to "c:/msysgit/bin". But we want completely unmodified paths; e.g. if we set bindir in the Makefile to "/bin", the define BINDIR shall expand to "/bin". Conversion to absolute Windows path will takes place later, during runtime. This commit adds a workaround by replacing "/" with its octal representation "\057", effectively hiding the path from MSYS' path conversion mechanism. MSYS does no longer see the absolute path and therefore leaves it alone. --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8d81095765..f716fda416 100644 --- a/Makefile +++ b/Makefile @@ -1049,6 +1049,12 @@ template_dir_SQ = $(subst ','\'',$(template_dir)) htmldir_SQ = $(subst ','\'',$(htmldir)) prefix_SQ = $(subst ','\'',$(prefix)) +ETC_GITCONFIG_SQ_C = $(subst /,\057,$(ETC_GITCONFIG_SQ)) +bindir_SQ_C = $(subst /,\057,$(bindir_SQ)) +gitexecdir_SQ_C = $(subst /,\057,$(gitexecdir_SQ)) +htmldir_SQ_C = $(subst /,\057,$(htmldir_SQ)) +template_dir_SQ_C = $(subst /,\057,$(template_dir_SQ)) + SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) @@ -1100,7 +1106,7 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS) help.o: help.c common-cmds.h GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ - '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ + '-DGIT_HTML_PATH="$(htmldir_SQ_C)"' \ '-DGIT_MAN_PATH="$(mandir_SQ)"' \ '-DGIT_INFO_PATH="$(infodir_SQ)"' $< @@ -1207,12 +1213,12 @@ git.o git.spec \ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ_C)"' -DBINDIR='"$(bindir_SQ_C)"' $< builtin-init-db.o: builtin-init-db.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ_C)"' $< config.o: config.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ_C)"' $< http.o: http.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $< From 7b6c6496374073d4519a035b5c2053395a60e014 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 10 Aug 2008 17:52:36 +0200 Subject: [PATCH 471/781] system_path(): Add prefix computation at runtime if RUNTIME_PREFIX set This commit modifies system_path() to compute the prefix at runtime if configured to do so. If RUNTIME_PREFIX is defined, system_path() tries to strip known directories that executables can be located in from the path of the executable. If the path is successfully stripped it is used as the prefix. For example, if the executable is "/msysgit/bin/git" and BINDIR is "/bin", then the prefix is computed as "/msysgit". We report an error if the runtime prefix computation fails, which can happen if the executable is not installed at a known location. The user should know that the global configuration is not picked up, because this can cause unexpected behavior. If we explicitly want to ignore system wide paths, we can set the environment variable GIT_CONFIG_NOSYSTEM, as our tests do. The implementation requires that argv0_path is set up properly, which is currently the case only on Windows. argv0_path must point to the absolute path of the directory of the executable, which is verified by two calls to assert(). On Windows, the wrapper for main() (see compat/mingw.h) guarantees that this is the case. On Unix, further work is required before RUNTIME_PREFIX can be enabled. --- Makefile | 3 +++ exec_cmd.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f716fda416..b229bff5fb 100644 --- a/Makefile +++ b/Makefile @@ -989,6 +989,9 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif ifdef THREADED_DELTA_SEARCH BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH diff --git a/exec_cmd.c b/exec_cmd.c index ce6741eb68..9fa89b8502 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,11 +9,48 @@ static const char *argv0_path; const char *system_path(const char *path) { - if (!is_absolute_path(path) && argv0_path) { - struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", argv0_path, path); - path = strbuf_detach(&d, NULL); +#ifdef RUNTIME_PREFIX + static const char *prefix; + + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix) { + const char *strip[] = { + GIT_EXEC_PATH, + BINDIR, + 0 + }; + const char **s; + + for (s = strip; *s; s++) { + const char *sargv = argv0_path + strlen(argv0_path); + const char *ss = *s + strlen(*s); + while (argv0_path < sargv && *s < ss + && (*sargv == *ss || + (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { + sargv--; + ss--; + } + if (*s == ss) { + struct strbuf d = STRBUF_INIT; + strbuf_add(&d, argv0_path, sargv - argv0_path); + prefix = strbuf_detach(&d, NULL); + break; + } + } } + + if (!prefix) { + fprintf(stderr, "RUNTIME_PREFIX requested for path '%s', " + "but prefix computation failed.\n", path); + return path; + } + + struct strbuf d = STRBUF_INIT; + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); +#endif return path; } From f2fdec9debe6803204ce9dd734058188110e3cf9 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 472/781] Refactor git_set_argv0_path() to git_extract_argv0_path() This commit moves the code that computes the dirname of argv[0] from git.c's main() to git_set_argv0_path() and renames the function to git_extract_argv0_path(). This makes the code in git.c's main less cluttered, and we can use the direname computation from other main() functions too. [spr: split Steve's original commit and wrote new commit message. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- exec_cmd.c | 15 +++++++++++++-- exec_cmd.h | 2 +- git.c | 20 +++++--------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 9fa89b8502..46ebf7ec82 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -54,9 +54,20 @@ const char *system_path(const char *path) return path; } -void git_set_argv0_path(const char *path) +const char *git_extract_argv0_path(const char *argv0) { - argv0_path = path; + const char *slash = argv0 + strlen(argv0); + + do + --slash; + while (slash >= argv0 && !is_dir_sep(*slash)); + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; } void git_set_argv_exec_path(const char *exec_path) diff --git a/exec_cmd.h b/exec_cmd.h index 594f961387..392e9032c3 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,7 +2,7 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); -extern void git_set_argv0_path(const char *path); +extern const char* git_extract_argv0_path(const char *path); extern const char* git_exec_path(void); extern void setup_path(void); extern const char **prepare_git_cmd(const char **argv); diff --git a/git.c b/git.c index fdb0f71019..cfcedc20dc 100644 --- a/git.c +++ b/git.c @@ -416,23 +416,13 @@ static void execv_dashed_external(const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; - char *slash = (char *)cmd + strlen(cmd); + const char *cmd; int done_alias = 0; - /* - * Take the basename of argv[0] as the command - * name, and the dirname as the default exec_path - * if we don't have anything better. - */ - do - --slash; - while (cmd <= slash && !is_dir_sep(*slash)); - if (cmd <= slash) { - *slash++ = 0; - git_set_argv0_path(cmd); - cmd = slash; - } + if (argv[0] && *argv[0]) + cmd = git_extract_argv0_path(argv[0]); + else + cmd = "git-help"; /* * "git-xxxx" is the same as "git xxxx", but we obviously: From 2a7e0eeb480c083fc66065a9505fbbfecae2cf4d Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 473/781] Glean libexec path from argv[0] for git-upload-pack and git-receive-pack. If the user specified the full path to git-upload-pack as the -u option to "git clone" when cloning a remote repository, and git was not on the default PATH on the remote machine, git-upload-pack was failing to exec git-pack-objects. By making the argv[0] path (if any) available to setup_path(), this will allow finding the "git" executable in the same directory as "git-upload-pack". The default built in to exec_cmd.c is to look for "git" in the ".../libexec/git-core" directory, but it is not installed there (any longer). Much the same applies to invoking git-receive-pack from a non-PATH location using the "--exec" argument to "git push". [ spr: split Steve's original commit into two commits. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- receive-pack.c | 3 +++ upload-pack.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/receive-pack.c b/receive-pack.c index d44c19e6b5..3699b166c7 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -467,6 +467,9 @@ int main(int argc, char **argv) int i; char *dir = NULL; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + argv++; for (i = 1; i < argc; i++) { char *arg = *argv++; diff --git a/upload-pack.c b/upload-pack.c index e5adbc011e..c469a60d79 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -616,6 +616,9 @@ int main(int argc, char **argv) int i; int strict = 0; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; From 9599d567403f6a0bf185f8a3c4e14a77b69004a5 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 08:58:21 +0200 Subject: [PATCH 474/781] Add calls to git_extract_argv0_path() in programs that call git_config_* Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls in the programs that use git_config. --- daemon.c | 3 +++ fast-import.c | 4 ++++ hash-object.c | 4 ++++ index-pack.c | 4 ++++ unpack-file.c | 4 ++++ var.c | 4 ++++ 6 files changed, 23 insertions(+) diff --git a/daemon.c b/daemon.c index 8dcde73200..172854e74c 100644 --- a/daemon.c +++ b/daemon.c @@ -1055,6 +1055,9 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + /* Without this we cannot rely on waitpid() to tell * what happened to our children. */ diff --git a/fast-import.c b/fast-import.c index d85b3a561f..239309f96d 100644 --- a/fast-import.c +++ b/fast-import.c @@ -150,6 +150,7 @@ Format of STDIN stream: #include "refs.h" #include "csum-file.h" #include "quote.h" +#include "exec_cmd.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1<"); if (get_sha1(argv[1], sha1)) diff --git a/var.c b/var.c index f1eb314e89..33457dc6ab 100644 --- a/var.c +++ b/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "cache.h" +#include "exec_cmd.h" static const char var_usage[] = "git var [-l | ]"; @@ -56,6 +57,9 @@ int main(int argc, char **argv) usage(var_usage); } + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory_gently(&nongit); val = NULL; From 8327b82bf72faaa5bcf0cee176312f1f89bae1c3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 11:30:33 +0200 Subject: [PATCH 475/781] Modify setup_path() to only add git_exec_path() to PATH We should search git programs only in the highest-priority location. The old code added the directories "argv_exec_path", "getenv(EXEC_PATH_ENVIRONMENT)", and "system_path(GIT_EXEC_PATH)" to PATH. The same order is implemented in git_exec_path(), which returns the highest priority location to search for executables. If the user explicitly overrides the default location (by --exec-path or GIT_EXEC_PATH) we can expect that all the required programs are there. It does not make sense that only some of the required programs are located at the highest priority location and other programs are picked up from a lower priority exec-path. If exec-path is overridden a complete set of commands should be provided, otherwise several different versions might easily get mixed, which is likely to spread confusion. Accessing the location with highest priority only is also required for testing of executables built with RUNTIME_PREFIX. Calling system_path(GIT_EXEC_PATH) is avoided if a higher-priority location is provided, which is the case for the tests. The call to system_path() must be avoided, if RUNTIME_PREFIX is set, because the call would fail if the executable is not installed at its final destination. But we test before installing. --- exec_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 46ebf7ec82..2a86670baa 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -111,9 +111,7 @@ void setup_path(void) strbuf_init(&new_path, 0); - add_path(&new_path, argv_exec_path); - add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, system_path(GIT_EXEC_PATH)); + add_path(&new_path, git_exec_path()); add_path(&new_path, argv0_path); if (old_path) From 1a78826c218ecf8bbda95802e8e0fc912a1d499b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:43:58 +0200 Subject: [PATCH 476/781] Windows: Revert to default paths and convert them by RUNTIME_PREFIX The RUNTIME_PREFIX mechanism allows us to use the default (absolute) paths on Windows too. Defining RUNTIME_PREFIX explicitly requests for translation of paths during runtime, depending on the path to the executable. --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b229bff5fb..b7c4e02d6c 100644 --- a/Makefile +++ b/Makefile @@ -755,6 +755,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 @@ -762,9 +763,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = ../libexec/git-core - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From 8ed472bcbb8a5eb47354050606129f13487c6e53 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 08:58:21 +0200 Subject: [PATCH 477/781] Add call to git_extract_argv0_path() to various programs Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls. --- http-push.c | 3 +++ imap-send.c | 4 ++++ merge-index.c | 4 ++++ merge-tree.c | 4 ++++ mktag.c | 4 ++++ mktree.c | 4 ++++ pack-redundant.c | 4 ++++ patch-id.c | 4 ++++ update-server-info.c | 4 ++++ 9 files changed, 35 insertions(+) diff --git a/http-push.c b/http-push.c index 6805288857..47fa1cb6b3 100644 --- a/http-push.c +++ b/http-push.c @@ -2170,6 +2170,9 @@ int main(int argc, char **argv) struct ref *ref; char *rewritten_url = NULL; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); remote = xcalloc(sizeof(*remote), 1); diff --git a/imap-send.c b/imap-send.c index 1ec1310921..6714f9114c 100644 --- a/imap-send.c +++ b/imap-send.c @@ -23,6 +23,7 @@ */ #include "cache.h" +#include "exec_cmd.h" typedef struct store_conf { char *name; @@ -1293,6 +1294,9 @@ main(int argc, char **argv) int r; int total, n = 0; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + /* init the random number generator */ arc4_init(); diff --git a/merge-index.c b/merge-index.c index 7827e87a92..5d89eadba0 100644 --- a/merge-index.c +++ b/merge-index.c @@ -1,5 +1,6 @@ #include "cache.h" #include "run-command.h" +#include "exec_cmd.h" static const char *pgm; static const char *arguments[9]; @@ -93,6 +94,9 @@ int main(int argc, char **argv) if (argc < 3) usage("git-merge-index [-o] [-q] (-a | [--] *)"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); read_cache(); diff --git a/merge-tree.c b/merge-tree.c index 02fc10f7e6..51061ae604 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -2,6 +2,7 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "blob.h" +#include "exec_cmd.h" static const char merge_tree_usage[] = "git-merge-tree "; static int resolve_directories = 1; @@ -345,6 +346,9 @@ int main(int argc, char **argv) if (argc != 4) usage(merge_tree_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); buf1 = get_tree_descriptor(t+0, argv[1]); diff --git a/mktag.c b/mktag.c index 0b34341f71..44490a6729 100644 --- a/mktag.c +++ b/mktag.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tag.h" +#include "exec_cmd.h" /* * A signature file has a very simple fixed format: four lines @@ -159,6 +160,9 @@ int main(int argc, char **argv) if (argc != 1) usage("git-mktag < signaturefile"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); strbuf_init(&buf, 0); diff --git a/mktree.c b/mktree.c index e0da110a98..0e83fc935b 100644 --- a/mktree.c +++ b/mktree.c @@ -6,6 +6,7 @@ #include "cache.h" #include "quote.h" #include "tree.h" +#include "exec_cmd.h" static struct treeent { unsigned mode; @@ -70,6 +71,9 @@ int main(int ac, char **av) unsigned char sha1[20]; int line_termination = '\n'; + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); while ((1 < ac) && av[1][0] == '-') { diff --git a/pack-redundant.c b/pack-redundant.c index 25b81a445c..8ff450b319 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "exec_cmd.h" #define BLKSIZE 512 @@ -601,6 +602,9 @@ int main(int argc, char **argv) unsigned char *sha1; char buf[42]; /* 40 byte sha1 + \n + \0 */ + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); for (i = 1; i < argc; i++) { diff --git a/patch-id.c b/patch-id.c index 9349bc5580..775e2954bd 100644 --- a/patch-id.c +++ b/patch-id.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static void flush_current_id(int patchlen, unsigned char *id, SHA_CTX *c) { @@ -79,6 +80,9 @@ int main(int argc, char **argv) if (argc != 1) usage(patch_id_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + generate_id_list(); return 0; } diff --git a/update-server-info.c b/update-server-info.c index 7e8209ea4b..286a4dd517 100644 --- a/update-server-info.c +++ b/update-server-info.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static const char update_server_info_usage[] = "git update-server-info [--force]"; @@ -19,6 +20,9 @@ int main(int ac, char **av) if (i != ac) usage(update_server_info_usage); + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); return !!update_server_info(force); From c45c40385e07ccc067a67d408131682767015b80 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Sep 2008 08:46:30 +0200 Subject: [PATCH 478/781] compat/mingw: Support a timeout in the poll emulation if no fds are given Our poll() emulation did not support the timeout argument. With this patch we support it as long as poll() does not need to wait on file descriptors as well because in this case the call just amounts to Sleep(). This is needed if the user sets help.autocorrect is set to a positive value. Signed-off-by: Johannes Sixt --- compat/mingw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index ccfa2a0a3d..7eed60db1b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -263,8 +263,13 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) { int i, pending; - if (timeout != -1) + if (timeout >= 0) { + if (nfds == 0) { + Sleep(timeout); + return 0; + } return errno = EINVAL, error("poll timeout not supported"); + } /* When there is only one fd to wait for, then we pretend that * input is available and let the actual wait happen when the From 226c37e6fc8ae0aa2232ae93eeb05c92e85c121a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 7 Nov 2008 15:02:10 +0100 Subject: [PATCH 479/781] Revert "t3903: Mark tests as broken on MinGW" This reverts commit fe3238dc4c870cb865bd2862f317afeb35018267, which worked around the bug that stash@{1} was not transfered correctly down the command invocation chain. But this bug was fixed later, so this workaround is not necessary anymore. --- t/t3903-stash.sh | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 7cb4e177b6..7484cbede6 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -88,11 +88,7 @@ test_expect_success 'drop top stash' ' test 1 = $(git show HEAD:file) ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'drop middle stash' ' +test_expect_success 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && @@ -112,11 +108,7 @@ $test_expect 'drop middle stash' ' test 1 = $(git show HEAD:file) ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'stash pop' ' +test_expect_success 'stash pop' ' git reset --hard && git stash pop && test 3 = $(cat file) && From e95a73efe91c53de473c195a0a12e1b66a726ff7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 7 Nov 2008 13:52:12 +0100 Subject: [PATCH 480/781] t3903-stash: Work around a racily-clean index that is not detected. We still have the problem that sometimes the time returned by stat() is off by a second into the past. As a consequence, git cannot detect when a file was modified such that only the content changed but no other aspect of the meta-data that stat() retrieves. So we artificially delay the modification so that at least the timestamp is different from the one recorded in the index. --- t/t3903-stash.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 7484cbede6..fa5de5b380 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -92,6 +92,7 @@ test_expect_success 'drop middle stash' ' git reset --hard && echo 8 > file && git stash && + sleep 1 && echo 9 > file && git stash && git stash drop stash@{1} && From 639583be9877f767dc63554666be3dfdadde2b51 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 17 Nov 2008 09:21:30 +0100 Subject: [PATCH 481/781] t5303: Do not use /dev/zero We do not have /dev/zero on Windows. As a work-around we use a file with a single NUL byte (because that's all that the tests need). Signed-off-by: Johannes Sixt --- t/t5303-pack-corruption-resilience.sh | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index b919db02ac..5132d41309 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -41,12 +41,6 @@ create_new_pack() { git verify-pack -v ${pack}.pack } -zeros () { - while :; do - echo -n xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - done | tr x '\0' -} - do_repack() { pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | git pack-objects $@ .git/objects/pack/pack` && @@ -61,6 +55,8 @@ do_corrupt_object() { test_must_fail git verify-pack ${pack}.pack } +printf '\0' > zero + test_expect_success \ 'initial setup validation' \ 'create_test_files && @@ -72,7 +68,7 @@ test_expect_success \ test_expect_success \ 'create corruption in header of first object' \ - 'do_corrupt_object $blob_1 0 < /dev/zero && + 'do_corrupt_object $blob_1 0 < zero && test_must_fail git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -131,7 +127,7 @@ test_expect_success \ 'create corruption in header of first delta' \ 'create_new_pack && git prune-packed && - do_corrupt_object $blob_2 0 < /dev/zero && + do_corrupt_object $blob_2 0 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -186,7 +182,7 @@ test_expect_success \ 'corruption in delta base reference of first delta (OBJ_REF_DELTA)' \ 'create_new_pack && git prune-packed && - do_corrupt_object $blob_2 2 < /dev/zero && + do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -213,7 +209,7 @@ test_expect_success \ 'corruption #0 in delta base reference of first delta (OBJ_OFS_DELTA)' \ 'create_new_pack --delta-base-offset && git prune-packed && - do_corrupt_object $blob_2 2 < /dev/zero && + do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -265,7 +261,7 @@ test_expect_success \ test_expect_success \ '... and a redundant pack allows for full recovery too' \ - 'do_corrupt_object $blob_2 2 < /dev/zero && + 'do_corrupt_object $blob_2 2 < zero && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null && From 8054a9ec602701973ca4010b5d37d6ec1889ec86 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 17 Nov 2008 09:25:19 +0100 Subject: [PATCH 482/781] t5303: Do not overwrite an existing pack This test corrupts a pack file, then repacks the objects. The consequence is that the repacked pack file has the same name as the original file (that has been corrupted). During its operation, git-pack-objects opens the corrupted file and keeps it open at all times. On Windows, this is a problem because a file that is open in any process cannot be delete or replaced, but that is what we do in some of the test cases, and so they fail. The work-around is to write the repacked objects to a file of a different name, and replace the original after git-pack-objects has terminated. Signed-off-by: Johannes Sixt --- t/t5303-pack-corruption-resilience.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 5132d41309..41c83e3477 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -43,8 +43,11 @@ create_new_pack() { do_repack() { pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | - git pack-objects $@ .git/objects/pack/pack` && - pack=".git/objects/pack/pack-${pack}" + git pack-objects $@ .git/objects/pack/packtmp` && + packtmp=".git/objects/pack/packtmp-${pack}" && + pack=".git/objects/pack/pack-${pack}" && + mv "${packtmp}.pack" "${pack}.pack" && + mv "${packtmp}.idx" "${pack}.idx" } do_corrupt_object() { From e12c7f1492cce63377ff393cb5cc60ef5aa80d63 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 19 Nov 2008 16:16:42 +0100 Subject: [PATCH 483/781] compat/mingw.c: Teach mingw_rename() to replace read-only files On POSIX, rename() can replace files that are not writable. On Windows, however, read-only files cannot be replaced without additional efforts: We have to make the destination writable first. Since the situations where the destination is read-only are rare, we do not make the destination writable on every invocation, but only if the first try to rename a file failed with an "access denied" error. Signed-off-by: Johannes Sixt --- compat/mingw.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index b534a8a472..3dbe6a77ff 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -819,6 +819,8 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { + DWORD attrs; + /* * Try native rename() first to get errno right. * It is based on MoveFile(), which cannot overwrite existing files. @@ -830,12 +832,19 @@ int mingw_rename(const char *pold, const char *pnew) if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED) { - DWORD attrs = GetFileAttributes(pnew); - if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { + if (GetLastError() == ERROR_ACCESS_DENIED && + (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { + if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; return -1; } + if ((attrs & FILE_ATTRIBUTE_READONLY) && + SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { + if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + return 0; + /* revert file attributes on failure */ + SetFileAttributes(pnew, attrs); + } } errno = EACCES; return -1; From d4654ac4b47a1fa0cb5537d0819eb86ba5bd3a18 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 10 Dec 2008 08:37:59 +0100 Subject: [PATCH 484/781] Revert "t5303: Do not overwrite an existing pack" This reverts commit 8054a9ec602701973ca4010b5d37d6ec1889ec86. --- t/t5303-pack-corruption-resilience.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 41c83e3477..5132d41309 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -43,11 +43,8 @@ create_new_pack() { do_repack() { pack=`printf "$blob_1\n$blob_2\n$blob_3\n" | - git pack-objects $@ .git/objects/pack/packtmp` && - packtmp=".git/objects/pack/packtmp-${pack}" && - pack=".git/objects/pack/pack-${pack}" && - mv "${packtmp}.pack" "${pack}.pack" && - mv "${packtmp}.idx" "${pack}.idx" + git pack-objects $@ .git/objects/pack/pack` && + pack=".git/objects/pack/pack-${pack}" } do_corrupt_object() { From 2fb7da977b49fbe81eeb074c277010759988a681 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 22 Dec 2008 16:08:58 +0100 Subject: [PATCH 485/781] Skip tests that involve symbolic links. Signed-off-by: Johannes Sixt --- t/t2300-cd-to-toplevel.sh | 6 ++++++ t/t5521-pull-symlink.sh | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/t/t2300-cd-to-toplevel.sh b/t/t2300-cd-to-toplevel.sh index beddb4e9f2..14416b3210 100755 --- a/t/t2300-cd-to-toplevel.sh +++ b/t/t2300-cd-to-toplevel.sh @@ -24,6 +24,10 @@ test_cd_to_toplevel repo 'at physical root' test_cd_to_toplevel repo/sub/dir 'at physical subdir' +if test "$no_symlinks"; then + say "symbolic links not supported - skipping tests" +else + ln -s repo symrepo test_cd_to_toplevel symrepo 'at symbolic root' @@ -34,4 +38,6 @@ cd repo ln -s sub/dir internal-link test_cd_to_toplevel internal-link 'at internal symbolic subdir' +fi # $no_symlinks + test_done diff --git a/t/t5521-pull-symlink.sh b/t/t5521-pull-symlink.sh index 5672b51e2e..88583bfc9f 100755 --- a/t/t5521-pull-symlink.sh +++ b/t/t5521-pull-symlink.sh @@ -4,6 +4,11 @@ test_description='pulling from symlinked subdir' . ./test-lib.sh +if test "$no_symlinks"; then + say "symbolic links not supported - skipping tests" + test_done +fi + # The scenario we are building: # # trash\ directory/ From ee10a9759a22a9a8885761436049ceaefc0b8086 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 10 Aug 2008 17:52:36 +0200 Subject: [PATCH 486/781] Move computation of absolute paths from Makefile to runtime and compute prefix on the fly if RUNTIME_PREFIX set This is the first commit of a series that adds support for relocatable binaries (called RUNTIME_PREFIX). Such binaries can be moved together with the system configuration files to a different directory, as long as the relative paths from the binary to the configuration files stays the same. This functionality is essential on Windows where we deliver git binaries with an installer that allows to freely choose the installation location. The commit series implements RUNTIME_PREFIX only on Windows. The architecture is such that adding support on Unix should not be too hard. This first commits makes all paths relative in the Makefile and teaches system_path() to add the prefix instead. We used to compute absolute paths in the Makefile and passed them to C as defines. We now pass relative paths to C and call system_path() to add the prefix at runtime. If RUNTIME_PREFIX is unset we use the static prefix. This will be the default on Unix. Thus, the behavior is unchanged compared to the old implementation. If RUNTIME_PREFIX is set the prefix is computed from the location of the executable. In this case, system_path() tries to strip known directories that executables can be located in from the path of the executable. If the path is successfully stripped it is used as the prefix. For example, if the executable is "/msysgit/bin/git" and BINDIR is "bin", then the prefix computed is "/msysgit". If the runtime prefix computation fails, we fall back to the static prefix specified in the makefile. This can be the case if the executable is not installed at a known location. Note that our test system sets GIT_CONFIG_NOSYSTEM to tell git to ignore global configuration files during testing. Hence testing does not trigger the fall back. Note that the implementation requires argv0_path to be set to an absolute path, which is currently the case only on Windows. argv0_path must point to the directory of the executable. We use assert() to verify this during debugging. On Windows, the wrapper for main() (see compat/mingw.h) guarantees that this is the case. On Unix, further work is required before RUNTIME_PREFIX can be enabled. --- Makefile | 45 ++++++++++++++++++++++++++--------------- builtin-help.c | 4 ++-- exec_cmd.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index aabf0130b9..da17fe950a 100644 --- a/Makefile +++ b/Makefile @@ -179,28 +179,32 @@ STRIP ?= strip # Among the variables below, these: # gitexecdir # template_dir +# mandir +# infodir # htmldir # ETC_GITCONFIG (but not sysconfdir) -# can be specified as a relative path ../some/where/else (which must begin -# with ../); this is interpreted as relative to $(bindir) and "git" at +# can be specified as a relative path some/where/else; +# this is interpreted as relative to $(prefix) and "git" at # runtime figures out where they are based on the path to the executable. # This can help installing the suite in a relocatable way. prefix = $(HOME) -bindir = $(prefix)/bin -mandir = $(prefix)/share/man -infodir = $(prefix)/share/info -gitexecdir = $(prefix)/libexec/git-core +bindir_relative = bin +bindir = $(prefix)/$(bindir_relative) +mandir = share/man +infodir = share/info +gitexecdir = libexec/git-core sharedir = $(prefix)/share -template_dir = $(sharedir)/git-core/templates -htmldir=$(sharedir)/doc/git-doc +template_dir = share/git-core/templates +htmldir = share/doc/git-doc ifeq ($(prefix),/usr) sysconfdir = /etc +ETC_GITCONFIG = $(sysconfdir)/gitconfig else sysconfdir = $(prefix)/etc +ETC_GITCONFIG = etc/gitconfig endif lib = lib -ETC_GITCONFIG = $(sysconfdir)/gitconfig # DESTDIR= # default configuration for gitweb @@ -1027,6 +1031,9 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif ifdef NO_PTHREADS THREADED_DELTA_SEARCH = @@ -1086,6 +1093,7 @@ ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) +bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) mandir_SQ = $(subst ','\'',$(mandir)) infodir_SQ = $(subst ','\'',$(infodir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) @@ -1251,7 +1259,12 @@ git.o git.spec \ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ + '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \ + '-DBINDIR="$(bindir_relative_SQ)"' \ + '-DPREFIX="$(prefix_SQ)"' \ + $< + builtin-init-db.o: builtin-init-db.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< @@ -1397,17 +1410,17 @@ remove-dashes: ### Installation rules -ifeq ($(firstword $(subst /, ,$(template_dir))),..) -template_instdir = $(bindir)/$(template_dir) -else +ifeq ($(abspath $(template_dir)),$(template_dir)) template_instdir = $(template_dir) +else +template_instdir = $(prefix)/$(template_dir) endif export template_instdir -ifeq ($(firstword $(subst /, ,$(gitexecdir))),..) -gitexec_instdir = $(bindir)/$(gitexecdir) -else +ifeq ($(abspath $(gitexecdir)),$(gitexecdir)) gitexec_instdir = $(gitexecdir) +else +gitexec_instdir = $(prefix)/$(gitexecdir) endif gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir)) export gitexec_instdir diff --git a/builtin-help.c b/builtin-help.c index f076efa921..9b57a74618 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -329,7 +329,7 @@ static void setup_man_path(void) * old_path, the ':' at the end will let 'man' to try * system-wide paths after ours to find the manual page. If * there is old_path, we need ':' as delimiter. */ - strbuf_addstr(&new_path, GIT_MAN_PATH); + strbuf_addstr(&new_path, system_path(GIT_MAN_PATH)); strbuf_addch(&new_path, ':'); if (old_path) strbuf_addstr(&new_path, old_path); @@ -375,7 +375,7 @@ static void show_man_page(const char *git_cmd) static void show_info_page(const char *git_cmd) { const char *page = cmd_to_page(git_cmd); - setenv("INFOPATH", GIT_INFO_PATH, 1); + setenv("INFOPATH", system_path(GIT_INFO_PATH), 1); execlp("info", "info", "gitman", page, NULL); } diff --git a/exec_cmd.c b/exec_cmd.c index cdd35f9195..669b82e35a 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,11 +9,57 @@ static const char *argv0_path; const char *system_path(const char *path) { - if (!is_absolute_path(path) && argv0_path) { - struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", argv0_path, path); - path = strbuf_detach(&d, NULL); + static const char *prefix; + + if (is_absolute_path(path)) { + return path; } + +#ifdef RUNTIME_PREFIX + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix) { + const char *strip[] = { + GIT_EXEC_PATH, + BINDIR, + 0 + }; + const char **s; + + for (s = strip; *s; s++) { + const char *sargv = argv0_path + strlen(argv0_path); + const char *ss = *s + strlen(*s); + while (argv0_path < sargv && *s < ss + && (*sargv == *ss || + (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { + sargv--; + ss--; + } + if (*s == ss) { + struct strbuf d = STRBUF_INIT; + /* We also skip the trailing directory separator. */ + assert(sargv - argv0_path - 1 >= 0); + strbuf_add(&d, argv0_path, sargv - argv0_path - 1); + prefix = strbuf_detach(&d, NULL); + break; + } + } + } + + if (!prefix) { + prefix = PREFIX; + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); + } +#else + prefix = PREFIX; +#endif + + struct strbuf d = STRBUF_INIT; + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); return path; } From 7501e1c7089414ec414dec8b2c95840ba6c95813 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 487/781] Refactor git_set_argv0_path() to git_extract_argv0_path() This commit moves the code that computes the dirname of argv[0] from git.c's main() to git_set_argv0_path() and renames the function to git_extract_argv0_path(). This makes the code in git.c's main less cluttered, and we can use the dirname computation from other main() functions too. [spr: split Steve's original commit and wrote new commit message. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- exec_cmd.c | 15 +++++++++++++-- exec_cmd.h | 2 +- git.c | 20 +++++--------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 669b82e35a..dde5cfd14f 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -63,9 +63,20 @@ const char *system_path(const char *path) return path; } -void git_set_argv0_path(const char *path) +const char *git_extract_argv0_path(const char *argv0) { - argv0_path = path; + const char *slash = argv0 + strlen(argv0); + + do + --slash; + while (slash >= argv0 && !is_dir_sep(*slash)); + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; } void git_set_argv_exec_path(const char *exec_path) diff --git a/exec_cmd.h b/exec_cmd.h index 594f961387..392e9032c3 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,7 +2,7 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); -extern void git_set_argv0_path(const char *path); +extern const char* git_extract_argv0_path(const char *path); extern const char* git_exec_path(void); extern void setup_path(void); extern const char **prepare_git_cmd(const char **argv); diff --git a/git.c b/git.c index 940a498962..6c3595decc 100644 --- a/git.c +++ b/git.c @@ -419,23 +419,13 @@ static void execv_dashed_external(const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; - char *slash = (char *)cmd + strlen(cmd); + const char *cmd; int done_alias = 0; - /* - * Take the basename of argv[0] as the command - * name, and the dirname as the default exec_path - * if we don't have anything better. - */ - do - --slash; - while (cmd <= slash && !is_dir_sep(*slash)); - if (cmd <= slash) { - *slash++ = 0; - git_set_argv0_path(cmd); - cmd = slash; - } + if (argv[0] && *argv[0]) + cmd = git_extract_argv0_path(argv[0]); + else + cmd = "git-help"; /* * "git-xxxx" is the same as "git xxxx", but we obviously: From ea476195ab8c45e123302ec5481274f59d11d38c Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 488/781] Glean libexec path from argv[0] for git-upload-pack and git-receive-pack. If the user specified the full path to git-upload-pack as the -u option to "git clone" when cloning a remote repository, and git was not on the default PATH on the remote machine, git-upload-pack was failing to exec git-pack-objects. By making the argv[0] path (if any) available to setup_path(), this will allow finding the "git" executable in the same directory as "git-upload-pack". The default built in to exec_cmd.c is to look for "git" in the ".../libexec/git-core" directory, but it is not installed there (any longer). Much the same applies to invoking git-receive-pack from a non-PATH location using the "--exec" argument to "git push". [ spr: split Steve's original commit into two commits. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- builtin-receive-pack.c | 3 +++ upload-pack.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index db67c3162c..bbedcfe5e4 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -579,6 +579,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) int i; char *dir = NULL; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + argv++; for (i = 1; i < argc; i++) { const char *arg = *argv++; diff --git a/upload-pack.c b/upload-pack.c index e5adbc011e..c469a60d79 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -616,6 +616,9 @@ int main(int argc, char **argv) int i; int strict = 0; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; From 61cc52a1ccfd426af3523d681dec63a8fa7c2842 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 08:58:21 +0200 Subject: [PATCH 489/781] Add calls to git_extract_argv0_path() in programs that call git_config_* Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls. --- daemon.c | 3 +++ fast-import.c | 4 ++++ hash-object.c | 4 ++++ http-push.c | 3 +++ imap-send.c | 4 ++++ index-pack.c | 4 ++++ merge-index.c | 4 ++++ merge-tree.c | 4 ++++ mktag.c | 4 ++++ mktree.c | 4 ++++ pack-redundant.c | 4 ++++ patch-id.c | 4 ++++ unpack-file.c | 4 ++++ update-server-info.c | 4 ++++ var.c | 4 ++++ 15 files changed, 58 insertions(+) diff --git a/daemon.c b/daemon.c index 1cef3098d2..fed789495d 100644 --- a/daemon.c +++ b/daemon.c @@ -949,6 +949,9 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/fast-import.c b/fast-import.c index a6bce66196..7762205b70 100644 --- a/fast-import.c +++ b/fast-import.c @@ -150,6 +150,7 @@ Format of STDIN stream: #include "refs.h" #include "csum-file.h" #include "quote.h" +#include "exec_cmd.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1< (-a | [--] *)"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); read_cache(); diff --git a/merge-tree.c b/merge-tree.c index 2d1413efbb..165ccfc608 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -2,6 +2,7 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "blob.h" +#include "exec_cmd.h" static const char merge_tree_usage[] = "git-merge-tree "; static int resolve_directories = 1; @@ -344,6 +345,9 @@ int main(int argc, char **argv) if (argc != 4) usage(merge_tree_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); buf1 = get_tree_descriptor(t+0, argv[1]); diff --git a/mktag.c b/mktag.c index ba3d495e07..ff32f8ab04 100644 --- a/mktag.c +++ b/mktag.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tag.h" +#include "exec_cmd.h" /* * A signature file has a very simple fixed format: four lines @@ -159,6 +160,9 @@ int main(int argc, char **argv) if (argc != 1) usage("git-mktag < signaturefile"); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); if (strbuf_read(&buf, 0, 4096) < 0) { diff --git a/mktree.c b/mktree.c index 514fd9b15a..8ac0d576ed 100644 --- a/mktree.c +++ b/mktree.c @@ -6,6 +6,7 @@ #include "cache.h" #include "quote.h" #include "tree.h" +#include "exec_cmd.h" static struct treeent { unsigned mode; @@ -70,6 +71,9 @@ int main(int ac, char **av) unsigned char sha1[20]; int line_termination = '\n'; + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); while ((1 < ac) && av[1][0] == '-') { diff --git a/pack-redundant.c b/pack-redundant.c index 25b81a445c..8ff450b319 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "exec_cmd.h" #define BLKSIZE 512 @@ -601,6 +602,9 @@ int main(int argc, char **argv) unsigned char *sha1; char buf[42]; /* 40 byte sha1 + \n + \0 */ + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory(); for (i = 1; i < argc; i++) { diff --git a/patch-id.c b/patch-id.c index 871f1d20c0..ff460e282a 100644 --- a/patch-id.c +++ b/patch-id.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c) { @@ -79,6 +80,9 @@ int main(int argc, char **argv) if (argc != 1) usage(patch_id_usage); + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + generate_id_list(); return 0; } diff --git a/unpack-file.c b/unpack-file.c index bcdc8bbb3b..f8bfda7d33 100644 --- a/unpack-file.c +++ b/unpack-file.c @@ -1,5 +1,6 @@ #include "cache.h" #include "blob.h" +#include "exec_cmd.h" static char *create_temp_file(unsigned char *sha1) { @@ -25,6 +26,9 @@ int main(int argc, char **argv) { unsigned char sha1[20]; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + if (argc != 2) usage("git-unpack-file "); if (get_sha1(argv[1], sha1)) diff --git a/update-server-info.c b/update-server-info.c index 7e8209ea4b..286a4dd517 100644 --- a/update-server-info.c +++ b/update-server-info.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static const char update_server_info_usage[] = "git update-server-info [--force]"; @@ -19,6 +20,9 @@ int main(int ac, char **av) if (i != ac) usage(update_server_info_usage); + if (av[0] && *av[0]) + git_extract_argv0_path(av[0]); + setup_git_directory(); return !!update_server_info(force); diff --git a/var.c b/var.c index f1eb314e89..33457dc6ab 100644 --- a/var.c +++ b/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "cache.h" +#include "exec_cmd.h" static const char var_usage[] = "git var [-l | ]"; @@ -56,6 +57,9 @@ int main(int argc, char **argv) usage(var_usage); } + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory_gently(&nongit); val = NULL; From 1b14cecc2c4acf2fef0dbd3b95e3b4dfe7246fa9 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 11:30:33 +0200 Subject: [PATCH 490/781] Modify setup_path() to only add git_exec_path() to PATH Searching git programs only in the highest priority location is sufficient. It does not make sense that some of the required programs are located at the highest priority location but other programs are picked up from a lower priority exec-path. If exec-path is overridden a complete set of commands should be provided, otherwise several different versions could get mixed, which is likely to cause confusion. If a user explicitly overrides the default location (by --exec-path or GIT_EXEC_PATH), we now expect that that all the required programs are found there. Instead of adding the directories "argv_exec_path", "getenv(EXEC_PATH_ENVIRONMENT)", and "system_path(GIT_EXEC_PATH)" to PATH, we now rely on git_exec_path(), which implements the same order, but only returns the highest priority location to search for executables. Accessing only the location with highest priority is also required for testing executables built with RUNTIME_PREFIX. The call to system_path() should be avoided if RUNTIME_PREFIX is set and the executable is not installed at its final destination. Because we test before installing, we want to avoid calling system_path() during tests. The modifications brought by this commit avoid calling system_path(GIT_EXEC_PATH) if a higher-priority location is provided, which is the case when running the tests. --- exec_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index dde5cfd14f..0de03c2bed 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -118,9 +118,7 @@ void setup_path(void) const char *old_path = getenv("PATH"); struct strbuf new_path = STRBUF_INIT; - add_path(&new_path, argv_exec_path); - add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, system_path(GIT_EXEC_PATH)); + add_path(&new_path, git_exec_path()); add_path(&new_path, argv0_path); if (old_path) From e8d0d369da5a9bb6e76846251f27e0f384f490ec Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:43:58 +0200 Subject: [PATCH 491/781] Windows: Revert to default paths and convert them by RUNTIME_PREFIX The RUNTIME_PREFIX mechanism allows us to use the default (absolute) paths on Windows too. Defining RUNTIME_PREFIX explicitly requests for translation of paths during runtime, depending on the path to the executable. --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index da17fe950a..2c4a3f0285 100644 --- a/Makefile +++ b/Makefile @@ -789,6 +789,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch @@ -797,9 +798,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = ../libexec/git-core - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From d1374e7cfed6d3aa9b11b756dba54c07a12e8224 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:09 +0100 Subject: [PATCH 492/781] Move computation of absolute paths from Makefile to runtime (in preparation for RUNTIME_PREFIX) This commit prepares the Makefile for relocatable binaries (called RUNTIME_PREFIX). Such binaries will be able to be moved together with the system configuration files to a different directory, requiring to compute the prefix at runtime. In a first step, we make all paths relative in the Makefile and teach system_path() to add the prefix instead. We used to compute absolute paths in the Makefile and passed them to C as defines. We now pass relative paths to C and call system_path() to add the prefix at runtime. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- Makefile | 42 ++++++++++++++++++++++++++---------------- builtin-help.c | 4 ++-- exec_cmd.c | 13 ++++++++----- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 2b873fa99f..1d2060aa3f 100644 --- a/Makefile +++ b/Makefile @@ -179,28 +179,32 @@ STRIP ?= strip # Among the variables below, these: # gitexecdir # template_dir +# mandir +# infodir # htmldir # ETC_GITCONFIG (but not sysconfdir) -# can be specified as a relative path ../some/where/else (which must begin -# with ../); this is interpreted as relative to $(bindir) and "git" at +# can be specified as a relative path some/where/else; +# this is interpreted as relative to $(prefix) and "git" at # runtime figures out where they are based on the path to the executable. # This can help installing the suite in a relocatable way. prefix = $(HOME) -bindir = $(prefix)/bin -mandir = $(prefix)/share/man -infodir = $(prefix)/share/info -gitexecdir = $(prefix)/libexec/git-core +bindir_relative = bin +bindir = $(prefix)/$(bindir_relative) +mandir = share/man +infodir = share/info +gitexecdir = libexec/git-core sharedir = $(prefix)/share -template_dir = $(sharedir)/git-core/templates -htmldir=$(sharedir)/doc/git-doc +template_dir = share/git-core/templates +htmldir = share/doc/git-doc ifeq ($(prefix),/usr) sysconfdir = /etc +ETC_GITCONFIG = $(sysconfdir)/gitconfig else sysconfdir = $(prefix)/etc +ETC_GITCONFIG = etc/gitconfig endif lib = lib -ETC_GITCONFIG = $(sysconfdir)/gitconfig # DESTDIR= # default configuration for gitweb @@ -1086,6 +1090,7 @@ ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) +bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) mandir_SQ = $(subst ','\'',$(mandir)) infodir_SQ = $(subst ','\'',$(infodir)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) @@ -1251,7 +1256,12 @@ git.o git.spec \ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ + '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \ + '-DBINDIR="$(bindir_relative_SQ)"' \ + '-DPREFIX="$(prefix_SQ)"' \ + $< + builtin-init-db.o: builtin-init-db.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< @@ -1407,17 +1417,17 @@ remove-dashes: ### Installation rules -ifeq ($(firstword $(subst /, ,$(template_dir))),..) -template_instdir = $(bindir)/$(template_dir) -else +ifeq ($(abspath $(template_dir)),$(template_dir)) template_instdir = $(template_dir) +else +template_instdir = $(prefix)/$(template_dir) endif export template_instdir -ifeq ($(firstword $(subst /, ,$(gitexecdir))),..) -gitexec_instdir = $(bindir)/$(gitexecdir) -else +ifeq ($(abspath $(gitexecdir)),$(gitexecdir)) gitexec_instdir = $(gitexecdir) +else +gitexec_instdir = $(prefix)/$(gitexecdir) endif gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir)) export gitexec_instdir diff --git a/builtin-help.c b/builtin-help.c index f076efa921..9b57a74618 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -329,7 +329,7 @@ static void setup_man_path(void) * old_path, the ':' at the end will let 'man' to try * system-wide paths after ours to find the manual page. If * there is old_path, we need ':' as delimiter. */ - strbuf_addstr(&new_path, GIT_MAN_PATH); + strbuf_addstr(&new_path, system_path(GIT_MAN_PATH)); strbuf_addch(&new_path, ':'); if (old_path) strbuf_addstr(&new_path, old_path); @@ -375,7 +375,7 @@ static void show_man_page(const char *git_cmd) static void show_info_page(const char *git_cmd) { const char *page = cmd_to_page(git_cmd); - setenv("INFOPATH", GIT_INFO_PATH, 1); + setenv("INFOPATH", system_path(GIT_INFO_PATH), 1); execlp("info", "info", "gitman", page, NULL); } diff --git a/exec_cmd.c b/exec_cmd.c index cdd35f9195..114d6389e4 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,11 +9,14 @@ static const char *argv0_path; const char *system_path(const char *path) { - if (!is_absolute_path(path) && argv0_path) { - struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", argv0_path, path); - path = strbuf_detach(&d, NULL); - } + static const char *prefix = PREFIX; + struct strbuf d = STRBUF_INIT; + + if (is_absolute_path(path)) + return path; + + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); return path; } From ae990d02111c43771cb1c5595a97e670850860e8 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Sun, 18 Jan 2009 13:00:10 +0100 Subject: [PATCH 493/781] Refactor git_set_argv0_path() to git_extract_argv0_path() This commit moves the code that computes the dirname of argv[0] from git.c's main() to git_set_argv0_path() and renames the function to git_extract_argv0_path(). This makes the code in git.c's main less cluttered, and we can use the dirname computation from other main() functions too. [ spr: - split Steve's original commit and wrote new commit message. - Integrated Johannes Schindelin's cca1704897e7fdb182f68d4c48a437c5d7bc5203 while rebasing onto master. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- exec_cmd.c | 14 ++++++++++++-- exec_cmd.h | 4 ++-- git.c | 19 +++++-------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 114d6389e4..e508f1e66d 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -20,9 +20,19 @@ const char *system_path(const char *path) return path; } -void git_set_argv0_path(const char *path) +const char *git_extract_argv0_path(const char *argv0) { - argv0_path = path; + const char *slash = argv0 + strlen(argv0); + + while (argv0 <= slash && !is_dir_sep(*slash)) + slash--; + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; } void git_set_argv_exec_path(const char *exec_path) diff --git a/exec_cmd.h b/exec_cmd.h index 594f961387..e2b546b615 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,8 +2,8 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); -extern void git_set_argv0_path(const char *path); -extern const char* git_exec_path(void); +extern const char *git_extract_argv0_path(const char *path); +extern const char *git_exec_path(void); extern void setup_path(void); extern const char **prepare_git_cmd(const char **argv); extern int execv_git_cmd(const char **argv); /* NULL terminated */ diff --git a/git.c b/git.c index ecc8fad09a..bf21e21cef 100644 --- a/git.c +++ b/git.c @@ -442,21 +442,12 @@ static int run_argv(int *argcp, const char ***argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; - char *slash = (char *)cmd + strlen(cmd); + const char *cmd; - /* - * Take the basename of argv[0] as the command - * name, and the dirname as the default exec_path - * if we don't have anything better. - */ - while (cmd <= slash && !is_dir_sep(*slash)) - slash--; - if (cmd <= slash) { - *slash++ = 0; - git_set_argv0_path(cmd); - cmd = slash; - } + if (argv[0] && *argv[0]) + cmd = git_extract_argv0_path(argv[0]); + else + cmd = "git-help"; /* * "git-xxxx" is the same as "git xxxx", but we obviously: From ba5c90c3e8956a0f4d6f2fcb63d5d1864c127b4c Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:11 +0100 Subject: [PATCH 494/781] git_extract_argv0_path(): Move check for valid argv0 from caller to callee This simplifies the calling code. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- exec_cmd.c | 6 +++++- git.c | 5 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index e508f1e66d..f8f416b646 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -22,7 +22,11 @@ const char *system_path(const char *path) const char *git_extract_argv0_path(const char *argv0) { - const char *slash = argv0 + strlen(argv0); + const char *slash; + + if (!argv0 || !*argv0) + return NULL; + slash = argv0 + strlen(argv0); while (argv0 <= slash && !is_dir_sep(*slash)) slash--; diff --git a/git.c b/git.c index bf21e21cef..320cb43564 100644 --- a/git.c +++ b/git.c @@ -444,9 +444,8 @@ int main(int argc, const char **argv) { const char *cmd; - if (argv[0] && *argv[0]) - cmd = git_extract_argv0_path(argv[0]); - else + cmd = git_extract_argv0_path(argv[0]); + if (!cmd) cmd = "git-help"; /* From bbcd2c22f2ca74b5091b81d59b76da5b17429580 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:12 +0100 Subject: [PATCH 495/781] Add calls to git_extract_argv0_path() in programs that call git_config_* Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- daemon.c | 2 ++ fast-import.c | 3 +++ hash-object.c | 3 +++ http-push.c | 2 ++ imap-send.c | 3 +++ index-pack.c | 3 +++ merge-index.c | 3 +++ merge-tree.c | 3 +++ mktag.c | 3 +++ mktree.c | 3 +++ pack-redundant.c | 3 +++ patch-id.c | 3 +++ unpack-file.c | 3 +++ update-server-info.c | 3 +++ upload-pack.c | 2 ++ var.c | 3 +++ 16 files changed, 45 insertions(+) diff --git a/daemon.c b/daemon.c index 540700ee84..d93cf960f9 100644 --- a/daemon.c +++ b/daemon.c @@ -937,6 +937,8 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/fast-import.c b/fast-import.c index f0e08aca70..1935206be0 100644 --- a/fast-import.c +++ b/fast-import.c @@ -150,6 +150,7 @@ Format of STDIN stream: #include "refs.h" #include "csum-file.h" #include "quote.h" +#include "exec_cmd.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1< (-a | [--] *)"); + git_extract_argv0_path(argv[0]); + setup_git_directory(); read_cache(); diff --git a/merge-tree.c b/merge-tree.c index 2d1413efbb..f18201acdb 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -2,6 +2,7 @@ #include "tree-walk.h" #include "xdiff-interface.h" #include "blob.h" +#include "exec_cmd.h" static const char merge_tree_usage[] = "git-merge-tree "; static int resolve_directories = 1; @@ -344,6 +345,8 @@ int main(int argc, char **argv) if (argc != 4) usage(merge_tree_usage); + git_extract_argv0_path(argv[0]); + setup_git_directory(); buf1 = get_tree_descriptor(t+0, argv[1]); diff --git a/mktag.c b/mktag.c index ba3d495e07..6d5083eaf0 100644 --- a/mktag.c +++ b/mktag.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tag.h" +#include "exec_cmd.h" /* * A signature file has a very simple fixed format: four lines @@ -159,6 +160,8 @@ int main(int argc, char **argv) if (argc != 1) usage("git-mktag < signaturefile"); + git_extract_argv0_path(argv[0]); + setup_git_directory(); if (strbuf_read(&buf, 0, 4096) < 0) { diff --git a/mktree.c b/mktree.c index 514fd9b15a..6283bc3d43 100644 --- a/mktree.c +++ b/mktree.c @@ -6,6 +6,7 @@ #include "cache.h" #include "quote.h" #include "tree.h" +#include "exec_cmd.h" static struct treeent { unsigned mode; @@ -70,6 +71,8 @@ int main(int ac, char **av) unsigned char sha1[20]; int line_termination = '\n'; + git_extract_argv0_path(av[0]); + setup_git_directory(); while ((1 < ac) && av[1][0] == '-') { diff --git a/pack-redundant.c b/pack-redundant.c index e93eb966e2..48a12bc135 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -7,6 +7,7 @@ */ #include "cache.h" +#include "exec_cmd.h" #define BLKSIZE 512 @@ -601,6 +602,8 @@ int main(int argc, char **argv) unsigned char *sha1; char buf[42]; /* 40 byte sha1 + \n + \0 */ + git_extract_argv0_path(argv[0]); + setup_git_directory(); for (i = 1; i < argc; i++) { diff --git a/patch-id.c b/patch-id.c index 871f1d20c0..3660ad461d 100644 --- a/patch-id.c +++ b/patch-id.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c) { @@ -79,6 +80,8 @@ int main(int argc, char **argv) if (argc != 1) usage(patch_id_usage); + git_extract_argv0_path(argv[0]); + generate_id_list(); return 0; } diff --git a/unpack-file.c b/unpack-file.c index bcdc8bbb3b..6dd8ad02fb 100644 --- a/unpack-file.c +++ b/unpack-file.c @@ -1,5 +1,6 @@ #include "cache.h" #include "blob.h" +#include "exec_cmd.h" static char *create_temp_file(unsigned char *sha1) { @@ -25,6 +26,8 @@ int main(int argc, char **argv) { unsigned char sha1[20]; + git_extract_argv0_path(argv[0]); + if (argc != 2) usage("git-unpack-file "); if (get_sha1(argv[1], sha1)) diff --git a/update-server-info.c b/update-server-info.c index 7e8209ea4b..7b38fd867b 100644 --- a/update-server-info.c +++ b/update-server-info.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "exec_cmd.h" static const char update_server_info_usage[] = "git update-server-info [--force]"; @@ -19,6 +20,8 @@ int main(int ac, char **av) if (i != ac) usage(update_server_info_usage); + git_extract_argv0_path(av[0]); + setup_git_directory(); return !!update_server_info(force); diff --git a/upload-pack.c b/upload-pack.c index e5adbc011e..5db6f93955 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -616,6 +616,8 @@ int main(int argc, char **argv) int i; int strict = 0; + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/var.c b/var.c index f1eb314e89..7362ed8735 100644 --- a/var.c +++ b/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "cache.h" +#include "exec_cmd.h" static const char var_usage[] = "git var [-l | ]"; @@ -56,6 +57,8 @@ int main(int argc, char **argv) usage(var_usage); } + git_extract_argv0_path(argv[0]); + setup_git_directory_gently(&nongit); val = NULL; From c9c57cd1e34508e434893ad90d2ed033ebb706ee Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:13 +0100 Subject: [PATCH 496/781] Modify setup_path() to only add git_exec_path() to PATH Searching git programs only in the highest priority location is sufficient. It does not make sense that some of the required programs are located at the highest priority location but other programs are picked up from a lower priority exec-path. If exec-path is overridden a complete set of commands should be provided, otherwise several different versions could get mixed, which is likely to cause confusion. If a user explicitly overrides the default location (by --exec-path or GIT_EXEC_PATH), we now expect that all the required programs are found there. Instead of adding the directories "argv_exec_path", "getenv(EXEC_PATH_ENVIRONMENT)", and "system_path(GIT_EXEC_PATH)" to PATH, we now rely on git_exec_path(), which implements the same order, but only returns the highest priority location to search for executables. Accessing only the location with highest priority is also required for testing executables built with RUNTIME_PREFIX. The call to system_path() should be avoided if RUNTIME_PREFIX is set and the executable is not installed at its final destination. Because we test before installing, we want to avoid calling system_path() during tests. The modifications in this commit avoid calling system_path(GIT_EXEC_PATH) if a higher-priority location is provided, which is the case when running the tests. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- exec_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index f8f416b646..23f4873b2b 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -78,9 +78,7 @@ void setup_path(void) const char *old_path = getenv("PATH"); struct strbuf new_path = STRBUF_INIT; - add_path(&new_path, argv_exec_path); - add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, system_path(GIT_EXEC_PATH)); + add_path(&new_path, git_exec_path()); add_path(&new_path, argv0_path); if (old_path) From 1f661e93301856bac94588d534414dad6b1d5a72 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:14 +0100 Subject: [PATCH 497/781] Compute prefix at runtime if RUNTIME_PREFIX is set This commit adds support for relocatable binaries (called RUNTIME_PREFIX). Such binaries can be moved together with the system configuration files to a different directory, as long as the relative paths from the binary to the configuration files is preserved. This functionality is essential on Windows where we deliver git binaries with an installer that allows to freely choose the installation location. If RUNTIME_PREFIX is unset we use the static prefix. This will be the default on Unix. Thus, the behavior on Unix will remain identical to the old implementation, which used to add the prefix in the Makefile. If RUNTIME_PREFIX is set the prefix is computed from the location of the executable. In this case, system_path() tries to strip known directories that executables can be located in from the path of the executable. If the path is successfully stripped it is used as the prefix. For example, if the executable is "/msysgit/bin/git" and BINDIR is "bin", then the prefix computed is "/msysgit". If the runtime prefix computation fails, we fall back to the static prefix specified in the makefile. This can be the case if the executable is not installed at a known location. Note that our test system sets GIT_CONFIG_NOSYSTEM to tell git to ignore global configuration files during testing. Hence testing does not trigger the fall back. Note that RUNTIME_PREFIX only works on Windows, though adding support on Unix should not be too hard. The implementation requires argv0_path to be set to an absolute path. argv0_path must point to the directory of the executable. We use assert() to verify this in debug builds. On Windows, the wrapper for main() (see compat/mingw.h) guarantees that argv0_path is correctly initialized. On Unix, further work is required before RUNTIME_PREFIX can be enabled. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- Makefile | 3 +++ exec_cmd.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/Makefile b/Makefile index 1d2060aa3f..fbe52c9c6d 100644 --- a/Makefile +++ b/Makefile @@ -1031,6 +1031,9 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif ifdef NO_PTHREADS THREADED_DELTA_SEARCH = diff --git a/exec_cmd.c b/exec_cmd.c index 23f4873b2b..f234066def 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,12 +9,56 @@ static const char *argv0_path; const char *system_path(const char *path) { +#ifdef RUNTIME_PREFIX + static const char *prefix; +#else static const char *prefix = PREFIX; +#endif struct strbuf d = STRBUF_INIT; if (is_absolute_path(path)) return path; +#ifdef RUNTIME_PREFIX + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix) { + const char *strip[] = { + GIT_EXEC_PATH, + BINDIR, + 0 + }; + const char **s; + + for (s = strip; *s; s++) { + const char *sargv = argv0_path + strlen(argv0_path); + const char *ss = *s + strlen(*s); + while (argv0_path < sargv && *s < ss + && (*sargv == *ss || + (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { + sargv--; + ss--; + } + if (*s == ss) { + struct strbuf d = STRBUF_INIT; + /* We also skip the trailing directory separator. */ + assert(sargv - argv0_path - 1 >= 0); + strbuf_add(&d, argv0_path, sargv - argv0_path - 1); + prefix = strbuf_detach(&d, NULL); + break; + } + } + } + + if (!prefix) { + prefix = PREFIX; + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); + } +#endif + strbuf_addf(&d, "%s/%s", prefix, path); path = strbuf_detach(&d, NULL); return path; From db384c91a0f8ce48c24342eab7a8d0c27824cad6 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 18 Jan 2009 13:00:15 +0100 Subject: [PATCH 498/781] Windows: Revert to default paths and convert them by RUNTIME_PREFIX The RUNTIME_PREFIX mechanism allows us to use the default paths on Windows too. Defining RUNTIME_PREFIX explicitly requests for translation of paths relative to the executable at runtime. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fbe52c9c6d..74ecd77f33 100644 --- a/Makefile +++ b/Makefile @@ -789,6 +789,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch @@ -797,9 +798,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = ../libexec/git-core - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From d439f6092dff6a5ef9615458addb45eecaf1fa44 Mon Sep 17 00:00:00 2001 From: Petr Kodl Date: Sat, 24 Jan 2009 15:04:39 +0100 Subject: [PATCH 499/781] hardlink implementation for mingw Signed-off-by: Johannes Schindelin --- compat/mingw.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ compat/mingw.h | 3 +- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index e25cb4fb23..869bd4acbe 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1003,3 +1003,138 @@ void mingw_open_html(const char *unixpath) printf("Launching default browser to display HTML ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } + +static int err_win_to_posix(DWORD winerr) +{ + int error = ENOSYS; + switch(winerr) { + case ERROR_ACCESS_DENIED: error = EACCES; break; + case ERROR_ACCOUNT_DISABLED: error = EACCES; break; + case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break; + case ERROR_ALREADY_ASSIGNED: error = EBUSY; break; + case ERROR_ALREADY_EXISTS: error = EEXIST; break; + case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break; + case ERROR_BAD_COMMAND: error = EIO; break; + case ERROR_BAD_DEVICE: error = ENODEV; break; + case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break; + case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_FORMAT: error = ENOEXEC; break; + case ERROR_BAD_LENGTH: error = EINVAL; break; + case ERROR_BAD_PATHNAME: error = ENOENT; break; + case ERROR_BAD_PIPE: error = EPIPE; break; + case ERROR_BAD_UNIT: error = ENODEV; break; + case ERROR_BAD_USERNAME: error = EINVAL; break; + case ERROR_BROKEN_PIPE: error = EPIPE; break; + case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break; + case ERROR_BUSY: error = EBUSY; break; + case ERROR_BUSY_DRIVE: error = EBUSY; break; + case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break; + case ERROR_CANNOT_MAKE: error = EACCES; break; + case ERROR_CANTOPEN: error = EIO; break; + case ERROR_CANTREAD: error = EIO; break; + case ERROR_CANTWRITE: error = EIO; break; + case ERROR_CRC: error = EIO; break; + case ERROR_CURRENT_DIRECTORY: error = EACCES; break; + case ERROR_DEVICE_IN_USE: error = EBUSY; break; + case ERROR_DEV_NOT_EXIST: error = ENODEV; break; + case ERROR_DIRECTORY: error = EINVAL; break; + case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break; + case ERROR_DISK_CHANGE: error = EIO; break; + case ERROR_DISK_FULL: error = ENOSPC; break; + case ERROR_DRIVE_LOCKED: error = EBUSY; break; + case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break; + case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break; + case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break; + case ERROR_FILE_EXISTS: error = EEXIST; break; + case ERROR_FILE_INVALID: error = ENODEV; break; + case ERROR_FILE_NOT_FOUND: error = ENOENT; break; + case ERROR_GEN_FAILURE: error = EIO; break; + case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break; + case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break; + case ERROR_INVALID_ACCESS: error = EACCES; break; + case ERROR_INVALID_ADDRESS: error = EFAULT; break; + case ERROR_INVALID_BLOCK: error = EFAULT; break; + case ERROR_INVALID_DATA: error = EINVAL; break; + case ERROR_INVALID_DRIVE: error = ENODEV; break; + case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break; + case ERROR_INVALID_FLAGS: error = EINVAL; break; + case ERROR_INVALID_FUNCTION: error = ENOSYS; break; + case ERROR_INVALID_HANDLE: error = EBADF; break; + case ERROR_INVALID_LOGON_HOURS: error = EACCES; break; + case ERROR_INVALID_NAME: error = EINVAL; break; + case ERROR_INVALID_OWNER: error = EINVAL; break; + case ERROR_INVALID_PARAMETER: error = EINVAL; break; + case ERROR_INVALID_PASSWORD: error = EPERM; break; + case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break; + case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break; + case ERROR_INVALID_TARGET_HANDLE: error = EIO; break; + case ERROR_INVALID_WORKSTATION: error = EACCES; break; + case ERROR_IO_DEVICE: error = EIO; break; + case ERROR_IO_INCOMPLETE: error = EINTR; break; + case ERROR_LOCKED: error = EBUSY; break; + case ERROR_LOCK_VIOLATION: error = EACCES; break; + case ERROR_LOGON_FAILURE: error = EACCES; break; + case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break; + case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break; + case ERROR_MORE_DATA: error = EPIPE; break; + case ERROR_NEGATIVE_SEEK: error = ESPIPE; break; + case ERROR_NOACCESS: error = EFAULT; break; + case ERROR_NONE_MAPPED: error = EINVAL; break; + case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break; + case ERROR_NOT_READY: error = EAGAIN; break; + case ERROR_NOT_SAME_DEVICE: error = EXDEV; break; + case ERROR_NO_DATA: error = EPIPE; break; + case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break; + case ERROR_NO_PROC_SLOTS: error = EAGAIN; break; + case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break; + case ERROR_OPEN_FAILED: error = EIO; break; + case ERROR_OPEN_FILES: error = EBUSY; break; + case ERROR_OPERATION_ABORTED: error = EINTR; break; + case ERROR_OUTOFMEMORY: error = ENOMEM; break; + case ERROR_PASSWORD_EXPIRED: error = EACCES; break; + case ERROR_PATH_BUSY: error = EBUSY; break; + case ERROR_PATH_NOT_FOUND: error = ENOENT; break; + case ERROR_PIPE_BUSY: error = EBUSY; break; + case ERROR_PIPE_CONNECTED: error = EPIPE; break; + case ERROR_PIPE_LISTENING: error = EPIPE; break; + case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break; + case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break; + case ERROR_READ_FAULT: error = EIO; break; + case ERROR_SEEK: error = EIO; break; + case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break; + case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break; + case ERROR_SHARING_VIOLATION: error = EACCES; break; + case ERROR_STACK_OVERFLOW: error = ENOMEM; break; + case ERROR_SWAPERROR: error = ENOENT; break; + case ERROR_TOO_MANY_MODULES: error = EMFILE; break; + case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break; + case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break; + case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break; + case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break; + case ERROR_WRITE_FAULT: error = EIO; break; + case ERROR_WRITE_PROTECT: error = EROFS; break; + } + return error; +} + + +int link(const char *oldpath, const char *newpath) +{ + typedef BOOL (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + static T create_hard_link = NULL; + if (!create_hard_link) { + create_hard_link = (T) GetProcAddress( + GetModuleHandle("kernel32.dll"), "CreateHardLinkA"); + if (!create_hard_link) + create_hard_link = (T)-1; + } + if (create_hard_link == (T)-1) { + errno = ENOSYS; + return -1; + } + if (!create_hard_link(newpath, oldpath, NULL)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} diff --git a/compat/mingw.h b/compat/mingw.h index 4f275cb8e6..20c02c7494 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -67,8 +67,6 @@ static inline int readlink(const char *path, char *buf, size_t bufsiz) { errno = ENOSYS; return -1; } static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } -static inline int link(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) @@ -134,6 +132,7 @@ int getpagesize(void); /* defined in MinGW's libgcc.a */ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); +int link(const char *oldpath, const char *newpath); /* * replacements of existing functions From 5a31d04bc8b2387f11f1d0a95d9b36c25685e59e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 28 Jan 2009 09:59:43 +0100 Subject: [PATCH 500/781] Windows: Fix intermittent failures of t7701 The last test case checks whether unpacked objects receive the time stamp of the pack file. Due to different implementations of stat(2) by MSYS and our version in compat/mingw.c, the test fails in about half of the test runs. Note the following facts: - The test uses perl's -M operator to compare the time stamps. Since we depend on MSYS perl, the result of this operator is based on MSYS's implementation of the stat(2) call. - NTFS on Windows records fractional seconds. - The MSYS implementation of stat(2) *rounds* fractional seconds to full seconds instead of truncating them. This becomes obvious by comparing the modification times reported by 'ls --full-time $f' and 'stat $f' for various files $f. - Our implementation of stat(2) in compat/mingw.c *truncates* to full seconds. The consequence of this is that - add_packed_git() picks up a truncated whole second modification time from the pack file time stamp, which is then used for the loose objects, while the pack file retains its time stamp in fractional seconds; - but the test case compares the pack file's rounded modification times to the loose objects' truncated modification times. And half of the time the rounded modification time is not the same as its truncated modification time. The fix is that we replace perl by 'test-chmtime -v +0', which prints the truncated whole-second mtime without modifying it. Signed-off-by: Johannes Sixt --- t/t7701-repack-unpack-unreachable.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 63a8225ae5..5babdf26e6 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -50,12 +50,10 @@ test_expect_success '-A with -d option leaves unreachable objects unpacked' ' compare_mtimes () { - perl -e 'my $reference = shift; - foreach my $file (@ARGV) { - exit(1) unless(-f $file && -M $file == -M $reference); - } - exit(0); - ' -- "$@" + read tref rest && + while read t rest; do + test "$tref" = "$t" || break + done } test_expect_success '-A without -d option leaves unreachable objects packed' ' @@ -87,7 +85,9 @@ test_expect_success 'unpacked objects receive timestamp of pack file' ' tmppack=".git/objects/pack/tmp_pack" && ln "$packfile" "$tmppack" && git repack -A -l -d && - compare_mtimes "$tmppack" "$fsha1path" "$csha1path" "$tsha1path" + test-chmtime -v +0 "$tmppack" "$fsha1path" "$csha1path" "$tsha1path" \ + > mtimes && + compare_mtimes < mtimes ' test_done From db75811cfaec90fa8a114f46c84d408f5e6ca7c9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 5 Feb 2009 17:15:31 +0100 Subject: [PATCH 501/781] MinGW tests: override 'pwd', too With MinGW based Git, we must not use the POSIXified version of paths. So we need to use 'pwd -W' instead of 'pwd' without options. Signed-off-by: Johannes Schindelin --- t/t5505-remote.sh | 3 --- t/test-lib.sh | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index b4dc0d2fbe..1f59960d90 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -107,9 +107,6 @@ test_expect_success 'remove remote' ' ) ' -case $(uname -s) in -*MINGW*) pwd() { builtin pwd -W; } ;; -esac cat > test/expect << EOF * remote origin URL: $(pwd)/one diff --git a/t/test-lib.sh b/t/test-lib.sh index cce3636c1b..7a5f77b765 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -536,5 +536,8 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + pwd() { + builtin pwd -W + } ;; esac From ea81ef5fea2fb40e665171ac30a3bfb3468e87b8 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 7 Feb 2009 00:03:47 +0100 Subject: [PATCH 502/781] builtin-receive-pack: Remove leftovers of old RUNTIME_PREFIX implementation --- builtin-receive-pack.c | 3 --- merge-index.c | 2 -- mktag.c | 2 -- 3 files changed, 7 deletions(-) diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index 8da9c1ff3a..6de186c397 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -607,9 +607,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) int i; char *dir = NULL; - if (argv[0] && *argv[0]) - git_extract_argv0_path(argv[0]); - argv++; for (i = 1; i < argc; i++) { const char *arg = *argv++; diff --git a/merge-index.c b/merge-index.c index 4c51b14eab..aa9cf23a39 100644 --- a/merge-index.c +++ b/merge-index.c @@ -96,8 +96,6 @@ int main(int argc, char **argv) git_extract_argv0_path(argv[0]); - git_extract_argv0_path(argv[0]); - setup_git_directory(); read_cache(); diff --git a/mktag.c b/mktag.c index 21370328e2..99a356e9ee 100644 --- a/mktag.c +++ b/mktag.c @@ -162,8 +162,6 @@ int main(int argc, char **argv) git_extract_argv0_path(argv[0]); - git_extract_argv0_path(argv[0]); - setup_git_directory(); if (strbuf_read(&buf, 0, 4096) < 0) { From 563478c3f83be93ab369368c5a418d7f75941594 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 9 Feb 2009 10:24:51 +0100 Subject: [PATCH 503/781] t2200: Avoid glob pattern that also matches files On Windows, there is an unfortunate interaction between the MSYS bash and git's command line processing: - Since Windows's CMD does not do the wildcard expansion, but passes arguments like path? through to the programs, the programs must do the expansion themselves. This happens in the startup code before main() is entered. - bash, however, passes the argument "path?" to git, assuming that git will see the unquoted word unchanged as a single argument. But actually git expands the unquoted word before main() is entered. Since at the time when the git ls-files is invoked not all names that the test case is interested in exist as files, only a subset was listed, so that the test failed. We now list all interesting paths explicitly. Signed-off-by: Johannes Sixt --- t/t2200-add-update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index b2ddf5ace3..652801ebca 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -150,7 +150,7 @@ test_expect_success 'add -u resolves unmerged paths' ' echo 2 >path3 && echo 2 >path5 && git add -u && - git ls-files -s "path?" >actual && + git ls-files -s path1 path3 path4 path5 path6 >actual && { echo "100644 $three 0 path1" echo "100644 $one 1 path3" From 861050cc2eaa963fcdb3b0860b854aee5f87e727 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 17 Feb 2009 18:54:01 +0100 Subject: [PATCH 504/781] t3400-rebase: Move detached HEAD check earlier 3ec7371f (Add two extra tests for git rebase, 2009-02-09) added a check that rebase works on a detached HEAD. For this check, the last test was picked, whose topic is to rebase a mode change. This rebase operation amounts to a no-op on Windows/MinGW so that HEAD@{1} *is* modechange@{1}, and the intended detached HEAD test fails. This patch moves the check earlier, into the group of tests that check basic rebase properties. Signed-off-by: Johannes Sixt --- t/t3400-rebase.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 8c0c5f5982..be7ae5a004 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -48,6 +48,10 @@ test_expect_success \ 'the rebase operation should not have destroyed author information' \ '! (git log | grep "Author:" | grep "<>")' +test_expect_success 'HEAD was detached during rebase' ' + test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1}) +' + test_expect_success 'rebase after merge master' ' git reset --hard topic && git merge master && @@ -85,10 +89,6 @@ test_expect_success 'rebase a single mode change' ' GIT_TRACE=1 git rebase master ' -test_expect_success 'HEAD was detached during rebase' ' - test $(git rev-parse HEAD@{1}) != $(git rev-parse modechange@{1}) -' - test_expect_success 'Show verbose error when HEAD could not be detached' ' : > B && test_must_fail git rebase topic 2> output.err > output.out && From 89012a7916918de08031e7c415afd79d9e68dce2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2009 16:22:36 +0100 Subject: [PATCH 505/781] Remove last remnant of NOEXECTEMPL Upstream Git learnt the trick from us, but decided to call it 'sample' instead of 'noexec'. Signed-off-by: Johannes Schindelin --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index a9bbf3d8a3..be00623c81 100644 --- a/Makefile +++ b/Makefile @@ -809,7 +809,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - NOEXECTEMPL = .noexec htmldir=doc/git/html/ endif ifneq (,$(findstring arm,$(uname_M))) From eebdca3a654bfb95018514d5b5b8803c1fcd3343 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 19:51:54 +0100 Subject: [PATCH 506/781] Revert unnecessary quoting of SHELL_PATH In bf788d7(Makefile: be nice when running in a path containing spaces), the Makefile was changed so that the SHELL_PATH is quoted, but that is actually not necessary, as we still have POSIX paths at that point, and we use /bin/sh which has no space in it. Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index be00623c81..0b0628a98c 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ all:: # broken, or spawning external process is slower than built-in grep git has). GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE - @"$(SHELL_PATH)" ./GIT-VERSION-GEN + @$(SHELL_PATH) ./GIT-VERSION-GEN -include GIT-VERSION-FILE uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') From e673e45f5893fc969b58c81553832efd8cfd0435 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 19:54:24 +0100 Subject: [PATCH 507/781] MinGW: use POSIXy signature of waitpid() Git's source code expects waitpid() to return a signed int status. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index d6005ad545..6219e18843 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -109,7 +109,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, unsigned *status, unsigned options) +static inline int waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); From 6d3e71d428b1ee007339d679c26a336c8aefeade Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 19:56:41 +0100 Subject: [PATCH 508/781] MinGW: only override PRIuMAX for GCC older than version 4 GCC has no problems with PRIuMAX with recent GCC versions, but these versions do not like I64u any longer. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 6219e18843..8898006278 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -200,7 +200,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') #define PATH_SEP ';' +#if !defined(__GNUC__) || __GNUC__ < 3 #define PRIuMAX "I64u" +#endif void mingw_open_html(const char *path); #define open_html mingw_open_html From 85f2fd02bd2602e10415bf8aa4e085a9658e2d18 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:12:41 +0100 Subject: [PATCH 509/781] Makefile: move the last MinGW specific settings to the appropriate place If we ever hope to use plain upstream git.git in msysGit, we need to play nice with other platforms. So move the MinGW specific settings where they do not affect anybody else. Signed-off-by: Johannes Schindelin --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 0b0628a98c..68c2d846dd 100644 --- a/Makefile +++ b/Makefile @@ -191,7 +191,7 @@ STRIP ?= strip # runtime figures out where they are based on the path to the executable. # This can help installing the suite in a relocatable way. -prefix = +prefix = $(HOME) bindir_relative = bin bindir = $(prefix)/$(bindir_relative) mandir = share/man @@ -235,7 +235,7 @@ AR = ar RM = rm -f TAR = tar FIND = find -INSTALL = /bin/install +INSTALL = install RPMBUILD = rpmbuild TCL_PATH = tclsh TCLTK_PATH = wish @@ -592,7 +592,7 @@ BUILTIN_OBJS += builtin-verify-tag.o BUILTIN_OBJS += builtin-write-tree.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) -EXTLIBS = /mingw/lib/libz.a +EXTLIBS = # # Platform specific tweaks @@ -779,6 +779,9 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) + prefix = + INSTALL = /bin/install + EXTLIBS += /mingw/lib/libz.a NO_MMAP = YesPlease NO_PREAD = YesPlease NO_OPENSSL = YesPlease From 5461f4e7863a655a6f5792edc8dc9768a62948e7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:22:14 +0100 Subject: [PATCH 510/781] Undo MSys specific munging of ssh transport URLs We have our own msys-1.0.dll, which needs no more munging of the ssh transport URLs. Besides, almost everything related to remotes is builtin by now. Signed-off-by: Johannes Schindelin --- git-parse-remote.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) mode change 100644 => 100755 git-parse-remote.sh diff --git a/git-parse-remote.sh b/git-parse-remote.sh old mode 100644 new mode 100755 index 7c0d242eec..695a4094bb --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -51,8 +51,7 @@ get_remote_url () { ;; *) die "internal error: get-remote-url $1" ;; - esac | sed "s|^\(.[^:][^:]*\):\(/[^/]\)|ssh://\1\2|" - # work around MinGW path mangling + esac } get_default_remote () { From 8d785de3c205c870f6ce3e459c27e3f2b849b1a7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:25:13 +0100 Subject: [PATCH 511/781] gitk: remove workaround for missing msgfmt In the meantime, gitk's Makefile has learnt to detect the absence of msgfmt and use the drop-in replacement in Tcl (which was developed for msysGit, but has been adopted both by gitk and git-gui). Signed-off-by: Johannes Schindelin --- gitk-git/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gitk-git/Makefile b/gitk-git/Makefile index 2dda57cbae..e1b6045605 100644 --- a/gitk-git/Makefile +++ b/gitk-git/Makefile @@ -19,10 +19,6 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) ## po-file creation rules XGETTEXT ?= xgettext -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') -ifneq (,$(findstring MINGW,$(uname_S))) - NO_MSGFMT=1 -endif ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else From 7cb52f1ebf546159e5460db087d9343d1b4139ed Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:28:26 +0100 Subject: [PATCH 512/781] No longer force use of /usr/bin/sort In msysGit, the PATH contains the MSys paths before anything else, so we can use "sort" (instead of "/usr/bin/sort"), just like git.git. Signed-off-by: Johannes Schindelin --- check-builtins.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check-builtins.sh b/check-builtins.sh index cd09309838..d6fe6cf174 100755 --- a/check-builtins.sh +++ b/check-builtins.sh @@ -9,7 +9,7 @@ EOF } | make -f - sayIt 2>/dev/null | sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p' | -/usr/bin/sort | +sort | { bad=0 while read builtin From c09458c701353b8e0ad92fe2d0245636e17cb8b8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:29:49 +0100 Subject: [PATCH 513/781] Remove hopelessly obsolete README.MinGW Rather than letting it get even more stale, remove README.MinGW. Signed-off-by: Johannes Schindelin --- README.MinGW | 77 ---------------------------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 README.MinGW diff --git a/README.MinGW b/README.MinGW deleted file mode 100644 index 74eb104c2c..0000000000 --- a/README.MinGW +++ /dev/null @@ -1,77 +0,0 @@ -This is a port of GIT to Windows using MinGW. - -The goal of this port is to have the tools runnable from the Windows -command line, not from MinGW's rxvt+bash environment. - -(Note: This file was written after-the-fact and may contain errors. -If you are trying this, please make notes and update it.) - - -INSTALLATION ------------- - -In order to compile this code you need: - -- MSYS, e.g. MSYS-1.0.11-2004.04.30-1.exe -- MinGW, e.g. MinGW-5.0.2.exe -- mingwruntime, e.g. mingw-runtime-3.9.tar.gz -- compilers and tools: - binutils-2.15.91-20040904-1.tar.gz - gcc-core-3.4.2-20040916-1.tar.gz - gcc-g++-3.4.2-20040916-1.tar.gz - gdb-6.3-2.exe - mingw32-make-3.80.0-3.tar.gz - unzip-5.51-1-bin.zip (this is not from MinGW, iirc) - msysDTK-1.0.1.exe (contains ssh, perl) - bash-3.1-MSYS-1.0.11-snapshot.tar.bz2 -- additional libraries: - zlib-1.2.3-mingwPORT-1.tar - w32api-3.6.tar.gz - tcltk-8.4.1-1.exe (for gitk, git-gui) - libiconv-1.9.2-1-{lib,bin,lib}.zip (for git-am, - from http://gnuwin32.sourceforge.net/packages/libiconv.htm) - -I am using these settings in config.mak to have pointers to the right tools: - -TCL_PATH=tclsh84 -TCLTK_PATH=wish84 -SHELL_PATH=D:/MSYS/1.0/bin/sh -PERL_PATH=D:/MSYS/1.0/bin/perl - - -STATUS ------- - -This code base will not compile on a POSIX system, although any help -to introduce the necessary #ifdefs is welcome. As such the status quo -is in no way intended to be merged upstream. - -This works: - -- All the plumbings. -- Many porcelains, in particular, checkout, add, rm, commit, diff, - branch, merge, rebase, log, show, bisect, grep... -- pull, clone, fetch, push via native git protocal as well as ssh. -- Local pull, clone, fetch, push. -- gitk, if invoked as "wish84 \bin\gitk". Ditto for git-gui. - -This does not work: - -- daemon, svn, *import, cvs* -- and certainly a lot more that I never have found a need to look at. - -Caveats (aka bugs): - -- Internally, the ported tools must do their own command line quoting - when other plumbings are executed. This sort of quoting is currently - implemented *very* simplistic: It just watches out for whitespace - and double quote `"' characters. This may become a problem if you have - exotic characters in your file names. - -- It seems that MSYS's default bash, 2.05b, has a bug that breaks git-am - (and, hence, git-rebase). If you see this error: - - Patch is empty. Was is split wrong? - - you need bash 3.1: Just unpack bash-3.1*.tar.bz2 and copy its bash.exe - over $MSYS/bin/sh.exe. From 3cb35a31b04fb8e5cbfda3affcaa87dfee620355 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:32:47 +0100 Subject: [PATCH 514/781] MinGW: use off64_t and lseek64() On Windows, off_t is restricted to 32-bit, even if it is perfectly capable of using 64-bit offsets; Force the use of 64-bit offsets by overriding the declarations of off_t and lseek() with their 64-bit counterparts. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 8898006278..bfdfdb4940 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -117,6 +117,9 @@ static inline int waitpid(pid_t pid, int *status, unsigned options) return -1; } +#define off_t off64_t +#define lseek lseek64 + /* * implementations of missing functions */ From b824fc9cefb0317b98f6fc34c1192d409e859ea2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2009 15:32:55 +0100 Subject: [PATCH 515/781] Introduce the function strip_path_suffix() The function strip_path_suffix() will try to strip a given suffix from a given path. The suffix must start at a directory boundary (i.e. "core" is not a path suffix of "libexec/git-core", but "git-core" is). Arbitrary runs of directory separators ("slashes") are assumed identical. Example: prefix = strip_path_suffix("C:\\msysgit/\\libexec\\git-core", "libexec///git-core"); will set prefix to "C:\\msysgit". Signed-off-by: Johannes Schindelin --- cache.h | 1 + path.c | 32 ++++++++++++++++++++++++++++++++ t/t0060-path-utils.sh | 4 ++++ test-path-utils.c | 5 +++++ 4 files changed, 42 insertions(+) diff --git a/cache.h b/cache.h index 2d889deb26..362116dc74 100644 --- a/cache.h +++ b/cache.h @@ -629,6 +629,7 @@ const char *make_nonrelative_path(const char *path); const char *make_relative_path(const char *abs, const char *base); int normalize_absolute_path(char *buf, const char *path); int longest_ancestor_length(const char *path, const char *prefix_list); +char *strip_path_suffix(const char *path, const char *suffix); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/path.c b/path.c index 108d9e9599..719be21e75 100644 --- a/path.c +++ b/path.c @@ -457,3 +457,35 @@ int longest_ancestor_length(const char *path, const char *prefix_list) return max_len; } + +/* strip arbitrary amount of directory separators at end of path */ +static inline int chomp_trailing_dir_sep(const char *path, int len) +{ + while (len && is_dir_sep(path[len - 1])) + len--; + return len; +} + +/* sets prefix if the suffix matches */ +char *strip_path_suffix(const char *path, const char *suffix) +{ + int path_len = strlen(path), suffix_len = strlen(suffix); + + while (suffix_len) { + if (!path_len) + return NULL; + + if (is_dir_sep(path[path_len - 1])) { + if (!is_dir_sep(suffix[suffix_len - 1])) + return NULL; + path_len = chomp_trailing_dir_sep(path, path_len); + suffix_len = chomp_trailing_dir_sep(suffix, suffix_len); + } + else if (path[--path_len] != suffix[--suffix_len]) + return NULL; + } + + if (path_len && !is_dir_sep(path[path_len - 1])) + return NULL; + return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); +} diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 6e7501f352..1df1d8948a 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -84,4 +84,8 @@ ancestor /foo/bar :://foo/.:: 4 ancestor /foo/bar //foo/./::/bar 4 ancestor /foo/bar ::/bar -1 +test_expect_success 'strip_path_suffix' ' + test c:/msysgit = $(test-path-utils strip_path_suffix \ + c:/msysgit/libexec//git-core libexec/git-core) +' test_done diff --git a/test-path-utils.c b/test-path-utils.c index 2c0f5a37e8..003680dcda 100644 --- a/test-path-utils.c +++ b/test-path-utils.c @@ -22,5 +22,10 @@ int main(int argc, char **argv) printf("%d\n", len); } + if (argc == 4 && !strcmp(argv[1], "strip_path_suffix")) { + char *prefix = strip_path_suffix(argv[2], argv[3]); + printf("%s\n", prefix ? prefix : "(null)"); + } + return 0; } From 047f0f01f21824cc925102ad4e8e623c4806e0aa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2009 15:41:37 +0100 Subject: [PATCH 516/781] system_path(): simplify using strip_path_suffix(), and add suffix "git" At least for the author of this patch, the logic in system_path() was too hard to understand. Using the function strip_path_suffix() documents the idea of the code better. The real change is to add the suffix "git", so that a runtime prefix will be computed correctly even when the executable was called in /git/ as is the case in msysGit (Windows insists to search the current directory before the PATH when looking for an executable). Signed-off-by: Johannes Schindelin --- exec_cmd.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index f234066def..217c12577f 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -23,35 +23,10 @@ const char *system_path(const char *path) assert(argv0_path); assert(is_absolute_path(argv0_path)); - if (!prefix) { - const char *strip[] = { - GIT_EXEC_PATH, - BINDIR, - 0 - }; - const char **s; - - for (s = strip; *s; s++) { - const char *sargv = argv0_path + strlen(argv0_path); - const char *ss = *s + strlen(*s); - while (argv0_path < sargv && *s < ss - && (*sargv == *ss || - (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { - sargv--; - ss--; - } - if (*s == ss) { - struct strbuf d = STRBUF_INIT; - /* We also skip the trailing directory separator. */ - assert(sargv - argv0_path - 1 >= 0); - strbuf_add(&d, argv0_path, sargv - argv0_path - 1); - prefix = strbuf_detach(&d, NULL); - break; - } - } - } - - if (!prefix) { + if (!prefix && + !(prefix = strip_path_suffix(argv0_path, GIT_EXEC_PATH)) && + !(prefix = strip_path_suffix(argv0_path, BINDIR)) && + !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; fprintf(stderr, "RUNTIME_PREFIX requested, " "but prefix computation failed. " From fc8f39c0dad332a7c909d5a379eb01d594cf3594 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 19 Feb 2009 21:40:10 +0100 Subject: [PATCH 517/781] strip_path_suffix(): fix comment Signed-off-by: Johannes Schindelin --- path.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/path.c b/path.c index 719be21e75..b31d0e1fb1 100644 --- a/path.c +++ b/path.c @@ -466,7 +466,11 @@ static inline int chomp_trailing_dir_sep(const char *path, int len) return len; } -/* sets prefix if the suffix matches */ +/* + * If path ends with suffix (complete path components), returns the + * part before suffix (sans trailing directory separators). + * Otherwise returns NULL. + */ char *strip_path_suffix(const char *path, const char *suffix) { int path_len = strlen(path), suffix_len = strlen(suffix); From 96fd02ed68fb068ba75d980bcd280bbdb5169bba Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 19:15:02 +0100 Subject: [PATCH 518/781] Revert "MinGW: use off64_t and lseek64()" This reverts commit 3cb35a31b04fb8e5cbfda3affcaa87dfee620355. The fix was incorrect. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index bfdfdb4940..8898006278 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -117,9 +117,6 @@ static inline int waitpid(pid_t pid, int *status, unsigned options) return -1; } -#define off_t off64_t -#define lseek lseek64 - /* * implementations of missing functions */ From ff9031617a6b8e3f49d2362d91e34029dace5ce2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 18:46:54 +0100 Subject: [PATCH 519/781] Quiet make: do not leave Windows behind On Windows, we have to check whether there are scripts which would override .exe files, but this check missed the "quietification". Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 105c31f51d..3c54b629df 100644 --- a/Makefile +++ b/Makefile @@ -1139,7 +1139,7 @@ SHELL = $(SHELL_PATH) all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS ifneq (,$X) - $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';) + $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';) endif all:: From f30905f5dd684e4ca57408f4e8f512d46791702f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 18:34:42 +0100 Subject: [PATCH 520/781] Add an (optional, since expensive) test for >2gb clones Define GIT_TEST_CLONE_2GB=t if you want the test not to be skipped. The test works by constructing a repository larger than 2gb, and then cloning it. The repository is forced larger than 2gb by setting compression and delta depth to zero, and then adding just enough unique objects of a given size. The objects consist of a running decimal number in ASCII, padded by spaces. Should that break in the future, e.g. when pack v4 becomes default, there is a commented-out call to test-genrandom which can be substituted, but that uses more cycles than the current method. Signed-off-by: Johannes Schindelin --- t/t5705-clone-2gb.sh | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 t/t5705-clone-2gb.sh diff --git a/t/t5705-clone-2gb.sh b/t/t5705-clone-2gb.sh new file mode 100755 index 0000000000..9f52154cac --- /dev/null +++ b/t/t5705-clone-2gb.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +test_description='Test cloning a repository larger than 2 gigabyte' +. ./test-lib.sh + +test -z "$GIT_TEST_CLONE_2GB" && +say "Skipping expensive 2GB clone test; enable it with GIT_TEST_CLONE_2GB=t" && +test_done && +exit + +test_expect_success 'setup' ' + + git config pack.compression 0 && + git config pack.depth 0 && + blobsize=$((20*1024*1024)) && + blobcount=$((2*1024*1024*1024/$blobsize+1)) && + i=1 && + (while test $i -le $blobcount + do + printf "Generating blob $i/$blobcount\r" >&2 && + printf "blob\nmark :$i\ndata $blobsize\n" && + #test-genrandom $i $blobsize && + printf "%-${blobsize}s" $i && + echo "M 100644 :$i $i" >> commit + i=$(($i+1)) || + echo $? > exit-status + done && + echo "commit refs/heads/master" && + echo "author A U Thor 123456789 +0000" && + echo "committer C O Mitter 123456789 +0000" && + echo "data 5" && + echo ">2gb" && + cat commit) | + git fast-import && + test ! -f exit-status + +' + +test_expect_success 'clone' ' + + git clone --bare --no-hardlinks . clone + +' + +test_done From 081c091d507cc2e7b8f318d9e999335d9e96caf8 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Mar 2009 19:15:02 +0100 Subject: [PATCH 521/781] MinGW: 64-bit file offsets The type 'off_t' should be used everywhere so that the bit-depth of that type can be adjusted in the standard C library, and you just need to recompile your program to benefit from the extended precision. Only that it was not done that way in the MS runtime library. This patch reroutes off_t to off64_t and provides the other necessary changes so that finally, clones larger than 2 gigabyte work on Windows (provided you are on a file system that allows files larger than 2gb). Initial patch by Sickboy . Signed-off-by: Johannes Schindelin --- compat/mingw.c | 8 +++++--- compat/mingw.h | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 869bd4acbe..c011754023 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -46,7 +46,8 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_size = fdata.nFileSizeLow | + (((off_t)fdata.nFileSizeHigh)<<32); buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); @@ -101,7 +102,7 @@ int mingw_fstat(int fd, struct stat *buf) } /* direct non-file handles to MS's fstat() */ if (GetFileType(fh) != FILE_TYPE_DISK) - return fstat(fd, buf); + return _fstati64(fd, buf); if (GetFileInformationByHandle(fh, &fdata)) { buf->st_ino = 0; @@ -109,7 +110,8 @@ int mingw_fstat(int fd, struct stat *buf) buf->st_uid = 0; buf->st_nlink = 1; buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_size = fdata.nFileSizeLow | + (((off_t)fdata.nFileSizeHigh)<<32); buf->st_dev = buf->st_rdev = 0; /* not used by Git */ buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); diff --git a/compat/mingw.h b/compat/mingw.h index 8898006278..92fb3103c2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -162,11 +162,14 @@ int mingw_rename(const char*, const char*); /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. */ +#define off_t off64_t +#define stat _stati64 +#define lseek _lseeki64 int mingw_lstat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat(x,y) mingw_lstat(x,y) +#define stat64(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime From fc048d74273cbf98c412916dd3332d03bf334c79 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 15:19:39 +0100 Subject: [PATCH 522/781] Brown paper bag fix for MinGW 64-bit stat When overriding the identifier "stat" so that "struct stat" will be substituted with "struct _stati64" everywhere, I tried to fix the calls to the _function_ stat(), too, but I forgot to change the earlier attempt "stat64" to "_stati64" there. So, the stat() calls were overridden by calls to _stati64() instead. Unfortunately, there is a function _stati64() so that I missed that calls to stat() were not actually overridden by calls to mingw_lstat(), but t4200-rerere.sh showed the error. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index 92fb3103c2..a0b74fb7ca 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -169,7 +169,7 @@ int mingw_lstat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime From dba002b9e521c639847650fbaeb8b87b66b9562e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 16:36:09 +0100 Subject: [PATCH 523/781] MinGW: fix diff --no-index /dev/null ... When launching "diff --no-index" with a parameter "/dev/null", the MSys bash converts the "/dev/null" to a "nul", which usually makes sense. But diff --no-index got confused and tried to access a _file_ called "nul". While at it, the comment in t4012, expressed as ":# " was turned into ": " so that MSys' path name mangling does not kick in. With this patch, t4012 passes in msysGit. Signed-off-by: Johannes Schindelin --- diff-no-index.c | 4 ++++ t/t4012-diff-binary.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/diff-no-index.c b/diff-no-index.c index 0a14268ba9..598687b50a 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -38,6 +38,10 @@ static int get_mode(const char *path, int *mode) if (!path || !strcmp(path, "/dev/null")) *mode = 0; +#ifdef _WIN32 + else if (!strcasecmp(path, "nul")) + *mode = 0; +#endif else if (!strcmp(path, "-")) *mode = create_ce_mode(0666); else if (lstat(path, &st)) diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 3cf5b5c4ea..f64aa48d24 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -87,7 +87,7 @@ nul_to_q() { test_expect_success 'diff --no-index with binary creation' ' echo Q | q_to_nul >binary && - (:# hide error code from diff, which just indicates differences + (: hide error code from diff, which just indicates differences git diff --binary --no-index /dev/null binary >current || true ) && From 23c5477dfb63cee46806b9f9c8d9d73d93db776e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 17:40:15 +0100 Subject: [PATCH 524/781] t4129: skip tests if core.filemode = false If we cannot test file modes, we cannot test file modes. Signed-off-by: Johannes Schindelin --- t/t4129-apply-samemode.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index adfcbb5a3b..a74101abba 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -16,6 +16,11 @@ test_expect_success setup ' git diff --stat -p >patch-1.txt ' +test "$(git config --bool core.filemode)" = false && +say "executable bit not honored - skipping" && +test_done && +exit + test_expect_success 'same mode (no index)' ' git reset --hard && chmod +x file && From 3a76fdaf98efbb1dc2f71352c811ab6d2710b74f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 19:12:37 +0100 Subject: [PATCH 525/781] MinGW: GCC >= 4 does not need SNPRINTF_SIZE_CORR anymore Signed-off-by: Johannes Schindelin --- Makefile | 1 - compat/snprintf.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3c54b629df..801303ebc8 100644 --- a/Makefile +++ b/Makefile @@ -804,7 +804,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch - COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 diff --git a/compat/snprintf.c b/compat/snprintf.c index 357e733074..7d780508a7 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -6,8 +6,12 @@ * number of characters to write without the trailing NUL. */ #ifndef SNPRINTF_SIZE_CORR +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 3 +#define SNPRINTF_SIZE_CORR 1 +#else #define SNPRINTF_SIZE_CORR 0 #endif +#endif #undef vsnprintf int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) From 3d27683b91df7d4fd6b70e32ed12b08721a46dbd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 19:44:03 +0100 Subject: [PATCH 526/781] Revert "MinGW: only override PRIuMAX for GCC older than version 4" This reverts commit 6d3e71d428b1ee007339d679c26a336c8aefeade. Apparently, GCC >= 4 does not like %I64u as modifier to show unsigned long longs. However, using %llu -- even if the compiler warning goes away -- fails spectacularly: The C runtime insists that %llu takes 32-bit numbers. So for now, we _have_ to live with compiler warnings galore. Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index a0b74fb7ca..b82903c74a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -203,9 +203,7 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') #define is_dir_sep(c) ((c) == '/' || (c) == '\\') #define PATH_SEP ';' -#if !defined(__GNUC__) || __GNUC__ < 3 #define PRIuMAX "I64u" -#endif void mingw_open_html(const char *path); #define open_html mingw_open_html From 04f4f675ae629eccb30be521868d9c1698d56170 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 20:29:54 +0100 Subject: [PATCH 527/781] MinGW: t6200 needs to understand Windows paths Signed-off-by: Johannes Schindelin --- t/t6200-fmt-merge-msg.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 8f5a06f7dd..763c46038a 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -82,6 +82,7 @@ test_expect_success 'merge-msg test #1' ' test_cmp expected actual ' +TEST_DIRECTORY=$(cd "$TEST_DIRECTORY" && pwd) cat >expected < Date: Sat, 7 Mar 2009 20:48:08 +0100 Subject: [PATCH 528/781] MinGW: the path separator to split GITPERLLIB is ';' on Win32 Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 801303ebc8..995a11c9f7 100644 --- a/Makefile +++ b/Makefile @@ -209,6 +209,7 @@ ETC_GITCONFIG = etc/gitconfig endif lib = lib # DESTDIR= +pathsep = : # default configuration for gitweb GITWEB_CONFIG = gitweb_config.perl @@ -776,6 +777,7 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) + pathsep = ; prefix = INSTALL = /bin/install EXTLIBS += /mingw/lib/libz.a @@ -1204,7 +1206,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl sed -e '1{' \ -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ -e ' h' \ - -e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ + -e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ -e ' H' \ -e ' x' \ -e '}' \ From d7bc3dd8f7a2091e9d7dec69bed96d53653d9a79 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 23:12:43 +0100 Subject: [PATCH 529/781] t5520: do not skip test that does not fail anymore Signed-off-by: Johannes Schindelin --- t/t5520-pull.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 8377733f7b..725771fac1 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -88,7 +88,6 @@ test_expect_success 'branch.to-rebase.rebase' ' test new = $(git show HEAD:file2) ' -say "Remote does not work in t/ - skipping." || test_expect_success '--rebase with rebased upstream' ' git remote add -f me . && From b1744a5fde45def23aa5778bf4a22df8f070422d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Mar 2009 17:58:32 +0100 Subject: [PATCH 530/781] t7300: fix clean up on Windows On Windows, you cannot remove files that are in use, not even with 'rm -rf'. So we need to run 'exec --- t/t7300-clean.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 1636fac2a4..929d5d4d3b 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -373,9 +373,9 @@ test_expect_success 'removal failure' ' mkdir foo && touch foo/bar && - exec Date: Wed, 18 Mar 2009 09:43:24 +0100 Subject: [PATCH 531/781] Let t0000 pass on Windows again This is needed after the recent test_cmp conversion (188c3827). Signed-off-by: Johannes Sixt --- t/t0000-basic.sh | 64 +++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index 5749602673..f7cdbad7cb 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -30,22 +30,6 @@ fi . ./test-lib.sh -test "$no_symlinks" && { - DIFF=$(which diff) - - function diff () { - opt= - case "$1" in -*) opt=$1; shift;; esac - tr -d "\015" < $1 > $1.doof - grep -v "^:\?120000" < $2 | \ - sed -e s/58a09c23e2ca152193f2786e06986b7b6712bdbe/600f42758e4458c37c2c1f8063378f540b4efad7/ \ - -e s/21ae8269cacbe57ae09138dcc3a2887f904d02b3/cfb8591b2f65de8b8cc1020cd7d9e67e7793b325/ \ - -e s/3c5e5399f3a333eddecce7a9b9465b63f65f51e2/ce580448f0148b985a513b693fdf7d802cacb44f/ \ - > $2.doof - $DIFF $opt $1.doof $2.doof - } -} - ################################################################ # git init has been done in an empty repository. # make sure it is empty. @@ -116,12 +100,31 @@ test_expect_success \ 'test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904' # Various types of objects +# Some filesystems do not support symblic links; on such systems +# some expected values are different mkdir path2 path3 path3/subp3 -for p in path0 path2/file2 path3/file3 path3/subp3/file3 +paths='path0 path2/file2 path3/file3 path3/subp3/file3' +for p in $paths do echo "hello $p" >$p - ln -s "hello $p" ${p}sym done +if test -z "$no_symlinks" +then + for p in $paths + do + ln -s "hello $p" ${p}sym + done + expectfilter=cat + expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b + expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3 + expectedptree2=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 +else + expectfilter='grep -v sym' + expectedtree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 + expectedptree1=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 + expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f +fi + test_expect_success \ 'adding various types of objects with git update-index --add.' \ 'find path* ! -type d -print | xargs git update-index --add' @@ -131,7 +134,7 @@ test_expect_success \ 'showing stage with git ls-files --stage' \ 'git ls-files --stage >current' -cat >expected <<\EOF +$expectfilter >expected <<\EOF 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 @@ -149,11 +152,9 @@ test_expect_success \ test_expect_success \ 'writing tree out with git write-tree.' \ 'tree=$(git write-tree)' -expected_tree=087704a96baf1c2d1c869a8b084481e121c88b5b -test "$no_symlinks" && expected_tree=8e18edf7d7edcf4371a3ac6ae5f07c2641db7c46 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$tree" = "$expected_tree"' + 'test "$tree" = "$expectedtree"' test_expect_success \ 'showing tree with git ls-tree' \ @@ -164,6 +165,7 @@ cat >expected <<\EOF 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 EOF +test -z "$no_symlinks" && test_expect_success \ 'git ls-tree output for a known tree.' \ 'test_cmp expected current' @@ -173,7 +175,7 @@ test_expect_success \ test_expect_success \ 'showing tree with git ls-tree -r' \ 'git ls-tree -r $tree >current' -cat >expected <<\EOF +$expectfilter >expected <<\EOF 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 @@ -204,6 +206,7 @@ cat >expected <<\EOF 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym EOF +test -z "$no_symlinks" && test_expect_success \ 'git ls-tree -r output for a known tree.' \ 'test_cmp expected current' @@ -211,20 +214,16 @@ test_expect_success \ test_expect_success \ 'writing partial tree out with git write-tree --prefix.' \ 'ptree=$(git write-tree --prefix=path3)' -expected_tree=21ae8269cacbe57ae09138dcc3a2887f904d02b3 -test "$no_symlinks" && expected_tree=cfb8591b2f65de8b8cc1020cd7d9e67e7793b325 test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expected_tree"' + 'test "$ptree" = "$expectedptree1"' test_expect_success \ 'writing partial tree out with git write-tree --prefix.' \ 'ptree=$(git write-tree --prefix=path3/subp3)' -expect_tree=3c5e5399f3a333eddecce7a9b9465b63f65f51e2 -test "$no_symlinks" && expect_tree=ce580448f0148b985a513b693fdf7d802cacb44f test_expect_success \ 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expect_tree"' + 'test "$ptree" = "$expectedptree2"' cat >badobjects <expected <<\EOF +$expectfilter >expected <<\EOF :100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0 :120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym :100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2 @@ -280,8 +279,7 @@ test_expect_success \ 'git diff-files >current && cmp -s current /dev/null' ################################################################ -P=087704a96baf1c2d1c869a8b084481e121c88b5b -test "$no_symlinks" && P=7bb943559a305bdd6bdee2cef6e5df2413c3d30a +P=$expectedtree test_expect_success \ 'git commit-tree records the correct tree in a commit.' \ 'commit0=$(echo NO | git commit-tree $P) && @@ -317,7 +315,7 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' -test "$no_symlinks" || +test -z "$no_symlinks" && test_expect_success 'absolute path works as expected' ' mkdir first && ln -s ../.git first/.git && From bf09f21ae48c0daec7ea17573465aea800b13a8f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Jan 2009 11:25:07 +0100 Subject: [PATCH 532/781] t4129: cannot test executable mode on Windows Signed-off-by: Johannes Sixt --- t/t4129-apply-samemode.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index adfcbb5a3b..6284b80e3a 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -4,6 +4,9 @@ test_description='applying patch with mode bits' . ./test-lib.sh +say "executable mode not supported - skipping tests" +test_done + test_expect_success setup ' echo original >file && git add file && From 278924204288aa622d1ab319eaee08d8972d2d2b Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 18 Mar 2009 13:31:38 +0100 Subject: [PATCH 533/781] t6031-merge-recursive: More fixes for exec bit challenged filesystems Commit 28f880241782024ecb212f1641c8dc487124523b improved the tests to work on filesystems that do not honor the exec bit, but it didn't go the full nine yards: If chmod +x does not work, then test -x will not work reliably, either, which was the only way how the tests checked the result. This patch works around the issue by testing the index if the filesystem does not report that the exec bit is set. Signed-off-by: Johannes Sixt --- t/t6031-merge-recursive.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t6031-merge-recursive.sh b/t/t6031-merge-recursive.sh index 8073e0c3ef..02aafa6d56 100755 --- a/t/t6031-merge-recursive.sh +++ b/t/t6031-merge-recursive.sh @@ -20,7 +20,7 @@ test_expect_success 'mode change in one branch: keep changed version' ' git commit -m b1 && git checkout a1 && git merge-recursive master -- a1 b1 && - test -x file1 + { test -x file1 || git ls-files -s file1 | grep ^100755; } ' test_expect_success 'mode change in both branches: expect conflict' ' @@ -46,7 +46,7 @@ test_expect_success 'mode change in both branches: expect conflict' ' echo "100644 $H 3 file2" ) >expect && test_cmp actual expect && - test -x file2 + { test -x file2 || git ls-files -s file2 | grep ^100755; } ' test_done From f659ae81d868ad7fbde7558187658cb965976a8c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 18 Mar 2009 13:35:40 +0100 Subject: [PATCH 534/781] test-lib: Work around missing sum on Windows Signed-off-by: Johannes Sixt --- t/t1002-read-tree-m-u-2way.sh | 6 ------ t/test-lib.sh | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh index c4565d559d..5e40cec530 100755 --- a/t/t1002-read-tree-m-u-2way.sh +++ b/t/t1002-read-tree-m-u-2way.sh @@ -10,12 +10,6 @@ This is identical to t1001, but uses -u to update the work tree as well. ' . ./test-lib.sh -sum ./test-lib.sh >/dev/null 2>&1 || { - function sum () { - md5sum "$@" - } -} - _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" compare_change () { diff --git a/t/test-lib.sh b/t/test-lib.sh index 54556cf093..1be09a4754 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -646,5 +646,8 @@ case $(uname -s) in find () { /usr/bin/find "$@" } + sum () { + md5sum "$@" + } ;; esac From b948d7cf5546d3ebb17d142ecee6fbd983c4b1e7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 11 Mar 2009 17:58:32 +0100 Subject: [PATCH 535/781] t7300: fix clean up on Windows On Windows, you cannot remove files that are in use, not even with 'rm -rf'. So we need to run 'exec Signed-off-by: Johannes Sixt --- t/t7300-clean.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 1636fac2a4..929d5d4d3b 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -373,9 +373,9 @@ test_expect_success 'removal failure' ' mkdir foo && touch foo/bar && - exec Date: Wed, 18 Mar 2009 13:44:42 +0100 Subject: [PATCH 536/781] t0060: Fix tests on Windows Since the MSYS bash mangles absolute paths that it passes as command line arguments to non-MSYS progams (such as git or test-path-utils), we have to bend over backwards to squeeze some usefulness out of the existing tests. In particular, a set of path normalization tests is added that test relative paths. Some paths in the ancestor path tests are adjusted to help MSYS bash's path mangling heuristics. Signed-off-by: Johannes Sixt --- t/t0060-path-utils.sh | 116 ++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 33 deletions(-) diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 8336114f98..d849868e49 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -7,41 +7,91 @@ test_description='Test various path utilities' . ./test-lib.sh -norm_abs() { - test_expect_success "normalize absolute: $1 => $2" \ +norm_path() { + test_expect_success "normalize path: $1 => $2" \ "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$2'" } +# On Windows, we are using MSYS's bash, which mangles the paths. +# Absolute paths are anchored at the MSYS installation directory, +# which means that the path / accounts for this many characters: +rootoff=$(test-path-utils normalize_path_copy / | wc -c) +# Account for the trailing LF: +if test "$rootoff" = 2; then + rootoff= # we are on Unix +else + rootoff=$(($rootoff-1)) +fi + ancestor() { - test_expect_success "longest ancestor: $1 $2 => $3" \ - "test \"\$(test-path-utils longest_ancestor_length '$1' '$2')\" = '$3'" + # We do some math with the expected ancestor length. + expected=$3 + if test -n "$rootoff" && test "x$expected" != x-1; then + expected=$(($expected+$rootoff)) + fi + test_expect_success "longest ancestor: $1 $2 => $expected" \ + "actual=\$(test-path-utils longest_ancestor_length '$1' '$2') && + test \"\$actual\" = '$expected'" } -norm_abs "" "" -norm_abs / / -norm_abs // / -norm_abs /// / -norm_abs /. / -norm_abs /./ / -norm_abs /./.. ++failed++ -norm_abs /../. ++failed++ -norm_abs /./../.// ++failed++ -norm_abs /dir/.. / -norm_abs /dir/sub/../.. / -norm_abs /dir/sub/../../.. ++failed++ -norm_abs /dir /dir -norm_abs /dir// /dir/ -norm_abs /./dir /dir -norm_abs /dir/. /dir/ -norm_abs /dir///./ /dir/ -norm_abs /dir//sub/.. /dir/ -norm_abs /dir/sub/../ /dir/ -norm_abs //dir/sub/../. /dir/ -norm_abs /dir/s1/../s2/ /dir/s2/ -norm_abs /d1/s1///s2/..//../s3/ /d1/s3/ -norm_abs /d1/s1//../s2/../../d2 /d2 -norm_abs /d1/.../d2 /d1/.../d2 -norm_abs /d1/..././../d2 /d1/d2 +norm_path "" "" +norm_path . "" +norm_path ./ "" +norm_path ./. "" +norm_path ./.. ++failed++ +norm_path ../. ++failed++ +norm_path ./../.// ++failed++ +norm_path dir/.. "" +norm_path dir/sub/../.. "" +norm_path dir/sub/../../.. ++failed++ +norm_path dir dir +norm_path dir// dir/ +norm_path ./dir dir +norm_path dir/. dir/ +norm_path dir///./ dir/ +norm_path dir//sub/.. dir/ +norm_path dir/sub/../ dir/ +norm_path dir/sub/../. dir/ +norm_path dir/s1/../s2/ dir/s2/ +norm_path d1/s1///s2/..//../s3/ d1/s3/ +norm_path d1/s1//../s2/../../d2 d2 +norm_path d1/.../d2 d1/.../d2 +norm_path d1/..././../d2 d1/d2 + +# Absolute path tests must be skipped on Windows because due to path mangling +# the test program never sees a POSIX-style absolute path +case $(uname -s) in +*MINGW*) + ;; +*) + +norm_path / / POSIX +norm_path // / POSIX +norm_path /// / POSIX +norm_path /. / POSIX +norm_path /./ / POSIX +norm_path /./.. ++failed++ POSIX +norm_path /../. ++failed++ POSIX +norm_path /./../.// ++failed++ POSIX +norm_path /dir/.. / POSIX +norm_path /dir/sub/../.. / POSIX +norm_path /dir/sub/../../.. ++failed++ POSIX +norm_path /dir /dir POSIX +norm_path /dir// /dir/ POSIX +norm_path /./dir /dir POSIX +norm_path /dir/. /dir/ POSIX +norm_path /dir///./ /dir/ POSIX +norm_path /dir//sub/.. /dir/ POSIX +norm_path /dir/sub/../ /dir/ POSIX +norm_path //dir/sub/../. /dir/ POSIX +norm_path /dir/s1/../s2/ /dir/s2/ POSIX +norm_path /d1/s1///s2/..//../s3/ /d1/s3/ POSIX +norm_path /d1/s1//../s2/../../d2 /d2 POSIX +norm_path /d1/.../d2 /d1/.../d2 POSIX +norm_path /d1/..././../d2 /d1/d2 POSIX + + ;; +esac ancestor / "" -1 ancestor / / -1 @@ -80,10 +130,10 @@ ancestor /foo/bar /:/foo:/bar/ 4 ancestor /foo/bar /foo:/:/bar/ 4 ancestor /foo/bar /:/bar/:/fo 0 ancestor /foo/bar /:/bar/ 0 -ancestor /foo/bar :://foo/. 4 -ancestor /foo/bar :://foo/.:: 4 -ancestor /foo/bar //foo/./::/bar 4 -ancestor /foo/bar ::/bar -1 +ancestor /foo/bar .:/foo/. 4 +ancestor /foo/bar .:/foo/.:.: 4 +ancestor /foo/bar /foo/./:.:/bar 4 +ancestor /foo/bar .:/bar -1 test_expect_success 'strip_path_suffix' ' test c:/msysgit = $(test-path-utils strip_path_suffix \ From ca0d369b00cad920e62b846f0ed4a9c8c5cf7114 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 13 Mar 2009 23:35:24 +0100 Subject: [PATCH 537/781] Tests on Windows: $(pwd) must return Windows-style paths Many tests pass $(pwd) in some form to git and later test that the output of git contains the correct value of $(pwd). For example, the test of 'git remote show' sets up a remote that contains $(pwd) and then the expected result must contain $(pwd). Again, MSYS-bash's path mangling kicks in: Plain $(pwd) uses the MSYS style absolute path /c/path/to/git. The test case would write this name into the 'expect' file. But when git is invoked, MSYS-bash converts this name to the Windows style path c:/path/to/git, and git would produce this form in the result; the test would fail. We fix this by passing -W to MSYS bash's pwd, which produces the Windows-style path. There are a two cases that need an accompanying change: - In t1504 the value of $(pwd) becomes part of a path list. In this case, the lone 'c' in something like /foo:c:/path/to/git:/bar inhibits MSYS-bashes path mangling; IOW in this case we want the /c/path/to/git form to allow path mangling. We use $PWD instead of $(pwd), which always has the latter form. - In t6200, $(pwd) - the Windows style path - must be used to construct the expected result because that is the path form that git sees. (The change in the test itself is just for consistency: 'git fetch' always sees the Windows-style path, with or without the change.) Signed-off-by: Johannes Sixt --- t/t1504-ceiling-dirs.sh | 2 +- t/t6200-fmt-merge-msg.sh | 4 ++-- t/test-lib.sh | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/t/t1504-ceiling-dirs.sh b/t/t1504-ceiling-dirs.sh index e377d48902..df5ad8c686 100755 --- a/t/t1504-ceiling-dirs.sh +++ b/t/t1504-ceiling-dirs.sh @@ -13,7 +13,7 @@ test_fail() { "git rev-parse --show-prefix" } -TRASH_ROOT="$(pwd)" +TRASH_ROOT="$PWD" ROOT_PARENT=$(dirname "$TRASH_ROOT") diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 8f5a06f7dd..2049ab6cf8 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -83,13 +83,13 @@ test_expect_success 'merge-msg test #1' ' ' cat >expected <actual && test_cmp expected actual diff --git a/t/test-lib.sh b/t/test-lib.sh index 1be09a4754..f4325f1b14 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -649,5 +649,9 @@ case $(uname -s) in sum () { md5sum "$@" } + # git sees Windows-style pwd + pwd () { + builtin pwd -W + } ;; esac From c43fb7fe2367a1b3a8ba76cf66212aa517a46e2d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 12 Mar 2009 15:25:10 +0100 Subject: [PATCH 538/781] MinGW: fix signature of CreateHardLinkA() If the declaration of CreateHardLinkA() does not contain the magic word "WINAPI", the stack will be clobbered in the error case. This fixes msysGit issue 204. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index c011754023..71e12dd478 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1122,7 +1122,7 @@ static int err_win_to_posix(DWORD winerr) int link(const char *oldpath, const char *newpath) { - typedef BOOL (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + typedef BOOL WINAPI (*T)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES); static T create_hard_link = NULL; if (!create_hard_link) { create_hard_link = (T) GetProcAddress( From 7e5a4c563667d011c0655679be3190461884a78e Mon Sep 17 00:00:00 2001 From: Janos Laube Date: Sat, 7 Mar 2009 03:54:10 +0100 Subject: [PATCH 539/781] support for win32 mmap Add USE_WIN32_MMAP which triggers the use of windows' native file memory mapping functionality in git_mmap()/git_munmap() functions. As git functions currently use mmap with MAP_PRIVATE set only, this implementation supports only that mode for now. On Windows offsets for memory mapped files need to match the allocation granularity. Take this into account when calculating the packed git- windowsize and file offsets. At the moment the only function which makes use of offsets in conjunction with mmap is use_pack() in sha1-file.c. Git fast-import's code path tries to map a portion of the temporary packfile which exceeds the current filesize, i.e. offset+length is greater than the filesize. The NO_MMAP code worked with that since pread() just reads the filecontent until EOF and returns gracefully, while MapViewOfFile() aborts the mapping and returns 'Access Denied'. Working around that by determining the filesize and adjusting the length parameter. Signed-off-by: Janos Laube --- Makefile | 6 +++++- compat/mingw.h | 5 +++++ compat/win32mmap.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 12 ++++++++--- 4 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 compat/win32mmap.c diff --git a/Makefile b/Makefile index 4097892986..4ac0e99906 100644 --- a/Makefile +++ b/Makefile @@ -781,7 +781,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) prefix = INSTALL = /bin/install EXTLIBS += /mingw/lib/libz.a - NO_MMAP = YesPlease NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease @@ -805,6 +804,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease + USE_WIN32_MMAP = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o @@ -974,6 +974,10 @@ ifdef NO_MMAP COMPAT_CFLAGS += -DNO_MMAP COMPAT_OBJS += compat/mmap.o endif +ifdef USE_WIN32_MMAP + COMPAT_CFLAGS += -DUSE_WIN32_MMAP + COMPAT_OBJS += compat/win32mmap.o +endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o diff --git a/compat/mingw.h b/compat/mingw.h index b82903c74a..b1156b865e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -159,6 +159,11 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz); int mingw_rename(const char*, const char*); #define rename mingw_rename +#ifdef USE_WIN32_MMAP +int mingw_getpagesize(void); +#define getpagesize mingw_getpagesize +#endif + /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. */ diff --git a/compat/win32mmap.c b/compat/win32mmap.c new file mode 100644 index 0000000000..66314b8430 --- /dev/null +++ b/compat/win32mmap.c @@ -0,0 +1,53 @@ +#include "../git-compat-util.h" + +/* Note that this doesn't return the actual pagesize, but + * the allocation granularity. If future Windows specific git code + * needs the real getpagesize function, we need to find another solution. + */ +int mingw_getpagesize(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwAllocationGranularity; +} + +void *git_mmap +(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + HANDLE hmap; + void *temp; + size_t len; + struct stat st; + uint64_t o = offset; + uint32_t l = o & 0xFFFFFFFF; + uint32_t h = (o >> 32) & 0xFFFFFFFF; + + if (!fstat(fd, &st)) + len = xsize_t(st.st_size); + else + die("mmap: could not determine filesize"); + + if ((length + offset) > len) + length = len - offset; + + if (!(flags & MAP_PRIVATE)) + die("Invalid usage of mmap when built with USE_WIN32_MMAP"); + + hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY, + 0, 0, 0); + + if (!hmap) + return MAP_FAILED; + + temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start); + + if (!CloseHandle(hmap)) + warning("unable to close file mapping handle\n"); + + return temp ? temp : MAP_FAILED; +} + +int git_munmap(void *start, size_t length) +{ + return !UnmapViewOfFile(start); +} diff --git a/git-compat-util.h b/git-compat-util.h index 878d83dd08..1eef4eb5b9 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -166,7 +166,7 @@ static inline const char *skip_prefix(const char *str, const char *prefix) return strncmp(str, prefix, len) ? NULL : str + len; } -#ifdef NO_MMAP +#if defined(NO_MMAP) || defined(USE_WIN32_MMAP) #ifndef PROT_READ #define PROT_READ 1 @@ -180,13 +180,19 @@ static inline const char *skip_prefix(const char *str, const char *prefix) extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); extern int git_munmap(void *start, size_t length); +#else /* NO_MMAP || USE_WIN32_MMAP */ + +#include + +#endif /* NO_MMAP || USE_WIN32_MMAP */ + +#ifdef NO_MMAP + /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024) #else /* NO_MMAP */ -#include - /* This value must be multiple of (pagesize * 2) */ #define DEFAULT_PACKED_GIT_WINDOW_SIZE \ (sizeof(void*) >= 8 \ From 8593d8429cbd09ce813c8f42f5c00bb7d5cf9e7e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 10 Mar 2009 22:54:17 +0100 Subject: [PATCH 540/781] recv_sideband: Bands #2 and #3 always go to stderr This removes the last parameter of recv_sideband, by which the callers told which channel bands #2 and #3 should be written to. Sayeth Shawn Pearce: The definition of the streams in the current sideband protocol are rather well defined for the one protocol that uses it, fetch-pack/receive-pack: stream #1: pack data stream #2: stderr messages, progress, meant for tty stream #3: abort message, remote is dead, goodbye! Since both callers of the function passed 2 for the parameter, we hereby remove it and send bands #2 and #3 to stderr explicitly using fprintf. This has the nice side-effect that these two streams pass through our ANSI emulation layer on Windows. Signed-off-by: Johannes Sixt Acked-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- builtin-archive.c | 2 +- builtin-fetch-pack.c | 2 +- sideband.c | 19 ++++++++----------- sideband.h | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/builtin-archive.c b/builtin-archive.c index 60adef9363..ab50cebba0 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -52,7 +52,7 @@ static int run_remote_archiver(int argc, const char **argv, die("git archive: expected a flush"); /* Now, start reading from fd[0] and spit it out to stdout */ - rv = recv_sideband("archive", fd[0], 1, 2); + rv = recv_sideband("archive", fd[0], 1); close(fd[0]); close(fd[1]); rv |= finish_connect(conn); diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index c2e5adc884..2b360994bf 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -482,7 +482,7 @@ static int sideband_demux(int fd, void *data) { int *xd = data; - return recv_sideband("fetch-pack", xd[0], fd, 2); + return recv_sideband("fetch-pack", xd[0], fd); } static int get_pack(int xd[2], char **pack_lockfile) diff --git a/sideband.c b/sideband.c index cca3360546..899b1ff366 100644 --- a/sideband.c +++ b/sideband.c @@ -19,7 +19,7 @@ #define FIX_SIZE 10 /* large enough for any of the above */ -int recv_sideband(const char *me, int in_stream, int out, int err) +int recv_sideband(const char *me, int in_stream, int out) { unsigned pf = strlen(PREFIX); unsigned sf; @@ -41,8 +41,7 @@ int recv_sideband(const char *me, int in_stream, int out, int err) if (len == 0) break; if (len < 1) { - len = sprintf(buf, "%s: protocol error: no band designator\n", me); - safe_write(err, buf, len); + fprintf(stderr, "%s: protocol error: no band designator\n", me); return SIDEBAND_PROTOCOL_ERROR; } band = buf[pf] & 0xff; @@ -50,8 +49,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err) switch (band) { case 3: buf[pf] = ' '; - buf[pf+1+len] = '\n'; - safe_write(err, buf, pf+1+len+1); + buf[pf+1+len] = '\0'; + fprintf(stderr, "%s\n", buf); return SIDEBAND_REMOTE_ERROR; case 2: buf[pf] = ' '; @@ -95,12 +94,12 @@ int recv_sideband(const char *me, int in_stream, int out, int err) memcpy(save, b + brk, sf); b[brk + sf - 1] = b[brk - 1]; memcpy(b + brk - 1, suffix, sf); - safe_write(err, b, brk + sf); + fprintf(stderr, "%.*s", brk + sf, b); memcpy(b + brk, save, sf); len -= brk; } else { int l = brk ? brk : len; - safe_write(err, b, l); + fprintf(stderr, "%.*s", l, b); len -= l; } @@ -112,10 +111,8 @@ int recv_sideband(const char *me, int in_stream, int out, int err) safe_write(out, buf + pf+1, len); continue; default: - len = sprintf(buf, - "%s: protocol error: bad band #%d\n", - me, band); - safe_write(err, buf, len); + fprintf(stderr, "%s: protocol error: bad band #%d\n", + me, band); return SIDEBAND_PROTOCOL_ERROR; } } diff --git a/sideband.h b/sideband.h index a84b6917c7..d72db35d1e 100644 --- a/sideband.h +++ b/sideband.h @@ -7,7 +7,7 @@ #define DEFAULT_PACKET_MAX 1000 #define LARGE_PACKET_MAX 65520 -int recv_sideband(const char *me, int in_stream, int out, int err); +int recv_sideband(const char *me, int in_stream, int out); ssize_t send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max); #endif From 3db39264cd3334ae5e9ab933f0298540bbe389a5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 10 Mar 2009 22:58:09 +0100 Subject: [PATCH 541/781] winansi: support ESC [ K (erase in line) Signed-off-by: Johannes Schindelin Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/winansi.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/compat/winansi.c b/compat/winansi.c index e2d96dfe6f..44dc293ad3 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -18,8 +18,6 @@ This file is git-specific. Therefore, this file does not attempt to implement any codes that are not used by git. - - TODO: K */ static HANDLE console; @@ -79,6 +77,20 @@ static void set_console_attr(void) SetConsoleTextAttribute(console, attributes); } +static void erase_in_line(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + FillConsoleOutputCharacterA(console, ' ', + sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, + NULL); +} + + static const char *set_attr(const char *str) { const char *func; @@ -218,7 +230,7 @@ static const char *set_attr(const char *str) set_console_attr(); break; case 'K': - /* TODO */ + erase_in_line(); break; default: /* Unsupported code */ From f7512386097c4f20e3c147e5de8888e49e4835c5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 21 Mar 2009 01:20:57 +0100 Subject: [PATCH 542/781] Respect core.autocrlf when preparing temporary files for external diff When preparing temporary files for an external diff, the files should be handled as if they were worktree files. This makes things consistent for the case when one side of the diff was found in the current working directory (and therefore creating a temporary file could be avoided altogether). This fixes msysGit issue 177. Signed-off-by: Johannes Schindelin --- diff.c | 13 ++++++++++--- t/t4020-diff-external.sh | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/diff.c b/diff.c index 75d9fab8f8..699ae6aca3 100644 --- a/diff.c +++ b/diff.c @@ -1946,17 +1946,23 @@ void diff_free_filespec_data(struct diff_filespec *s) s->cnt_data = NULL; } -static void prep_temp_blob(struct diff_tempfile *temp, +static void prep_temp_blob(const char *path, struct diff_tempfile *temp, void *blob, unsigned long size, const unsigned char *sha1, int mode) { int fd; + struct strbuf buf = STRBUF_INIT; fd = git_mkstemp(temp->tmp_path, PATH_MAX, ".diff_XXXXXX"); if (fd < 0) die("unable to create temp-file: %s", strerror(errno)); + if (convert_to_working_tree(path, + (const char *)blob, (size_t)size, &buf)) { + blob = buf.buf; + size = buf.len; + } if (write_in_full(fd, blob, size) != size) die("unable to write temp-file"); close(fd); @@ -1964,6 +1970,7 @@ static void prep_temp_blob(struct diff_tempfile *temp, strcpy(temp->hex, sha1_to_hex(sha1)); temp->hex[40] = 0; sprintf(temp->mode, "%06o", mode); + strbuf_release(&buf); } static struct diff_tempfile *prepare_temp_file(const char *name, @@ -2004,7 +2011,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, die("readlink(%s)", name); if (ret == sizeof(buf)) die("symlink too long: %s", name); - prep_temp_blob(temp, buf, ret, + prep_temp_blob(name, temp, buf, ret, (one->sha1_valid ? one->sha1 : null_sha1), (one->sha1_valid ? @@ -2030,7 +2037,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, else { if (diff_populate_filespec(one, 0)) die("cannot read data blob for %s", one->path); - prep_temp_blob(temp, one->data, one->size, + prep_temp_blob(name, temp, one->data, one->size, one->sha1, one->mode); } return temp; diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 281680d95a..f8c99f1a98 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -136,4 +136,20 @@ test_expect_success 'GIT_EXTERNAL_DIFF with more than one changed files' ' GIT_EXTERNAL_DIFF=echo git diff ' +echo "#!$SHELL_PATH" >fake-diff.sh +cat >> fake-diff.sh <<\EOF +cat $2 >> crlfed.txt +EOF +chmod a+x fake-diff.sh + +keep_only_cr () { + tr -dc '\015' +} + +test_expect_success 'external diff with autocrlf = true' ' + git config core.autocrlf true && + GIT_EXTERNAL_DIFF=./fake-diff.sh git diff && + test $(wc -l < crlfed.txt) = $(cat crlfed.txt | keep_only_cr | wc -c) +' + test_done From d4eb98cedebe98918b58b30f19b216831098199e Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 23 Mar 2009 09:58:44 +0100 Subject: [PATCH 543/781] Undo MinGW specific test suite changes that are no longer needed The test failures are fixed meanwhile for various reasons: - Path mangling happens less often due to an updated MSYS-1.0.DLL. - pwd now always reports a Windows-style path (this was introduced in 4114156a). - The whitespace breakage in t1003 has mysteriously disappeared (perhaps due to a tool upgrade?) - The work-around in t4116 was fixed in 36adb4ab. Signed-off-by: Johannes Sixt --- t/t0001-init.sh | 2 +- t/t1003-read-tree-prefix.sh | 4 ---- t/t4116-apply-reverse.sh | 3 +-- t/t5505-remote.sh | 4 ---- t/t5511-refspec.sh | 23 +---------------------- t/t7201-co.sh | 6 +----- 6 files changed, 4 insertions(+), 38 deletions(-) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 41a36bb1a3..5ac0a273a9 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -108,7 +108,7 @@ test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' ' mkdir git-dir-wt-1.git && GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init ) && - check_config git-dir-wt-1.git false "$(pwd -W)" + check_config git-dir-wt-1.git false "$(pwd)" ' test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' ' diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh index c59ce72d94..8c6d67edda 100755 --- a/t/t1003-read-tree-prefix.sh +++ b/t/t1003-read-tree-prefix.sh @@ -8,10 +8,6 @@ test_description='git read-tree --prefix test. . ./test-lib.sh -cmp () { - diff -w "$@" -} - test_expect_success setup ' echo hello >one && git update-index --add one && diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 1f8743bfa6..2298ece801 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -42,8 +42,7 @@ test_expect_success 'apply in reverse' ' git reset --hard second && git apply --reverse --binary --index patch && git diff >diff && - : > empty && - test_cmp empty diff + test_cmp /dev/null diff ' diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 56b37ea432..5ec668d6d8 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -107,10 +107,6 @@ test_expect_success 'remove remote' ' ) ' -case $(uname -s) in -*MINGW*) pwd() { builtin pwd -W; } ;; -esac - test_expect_success 'remove remote protects non-remote branches' ' ( cd test && diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 0d27a28491..22ba380034 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -4,8 +4,6 @@ test_description='refspec parsing' . ./test-lib.sh -test_expect=test_expect_success - test_refspec () { kind=$1 refspec=$2 expect=$3 @@ -21,7 +19,7 @@ test_refspec () { title="$kind $refspec (invalid)" test='test_must_fail git ls-remote frotz' fi - $test_expect "$title" "$test" + test_expect_success "$title" "$test" } test_refspec push '' invalid @@ -51,14 +49,7 @@ test_refspec fetch 'refs/heads/*:refs/remotes/frotz/*' test_refspec fetch 'refs/heads/*:refs/remotes/frotz' invalid test_refspec fetch 'refs/heads:refs/remotes/frotz/*' invalid test_refspec fetch 'refs/heads/master:refs/remotes/frotz/xyzzy' - -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac test_refspec fetch 'refs/heads/master::refs/remotes/frotz/xyzzy' invalid -test_expect=test_expect_success - test_refspec fetch 'refs/heads/maste :refs/remotes/frotz/xyzzy' invalid test_refspec push 'master~1:refs/remotes/frotz/backup' @@ -81,16 +72,4 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid -test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid -test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid - -test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid -test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid - -test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid -test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid - -test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' -test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' - test_done diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 528b9f65b1..0e21632f19 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -207,11 +207,7 @@ test_expect_success 'checkout to detach HEAD with branchname^' ' fi ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'checkout to detach HEAD with :/message' ' +test_expect_success 'checkout to detach HEAD with :/message' ' git checkout -f master && git clean -f && git checkout ":/Initial" && From 20213ddd23407dc127e499cd59bc1b17989a90d1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 22 Mar 2009 04:59:20 -0400 Subject: [PATCH 544/781] remote: improve sorting of "configure for git push" list The data structure used to store this list is a string_list of sources with the destination in the util member. The current code just sorts on the source; if a single source is pushed to two different destination refs at a remote, then the order in which they are printed is non-deterministic. This patch implements a comparison using both fields. Besides being a little nicer on the eyes, giving a stable sort prevents false negatives in the test suite when comparing output. Signed-off-by: Jeff King --- builtin-remote.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/builtin-remote.c b/builtin-remote.c index 993acd6a09..9ef846f6a4 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -922,6 +922,20 @@ int add_push_to_show_info(struct string_list_item *push_item, void *cb_data) return 0; } +/* + * Sorting comparison for a string list that has push_info + * structs in its util field + */ +static int cmp_string_with_push(const void *va, const void *vb) +{ + const struct string_list_item *a = va; + const struct string_list_item *b = vb; + const struct push_info *a_push = a->util; + const struct push_info *b_push = b->util; + int cmp = strcmp(a->string, b->string); + return cmp ? cmp : strcmp(a_push->dest, b_push->dest); +} + int show_push_info_item(struct string_list_item *item, void *cb_data) { struct show_info *show_info = cb_data; @@ -1032,7 +1046,8 @@ static int show(int argc, const char **argv) info.width = info.width2 = 0; for_each_string_list(add_push_to_show_info, &states.push, &info); - sort_string_list(info.list); + qsort(info.list->items, info.list->nr, + sizeof(*info.list->items), cmp_string_with_push); if (info.list->nr) printf(" Local ref%s configured for 'git push'%s:\n", info.list->nr > 1 ? "s" : "", From bb6fe4e69c90fd9466412be55996e727f3e40cfa Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 25 Mar 2009 09:30:47 +0100 Subject: [PATCH 545/781] Redo part of the undone change in t5511 A bit too much was undone in d4eb98ce. Signed-off-by: Johannes Sixt --- t/t5511-refspec.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index 22ba380034..c28932216b 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me' test_refspec push ':refs/remotes/frotz/delete me' invalid test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid + +test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid +test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid + +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*' +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*' + test_done From d8f0692f7a0576f8fe4ca774d1227e802dd68a21 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Sep 2007 15:54:53 +0100 Subject: [PATCH 546/781] Revert bd2f73a6(Support the tools scripted in perl.) This is not needed in msysGit, since we call Perl from inside MSys, and therefore paths are handled gracefully. Incidentally, it fixes issue 46 (msysGit fails to install in paths beginning with C). This reverts bd2f73a6ba6daf6158112874414d338c7b0e528d. Signed-off-by: Johannes Schindelin --- perl/Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/perl/Makefile b/perl/Makefile index 2fefcd8bbb..e3dd1a5547 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -20,11 +20,7 @@ clean: $(RM) $(makfile).old ifdef NO_PERL_MAKEMAKER -# We exploit that /bin/sh transforms the DOS-Stype path in TEMP into -# the MSYS style pseudo-mount form. -# This colon-free from is needed because our perl scripts look at -# $(instdir_SQ) and split it at colons. -instdir_SQ = $(subst ','\'',$(shell cmd /x/d/c "set TEMP=$(prefix)/lib && sh -c 'echo \$$TEMP'")) +instdir_SQ = $(subst ','\'',$(prefix)/lib) $(makfile): ../GIT-CFLAGS Makefile echo all: private-Error.pm Git.pm > $@ echo ' mkdir -p blib/lib' >> $@ From 3fb2564c942a4fd094b47a809921cfef8270fd9f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 19 Feb 2009 20:25:13 +0100 Subject: [PATCH 547/781] gitk: remove workaround for missing msgfmt In the meantime, gitk's Makefile has learnt to detect the absence of msgfmt and use the drop-in replacement in Tcl (which was developed for msysGit, but has been adopted both by gitk and git-gui). Signed-off-by: Johannes Schindelin --- gitk-git/Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gitk-git/Makefile b/gitk-git/Makefile index 2dda57cbae..e1b6045605 100644 --- a/gitk-git/Makefile +++ b/gitk-git/Makefile @@ -19,10 +19,6 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) ## po-file creation rules XGETTEXT ?= xgettext -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') -ifneq (,$(findstring MINGW,$(uname_S))) - NO_MSGFMT=1 -endif ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else From 2843e0e055d42a9f86ab508ca4de62c48d9bbf39 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 7 Mar 2009 20:48:08 +0100 Subject: [PATCH 548/781] MinGW: the path separator to split GITPERLLIB is ';' on Win32 Signed-off-by: Johannes Schindelin --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index aae3b09411..65b10c4569 100644 --- a/Makefile +++ b/Makefile @@ -215,6 +215,7 @@ ETC_GITCONFIG = etc/gitconfig endif lib = lib # DESTDIR= +pathsep = : # default configuration for gitweb GITWEB_CONFIG = gitweb_config.perl @@ -784,6 +785,7 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) COMPAT_OBJS += compat/cygwin.o endif ifneq (,$(findstring MINGW,$(uname_S))) + pathsep = ; NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_CURL = YesPlease @@ -1223,7 +1225,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl sed -e '1{' \ -e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \ -e ' h' \ - -e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ + -e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \ -e ' H' \ -e ' x' \ -e '}' \ From a094080e8eec0bffcd17da6804ee09bc5309da6c Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Jan 2009 11:30:16 +0100 Subject: [PATCH 549/781] Do not issue the warning about the fallback of the PREFIX. It confuses gitk when it is browsing this repository on Windows. --- exec_cmd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 408e4e55e1..13e036fc37 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -28,9 +28,10 @@ const char *system_path(const char *path) !(prefix = strip_path_suffix(argv0_path, BINDIR)) && !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; - fprintf(stderr, "RUNTIME_PREFIX requested, " - "but prefix computation failed. " - "Using static fallback '%s'.\n", prefix); + /* + * RUNTIME_PREFIX requested, but prefix computation failed. + * Using static fallback. + */ } #endif From ccd3859ceb5622294f2a4b61524974a0c1ee22f7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 22 Jul 2008 13:42:58 +0200 Subject: [PATCH 550/781] Windows: Better support PAGER settings with spaces in the path On Windows, the pager was always run via a shell, which is not the case on Unix, where the shell variant was only used as a fallback. Thus, setting the pager, for example, like this: PAGER="C:/Program Files/msys/bin/less" would fail; an extra set of quotes is needed: PAGER="\"C:/Program Files/msys/bin/less\"" With this patch the former setting works as well. Signed-off-by: Johannes Sixt --- pager.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pager.c b/pager.c index 4921843577..77e9dd6ae4 100644 --- a/pager.c +++ b/pager.c @@ -9,7 +9,6 @@ static int spawned_pager; -#ifndef __MINGW32__ static void pager_preexec(void) { /* @@ -24,7 +23,6 @@ static void pager_preexec(void) setenv("LESS", "FRSX", 0); } -#endif static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; static struct child_process pager_process; @@ -68,13 +66,15 @@ void setup_pager(void) /* spawn the pager */ pager_argv[2] = pager; - pager_process.argv = pager_argv; - pager_process.in = -1; -#ifndef __MINGW32__ pager_process.preexec_cb = pager_preexec; -#endif - if (start_command(&pager_process)) - return; + pager_process.argv = &pager_argv[2]; + pager_process.in = -1; + if (start_command(&pager_process)) { + pager_process.argv = pager_argv; + pager_process.in = -1; + if (start_command(&pager_process)) + return; + } /* original process continues, but writes to the pipe */ dup2(pager_process.in, 1); From ddce70517e7486c64107f5ffd1383f0a3a2db34d Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 26 Mar 2009 21:11:50 +0100 Subject: [PATCH 551/781] Skip tests that fail due to incomplete implementations, missing tools... --- t/Makefile | 24 ++++++++++++++++++++++++ t/t4150-am.sh | 6 +----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/t/Makefile b/t/Makefile index bf816fc850..a0ed388ba5 100644 --- a/t/Makefile +++ b/t/Makefile @@ -42,3 +42,27 @@ valgrind: GIT_TEST_OPTS=--valgrind $(MAKE) .PHONY: pre-clean $(T) aggregate-results clean valgrind + +-include Makefile.local + +GIT_SKIP_TESTS := $(GIT_SKIP_TESTS_LOCAL) +# git am does not treat absolute path to mbox file correctly +GIT_SKIP_TESTS += t4150.18 +# git upload-pack does not write an error message in this case +# (reason unknown; seems to be a race condition) +GIT_SKIP_TESTS += t5530.6 +# output contains CRLF (I think) +GIT_SKIP_TESTS += t7401.14 +# output contains CRLF (I think) +GIT_SKIP_TESTS += t7508.1[68] +# cannot run fake.sendmail for some reason +GIT_SKIP_TESTS += t9001 +# there's a problem with GIT_DIR in test 12 (why only there?) +# needs fixups with $PWD instead of $(pwd) - tries to run rsh c +GIT_SKIP_TESTS += t9200 +# CGI.pm not found +GIT_SKIP_TESTS += t9500 +export GIT_SKIP_TESTS + +NO_SVN_TESTS=SkipThem +export NO_SVN_TESTS diff --git a/t/t4150-am.sh b/t/t4150-am.sh index a8aa02e936..5e65afa0c1 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -245,11 +245,7 @@ test_expect_success 'am works from file (relative path given) in subdirectory' ' test -z "$(git diff second)" ' -case $(uname -s) in -*MINGW*) test_expect=test_expect_failure;; -*) test_expect=test_expect_success;; -esac -$test_expect 'am works from file (absolute path given) in subdirectory' ' +test_expect_success 'am works from file (absolute path given) in subdirectory' ' rm -fr subdir && git checkout first && P=$(pwd) && From 4eb0463971e7a806ac8b7cf4c6cfede2b7f4fff8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 13:42:51 +0100 Subject: [PATCH 552/781] Make report() from usage.c public as vreport(). We will use it for customized error reporting routines. --- git-compat-util.h | 1 + usage.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index f09f244061..d94c683e0c 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -150,6 +150,7 @@ #endif /* General helper functions */ +extern void vreport(const char *prefix, const char *err, va_list params); extern void usage(const char *err) NORETURN; extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); diff --git a/usage.c b/usage.c index 820d09f92b..349f3fb350 100644 --- a/usage.c +++ b/usage.c @@ -5,7 +5,7 @@ */ #include "git-compat-util.h" -static void report(const char *prefix, const char *err, va_list params) +void vreport(const char *prefix, const char *err, va_list params) { char msg[1024]; vsnprintf(msg, sizeof(msg), err, params); @@ -20,18 +20,18 @@ static NORETURN void usage_builtin(const char *err) static NORETURN void die_builtin(const char *err, va_list params) { - report("fatal: ", err, params); + vreport("fatal: ", err, params); exit(128); } static void error_builtin(const char *err, va_list params) { - report("error: ", err, params); + vreport("error: ", err, params); } static void warn_builtin(const char *warn, va_list params) { - report("warning: ", warn, params); + vreport("warning: ", warn, params); } /* If we are in a dlopen()ed .so write to a global variable would segfault From 85763c86da5f0826a879f37056f2de033cb5ca12 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 16 Nov 2007 13:46:37 +0100 Subject: [PATCH 553/781] Implement thread-specific die() routines; use one in start_async(). --- run-command.c | 16 ++++++++++++++++ t/Makefile | 3 --- usage.c | 32 +++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/run-command.c b/run-command.c index b05c734d05..09725b983f 100644 --- a/run-command.c +++ b/run-command.c @@ -293,9 +293,22 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const } #ifdef __MINGW32__ +static int close_fd = -1; +NORETURN void die_from_thread(const char *err, va_list params) +{ + vreport("fatal: ", err, params); + if (close_fd >= 0) + close(close_fd); + _endthreadex(128); + exit(128); /* silence compiler */ +} + static __stdcall unsigned run_thread(void *data) { struct async *async = data; + close_fd = async->fd_for_proc; + extern NORETURN void die_from_thread(const char *err, va_list params); + set_die_routine(die_from_thread); return async->proc(async->fd_for_proc, async->data); } #endif @@ -349,6 +362,9 @@ int finish_async(struct async *async) else if (!GetExitCodeThread(async->tid, &ret)) ret = error("cannot get thread exit code: %lu", GetLastError()); CloseHandle(async->tid); + if (ret) + /* test suite tests for this string */ + error("waitpid (async) failed"); #endif return ret; } diff --git a/t/Makefile b/t/Makefile index a0ed388ba5..9af58b9bc6 100644 --- a/t/Makefile +++ b/t/Makefile @@ -48,9 +48,6 @@ valgrind: GIT_SKIP_TESTS := $(GIT_SKIP_TESTS_LOCAL) # git am does not treat absolute path to mbox file correctly GIT_SKIP_TESTS += t4150.18 -# git upload-pack does not write an error message in this case -# (reason unknown; seems to be a race condition) -GIT_SKIP_TESTS += t5530.6 # output contains CRLF (I think) GIT_SKIP_TESTS += t7401.14 # output contains CRLF (I think) diff --git a/usage.c b/usage.c index 349f3fb350..9e35e8a390 100644 --- a/usage.c +++ b/usage.c @@ -34,16 +34,38 @@ static void warn_builtin(const char *warn, va_list params) vreport("warning: ", warn, params); } +typedef void (*die_fn_t)(const char *err, va_list params) NORETURN; + +static DWORD tls_index; + +static void tls_init(void) __attribute__((constructor)); +static void tls_init(void) +{ + tls_index = TlsAlloc(); +} + +struct routines { + die_fn_t die_routine; +}; /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static void (*usage_routine)(const char *err) NORETURN = usage_builtin; -static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; static void (*warn_routine)(const char *err, va_list params) = warn_builtin; void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN) { - die_routine = routine; + struct routines *r = TlsGetValue(tls_index); + if (r == NULL) { + /* avoid die()! */ + r = calloc(sizeof(*r), 1); + if (r == NULL) { + fprintf(stderr, "cannot allocate thread-local storage"); + return; + } + TlsSetValue(tls_index, r); + } + r->die_routine = routine; } void usage(const char *err) @@ -54,9 +76,13 @@ void usage(const char *err) void die(const char *err, ...) { va_list params; + struct routines *r = TlsGetValue(tls_index); va_start(params, err); - die_routine(err, params); + if (r == NULL || r->die_routine == NULL) + die_builtin(err, params); + else + r->die_routine(err, params); va_end(params); } From f80f1db8b51e34741aa54eec93d1ce7b26655e78 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sun, 16 Mar 2008 21:47:53 +0100 Subject: [PATCH 554/781] Need diff -u -b in t7401 because some lines end in CRLF. --- t/t7401-submodule-summary.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index d2d6d5be25..50030c1a49 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -14,6 +14,8 @@ esac . ./test-lib.sh +export GIT_TEST_CMP='diff -u -b' # some lines end in CRLF + add_file () { sm=$1 shift From fc7fe85cbcae92e5bfc68eb6d17b4857b704c1f7 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 7 Nov 2007 11:19:00 +0100 Subject: [PATCH 555/781] gitk: Swap positions of 'next' and 'prev' buttons in the 'Find' section. The button order 'prev' left of 'next' feels more natural than the other way round, in particular, compared to the order of the forward and backward arrows that are in the line above. Signed-off-by: Johannes Sixt --- gitk-git/gitk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index a2c589f749..f43ca48dff 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2057,7 +2057,7 @@ proc makewindow {} { button .tf.lbar.fnext -text [mc "next"] -command {dofind 1 1} button .tf.lbar.fprev -text [mc "prev"] -command {dofind -1 1} label .tf.lbar.flab2 -text " [mc "commit"] " - pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \ + pack .tf.lbar.flabel .tf.lbar.fprev .tf.lbar.fnext .tf.lbar.flab2 \ -side left -fill y set gdttype [mc "containing:"] set gm [tk_optionMenu .tf.lbar.gdttype gdttype \ From 50f37d18b6c7c84ed81938226ca1bfbc00628fb8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 22 Jan 2009 11:26:41 +0100 Subject: [PATCH 556/781] Implement test-stat the prints the modification time. Compile with gcc -o test-stat -Wall test-stat.c -DEMULATE or gcc -o test-stat -Wall test-stat.c --- test-stat.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 test-stat.c diff --git a/test-stat.c b/test-stat.c new file mode 100644 index 0000000000..ff859412f0 --- /dev/null +++ b/test-stat.c @@ -0,0 +1,170 @@ +#include +#include +#include + +#ifdef EMULATE +#define HINT fprintf(stderr, "emulated stat\n") +#include +#include +#include + +/* Use mingw_lstat() instead of lstat()/stat() and + * mingw_fstat() instead of fstat() on Windows. + */ +int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_fstat(int fd, struct stat *buf); +#define fstat mingw_fstat +#define lstat mingw_lstat +#define stat(x,y) mingw_lstat(x,y) + +#define PATH_MAX 260 + +static inline int file_attr_to_st_mode (DWORD attr) +{ + int fMode = S_IREAD; + if (attr & FILE_ATTRIBUTE_DIRECTORY) + fMode |= S_IFDIR; + else + fMode |= S_IFREG; + if (!(attr & FILE_ATTRIBUTE_READONLY)) + fMode |= S_IWRITE; + return fMode; +} + +static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) +{ + if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) + return 0; + + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_SHARING_BUFFER_EXCEEDED: + return EACCES; + case ERROR_BUFFER_OVERFLOW: + return ENAMETOOLONG; + case ERROR_NOT_ENOUGH_MEMORY: + return ENOMEM; + default: + return ENOENT; + } +} + +static inline time_t filetime_to_time_t(const FILETIME *ft) +{ + long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; + winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ + winTime /= 10000000; /* Nano to seconds resolution */ + return (time_t)winTime; +} + +/* We keep the do_lstat code in a separate function to avoid recursion. + * When a path ends with a slash, the stat will fail with ENOENT. In + * this case, we strip the trailing slashes and stat again. + */ +static int do_lstat(const char *file_name, struct stat *buf) +{ + WIN32_FILE_ATTRIBUTE_DATA fdata; + + if (!(errno = get_file_attr(file_name, &fdata))) { + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = 0; /* not used by Git */ + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + return 0; + } + return -1; +} + +/* We provide our own lstat/fstat functions, since the provided + * lstat/fstat functions are so slow. These stat functions are + * tailored for Git's usage (read: fast), and are not meant to be + * complete. Note that Git stat()s are redirected to mingw_lstat() + * too, since Windows doesn't really handle symlinks that well. + */ +int mingw_lstat(const char *file_name, struct stat *buf) +{ + int namelen; + static char alt_name[PATH_MAX]; + + if (!do_lstat(file_name, buf)) + return 0; + + /* if file_name ended in a '/', Windows returned ENOENT; + * try again without trailing slashes + */ + if (errno != ENOENT) + return -1; + + namelen = strlen(file_name); + if (namelen && file_name[namelen-1] != '/') + return -1; + while (namelen && file_name[namelen-1] == '/') + --namelen; + if (!namelen || namelen >= PATH_MAX) + return -1; + + memcpy(alt_name, file_name, namelen); + alt_name[namelen] = 0; + return do_lstat(alt_name, buf); +} + +#undef fstat +int mingw_fstat(int fd, struct stat *buf) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + BY_HANDLE_FILE_INFORMATION fdata; + + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + /* direct non-file handles to MS's fstat() */ + if (GetFileType(fh) != FILE_TYPE_DISK) + return fstat(fd, buf); + + if (GetFileInformationByHandle(fh, &fdata)) { + buf->st_ino = 0; + buf->st_gid = 0; + buf->st_uid = 0; + buf->st_nlink = 1; + buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); + buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ + buf->st_dev = buf->st_rdev = 0; /* not used by Git */ + buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); + buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); + buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + return 0; + } + errno = EBADF; + return -1; +} + +#else +#define HINT (void)0 +#endif + +int main(int argc, char**argv) +{ + int i; + int err = 0; + HINT; + for (i = 1; i < argc; i++) + { + struct stat st; + if (stat(argv[i], &st)) { + perror(argv[i]); + err = 1; + continue; + } + printf("%s: %s\n", argv[i], ctime(&st.st_mtime)); + } + return err; +} From abd1fa1a1b8fa85962aa38dbb9465e68b09d1299 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 31 Mar 2009 15:09:06 +0200 Subject: [PATCH 557/781] test-suite: Log everything to a file in non-verbose mode Using 'return' from a test snippet is now a no-go because it would skip the assignment of the resulting exit code and it would also skip set +x. Signed-off-by: Johannes Sixt --- t/.gitignore | 1 + t/Makefile | 2 +- t/t0040-parse-options.sh | 3 + t/t1503-rev-parse-verify.sh | 1 + t/t5505-remote.sh | 1 + t/t6022-merge-rename.sh | 177 +++++++------------------------- t/t6034-merge-rename-nocruft.sh | 65 +++--------- t/t9300-fast-import.sh | 16 +-- t/test-lib.sh | 15 ++- 9 files changed, 68 insertions(+), 213 deletions(-) diff --git a/t/.gitignore b/t/.gitignore index 7dcbb232cd..dbe58eb9b3 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,2 +1,3 @@ /trash directory* /test-results +/test-log diff --git a/t/Makefile b/t/Makefile index 9af58b9bc6..6eefc08fea 100644 --- a/t/Makefile +++ b/t/Makefile @@ -21,7 +21,7 @@ $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) pre-clean: - $(RM) -r test-results + $(RM) -r test-results test-log clean: $(RM) -r 'trash directory'.* test-results diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index e38241c80a..da272e0124 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -39,6 +39,7 @@ Standard options EOF test_expect_success 'test help' ' + set +x && test_must_fail test-parse-options -h > output 2> output.err && test ! -s output && test_cmp expect.err output.err @@ -158,6 +159,7 @@ error: did you mean \`--boolean\` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' + set +x && test_must_fail test-parse-options -boolean > output 2> output.err && test ! -s output && test_cmp typo.err output.err @@ -223,6 +225,7 @@ Callback: "not set", 1 EOF test_expect_success 'OPT_CALLBACK() and callback errors work' ' + set +x && test_must_fail test-parse-options --no-length > output 2> output.err && test_cmp expect output && test_cmp expect.err output.err diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index cc65394947..4c677340f4 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -71,6 +71,7 @@ test_expect_success 'fails with any bad rev or many good revs' ' ' test_expect_success 'fails silently when using -q' ' + set +x && test_must_fail git rev-parse --verify --quiet 2>error && test -z "$(cat error)" && test_must_fail git rev-parse -q --verify foo 2>error && diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 5ec668d6d8..7267b1ae70 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -247,6 +247,7 @@ EOF test_expect_success 'set-head --auto fails w/multiple HEADs' ' (cd test && + set +x && test_must_fail git remote set-head --auto two >output 2>&1 && test_cmp expect output) ' diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index e3f7ae8120..d69a364cae 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -95,30 +95,15 @@ git checkout master' test_expect_success 'pull renaming branch into unrenaming one' \ ' git show-branch - git pull . white && { - echo "BAD: should have conflicted" - return 1 - } - git ls-files -s - test "$(git ls-files -u B | wc -l)" -eq 3 || { - echo "BAD: should have left stages for B" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . white && + git ls-files -s && + test "$(git ls-files -u B | wc -l)" -eq 3 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep master || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep master && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'pull renaming branch into another renaming one' \ @@ -126,95 +111,44 @@ test_expect_success 'pull renaming branch into another renaming one' \ rm -f B git reset --hard git checkout red - git pull . white && { - echo "BAD: should have conflicted" - return 1 - } - test "$(git ls-files -u B | wc -l)" -eq 3 || { - echo "BAD: should have left stages" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . white && + test "$(git ls-files -u B | wc -l)" -eq 3 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep red || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep red && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'pull unrenaming branch into renaming one' \ ' git reset --hard git show-branch - git pull . master && { - echo "BAD: should have conflicted" - return 1 - } - test "$(git ls-files -u B | wc -l)" -eq 3 || { - echo "BAD: should have left stages" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . master && + test "$(git ls-files -u B | wc -l)" -eq 3 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep red || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep red && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'pull conflicting renames' \ ' git reset --hard git show-branch - git pull . blue && { - echo "BAD: should have conflicted" - return 1 - } - test "$(git ls-files -u A | wc -l)" -eq 1 || { - echo "BAD: should have left a stage" - return 1 - } - test "$(git ls-files -u B | wc -l)" -eq 1 || { - echo "BAD: should have left a stage" - return 1 - } - test "$(git ls-files -u C | wc -l)" -eq 1 || { - echo "BAD: should have left a stage" - return 1 - } - test "$(git ls-files -s N | wc -l)" -eq 1 || { - echo "BAD: should have merged N" - return 1 - } + test_must_fail git pull . blue && + test "$(git ls-files -u A | wc -l)" -eq 1 && + test "$(git ls-files -u B | wc -l)" -eq 1 && + test "$(git ls-files -u C | wc -l)" -eq 1 && + test "$(git ls-files -s N | wc -l)" -eq 1 && sed -ne "/^g/{ p q - }" B | grep red || { - echo "BAD: should have listed our change first" - return 1 - } - test "$(git diff white N | wc -l)" -eq 0 || { - echo "BAD: should have taken colored branch" - return 1 - } + }" B | grep red && + test "$(git diff white N | wc -l)" -eq 0 ' test_expect_success 'interference with untracked working tree file' ' @@ -222,14 +156,8 @@ test_expect_success 'interference with untracked working tree file' ' git reset --hard git show-branch echo >A this file should not matter - git pull . white && { - echo "BAD: should have conflicted" - return 1 - } - test -f A || { - echo "BAD: should have left A intact" - return 1 - } + test_must_fail git pull . white && + test -f A ' test_expect_success 'interference with untracked working tree file' ' @@ -239,14 +167,8 @@ test_expect_success 'interference with untracked working tree file' ' git show-branch rm -f A echo >A this file should not matter - git pull . red && { - echo "BAD: should have conflicted" - return 1 - } - test -f A || { - echo "BAD: should have left A intact" - return 1 - } + test_must_fail git pull . red && + test -f A ' test_expect_success 'interference with untracked working tree file' ' @@ -256,14 +178,8 @@ test_expect_success 'interference with untracked working tree file' ' git checkout -f master git tag -f anchor git show-branch - git pull . yellow || { - echo "BAD: should have cleanly merged" - return 1 - } - test -f M && { - echo "BAD: should have removed M" - return 1 - } + git pull . yellow + test ! -f M && git reset --hard anchor ' @@ -276,14 +192,8 @@ test_expect_success 'updated working tree file should prevent the merge' ' git show-branch echo >>M one line addition cat M >M.saved - git pull . yellow && { - echo "BAD: should have complained" - return 1 - } - diff M M.saved || { - echo "BAD: should have left M intact" - return 1 - } + test_must_fail git pull . yellow && + diff M M.saved && rm -f M.saved ' @@ -297,14 +207,8 @@ test_expect_success 'updated working tree file should prevent the merge' ' echo >>M one line addition cat M >M.saved git update-index M - git pull . yellow && { - echo "BAD: should have complained" - return 1 - } - diff M M.saved || { - echo "BAD: should have left M intact" - return 1 - } + test_must_fail git pull . yellow && + diff M M.saved && rm -f M.saved ' @@ -316,18 +220,9 @@ test_expect_success 'interference with untracked working tree file' ' git tag -f anchor git show-branch echo >M this file should not matter - git pull . master || { - echo "BAD: should have cleanly merged" - return 1 - } - test -f M || { - echo "BAD: should have left M intact" - return 1 - } - git ls-files -s | grep M && { - echo "BAD: M must be untracked in the result" - return 1 - } + git pull . master && + test -f M && + ! (git ls-files -s | grep M) && git reset --hard anchor ' diff --git a/t/t6034-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh index 65be95fbaa..d1b1d1a441 100755 --- a/t/t6034-merge-rename-nocruft.sh +++ b/t/t6034-merge-rename-nocruft.sh @@ -73,33 +73,12 @@ test_expect_success 'merge white into red (A->B,M->N)' \ ' git checkout -b red-white red && git merge white && - git write-tree >/dev/null || { - echo "BAD: merge did not complete" - return 1 - } - - test -f B || { - echo "BAD: B does not exist in working directory" - return 1 - } - test -f N || { - echo "BAD: N does not exist in working directory" - return 1 - } - test -f R || { - echo "BAD: R does not exist in working directory" - return 1 - } - - test -f A && { - echo "BAD: A still exists in working directory" - return 1 - } - test -f M && { - echo "BAD: M still exists in working directory" - return 1 - } - return 0 + git write-tree >/dev/null && + test -f B && + test -f N && + test -f R && + ! test -f A && + ! test -f M ' # This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9 @@ -108,32 +87,12 @@ test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \ git checkout -b white-blue white && echo dirty >A && git merge blue && - git write-tree >/dev/null || { - echo "BAD: merge did not complete" - return 1 - } - - test -f A || { - echo "BAD: A does not exist in working directory" - return 1 - } - test `cat A` = dirty || { - echo "BAD: A content is wrong" - return 1 - } - test -f B || { - echo "BAD: B does not exist in working directory" - return 1 - } - test -f N || { - echo "BAD: N does not exist in working directory" - return 1 - } - test -f M && { - echo "BAD: M still exists in working directory" - return 1 - } - return 0 + git write-tree >/dev/null && + test -f A && + test `cat A` = dirty && + test -f B && + test -f N && + ! test -f M ' test_done diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 821be7ce8d..a7a13b7e57 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -399,20 +399,8 @@ from refs/heads/branch INPUT_END test_expect_success \ 'F: non-fast-forward update skips' \ - 'if git fast-import &1 if test "$verbose" = "t" then + set_x= set_nox= exec 4>&2 3>&1 else - exec 4>/dev/null 3>/dev/null + test_log_dir="$TEST_DIRECTORY/test-log" + mkdir -p "$test_log_dir" + test_log_path="$test_log_dir/${0%.sh}-$$" + set_x='set -x;' + set_nox='set +x' + exec 3>"$test_log_path" 4>&3 fi test_failure=0 @@ -303,8 +310,9 @@ test_debug () { } test_run_ () { - eval >&3 2>&4 "$1" - eval_ret="$?" + eval >&3 2>&4 $set_x "$1" ' + eval_ret=$? + $set_nox' return 0 } @@ -540,7 +548,6 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. -TEST_DIRECTORY=$(pwd) if test -z "$valgrind" then if test -z "$GIT_TEST_INSTALLED" From 1e52e22d9e874e135f0f724ef87d952afdfc5316 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 3 Apr 2009 08:49:59 +0200 Subject: [PATCH 558/781] Windows: Work around intermittent failures in mingw_rename We have replaced rename() with a version that can rename a file to a destination that already exists. Nevertheless, many users, the author included, observe failures in the code that are not reproducible. The theory is that the failures are due to some other process that happens to have opened the destination file briefly at the wrong moment. (And there is no way on Windows to delete or replace a file that is currently open.) One such process could be Windows Explorer that is updating its directory listing because it detected a change in the .git directory or a virus scanner. The failure is more often observed while there is heavy git activity (for example while the test suite is running or during a rebase operation). We work around the failure by retrying the rename operation if it failed due to ERROR_ACCESS_DENIED. The retries are delayed a bit: The first only by giving up the time slice, the next after the minimal scheduling granularity, and if more retries are needed, then we wait some non-trivial amount of time with exponential back-off. Signed-off-by: Johannes Sixt --- compat/mingw.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 2839d9df6e..9f647e15cc 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -934,7 +934,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { - DWORD attrs; + DWORD attrs, gle; + int tries = 0; + static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. @@ -944,10 +946,12 @@ int mingw_rename(const char *pold, const char *pnew) return 0; if (errno != EEXIST) return -1; +repeat: if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED && + gle = GetLastError(); + if (gle == ERROR_ACCESS_DENIED && (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; @@ -957,10 +961,24 @@ int mingw_rename(const char *pold, const char *pnew) SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; + gle = GetLastError(); /* revert file attributes on failure */ SetFileAttributes(pnew, attrs); } } + if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) { + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + warning("rename retry #%d %s -> %s", tries, pold, pnew); + goto repeat; + } errno = EACCES; return -1; } From 7ee5b02494aadbe53e5a50f085ce0c81908b5781 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Sun, 5 Apr 2009 14:42:27 +0200 Subject: [PATCH 559/781] doc/merge-config: list ecmerge as a built-in merge tool Signed-off-by: Markus Heidelberg --- Documentation/merge-config.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 1ff08ff2cc..9c44af8e4a 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -22,7 +22,8 @@ merge.stat:: merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", - "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and + "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", + "ecmerge" and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool..cmd option. From 1fadfbe9b6df8f5e8733741986003f08ba9df2df Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Sun, 5 Apr 2009 14:42:57 +0200 Subject: [PATCH 560/781] git-mergetool/difftool: make (g)vimdiff workable under Windows Under Windows vimdiff and gvimdiff are not available as symbolic links, but as batch files vimdiff.bat and gvimdiff.bat. These files weren't found by 'type vimdiff' which led to the following error: The merge tool vimdiff is not available as 'vimdiff' Even if they were found, it wouldn't work to invoke these batch files from git-mergetool. To solve this, use vim and gvim (vim.exe and gvim.exe) and pass the -d command line switch over to them. Signed-off-by: Markus Heidelberg --- contrib/difftool/git-difftool-helper | 10 ++++++++-- git-mergetool.sh | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/contrib/difftool/git-difftool-helper b/contrib/difftool/git-difftool-helper index 9c0a13452a..e481913c91 100755 --- a/contrib/difftool/git-difftool-helper +++ b/contrib/difftool/git-difftool-helper @@ -86,11 +86,11 @@ launch_merge_tool () { ;; vimdiff) - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$REMOTE" ;; gvimdiff) - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$REMOTE" ;; xxdiff) @@ -160,6 +160,12 @@ init_merge_tool_path() { merge_tool_path=$(git config mergetool."$1".path) if test -z "$merge_tool_path"; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; diff --git a/git-mergetool.sh b/git-mergetool.sh index 87fa88af55..6e611e94a4 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -214,12 +214,12 @@ merge_file () { ;; vimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; gvimdiff) touch "$BACKUP" - "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" + "$merge_tool_path" -d -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE" check_unchanged ;; xxdiff) @@ -359,6 +359,12 @@ init_merge_tool_path() { merge_tool_path=`git config mergetool.$1.path` if test -z "$merge_tool_path" ; then case "$1" in + vimdiff) + merge_tool_path=vim + ;; + gvimdiff) + merge_tool_path=gvim + ;; emerge) merge_tool_path=emacs ;; From 57d87482147e062ac1024f293f513a2400825fcb Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Sun, 5 Apr 2009 14:43:27 +0200 Subject: [PATCH 561/781] git-mergetool: add new merge tool TortoiseMerge TortoiseMerge comes with TortoiseSVN or TortoiseGit for Windows. It can only be used as a merge tool with an existing base file. It cannot be used without a base nor as a diff tool. The documentation only mentions the slash '/' as command line option prefix, which refused to work, but the parser also accepts the dash '-' See http://code.google.com/p/msysgit/issues/detail?id=226 Signed-off-by: Markus Heidelberg --- Documentation/git-mergetool.txt | 3 ++- Documentation/merge-config.txt | 2 +- git-mergetool.sh | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 5d3c632872..5edac4d267 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -26,7 +26,8 @@ OPTIONS --tool=:: Use the merge resolution program specified by . Valid merge tools are: - kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff + kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, + tortoisemerge and opendiff + If a merge resolution program is not specified, 'git-mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 9c44af8e4a..8c10f66702 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -23,7 +23,7 @@ merge.tool:: Controls which merge resolution program is used by linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3", "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", - "ecmerge" and + "ecmerge", tortoisemerge and "opendiff". Any other value is treated is custom merge tool and there must be a corresponding mergetool..cmd option. diff --git a/git-mergetool.sh b/git-mergetool.sh index 6e611e94a4..be9717a2f1 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -265,6 +265,16 @@ merge_file () { fi status=$? ;; + tortoisemerge) + if base_present ; then + touch "$BACKUP" + "$merge_tool_path" -base:"$BASE" -mine:"$LOCAL" -theirs:"$REMOTE" -merged:"$MERGED" + check_unchanged + else + echo "TortoiseMerge cannot be used without a base" 1>&2 + status=1 + fi + ;; *) if test -n "$merge_tool_cmd"; then if test "$merge_tool_trust_exit_code" = "false"; then @@ -345,7 +355,7 @@ valid_custom_tool() valid_tool() { case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge) + kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge | tortoisemerge) ;; # happy *) if ! valid_custom_tool "$1"; then @@ -404,9 +414,9 @@ fi if test -z "$merge_tool" ; then if test -n "$DISPLAY"; then if test -n "$GNOME_DESKTOP_SESSION_ID" ; then - merge_tool_candidates="meld kdiff3 tkdiff xxdiff gvimdiff" + merge_tool_candidates="meld kdiff3 tkdiff xxdiff tortoisemerge gvimdiff" else - merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff" + merge_tool_candidates="kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff" fi fi if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then From 7ba615a300fe2742e8d32f0313c6ee9a1a1aaed3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 7 Apr 2009 17:40:03 +0200 Subject: [PATCH 562/781] Add a simple getpass() for MinGW This should be replaced with a graphical getpass() at some stage. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index d50186e5f5..2ab5bbec1f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1157,3 +1157,18 @@ int link(const char *oldpath, const char *newpath) } return 0; } + +char *getpass(const char *prompt) +{ + struct strbuf buf = STRBUF_INIT; + + fputs(prompt, stderr); + for (;;) { + char c = _getch(); + if (c == '\r' || c == '\n') + break; + strbuf_addch(&buf, c); + } + fputs("\n", stderr); + return strbuf_detach(&buf, NULL); +} From 064f4d6929437a215874fc3defd1f22467ee8596 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Tue, 24 Mar 2009 13:00:33 -0400 Subject: [PATCH 563/781] Enable THREADED_DELTA_SEARCH for mingw Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b71bdd2421..9e2b41c4b1 100644 --- a/Makefile +++ b/Makefile @@ -811,7 +811,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease - NO_PTHREADS = YesPlease + THREADED_DELTA_SEARCH = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease From c04dd04f0fde515b59266b00fd8726a934763b5a Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 11 Apr 2009 22:27:05 +0100 Subject: [PATCH 564/781] Mark t1301 permission test to depend on POSIXPERM Signed-off-by: Johannes Sixt --- t/t1301-shared-repo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 47a219680c..de42d21c92 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -126,7 +126,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' ' esac ' -test_expect_success 'forced modes' ' +test_expect_success POSIXPERM 'forced modes' ' mkdir -p templates/hooks && echo update-server-info >templates/hooks/post-update && chmod +x templates/hooks/post-update && From a36adafee41ad44aa35b419fe1db147964ac7128 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 13 Apr 2009 21:43:27 +0200 Subject: [PATCH 565/781] Revert accidentally merged commits This reverts the following commits: abd1fa1 test-suite: Log everything to a file in non-verbose mode 50f37d1 Implement test-stat the prints the modification time. fc7fe85 gitk: Swap positions of 'next' and 'prev' buttons in the 'Find' section. f80f1db Need diff -u -b in t7401 because some lines end in CRLF. 85763c8 Implement thread-specific die() routines; use one in start_async(). 4eb0463 Make report() from usage.c public as vreport(). ddce705 Skip tests that fail due to incomplete implementations, missing tools... a094080 Do not issue the warning about the fallback of the PREFIX. These were brought in by the merge commit dc8b641 that merged my private work-in-progress branch. Only these two commits remain: 1e52e22 Windows: Work around intermittent failures in mingw_rename ccd3859 Windows: Better support PAGER settings with spaces in the path Signed-off-by: Johannes Sixt --- exec_cmd.c | 7 +- git-compat-util.h | 1 - gitk-git/gitk | 2 +- run-command.c | 16 --- t/.gitignore | 1 - t/Makefile | 23 +---- t/t0040-parse-options.sh | 3 - t/t1503-rev-parse-verify.sh | 1 - t/t4150-am.sh | 6 +- t/t5505-remote.sh | 1 - t/t6022-merge-rename.sh | 177 +++++++++++++++++++++++++------- t/t6034-merge-rename-nocruft.sh | 65 +++++++++--- t/t7401-submodule-summary.sh | 2 - t/t9300-fast-import.sh | 16 ++- t/test-lib.sh | 15 +-- test-stat.c | 170 ------------------------------ usage.c | 40 ++------ 17 files changed, 229 insertions(+), 317 deletions(-) delete mode 100644 test-stat.c diff --git a/exec_cmd.c b/exec_cmd.c index 13e036fc37..408e4e55e1 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -28,10 +28,9 @@ const char *system_path(const char *path) !(prefix = strip_path_suffix(argv0_path, BINDIR)) && !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; - /* - * RUNTIME_PREFIX requested, but prefix computation failed. - * Using static fallback. - */ + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); } #endif diff --git a/git-compat-util.h b/git-compat-util.h index d94c683e0c..f09f244061 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -150,7 +150,6 @@ #endif /* General helper functions */ -extern void vreport(const char *prefix, const char *err, va_list params); extern void usage(const char *err) NORETURN; extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); diff --git a/gitk-git/gitk b/gitk-git/gitk index f43ca48dff..a2c589f749 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2057,7 +2057,7 @@ proc makewindow {} { button .tf.lbar.fnext -text [mc "next"] -command {dofind 1 1} button .tf.lbar.fprev -text [mc "prev"] -command {dofind -1 1} label .tf.lbar.flab2 -text " [mc "commit"] " - pack .tf.lbar.flabel .tf.lbar.fprev .tf.lbar.fnext .tf.lbar.flab2 \ + pack .tf.lbar.flabel .tf.lbar.fnext .tf.lbar.fprev .tf.lbar.flab2 \ -side left -fill y set gdttype [mc "containing:"] set gm [tk_optionMenu .tf.lbar.gdttype gdttype \ diff --git a/run-command.c b/run-command.c index 09725b983f..b05c734d05 100644 --- a/run-command.c +++ b/run-command.c @@ -293,22 +293,9 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const } #ifdef __MINGW32__ -static int close_fd = -1; -NORETURN void die_from_thread(const char *err, va_list params) -{ - vreport("fatal: ", err, params); - if (close_fd >= 0) - close(close_fd); - _endthreadex(128); - exit(128); /* silence compiler */ -} - static __stdcall unsigned run_thread(void *data) { struct async *async = data; - close_fd = async->fd_for_proc; - extern NORETURN void die_from_thread(const char *err, va_list params); - set_die_routine(die_from_thread); return async->proc(async->fd_for_proc, async->data); } #endif @@ -362,9 +349,6 @@ int finish_async(struct async *async) else if (!GetExitCodeThread(async->tid, &ret)) ret = error("cannot get thread exit code: %lu", GetLastError()); CloseHandle(async->tid); - if (ret) - /* test suite tests for this string */ - error("waitpid (async) failed"); #endif return ret; } diff --git a/t/.gitignore b/t/.gitignore index dbe58eb9b3..7dcbb232cd 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,3 +1,2 @@ /trash directory* /test-results -/test-log diff --git a/t/Makefile b/t/Makefile index 6eefc08fea..bf816fc850 100644 --- a/t/Makefile +++ b/t/Makefile @@ -21,7 +21,7 @@ $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) pre-clean: - $(RM) -r test-results test-log + $(RM) -r test-results clean: $(RM) -r 'trash directory'.* test-results @@ -42,24 +42,3 @@ valgrind: GIT_TEST_OPTS=--valgrind $(MAKE) .PHONY: pre-clean $(T) aggregate-results clean valgrind - --include Makefile.local - -GIT_SKIP_TESTS := $(GIT_SKIP_TESTS_LOCAL) -# git am does not treat absolute path to mbox file correctly -GIT_SKIP_TESTS += t4150.18 -# output contains CRLF (I think) -GIT_SKIP_TESTS += t7401.14 -# output contains CRLF (I think) -GIT_SKIP_TESTS += t7508.1[68] -# cannot run fake.sendmail for some reason -GIT_SKIP_TESTS += t9001 -# there's a problem with GIT_DIR in test 12 (why only there?) -# needs fixups with $PWD instead of $(pwd) - tries to run rsh c -GIT_SKIP_TESTS += t9200 -# CGI.pm not found -GIT_SKIP_TESTS += t9500 -export GIT_SKIP_TESTS - -NO_SVN_TESTS=SkipThem -export NO_SVN_TESTS diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index da272e0124..e38241c80a 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -39,7 +39,6 @@ Standard options EOF test_expect_success 'test help' ' - set +x && test_must_fail test-parse-options -h > output 2> output.err && test ! -s output && test_cmp expect.err output.err @@ -159,7 +158,6 @@ error: did you mean \`--boolean\` (with two dashes ?) EOF test_expect_success 'detect possible typos' ' - set +x && test_must_fail test-parse-options -boolean > output 2> output.err && test ! -s output && test_cmp typo.err output.err @@ -225,7 +223,6 @@ Callback: "not set", 1 EOF test_expect_success 'OPT_CALLBACK() and callback errors work' ' - set +x && test_must_fail test-parse-options --no-length > output 2> output.err && test_cmp expect output && test_cmp expect.err output.err diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index 4c677340f4..cc65394947 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -71,7 +71,6 @@ test_expect_success 'fails with any bad rev or many good revs' ' ' test_expect_success 'fails silently when using -q' ' - set +x && test_must_fail git rev-parse --verify --quiet 2>error && test -z "$(cat error)" && test_must_fail git rev-parse -q --verify foo 2>error && diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 5e65afa0c1..a8aa02e936 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -245,7 +245,11 @@ test_expect_success 'am works from file (relative path given) in subdirectory' ' test -z "$(git diff second)" ' -test_expect_success 'am works from file (absolute path given) in subdirectory' ' +case $(uname -s) in +*MINGW*) test_expect=test_expect_failure;; +*) test_expect=test_expect_success;; +esac +$test_expect 'am works from file (absolute path given) in subdirectory' ' rm -fr subdir && git checkout first && P=$(pwd) && diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 7267b1ae70..5ec668d6d8 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -247,7 +247,6 @@ EOF test_expect_success 'set-head --auto fails w/multiple HEADs' ' (cd test && - set +x && test_must_fail git remote set-head --auto two >output 2>&1 && test_cmp expect output) ' diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index d69a364cae..e3f7ae8120 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -95,15 +95,30 @@ git checkout master' test_expect_success 'pull renaming branch into unrenaming one' \ ' git show-branch - test_must_fail git pull . white && - git ls-files -s && - test "$(git ls-files -u B | wc -l)" -eq 3 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . white && { + echo "BAD: should have conflicted" + return 1 + } + git ls-files -s + test "$(git ls-files -u B | wc -l)" -eq 3 || { + echo "BAD: should have left stages for B" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep master && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep master || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'pull renaming branch into another renaming one' \ @@ -111,44 +126,95 @@ test_expect_success 'pull renaming branch into another renaming one' \ rm -f B git reset --hard git checkout red - test_must_fail git pull . white && - test "$(git ls-files -u B | wc -l)" -eq 3 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . white && { + echo "BAD: should have conflicted" + return 1 + } + test "$(git ls-files -u B | wc -l)" -eq 3 || { + echo "BAD: should have left stages" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep red && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep red || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'pull unrenaming branch into renaming one' \ ' git reset --hard git show-branch - test_must_fail git pull . master && - test "$(git ls-files -u B | wc -l)" -eq 3 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . master && { + echo "BAD: should have conflicted" + return 1 + } + test "$(git ls-files -u B | wc -l)" -eq 3 || { + echo "BAD: should have left stages" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep red && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep red || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'pull conflicting renames' \ ' git reset --hard git show-branch - test_must_fail git pull . blue && - test "$(git ls-files -u A | wc -l)" -eq 1 && - test "$(git ls-files -u B | wc -l)" -eq 1 && - test "$(git ls-files -u C | wc -l)" -eq 1 && - test "$(git ls-files -s N | wc -l)" -eq 1 && + git pull . blue && { + echo "BAD: should have conflicted" + return 1 + } + test "$(git ls-files -u A | wc -l)" -eq 1 || { + echo "BAD: should have left a stage" + return 1 + } + test "$(git ls-files -u B | wc -l)" -eq 1 || { + echo "BAD: should have left a stage" + return 1 + } + test "$(git ls-files -u C | wc -l)" -eq 1 || { + echo "BAD: should have left a stage" + return 1 + } + test "$(git ls-files -s N | wc -l)" -eq 1 || { + echo "BAD: should have merged N" + return 1 + } sed -ne "/^g/{ p q - }" B | grep red && - test "$(git diff white N | wc -l)" -eq 0 + }" B | grep red || { + echo "BAD: should have listed our change first" + return 1 + } + test "$(git diff white N | wc -l)" -eq 0 || { + echo "BAD: should have taken colored branch" + return 1 + } ' test_expect_success 'interference with untracked working tree file' ' @@ -156,8 +222,14 @@ test_expect_success 'interference with untracked working tree file' ' git reset --hard git show-branch echo >A this file should not matter - test_must_fail git pull . white && - test -f A + git pull . white && { + echo "BAD: should have conflicted" + return 1 + } + test -f A || { + echo "BAD: should have left A intact" + return 1 + } ' test_expect_success 'interference with untracked working tree file' ' @@ -167,8 +239,14 @@ test_expect_success 'interference with untracked working tree file' ' git show-branch rm -f A echo >A this file should not matter - test_must_fail git pull . red && - test -f A + git pull . red && { + echo "BAD: should have conflicted" + return 1 + } + test -f A || { + echo "BAD: should have left A intact" + return 1 + } ' test_expect_success 'interference with untracked working tree file' ' @@ -178,8 +256,14 @@ test_expect_success 'interference with untracked working tree file' ' git checkout -f master git tag -f anchor git show-branch - git pull . yellow - test ! -f M && + git pull . yellow || { + echo "BAD: should have cleanly merged" + return 1 + } + test -f M && { + echo "BAD: should have removed M" + return 1 + } git reset --hard anchor ' @@ -192,8 +276,14 @@ test_expect_success 'updated working tree file should prevent the merge' ' git show-branch echo >>M one line addition cat M >M.saved - test_must_fail git pull . yellow && - diff M M.saved && + git pull . yellow && { + echo "BAD: should have complained" + return 1 + } + diff M M.saved || { + echo "BAD: should have left M intact" + return 1 + } rm -f M.saved ' @@ -207,8 +297,14 @@ test_expect_success 'updated working tree file should prevent the merge' ' echo >>M one line addition cat M >M.saved git update-index M - test_must_fail git pull . yellow && - diff M M.saved && + git pull . yellow && { + echo "BAD: should have complained" + return 1 + } + diff M M.saved || { + echo "BAD: should have left M intact" + return 1 + } rm -f M.saved ' @@ -220,9 +316,18 @@ test_expect_success 'interference with untracked working tree file' ' git tag -f anchor git show-branch echo >M this file should not matter - git pull . master && - test -f M && - ! (git ls-files -s | grep M) && + git pull . master || { + echo "BAD: should have cleanly merged" + return 1 + } + test -f M || { + echo "BAD: should have left M intact" + return 1 + } + git ls-files -s | grep M && { + echo "BAD: M must be untracked in the result" + return 1 + } git reset --hard anchor ' diff --git a/t/t6034-merge-rename-nocruft.sh b/t/t6034-merge-rename-nocruft.sh index d1b1d1a441..65be95fbaa 100755 --- a/t/t6034-merge-rename-nocruft.sh +++ b/t/t6034-merge-rename-nocruft.sh @@ -73,12 +73,33 @@ test_expect_success 'merge white into red (A->B,M->N)' \ ' git checkout -b red-white red && git merge white && - git write-tree >/dev/null && - test -f B && - test -f N && - test -f R && - ! test -f A && - ! test -f M + git write-tree >/dev/null || { + echo "BAD: merge did not complete" + return 1 + } + + test -f B || { + echo "BAD: B does not exist in working directory" + return 1 + } + test -f N || { + echo "BAD: N does not exist in working directory" + return 1 + } + test -f R || { + echo "BAD: R does not exist in working directory" + return 1 + } + + test -f A && { + echo "BAD: A still exists in working directory" + return 1 + } + test -f M && { + echo "BAD: M still exists in working directory" + return 1 + } + return 0 ' # This test broke in 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9 @@ -87,12 +108,32 @@ test_expect_success 'merge blue into white (A->B, mod A, A untracked)' \ git checkout -b white-blue white && echo dirty >A && git merge blue && - git write-tree >/dev/null && - test -f A && - test `cat A` = dirty && - test -f B && - test -f N && - ! test -f M + git write-tree >/dev/null || { + echo "BAD: merge did not complete" + return 1 + } + + test -f A || { + echo "BAD: A does not exist in working directory" + return 1 + } + test `cat A` = dirty || { + echo "BAD: A content is wrong" + return 1 + } + test -f B || { + echo "BAD: B does not exist in working directory" + return 1 + } + test -f N || { + echo "BAD: N does not exist in working directory" + return 1 + } + test -f M && { + echo "BAD: M still exists in working directory" + return 1 + } + return 0 ' test_done diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 50030c1a49..d2d6d5be25 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -14,8 +14,6 @@ esac . ./test-lib.sh -export GIT_TEST_CMP='diff -u -b' # some lines end in CRLF - add_file () { sm=$1 shift diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index a7a13b7e57..821be7ce8d 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -399,8 +399,20 @@ from refs/heads/branch INPUT_END test_expect_success \ 'F: non-fast-forward update skips' \ - 'test_must_fail git fast-import &1 if test "$verbose" = "t" then - set_x= set_nox= exec 4>&2 3>&1 else - test_log_dir="$TEST_DIRECTORY/test-log" - mkdir -p "$test_log_dir" - test_log_path="$test_log_dir/${0%.sh}-$$" - set_x='set -x;' - set_nox='set +x' - exec 3>"$test_log_path" 4>&3 + exec 4>/dev/null 3>/dev/null fi test_failure=0 @@ -310,9 +303,8 @@ test_debug () { } test_run_ () { - eval >&3 2>&4 $set_x "$1" ' - eval_ret=$? - $set_nox' + eval >&3 2>&4 "$1" + eval_ret="$?" return 0 } @@ -548,6 +540,7 @@ test_done () { # Test the binaries we have just built. The tests are kept in # t/ subdirectory and are run in 'trash directory' subdirectory. +TEST_DIRECTORY=$(pwd) if test -z "$valgrind" then if test -z "$GIT_TEST_INSTALLED" diff --git a/test-stat.c b/test-stat.c deleted file mode 100644 index ff859412f0..0000000000 --- a/test-stat.c +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include -#include - -#ifdef EMULATE -#define HINT fprintf(stderr, "emulated stat\n") -#include -#include -#include - -/* Use mingw_lstat() instead of lstat()/stat() and - * mingw_fstat() instead of fstat() on Windows. - */ -int mingw_lstat(const char *file_name, struct stat *buf); -int mingw_fstat(int fd, struct stat *buf); -#define fstat mingw_fstat -#define lstat mingw_lstat -#define stat(x,y) mingw_lstat(x,y) - -#define PATH_MAX 260 - -static inline int file_attr_to_st_mode (DWORD attr) -{ - int fMode = S_IREAD; - if (attr & FILE_ATTRIBUTE_DIRECTORY) - fMode |= S_IFDIR; - else - fMode |= S_IFREG; - if (!(attr & FILE_ATTRIBUTE_READONLY)) - fMode |= S_IWRITE; - return fMode; -} - -static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) -{ - if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) - return 0; - - switch (GetLastError()) { - case ERROR_ACCESS_DENIED: - case ERROR_SHARING_VIOLATION: - case ERROR_LOCK_VIOLATION: - case ERROR_SHARING_BUFFER_EXCEEDED: - return EACCES; - case ERROR_BUFFER_OVERFLOW: - return ENAMETOOLONG; - case ERROR_NOT_ENOUGH_MEMORY: - return ENOMEM; - default: - return ENOENT; - } -} - -static inline time_t filetime_to_time_t(const FILETIME *ft) -{ - long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; - winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ - winTime /= 10000000; /* Nano to seconds resolution */ - return (time_t)winTime; -} - -/* We keep the do_lstat code in a separate function to avoid recursion. - * When a path ends with a slash, the stat will fail with ENOENT. In - * this case, we strip the trailing slashes and stat again. - */ -static int do_lstat(const char *file_name, struct stat *buf) -{ - WIN32_FILE_ATTRIBUTE_DATA fdata; - - if (!(errno = get_file_attr(file_name, &fdata))) { - buf->st_ino = 0; - buf->st_gid = 0; - buf->st_uid = 0; - buf->st_nlink = 1; - buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = 0; /* not used by Git */ - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); - return 0; - } - return -1; -} - -/* We provide our own lstat/fstat functions, since the provided - * lstat/fstat functions are so slow. These stat functions are - * tailored for Git's usage (read: fast), and are not meant to be - * complete. Note that Git stat()s are redirected to mingw_lstat() - * too, since Windows doesn't really handle symlinks that well. - */ -int mingw_lstat(const char *file_name, struct stat *buf) -{ - int namelen; - static char alt_name[PATH_MAX]; - - if (!do_lstat(file_name, buf)) - return 0; - - /* if file_name ended in a '/', Windows returned ENOENT; - * try again without trailing slashes - */ - if (errno != ENOENT) - return -1; - - namelen = strlen(file_name); - if (namelen && file_name[namelen-1] != '/') - return -1; - while (namelen && file_name[namelen-1] == '/') - --namelen; - if (!namelen || namelen >= PATH_MAX) - return -1; - - memcpy(alt_name, file_name, namelen); - alt_name[namelen] = 0; - return do_lstat(alt_name, buf); -} - -#undef fstat -int mingw_fstat(int fd, struct stat *buf) -{ - HANDLE fh = (HANDLE)_get_osfhandle(fd); - BY_HANDLE_FILE_INFORMATION fdata; - - if (fh == INVALID_HANDLE_VALUE) { - errno = EBADF; - return -1; - } - /* direct non-file handles to MS's fstat() */ - if (GetFileType(fh) != FILE_TYPE_DISK) - return fstat(fd, buf); - - if (GetFileInformationByHandle(fh, &fdata)) { - buf->st_ino = 0; - buf->st_gid = 0; - buf->st_uid = 0; - buf->st_nlink = 1; - buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = 0; /* not used by Git */ - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); - return 0; - } - errno = EBADF; - return -1; -} - -#else -#define HINT (void)0 -#endif - -int main(int argc, char**argv) -{ - int i; - int err = 0; - HINT; - for (i = 1; i < argc; i++) - { - struct stat st; - if (stat(argv[i], &st)) { - perror(argv[i]); - err = 1; - continue; - } - printf("%s: %s\n", argv[i], ctime(&st.st_mtime)); - } - return err; -} diff --git a/usage.c b/usage.c index 9e35e8a390..820d09f92b 100644 --- a/usage.c +++ b/usage.c @@ -5,7 +5,7 @@ */ #include "git-compat-util.h" -void vreport(const char *prefix, const char *err, va_list params) +static void report(const char *prefix, const char *err, va_list params) { char msg[1024]; vsnprintf(msg, sizeof(msg), err, params); @@ -20,52 +20,30 @@ static NORETURN void usage_builtin(const char *err) static NORETURN void die_builtin(const char *err, va_list params) { - vreport("fatal: ", err, params); + report("fatal: ", err, params); exit(128); } static void error_builtin(const char *err, va_list params) { - vreport("error: ", err, params); + report("error: ", err, params); } static void warn_builtin(const char *warn, va_list params) { - vreport("warning: ", warn, params); + report("warning: ", warn, params); } -typedef void (*die_fn_t)(const char *err, va_list params) NORETURN; - -static DWORD tls_index; - -static void tls_init(void) __attribute__((constructor)); -static void tls_init(void) -{ - tls_index = TlsAlloc(); -} - -struct routines { - die_fn_t die_routine; -}; /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static void (*usage_routine)(const char *err) NORETURN = usage_builtin; +static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; static void (*warn_routine)(const char *err, va_list params) = warn_builtin; void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN) { - struct routines *r = TlsGetValue(tls_index); - if (r == NULL) { - /* avoid die()! */ - r = calloc(sizeof(*r), 1); - if (r == NULL) { - fprintf(stderr, "cannot allocate thread-local storage"); - return; - } - TlsSetValue(tls_index, r); - } - r->die_routine = routine; + die_routine = routine; } void usage(const char *err) @@ -76,13 +54,9 @@ void usage(const char *err) void die(const char *err, ...) { va_list params; - struct routines *r = TlsGetValue(tls_index); va_start(params, err); - if (r == NULL || r->die_routine == NULL) - die_builtin(err, params); - else - r->die_routine(err, params); + die_routine(err, params); va_end(params); } From 3d3ecb65e34a62b83648516150ec8a99e1b3ace7 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 15 Apr 2009 17:14:03 +0100 Subject: [PATCH 566/781] gitk: avoid crash if closed while reading references As recorded in msysGit issue 125 if the user closes gitk while it reports itself as still reading references then Tk will crash in the geometry management code. This has been fixed for Tk 8.5.7 and above. This patch avoids the problem by flushing outstanding geometry events before calling the readrefs procedure. See also http://code.google.com/p/msysgit/issues/detail?id=125 Signed-off-by: Pat Thoyts Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 1 + 1 file changed, 1 insertion(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index a2c589f749..e78459feda 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -10887,6 +10887,7 @@ makewindow # wait for the window to become visible tkwait visibility . wm title . "[file tail $argv0]: [file tail [pwd]]" +update readrefs if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} { From 933833643ac7e5c08cb8ea3cb00e1fa128e57960 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 19 Apr 2009 17:27:59 +0200 Subject: [PATCH 567/781] Makefile: Clean up after USE_WIN32_MMAP went upstream This commit removes left overs of 7e5a4c563667d011c0655679be3190461884a78e, which was applied by Junio in a slightly modified version in b130a72b274441bb5d687de93efef4d990c40c0a. --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index 9e2b41c4b1..b851df818a 100644 --- a/Makefile +++ b/Makefile @@ -1010,10 +1010,6 @@ else COMPAT_OBJS += compat/win32mmap.o endif endif -ifdef USE_WIN32_MMAP - COMPAT_CFLAGS += -DUSE_WIN32_MMAP - COMPAT_OBJS += compat/win32mmap.o -endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o From aa3abfc9852a4d4cfaa7f0042102eb56ed2e0daa Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 20 Apr 2009 21:43:11 +0200 Subject: [PATCH 568/781] Work around a regression in Windows 7, causing erase_in_line() to crash sometimes The function FillConsoleOutputCharacterA() was pretty content in XP to take a NULL pointer if we did not want to store the number of written columns. In Windows 7, it crashes, but only when called from within Git Bash, not from within cmd.exe. Go figure. Signed-off-by: Johannes Schindelin --- compat/winansi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/winansi.c b/compat/winansi.c index 44dc293ad3..4bee335f9e 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -80,6 +80,7 @@ static void set_console_attr(void) static void erase_in_line(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; + long dummy; /* Needed for Windows 7 (or Vista) regression */ if (!console) return; @@ -87,7 +88,7 @@ static void erase_in_line(void) GetConsoleScreenBufferInfo(console, &sbi); FillConsoleOutputCharacterA(console, ' ', sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition, - NULL); + &dummy); } From aea0a0601b58268e40e60441567d004f47de72f3 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Wed, 1 Apr 2009 14:10:24 +0200 Subject: [PATCH 569/781] Add custom memory allocator to MinGW and MacOS builds The standard allocator on Windows is pretty bad prior to Windows Vista, and nedmalloc is better than the modified dlmalloc provided with newer versions of the MinGW libc. NedMalloc stats in Git ---------------------- All results are the best result out of 3 runs. The benchmarks have been done on different hardware, so the repack times are not comparable. These benchmarks are all based on 'git repack -adf' on the Linux kernel. XP ----------------------------------------------- MinGW Threads Total Time Speed ----------------------------------------------- 3.4.2 (1T) 00:12:28.422 3.4.2 + nedmalloc (1T) 00:07:25.437 1.68x 3.4.5 (1T) 00:12:20.718 3.4.5 + nedmalloc (1T) 00:07:24.809 1.67x 4.3.3-tdm (1T) 00:12:01.843 4.3.3-tdm + nedmalloc (1T) 00:07:16.468 1.65x 4.3.3-tdm (2T) 00:07:35.062 4.3.3-tdm + nedmalloc (2T) 00:04:57.874 1.54x Vista ----------------------------------------------- MinGW Threads Total Time Speed ----------------------------------------------- 4.3.3-tdm (1T) 00:07:40.844 4.3.3-tdm + nedmalloc (1T) 00:07:17.548 1.05x 4.3.3-tdm (2T) 00:05:33.746 4.3.3-tdm + nedmalloc (2T) 00:05:27.334 1.02x Mac Mini ----------------------------------------------- GCC Threads Total Time Speed ----------------------------------------------- i686-darwin9-4.0.1 (2T) 00:09:57.346 i686-darwin9-4.0.1+ned (2T) 00:08:51.072 1.12x Signed-off-by: Marius Storm-Olsen --- Makefile | 9 + compat/nedmalloc/License.txt | 23 + compat/nedmalloc/Readme.txt | 136 + compat/nedmalloc/malloc.c.h | 5750 ++++++++++++++++++++++++++++++++++ compat/nedmalloc/nedmalloc.c | 966 ++++++ compat/nedmalloc/nedmalloc.h | 180 ++ 6 files changed, 7064 insertions(+) create mode 100644 compat/nedmalloc/License.txt create mode 100644 compat/nedmalloc/Readme.txt create mode 100644 compat/nedmalloc/malloc.c.h create mode 100644 compat/nedmalloc/nedmalloc.c create mode 100644 compat/nedmalloc/nedmalloc.h diff --git a/Makefile b/Makefile index b851df818a..bec8a4229e 100644 --- a/Makefile +++ b/Makefile @@ -165,6 +165,9 @@ all:: # Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call # your external grep (e.g., if your system lacks grep, if its grep is # broken, or spawning external process is slower than built-in grep git has). +# +# Define USE_NED_ALLOCATOR if you want to replace the platforms default +# memory allocators with the nedmalloc allocator written by Niall Douglas. GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -827,6 +830,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_NSEC = YesPlease USE_WIN32_MMAP = YesPlease + USE_NED_ALLOCATOR = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o @@ -1106,6 +1110,11 @@ ifdef NO_EXTERNAL_GREP BASIC_CFLAGS += -DNO_EXTERNAL_GREP endif +ifdef USE_NED_ALLOCATOR + COMPAT_CFLAGS += -DUSE_NED_ALLOCATOR -DOVERRIDE_STRDUP -DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR -Icompat/nedmalloc + COMPAT_OBJS += compat/nedmalloc/nedmalloc.o +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK=NoThanks endif diff --git a/compat/nedmalloc/License.txt b/compat/nedmalloc/License.txt new file mode 100644 index 0000000000..36b7cd93cd --- /dev/null +++ b/compat/nedmalloc/License.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/compat/nedmalloc/Readme.txt b/compat/nedmalloc/Readme.txt new file mode 100644 index 0000000000..0534be7c20 --- /dev/null +++ b/compat/nedmalloc/Readme.txt @@ -0,0 +1,136 @@ +nedalloc v1.05 15th June 2008: +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +by Niall Douglas (http://www.nedprod.com/programs/portable/nedmalloc/) + +Enclosed is nedalloc, an alternative malloc implementation for multiple +threads without lock contention based on dlmalloc v2.8.4. It is more +or less a newer implementation of ptmalloc2, the standard allocator in +Linux (which is based on dlmalloc v2.7.0) but also contains a per-thread +cache for maximum CPU scalability. + +It is licensed under the Boost Software License which basically means +you can do anything you like with it. This does not apply to the malloc.c.h +file which remains copyright to others. + +It has been tested on win32 (x86), win64 (x64), Linux (x64), FreeBSD (x64) +and Apple MacOS X (x86). It works very well on all of these and is very +significantly faster than the system allocator on all of these platforms. + +By literally dropping in this allocator as a replacement for your system +allocator, you can see real world improvements of up to three times in normal +code! + +To use: +-=-=-=- +Drop in nedmalloc.h, nedmalloc.c and malloc.c.h into your project. +Configure using the instructions in nedmalloc.h. Run and enjoy. + +To test, compile test.c. It will run a comparison between your system +allocator and nedalloc and tell you how much faster nedalloc is. It also +serves as an example of usage. + +Notes: +-=-=-= +If you want the very latest version of this allocator, get it from the +TnFOX SVN repository at svn://svn.berlios.de/viewcvs/tnfox/trunk/src/nedmalloc + +Because of how nedalloc allocates an mspace per thread, it can cause +severe bloating of memory usage under certain allocation patterns. +You can substantially reduce this wastage by setting MAXTHREADSINPOOL +or the threads parameter to nedcreatepool() to a fraction of the number of +threads which would normally be in a pool at once. This will reduce +bloating at the cost of an increase in lock contention. If allocated size +is less than THREADCACHEMAX, locking is avoided 90-99% of the time and +if most of your allocations are below this value, you can safely set +MAXTHREADSINPOOL to one. + +You will suffer memory leakage unless you call neddisablethreadcache() +per pool for every thread which exits. This is because nedalloc cannot +portably know when a thread exits and thus when its thread cache can +be returned for use by other code. Don't forget pool zero, the system pool. + +For C++ type allocation patterns (where the same sizes of memory are +regularly allocated and deallocated as objects are created and destroyed), +the threadcache always benefits performance. If however your allocation +patterns are different, searching the threadcache may significantly slow +down your code - as a rule of thumb, if cache utilisation is below 80% +(see the source for neddisablethreadcache() for how to enable debug +printing in release mode) then you should disable the thread cache for +that thread. You can compile out the threadcache code by setting +THREADCACHEMAX to zero. + +Speed comparisons: +-=-=-=-=-=-=-=-=-= +See Benchmarks.xls for details. + +The enclosed test.c can do two things: it can be a torture test or a speed +test. The speed test is designed to be a representative synthetic +memory allocator test. It works by randomly mixing allocations with frees +with half of the allocation sizes being a two power multiple less than +512 bytes (to mimic C++ stack instantiated objects) and the other half +being a simple random value less than 16Kb. + +The real world code results are from Tn's TestIO benchmark. This is a +heavily multithreaded and memory intensive benchmark with a lot of branching +and other stuff modern processors don't like so much. As you'll note, the +test doesn't show the benefits of the threadcache mostly due to the saturation +of the memory bus being the limiting factor. + +ChangeLog: +-=-=-=-=-= +v1.05 15th June 2008: + * { 1042 } Added error check for TLSSET() and TLSFREE() macros. Thanks to +Markus Elfring for reporting this. + * { 1043 } Fixed a segfault when freeing memory allocated using +nedindependent_comalloc(). Thanks to Pavel Vozenilek for reporting this. + +v1.04 14th July 2007: + * Fixed a bug with the new optimised implementation that failed to lock +on a realloc under certain conditions. + * Fixed lack of thread synchronisation in InitPool() causing pool corruption + * Fixed a memory leak of thread cache contents on disabling. Thanks to Earl +Chew for reporting this. + * Added a sanity check for freed blocks being valid. + * Reworked test.c into being a torture test. + * Fixed GCC assembler optimisation misspecification + +v1.04alpha_svn915 7th October 2006: + * Fixed failure to unlock thread cache list if allocating a new list failed. +Thanks to Dmitry Chichkov for reporting this. Futher thanks to Aleksey Sanin. + * Fixed realloc(0, ) segfaulting. Thanks to Dmitry Chichkov for +reporting this. + * Made config defines #ifndef so they can be overriden by the build system. +Thanks to Aleksey Sanin for suggesting this. + * Fixed deadlock in nedprealloc() due to unnecessary locking of preferred +thread mspace when mspace_realloc() always uses the original block's mspace +anyway. Thanks to Aleksey Sanin for reporting this. + * Made some speed improvements by hacking mspace_malloc() to no longer lock +its mspace, thus allowing the recursive mutex implementation to be removed +with an associated speed increase. Thanks to Aleksey Sanin for suggesting this. + * Fixed a bug where allocating mspaces overran its max limit. Thanks to +Aleksey Sanin for reporting this. + +v1.03 10th July 2006: + * Fixed memory corruption bug in threadcache code which only appeared with >4 +threads and in heavy use of the threadcache. + +v1.02 15th May 2006: + * Integrated dlmalloc v2.8.4, fixing the win32 memory release problem and +improving performance still further. Speed is now up to twice the speed of v1.01 +(average is 67% faster). + * Fixed win32 critical section implementation. Thanks to Pavel Kuznetsov +for reporting this. + * Wasn't locking mspace if all mspaces were locked. Thanks to Pavel Kuznetsov +for reporting this. + * Added Apple Mac OS X support. + +v1.01 24th February 2006: + * Fixed multiprocessor scaling problems by removing sources of cache sloshing + * Earl Chew agilent com> sent patches for the following: + 1. size2binidx() wasn't working for default code path (non x86) + 2. Fixed failure to release mspace lock under certain circumstances which + caused a deadlock + +v1.00 1st January 2006: + * First release diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h new file mode 100644 index 0000000000..1d9bbe0aba --- /dev/null +++ b/compat/nedmalloc/malloc.c.h @@ -0,0 +1,5750 @@ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/licenses/publicdomain. Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version pre-2.8.4 Mon Nov 27 11:22:37 2006 (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.4.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (default) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with either a pthread mutex or a win32 + spinlock (depending on WIN32). This is not especially fast, and + can be a major bottleneck. It is designed only to provide + minimal protection in concurrent environments, and to provide a + basis for extensions. If you are using malloc in a concurrent + program, consider instead using nedmalloc + (http://www.nedprod.com/programs/portable/nedmalloc/) or + ptmalloc (See http://www.malloc.de), which are derived + from versions of this malloc. + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. In real-time + applications, you can optionally suppress segment traversals using + NO_SEGMENT_TRAVERSAL, which assures bounded execution even when + system allocators return non-contiguous spaces, at the typical + expense of carrying around more memory and increased fragmentation. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. You can also +use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. Beware that there seem to be some + cases where this malloc might not be a pure drop-in replacement for + Win32 malloc: Random-looking failures from Win32 GDI API's (eg; + SetDIBits()) may be due to bugs in some video driver implementations + when pixel buffers are malloc()ed, and the region spans more than + one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) + default granularity, pixel buffers may straddle virtual allocation + regions more often than when using the Microsoft allocator. You can + avoid this by using VirtualAlloc() and VirtualFree() for all pixel + buffers rather than using malloc(). If this is not possible, + recompile this malloc with a larger DEFAULT_GRANULARITY. + +MALLOC_ALIGNMENT default: (size_t)8 + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) If set to a + non-zero value other than 1, locks are used, but their + implementation is left out, so lock functions must be supplied manually. + +USE_SPIN_LOCKS default: 1 iff USE_LOCKS and on x86 using gcc or MSC + If true, uses custom spin locks for locking. This is currently + supported only for x86 platforms using gcc or recent MS compilers. + Otherwise, posix locks or win32 critical sections are used. + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. + +MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +NO_SEGMENT_TRAVERSAL default: 0 + If non-zero, suppresses traversals of memory segments + returned by either MORECORE or CALL_MMAP. This disables + merging of segments that are contiguous, and selectively + releasing them to the OS if unused, but bounds execution times. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 except on WINCE. + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero and on WIN32 except for WINCE. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. Similarly for Win32 under recent MS compilers. + (On most x86s, the asm version is only slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP + The number of consolidated frees between checks to release + unused segments when freeing. When using non-contiguous segments, + especially with multiple mspaces, checking only for topmost space + doesn't always suffice to trigger trimming. To compensate for this, + free() will, with a period of MAX_RELEASE_CHECK_RATE (or the + current number of segments, if greater) try to release unused + segments to the OS when freeing chunks that result in + consolidation. The best value for this parameter is a compromise + between slowing down frees with relatively costly checks that + rarely trigger versus holding on to unused memory. To effectively + disable, set to MAX_SIZE_T. This may lead to a very slight speed + improvement at the expense of carrying around more memory. +*/ + +/* Version identifier to allow people to support multiple versions */ +#ifndef DLMALLOC_VERSION +#define DLMALLOC_VERSION 20804 +#endif /* DLMALLOC_VERSION */ + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#ifdef _WIN32_WCE +#define LACKS_FCNTL_H +#define WIN32 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x403 +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION +#endif /* MALLOC_FAILURE_ACTION */ +#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ +#define MMAP_CLEARS 0 +#else +#define MMAP_CLEARS 1 +#endif /* _WIN32_WCE */ +#endif /* WIN32 */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +/* OSX allocators provide 16 byte alignment */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)16U) +#endif +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 /* define to a value */ +#else +#define ONLY_MSPACES 1 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)8U) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ +#ifndef USE_LOCKS +#define USE_LOCKS 0 +#endif /* USE_LOCKS */ +#ifndef USE_SPIN_LOCKS +#if USE_LOCKS && (defined(__GNUC__) && ((defined(__i386__) || defined(__x86_64__)))) || (defined(_MSC_VER) && _MSC_VER>=1310) +#define USE_SPIN_LOCKS 1 +#else +#define USE_SPIN_LOCKS 0 +#endif /* USE_LOCKS && ... */ +#endif /* USE_SPIN_LOCKS */ +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#define MORECORE_DEFAULT sbrk +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if (MORECORE_CONTIGUOUS || defined(WIN32)) +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef MAX_RELEASE_CHECK_RATE +#if HAVE_MMAP +#define MAX_RELEASE_CHECK_RATE 4095 +#else +#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* MAX_RELEASE_CHECK_RATE */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ +#ifndef NO_SEGMENT_TRAVERSAL +#define NO_SEGMENT_TRAVERSAL 0 +#endif /* NO_SEGMENT_TRAVERSAL */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ +#ifndef STRUCT_MALLINFO_DECLARED +#define STRUCT_MALLINFO_DECLARED 1 +struct mallinfo { + MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE smblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblks; /* always 0 */ + MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE fordblks; /* total free space */ + MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ +}; +#endif /* STRUCT_MALLINFO_DECLARED */ +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +/* + Try to persuade compilers to inline. The most critical functions for + inlining are defined as macros, so these aren't used for them. +*/ + +#ifndef FORCEINLINE + #if defined(__GNUC__) +#define FORCEINLINE __inline __attribute__ ((always_inline)) + #elif defined(_MSC_VER) + #define FORCEINLINE __forceinline + #endif +#endif +#ifndef NOINLINE + #if defined(__GNUC__) + #define NOINLINE __attribute__ ((noinline)) + #elif defined(_MSC_VER) + #define NOINLINE __declspec(noinline) + #else + #define NOINLINE + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#ifndef FORCEINLINE + #define FORCEINLINE inline +#endif +#endif /* __cplusplus */ +#ifndef FORCEINLINE + #define FORCEINLINE +#endif + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlrealloc realloc +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#endif /* USE_DL_PREFIX */ + + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ + +void* dlrealloc(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +void* dlmemalign(size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. To workaround the fact that mallopt is specified to use int, + not size_t parameters, the value -1 is specially treated as the + maximum unsigned size_t value. + + SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +size_t dlmalloc_max_footprint(void); + +#if !NO_MALLINFO +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: always zero. + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: always zero + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +struct mallinfo dlmallinfo(void); +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use regular calloc and assign pointers into this + space to represent elements. (In this case though, you cannot + independently free elements.) + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use a single regular malloc, and assign pointers at + particular offsets in the aggregate space. (In this case though, you + cannot independently free elements.) + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +void** dlindependent_comalloc(size_t, size_t*, void**); + + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +int dlmalloc_trim(size_t); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +void dlmalloc_stats(void); + +#endif /* ONLY_MSPACES */ + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + + +#if MSPACES + +/* + mspace is an opaque type representing an independent + region of space that supports mspace_malloc, etc. +*/ +typedef void* mspace; + +/* + create_mspace creates and returns a new independent space with the + given initial capacity, or, if 0, the default granularity size. It + returns null if there is no system memory available to create the + space. If argument locked is non-zero, the space uses a separate + lock to control access. The capacity of the space will grow + dynamically as needed to service mspace_malloc requests. You can + control the sizes of incremental increases of this space by + compiling with a different DEFAULT_GRANULARITY or dynamically + setting with mallopt(M_GRANULARITY, value). +*/ +mspace create_mspace(size_t capacity, int locked); + +/* + destroy_mspace destroys the given space, and attempts to return all + of its memory back to the system, returning the total number of + bytes freed. After destruction, the results of access to all memory + used by the space become undefined. +*/ +size_t destroy_mspace(mspace msp); + +/* + create_mspace_with_base uses the memory supplied as the initial base + of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this + space is used for bookkeeping, so the capacity must be at least this + large. (Otherwise 0 is returned.) When this initial space is + exhausted, additional memory will be obtained from the system. + Destroying this space will deallocate all additionally allocated + space (if possible) but not the initial base. +*/ +mspace create_mspace_with_base(void* base, size_t capacity, int locked); + +/* + mspace_mmap_large_chunks controls whether requests for large chunks + are allocated in their own mmapped regions, separate from others in + this mspace. By default this is enabled, which reduces + fragmentation. However, such chunks are not necessarily released to + the system upon destroy_mspace. Disabling by setting to false may + increase fragmentation, but avoids leakage when relying on + destroy_mspace to release all memory allocated using this space. +*/ +int mspace_mmap_large_chunks(mspace msp, int enable); + + +/* + mspace_malloc behaves as malloc, but operates within + the given space. +*/ +void* mspace_malloc(mspace msp, size_t bytes); + +/* + mspace_free behaves as free, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_free is not actually needed. + free may be called instead of mspace_free because freed chunks from + any space are handled by their originating spaces. +*/ +void mspace_free(mspace msp, void* mem); + +/* + mspace_realloc behaves as realloc, but operates within + the given space. + + If compiled with FOOTERS==1, mspace_realloc is not actually + needed. realloc may be called instead of mspace_realloc because + realloced chunks from any space are handled by their originating + spaces. +*/ +void* mspace_realloc(mspace msp, void* mem, size_t newsize); + +/* + mspace_calloc behaves as calloc, but operates within + the given space. +*/ +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); + +/* + mspace_memalign behaves as memalign, but operates within + the given space. +*/ +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); + +/* + mspace_independent_calloc behaves as independent_calloc, but + operates within the given space. +*/ +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]); + +/* + mspace_independent_comalloc behaves as independent_comalloc, but + operates within the given space. +*/ +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]); + +/* + mspace_footprint() returns the number of bytes obtained from the + system for this space. +*/ +size_t mspace_footprint(mspace msp); + +/* + mspace_max_footprint() returns the peak number of bytes obtained from the + system for this space. +*/ +size_t mspace_max_footprint(mspace msp); + + +#if !NO_MALLINFO +/* + mspace_mallinfo behaves as mallinfo, but reports properties of + the given space. +*/ +struct mallinfo mspace_mallinfo(mspace msp); +#endif /* NO_MALLINFO */ + +/* + malloc_usable_size(void* p) behaves the same as malloc_usable_size; +*/ + size_t mspace_usable_size(void* mem); + +/* + mspace_malloc_stats behaves as malloc_stats, but reports + properties of the given space. +*/ +void mspace_malloc_stats(mspace msp); + +/* + mspace_trim behaves as malloc_trim, but + operates within the given space. +*/ +int mspace_trim(mspace msp, size_t pad); + +/* + An alias for mallopt. +*/ +int mspace_mallopt(int, int); + +#endif /* MSPACES */ + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef WIN32 +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* WIN32 */ + +#include /* for printing in malloc_stats */ + +#ifndef LACKS_ERRNO_H +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#if FOOTERS +#include /* for magic initialization */ +#endif /* FOOTERS */ +#ifndef LACKS_STDLIB_H +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#ifndef assert +#define assert(x) +#endif +#define DEBUG 0 +#endif /* DEBUG */ +#ifndef LACKS_STRING_H +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +#include /* for mmap */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#ifndef LACKS_UNISTD_H +#include /* for sbrk, sysconf */ +#else /* LACKS_UNISTD_H */ +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +extern void* sbrk(ptrdiff_t); +#endif /* FreeBSD etc */ +#endif /* LACKS_UNISTD_H */ + +/* Declarations for locking */ +#if USE_LOCKS +#ifndef WIN32 +#include +#if defined (__SVR4) && defined (__sun) /* solaris */ +#include +#endif /* solaris */ +#else +#ifndef _M_AMD64 +/* These are already defined on AMD64 builds */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +#ifndef __MINGW32__ +LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp); +LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); +#endif +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _M_AMD64 */ +#ifndef __MINGW32__ +#pragma intrinsic (_InterlockedCompareExchange) +#pragma intrinsic (_InterlockedExchange) +#else + /* --[ start GCC compatibility ]---------------------------------------------- + * Compatibility header for GCC -- GCC equivalents of intrinsic + * Microsoft Visual C++ functions. Originally developed for the ReactOS + * () and TinyKrnl () + * projects. + * + * Copyright (c) 2006 KJK::Hyperion + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + /*** Atomic operations ***/ + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 + #define _ReadWriteBarrier() __sync_synchronize() + #else + static __inline__ __attribute__((always_inline)) long __sync_lock_test_and_set(volatile long * const Target, const long Value) + { + long res; + __asm__ __volatile__("xchg%z0 %2, %0" : "=g" (*(Target)), "=r" (res) : "1" (Value)); + return res; + } + static void __inline__ __attribute__((always_inline)) _MemoryBarrier(void) + { + __asm__ __volatile__("" : : : "memory"); + } + #define _ReadWriteBarrier() _MemoryBarrier() + #endif + /* BUGBUG: GCC only supports full barriers */ + static __inline__ __attribute__((always_inline)) long _InterlockedExchange(volatile long * const Target, const long Value) + { + /* NOTE: __sync_lock_test_and_set would be an acquire barrier, so we force a full barrier */ + _ReadWriteBarrier(); + return __sync_lock_test_and_set(Target, Value); + } + /* --[ end GCC compatibility ]---------------------------------------------- */ +#endif +#define interlockedcompareexchange _InterlockedCompareExchange +#define interlockedexchange _InterlockedExchange +#endif /* Win32 */ +#endif /* USE_LOCKS */ + +/* Declarations for bit scanning on win32 */ +#if defined(_MSC_VER) && _MSC_VER>=1300 +#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define BitScanForward _BitScanForward +#define BitScanReverse _BitScanReverse +#pragma intrinsic(_BitScanForward) +#pragma intrinsic(_BitScanReverse) +#endif /* BitScanForward */ +#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ + +#ifndef WIN32 +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize ((size_t)4096U) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif +#endif + + + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some platforms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define SIZE_T_FOUR ((size_t)4) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if HAVE_MMAP + +#ifndef WIN32 +#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) +#define MMAP_PROT (PROT_READ|PROT_WRITE) +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif /* MAP_ANON */ +#ifdef MAP_ANONYMOUS +#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) +#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) +#else /* MAP_ANONYMOUS */ +/* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. +*/ +#define MMAP_FLAGS (MAP_PRIVATE) +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ +#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) +#endif /* MAP_ANONYMOUS */ + +#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) + +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static FORCEINLINE void* win32mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static FORCEINLINE void* win32direct_mmap(size_t size) { + void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, + PAGE_READWRITE); + return (ptr != 0)? ptr: MFAIL; +} + +/* This function supports releasing coalesed segments */ +static FORCEINLINE int win32munmap(void* ptr, size_t size) { + MEMORY_BASIC_INFORMATION minfo; + char* cptr = (char*)ptr; + while (size) { + if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) + return -1; + if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || + minfo.State != MEM_COMMIT || minfo.RegionSize > size) + return -1; + if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) + return -1; + cptr += minfo.RegionSize; + size -= minfo.RegionSize; + } + return 0; +} + +#define MMAP_DEFAULT(s) win32mmap(s) +#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MREMAP +#ifndef WIN32 +#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#endif /* WIN32 */ +#endif /* HAVE_MREMAP */ + + +/** + * Define CALL_MORECORE + */ +#if HAVE_MORECORE + #ifdef MORECORE + #define CALL_MORECORE(S) MORECORE(S) + #else /* MORECORE */ + #define CALL_MORECORE(S) MORECORE_DEFAULT(S) + #endif /* MORECORE */ +#else /* HAVE_MORECORE */ + #define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/** + * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP + */ +#if HAVE_MMAP + #define IS_MMAPPED_BIT (SIZE_T_ONE) + #define USE_MMAP_BIT (SIZE_T_ONE) + + #ifdef MMAP + #define CALL_MMAP(s) MMAP(s) + #else /* MMAP */ + #define CALL_MMAP(s) MMAP_DEFAULT(s) + #endif /* MMAP */ + #ifdef MUNMAP + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) + #else /* MUNMAP */ + #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) + #endif /* MUNMAP */ + #ifdef DIRECT_MMAP + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #else /* DIRECT_MMAP */ + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) + #endif /* DIRECT_MMAP */ +#else /* HAVE_MMAP */ + #define IS_MMAPPED_BIT (SIZE_T_ZERO) + #define USE_MMAP_BIT (SIZE_T_ZERO) + + #define MMAP(s) MFAIL + #define MUNMAP(a, s) (-1) + #define DIRECT_MMAP(s) MFAIL + #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) + #define CALL_MMAP(s) MMAP(s) + #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) +#endif /* HAVE_MMAP */ + +/** + * Define CALL_MREMAP + */ +#if HAVE_MMAP && HAVE_MREMAP + #ifdef MREMAP + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) + #else /* MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) + #endif /* MREMAP */ +#else /* HAVE_MMAP && HAVE_MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +/* + When locks are defined, there is one global lock, plus + one per-mspace lock. + + The global lock_ensures that mparams.magic and other unique + mparams values are initialized only once. It also protects + sequences of calls to MORECORE. In many cases sys_alloc requires + two calls, that should not be interleaved with calls by other + threads. This does not protect against direct calls to MORECORE + by other threads not using this lock, so there is still code to + cope the best we can on interference. + + Per-mspace locks surround calls to malloc, free, etc. To enable use + in layered extensions, per-mspace locks are reentrant. + + Because lock-protected regions generally have bounded times, it is + OK to use the supplied simple spinlocks in the custom versions for + x86. + + If USE_LOCKS is > 1, the definitions of lock routines here are + bypassed, in which case you will need to define at least + INITIAL_LOCK, ACQUIRE_LOCK, RELEASE_LOCK and possibly TRY_LOCK + (which is not used in this malloc, but commonly needed in + extensions.) +*/ + +#if USE_LOCKS == 1 + +#if USE_SPIN_LOCKS +#ifndef WIN32 + +/* Custom pthread-style spin locks on x86 and x64 for gcc */ +struct pthread_mlock_t { + volatile unsigned int l; + volatile unsigned int c; + volatile pthread_t threadid; +}; +#define MLOCK_T struct pthread_mlock_t +#define CURRENT_THREAD pthread_self() +#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), 0) +#define ACQUIRE_LOCK(sl) pthread_acquire_lock(sl) +#define RELEASE_LOCK(sl) pthread_release_lock(sl) +#define TRY_LOCK(sl) pthread_try_lock(sl) +#define SPINS_PER_YIELD 63 + +static MLOCK_T malloc_global_mutex = { 0, 0, 0}; + +static FORCEINLINE int pthread_acquire_lock (MLOCK_T *sl) { + int spins = 0; + volatile unsigned int* lp = &sl->l; + for (;;) { + if (*lp != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 0; + } + } + else { + /* place args to cmpxchgl in locals to evade oddities in some gccs */ + int cmp = 0; + int val = 1; + int ret; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(lp)), "0"(cmp) + : "memory", "cc"); + if (!ret) { + assert(!sl->threadid); + sl->c = 1; + sl->threadid = CURRENT_THREAD; + return 0; + } + if ((++spins & SPINS_PER_YIELD) == 0) { +#if defined (__SVR4) && defined (__sun) /* solaris */ + thr_yield(); +#else +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) + sched_yield(); +#else /* no-op yield on unknown systems */ + ; +#endif /* __linux__ || __FreeBSD__ || __APPLE__ */ +#endif /* solaris */ + } + } + } +} + +static FORCEINLINE void pthread_release_lock (MLOCK_T *sl) { + assert(sl->l != 0); + assert(sl->threadid == CURRENT_THREAD); + if (--sl->c == 0) { + sl->threadid = 0; + volatile unsigned int* lp = &sl->l; + int prev = 0; + int ret; + __asm__ __volatile__ ("lock; xchgl %0, %1" + : "=r" (ret) + : "m" (*(lp)), "0"(prev) + : "memory"); + } +} + +static FORCEINLINE int pthread_try_lock (MLOCK_T *sl) { + volatile unsigned int* lp = &sl->l; + if (*lp != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 1; + } + } + else { + int cmp = 0; + int val = 1; + int ret; + __asm__ __volatile__ ("lock; cmpxchgl %1, %2" + : "=a" (ret) + : "r" (val), "m" (*(lp)), "0"(cmp) + : "memory", "cc"); + if (!ret) { + assert(!sl->threadid); + sl->c = 1; + sl->threadid = CURRENT_THREAD; + return 1; + } + } + return 0; +} + + +#else /* WIN32 */ +/* Custom win32-style spin locks on x86 and x64 for MSC */ +struct win32_mlock_t +{ + volatile long l; + volatile unsigned int c; + volatile long threadid; +}; + +#define MLOCK_T struct win32_mlock_t +#define CURRENT_THREAD win32_getcurrentthreadid() +#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), 0) +#define ACQUIRE_LOCK(sl) win32_acquire_lock(sl) +#define RELEASE_LOCK(sl) win32_release_lock(sl) +#define TRY_LOCK(sl) win32_try_lock(sl) +#define SPINS_PER_YIELD 63 + +static MLOCK_T malloc_global_mutex = { 0, 0, 0}; + +static FORCEINLINE long win32_getcurrentthreadid() { +#ifdef _MSC_VER +#if defined(_M_IX86) + long *threadstruct=(long *)__readfsdword(0x18); + long threadid=threadstruct[0x24/sizeof(long)]; + return threadid; +#elif defined(_M_X64) + /* todo */ + return GetCurrentThreadId(); +#else + return GetCurrentThreadId(); +#endif +#else + return GetCurrentThreadId(); +#endif +} + +static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) { + int spins = 0; + for (;;) { + if (sl->l != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 0; + } + } + else { + if (!interlockedexchange(&sl->l, 1)) { + assert(!sl->threadid); + sl->c=CURRENT_THREAD; + sl->threadid = CURRENT_THREAD; + sl->c = 1; + return 0; + } + } + if ((++spins & SPINS_PER_YIELD) == 0) + SleepEx(0, FALSE); + } +} + +static FORCEINLINE void win32_release_lock (MLOCK_T *sl) { + assert(sl->threadid == CURRENT_THREAD); + assert(sl->l != 0); + if (--sl->c == 0) { + sl->threadid = 0; + interlockedexchange (&sl->l, 0); + } +} + +static FORCEINLINE int win32_try_lock (MLOCK_T *sl) { + if(sl->l != 0) { + if (sl->threadid == CURRENT_THREAD) { + ++sl->c; + return 1; + } + } + else { + if (!interlockedexchange(&sl->l, 1)){ + assert(!sl->threadid); + sl->threadid = CURRENT_THREAD; + sl->c = 1; + return 1; + } + } + return 0; +} + +#endif /* WIN32 */ +#else /* USE_SPIN_LOCKS */ + +#ifndef WIN32 +/* pthreads-based locks */ + +#define MLOCK_T pthread_mutex_t +#define CURRENT_THREAD pthread_self() +#define INITIAL_LOCK(sl) pthread_init_lock(sl) +#define ACQUIRE_LOCK(sl) pthread_mutex_lock(sl) +#define RELEASE_LOCK(sl) pthread_mutex_unlock(sl) +#define TRY_LOCK(sl) (!pthread_mutex_trylock(sl)) + +static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Cope with old-style linux recursive lock initialization by adding */ +/* skipped internal declaration from pthread.h */ +#ifdef linux +#ifndef PTHREAD_MUTEX_RECURSIVE +extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr, + int __kind)); +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y) +#endif +#endif + +static int pthread_init_lock (MLOCK_T *sl) { + pthread_mutexattr_t attr; + if (pthread_mutexattr_init(&attr)) return 1; + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1; + if (pthread_mutex_init(sl, &attr)) return 1; + if (pthread_mutexattr_destroy(&attr)) return 1; + return 0; +} + +#else /* WIN32 */ +/* Win32 critical sections */ +#define MLOCK_T CRITICAL_SECTION +#define CURRENT_THREAD GetCurrentThreadId() +#define INITIAL_LOCK(s) (!InitializeCriticalSectionAndSpinCount((s), 0x80000000|4000)) +#define ACQUIRE_LOCK(s) (EnterCriticalSection(s), 0) +#define RELEASE_LOCK(s) LeaveCriticalSection(s) +#define TRY_LOCK(s) TryEnterCriticalSection(s) +#define NEED_GLOBAL_LOCK_INIT + +static MLOCK_T malloc_global_mutex; +static volatile long malloc_global_mutex_status; + +/* Use spin loop to initialize global lock */ +static void init_malloc_global_mutex() { + for (;;) { + long stat = malloc_global_mutex_status; + if (stat > 0) + return; + /* transition to < 0 while initializing, then to > 0) */ + if (stat == 0 && + interlockedcompareexchange(&malloc_global_mutex_status, -1, 0) == 0) { + InitializeCriticalSection(&malloc_global_mutex); + interlockedexchange(&malloc_global_mutex_status,1); + return; + } + SleepEx(0, FALSE); + } +} + +#endif /* WIN32 */ +#endif /* USE_SPIN_LOCKS */ +#endif /* USE_LOCKS == 1 */ + +/* ----------------------- User-defined locks ------------------------ */ + +#if USE_LOCKS > 1 +/* Define your own lock implementation here */ +/* #define INITIAL_LOCK(sl) ... */ +/* #define ACQUIRE_LOCK(sl) ... */ +/* #define RELEASE_LOCK(sl) ... */ +/* #define TRY_LOCK(sl) ... */ +/* static MLOCK_T malloc_global_mutex = ... */ +#endif /* USE_LOCKS > 1 */ + +/* ----------------------- Lock-based state ------------------------ */ + +#if USE_LOCKS +#define USE_LOCK_BIT (2U) +#else /* USE_LOCKS */ +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) +#endif /* USE_LOCKS */ + +#if USE_LOCKS +#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); +#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); +#else /* USE_LOCKS */ +#define ACQUIRE_MALLOC_GLOBAL_LOCK() +#define RELEASE_MALLOC_GLOBAL_LOCK() +#endif /* USE_LOCKS */ + + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 0) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse. This redundancy enables usage checks within free and realloc, + and reduces indirection when freeing and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, which have the lowest-order bit + (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set + PINUSE_BIT in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk { + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use. If the chunk was obtained with mmap, the prev_foot field has + IS_MMAPPED_BIT set, otherwise holding the offset of the base of the + mmapped region to the base of the chunk. + + FLAG4_BIT is not used by this malloc, but might be useful in extensions. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define FLAG4_BIT (SIZE_T_FOUR) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) +#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define chunksize(p) ((p)->head & ~(FLAG_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +#define is_mmapped(p)\ + (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; + + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If IS_MMAPPED_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment { + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ +}; + +#define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Trim support + Fields holding the amount of unused topmost memory that should trigger + timming, and a counter to force periodic scanning to release unused + non-topmost segments. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. + + Extension support + A void* pointer and a size_t field that can be used to help implement + extensions to this malloc. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state { + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t release_checks; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; + void* extp; /* Unused but available for extensions */ + size_t exts; +}; + +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. Note that the non-zeroness of "magic" + also serves as an initialization flag. +*/ + +struct malloc_params { + volatile size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* Ensure mparams initialized */ +#define ensure_initialization() (mparams.magic != 0 || init_mparams()) + +#if !ONLY_MSPACES + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) + +#endif /* !ONLY_MSPACES */ + +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity - SIZE_T_ONE))\ + & ~(mparams.granularity - SIZE_T_ONE)) + + +/* For mmap, use granularity alignment on windows, else page-align */ +#ifdef WIN32 +#define mmap_align(S) granularity_align(S) +#else +#define mmap_align(S) page_align(S) +#endif + +/* For sys_alloc, enough padding to ensure can malloc request on success */ +#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char* addr) { + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) { + msegmentptr sp = &m->seg; + for (;;) { + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS + +#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) ((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I. Use x86 asm if possible */ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_tree_index(S, I)\ +{\ + unsigned int X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + __asm__("bsrl\t%1, %0\n\t" : "=r" (K) : "rm" (X));\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K = _bit_scan_reverse (X); \ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + _BitScanReverse((DWORD *) &K, X);\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} + +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + +/* index corresponding to given bit. Use x86 asm if possible */ + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + __asm__("bsfl\t%1, %0\n\t" : "=r" (J) : "rm" (X));\ + I = (bindex_t)J;\ +} + +#elif defined (__INTEL_COMPILER) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + J = _bit_scan_forward (X); \ + I = (bindex_t)J;\ +} + +#elif defined(_MSC_VER) && _MSC_VER>=1300 +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + _BitScanForward((DWORD *) &J, X);\ + I = (bindex_t)J;\ +} + +#elif USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* GNUC */ + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probablistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has its cinuse bit on */ +#define ok_cinuse(p) cinuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_cinuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +/* Initialize mparams */ +static int init_mparams(void) { +#ifdef NEED_GLOBAL_LOCK_INIT + if (malloc_global_mutex_status <= 0) + init_malloc_global_mutex(); +#endif + + ACQUIRE_MALLOC_GLOBAL_LOCK(); + if (mparams.magic == 0) { + size_t magic; + size_t psize; + size_t gsize; + +#ifndef WIN32 + psize = malloc_getpagesize; + gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); +#else /* WIN32 */ + { + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + psize = system_info.dwPageSize; + gsize = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((gsize & (gsize-SIZE_T_ONE)) != 0) || + ((psize & (psize-SIZE_T_ONE)) != 0)) + ABORT; + + mparams.granularity = gsize; + mparams.page_size = psize; + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if !ONLY_MSPACES + /* Set up lock for main malloc area */ + gm->mflags = mparams.default_mflags; + INITIAL_LOCK(&gm->mutex); +#endif + +#if (FOOTERS && !INSECURE) + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) { + magic = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ +#ifdef WIN32 + magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); +#else + magic = (size_t)(time(0) ^ (size_t)0x55555555U); +#endif + magic |= (size_t)8U; /* ensure nonzero */ + magic &= ~(size_t)7U; /* improve chances of fault for bad values */ + } +#else /* (FOOTERS && !INSECURE) */ + magic = (size_t)0x58585858U; +#endif /* (FOOTERS && !INSECURE) */ + + mparams.magic = magic; + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + return 1; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) { + size_t val = (value == -1)? MAX_SIZE_T : (size_t)value; + ensure_initialization(); + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; + return 1; + } + else + return 0; + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; + } +} + +#if DEBUG +/* ------------------------- Debugging Support --------------------------- */ + +/* Check properties of any chunk, whether free, inuse, mmapped etc */ +static void do_check_any_chunk(mstate m, mchunkptr p) { + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); +} + +/* Check properties of top chunk */ +static void do_check_top_chunk(mstate m, mchunkptr p) { + msegmentptr sp = segment_holding(m, (char*)p); + size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ + assert(sp != 0); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(sz == m->topsize); + assert(sz > 0); + assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); + assert(pinuse(p)); + assert(!pinuse(chunk_plus_offset(p, sz))); +} + +/* Check properties of (inuse) mmapped chunks */ +static void do_check_mmapped_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD); + assert(is_mmapped(p)); + assert(use_mmap(m)); + assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); + assert(ok_address(m, p)); + assert(!is_small(sz)); + assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); + assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); + assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); +} + +/* Check properties of inuse chunks */ +static void do_check_inuse_chunk(mstate m, mchunkptr p) { + do_check_any_chunk(m, p); + assert(cinuse(p)); + assert(next_pinuse(p)); + /* If not pinuse and not mmapped, previous chunk has OK offset */ + assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); + if (is_mmapped(p)) + do_check_mmapped_chunk(m, p); +} + +/* Check properties of free chunks */ +static void do_check_free_chunk(mstate m, mchunkptr p) { + size_t sz = chunksize(p); + mchunkptr next = chunk_plus_offset(p, sz); + do_check_any_chunk(m, p); + assert(!cinuse(p)); + assert(!next_pinuse(p)); + assert (!is_mmapped(p)); + if (p != m->dv && p != m->top) { + if (sz >= MIN_CHUNK_SIZE) { + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(is_aligned(chunk2mem(p))); + assert(next->prev_foot == sz); + assert(pinuse(p)); + assert (next == m->top || cinuse(next)); + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_T_SIZE */ + assert(sz == SIZE_T_SIZE); + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); + do_check_inuse_chunk(m, p); + assert((sz & CHUNK_ALIGN_MASK) == 0); + assert(sz >= MIN_CHUNK_SIZE); + assert(sz >= s); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); + } +} + +/* Check a tree and its subtrees. */ +static void do_check_tree(mstate m, tchunkptr t) { + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->index; + size_t tsize = chunksize(t); + bindex_t idx; + compute_tree_index(tsize, idx); + assert(tindex == idx); + assert(tsize >= MIN_LARGE_SIZE); + assert(tsize >= minsize_for_tree_index(idx)); + assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); + + do { /* traverse through chain of same-sized nodes */ + do_check_any_chunk(m, ((mchunkptr)u)); + assert(u->index == tindex); + assert(chunksize(u) == tsize); + assert(!cinuse(u)); + assert(!next_pinuse(u)); + assert(u->fd->bk == u); + assert(u->bk->fd == u); + if (u->parent == 0) { + assert(u->child[0] == 0); + assert(u->child[1] == 0); + } + else { + assert(head == 0); /* only one node on chain has parent */ + head = u; + assert(u->parent != u); + assert (u->parent->child[0] == u || + u->parent->child[1] == u || + *((tbinptr*)(u->parent)) == u); + if (u->child[0] != 0) { + assert(u->child[0]->parent == u); + assert(u->child[0] != u); + do_check_tree(m, u->child[0]); + } + if (u->child[1] != 0) { + assert(u->child[1]->parent == u); + assert(u->child[1] != u); + do_check_tree(m, u->child[1]); + } + if (u->child[0] != 0 && u->child[1] != 0) { + assert(chunksize(u->child[0]) < chunksize(u->child[1])); + } + } + u = u->fd; + } while (u != t); + assert(head != 0); +} + +/* Check all the chunks in a treebin. */ +static void do_check_treebin(mstate m, bindex_t i) { + tbinptr* tb = treebin_at(m, i); + tchunkptr t = *tb; + int empty = (m->treemap & (1U << i)) == 0; + if (t == 0) + assert(empty); + if (!empty) + do_check_tree(m, t); +} + +/* Check all the chunks in a smallbin. */ +static void do_check_smallbin(mstate m, bindex_t i) { + sbinptr b = smallbin_at(m, i); + mchunkptr p = b->bk; + unsigned int empty = (m->smallmap & (1U << i)) == 0; + if (p == b) + assert(empty); + if (!empty) { + for (; p != b; p = p->bk) { + size_t size = chunksize(p); + mchunkptr q; + /* each chunk claims to be free */ + do_check_free_chunk(m, p); + /* chunk belongs in bin */ + assert(small_index(size) == i); + assert(p->bk == b || chunksize(p->bk) == chunksize(p)); + /* chunk is followed by an inuse chunk */ + q = next_chunk(p); + if (q->head != FENCEPOST_HEAD) + do_check_inuse_chunk(m, q); + } + } +} + +/* Find x in a bin. Used in other check functions. */ +static int bin_find(mstate m, mchunkptr x) { + size_t size = chunksize(x); + if (is_small(size)) { + bindex_t sidx = small_index(size); + sbinptr b = smallbin_at(m, sidx); + if (smallmap_is_marked(m, sidx)) { + mchunkptr p = b; + do { + if (p == x) + return 1; + } while ((p = p->fd) != b); + } + } + else { + bindex_t tidx; + compute_tree_index(size, tidx); + if (treemap_is_marked(m, tidx)) { + tchunkptr t = *treebin_at(m, tidx); + size_t sizebits = size << leftshift_for_tree_index(tidx); + while (t != 0 && chunksize(t) != size) { + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + if (t != 0) { + tchunkptr u = t; + do { + if (u == (tchunkptr)x) + return 1; + } while ((u = u->fd) != t); + } + } + } + return 0; +} + +/* Traverse each chunk and check it; return total */ +static size_t traverse_and_check(mstate m) { + size_t sum = 0; + if (is_initialized(m)) { + msegmentptr s = &m->seg; + sum += m->topsize + TOP_FOOT_SIZE; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + mchunkptr lastq = 0; + assert(pinuse(q)); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + sum += chunksize(q); + if (cinuse(q)) { + assert(!bin_find(m, q)); + do_check_inuse_chunk(m, q); + } + else { + assert(q == m->dv || bin_find(m, q)); + assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */ + do_check_free_chunk(m, q); + } + lastq = q; + q = next_chunk(q); + } + s = s->next; + } + } + return sum; +} + +/* Check all properties of malloc_state. */ +static void do_check_malloc_state(mstate m) { + bindex_t i; + size_t total; + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + do_check_smallbin(m, i); + for (i = 0; i < NTREEBINS; ++i) + do_check_treebin(m, i); + + if (m->dvsize != 0) { /* check dv chunk */ + do_check_any_chunk(m, m->dv); + assert(m->dvsize == chunksize(m->dv)); + assert(m->dvsize >= MIN_CHUNK_SIZE); + assert(bin_find(m, m->dv) == 0); + } + + if (m->top != 0) { /* check top chunk */ + do_check_top_chunk(m, m->top); + /*assert(m->topsize == chunksize(m->top)); redundant */ + assert(m->topsize > 0); + assert(bin_find(m, m->top) == 0); + } + + total = traverse_and_check(m); + assert(total <= m->footprint); + assert(m->footprint <= m->max_footprint); +} +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +static struct mallinfo internal_mallinfo(mstate m) { + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + ensure_initialization(); + if (!PREACTION(m)) { + check_malloc_state(m); + if (is_initialized(m)) { + size_t nfree = SIZE_T_ONE; /* top always free */ + size_t mfree = m->topsize + TOP_FOOT_SIZE; + size_t sum = mfree; + msegmentptr s = &m->seg; + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + size_t sz = chunksize(q); + sum += sz; + if (!cinuse(q)) { + mfree += sz; + ++nfree; + } + q = next_chunk(q); + } + s = s->next; + } + + nm.arena = sum; + nm.ordblks = nfree; + nm.hblkhd = m->footprint - sum; + nm.usmblks = m->max_footprint; + nm.uordblks = m->footprint - mfree; + nm.fordblks = mfree; + nm.keepcost = m->topsize; + } + + POSTACTION(m); + } + return nm; +} +#endif /* !NO_MALLINFO */ + +static void internal_malloc_stats(mstate m) { + ensure_initialization(); + if (!PREACTION(m)) { + size_t maxfp = 0; + size_t fp = 0; + size_t used = 0; + check_malloc_state(m); + if (is_initialized(m)) { + msegmentptr s = &m->seg; + maxfp = m->max_footprint; + fp = m->footprint; + used = fp - (m->topsize + TOP_FOOT_SIZE); + + while (s != 0) { + mchunkptr q = align_as_chunk(s->base); + while (segment_holds(s, q) && + q != m->top && q->head != FENCEPOST_HEAD) { + if (!cinuse(q)) + used -= chunksize(q); + q = next_chunk(q); + } + s = s->next; + } + } + + fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); + fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); + fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); + + POSTACTION(m); + } +} + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (F == B)\ + clear_smallmap(M, I);\ + else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\ + (B == smallbin_at(M,I) || ok_address(M, B)))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F)\ + clear_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, F))) {\ + B->fd = F;\ + F->bk = B;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + + + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + assert(is_small(DVS));\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F))) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + (m == gm)? dlmalloc(b) : mspace_malloc(m, b) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). There is also enough space + allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain + the PINUSE bit so frees can be checked. +*/ + +/* Malloc using mmap */ +static void* mmap_alloc(mstate m, size_t nb) { + size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(CALL_DIRECT_MMAP(mmsize)); + if (mm != CMFAIL) { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset | IS_MMAPPED_BIT; + (p)->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; + + if (mm < m->least_addr) + m->least_addr = mm; + if ((m->footprint += mmsize) > m->max_footprint) + m->max_footprint = m->footprint; + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { + size_t oldsize = chunksize(oldp); + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + return 0; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + return oldp; + else { + size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, 1); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) { + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char*)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) { + /* Establish circular links for smallbins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = smallbin_at(m,i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) { + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallbins = m->treebins = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + for (i = 0; i < NTREEBINS; ++i) + *treebin_at(m, i) = 0; + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char*)oldfirst - (char*)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char*)oldfirst > (char*)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else { + if (!cinuse(oldfirst)) { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { + /* Determine locations and sizes of segment, fenceposts, old top */ + char* old_top = (char*)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmapped; + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + if ((char*)(&(nextp->head)) < old_end) + p = nextp; + else + break; + } + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + + ensure_initialization(); + + /* Directly map large chunks */ + if (use_mmap(m) && nb >= mparams.mmap_threshold) { + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + + In all cases, we need to request enough bytes from system to ensure + we can malloc nb bytes upon success, so pad with enough space for + top_foot, plus alignment-pad to make sure we don't lose bytes if + not on boundary, and round this up to a granularity unit. + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { + char* br = CMFAIL; + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); + size_t asize = 0; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); + if (base != CMFAIL) { + asize = granularity_align(nb + SYS_ALLOC_PADDING); + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + asize += (page_align((size_t)base) - (size_t)base); + /* Can't call MORECORE if size is negative when treated as signed */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == base) { + tbase = base; + tsize = asize; + } + } + } + else { + /* Subtract out existing available top space from MORECORE request. */ + asize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); + /* Use mem here only if it did continuously extend old space */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { + tbase = br; + tsize = asize; + } + } + + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (asize < HALF_MAX_SIZE_T && + asize < nb + SYS_ALLOC_PADDING) { + size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - asize); + if (esize < HALF_MAX_SIZE_T) { + char* end = (char*)CALL_MORECORE(esize); + if (end != CMFAIL) + asize += esize; + else { /* Can't use; try to release */ + (void) CALL_MORECORE(-asize); + br = CMFAIL; + } + } + } + } + if (br != CMFAIL) { /* Use the space we did get */ + tbase = br; + tsize = asize; + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + + RELEASE_MALLOC_GLOBAL_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + size_t rsize = granularity_align(nb + SYS_ALLOC_PADDING); + if (rsize > nb) { /* Fail if wraps around zero */ + char* mp = (char*)(CALL_MMAP(rsize)); + if (mp != CMFAIL) { + tbase = mp; + tsize = rsize; + mmap_flag = IS_MMAPPED_BIT; + } + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + size_t asize = granularity_align(nb + SYS_ALLOC_PADDING); + if (asize < HALF_MAX_SIZE_T) { + char* br = CMFAIL; + char* end = CMFAIL; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); + RELEASE_MALLOC_GLOBAL_LOCK(); + if (br != CMFAIL && end != CMFAIL && br < end) { + size_t ssize = end - br; + if (ssize > nb + TOP_FOOT_SIZE) { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) { + + if ((m->footprint += tsize) > m->max_footprint) + m->max_footprint = m->footprint; + + if (!is_initialized(m)) { /* first-time initialization */ + m->seg.base = m->least_addr = tbase; + m->seg.size = tsize; + m->seg.sflags = mmap_flag; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + init_bins(m); +#if !ONLY_MSPACES + if (is_global(m)) + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + else +#endif + { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); + } + } + + else { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + /* Only consider most recent segment if traversal suppressed */ + while (sp != 0 && tbase != sp->base + sp->size) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag && + segment_holds(sp, m->top)) { /* append */ + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; + sp = &m->seg; + while (sp != 0 && sp->base != tbase + tsize) + sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) { + char* oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + add_segment(m, tbase, tsize, mmap_flag); + } + } + + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) { + size_t released = 0; + int nsegs = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + ++nsegs; + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char*)sp)); + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + else { + unlink_large_chunk(m, tp); + } + if (CALL_MUNMAP(base, size) == 0) { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else { /* back out if cannot unmap */ + insert_large_chunk(m, tp, psize); + } + } + } + if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ + break; + pred = sp; + sp = next; + } + /* Reset check counter */ + m->release_checks = ((nsegs > MAX_RELEASE_CHECK_RATE)? + nsegs : MAX_RELEASE_CHECK_RATE); + return released; +} + +static int sys_trim(mstate m, size_t pad) { + size_t released = 0; + ensure_initialization(); + if (pad < MAX_REQUEST && is_initialized(m)) { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); + + if (!is_extern_segment(sp)) { + if (is_mmapped_segment(sp)) { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ + size_t newsize = sp->size - extra; + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + released = extra; + } + } + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + ACQUIRE_MALLOC_GLOBAL_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char* old_br = (char*)(CALL_MORECORE(0)); + if (old_br == sp->base + sp->size) { + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); + if (rel_br != CMFAIL && new_br < old_br) + released = old_br - new_br; + } + } + RELEASE_MALLOC_GLOBAL_LOCK(); + } + } + + if (released != 0) { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + released += release_unused_segments(m); + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0 && m->topsize > m->trim_check) + m->trim_check = MAX_SIZE_T; + } + + return (released != 0)? 1 : 0; +} + + +/* ---------------------------- malloc support --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void* tmalloc_large(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + if ((t = *treebin_at(m, idx)) != 0) { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + if (leftbits != 0) { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) { /* find smallest of tree or subtree */ + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { + if (RTCHECK(ok_address(m, v))) { /* split */ + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + return chunk2mem(v); + } + } + CORRUPTION_ERROR_ACTION(m); + } + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void* tmalloc_small(mstate m, size_t nb) { + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) { + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +/* --------------------------- realloc support --------------------------- */ + +static void* internal_realloc(mstate m, void* oldmem, size_t bytes) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + return 0; + } + if (!PREACTION(m)) { + mchunkptr oldp = mem2chunk(oldmem); + size_t oldsize = chunksize(oldp); + mchunkptr next = chunk_plus_offset(oldp, oldsize); + mchunkptr newp = 0; + void* extra = 0; + + /* Try to either shrink or extend into top. Else malloc-copy-free */ + + if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && + ok_next(oldp, next) && ok_pinuse(next))) { + size_t nb = request2size(bytes); + if (is_mmapped(oldp)) + newp = mmap_resize(m, oldp, nb); + else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + newp = oldp; + if (rsize >= MIN_CHUNK_SIZE) { + mchunkptr remainder = chunk_plus_offset(newp, nb); + set_inuse(m, newp, nb); + set_inuse(m, remainder, rsize); + extra = chunk2mem(remainder); + } + } + else if (next == m->top && oldsize + m->topsize > nb) { + /* Expand into top */ + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(oldp, nb); + set_inuse(m, oldp, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = oldp; + } + } + else { + USAGE_ERROR_ACTION(m, oldmem); + POSTACTION(m); + return 0; + } + + POSTACTION(m); + + if (newp != 0) { + if (extra != 0) { + internal_free(m, extra); + } + check_inuse_chunk(m, newp); + return chunk2mem(newp); + } + else { + void* newmem = internal_malloc(m, bytes); + if (newmem != 0) { + size_t oc = oldsize - overhead_for(oldp); + memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); + internal_free(m, oldmem); + } + return newmem; + } + } + return 0; +} + +/* --------------------------- memalign support -------------------------- */ + +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ + return internal_malloc(m, bytes); + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + alignment = MIN_CHUNK_SIZE; + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ + size_t a = MALLOC_ALIGNMENT << 1; + while (a < alignment) a <<= 1; + alignment = a; + } + + if (bytes >= MAX_REQUEST - alignment) { + if (m != 0) { /* Test isn't needed but avoids compiler warning */ + MALLOC_FAILURE_ACTION; + } + } + else { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + char* mem = (char*)internal_malloc(m, req); + if (mem != 0) { + void* leader = 0; + void* trailer = 0; + mchunkptr p = mem2chunk(mem); + + if (PREACTION(m)) return 0; + if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */ + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char* br = (char*)mem2chunk((size_t)(((size_t)(mem + + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + newp->prev_foot = p->prev_foot + leadsize; + newp->head = (newsize|CINUSE_BIT); + } + else { /* Otherwise, give back leader, use the rest */ + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + leader = chunk2mem(p); + } + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) { + size_t size = chunksize(p); + if (size > nb + MIN_CHUNK_SIZE) { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + trailer = chunk2mem(remainder); + } + } + + assert (chunksize(p) >= nb); + assert((((size_t)(chunk2mem(p))) % alignment) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + if (leader != 0) { + internal_free(m, leader); + } + if (trailer != 0) { + internal_free(m, trailer); + } + return chunk2mem(p); + } + } + return 0; +} + +/* ------------------------ comalloc/coalloc support --------------------- */ + +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + /* + This provides common support for independent_X routines, handling + all of the combinations that can result. + + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed + */ + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + ensure_initialization(); + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (void**)internal_malloc(m, 0); + marray = 0; + array_size = request2size(n_elements * (sizeof(void*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; + + if (PREACTION(m)) return 0; + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) { /* optionally clear the elements */ + memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void**) (chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) { + assert(remainder_size == element_size); + } + else { + assert(remainder_size == request2size(sizes[i])); + } + check_inuse_chunk(m, mem2chunk(marray)); + } + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(m, mem2chunk(marray[i])); + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + + +/* -------------------------- public routines ---------------------------- */ + +#if !ONLY_MSPACES + +void* dlmalloc(size_t bytes) { + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + +#if USE_LOCKS + ensure_initialization(); /* initialize in sys_alloc if not using locks */ +#endif + + if (!PREACTION(gm)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(gm, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else { /* exhaust dv */ + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + + postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +void dlfree(void* mem) { + /* + Consolidate freed chunks with preceeding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = dlmalloc(req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* dlrealloc(void* oldmem, size_t bytes) { + if (oldmem == 0) + return dlmalloc(bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + dlfree(oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(mem2chunk(oldmem)); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + return internal_realloc(m, oldmem, bytes); + } +} + +void* dlmemalign(size_t alignment, size_t bytes) { + return internal_memalign(gm, alignment, bytes); +} + +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +void* dlvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void* dlpvalloc(size_t bytes) { + size_t pagesz; + ensure_initialization(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +int dlmalloc_trim(size_t pad) { + ensure_initialization(); + int result = 0; + if (!PREACTION(gm)) { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + return result; +} + +size_t dlmalloc_footprint(void) { + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) { + return gm->max_footprint; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) { + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +void dlmalloc_stats() { + internal_malloc_stats(gm); +} + +int dlmallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* !ONLY_MSPACES */ + +size_t dlmalloc_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES + +static mstate init_user_mstate(char* tbase, size_t tsize) { + size_t msize = pad_request(sizeof(struct malloc_state)); + mchunkptr mn; + mchunkptr msp = align_as_chunk(tbase); + mstate m = (mstate)(chunk2mem(msp)); + memset(m, 0, msize); + INITIAL_LOCK(&m->mutex); + msp->head = (msize|PINUSE_BIT|CINUSE_BIT); + m->seg.base = m->least_addr = tbase; + m->seg.size = m->footprint = m->max_footprint = tsize; + m->magic = mparams.magic; + m->release_checks = MAX_RELEASE_CHECK_RATE; + m->mflags = mparams.default_mflags; + m->extp = 0; + m->exts = 0; + disable_contiguous(m); + init_bins(m); + mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); + check_top_chunk(m, m->top); + return m; +} + +mspace create_mspace(size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + size_t rs = ((capacity == 0)? mparams.granularity : + (capacity + TOP_FOOT_SIZE + msize)); + size_t tsize = granularity_align(rs); + char* tbase = (char*)(CALL_MMAP(tsize)); + if (tbase != CMFAIL) { + m = init_user_mstate(tbase, tsize); + m->seg.sflags = IS_MMAPPED_BIT; + set_lock(m, locked); + } + } + return (mspace)m; +} + +mspace create_mspace_with_base(void* base, size_t capacity, int locked) { + mstate m = 0; + size_t msize; + ensure_initialization(); + msize = pad_request(sizeof(struct malloc_state)); + if (capacity > msize + TOP_FOOT_SIZE && + capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { + m = init_user_mstate((char*)base, capacity); + m->seg.sflags = EXTERN_BIT; + set_lock(m, locked); + } + return (mspace)m; +} + +int mspace_mmap_large_chunks(mspace msp, int enable) { + int ret = 0; + mstate ms = (mstate)msp; + if (!PREACTION(ms)) { + if (use_mmap(ms)) + ret = 1; + if (enable) + enable_mmap(ms); + else + disable_mmap(ms); + POSTACTION(ms); + } + return ret; +} + +size_t destroy_mspace(mspace msp) { + size_t freed = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + msegmentptr sp = &ms->seg; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + flag_t flag = sp->sflags; + sp = sp->next; + if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) && + CALL_MUNMAP(base, size) == 0) + freed += size; + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return freed; +} + +/* + mspace versions of routines are near-clones of the global + versions. This is not so nice but better than the alternatives. +*/ + + +void* mspace_malloc(mspace msp, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (!PREACTION(ms)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = ms->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(ms, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(ms, b, p, idx); + set_inuse_and_pinuse(ms, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb > ms->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(ms, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(ms, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(ms, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(ms, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + } + + if (nb <= ms->dvsize) { + size_t rsize = ms->dvsize - nb; + mchunkptr p = ms->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = ms->dv = chunk_plus_offset(p, nb); + ms->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + } + else { /* exhaust dv */ + size_t dvs = ms->dvsize; + ms->dvsize = 0; + ms->dv = 0; + set_inuse_and_pinuse(ms, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + else if (nb < ms->topsize) { /* Split top */ + size_t rsize = ms->topsize -= nb; + mchunkptr p = ms->top; + mchunkptr r = ms->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(ms, p, nb); + mem = chunk2mem(p); + check_top_chunk(ms, ms->top); + check_malloced_chunk(ms, mem, nb); + goto postaction; + } + + mem = sys_alloc(ms, nb); + + postaction: + POSTACTION(ms); + return mem; + } + + return 0; +} + +void mspace_free(mspace msp, void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); +#else /* FOOTERS */ + mstate fm = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + + if (is_small(psize)) { + insert_small_chunk(fm, p, psize); + check_free_chunk(fm, p); + } + else { + tchunkptr tp = (tchunkptr)p; + insert_large_chunk(fm, tp, psize); + check_free_chunk(fm, p); + if (--fm->release_checks == 0) + release_unused_segments(fm); + } + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +} + +void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = internal_malloc(ms, req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) + memset(mem, 0, req); + return mem; +} + +void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { + if (oldmem == 0) + return mspace_malloc(msp, bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + mspace_free(msp, oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if FOOTERS + mchunkptr p = mem2chunk(oldmem); + mstate ms = get_mstate_for(p); +#else /* FOOTERS */ + mstate ms = (mstate)msp; +#endif /* FOOTERS */ + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_realloc(ms, oldmem, bytes); + } +} + +void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return internal_memalign(ms, alignment, bytes); +} + +void** mspace_independent_calloc(mspace msp, size_t n_elements, + size_t elem_size, void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, &sz, 3, chunks); +} + +void** mspace_independent_comalloc(mspace msp, size_t n_elements, + size_t sizes[], void* chunks[]) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + return 0; + } + return ialloc(ms, n_elements, sizes, 0, chunks); +} + +int mspace_trim(mspace msp, size_t pad) { + int result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + if (!PREACTION(ms)) { + result = sys_trim(ms, pad); + POSTACTION(ms); + } + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + +void mspace_malloc_stats(mspace msp) { + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + internal_malloc_stats(ms); + } + else { + USAGE_ERROR_ACTION(ms,ms); + } +} + +size_t mspace_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + + +size_t mspace_max_footprint(mspace msp) { + size_t result = 0; + mstate ms = (mstate)msp; + if (ok_magic(ms)) { + result = ms->max_footprint; + } + else { + USAGE_ERROR_ACTION(ms,ms); + } + return result; +} + + +#if !NO_MALLINFO +struct mallinfo mspace_mallinfo(mspace msp) { + mstate ms = (mstate)msp; + if (!ok_magic(ms)) { + USAGE_ERROR_ACTION(ms,ms); + } + return internal_mallinfo(ms); +} +#endif /* NO_MALLINFO */ + +size_t mspace_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +int mspace_mallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* MSPACES */ + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + V2.8.4 (not yet released) + * Add mspace_mmap_large_chunks; thanks to Jean Brouwers + * Fix insufficient sys_alloc padding when using 16byte alignment + * Fix bad error check in mspace_footprint + * Adaptations for ptmalloc, courtesy of Wolfram Gloger. + * Reentrant spin locks, courtesy of Earl Chew and others + * Win32 improvements, courtesy of Niall Douglas and Earl Chew + * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options + * Extension hook in malloc_state + * Various small adjustments to reduce warnings on some compilers + * Various configuration extensions/changes for more platforms. Thanks + to all who contributed these. + + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ + + diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c new file mode 100644 index 0000000000..a381a7df36 --- /dev/null +++ b/compat/nedmalloc/nedmalloc.c @@ -0,0 +1,966 @@ +/* Alternative malloc implementation for multiple threads without +lock contention based on dlmalloc. (C) 2005-2006 Niall Douglas + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#ifdef _MSC_VER +/* Enable full aliasing on MSVC */ +/*#pragma optimize("a", on)*/ +#endif + +/*#define FULLSANITYCHECKS*/ + +#include "nedmalloc.h" +#if defined(WIN32) && !defined(__MINGW32__) + #include +#endif +#define MSPACES 1 +#define ONLY_MSPACES 1 +#ifndef USE_LOCKS + #define USE_LOCKS 1 +#endif +#define FOOTERS 1 /* Need to enable footers so frees lock the right mspace */ +#undef DEBUG /* dlmalloc wants DEBUG either 0 or 1 */ +#ifdef _DEBUG + #define DEBUG 1 +#else + #define DEBUG 0 +#endif +#ifdef NDEBUG /* Disable assert checking on release builds */ + #undef DEBUG +#endif +/* The default of 64Kb means we spend too much time kernel-side */ +#ifndef DEFAULT_GRANULARITY +#define DEFAULT_GRANULARITY (1*1024*1024) +#endif +/*#define USE_SPIN_LOCKS 0*/ + + +/*#define FORCEINLINE*/ +#include "malloc.c.h" +#ifdef NDEBUG /* Disable assert checking on release builds */ + #undef DEBUG +#endif + +/* The maximum concurrent threads in a pool possible */ +#ifndef MAXTHREADSINPOOL +#define MAXTHREADSINPOOL 16 +#endif +/* The maximum number of threadcaches which can be allocated */ +#ifndef THREADCACHEMAXCACHES +#define THREADCACHEMAXCACHES 256 +#endif +/* The maximum size to be allocated from the thread cache */ +#ifndef THREADCACHEMAX +#define THREADCACHEMAX 8192 +#endif +#if 0 +/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */ +#define THREADCACHEMAXBINS ((13-4)*2) +#else +/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */ +#define THREADCACHEMAXBINS (13-4) +#endif +/* Point at which the free space in a thread cache is garbage collected */ +#ifndef THREADCACHEMAXFREESPACE +#define THREADCACHEMAXFREESPACE (512*1024) +#endif + + +#ifdef WIN32 + #define TLSVAR DWORD + #define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k)) + #define TLSFREE(k) (!TlsFree(k)) + #define TLSGET(k) TlsGetValue(k) + #define TLSSET(k, a) (!TlsSetValue(k, a)) + #ifdef DEBUG +static LPVOID ChkedTlsGetValue(DWORD idx) +{ + LPVOID ret=TlsGetValue(idx); + assert(S_OK==GetLastError()); + return ret; +} + #undef TLSGET + #define TLSGET(k) ChkedTlsGetValue(k) + #endif +#else + #define TLSVAR pthread_key_t + #define TLSALLOC(k) pthread_key_create(k, 0) + #define TLSFREE(k) pthread_key_delete(k) + #define TLSGET(k) pthread_getspecific(k) + #define TLSSET(k, a) pthread_setspecific(k, a) +#endif + +#if 0 +/* Only enable if testing with valgrind. Causes misoperation */ +#define mspace_malloc(p, s) malloc(s) +#define mspace_realloc(p, m, s) realloc(m, s) +#define mspace_calloc(p, n, s) calloc(n, s) +#define mspace_free(p, m) free(m) +#endif + + +#if defined(__cplusplus) +#if !defined(NO_NED_NAMESPACE) +namespace nedalloc { +#else +extern "C" { +#endif +#endif + +size_t nedblksize(void *mem) THROWSPEC +{ +#if 0 + /* Only enable if testing with valgrind. Causes misoperation */ + return THREADCACHEMAX; +#else + if(mem) + { + mchunkptr p=mem2chunk(mem); + assert(cinuse(p)); /* If this fails, someone tried to free a block twice */ + if(cinuse(p)) + return chunksize(p)-overhead_for(p); + } + return 0; +#endif +} + +void nedsetvalue(void *v) THROWSPEC { nedpsetvalue(0, v); } +void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc(0, size); } +void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc(0, no, size); } +void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc(0, mem, size); } +void nedfree(void *mem) THROWSPEC { nedpfree(0, mem); } +void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign(0, alignment, bytes); } +#if !NO_MALLINFO +struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); } +#endif +int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); } +int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); } +void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); } +size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); } +void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); } +void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); } + +struct threadcacheblk_t; +typedef struct threadcacheblk_t threadcacheblk; +struct threadcacheblk_t +{ /* Keep less than 16 bytes on 32 bit systems and 32 bytes on 64 bit systems */ +#ifdef FULLSANITYCHECKS + unsigned int magic; +#endif + unsigned int lastUsed, size; + threadcacheblk *next, *prev; +}; +typedef struct threadcache_t +{ +#ifdef FULLSANITYCHECKS + unsigned int magic1; +#endif + int mymspace; /* Last mspace entry this thread used */ + long threadid; + unsigned int mallocs, frees, successes; + size_t freeInCache; /* How much free space is stored in this cache */ + threadcacheblk *bins[(THREADCACHEMAXBINS+1)*2]; +#ifdef FULLSANITYCHECKS + unsigned int magic2; +#endif +} threadcache; +struct nedpool_t +{ + MLOCK_T mutex; + void *uservalue; + int threads; /* Max entries in m to use */ + threadcache *caches[THREADCACHEMAXCACHES]; + TLSVAR mycache; /* Thread cache for this thread. 0 for unset, negative for use mspace-1 directly, otherwise is cache-1 */ + mstate m[MAXTHREADSINPOOL+1]; /* mspace entries for this pool */ +}; +static nedpool syspool; + +static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC +{ /* 8=1000 16=10000 20=10100 24=11000 32=100000 48=110000 4096=1000000000000 */ + unsigned int topbit, size=(unsigned int)(_size>>4); + /* 16=1 20=1 24=1 32=10 48=11 64=100 96=110 128=1000 4096=100000000 */ + +#if defined(__GNUC__) + topbit = sizeof(size)*__CHAR_BIT__ - 1 - __builtin_clz(size); +#elif defined(_MSC_VER) && _MSC_VER>=1300 + { + unsigned long bsrTopBit; + + _BitScanReverse(&bsrTopBit, size); + + topbit = bsrTopBit; + } +#else +#if 0 + union { + unsigned asInt[2]; + double asDouble; + }; + int n; + + asDouble = (double)size + 0.5; + topbit = (asInt[!FOX_BIGENDIAN] >> 20) - 1023; +#else + { + unsigned int x=size; + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >>16); + x = ~x; + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x = x + (x << 8); + x = x + (x << 16); + topbit=31 - (x >> 24); + } +#endif +#endif + return topbit; +} + + +#ifdef FULLSANITYCHECKS +static void tcsanitycheck(threadcacheblk **ptr) THROWSPEC +{ + assert((ptr[0] && ptr[1]) || (!ptr[0] && !ptr[1])); + if(ptr[0] && ptr[1]) + { + assert(nedblksize(ptr[0])>=sizeof(threadcacheblk)); + assert(nedblksize(ptr[1])>=sizeof(threadcacheblk)); + assert(*(unsigned int *) "NEDN"==ptr[0]->magic); + assert(*(unsigned int *) "NEDN"==ptr[1]->magic); + assert(!ptr[0]->prev); + assert(!ptr[1]->next); + if(ptr[0]==ptr[1]) + { + assert(!ptr[0]->next); + assert(!ptr[1]->prev); + } + } +} +static void tcfullsanitycheck(threadcache *tc) THROWSPEC +{ + threadcacheblk **tcbptr=tc->bins; + int n; + for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2) + { + threadcacheblk *b, *ob=0; + tcsanitycheck(tcbptr); + for(b=tcbptr[0]; b; ob=b, b=b->next) + { + assert(*(unsigned int *) "NEDN"==b->magic); + assert(!ob || ob->next==b); + assert(!ob || b->prev==ob); + } + } +} +#endif + +static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC +{ +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + if(tc->freeInCache) + { + threadcacheblk **tcbptr=tc->bins; + int n; + for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2) + { + threadcacheblk **tcb=tcbptr+1; /* come from oldest end of list */ + /*tcsanitycheck(tcbptr);*/ + for(; *tcb && tc->frees-(*tcb)->lastUsed>=age; ) + { + threadcacheblk *f=*tcb; + size_t blksize=f->size; /*nedblksize(f);*/ + assert(blksize<=nedblksize(f)); + assert(blksize); +#ifdef FULLSANITYCHECKS + assert(*(unsigned int *) "NEDN"==(*tcb)->magic); +#endif + *tcb=(*tcb)->prev; + if(*tcb) + (*tcb)->next=0; + else + *tcbptr=0; + tc->freeInCache-=blksize; + assert((long) tc->freeInCache>=0); + mspace_free(0, f); + /*tcsanitycheck(tcbptr);*/ + } + } + } +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif +} +static void DestroyCaches(nedpool *p) THROWSPEC +{ + if(p->caches) + { + threadcache *tc; + int n; + for(n=0; ncaches[n])) + { + tc->frees++; + RemoveCacheEntries(p, tc, 0); + assert(!tc->freeInCache); + tc->mymspace=-1; + tc->threadid=0; + mspace_free(0, tc); + p->caches[n]=0; + } + } + } +} + +static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC +{ + threadcache *tc=0; + int n, end; + ACQUIRE_LOCK(&p->mutex); + for(n=0; ncaches[n]; n++); + if(THREADCACHEMAXCACHES==n) + { /* List exhausted, so disable for this thread */ + RELEASE_LOCK(&p->mutex); + return 0; + } + tc=p->caches[n]=(threadcache *) mspace_calloc(p->m[0], 1, sizeof(threadcache)); + if(!tc) + { + RELEASE_LOCK(&p->mutex); + return 0; + } +#ifdef FULLSANITYCHECKS + tc->magic1=*(unsigned int *)"NEDMALC1"; + tc->magic2=*(unsigned int *)"NEDMALC2"; +#endif + tc->threadid=(long)(size_t)CURRENT_THREAD; + for(end=0; p->m[end]; end++); + tc->mymspace=tc->threadid % end; + RELEASE_LOCK(&p->mutex); + if(TLSSET(p->mycache, (void *)(size_t)(n+1))) abort(); + return tc; +} + +static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROWSPEC +{ + void *ret=0; + unsigned int bestsize; + unsigned int idx=size2binidx(*size); + size_t blksize=0; + threadcacheblk *blk, **binsptr; +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + /* Calculate best fit bin size */ + bestsize=1<<(idx+4); +#if 0 + /* Finer grained bin fit */ + idx<<=1; + if(*size>bestsize) + { + idx++; + bestsize+=bestsize>>1; + } + if(*size>bestsize) + { + idx++; + bestsize=1<<(4+(idx>>1)); + } +#else + if(*size>bestsize) + { + idx++; + bestsize<<=1; + } +#endif + assert(bestsize>=*size); + if(*sizebins[idx*2]; + /* Try to match close, but move up a bin if necessary */ + blk=*binsptr; + if(!blk || blk->size<*size) + { /* Bump it up a bin */ + if(idxsize; /*nedblksize(blk);*/ + assert(nedblksize(blk)>=blksize); + assert(blksize>=*size); + if(blk->next) + blk->next->prev=0; + *binsptr=blk->next; + if(!*binsptr) + binsptr[1]=0; +#ifdef FULLSANITYCHECKS + blk->magic=0; +#endif + assert(binsptr[0]!=blk && binsptr[1]!=blk); + assert(nedblksize(blk)>=sizeof(threadcacheblk) && nedblksize(blk)<=THREADCACHEMAX+CHUNK_OVERHEAD); + /*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) size);*/ + ret=(void *) blk; + } + ++tc->mallocs; + if(ret) + { + assert(blksize>=*size); + ++tc->successes; + tc->freeInCache-=blksize; + assert((long) tc->freeInCache>=0); + } +#if defined(DEBUG) && 0 + if(!(tc->mallocs & 0xfff)) + { + printf("*** threadcache=%u, mallocs=%u (%f), free=%u (%f), freeInCache=%u\n", (unsigned int) tc->threadid, tc->mallocs, + (float) tc->successes/tc->mallocs, tc->frees, (float) tc->successes/tc->frees, (unsigned int) tc->freeInCache); + } +#endif +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + return ret; +} +static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspace) THROWSPEC +{ + unsigned int age=THREADCACHEMAXFREESPACE/8192; + /*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/ + while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE) + { + RemoveCacheEntries(p, tc, age); + /*printf("*** Removing cache entries older than %u (%u)\n", age, (unsigned int) tc->freeInCache);*/ + age>>=1; + } + /*RELEASE_LOCK(&p->m[mymspace]->mutex);*/ +} +static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *mem, size_t size) THROWSPEC +{ + unsigned int bestsize; + unsigned int idx=size2binidx(size); + threadcacheblk **binsptr, *tck=(threadcacheblk *) mem; + assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD); +#ifdef DEBUG + { /* Make sure this is a valid memory block */ + mchunkptr p = mem2chunk(mem); + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } + } +#endif +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif + /* Calculate best fit bin size */ + bestsize=1<<(idx+4); +#if 0 + /* Finer grained bin fit */ + idx<<=1; + if(size>bestsize) + { + unsigned int biggerbestsize=bestsize+bestsize<<1; + if(size>=biggerbestsize) + { + idx++; + bestsize=biggerbestsize; + } + } +#endif + if(bestsize!=size) /* dlmalloc can round up, so we round down to preserve indexing */ + size=bestsize; + binsptr=&tc->bins[idx*2]; + assert(idx<=THREADCACHEMAXBINS); + if(tck==*binsptr) + { + fprintf(stderr, "Attempt to free already freed memory block %p - aborting!\n", tck); + abort(); + } +#ifdef FULLSANITYCHECKS + tck->magic=*(unsigned int *) "NEDN"; +#endif + tck->lastUsed=++tc->frees; + tck->size=(unsigned int) size; + tck->next=*binsptr; + tck->prev=0; + if(tck->next) + tck->next->prev=tck; + else + binsptr[1]=tck; + assert(!*binsptr || (*binsptr)->size==tck->size); + *binsptr=tck; + assert(tck==tc->bins[idx*2]); + assert(tc->bins[idx*2+1]==tck || binsptr[0]->next->prev==tck); + /*printf("free: %p, %p, %p, %lu\n", p, tc, mem, (long) size);*/ + tc->freeInCache+=size; +#ifdef FULLSANITYCHECKS + tcfullsanitycheck(tc); +#endif +#if 1 + if(tc->freeInCache>=THREADCACHEMAXFREESPACE) + ReleaseFreeInCache(p, tc, mymspace); +#endif +} + + + + +static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC +{ /* threads is -1 for system pool */ + ensure_initialization(); + ACQUIRE_MALLOC_GLOBAL_LOCK(); + if(p->threads) goto done; + if(INITIAL_LOCK(&p->mutex)) goto err; + if(TLSALLOC(&p->mycache)) goto err; + if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err; + p->m[0]->extp=p; + p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads; +done: + RELEASE_MALLOC_GLOBAL_LOCK(); + return 1; +err: + if(threads<0) + abort(); /* If you can't allocate for system pool, we're screwed */ + DestroyCaches(p); + if(p->m[0]) + { + destroy_mspace(p->m[0]); + p->m[0]=0; + } + if(p->mycache) + { + if(TLSFREE(p->mycache)) abort(); + p->mycache=0; + } + RELEASE_MALLOC_GLOBAL_LOCK(); + return 0; +} +static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, size_t size) THROWSPEC +{ /* Gets called when thread's last used mspace is in use. The strategy + is to run through the list of all available mspaces looking for an + unlocked one and if we fail, we create a new one so long as we don't + exceed p->threads */ + int n, end; + for(n=end=*lastUsed+1; p->m[n]; end=++n) + { + if(TRY_LOCK(&p->m[n]->mutex)) goto found; + } + for(n=0; n<*lastUsed && p->m[n]; n++) + { + if(TRY_LOCK(&p->m[n]->mutex)) goto found; + } + if(endthreads) + { + mstate temp; + if(!(temp=(mstate) create_mspace(size, 1))) + goto badexit; + /* Now we're ready to modify the lists, we lock */ + ACQUIRE_LOCK(&p->mutex); + while(p->m[end] && endthreads) + end++; + if(end>=p->threads) + { /* Drat, must destroy it now */ + RELEASE_LOCK(&p->mutex); + destroy_mspace((mspace) temp); + goto badexit; + } + /* We really want to make sure this goes into memory now but we + have to be careful of breaking aliasing rules, so write it twice */ + *((volatile struct malloc_state **) &p->m[end])=p->m[end]=temp; + ACQUIRE_LOCK(&p->m[end]->mutex); + /*printf("Created mspace idx %d\n", end);*/ + RELEASE_LOCK(&p->mutex); + n=end; + goto found; + } + /* Let it lock on the last one it used */ +badexit: + ACQUIRE_LOCK(&p->m[*lastUsed]->mutex); + return p->m[*lastUsed]; +found: + *lastUsed=n; + if(tc) + tc->mymspace=n; + else + { + if(TLSSET(p->mycache, (void *)(size_t)(-(n+1)))) abort(); + } + return p->m[n]; +} + +nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC +{ + nedpool *ret; + if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) return 0; + if(!InitPool(ret, capacity, threads)) + { + nedpfree(0, ret); + return 0; + } + return ret; +} +void neddestroypool(nedpool *p) THROWSPEC +{ + int n; + ACQUIRE_LOCK(&p->mutex); + DestroyCaches(p); + for(n=0; p->m[n]; n++) + { + destroy_mspace(p->m[n]); + p->m[n]=0; + } + RELEASE_LOCK(&p->mutex); + if(TLSFREE(p->mycache)) abort(); + nedpfree(0, p); +} + +void nedpsetvalue(nedpool *p, void *v) THROWSPEC +{ + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + p->uservalue=v; +} +void *nedgetvalue(nedpool **p, void *mem) THROWSPEC +{ + nedpool *np=0; + mchunkptr mcp=mem2chunk(mem); + mstate fm; + if(!(is_aligned(chunk2mem(mcp))) && mcp->head != FENCEPOST_HEAD) return 0; + if(!cinuse(mcp)) return 0; + if(!next_pinuse(mcp)) return 0; + if(!is_mmapped(mcp) && !pinuse(mcp)) + { + if(next_chunk(prev_chunk(mcp))!=mcp) return 0; + } + fm=get_mstate_for(mcp); + if(!ok_magic(fm)) return 0; + if(!ok_address(fm, mcp)) return 0; + if(!fm->extp) return 0; + np=(nedpool *) fm->extp; + if(p) *p=np; + return np->uservalue; +} + +void neddisablethreadcache(nedpool *p) THROWSPEC +{ + int mycache; + if(!p) + { + p=&syspool; + if(!syspool.threads) InitPool(&syspool, 0, -1); + } + mycache=(int)(size_t) TLSGET(p->mycache); + if(!mycache) + { /* Set to mspace 0 */ + if(TLSSET(p->mycache, (void *)-1)) abort(); + } + else if(mycache>0) + { /* Set to last used mspace */ + threadcache *tc=p->caches[mycache-1]; +#if defined(DEBUG) + printf("Threadcache utilisation: %lf%% in cache with %lf%% lost to other threads\n", + 100.0*tc->successes/tc->mallocs, 100.0*((double) tc->mallocs-tc->frees)/tc->mallocs); +#endif + if(TLSSET(p->mycache, (void *)(size_t)(-tc->mymspace))) abort(); + tc->frees++; + RemoveCacheEntries(p, tc, 0); + assert(!tc->freeInCache); + tc->mymspace=-1; + tc->threadid=0; + mspace_free(0, p->caches[mycache-1]); + p->caches[mycache-1]=0; + } +} + +#define GETMSPACE(m,p,tc,ms,s,action) \ + do \ + { \ + mstate m = GetMSpace((p),(tc),(ms),(s)); \ + action; \ + RELEASE_LOCK(&m->mutex); \ + } while (0) + +static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC +{ /* Returns a locked and ready for use mspace */ + mstate m=p->m[mymspace]; + assert(m); + if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);\ + /*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/ + return m; +} +static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC +{ + int mycache; + if(size && *sizemycache); + if(mycache>0) + { + *tc=(*p)->caches[mycache-1]; + *mymspace=(*tc)->mymspace; + } + else if(!mycache) + { + *tc=AllocCache(*p); + if(!*tc) + { /* Disable */ + if(TLSSET((*p)->mycache, (void *)-1)) abort(); + *mymspace=0; + } + else + *mymspace=(*tc)->mymspace; + } + else + { + *tc=0; + *mymspace=-mycache-1; + } + assert(*mymspace>=0); + assert((long)(size_t)CURRENT_THREAD==(*tc)->threadid); +#ifdef FULLSANITYCHECKS + if(*tc) + { + if(*(unsigned int *)"NEDMALC1"!=(*tc)->magic1 || *(unsigned int *)"NEDMALC2"!=(*tc)->magic2) + { + abort(); + } + } +#endif +} + +void * nedpmalloc(nedpool *p, size_t size) THROWSPEC +{ + void *ret=0; + threadcache *tc; + int mymspace; + GetThreadCache(&p, &tc, &mymspace, &size); +#if THREADCACHEMAX + if(tc && size<=THREADCACHEMAX) + { /* Use the thread cache */ + ret=threadcache_malloc(p, tc, &size); + } +#endif + if(!ret) + { /* Use this thread's mspace */ + GETMSPACE(m, p, tc, mymspace, size, + ret=mspace_malloc(m, size)); + } + return ret; +} +void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC +{ + size_t rsize=size*no; + void *ret=0; + threadcache *tc; + int mymspace; + GetThreadCache(&p, &tc, &mymspace, &rsize); +#if THREADCACHEMAX + if(tc && rsize<=THREADCACHEMAX) + { /* Use the thread cache */ + if((ret=threadcache_malloc(p, tc, &rsize))) + memset(ret, 0, rsize); + } +#endif + if(!ret) + { /* Use this thread's mspace */ + GETMSPACE(m, p, tc, mymspace, rsize, + ret=mspace_calloc(m, 1, rsize)); + } + return ret; +} +void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC +{ + void *ret=0; + threadcache *tc; + int mymspace; + if(!mem) return nedpmalloc(p, size); + GetThreadCache(&p, &tc, &mymspace, &size); +#if THREADCACHEMAX + if(tc && size && size<=THREADCACHEMAX) + { /* Use the thread cache */ + size_t memsize=nedblksize(mem); + assert(memsize); + if((ret=threadcache_malloc(p, tc, &size))) + { + memcpy(ret, mem, memsizem[n]; n++) + { + struct mallinfo t=mspace_mallinfo(p->m[n]); + ret.arena+=t.arena; + ret.ordblks+=t.ordblks; + ret.hblkhd+=t.hblkhd; + ret.usmblks+=t.usmblks; + ret.uordblks+=t.uordblks; + ret.fordblks+=t.fordblks; + ret.keepcost+=t.keepcost; + } + return ret; +} +#endif +int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC +{ + return mspace_mallopt(parno, value); +} +int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC +{ + int n, ret=0; + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + for(n=0; p->m[n]; n++) + { + ret+=mspace_trim(p->m[n], pad); + } + return ret; +} +void nedpmalloc_stats(nedpool *p) THROWSPEC +{ + int n; + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + for(n=0; p->m[n]; n++) + { + mspace_malloc_stats(p->m[n]); + } +} +size_t nedpmalloc_footprint(nedpool *p) THROWSPEC +{ + size_t ret=0; + int n; + if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); } + for(n=0; p->m[n]; n++) + { + ret+=mspace_footprint(p->m[n]); + } + return ret; +} +void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC +{ + void **ret; + threadcache *tc; + int mymspace; + GetThreadCache(&p, &tc, &mymspace, &elemsize); + GETMSPACE(m, p, tc, mymspace, elemsno*elemsize, + ret=mspace_independent_calloc(m, elemsno, elemsize, chunks)); + return ret; +} +void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC +{ + void **ret; + threadcache *tc; + int mymspace; + size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t)); + if(!adjustedsizes) return 0; + for(i=0; i /* for size_t */ + +#ifndef EXTSPEC + #define EXTSPEC extern +#endif + +#if defined(_MSC_VER) && _MSC_VER>=1400 + #define MALLOCATTR __declspec(restrict) +#endif +#ifdef __GNUC__ + #define MALLOCATTR __attribute__ ((malloc)) +#endif +#ifndef MALLOCATTR + #define MALLOCATTR +#endif + +#ifdef REPLACE_SYSTEM_ALLOCATOR + #define nedmalloc malloc + #define nedcalloc calloc + #define nedrealloc realloc + #define nedfree free + #define nedmemalign memalign + #define nedmallinfo mallinfo + #define nedmallopt mallopt + #define nedmalloc_trim malloc_trim + #define nedmalloc_stats malloc_stats + #define nedmalloc_footprint malloc_footprint + #define nedindependent_calloc independent_calloc + #define nedindependent_comalloc independent_comalloc + #ifdef _MSC_VER + #define nedblksize _msize + #endif +#endif + +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif + +#if !NO_MALLINFO +struct mallinfo; +#endif + +#if defined(__cplusplus) + #if !defined(NO_NED_NAMESPACE) +namespace nedalloc { + #else +extern "C" { + #endif + #define THROWSPEC throw() +#else + #define THROWSPEC +#endif + +/* These are the global functions */ + +/* Gets the usable size of an allocated block. Note this will always be bigger than what was +asked for due to rounding etc. +*/ +EXTSPEC size_t nedblksize(void *mem) THROWSPEC; + +EXTSPEC void nedsetvalue(void *v) THROWSPEC; + +EXTSPEC MALLOCATTR void * nedmalloc(size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedcalloc(size_t no, size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedrealloc(void *mem, size_t size) THROWSPEC; +EXTSPEC void nedfree(void *mem) THROWSPEC; +EXTSPEC MALLOCATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC; +#if !NO_MALLINFO +EXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC; +#endif +EXTSPEC int nedmallopt(int parno, int value) THROWSPEC; +EXTSPEC int nedmalloc_trim(size_t pad) THROWSPEC; +EXTSPEC void nedmalloc_stats(void) THROWSPEC; +EXTSPEC size_t nedmalloc_footprint(void) THROWSPEC; +EXTSPEC MALLOCATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC; +EXTSPEC MALLOCATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC; + +/* These are the pool functions */ +struct nedpool_t; +typedef struct nedpool_t nedpool; + +/* Creates a memory pool for use with the nedp* functions below. +Capacity is how much to allocate immediately (if you know you'll be allocating a lot +of memory very soon) which you can leave at zero. Threads specifies how many threads +will *normally* be accessing the pool concurrently. Setting this to zero means it +extends on demand, but be careful of this as it can rapidly consume system resources +where bursts of concurrent threads use a pool at once. +*/ +EXTSPEC MALLOCATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC; + +/* Destroys a memory pool previously created by nedcreatepool(). +*/ +EXTSPEC void neddestroypool(nedpool *p) THROWSPEC; + +/* Sets a value to be associated with a pool. You can retrieve this value by passing +any memory block allocated from that pool. +*/ +EXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC; +/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown. +Optionally can also retrieve pool. +*/ +EXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC; + +/* Disables the thread cache for the calling thread, returning any existing cache +data to the central pool. +*/ +EXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC; + +EXTSPEC MALLOCATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC; +EXTSPEC MALLOCATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC; +EXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC; +EXTSPEC MALLOCATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC; +#if !NO_MALLINFO +EXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC; +#endif +EXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC; +EXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC; +EXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC; +EXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC; +EXTSPEC MALLOCATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC; +EXTSPEC MALLOCATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC; + +#if defined(__cplusplus) +} +#endif + +#undef MALLOCATTR +#undef EXTSPEC + +#endif From 1afce7945356c2b23caa346ef2e5d9aefb43f458 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Wed, 8 Apr 2009 23:01:47 +0200 Subject: [PATCH 570/781] MinGW readdir reimplementation to support d_type The original readdir implementation was fast, but didn't support the d_type. This means that git would do additional lstats for each entry, to figure out if the entry was a directory or not. This unneedingly slowed down many operations, since Windows API provides this information directly when walking the directories. By running this implementation on Moe's repo structure: mkdir bummer && cd bummer; for ((i=0;i<100;i++)); do mkdir $i && pushd $i; for ((j=0;j<1000;j++)); do echo "$j" >$j; done; popd; done We see the following speedups: git add . ------------------- old: 00:00:23(.087) new: 00:00:21(.512) 1.07x git status ------------------- old: 00:00:03(.306) new: 00:00:01(.684) 1.96x git clean -dxf ------------------- old: 00:00:01(.918) new: 00:00:00(.295) 6.50x Signed-off-by: Marius Storm-Olsen --- compat/mingw.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ compat/mingw.h | 29 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 2ab5bbec1f..2951f33d43 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1172,3 +1172,62 @@ char *getpass(const char *prompt) fputs("\n", stderr); return strbuf_detach(&buf, NULL); } + +#ifndef NO_MINGW_REPLACE_READDIR +/* MinGW readdir implementation to avoid extra lstats for Git */ +struct mingw_DIR +{ + struct _finddata_t dd_dta; /* disk transfer area for this dir */ + struct mingw_dirent dd_dir; /* Our own implementation, including d_type */ + long dd_handle; /* _findnext handle */ + int dd_stat; /* 0 = next entry to read is first entry, -1 = off the end, positive = 0 based index of next entry */ + char dd_name[1]; /* given path for dir with search pattern (struct is extended) */ +}; + +struct dirent *mingw_readdir(DIR *dir) +{ + WIN32_FIND_DATAA buf; + HANDLE handle; + struct mingw_DIR *mdir = (struct mingw_DIR*)dir; + + if (!dir->dd_handle) { + errno = EBADF; /* No set_errno for mingw */ + return NULL; + } + + if (dir->dd_handle == (long)INVALID_HANDLE_VALUE && dir->dd_stat == 0) + { + handle = FindFirstFileA(dir->dd_name, &buf); + DWORD lasterr = GetLastError(); + dir->dd_handle = (long)handle; + if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { + errno = err_win_to_posix(lasterr); + return NULL; + } + } else if (dir->dd_handle == (long)INVALID_HANDLE_VALUE) { + return NULL; + } else if (!FindNextFileA((HANDLE)dir->dd_handle, &buf)) { + DWORD lasterr = GetLastError(); + FindClose((HANDLE)dir->dd_handle); + dir->dd_handle = (long)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 */ + mdir->dd_dir.d_type = 0; + if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mdir->dd_dir.d_type |= DT_DIR; + else + mdir->dd_dir.d_type |= DT_REG; + + return (struct dirent*)&dir->dd_dir; +} +#endif // !NO_MINGW_REPLACE_READDIR diff --git a/compat/mingw.h b/compat/mingw.h index b1156b865e..1b91399f40 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -233,3 +233,32 @@ int main(int argc, const char **argv) \ return mingw_main(argc, argv); \ } \ static int mingw_main(c,v) + +#ifndef NO_MINGW_REPLACE_READDIR +/* + * A replacement of readdir, to ensure that it reads the file type at + * the same time. This avoid extra unneeded lstats in git on MinGW + */ +#undef DT_UNKNOWN +#undef DT_DIR +#undef DT_REG +#undef DT_LNK +#define DT_UNKNOWN 0 +#define DT_DIR 1 +#define DT_REG 2 +#define DT_LNK 3 + +struct mingw_dirent +{ + long d_ino; /* Always zero. */ + union { + unsigned short d_reclen; /* Always zero. */ + unsigned char d_type; /* Reimplementation adds this */ + }; + unsigned short d_namlen; /* Length of name in d_name. */ + char d_name[FILENAME_MAX]; /* File name. */ +}; +#define dirent mingw_dirent +#define readdir(x) mingw_readdir(x) +struct dirent *mingw_readdir(DIR *dir); +#endif // !NO_MINGW_REPLACE_READDIR From c893961d488d8e3ecb7dbcfdb3591bc151b4c9bf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 4 May 2009 16:45:46 +0200 Subject: [PATCH 571/781] test-chmtime: work around Windows limitation Windows has problems changing the mtime when the file is write protected, even by the owner of said file. Add a Windows-only workaround to change the mode if necessary before trying to change the mtime. Signed-off-by: Johannes Schindelin --- test-chmtime.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test-chmtime.c b/test-chmtime.c index d5358cbaac..fe476cb618 100644 --- a/test-chmtime.c +++ b/test-chmtime.c @@ -87,6 +87,15 @@ int main(int argc, const char *argv[]) return -1; } +#ifdef WIN32 + if (!(sb.st_mode & S_IWUSR) && + chmod(argv[i], sb.st_mode | S_IWUSR)) { + fprintf(stderr, "Could not make user-writable %s: %s", + argv[i], strerror(errno)); + return -1; + } +#endif + utb.actime = sb.st_atime; utb.modtime = set_eq ? set_time : sb.st_mtime + set_time; From 4f372b5e306c8b0745d8fced630d073d2acb4c74 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:30:33 +0200 Subject: [PATCH 572/781] Fix warnings in nedmalloc when compiling with GCC 4.4.0 Signed-off-by: Johannes Schindelin --- compat/nedmalloc/malloc.c.h | 4 +++- compat/nedmalloc/nedmalloc.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index 1d9bbe0aba..678beb821a 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -1270,7 +1270,9 @@ int mspace_mallopt(int, int); /*------------------------------ internal #includes ---------------------- */ #ifdef WIN32 +#ifndef __GNUC__ #pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif #endif /* WIN32 */ #include /* for printing in malloc_stats */ @@ -2541,7 +2543,7 @@ struct malloc_params { static struct malloc_params mparams; /* Ensure mparams initialized */ -#define ensure_initialization() (mparams.magic != 0 || init_mparams()) +#define ensure_initialization() if (mparams.magic == 0) init_mparams() #if !ONLY_MSPACES diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index a381a7df36..60a40934af 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -34,7 +34,7 @@ DEALINGS IN THE SOFTWARE. /*#define FULLSANITYCHECKS*/ #include "nedmalloc.h" -#if defined(WIN32) && !defined(__MINGW32__) +#if defined(WIN32) #include #endif #define MSPACES 1 From 5dae887ff1468189d8c900440e30db97d03d8f12 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:31:17 +0200 Subject: [PATCH 573/781] MinGW: Fix compiler warning in merge-recursive GCC 4.4.0 on Windows does not like the format %zu. It is quite unlikely, though, that we need more merge bases than a %d can display, so replace the %zu by a %d. Signed-off-by: Johannes Schindelin --- builtin-merge-recursive.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 703045bfc8..d26a96e486 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -45,8 +45,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) bases[bases_count++] = sha; } else - warning("Cannot handle more than %zu bases. " - "Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]); + warning("Cannot handle more than %d bases. " + "Ignoring %s.", + (int)ARRAY_SIZE(bases)-1, argv[i]); } if (argc - i != 3) /* "--" "" "" */ die("Not handling anything other than two heads merge."); From 3c0d7263c5d0fd4c7fd7db50b189a2bc1959ac0f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:45:59 +0200 Subject: [PATCH 574/781] MinGW: declare getpass() Signed-off-by: Johannes Schindelin --- compat/mingw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compat/mingw.h b/compat/mingw.h index 1b91399f40..4f7ba4c13f 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -38,6 +38,8 @@ struct passwd { char *pw_dir; }; +extern char *getpass(const char *prompt); + struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ From d9215c962be9e94721f6a5565da46891a157f249 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:46:48 +0200 Subject: [PATCH 575/781] winansi: fix compile warnings Signed-off-by: Johannes Schindelin --- compat/win32.h | 1 + compat/winansi.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/win32.h b/compat/win32.h index c26384e595..d531130b12 100644 --- a/compat/win32.h +++ b/compat/win32.h @@ -1,5 +1,6 @@ /* common Win32 functions for MinGW and Cygwin */ #include +#include static inline int file_attr_to_st_mode (DWORD attr) { diff --git a/compat/winansi.c b/compat/winansi.c index 4bee335f9e..9217c24b43 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -80,7 +80,7 @@ static void set_console_attr(void) static void erase_in_line(void) { CONSOLE_SCREEN_BUFFER_INFO sbi; - long dummy; /* Needed for Windows 7 (or Vista) regression */ + DWORD dummy; /* Needed for Windows 7 (or Vista) regression */ if (!console) return; From 9b69cf132266161bbb96a705df15808f3ae3e56f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 7 May 2009 14:47:21 +0200 Subject: [PATCH 576/781] Shut up GCC 4.4.0 GCC babbles something about "type-punned" pointers. Just add an extra layer of casting to avoid the warning. Signed-off-by: Johannes Schindelin --- decorate.c | 3 ++- object.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/decorate.c b/decorate.c index 82d9e221ea..a216001dd8 100644 --- a/decorate.c +++ b/decorate.c @@ -8,7 +8,8 @@ static unsigned int hash_obj(const struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + const void *p = obj->sha1; + unsigned int hash = *(const unsigned int *)p; return hash % n; } diff --git a/object.c b/object.c index 7e6a92c88e..ce294241d3 100644 --- a/object.c +++ b/object.c @@ -45,7 +45,8 @@ int type_from_string(const char *str) static unsigned int hash_obj(struct object *obj, unsigned int n) { - unsigned int hash = *(unsigned int *)obj->sha1; + const void *p = obj->sha1; + unsigned int hash = *(const unsigned int *)p; return hash % n; } From fdffdb2ddbf05442dd2662937e62258991e4b28c Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 18 May 2009 12:42:41 +0100 Subject: [PATCH 577/781] git: browsing paths with spaces when using the start command msysGit issue 258 tracks a problem opening a browser onto file paths that contain spaces or parentheses when calling the web--browse script. This path modifies how the start command is called to solve this. Signed-off-by: Pat Thoyts --- git-web--browse.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/git-web--browse.sh b/git-web--browse.sh index 7ed0faddcd..4f5c740df5 100755 --- a/git-web--browse.sh +++ b/git-web--browse.sh @@ -161,9 +161,12 @@ case "$browser" in ;; esac ;; - w3m|links|lynx|open|start) + w3m|links|lynx|open) eval "$browser_path" "$@" ;; + start) + exec "$browser_path" '"web-browse"' "$@" + ;; dillo) "$browser_path" "$@" & ;; From b078c82afda34beb2fa33f7227cc3e10ac3db226 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 18 May 2009 14:53:34 +0200 Subject: [PATCH 578/781] Error out rather than hang when plink does not know the host yet As reported in msysGit issue 96, plink wants to interact with the user asking if a host key should be accepted, but this just blocks the terminal, as plink tries to get the answer from stdin. However, stdin is already connected to Git that wants to send input to the remote command. Rather than blocking, just call plink with -batch so that it will error out with an error message. Signed-off-by: Johannes Schindelin --- connect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/connect.c b/connect.c index b3c4d22050..db7020939a 100644 --- a/connect.c +++ b/connect.c @@ -602,13 +602,15 @@ struct child_process *git_connect(int fd[2], const char *url_orig, die("command line too long"); conn->in = conn->out = -1; - conn->argv = arg = xcalloc(6, sizeof(*arg)); + conn->argv = arg = xcalloc(7, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); int putty = ssh && strstr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; + if (putty) + *arg++ = "-batch"; if (port) { /* P is for PuTTY, p is for OpenSSH */ *arg++ = putty ? "-P" : "-p"; From ac3f43986a2a5948d474adb21cd5fde78178d367 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 20 May 2009 13:42:04 +0200 Subject: [PATCH 579/781] Correctly detect Plink.exe, and avoid passing -batch to TortoisePlink On Windows, file names are case-insensitive, and some versions of TortoisePlink do not handle -batch well (i.e. they do not understand, neither ignore it). Signed-off-by: Johannes Schindelin --- connect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connect.c b/connect.c index db7020939a..692d476578 100644 --- a/connect.c +++ b/connect.c @@ -605,11 +605,11 @@ struct child_process *git_connect(int fd[2], const char *url_orig, conn->argv = arg = xcalloc(7, sizeof(*arg)); if (protocol == PROTO_SSH) { const char *ssh = getenv("GIT_SSH"); - int putty = ssh && strstr(ssh, "plink"); + int putty = ssh && strcasestr(ssh, "plink"); if (!ssh) ssh = "ssh"; *arg++ = ssh; - if (putty) + if (putty && !strcasestr(ssh, "tortoiseplink")) *arg++ = "-batch"; if (port) { /* P is for PuTTY, p is for OpenSSH */ From 5fb08d69b146757b7bfbfb20c7c002b496e867d4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 23 May 2009 10:49:17 +0200 Subject: [PATCH 580/781] MinGW: Teach Makefile to detect msysgit This commit changes handling of the msysgit specific settings, so that they can be applied to Junio's git.git. Some msysgit settings differ from the standard MinGW settings. We move them into a ifndef block that is only evaluated if a file THIS_IS_MSYSGIT is present in the parent directory, which will be the case for an msysgit working environment, and we assume that such a file is not present accidentally. Signed-off-by: Steffen Prohaska --- Makefile | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 52e190be35..e4fa9a4ee2 100644 --- a/Makefile +++ b/Makefile @@ -817,9 +817,6 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) endif ifneq (,$(findstring MINGW,$(uname_S))) pathsep = ; - prefix = - INSTALL = /bin/install - EXTLIBS += /mingw/lib/libz.a NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease @@ -838,8 +835,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease - NO_R_TO_GCC_LINKER = YesPlease - INTERNAL_QSORT = YesPlease RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease @@ -853,7 +848,16 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe +ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) htmldir=doc/git/html/ + prefix = + INSTALL = /bin/install + EXTLIBS += /mingw/lib/libz.a + NO_R_TO_GCC_LINKER = YesPlease + INTERNAL_QSORT = YesPlease +else + NO_CURL = YesPlease +endif endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease From e564daea9217d848b5869f5e47723890934ae8a7 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 24 May 2009 08:38:21 +0200 Subject: [PATCH 581/781] Fix "MinGW: GCC >= 4 does not need SNPRINTF_SIZE_CORR anymore" The commit message of 3a76fdaf98efbb1dc2f71352c811ab6d2710b74f explains that GCC >= 4 does not need SNPRINTF_SIZE_CORR, but the ifdef tested for < 3, instead of < 4. This is fixed. Thanks to Johannes Sixt for spotting the bug. --- compat/snprintf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index 7d780508a7..6c0fb056a5 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -6,7 +6,7 @@ * number of characters to write without the trailing NUL. */ #ifndef SNPRINTF_SIZE_CORR -#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 3 +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 4 #define SNPRINTF_SIZE_CORR 1 #else #define SNPRINTF_SIZE_CORR 0 From b2bab8d91b346abf4a4603d443df2dce7b62301f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 25 May 2009 06:44:26 +0200 Subject: [PATCH 582/781] Revert "Renaming .gitk-new to .gitk fails if there is already a .gitk." This reverts commit 3a8b35c3e37369014dc06c767e8fa569150a1e59 A quick test showed that this is unnecessary. Unfortunately, the commit message does not explain the specific reason for the patch. It could be issues with FAT or Windows shares. We hope that this is fixed since we switched to Tcl/Tk 8.5.5. --- gitk-git/gitk | 1 - 1 file changed, 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index a5f77e2f87..1a7887b252 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2568,7 +2568,6 @@ proc savestuff {w} { } puts $f "}" close $f - catch {file delete "~/.gitk"} file rename -force "~/.gitk-new" "~/.gitk" } set stuffsaved 1 From ef407fda650d652d554e385ec4604c88d39949d4 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 25 May 2009 06:56:11 +0200 Subject: [PATCH 583/781] Enable THREADED_DELTA_SEARCH only for msysgit, but not mingw in general --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e4fa9a4ee2..1f034e3a91 100644 --- a/Makefile +++ b/Makefile @@ -826,7 +826,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease - THREADED_DELTA_SEARCH = YesPlease NEEDS_LIBICONV = YesPlease OLD_ICONV = YesPlease NO_C99_FORMAT = YesPlease @@ -855,8 +854,10 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) EXTLIBS += /mingw/lib/libz.a NO_R_TO_GCC_LINKER = YesPlease INTERNAL_QSORT = YesPlease + THREADED_DELTA_SEARCH = YesPlease else NO_CURL = YesPlease + NO_PTHREADS = YesPlease endif endif ifneq (,$(findstring arm,$(uname_M))) From a464b3e17abc16b3ece8fa8c4b4e98a499873b45 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Mon, 1 Jun 2009 08:15:12 +0200 Subject: [PATCH 584/781] Move conio.h from win32.h to mingw.c We need conio.h to avoid a warning about the implicit declaration of _getch(). Including it in mingw.c is sufficient. --- compat/mingw.c | 1 + compat/win32.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index d85d68065e..bed417875e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,5 +1,6 @@ #include "../git-compat-util.h" #include "win32.h" +#include #include "../strbuf.h" unsigned int _CRT_fmode = _O_BINARY; diff --git a/compat/win32.h b/compat/win32.h index d531130b12..c26384e595 100644 --- a/compat/win32.h +++ b/compat/win32.h @@ -1,6 +1,5 @@ /* common Win32 functions for MinGW and Cygwin */ #include -#include static inline int file_attr_to_st_mode (DWORD attr) { From 65deb66a2d92ef38d2cdee71328b48a22605ad1b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 Jun 2009 14:49:39 +0200 Subject: [PATCH 585/781] import-tars: support symlinks Without this patch, symbolic links are turned into empty files. Signed-off-by: Johannes Schindelin --- contrib/fast-import/import-tars.perl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/contrib/fast-import/import-tars.perl b/contrib/fast-import/import-tars.perl index 6309d146e7..78e40d2a13 100755 --- a/contrib/fast-import/import-tars.perl +++ b/contrib/fast-import/import-tars.perl @@ -82,10 +82,16 @@ foreach my $tar_file (@ARGV) $mtime = oct $mtime; next if $typeflag == 5; # directory - print FI "blob\n", "mark :$next_mark\n", "data $size\n"; - while ($size > 0 && read(I, $_, 512) == 512) { - print FI substr($_, 0, $size); - $size -= 512; + print FI "blob\n", "mark :$next_mark\n"; + if ($typeflag == 2) { # symbolic link + print FI "data ", length($linkname), "\n", $linkname; + $mode = 0120000; + } else { + print FI "data $size\n"; + while ($size > 0 && read(I, $_, 512) == 512) { + print FI substr($_, 0, $size); + $size -= 512; + } } print FI "\n"; @@ -118,7 +124,8 @@ EOF { my ($mark, $mode) = @{$files{$path}}; $path =~ s,^([^/]+)/,, if $have_top_dir; - printf FI "M %o :%i %s\n", $mode & 0111 ? 0755 : 0644, $mark, $path; + $mode = $mode & 0111 ? 0755 : 0644 unless $mode == 0120000; + printf FI "M %o :%i %s\n", $mode, $mark, $path; } print FI "\n"; From 7336516a6f2ac781b4a78a73f99e41e9e8b66e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 17 Jun 2009 22:37:31 +0300 Subject: [PATCH 586/781] Refactor winsock initialization into a separate function Signed-off-by: Martin Storsjo --- compat/mingw.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index bed417875e..f570d115c9 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -886,16 +886,25 @@ char **env_setenv(char **env, const char *name) return env; } -/* this is the first function to call into WS_32; initialize it */ -#undef gethostbyname -struct hostent *mingw_gethostbyname(const char *host) +static void ensure_socket_initialization(void) { WSADATA wsa; + static int initialized = 0; + + if (initialized) + return; if (WSAStartup(MAKEWORD(2,2), &wsa)) die("unable to initialize winsock subsystem, error %d", WSAGetLastError()); atexit((void(*)(void)) WSACleanup); + initialized = 1; +} + +#undef gethostbyname +struct hostent *mingw_gethostbyname(const char *host) +{ + ensure_socket_initialization(); return gethostbyname(host); } From bc611ebb9212f5a88446e1b9971e30d7e872feeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 18 Jun 2009 09:40:22 +0300 Subject: [PATCH 587/781] Enable support for IPv6 on MinGW The IPv6 support functions are loaded dynamically, to maintain backwards compatibility with versions of Windows prior to XP, and fallback wrappers are provided, implemented in terms of gethostbyname and gethostbyaddr. Signed-off-by: Martin Storsjo --- Makefile | 1 - compat/mingw.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++- compat/mingw.h | 13 ++++ 3 files changed, 181 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7a53bb7da1..81d4c8950e 100644 --- a/Makefile +++ b/Makefile @@ -824,7 +824,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_PREAD = YesPlease NO_OPENSSL = YesPlease NO_SYMLINK_HEAD = YesPlease - NO_IPV6 = YesPlease NO_SETENV = YesPlease NO_UNSETENV = YesPlease NO_STRCASESTR = YesPlease diff --git a/compat/mingw.c b/compat/mingw.c index f570d115c9..5cda95d084 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -886,10 +886,129 @@ char **env_setenv(char **env, const char *name) return env; } +/* + * Note, this isn't a complete replacement for getaddrinfo. It assumes + * that service contains a numerical port, or that it it is null. It + * does a simple search using gethostbyname, and returns one IPv4 host + * if one was found. + */ +static int WSAAPI getaddrinfo_stub(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + struct hostent *h = gethostbyname(node); + struct addrinfo *ai; + struct sockaddr_in *sin; + + if (!h) + return WSAGetLastError(); + + ai = xmalloc(sizeof(struct addrinfo)); + *res = ai; + ai->ai_flags = 0; + ai->ai_family = AF_INET; + ai->ai_socktype = hints->ai_socktype; + switch (hints->ai_socktype) { + case SOCK_STREAM: + ai->ai_protocol = IPPROTO_TCP; + break; + case SOCK_DGRAM: + ai->ai_protocol = IPPROTO_UDP; + break; + default: + ai->ai_protocol = 0; + break; + } + ai->ai_addrlen = sizeof(struct sockaddr_in); + ai->ai_canonname = strdup(h->h_name); + + sin = xmalloc(ai->ai_addrlen); + memset(sin, 0, ai->ai_addrlen); + sin->sin_family = AF_INET; + if (service) + sin->sin_port = htons(atoi(service)); + sin->sin_addr = *(struct in_addr *)h->h_addr; + ai->ai_addr = (struct sockaddr *)sin; + ai->ai_next = 0; + return 0; +} + +static void WSAAPI freeaddrinfo_stub(struct addrinfo *res) +{ + free(res->ai_canonname); + free(res->ai_addr); + free(res); +} + +static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, + char *serv, DWORD servlen, int flags) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; + if (sa->sa_family != AF_INET) + return EAI_FAMILY; + if (!host && !serv) + return EAI_NONAME; + + if (host && hostlen > 0) { + struct hostent *ent = NULL; + if (!(flags & NI_NUMERICHOST)) + ent = gethostbyaddr((const char *)&sin->sin_addr, + sizeof(sin->sin_addr), AF_INET); + + if (ent) + snprintf(host, hostlen, "%s", ent->h_name); + else if (flags & NI_NAMEREQD) + return EAI_NONAME; + else + snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr)); + } + + if (serv && servlen > 0) { + struct servent *ent = NULL; + if (!(flags & NI_NUMERICSERV)) + ent = getservbyport(sin->sin_port, + flags & NI_DGRAM ? "udp" : "tcp"); + + if (ent) + snprintf(serv, servlen, "%s", ent->s_name); + else + snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); + } + + return 0; +} + +static HMODULE ipv6_dll = NULL; +static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res); +static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service, + const struct addrinfo *hints, + struct addrinfo **res); +static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, + char *serv, DWORD servlen, int flags); +/* + * gai_strerror is an inline function in the ws2tcpip.h header, so we + * don't need to try to load that one dynamically. + */ + +static void socket_cleanup(void) +{ + WSACleanup(); + if (ipv6_dll) + FreeLibrary(ipv6_dll); + ipv6_dll = NULL; + ipv6_freeaddrinfo = freeaddrinfo_stub; + ipv6_getaddrinfo = getaddrinfo_stub; + ipv6_getnameinfo = getnameinfo_stub; +} + static void ensure_socket_initialization(void) { WSADATA wsa; static int initialized = 0; + const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL }; + const char **name; if (initialized) return; @@ -897,7 +1016,35 @@ static void ensure_socket_initialization(void) if (WSAStartup(MAKEWORD(2,2), &wsa)) die("unable to initialize winsock subsystem, error %d", WSAGetLastError()); - atexit((void(*)(void)) WSACleanup); + + for (name = libraries; *name; name++) { + ipv6_dll = LoadLibrary(*name); + if (!ipv6_dll) + continue; + + ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *)) + GetProcAddress(ipv6_dll, "freeaddrinfo"); + ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *, + const struct addrinfo *, + struct addrinfo **)) + GetProcAddress(ipv6_dll, "getaddrinfo"); + ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *, + socklen_t, char *, DWORD, + char *, DWORD, int)) + GetProcAddress(ipv6_dll, "getnameinfo"); + if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) { + FreeLibrary(ipv6_dll); + ipv6_dll = NULL; + } else + break; + } + if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) { + ipv6_freeaddrinfo = freeaddrinfo_stub; + ipv6_getaddrinfo = getaddrinfo_stub; + ipv6_getnameinfo = getnameinfo_stub; + } + + atexit(socket_cleanup); initialized = 1; } @@ -908,6 +1055,26 @@ struct hostent *mingw_gethostbyname(const char *host) return gethostbyname(host); } +void mingw_freeaddrinfo(struct addrinfo *res) +{ + ipv6_freeaddrinfo(res); +} + +int mingw_getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res) +{ + ensure_socket_initialization(); + return ipv6_getaddrinfo(node, service, hints, res); +} + +int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, char *serv, DWORD servlen, + int flags) +{ + ensure_socket_initialization(); + return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); +} + int mingw_socket(int domain, int type, int protocol) { int sockfd; diff --git a/compat/mingw.h b/compat/mingw.h index 4f7ba4c13f..244ace82e1 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -1,4 +1,5 @@ #include +#include /* * things that are not available in header files @@ -152,6 +153,18 @@ char *mingw_getenv(const char *name); struct hostent *mingw_gethostbyname(const char *host); #define gethostbyname mingw_gethostbyname +void mingw_freeaddrinfo(struct addrinfo *res); +#define freeaddrinfo mingw_freeaddrinfo + +int mingw_getaddrinfo(const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); +#define getaddrinfo mingw_getaddrinfo + +int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, DWORD hostlen, char *serv, DWORD servlen, + int flags); +#define getnameinfo mingw_getnameinfo + int mingw_socket(int domain, int type, int protocol); #define socket mingw_socket From 198cb7c3f0b8420d8ba21fc8005b3ce6091e75b6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 588/781] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Signed-off-by: Johannes Schindelin --- http.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index a2720d576d..a7ebbaf94e 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,6 @@ #include "http.h" #include "pack.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -129,6 +130,15 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; + *result = system_path(*result); + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -136,17 +146,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From ed04b5ce213a39f9f0379640d8e4078c0a2635f8 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 589/781] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index d508f83349..7a6a82c810 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -898,7 +898,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From 069b288d1b44ad729eac9a31193e0b17a6ab5f6b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Jul 2009 22:21:55 +0200 Subject: [PATCH 590/781] Skip tests requiring 'iconv' when that is not found Signed-off-by: Johannes Schindelin --- t/t3900-i18n-commit.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 256c4c9701..a0fb178a67 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -64,6 +64,13 @@ test_expect_success 'config to remove customization' ' git config i18n.commitencoding UTF-8 ' +iconv --help 2>/dev/null >/dev/null +test $? = 127 && { + say "No iconv found; skip rest" + test_done + exit +} + test_expect_success 'ISO8859-1 should be shown in UTF-8 now' ' compare_with ISO8859-1 "$TEST_DIRECTORY"/t3900/1-UTF-8.txt ' From ea20f4081910213be44e2f38360099f961091c2c Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Mon, 10 Aug 2009 12:47:37 +0200 Subject: [PATCH 591/781] Symlink support Add symlink support; with UAC, you may need administrator's privileges to create symlinks, but you can at least read them. As reparse points on Windows differentiate between file and directory links, we just assume that file links are meant for the time being; it might be very hard to determine the type before the target exists, but it is thinkable to change the type on-the-fly. A bridge to cross when we arrive there (read: something for somebody to fix who actually has that problem). Signed-off-by: Johannes Schindelin --- compat/mingw.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- compat/mingw.h | 6 ++--- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5cda95d084..20f370b73b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,6 +1,7 @@ #include "../git-compat-util.h" #include "win32.h" #include +#include #include "../strbuf.h" unsigned int _CRT_fmode = _O_BINARY; @@ -166,6 +167,21 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_mode = S_IREAD | S_IFLNK; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + } + FindClose(handle); + } + } return 0; } return -1; @@ -1334,6 +1350,58 @@ int link(const char *oldpath, const char *newpath) return 0; } +int symlink(const char *oldpath, const char *newpath) +{ + typedef BOOL WINAPI (*symlink_fn)(const char*, const char*, DWORD); + static symlink_fn create_symbolic_link = NULL; + if (!create_symbolic_link) { + create_symbolic_link = (symlink_fn) GetProcAddress( + GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkA"); + if (!create_symbolic_link) + create_symbolic_link = (symlink_fn)-1; + } + if (create_symbolic_link == (symlink_fn)-1) { + errno = ENOSYS; + return -1; + } + + if (!create_symbolic_link(newpath, oldpath, 0)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} + +int readlink(const char *path, char *buf, size_t bufsiz) +{ + HANDLE handle = CreateFile(path, GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle != INVALID_HANDLE_VALUE) { + unsigned char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + DWORD dummy = 0; + if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) { + REPARSE_DATA_BUFFER *b = (REPARSE_DATA_BUFFER *) buffer; + if (b->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + int len = b->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = b->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + snprintf(buf, bufsiz, "%*ls", len, & b->SymbolicLinkReparseBuffer.PathBuffer[offset]); + CloseHandle(handle); + return len; + } + } + + CloseHandle(handle); + } + + errno = EINVAL; + return -1; +} + char *getpass(const char *prompt) { struct strbuf buf = STRBUF_INIT; @@ -1399,7 +1467,10 @@ struct dirent *mingw_readdir(DIR *dir) /* Set file type, based on WIN32_FIND_DATA */ mdir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + if ((buf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (buf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) + mdir->dd_dir.d_type |= DT_LNK; + else if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) mdir->dd_dir.d_type |= DT_DIR; else mdir->dd_dir.d_type |= DT_REG; diff --git a/compat/mingw.h b/compat/mingw.h index c76af61617..4f9f7f4887 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -66,10 +66,6 @@ struct itimerval { * trivial stubs */ -static inline int readlink(const char *path, char *buf, size_t bufsiz) -{ errno = ENOSYS; return -1; } -static inline int symlink(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) @@ -138,6 +134,8 @@ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); +int symlink(const char *oldpath, const char *newpath); +int readlink(const char *path, char *buf, size_t bufsiz); /* * replacements of existing functions From afb9111bacf3da37d87186057739b3e3fbf044b0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 18:08:44 +0200 Subject: [PATCH 592/781] Fix style of multi-line comments In git.git, we want multi-line comments between single /* and */ in a line. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 20f370b73b..ed2664dc00 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -147,7 +147,8 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } -/* We keep the do_lstat code in a separate function to avoid recursion. +/* + * We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. */ @@ -187,7 +188,8 @@ static int do_lstat(const char *file_name, struct stat *buf) return -1; } -/* We provide our own lstat/fstat functions, since the provided +/* + * We provide our own lstat/fstat functions, since the provided * lstat/fstat functions are so slow. These stat functions are * tailored for Git's usage (read: fast), and are not meant to be * complete. Note that Git stat()s are redirected to mingw_lstat() @@ -201,7 +203,8 @@ int mingw_lstat(const char *file_name, struct stat *buf) if (!do_lstat(file_name, buf)) return 0; - /* if file_name ended in a '/', Windows returned ENOENT; + /* + * if file_name ended in a '/', Windows returned ENOENT; * try again without trailing slashes */ if (errno != ENOENT) @@ -368,7 +371,8 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) return errno = EINVAL, error("poll timeout not supported"); } - /* When there is only one fd to wait for, then we pretend that + /* + * When there is only one fd to wait for, then we pretend that * input is available and let the actual wait happen when the * caller invokes read(). */ @@ -408,7 +412,8 @@ repeat: ufds[i].revents = 0; } if (!pending) { - /* The only times that we spin here is when the process + /* + * The only times that we spin here is when the process * that is connected through the pipes is waiting for * its own input data to become available. But since * the process (pack-objects) is itself CPU intensive, @@ -663,7 +668,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (cons == INVALID_HANDLE_VALUE) { - /* There is no console associated with this process. + /* + * There is no console associated with this process. * Since the child is a console process, Windows * would normally create a console window. But * since we'll be redirecting std streams, we do @@ -674,7 +680,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, */ flags = DETACHED_PROCESS; } else { - /* There is already a console. If we specified + /* + * There is already a console. If we specified * DETACHED_PROCESS here, too, Windows would * disassociate the child from the console. * The same is true for CREATE_NO_WINDOW. @@ -874,9 +881,7 @@ static int lookup_env(char **env, const char *name, size_t nmln) return -1; } -/* - * If name contains '=', then sets the variable, otherwise it unsets it - */ +/* If name contains '=', then sets the variable, otherwise it unsets it */ char **env_setenv(char **env, const char *name) { char *eq = strchrnul(name, '='); @@ -1195,7 +1200,8 @@ static int timer_interval; static int one_shot; static sig_handler_t timer_fn = SIG_DFL; -/* The timer works like this: +/* + * The timer works like this: * The thread, ticktack(), is a trivial routine that most of the time * only waits to receive the signal to terminate. The main thread tells * the thread to terminate by setting the timer_event to the signalled @@ -1454,8 +1460,10 @@ struct dirent *mingw_readdir(DIR *dir) DWORD lasterr = GetLastError(); FindClose((HANDLE)dir->dd_handle); dir->dd_handle = (long)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. */ + /* + * 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; From 8653dacef71c86e5a95d32eda5240bbafc40d1a6 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:44:01 +0200 Subject: [PATCH 593/781] On Windows, mark directory hidden when starting with dot. In Windows a file or directory starting with a dot is not automatically hidden. So lets mark it as hidden when such a directory is created. This fixes msysGit issue 288. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 26 ++++++++++++++++++++++++++ compat/mingw.h | 9 +++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5cda95d084..c3f5cef22c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -118,6 +118,32 @@ static int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index c76af61617..19a0205f86 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -100,12 +100,6 @@ static inline int fcntl(int fd, int cmd, long arg) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} -#define mkdir mingw_mkdir - static inline int mingw_unlink(const char *pathname) { /* read-only files cannot be removed */ @@ -143,6 +137,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_mkdir(const char *path, int mode); +#define mkdir mingw_mkdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 996ff4a9ae8d4db3b5fedea3f1cf03ea0f689035 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:59:27 +0200 Subject: [PATCH 594/781] Make auto-hiding dot-files optional on Windows. Although a file starting with a dot usually ought to be hidden, there could be reasons users do not want it to happen automatically. Original patch by Erik Faye-Lund. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- cache.h | 1 + compat/mingw.c | 3 ++- config.c | 5 +++++ environment.c | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cache.h b/cache.h index e6c7f3307d..f591437a50 100644 --- a/cache.h +++ b/cache.h @@ -518,6 +518,7 @@ extern size_t delta_base_cache_limit; extern int auto_crlf; extern int fsync_object_files; extern int core_preload_index; +extern int hide_dotfiles; enum safe_crlf { SAFE_CRLF_FALSE = 0, diff --git a/compat/mingw.c b/compat/mingw.c index c3f5cef22c..665d861389 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -130,8 +130,9 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { + extern int hide_dotfiles; int ret = mkdir(path); - if (!ret) { + if (!ret && hide_dotfiles) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when diff --git a/config.c b/config.c index 738b24419d..fc45ea2198 100644 --- a/config.c +++ b/config.c @@ -505,6 +505,11 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 8f5eaa7dd8..940f3cfa3a 100644 --- a/environment.c +++ b/environment.c @@ -48,6 +48,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_replace_parents = 1; +int hide_dotfiles = 1; /* Parallel index stat data preload? */ int core_preload_index = 0; From 5d098f4e5f1e21d802769f16058118ec12cdda25 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:08:05 +0200 Subject: [PATCH 595/781] Document the core.hideDotFiles variable Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index c6f09f801a..7c6f7fcb87 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -118,6 +118,10 @@ core.fileMode:: the working copy are ignored; useful on broken filesystems like FAT. See linkgit:git-update-index[1]. True by default. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories whose name starts with a dot as hidden. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful From 2328ceef54b7b2e40ad66ecd74a3451bf7c3c6d5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:12:17 +0200 Subject: [PATCH 596/781] Windows: mark newly-created files whose name starts with a dot as hidden Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 2 +- compat/mingw.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 7c6f7fcb87..30ab22b840 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -120,7 +120,7 @@ core.fileMode:: core.hideDotFiles:: (Windows-only) If true (which is the default), mark newly-created - directories whose name starts with a dot as hidden. + directories and files whose name starts with a dot as hidden. core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, diff --git a/compat/mingw.c b/compat/mingw.c index 665d861389..a68ef11696 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" +extern int hide_dotfiles; unsigned int _CRT_fmode = _O_BINARY; static int err_win_to_posix(DWORD winerr) @@ -130,7 +131,6 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { - extern int hide_dotfiles; int ret = mkdir(path); if (!ret && hide_dotfiles) { /* @@ -162,6 +162,16 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && hide_dotfiles) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } From 4863902f4f89d00a7fa916d11cf24fe1cb9b8160 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Wed, 12 Aug 2009 23:40:50 +0200 Subject: [PATCH 597/781] Windows: mark newly-created dot files by fopen() as hidden Files starting with a dot are considered "hidden", i.e. you have to ask explicitely to see them. On Windows, this is not done automatically, as Windows has its own mechanism. We already mark dot directories created by mkdir() and dot files created by open() as hidden, so let's do that with fopen(), too (but only if the file was just created, not when it already exists). Naturally, we make this behavior optional on core.hideDotFiles. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index a68ef11696..293bd5999d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,6 +175,24 @@ int mingw_open (const char *filename, int oflags, ...) return fd; } +#undef fopen +FILE *mingw_fopen (const char *filename, const char *mode) +{ + int hide = 0; + if (hide_dotfiles && basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); + + FILE *file = fopen(filename, mode); + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; +} + static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; diff --git a/compat/mingw.h b/compat/mingw.h index 19a0205f86..8fe1773974 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -143,6 +143,9 @@ int mingw_mkdir(const char *path, int mode); int mingw_open (const char *filename, int oflags, ...); #define open mingw_open +FILE *mingw_fopen (const char *filename, const char *mode); +#define fopen mingw_fopen + char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd From 3c150abb1016cef67dfa2644578dbca8700e280c Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 16 Aug 2009 13:34:03 +0800 Subject: [PATCH 598/781] Avoid declaration after instruction Microsoft Visual C++ does not understand this C99 style. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 16 ++++++++++++---- help.c | 3 ++- run-command.c | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 62983d0e32..d262e1c226 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -151,13 +151,17 @@ int mingw_open (const char *filename, int oflags, ...) { va_list args; unsigned mode; + int fd; + va_start(args, oflags); mode = va_arg(args, int); va_end(args); if (!strcmp(filename, "/dev/null")) filename = "nul"; - int fd = open(filename, oflags, mode); + + fd = open(filename, oflags, mode); + if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { DWORD attrs = GetFileAttributes(filename); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) @@ -656,10 +660,11 @@ static char **get_path_split(void) static void free_path_split(char **path) { + char **p = path; + if (!path) return; - char **p = path; while (*p) free(*p++); free(path); @@ -1361,9 +1366,11 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out) #undef signal sig_handler_t mingw_signal(int sig, sig_handler_t handler) { + sig_handler_t old; + if (sig != SIGALRM) return signal(sig, handler); - sig_handler_t old = timer_fn; + old = timer_fn; timer_fn = handler; return old; } @@ -1502,8 +1509,9 @@ struct dirent *mingw_readdir(DIR *dir) if (dir->dd_handle == (long)INVALID_HANDLE_VALUE && dir->dd_stat == 0) { + DWORD lasterr; handle = FindFirstFileA(dir->dd_name, &buf); - DWORD lasterr = GetLastError(); + lasterr = GetLastError(); dir->dd_handle = (long)handle; if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { errno = err_win_to_posix(lasterr); diff --git a/help.c b/help.c index 6c46d8b494..399b0b40f4 100644 --- a/help.c +++ b/help.c @@ -127,7 +127,7 @@ static int is_executable(const char *name) return 0; #ifdef __MINGW32__ - /* cannot trust the executable bit, peek into the file instead */ +{ /* cannot trust the executable bit, peek into the file instead */ char buf[3] = { 0 }; int n; int fd = open(name, O_RDONLY); @@ -140,6 +140,7 @@ static int is_executable(const char *name) st.st_mode |= S_IXUSR; close(fd); } +} #endif return st.st_mode & S_IXUSR; } diff --git a/run-command.c b/run-command.c index ff3d8e2d8b..d1df7abe9a 100644 --- a/run-command.c +++ b/run-command.c @@ -123,6 +123,7 @@ int start_command(struct child_process *cmd) exit(127); } #else +{ int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ const char **sargv = cmd->argv; char **env = environ; @@ -186,6 +187,7 @@ int start_command(struct child_process *cmd) dup2(s1, 1), close(s1); if (s2 >= 0) dup2(s2, 2), close(s2); +} #endif if (cmd->pid < 0) { From 0b79d7e97888f2f26820ac7c7d5b911e4f84821e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:30:55 +0200 Subject: [PATCH 599/781] Fix a few old-style function declarations in compat/ Signed-off-by: Johannes Schindelin --- compat/fnmatch/fnmatch.c | 20 +-- compat/mingw.c | 2 +- compat/mingw.h | 2 +- compat/nedmalloc/malloc.c.h | 2 +- compat/nedmalloc/nedmalloc.c | 4 +- compat/regex/regex.c | 240 +++++++++++------------------------ 6 files changed, 84 insertions(+), 186 deletions(-) diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 14feac7fe1..1180fc793f 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -130,10 +130,7 @@ extern int errno; /* This function doesn't exist on most systems. */ # if !defined HAVE___STRCHRNUL && !defined _LIBC -static char * -__strchrnul (s, c) - const char *s; - int c; +static char * __strchrnul (const char *s, int c) { char *result = strchr (s, c); if (result == NULL) @@ -153,13 +150,8 @@ __strchrnul (s, c) static int internal_fnmatch __P ((const char *pattern, const char *string, int no_leading_period, int flags)) internal_function; -static int -internal_function -internal_fnmatch (pattern, string, no_leading_period, flags) - const char *pattern; - const char *string; - int no_leading_period; - int flags; +static int internal_function internal_fnmatch (const char *pattern, + const char *string, int no_leading_period, int flags) { register const char *p = pattern, *n = string; register unsigned char c; @@ -476,11 +468,7 @@ internal_fnmatch (pattern, string, no_leading_period, flags) } -int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +int fnmatch (const char *pattern, const char *string, int flags) { return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); } diff --git a/compat/mingw.c b/compat/mingw.c index d262e1c226..d70fd21573 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -907,7 +907,7 @@ void mingw_execvp(const char *cmd, char *const *argv) free_path_split(path); } -char **copy_environ() +char **copy_environ(void) { char **env; int i = 0; diff --git a/compat/mingw.h b/compat/mingw.h index 201e79c741..cfbcc0e0cd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -78,7 +78,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline int getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index 74c42e3162..41b8698ab3 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -1802,7 +1802,7 @@ struct win32_mlock_t static MLOCK_T malloc_global_mutex = { 0, 0, 0}; -static FORCEINLINE long win32_getcurrentthreadid() { +static FORCEINLINE long win32_getcurrentthreadid(void) { #ifdef _MSC_VER #if defined(_M_IX86) long *threadstruct=(long *)__readfsdword(0x18); diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index d9a17a8057..229f942d10 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -159,8 +159,8 @@ struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); } #endif int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); } int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); } -void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); } -size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); } +void nedmalloc_stats(void) THROWSPEC { nedpmalloc_stats(0); } +size_t nedmalloc_footprint(void) THROWSPEC { return nedpmalloc_footprint(0); } void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); } void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); } diff --git a/compat/regex/regex.c b/compat/regex/regex.c index 5ea007567d..9e8a203857 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -64,8 +64,7 @@ extern char *re_syntax_table; static char re_syntax_table[CHAR_SET_SIZE]; -static void -init_syntax_once () +static void init_syntax_once(void) { register int c; static int done = 0; @@ -380,10 +379,7 @@ typedef enum } while (0) #ifdef DEBUG -static void -extract_number (dest, source) - int *dest; - unsigned char *source; +static void extract_number(int *dest, unsigned char *source) { int temp = SIGN_EXTEND_CHAR (*(source + 1)); *dest = *source & 0377; @@ -407,10 +403,8 @@ extract_number (dest, source) } while (0) #ifdef DEBUG -static void -extract_number_and_incr (destination, source) - int *destination; - unsigned char **source; +static void extract_number_and_incr(int *destination, + unsigned char **source) { extract_number (destination, *source); *source += 2; @@ -455,9 +449,7 @@ extern void printchar (); /* Print the fastmap in human-readable form. */ -void -print_fastmap (fastmap) - char *fastmap; +void print_fastmap(char *fastmap) { unsigned was_a_range = 0; unsigned i = 0; @@ -487,10 +479,8 @@ print_fastmap (fastmap) /* Print a compiled pattern string in human-readable form, starting at the START pointer into it and ending just before the pointer END. */ -void -print_partial_compiled_pattern (start, end) - unsigned char *start; - unsigned char *end; +void print_partial_compiled_pattern(unsigned char *start, + unsigned char *end) { int mcnt, mcnt2; unsigned char *p = start; @@ -695,9 +685,7 @@ print_partial_compiled_pattern (start, end) } -void -print_compiled_pattern (bufp) - struct re_pattern_buffer *bufp; +void print_compiled_pattern(struct re_pattern_buffer *bufp) { unsigned char *buffer = bufp->buffer; @@ -722,13 +710,9 @@ print_compiled_pattern (bufp) } -void -print_double_string (where, string1, size1, string2, size2) - const char *where; - const char *string1; - const char *string2; - int size1; - int size2; +void print_double_string(const char *where, + const char *string1, int size1, + const char *string2, int size2) { unsigned this_char; @@ -777,9 +761,7 @@ reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; The argument SYNTAX is a bit mask comprised of the various bits defined in regex.h. We return the old syntax. */ -reg_syntax_t -re_set_syntax (syntax) - reg_syntax_t syntax; +reg_syntax_t re_set_syntax(reg_syntax_t syntax) { reg_syntax_t ret = re_syntax_options; @@ -1031,12 +1013,9 @@ typedef struct The `fastmap' and `newline_anchor' fields are neither examined nor set. */ -static reg_errcode_t -regex_compile (pattern, size, syntax, bufp) - const char *pattern; - int size; - reg_syntax_t syntax; - struct re_pattern_buffer *bufp; +static reg_errcode_t regex_compile(const char *pattern, + int size, reg_syntax_t syntax, + struct re_pattern_buffer *bufp) { /* We fetch characters from PATTERN here. Even though PATTERN is `char *' (i.e., signed), we declare these variables as unsigned, so @@ -2036,11 +2015,8 @@ regex_compile (pattern, size, syntax, bufp) /* Store OP at LOC followed by two-byte integer parameter ARG. */ -static void -store_op1 (op, loc, arg) - re_opcode_t op; - unsigned char *loc; - int arg; +static void store_op1(re_opcode_t op, unsigned char *loc, + int arg) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg); @@ -2049,11 +2025,8 @@ store_op1 (op, loc, arg) /* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -store_op2 (op, loc, arg1, arg2) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; +static void store_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg1); @@ -2064,12 +2037,8 @@ store_op2 (op, loc, arg1, arg2) /* Copy the bytes from LOC to END to open up three bytes of space at LOC for OP followed by two-byte integer parameter ARG. */ -static void -insert_op1 (op, loc, arg, end) - re_opcode_t op; - unsigned char *loc; - int arg; - unsigned char *end; +static void insert_op1(re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 3; @@ -2083,12 +2052,8 @@ insert_op1 (op, loc, arg, end) /* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -insert_op2 (op, loc, arg1, arg2, end) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; - unsigned char *end; +static void insert_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 5; @@ -2104,10 +2069,8 @@ insert_op2 (op, loc, arg1, arg2, end) after an alternative or a begin-subexpression. We assume there is at least one character before the ^. */ -static boolean -at_begline_loc_p (pattern, p, syntax) - const char *pattern, *p; - reg_syntax_t syntax; +static boolean at_begline_loc_p(const char *pattern, + const char *p, reg_syntax_t syntax) { const char *prev = p - 2; boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; @@ -2123,10 +2086,8 @@ at_begline_loc_p (pattern, p, syntax) /* The dual of at_begline_loc_p. This one is for $. We assume there is at least one character after the $, i.e., `P < PEND'. */ -static boolean -at_endline_loc_p (p, pend, syntax) - const char *p, *pend; - int syntax; +static boolean at_endline_loc_p(const char *p, + const char *pend, int syntax) { const char *next = p; boolean next_backslash = *next == '\\'; @@ -2145,10 +2106,8 @@ at_endline_loc_p (p, pend, syntax) /* Returns true if REGNUM is in one of COMPILE_STACK's elements and false if it's not. */ -static boolean -group_in_compile_stack (compile_stack, regnum) - compile_stack_type compile_stack; - regnum_t regnum; +static boolean group_in_compile_stack(compile_stack_type + compile_stack, regnum_t regnum) { int this_element; @@ -2173,12 +2132,9 @@ group_in_compile_stack (compile_stack, regnum) We use these short variable names so we can use the same macros as `regex_compile' itself. */ -static reg_errcode_t -compile_range (p_ptr, pend, translate, syntax, b) - const char **p_ptr, *pend; - char *translate; - reg_syntax_t syntax; - unsigned char *b; +static reg_errcode_t compile_range(const char **p_ptr, + const char *pend, char *translate, + reg_syntax_t syntax, unsigned char *b) { unsigned this_char; @@ -2505,9 +2461,7 @@ typedef struct Returns 0 if we succeed, -2 if an internal error. */ -int -re_compile_fastmap (bufp) - struct re_pattern_buffer *bufp; +int re_compile_fastmap(struct re_pattern_buffer *bufp) { int j, k; fail_stack_type fail_stack; @@ -2790,12 +2744,10 @@ re_compile_fastmap (bufp) PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ -void -re_set_registers (bufp, regs, num_regs, starts, ends) - struct re_pattern_buffer *bufp; - struct re_registers *regs; - unsigned num_regs; - regoff_t *starts, *ends; +void re_set_registers(struct re_pattern_buffer *bufp, + struct re_registers *regs, + unsigned num_regs, + regoff_t *starts, regoff_t *ends) { if (num_regs) { @@ -2817,12 +2769,10 @@ re_set_registers (bufp, regs, num_regs, starts, ends) /* Like re_search_2, below, but only one string is specified, and doesn't let you say where to stop matching. */ -int -re_search (bufp, string, size, startpos, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; - struct re_registers *regs; +int re_search(struct re_pattern_buffer *bufp, + const char *string, int size, + int startpos, int range, + struct re_registers *regs) { return re_search_2 (bufp, NULL, 0, string, size, startpos, range, regs, size); @@ -2850,15 +2800,11 @@ re_search (bufp, string, size, startpos, range, regs) found, -1 if no match, or -2 if error (such as failure stack overflow). */ -int -re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int startpos; - int range; - struct re_registers *regs; - int stop; +int re_search_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int startpos, int range, + struct re_registers *regs, int stop) { int val; register char *fastmap = bufp->fastmap; @@ -3109,12 +3055,9 @@ typedef union #ifndef emacs /* Emacs never uses this. */ /* re_match is like re_match_2 except it takes only a single string. */ -int -re_match (bufp, string, size, pos, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, pos; - struct re_registers *regs; +int re_match(struct re_pattern_buffer *bufp, + const char *string, int size, int pos, + struct re_registers *regs) { return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); } @@ -3134,14 +3077,10 @@ re_match (bufp, string, size, pos, regs) failure stack overflowing). Otherwise, we return the length of the matched substring. */ -int -re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int pos; - struct re_registers *regs; - int stop; +int re_match_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, struct re_registers *regs, int stop) { /* General temporaries. */ int mcnt; @@ -4330,10 +4269,9 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) We don't handle duplicates properly (yet). */ -static boolean -group_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean group_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; /* Point to after the args to the start_memory. */ @@ -4439,10 +4377,9 @@ group_match_null_string_p (p, end, reg_info) It expects P to be the first byte of a single alternative and END one byte past the last. The alternative can contain groups. */ -static boolean -alt_match_null_string_p (p, end, reg_info) - unsigned char *p, *end; - register_info_type *reg_info; +static boolean alt_match_null_string_p(unsigned char *p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; unsigned char *p1 = p; @@ -4476,10 +4413,9 @@ alt_match_null_string_p (p, end, reg_info) Sets P to one after the op and its arguments, if any. */ -static boolean -common_op_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean common_op_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; boolean ret; @@ -4564,13 +4500,8 @@ common_op_match_null_string_p (p, end, reg_info) /* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN bytes; nonzero otherwise. */ -static int -bcmp_translate( - unsigned char *s1, - unsigned char *s2, - int len, - char *translate -) +static int bcmp_translate(unsigned char *s1, unsigned char *s2, + int len, char *translate) { register unsigned char *p1 = s1, *p2 = s2; while (len) @@ -4592,11 +4523,8 @@ bcmp_translate( We call regex_compile to do the actual compilation. */ -const char * -re_compile_pattern (pattern, length, bufp) - const char *pattern; - int length; - struct re_pattern_buffer *bufp; +const char *re_compile_pattern(const char *pattern, + int length, struct re_pattern_buffer *bufp) { reg_errcode_t ret; @@ -4625,9 +4553,7 @@ re_compile_pattern (pattern, length, bufp) /* BSD has one and only one pattern buffer. */ static struct re_pattern_buffer re_comp_buf; -char * -re_comp (s) - const char *s; +char *re_comp(const char *s) { reg_errcode_t ret; @@ -4663,9 +4589,7 @@ re_comp (s) } -int -re_exec (s) - const char *s; +int re_exec(const char *s) { const int len = strlen (s); return @@ -4711,11 +4635,7 @@ re_exec (s) It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for the return codes and their meanings.) */ -int -regcomp (preg, pattern, cflags) - regex_t *preg; - const char *pattern; - int cflags; +int regcomp(regex_t *preg, const char *pattern, int cflags) { reg_errcode_t ret; unsigned syntax @@ -4786,13 +4706,9 @@ regcomp (preg, pattern, cflags) We return 0 if we find a match and REG_NOMATCH if not. */ -int -regexec (preg, string, nmatch, pmatch, eflags) - const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; - int eflags; +int regexec(const regex_t *preg, const char *string, + size_t nmatch, regmatch_t pmatch[], + int eflags) { int ret; struct re_registers regs; @@ -4851,12 +4767,8 @@ regexec (preg, string, nmatch, pmatch, eflags) /* Returns a message corresponding to an error code, ERRCODE, returned from either regcomp or regexec. We don't use PREG here. */ -size_t -regerror (errcode, preg, errbuf, errbuf_size) - int errcode; - const regex_t *preg; - char *errbuf; - size_t errbuf_size; +size_t regerror(int errcode, const regex_t *preg, + char *errbuf, size_t errbuf_size) { const char *msg; size_t msg_size; @@ -4895,9 +4807,7 @@ regerror (errcode, preg, errbuf, errbuf_size) /* Free dynamically allocated space used by PREG. */ -void -regfree (preg) - regex_t *preg; +void regfree(regex_t *preg) { if (preg->buffer != NULL) free (preg->buffer); From 95971f14a81d531b8fcb34e66b82c7fe537003dc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:31:29 +0200 Subject: [PATCH 600/781] compat/mingw.c: Fix declaration after instruction Signed-off-by: Johannes Schindelin --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index d70fd21573..449bea140a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -184,10 +184,11 @@ int mingw_open (const char *filename, int oflags, ...) FILE *mingw_fopen (const char *filename, const char *mode) { int hide = 0; + FILE *file; if (hide_dotfiles && basename((char*)filename)[0] == '.') hide = access(filename, F_OK); - FILE *file = fopen(filename, mode); + file = fopen(filename, mode); /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when From 1edac2172dd74fa656dc6e4a9e450751f9a5d1a9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 09:59:58 +0200 Subject: [PATCH 601/781] MinGW means that we have gcc, so we can add gcc-specific compiler options These were suggested by Junio at some stage. Signed-off-by: Johannes Schindelin --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 690ac55b7d..e0f9a631c2 100644 --- a/Makefile +++ b/Makefile @@ -905,6 +905,9 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_REGEX = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" + # We have GCC, so let's make use of those nice options + COMPAT_CFLAGS += -Werror -Wno-pointer-to-int-cast \ + -Wold-style-definition -Wdeclaration-after-statement COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe From 8d7c8c95b6d995555d514b43ab6969a1cf7e3044 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 16 Aug 2009 13:53:30 +0800 Subject: [PATCH 602/781] Define SNPRINTF_SIZE_CORR=1 for Microsoft Visual C++ The Microsoft C runtime's vsnprintf function does not add NUL at the end of the buffer. Further, Microsoft deprecated vsnprintf in favor of _vsnprintf, so add a #define to that end. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/snprintf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index 6c0fb056a5..47b2b8a55e 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -6,7 +6,7 @@ * number of characters to write without the trailing NUL. */ #ifndef SNPRINTF_SIZE_CORR -#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 4 +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 4 || defined(_MSC_VER) #define SNPRINTF_SIZE_CORR 1 #else #define SNPRINTF_SIZE_CORR 0 @@ -14,6 +14,11 @@ #endif #undef vsnprintf + +#if defined(_MSC_VER) +#define vsnprintf _vsnprintf +#endif + int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; From d84f77b0cc2381c59d39011d92bd0ad6740f96ab Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 18 Aug 2009 23:39:54 +0800 Subject: [PATCH 603/781] Test for WIN32 instead of __MINGW32_ The code which is conditional on MinGW32 is actually conditional on Windows. Use the WIN32 symbol, which is defined by the MINGW32 and MSVC environments, but not by Cygwin. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- help.c | 2 +- run-command.c | 8 ++++---- run-command.h | 2 +- setup.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/help.c b/help.c index 399b0b40f4..9dae4e7551 100644 --- a/help.c +++ b/help.c @@ -126,7 +126,7 @@ static int is_executable(const char *name) !S_ISREG(st.st_mode)) return 0; -#ifdef __MINGW32__ +#ifdef WIN32 { /* cannot trust the executable bit, peek into the file instead */ char buf[3] = { 0 }; int n; diff --git a/run-command.c b/run-command.c index d1df7abe9a..d0833f846e 100644 --- a/run-command.c +++ b/run-command.c @@ -67,7 +67,7 @@ int start_command(struct child_process *cmd) trace_argv_printf(cmd->argv, "trace: run_command:"); -#ifndef __MINGW32__ +#ifndef WIN32 fflush(NULL); cmd->pid = fork(); if (!cmd->pid) { @@ -294,7 +294,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const return run_command(&cmd); } -#ifdef __MINGW32__ +#ifdef WIN32 static __stdcall unsigned run_thread(void *data) { struct async *async = data; @@ -310,7 +310,7 @@ int start_async(struct async *async) return error("cannot create pipe: %s", strerror(errno)); async->out = pipe_out[0]; -#ifndef __MINGW32__ +#ifndef WIN32 /* Flush stdio before fork() to avoid cloning buffers */ fflush(NULL); @@ -339,7 +339,7 @@ int start_async(struct async *async) int finish_async(struct async *async) { -#ifndef __MINGW32__ +#ifndef WIN32 int ret = 0; if (wait_or_whine(async->pid)) diff --git a/run-command.h b/run-command.h index e345502843..09a4cb25b2 100644 --- a/run-command.h +++ b/run-command.h @@ -79,7 +79,7 @@ struct async { int (*proc)(int fd, void *data); void *data; int out; /* caller reads from here and closes it */ -#ifndef __MINGW32__ +#ifndef WIN32 pid_t pid; #else HANDLE tid; diff --git a/setup.c b/setup.c index e3781b656d..029371e584 100644 --- a/setup.c +++ b/setup.c @@ -41,7 +41,7 @@ const char *prefix_path(const char *prefix, int len, const char *path) const char *prefix_filename(const char *pfx, int pfx_len, const char *arg) { static char path[PATH_MAX]; -#ifndef __MINGW32__ +#ifndef WIN32 if (!pfx || !*pfx || is_absolute_path(arg)) return arg; memcpy(path, pfx, pfx_len); From e76177f62a158b71c22cc3f7fa3aaa0ffa646860 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 17 Aug 2009 14:52:01 +0800 Subject: [PATCH 604/781] mingw.c: Use the O_BINARY flag to open files On Windows, non-text files must be opened using the O_BINARY flag. MinGW does this for us automatically, but Microsoft Visual C++ does not. So let's be explicit. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 449bea140a..5d3d24617e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -160,7 +160,7 @@ int mingw_open (const char *filename, int oflags, ...) if (!strcmp(filename, "/dev/null")) filename = "nul"; - fd = open(filename, oflags, mode); + fd = open(filename, oflags | O_BINARY, mode); if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { DWORD attrs = GetFileAttributes(filename); @@ -353,7 +353,7 @@ int mkstemp(char *template) char *filename = mktemp(template); if (filename == NULL) return -1; - return open(filename, O_RDWR | O_CREAT, 0600); + return open(filename, O_RDWR | O_CREAT | O_BINARY, 0600); } int gettimeofday(struct timeval *tv, void *tz) From d92d40ecd04798b7a31b9a5f38052d43c86e2ae0 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 18 Aug 2009 23:59:53 +0800 Subject: [PATCH 605/781] Place __stdcall between return value and function name MSVC requires that __stdcall be between return value and function name. Further, all Win32 API definitions look like this: TYPE WINAPI function_name... Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++-- run-command.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 5d3d24617e..fd642e4309 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1271,7 +1271,7 @@ static sig_handler_t timer_fn = SIG_DFL; * length to call the signal handler. */ -static __stdcall unsigned ticktack(void *dummy) +static unsigned __stdcall ticktack(void *dummy) { while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { if (timer_fn == SIG_DFL) @@ -1400,7 +1400,7 @@ void mingw_open_html(const char *unixpath) int link(const char *oldpath, const char *newpath) { - typedef BOOL WINAPI (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES); + typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES); static T create_hard_link = NULL; if (!create_hard_link) { create_hard_link = (T) GetProcAddress( diff --git a/run-command.c b/run-command.c index d0833f846e..62bea191d4 100644 --- a/run-command.c +++ b/run-command.c @@ -295,7 +295,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const } #ifdef WIN32 -static __stdcall unsigned run_thread(void *data) +static unsigned __stdcall run_thread(void *data) { struct async *async = data; return async->proc(async->fd_for_proc, async->data); From 8d28be57afb7077f61f41e98ee39cf50b6bda249 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 21 Aug 2009 10:34:05 +0200 Subject: [PATCH 606/781] Lines of git submodule output on Windows have CRLF Signed-off-by: Johannes Sixt --- t/t7407-submodule-foreach.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 2a527750ce..1f6480a1ae 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -11,6 +11,10 @@ that are currently checked out. . ./test-lib.sh +case $(uname -s) in +*MINGW*) GIT_TEST_CMP="diff -uw";; +esac + test_expect_success 'setup a submodule tree' ' echo file > file && From b7d572cbf2a1f7eed657c4eacf2caa58676e585d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 26 Jul 2009 05:08:42 +0200 Subject: [PATCH 607/781] Handle http.* config variables pointing to files gracefully on Windows On Windows, we would like to be able to have a default http.sslCAinfo that points to an MSys path (i.e. relative to the installation root of Git). As Git is a MinGW program, it has to handle the conversion of the MSys path into a MinGW32 path itself. Signed-off-by: Johannes Schindelin --- http.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/http.c b/http.c index 23b2a1932c..968520b8c4 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,6 @@ #include "http.h" #include "pack.h" +#include "exec_cmd.h" int data_received; int active_requests; @@ -129,6 +130,15 @@ static void process_curl_messages(void) } #endif +static int git_config_path(const char **result, + const char *var, const char *value) +{ + if (git_config_string(result, var, value)) + return 1; + *result = system_path(*result); + return 0; +} + static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { @@ -136,17 +146,17 @@ static int http_options(const char *var, const char *value, void *cb) return 0; } if (!strcmp("http.sslcert", var)) - return git_config_string(&ssl_cert, var, value); + return git_config_path(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 if (!strcmp("http.sslkey", var)) - return git_config_string(&ssl_key, var, value); + return git_config_path(&ssl_key, var, value); #endif #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) - return git_config_string(&ssl_capath, var, value); + return git_config_path(&ssl_capath, var, value); #endif if (!strcmp("http.sslcainfo", var)) - return git_config_string(&ssl_cainfo, var, value); + return git_config_path(&ssl_cainfo, var, value); if (!strcmp("http.sslcertpasswordprotected", var)) { if (git_config_bool(var, value)) ssl_cert_password_required = 1; From 35f39b14eaf0f2cb9a9c171ceb20e1a368785708 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Mon, 27 Jul 2009 21:05:40 +0200 Subject: [PATCH 608/781] send-email: accept absolute path even on Windows Signed-off-by: Johannes Schindelin --- git-send-email.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index f5ba4e7699..c4f1dfbd7a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -897,7 +897,7 @@ X-Mailer: git-send-email $gitversion if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif ($smtp_server =~ m#^/# || $smtp_server =~ m#[a-zA-Z]\:#) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { From ae3bedd5cdfa2d374a7ea00150ed113b0845b14a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 29 Jul 2009 22:21:55 +0200 Subject: [PATCH 609/781] Skip tests requiring 'iconv' when that is not found Signed-off-by: Johannes Schindelin --- t/t3900-i18n-commit.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 256c4c9701..a0fb178a67 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -64,6 +64,13 @@ test_expect_success 'config to remove customization' ' git config i18n.commitencoding UTF-8 ' +iconv --help 2>/dev/null >/dev/null +test $? = 127 && { + say "No iconv found; skip rest" + test_done + exit +} + test_expect_success 'ISO8859-1 should be shown in UTF-8 now' ' compare_with ISO8859-1 "$TEST_DIRECTORY"/t3900/1-UTF-8.txt ' From 043a43e7ec1ca4aa492406f438d89e1f35df127a Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Mon, 10 Aug 2009 12:47:37 +0200 Subject: [PATCH 610/781] Symlink support Add symlink support; with UAC, you may need administrator's privileges to create symlinks, but you can at least read them. As reparse points on Windows differentiate between file and directory links, we just assume that file links are meant for the time being; it might be very hard to determine the type before the target exists, but it is thinkable to change the type on-the-fly. A bridge to cross when we arrive there (read: something for somebody to fix who actually has that problem). Signed-off-by: Johannes Schindelin --- compat/mingw.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++- compat/mingw.h | 6 ++--- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6b5b5b2c70..4b1073d49a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1,6 +1,7 @@ #include "../git-compat-util.h" #include "win32.h" #include +#include #include "../strbuf.h" #include @@ -170,6 +171,21 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_mode = S_IREAD | S_IFLNK; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + } + FindClose(handle); + } + } return 0; } return -1; @@ -1175,6 +1191,58 @@ int link(const char *oldpath, const char *newpath) return 0; } +int symlink(const char *oldpath, const char *newpath) +{ + typedef BOOL WINAPI (*symlink_fn)(const char*, const char*, DWORD); + static symlink_fn create_symbolic_link = NULL; + if (!create_symbolic_link) { + create_symbolic_link = (symlink_fn) GetProcAddress( + GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkA"); + if (!create_symbolic_link) + create_symbolic_link = (symlink_fn)-1; + } + if (create_symbolic_link == (symlink_fn)-1) { + errno = ENOSYS; + return -1; + } + + if (!create_symbolic_link(newpath, oldpath, 0)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} + +int readlink(const char *path, char *buf, size_t bufsiz) +{ + HANDLE handle = CreateFile(path, GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle != INVALID_HANDLE_VALUE) { + unsigned char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + DWORD dummy = 0; + if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) { + REPARSE_DATA_BUFFER *b = (REPARSE_DATA_BUFFER *) buffer; + if (b->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + int len = b->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); + int offset = b->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + snprintf(buf, bufsiz, "%*ls", len, & b->SymbolicLinkReparseBuffer.PathBuffer[offset]); + CloseHandle(handle); + return len; + } + } + + CloseHandle(handle); + } + + errno = EINVAL; + return -1; +} + char *getpass(const char *prompt) { struct strbuf buf = STRBUF_INIT; @@ -1241,7 +1309,10 @@ struct dirent *mingw_readdir(DIR *dir) /* Set file type, based on WIN32_FIND_DATA */ mdir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + if ((buf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (buf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) + mdir->dd_dir.d_type |= DT_LNK; + else if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) mdir->dd_dir.d_type |= DT_DIR; else mdir->dd_dir.d_type |= DT_REG; diff --git a/compat/mingw.h b/compat/mingw.h index 5b5258bceb..2779bbb1a7 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -68,10 +68,6 @@ struct itimerval { * trivial stubs */ -static inline int readlink(const char *path, char *buf, size_t bufsiz) -{ errno = ENOSYS; return -1; } -static inline int symlink(const char *oldpath, const char *newpath) -{ errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } static inline int fork(void) @@ -140,6 +136,8 @@ struct passwd *getpwuid(int uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); +int symlink(const char *oldpath, const char *newpath); +int readlink(const char *path, char *buf, size_t bufsiz); /* * replacements of existing functions From e8a0ecc3acba68fbcf758553c10ab97eb6be8898 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 18:08:44 +0200 Subject: [PATCH 611/781] Fix style of multi-line comments In git.git, we want multi-line comments between single /* and */ in a line. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4b1073d49a..4e8402a941 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -151,7 +151,8 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } -/* We keep the do_lstat code in a separate function to avoid recursion. +/* + * We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. */ @@ -191,7 +192,8 @@ static int do_lstat(const char *file_name, struct stat *buf) return -1; } -/* We provide our own lstat/fstat functions, since the provided +/* + * We provide our own lstat/fstat functions, since the provided * lstat/fstat functions are so slow. These stat functions are * tailored for Git's usage (read: fast), and are not meant to be * complete. Note that Git stat()s are redirected to mingw_lstat() @@ -205,7 +207,8 @@ int mingw_lstat(const char *file_name, struct stat *buf) if (!do_lstat(file_name, buf)) return 0; - /* if file_name ended in a '/', Windows returned ENOENT; + /* + * if file_name ended in a '/', Windows returned ENOENT; * try again without trailing slashes */ if (errno != ENOENT) @@ -372,7 +375,8 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout) return errno = EINVAL, error("poll timeout not supported"); } - /* When there is only one fd to wait for, then we pretend that + /* + * When there is only one fd to wait for, then we pretend that * input is available and let the actual wait happen when the * caller invokes read(). */ @@ -412,7 +416,8 @@ repeat: ufds[i].revents = 0; } if (!pending) { - /* The only times that we spin here is when the process + /* + * The only times that we spin here is when the process * that is connected through the pipes is waiting for * its own input data to become available. But since * the process (pack-objects) is itself CPU intensive, @@ -668,7 +673,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (cons == INVALID_HANDLE_VALUE) { - /* There is no console associated with this process. + /* + * There is no console associated with this process. * Since the child is a console process, Windows * would normally create a console window. But * since we'll be redirecting std streams, we do @@ -679,7 +685,8 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, */ flags = DETACHED_PROCESS; } else { - /* There is already a console. If we specified + /* + * There is already a console. If we specified * DETACHED_PROCESS here, too, Windows would * disassociate the child from the console. * The same is true for CREATE_NO_WINDOW. @@ -1036,7 +1043,8 @@ static int timer_interval; static int one_shot; static sig_handler_t timer_fn = SIG_DFL; -/* The timer works like this: +/* + * The timer works like this: * The thread, ticktack(), is a trivial routine that most of the time * only waits to receive the signal to terminate. The main thread tells * the thread to terminate by setting the timer_event to the signalled @@ -1296,8 +1304,10 @@ struct dirent *mingw_readdir(DIR *dir) DWORD lasterr = GetLastError(); FindClose((HANDLE)dir->dd_handle); dir->dd_handle = (long)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. */ + /* + * 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; From 33dc23c8d16a7c99d98d839fb1987a3dda4ac25b Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:44:01 +0200 Subject: [PATCH 612/781] On Windows, mark directory hidden when starting with dot. In Windows a file or directory starting with a dot is not automatically hidden. So lets mark it as hidden when such a directory is created. This fixes msysGit issue 288. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 26 ++++++++++++++++++++++++++ compat/mingw.h | 9 +++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4e8402a941..e1ac77d0ed 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -119,6 +119,32 @@ static int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index 2779bbb1a7..0091ba7f3c 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -98,12 +98,6 @@ static inline int fcntl(int fd, int cmd, long arg) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} -#define mkdir mingw_mkdir - static inline int mingw_unlink(const char *pathname) { /* read-only files cannot be removed */ @@ -143,6 +137,9 @@ int readlink(const char *path, char *buf, size_t bufsiz); * replacements of existing functions */ +int mingw_mkdir(const char *path, int mode); +#define mkdir mingw_mkdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 250c0f4ea5657bb041e42cbac26f83cddc71c1d7 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Sat, 8 Aug 2009 22:59:27 +0200 Subject: [PATCH 613/781] Make auto-hiding dot-files optional on Windows. Although a file starting with a dot usually ought to be hidden, there could be reasons users do not want it to happen automatically. Original patch by Erik Faye-Lund. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- cache.h | 1 + compat/mingw.c | 3 ++- config.c | 5 +++++ environment.c | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cache.h b/cache.h index a5eeead1e2..767a50e4ed 100644 --- a/cache.h +++ b/cache.h @@ -525,6 +525,7 @@ extern int auto_crlf; extern int read_replace_refs; extern int fsync_object_files; extern int core_preload_index; +extern int hide_dotfiles; enum safe_crlf { SAFE_CRLF_FALSE = 0, diff --git a/compat/mingw.c b/compat/mingw.c index e1ac77d0ed..126b784119 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -131,8 +131,9 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { + extern int hide_dotfiles; int ret = mkdir(path); - if (!ret) { + if (!ret && hide_dotfiles) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when diff --git a/config.c b/config.c index c644061136..49010e4890 100644 --- a/config.c +++ b/config.c @@ -503,6 +503,11 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 5de6837840..ea1abbf289 100644 --- a/environment.c +++ b/environment.c @@ -50,6 +50,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_replace_parents = 1; +int hide_dotfiles = 1; /* Parallel index stat data preload? */ int core_preload_index = 0; From c1b3bedfaca75caacb072f5636167d23dc21103d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:08:05 +0200 Subject: [PATCH 614/781] Document the core.hideDotFiles variable Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index cd1781498e..bbb7ee262e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -133,6 +133,10 @@ core.fileMode:: the working copy are ignored; useful on broken filesystems like FAT. See linkgit:git-update-index[1]. True by default. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories whose name starts with a dot as hidden. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful From 5cdb2faf0eb8ba0572b798d7c29071a742a3cb66 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 9 Aug 2009 19:12:17 +0200 Subject: [PATCH 615/781] Windows: mark newly-created files whose name starts with a dot as hidden Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- Documentation/config.txt | 2 +- compat/mingw.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index bbb7ee262e..f9fd44e783 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -135,7 +135,7 @@ core.fileMode:: core.hideDotFiles:: (Windows-only) If true (which is the default), mark newly-created - directories whose name starts with a dot as hidden. + directories and files whose name starts with a dot as hidden. core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, diff --git a/compat/mingw.c b/compat/mingw.c index 126b784119..7bb2635b6d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,9 +2,11 @@ #include "win32.h" #include #include +#include #include "../strbuf.h" -#include +extern int hide_dotfiles; +unsigned int _CRT_fmode = _O_BINARY; static int err_win_to_posix(DWORD winerr) { @@ -131,7 +133,6 @@ static int make_hidden(const char *path) #undef mkdir int mingw_mkdir(const char *path, int mode) { - extern int hide_dotfiles; int ret = mkdir(path); if (!ret && hide_dotfiles) { /* @@ -167,6 +168,16 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && hide_dotfiles) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } From f95b4f00a6b3bfb64dae4a9d27bce4b8998562d1 Mon Sep 17 00:00:00 2001 From: Johan 't Hart Date: Wed, 12 Aug 2009 23:40:50 +0200 Subject: [PATCH 616/781] Windows: mark newly-created dot files by fopen() as hidden Files starting with a dot are considered "hidden", i.e. you have to ask explicitely to see them. On Windows, this is not done automatically, as Windows has its own mechanism. We already mark dot directories created by mkdir() and dot files created by open() as hidden, so let's do that with fopen(), too (but only if the file was just created, not when it already exists). Naturally, we make this behavior optional on core.hideDotFiles. Signed-off-by: Johannes Schindelin Acked-by: Johannes Sixt --- compat/mingw.c | 18 ++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 7bb2635b6d..556ed57fea 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -181,6 +181,24 @@ int mingw_open (const char *filename, int oflags, ...) return fd; } +#undef fopen +FILE *mingw_fopen (const char *filename, const char *mode) +{ + int hide = 0; + if (hide_dotfiles && basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); + + FILE *file = fopen(filename, mode); + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; +} + static inline time_t filetime_to_time_t(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; diff --git a/compat/mingw.h b/compat/mingw.h index 0091ba7f3c..0300a14c4a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -143,6 +143,9 @@ int mingw_mkdir(const char *path, int mode); int mingw_open (const char *filename, int oflags, ...); #define open mingw_open +FILE *mingw_fopen (const char *filename, const char *mode); +#define fopen mingw_fopen + char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd From 91b223732572b61f09efc29e62dba5e1c25b4f50 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:30:55 +0200 Subject: [PATCH 617/781] Fix a few old-style function declarations in compat/ Signed-off-by: Johannes Schindelin --- compat/fnmatch/fnmatch.c | 20 +-- compat/mingw.h | 2 +- compat/nedmalloc/malloc.c.h | 2 +- compat/nedmalloc/nedmalloc.c | 4 +- compat/regex/regex.c | 232 +++++++++++------------------------ 5 files changed, 81 insertions(+), 179 deletions(-) diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 14feac7fe1..1180fc793f 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -130,10 +130,7 @@ extern int errno; /* This function doesn't exist on most systems. */ # if !defined HAVE___STRCHRNUL && !defined _LIBC -static char * -__strchrnul (s, c) - const char *s; - int c; +static char * __strchrnul (const char *s, int c) { char *result = strchr (s, c); if (result == NULL) @@ -153,13 +150,8 @@ __strchrnul (s, c) static int internal_fnmatch __P ((const char *pattern, const char *string, int no_leading_period, int flags)) internal_function; -static int -internal_function -internal_fnmatch (pattern, string, no_leading_period, flags) - const char *pattern; - const char *string; - int no_leading_period; - int flags; +static int internal_function internal_fnmatch (const char *pattern, + const char *string, int no_leading_period, int flags) { register const char *p = pattern, *n = string; register unsigned char c; @@ -476,11 +468,7 @@ internal_fnmatch (pattern, string, no_leading_period, flags) } -int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +int fnmatch (const char *pattern, const char *string, int flags) { return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); } diff --git a/compat/mingw.h b/compat/mingw.h index 0300a14c4a..1b528daba2 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -80,7 +80,7 @@ static inline int getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline int getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index 74c42e3162..41b8698ab3 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -1802,7 +1802,7 @@ struct win32_mlock_t static MLOCK_T malloc_global_mutex = { 0, 0, 0}; -static FORCEINLINE long win32_getcurrentthreadid() { +static FORCEINLINE long win32_getcurrentthreadid(void) { #ifdef _MSC_VER #if defined(_M_IX86) long *threadstruct=(long *)__readfsdword(0x18); diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index d9a17a8057..229f942d10 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -159,8 +159,8 @@ struct mallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo(0); } #endif int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt(0, parno, value); } int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim(0, pad); } -void nedmalloc_stats() THROWSPEC { nedpmalloc_stats(0); } -size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint(0); } +void nedmalloc_stats(void) THROWSPEC { nedpmalloc_stats(0); } +size_t nedmalloc_footprint(void) THROWSPEC { return nedpmalloc_footprint(0); } void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc(0, elemsno, elemsize, chunks); } void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc(0, elems, sizes, chunks); } diff --git a/compat/regex/regex.c b/compat/regex/regex.c index 67d5c370a0..68de236af1 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -64,8 +64,7 @@ extern char *re_syntax_table; static char re_syntax_table[CHAR_SET_SIZE]; -static void -init_syntax_once () +static void init_syntax_once(void) { register int c; static int done = 0; @@ -380,10 +379,7 @@ typedef enum } while (0) #ifdef DEBUG -static void -extract_number (dest, source) - int *dest; - unsigned char *source; +static void extract_number(int *dest, unsigned char *source) { int temp = SIGN_EXTEND_CHAR (*(source + 1)); *dest = *source & 0377; @@ -407,10 +403,8 @@ extract_number (dest, source) } while (0) #ifdef DEBUG -static void -extract_number_and_incr (destination, source) - int *destination; - unsigned char **source; +static void extract_number_and_incr(int *destination, + unsigned char **source) { extract_number (destination, *source); *source += 2; @@ -455,9 +449,7 @@ extern void printchar (); /* Print the fastmap in human-readable form. */ -void -print_fastmap (fastmap) - char *fastmap; +void print_fastmap(char *fastmap) { unsigned was_a_range = 0; unsigned i = 0; @@ -487,10 +479,8 @@ print_fastmap (fastmap) /* Print a compiled pattern string in human-readable form, starting at the START pointer into it and ending just before the pointer END. */ -void -print_partial_compiled_pattern (start, end) - unsigned char *start; - unsigned char *end; +void print_partial_compiled_pattern(unsigned char *start, + unsigned char *end) { int mcnt, mcnt2; unsigned char *p = start; @@ -695,9 +685,7 @@ print_partial_compiled_pattern (start, end) } -void -print_compiled_pattern (bufp) - struct re_pattern_buffer *bufp; +void print_compiled_pattern(struct re_pattern_buffer *bufp) { unsigned char *buffer = bufp->buffer; @@ -722,13 +710,9 @@ print_compiled_pattern (bufp) } -void -print_double_string (where, string1, size1, string2, size2) - const char *where; - const char *string1; - const char *string2; - int size1; - int size2; +void print_double_string(const char *where, + const char *string1, int size1, + const char *string2, int size2) { unsigned this_char; @@ -777,9 +761,7 @@ reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; The argument SYNTAX is a bit mask comprised of the various bits defined in regex.h. We return the old syntax. */ -reg_syntax_t -re_set_syntax (syntax) - reg_syntax_t syntax; +reg_syntax_t re_set_syntax(reg_syntax_t syntax) { reg_syntax_t ret = re_syntax_options; @@ -1031,12 +1013,9 @@ typedef struct The `fastmap' and `newline_anchor' fields are neither examined nor set. */ -static reg_errcode_t -regex_compile (pattern, size, syntax, bufp) - const char *pattern; - int size; - reg_syntax_t syntax; - struct re_pattern_buffer *bufp; +static reg_errcode_t regex_compile(const char *pattern, + int size, reg_syntax_t syntax, + struct re_pattern_buffer *bufp) { /* We fetch characters from PATTERN here. Even though PATTERN is `char *' (i.e., signed), we declare these variables as unsigned, so @@ -2036,11 +2015,8 @@ regex_compile (pattern, size, syntax, bufp) /* Store OP at LOC followed by two-byte integer parameter ARG. */ -static void -store_op1 (op, loc, arg) - re_opcode_t op; - unsigned char *loc; - int arg; +static void store_op1(re_opcode_t op, unsigned char *loc, + int arg) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg); @@ -2049,11 +2025,8 @@ store_op1 (op, loc, arg) /* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -store_op2 (op, loc, arg1, arg2) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; +static void store_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2) { *loc = (unsigned char) op; STORE_NUMBER (loc + 1, arg1); @@ -2064,12 +2037,8 @@ store_op2 (op, loc, arg1, arg2) /* Copy the bytes from LOC to END to open up three bytes of space at LOC for OP followed by two-byte integer parameter ARG. */ -static void -insert_op1 (op, loc, arg, end) - re_opcode_t op; - unsigned char *loc; - int arg; - unsigned char *end; +static void insert_op1(re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 3; @@ -2083,12 +2052,8 @@ insert_op1 (op, loc, arg, end) /* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ -static void -insert_op2 (op, loc, arg1, arg2, end) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; - unsigned char *end; +static void insert_op2(re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end) { register unsigned char *pfrom = end; register unsigned char *pto = end + 5; @@ -2104,10 +2069,8 @@ insert_op2 (op, loc, arg1, arg2, end) after an alternative or a begin-subexpression. We assume there is at least one character before the ^. */ -static boolean -at_begline_loc_p (pattern, p, syntax) - const char *pattern, *p; - reg_syntax_t syntax; +static boolean at_begline_loc_p(const char *pattern, + const char *p, reg_syntax_t syntax) { const char *prev = p - 2; boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; @@ -2123,10 +2086,8 @@ at_begline_loc_p (pattern, p, syntax) /* The dual of at_begline_loc_p. This one is for $. We assume there is at least one character after the $, i.e., `P < PEND'. */ -static boolean -at_endline_loc_p (p, pend, syntax) - const char *p, *pend; - int syntax; +static boolean at_endline_loc_p(const char *p, + const char *pend, int syntax) { const char *next = p; boolean next_backslash = *next == '\\'; @@ -2145,10 +2106,8 @@ at_endline_loc_p (p, pend, syntax) /* Returns true if REGNUM is in one of COMPILE_STACK's elements and false if it's not. */ -static boolean -group_in_compile_stack (compile_stack, regnum) - compile_stack_type compile_stack; - regnum_t regnum; +static boolean group_in_compile_stack(compile_stack_type + compile_stack, regnum_t regnum) { int this_element; @@ -2173,12 +2132,9 @@ group_in_compile_stack (compile_stack, regnum) We use these short variable names so we can use the same macros as `regex_compile' itself. */ -static reg_errcode_t -compile_range (p_ptr, pend, translate, syntax, b) - const char **p_ptr, *pend; - char *translate; - reg_syntax_t syntax; - unsigned char *b; +static reg_errcode_t compile_range(const char **p_ptr, + const char *pend, char *translate, + reg_syntax_t syntax, unsigned char *b) { unsigned this_char; @@ -2505,9 +2461,7 @@ typedef struct Returns 0 if we succeed, -2 if an internal error. */ -int -re_compile_fastmap (bufp) - struct re_pattern_buffer *bufp; +int re_compile_fastmap(struct re_pattern_buffer *bufp) { int j, k; fail_stack_type fail_stack; @@ -2790,12 +2744,10 @@ re_compile_fastmap (bufp) PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ -void -re_set_registers (bufp, regs, num_regs, starts, ends) - struct re_pattern_buffer *bufp; - struct re_registers *regs; - unsigned num_regs; - regoff_t *starts, *ends; +void re_set_registers(struct re_pattern_buffer *bufp, + struct re_registers *regs, + unsigned num_regs, + regoff_t *starts, regoff_t *ends) { if (num_regs) { @@ -2817,12 +2769,10 @@ re_set_registers (bufp, regs, num_regs, starts, ends) /* Like re_search_2, below, but only one string is specified, and doesn't let you say where to stop matching. */ -int -re_search (bufp, string, size, startpos, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; - struct re_registers *regs; +int re_search(struct re_pattern_buffer *bufp, + const char *string, int size, + int startpos, int range, + struct re_registers *regs) { return re_search_2 (bufp, NULL, 0, string, size, startpos, range, regs, size); @@ -2850,15 +2800,11 @@ re_search (bufp, string, size, startpos, range, regs) found, -1 if no match, or -2 if error (such as failure stack overflow). */ -int -re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int startpos; - int range; - struct re_registers *regs; - int stop; +int re_search_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int startpos, int range, + struct re_registers *regs, int stop) { int val; register char *fastmap = bufp->fastmap; @@ -3109,12 +3055,9 @@ typedef union #ifndef emacs /* Emacs never uses this. */ /* re_match is like re_match_2 except it takes only a single string. */ -int -re_match (bufp, string, size, pos, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, pos; - struct re_registers *regs; +int re_match(struct re_pattern_buffer *bufp, + const char *string, int size, int pos, + struct re_registers *regs) { return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); } @@ -3134,14 +3077,10 @@ re_match (bufp, string, size, pos, regs) failure stack overflowing). Otherwise, we return the length of the matched substring. */ -int -re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int pos; - struct re_registers *regs; - int stop; +int re_match_2(struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, struct re_registers *regs, int stop) { /* General temporaries. */ int mcnt; @@ -4330,10 +4269,9 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) We don't handle duplicates properly (yet). */ -static boolean -group_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean group_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; /* Point to after the args to the start_memory. */ @@ -4439,10 +4377,9 @@ group_match_null_string_p (p, end, reg_info) It expects P to be the first byte of a single alternative and END one byte past the last. The alternative can contain groups. */ -static boolean -alt_match_null_string_p (p, end, reg_info) - unsigned char *p, *end; - register_info_type *reg_info; +static boolean alt_match_null_string_p(unsigned char *p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; unsigned char *p1 = p; @@ -4476,10 +4413,9 @@ alt_match_null_string_p (p, end, reg_info) Sets P to one after the op and its arguments, if any. */ -static boolean -common_op_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; +static boolean common_op_match_null_string_p(unsigned char **p, + unsigned char *end, + register_info_type *reg_info) { int mcnt; boolean ret; @@ -4564,13 +4500,8 @@ common_op_match_null_string_p (p, end, reg_info) /* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN bytes; nonzero otherwise. */ -static int -bcmp_translate( - unsigned char *s1, - unsigned char *s2, - int len, - char *translate -) +static int bcmp_translate(unsigned char *s1, unsigned char *s2, + int len, char *translate) { register unsigned char *p1 = s1, *p2 = s2; while (len) @@ -4592,11 +4523,8 @@ bcmp_translate( We call regex_compile to do the actual compilation. */ -const char * -re_compile_pattern (pattern, length, bufp) - const char *pattern; - int length; - struct re_pattern_buffer *bufp; +const char *re_compile_pattern(const char *pattern, + int length, struct re_pattern_buffer *bufp) { reg_errcode_t ret; @@ -4625,9 +4553,7 @@ re_compile_pattern (pattern, length, bufp) /* BSD has one and only one pattern buffer. */ static struct re_pattern_buffer re_comp_buf; -char * -re_comp (s) - const char *s; +char *re_comp(const char *s) { reg_errcode_t ret; @@ -4663,9 +4589,7 @@ re_comp (s) } -int -re_exec (s) - const char *s; +int re_exec(const char *s) { const int len = strlen (s); return @@ -4711,11 +4635,7 @@ re_exec (s) It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for the return codes and their meanings.) */ -int -regcomp (preg, pattern, cflags) - regex_t *preg; - const char *pattern; - int cflags; +int regcomp(regex_t *preg, const char *pattern, int cflags) { reg_errcode_t ret; unsigned syntax @@ -4786,13 +4706,9 @@ regcomp (preg, pattern, cflags) We return 0 if we find a match and REG_NOMATCH if not. */ -int -regexec (preg, string, nmatch, pmatch, eflags) - const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; - int eflags; +int regexec(const regex_t *preg, const char *string, + size_t nmatch, regmatch_t pmatch[], + int eflags) { int ret; struct re_registers regs; @@ -4892,9 +4808,7 @@ regerror(int errcode, const regex_t *preg, /* Free dynamically allocated space used by PREG. */ -void -regfree (preg) - regex_t *preg; +void regfree(regex_t *preg) { if (preg->buffer != NULL) free (preg->buffer); From 12b6e8cb65aa65f22f243a5b7d347175bbf3fd20 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 10:31:29 +0200 Subject: [PATCH 618/781] compat/mingw.c: Fix declaration after instruction Signed-off-by: Johannes Schindelin --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 556ed57fea..9e0f5e0ffb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -185,10 +185,11 @@ int mingw_open (const char *filename, int oflags, ...) FILE *mingw_fopen (const char *filename, const char *mode) { int hide = 0; + FILE *file; if (hide_dotfiles && basename((char*)filename)[0] == '.') hide = access(filename, F_OK); - FILE *file = fopen(filename, mode); + file = fopen(filename, mode); /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when From a2546af6686b7f55ce21660821dba2bde641efcf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 19 Aug 2009 09:59:58 +0200 Subject: [PATCH 619/781] MinGW means that we have gcc, so we can add gcc-specific compiler options These were suggested by Junio at some stage. Signed-off-by: Johannes Schindelin --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index fea237bc80..8f1f157e4f 100644 --- a/Makefile +++ b/Makefile @@ -980,6 +980,9 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_REGEX = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" + # We have GCC, so let's make use of those nice options + COMPAT_CFLAGS += -Werror -Wno-pointer-to-int-cast \ + -Wold-style-definition -Wdeclaration-after-statement COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe From c124c9679255ad759d3441c5fd946a249fd39be3 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Sun, 16 Aug 2009 13:53:30 +0800 Subject: [PATCH 620/781] Define SNPRINTF_SIZE_CORR=1 for Microsoft Visual C++ The Microsoft C runtime's vsnprintf function does not add NUL at the end of the buffer. Further, Microsoft deprecated vsnprintf in favor of _vsnprintf, so add a #define to that end. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/snprintf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compat/snprintf.c b/compat/snprintf.c index e1e0e7543d..28b02c6837 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -9,7 +9,7 @@ * always have room for a trailing NUL byte. */ #ifndef SNPRINTF_SIZE_CORR -#if defined(WIN32) && (!defined(__GNUC__) || __GNUC__ < 4) +#if defined(WIN32) && defined(__GNUC__) && __GNUC__ < 4 || defined(_MSC_VER) #define SNPRINTF_SIZE_CORR 1 #else #define SNPRINTF_SIZE_CORR 0 @@ -17,6 +17,11 @@ #endif #undef vsnprintf + +#if defined(_MSC_VER) +#define vsnprintf _vsnprintf +#endif + int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap) { char *s; From 62d2d6829cc7adab30cb2b52bc90a0d70f6952c1 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 17 Aug 2009 14:52:01 +0800 Subject: [PATCH 621/781] mingw.c: Use the O_BINARY flag to open files On Windows, non-text files must be opened using the O_BINARY flag. MinGW does this for us automatically, but Microsoft Visual C++ does not. So let's be explicit. Signed-off-by: Frank Li Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9e0f5e0ffb..10d67964ed 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -161,7 +161,7 @@ int mingw_open (const char *filename, int oflags, ...) if (!strcmp(filename, "/dev/null")) filename = "nul"; - fd = open(filename, oflags, mode); + fd = open(filename, oflags | O_BINARY, mode); if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) { DWORD attrs = GetFileAttributes(filename); @@ -354,7 +354,7 @@ int mkstemp(char *template) char *filename = mktemp(template); if (filename == NULL) return -1; - return open(filename, O_RDWR | O_CREAT, 0600); + return open(filename, O_RDWR | O_CREAT | O_BINARY, 0600); } int gettimeofday(struct timeval *tv, void *tz) From 127aa63757870526b106c045310a3b6c4cee0324 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 622/781] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index c132f50da5..cca351288e 100755 --- a/git-am.sh +++ b/git-am.sh @@ -172,7 +172,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 8ed9ebe27ae70f634f4f734aa581ca796ccf906a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 14 Oct 2009 11:51:03 -0700 Subject: [PATCH 623/781] CRLF in info/grafts causes parse error "Yann Dirson" writes: > When creating an info/grafts under windows, one typically gets a CRLF file. > Then: > > * gitk loudly complains about "bad graft data" > * "git log > /dev/null" does not report any problem > * "git log > foo" does report the problem on sdterr, but exit code is still 0 > > Recreating the graft as a LF file (eg with "echo" or "printf") causes the > graft to be properly interpreted. I do not see any reason to forbid trailing CR at the end of the line (for that matter, any trailing whitespaces) in the said file. How about doing this? commit.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) --- commit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commit.c b/commit.c index fedbd5e526..0db2124f98 100644 --- a/commit.c +++ b/commit.c @@ -132,8 +132,8 @@ struct commit_graft *read_graft_line(char *buf, int len) int i; struct commit_graft *graft = NULL; - if (buf[len-1] == '\n') - buf[--len] = 0; + while (isspace(buf[len-1])) + buf[--len] = '\0'; if (buf[0] == '#' || buf[0] == '\0') return NULL; if ((len + 1) % 41) { From cd4896c3b6f79d7eec4a17e7f23d1ea446bd6323 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 624/781] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 8f1f157e4f..1acad5fd5b 100644 --- a/Makefile +++ b/Makefile @@ -1601,6 +1601,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1608,6 +1609,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From ccc5cdf764be2d46b91a5840de5edd763851bf91 Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Mon, 26 Oct 2009 23:39:31 +0100 Subject: [PATCH 625/781] Replace dir separator in symlinks It seems quite a few windows utilities cannot handle '../' in symlinks, so we replace every / with a \. While at it, replace make_backslash_path with a thread-safe version. Signed-off-by: Thorvald Natvig Signed-off-by: Johannes Schindelin --- compat/mingw.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 10d67964ed..2424380cba 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1213,9 +1213,8 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler) return old; } -static const char *make_backslash_path(const char *path) +static const char *make_backslash_path(const char *path, char *buf) { - static char buf[PATH_MAX + 1]; char *c; if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) @@ -1230,7 +1229,8 @@ static const char *make_backslash_path(const char *path) void mingw_open_html(const char *unixpath) { - const char *htmlpath = make_backslash_path(unixpath); + char buf[PATH_MAX + 1]; + const char *htmlpath = make_backslash_path(unixpath, buf); printf("Launching default browser to display HTML ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); } @@ -1260,6 +1260,8 @@ int symlink(const char *oldpath, const char *newpath) { typedef BOOL WINAPI (*symlink_fn)(const char*, const char*, DWORD); static symlink_fn create_symbolic_link = NULL; + char buf[PATH_MAX + 1]; + if (!create_symbolic_link) { create_symbolic_link = (symlink_fn) GetProcAddress( GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkA"); @@ -1271,7 +1273,7 @@ int symlink(const char *oldpath, const char *newpath) return -1; } - if (!create_symbolic_link(newpath, oldpath, 0)) { + if (!create_symbolic_link(newpath, make_backslash_path(oldpath, buf), 0)) { errno = err_win_to_posix(GetLastError()); return -1; } @@ -1295,7 +1297,11 @@ int readlink(const char *path, char *buf, size_t bufsiz) if (b->ReparseTag == IO_REPARSE_TAG_SYMLINK) { int len = b->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); int offset = b->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + int i; snprintf(buf, bufsiz, "%*ls", len, & b->SymbolicLinkReparseBuffer.PathBuffer[offset]); + for (i = 0; i < len; i++) + if (buf[i] == '\\') + buf[i] = '/'; CloseHandle(handle); return len; } From 9ba38c833b5bbe06f74f19bc6911036ef6a9fb09 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 5 Oct 2009 10:22:18 +0200 Subject: [PATCH 626/781] Make the MSVC projects use PDB/IDB files named after the project Instead of having all PDB files for all projects named "vc90.pdb", name them after the respective project to make the relation more clear (and to avoid name clashes when copying files around). Signed-off-by: Sebastian Schuberth Acked-by: Marius Storm-Olsen Signed-off-by: Johannes Schindelin --- contrib/buildsystems/Generators/Vcproj.pm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/buildsystems/Generators/Vcproj.pm b/contrib/buildsystems/Generators/Vcproj.pm index be94ba18d2..cfa74adcc2 100644 --- a/contrib/buildsystems/Generators/Vcproj.pm +++ b/contrib/buildsystems/Generators/Vcproj.pm @@ -178,6 +178,7 @@ sub createLibProject { MinimalRebuild="true" RuntimeLibrary="1" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> @@ -244,6 +245,7 @@ sub createLibProject { RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> @@ -401,6 +403,7 @@ sub createAppProject { MinimalRebuild="true" RuntimeLibrary="1" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> @@ -472,6 +475,7 @@ sub createAppProject { RuntimeLibrary="0" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" + ProgramDataBaseFileName="\$(IntDir)\\\$(TargetName).pdb" WarningLevel="3" DebugInformationFormat="3" /> From 7e9e93bc6764d65e26a5cb4f3fc6462c52ab075d Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 19 Oct 2009 18:28:50 +0200 Subject: [PATCH 627/781] Use faster byte swapping when compiling with MSVC When compiling with MSVC on x86-compatible, use an intrinsic for byte swapping. In contrast to the GCC path, we do not prefer inline assembly here as it is not supported for the x64 platform. Signed-off-by: Sebastian Schuberth Signed-off-by: Johannes Schindelin --- compat/bswap.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compat/bswap.h b/compat/bswap.h index 5cc4acbfcc..279e0b48b1 100644 --- a/compat/bswap.h +++ b/compat/bswap.h @@ -28,6 +28,16 @@ static inline uint32_t default_swab32(uint32_t val) } \ __res; }) +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + +#include + +#define bswap32(x) _byteswap_ulong(x) + +#endif + +#ifdef bswap32 + #undef ntohl #undef htonl #define ntohl(x) bswap32(x) From 1abf3a543677b83852b21f96d02a4baeebf49567 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Tue, 27 Oct 2009 12:13:05 +0100 Subject: [PATCH 628/781] Do not try to remove directories when removing old links When building Git with MSVC on Windows, directories named after the Git alias are created for the output files, e.g. there is a "git-merge-index" directory next to the "git-merge-index.exe" executable in the build root. Previously, "make all" just checked if "git-merge-index" and "git-merge-index.exe" are the same file, and if not, tried to remove "git-merge-index". This fails in the case of "git-merge-index" being a directory, which is why this is checked now. Signed-off-by: Sebastian Schuberth Signed-off-by: Johannes Schindelin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1acad5fd5b..393d4b1f2a 100644 --- a/Makefile +++ b/Makefile @@ -1378,7 +1378,7 @@ SHELL = $(SHELL_PATH) all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS ifneq (,$X) - $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';) + $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';) endif all:: From 915ac13797b2224295a21233e8ca3d6981a02fac Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 629/781] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 1b528daba2..adf5ff5686 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -5,6 +5,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -70,17 +71,17 @@ struct itimerval { static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid(void) +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -106,7 +107,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -126,7 +127,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 71d16883000440739a8b4f78435fefed1d17b974 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 630/781] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index adf5ff5686..45cb239872 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -11,12 +11,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From f1d8529445e627801b433fffcc034ad90a7e99ff Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 631/781] core.hidedotfiles: only hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 2 ++ builtin-init-db.c | 1 + cache.h | 8 +++++++- compat/mingw.c | 16 ++++++++++++---- compat/mingw.h | 3 +++ config.c | 4 ++++ environment.c | 2 +- git-compat-util.h | 4 ++++ 8 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index f9fd44e783..6370d6f6f7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -136,6 +136,8 @@ core.fileMode:: core.hideDotFiles:: (Windows-only) If true (which is the default), mark newly-created directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, diff --git a/builtin-init-db.c b/builtin-init-db.c index dd84caecbc..8640643675 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -298,6 +298,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 767a50e4ed..d3bfe0d36f 100644 --- a/cache.h +++ b/cache.h @@ -525,7 +525,13 @@ extern int auto_crlf; extern int read_replace_refs; extern int fsync_object_files; extern int core_preload_index; -extern int hide_dotfiles; + +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; enum safe_crlf { SAFE_CRLF_FALSE = 0, diff --git a/compat/mingw.c b/compat/mingw.c index 2424380cba..45c5a19aaa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -4,8 +4,8 @@ #include #include #include "../strbuf.h" +#include "../cache.h" -extern int hide_dotfiles; unsigned int _CRT_fmode = _O_BINARY; static int err_win_to_posix(DWORD winerr) @@ -130,11 +130,17 @@ static int make_hidden(const char *path) return -1; } +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + #undef mkdir int mingw_mkdir(const char *path, int mode) { int ret = mkdir(path); - if (!ret && hide_dotfiles) { + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when @@ -168,7 +174,8 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } - if ((oflags & O_CREAT) && fd >= 0 && hide_dotfiles) { + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when @@ -186,7 +193,8 @@ FILE *mingw_fopen (const char *filename, const char *mode) { int hide = 0; FILE *file; - if (hide_dotfiles && basename((char*)filename)[0] == '.') + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') hide = access(filename, F_OK); file = fopen(filename, mode); diff --git a/compat/mingw.h b/compat/mingw.h index 45cb239872..364cc72bae 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -231,6 +231,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 49010e4890..c8cdb81633 100644 --- a/config.c +++ b/config.c @@ -504,6 +504,10 @@ static int git_default_core_config(const char *var, const char *value) } if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } hide_dotfiles = git_config_bool(var, value); return 0; } diff --git a/environment.c b/environment.c index ea1abbf289..ccbae176ea 100644 --- a/environment.c +++ b/environment.c @@ -50,7 +50,7 @@ enum push_default_type push_default = PUSH_DEFAULT_MATCHING; #endif enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; int grafts_replace_parents = 1; -int hide_dotfiles = 1; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index ef60803384..db19559bc3 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -464,4 +464,8 @@ void git_qsort(void *base, size_t nmemb, size_t size, */ int unlink_or_warn(const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From c8364b54aacb2c1c6cbf4200618a5241764c13d3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 632/781] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 45c5a19aaa..33b6b80e05 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -134,6 +134,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 9e44c8e5267528713a26f22d4355327076df29ec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 633/781] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index cca351288e..c132f50da5 100755 --- a/git-am.sh +++ b/git-am.sh @@ -172,7 +172,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 2a3fb596222c33c331ab82548501c03b0c68ae35 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Sat, 23 Jan 2010 15:20:28 +0100 Subject: [PATCH 634/781] If deriving SVN_SSH from GIT_SSH on msys, also add quotes In contrast to GIT_SSH, SVN_SSH requires quotes for paths that contain spaces. As GIT_SSH will not work if it contains quotes, it is safe to assume it never contains quotes. Also, adding quotes to SVN_SSH for paths that do not contain spaces does no harm. So we always add quotes when deriving SVN_SSH from GIT_SSH. This fixes msysGit issue 385, see http://code.google.com/p/msysgit/issues/detail?id=385 Signed-off-by: Sebastian Schuberth Signed-off-by: Johannes Schindelin --- git-svn.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-svn.perl b/git-svn.perl index b321c968af..4f7dc2b73b 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -26,6 +26,7 @@ if (! exists $ENV{SVN_SSH}) { $ENV{SVN_SSH} = $ENV{GIT_SSH}; if ($^O eq 'msys') { $ENV{SVN_SSH} =~ s/\\/\\\\/g; + $ENV{SVN_SSH} =~ s/(.*)/"$1"/; } } } From b27a86a21e5b42722c0c8abb7491f032c5549778 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 635/781] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 2539a7bdb81dcc920c97837a9bfb9d4c4e1ac280 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Mon, 15 Feb 2010 22:36:28 +0100 Subject: [PATCH 636/781] [PATCH] fix threaded grep for machines with only one cpu In case the machine has only one cpu the mutex initialization was skipped. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- builtin-grep.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 26d4deb1cc..644051c200 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -220,12 +220,6 @@ static void start_threads(struct grep_opt *opt) { int i; - pthread_mutex_init(&grep_mutex, NULL); - pthread_mutex_init(&read_sha1_mutex, NULL); - pthread_cond_init(&cond_add, NULL); - pthread_cond_init(&cond_write, NULL); - pthread_cond_init(&cond_result, NULL); - for (i = 0; i < ARRAY_SIZE(todo); i++) { strbuf_init(&todo[i].out, 0); } @@ -880,6 +874,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; + pthread_mutex_init(&grep_mutex, NULL); + pthread_mutex_init(&read_sha1_mutex, NULL); + pthread_cond_init(&cond_add, NULL); + pthread_cond_init(&cond_write, NULL); + pthread_cond_init(&cond_result, NULL); + if (use_threads) start_threads(&opt); #else From 51cb20e7373c951f6b0c6c9368d196c26c41c443 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 637/781] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index f11f98c3ce..90541a39c6 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index afd3053f96..f6a159044f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -776,6 +776,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From d2d1e96d8aa6d9e76d070ddc1a278f1126446bc0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 Feb 2010 02:12:43 +0100 Subject: [PATCH 638/781] Revert "[PATCH] fix threaded grep for machines with only one cpu" This reverts commit 2539a7bdb81dcc920c97837a9bfb9d4c4e1ac280. --- builtin-grep.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 644051c200..26d4deb1cc 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -220,6 +220,12 @@ static void start_threads(struct grep_opt *opt) { int i; + pthread_mutex_init(&grep_mutex, NULL); + pthread_mutex_init(&read_sha1_mutex, NULL); + pthread_cond_init(&cond_add, NULL); + pthread_cond_init(&cond_write, NULL); + pthread_cond_init(&cond_result, NULL); + for (i = 0; i < ARRAY_SIZE(todo); i++) { strbuf_init(&todo[i].out, 0); } @@ -874,12 +880,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (online_cpus() == 1 || !grep_threads_ok(&opt)) use_threads = 0; - pthread_mutex_init(&grep_mutex, NULL); - pthread_mutex_init(&read_sha1_mutex, NULL); - pthread_cond_init(&cond_add, NULL); - pthread_cond_init(&cond_write, NULL); - pthread_cond_init(&cond_result, NULL); - if (use_threads) start_threads(&opt); #else From 3daa340643aada6f27d3f3acf5c91549d710019a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 16 Feb 2010 15:59:43 -0800 Subject: [PATCH 639/781] Fix use of mutex in threaded grep The program can decide at runtime not to use threading even if the support is compiled in. In such a case, mutexes are not necessary and left uninitialized. But the code incorrectly tried to take and release the read_sha1_mutex unconditionally. Signed-off-by: Junio C Hamano Acked-by: Fredrik Kuivinen Diagnosed-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- builtin-grep.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/builtin-grep.c b/builtin-grep.c index 26d4deb1cc..8cec8b6e38 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -408,15 +408,25 @@ static int pathspec_matches(const char **paths, const char *name, int max_depth) return 0; } +static void *read_sha1_file_locked(const unsigned char *sha1, enum object_type *type, unsigned long *size) +{ + void *data; + + if (use_threads) { + read_sha1_lock(); + data = read_sha1_file(sha1, type, size); + read_sha1_unlock(); + } else { + data = read_sha1_file(sha1, type, size); + } + return data; +} + static void *load_sha1(const unsigned char *sha1, unsigned long *size, const char *name) { enum object_type type; - char *data; - - read_sha1_lock(); - data = read_sha1_file(sha1, &type, size); - read_sha1_unlock(); + void *data = read_sha1_file_locked(sha1, &type, size); if (!data) error("'%s': unable to read %s", name, sha1_to_hex(sha1)); @@ -605,10 +615,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths, void *data; unsigned long size; - read_sha1_lock(); - data = read_sha1_file(entry.sha1, &type, &size); - read_sha1_unlock(); - + data = read_sha1_file_locked(entry.sha1, &type, &size); if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); From c44de514e5db1ab4ef77c621199b1faffa624061 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 640/781] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 90b60aea820afcec62f73f15f279e918261c6935 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 641/781] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4e409f0c2b..265646f735 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -157,6 +157,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ab7cf886bb..f66c83166b 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -112,14 +112,6 @@ static inline int fcntl(int fd, int cmd, long arg) * simple adaptors */ -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -175,6 +167,9 @@ int readlink(const char *path, char *buf, size_t bufsiz); int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 918092c518a526ab8bde8cbbe62096c3b2ea6b17 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 642/781] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 265646f735..e637209baf 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -7,6 +7,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -160,9 +161,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1220,7 +1236,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 7a7e4a52085cf3e82cf7b697787fc3e79bd03aaa Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 643/781] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 8dfb578d003da0d4f07466d7b9fbbb14f5d09a74 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 644/781] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 89f5b0c385af73ec27499c41d42c45e540203ef3 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 645/781] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From c31440e711dd6d2910ad70c9ba0ed6f0e2292862 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 23 Feb 2010 12:42:56 +0100 Subject: [PATCH 646/781] Print RUNTIME_PREFIX warning only when GIT_TRACE is set When RUNTIME_PREFIX is enabled, the installation prefix is derived by trying a limited set of known locations where the git executable can reside. If none of these is found, a warning is emitted. When git is built in a directory that matches neither of these known names, the warning would always be emitted when the uninstalled executable is run. This is a problem on Windows, where gitk picks the uninstalled git when invoked from the build directory and gets confused by the warning. Print the warning only when GIT_TRACE is set. Signed-off-by: Johannes Sixt Signed-off-by: Johannes Schindelin --- exec_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec_cmd.c b/exec_cmd.c index 408e4e55e1..b2c07c70ce 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -28,7 +28,7 @@ const char *system_path(const char *path) !(prefix = strip_path_suffix(argv0_path, BINDIR)) && !(prefix = strip_path_suffix(argv0_path, "git"))) { prefix = PREFIX; - fprintf(stderr, "RUNTIME_PREFIX requested, " + trace_printf("RUNTIME_PREFIX requested, " "but prefix computation failed. " "Using static fallback '%s'.\n", prefix); } From 6a5f4e550b8b7e8140c0792eab123ebd90f6bb1f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 647/781] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index e637209baf..5326a1bd9a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -158,6 +159,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -178,6 +227,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1277,6 +1330,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 03a5d44342b5427244592fe1d1cf73a5012dfd9f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 648/781] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 5326a1bd9a..d7d8970111 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -234,6 +234,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index f66c83166b..4650d8a882 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -170,6 +170,9 @@ int mingw_mkdir(const char *path, int mode); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 4d055078ccc7dfbd844aa8862dba79edbd6a003f Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 649/781] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From b38a696841b1f1a74b35e5cac7074f8077ff7d07 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Mar 2010 00:41:08 +0100 Subject: [PATCH 650/781] mingw: support fopen(/dev/null) Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index e637209baf..d131092a6e 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -225,7 +225,7 @@ FILE *mingw_fopen (const char *filename, const char *mode) basename((char*)filename)[0] == '.') hide = access(filename, F_OK); - file = fopen(filename, mode); + file = fopen(strcmp(filename, "/dev/null") ? filename : "NUL", mode); /* * In Windows a file or dir starting with a dot is not * automatically hidden. So lets mark it as hidden when From f34a7373a412158e6b3611176a136c43179fe024 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 651/781] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 0c48e5ba6f79ff5a28a1aa2fa363e4cd39a6fc36 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 652/781] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From ef6aded56341fbb09c13c3ca96bd914c7a2509f6 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 653/781] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 326fd3a1c2d2f40673637b30d61705b053abd138 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 654/781] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..2f1d076af7 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From dceac1e66c4335ed59fe68adaf0c89fe0caa51fd Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 655/781] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index cdedaa7121..d0a51ef5d1 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2815,6 +2817,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From 86058f6803510aface880d2e7690d45d2eb62b08 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 656/781] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 4a034803db43183ad347092fcb6a34ce5dbac367 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 657/781] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index cdedaa7121..a22888c862 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9397,7 +9397,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 888ef1ec0c362a58a89b2427659351f315dae11c Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 658/781] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 87ad2b93f7..103d8d884d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9401,11 +9401,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From ccc538e353bc7d137b1fe59b19f5a7ae85aaa312 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 659/781] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 31 ++++++++++++++++++++++++------- compat/mingw.h | 3 ++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 0df1a3d5ea..9c10a4cb79 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -334,8 +334,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) * We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -357,11 +360,16 @@ static int do_lstat(const char *file_name, struct stat *buf) if (handle != INVALID_HANDLE_VALUE) { if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { - char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - buf->st_mode = S_IREAD | S_IFLNK; + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) buf->st_mode |= S_IWRITE; - buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); } FindClose(handle); } @@ -378,12 +386,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(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]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* @@ -403,7 +411,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index 4650d8a882..ff5477b553 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -222,10 +222,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From db2af245ebab3f6a52abc3efb0ec76bd543b59f3 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 660/781] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9c10a4cb79..fc53b79284 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1548,6 +1548,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1557,9 +1558,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 5cf938f51e7331e269078eff85f3460c3926681e Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 661/781] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 5386504790..8cb12222ca 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -291,4 +291,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index c1951bb021..8132d24b4d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -773,6 +773,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 9d2ad68fc674c54698248d7834151e250fd70f64 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 662/781] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index fc53b79284..9af3c60814 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -134,7 +134,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 5c1e99faf4cbe2c171fcad72812d4ff8ca48b47f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 663/781] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 9af3c60814..6e04c55ce4 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -364,7 +364,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From d00d6559bb551fe6e1cd6543804f6a36cf2f6475 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 664/781] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index 9d30ddb28d..4e29bbee70 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -582,7 +582,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1001,28 +1000,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From 8e47f498ab4117d7f256f93d8d437dbbd4a999bb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 665/781] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index 4e29bbee70..ec397cdb1e 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include "thread-utils.h" @@ -548,6 +549,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -773,9 +799,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -859,6 +887,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -934,6 +964,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -999,6 +1043,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1021,6 +1088,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 6bae30545b..6db05e0df8 100644 --- a/git.c +++ b/git.c @@ -320,7 +320,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep, RUN_SETUP }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From c0d50e35f612535c16638b932287c91ed39f929a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 666/781] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index ec397cdb1e..ba5452642f 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -799,7 +799,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -887,8 +887,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -965,16 +966,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From cf4df60f7a12f22ea81385f176907320b422fc2e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 667/781] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..11c35afb9c 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 10b6d8a4140dc43b0a16b596288539d56fe2836b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 668/781] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 515851c31e..07f0f08ade 100644 --- a/Makefile +++ b/Makefile @@ -1851,6 +1851,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1858,6 +1859,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From f2131a6dda7e76f1bb31ab7ec135e5f82826f16e Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 669/781] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3347362632..a75094b257 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 52522d24e4110cd2d7e62cb5c6266e59a2795e49 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 670/781] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index a75094b257..2082e3d2bd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From d4747054af8e5142583a7caa780a14f188a852ab Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 671/781] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 626b19ac93..2df16315d6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..76e0fa0525 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 0f4263c09a..52c35301ac 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 30716903f5..34baee3115 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,23 +172,50 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2082e3d2bd..e090faa69e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -276,6 +273,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 64e41bea22..535eed8c75 100644 --- a/config.c +++ b/config.c @@ -536,6 +536,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index b56c297b04..a4769334b1 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -490,4 +490,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From d6ffa16437c0d0305aaa98d300742897e09f9629 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 672/781] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 34baee3115..921ca7c61f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From fd198cb64c46f54d43e219abd759384881243aa2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 673/781] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 11c35afb9c..1056075545 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 2b30504bf120336d797b8593a7605c4de55e4774 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 674/781] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 125a0a151c6bebb64d0e56709ef137226bf5dff6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 675/781] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index f11f98c3ce..90541a39c6 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index c582964b0d..97f3e7f50e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -782,6 +782,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 1cce13c1fb70cd99b9e27f4e10ea9b0e954a91aa Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 676/781] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From a8a00c3393dff53128ebf83c063efaefcb6502d2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 677/781] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 921ca7c61f..095294ee80 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index e090faa69e..ff9611bf74 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From e17d791256e10ecd15f804da51774e92fa755fea Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 678/781] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 095294ee80..25479604fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1224,7 +1240,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From eeb39261e100701aa310a51ab0753075b42110c5 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 679/781] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 83338e1cba1eb0bb170441a7e2447a60337cd61f Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 680/781] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 5950d13b824b4900e52f5ceccf235e89ef20c63e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 681/781] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From b7bec05fcadab1dc831906e297d5c88c8c0bf193 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 682/781] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 661c66869951ac3512795e033c651526100ba769 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 683/781] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From bee55df28b9ed5621df9ab36f991afbde89b6988 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 684/781] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 7aeb2e85ea43ff040d9b11d3ee85412e3d44aeac Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 685/781] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 1095338b07cf721f68416b7f8abb81a126a32892 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 686/781] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 25479604fa..78ad8f76fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1281,6 +1334,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From cc0ee235d666431a65f61902381cf2a44d055307 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 687/781] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 78ad8f76fb..6ecad87476 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ff9611bf74..cdd119c473 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 0648946884bbdd0e21e70456fb3fa8fee59e2dd7 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 688/781] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 59a159417e07174bc4189849a8482e587624ba03 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 689/781] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1f36a3e815..50773a3d9d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2814,6 +2816,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From c468c93eec068e4230bdd6b0d8bff49941c102e8 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 690/781] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 56a4a1237f8892d1d36d4c45e4b14683dfd2a8c4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 691/781] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 50773a3d9d..2815f04328 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9399,7 +9399,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From 5756bfec1fae7337142200d4bf7bdcc107064f40 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 692/781] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2815f04328..793c4373b4 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9400,11 +9400,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From aa2a0ce5568199e3d212b25280ffb7e8cf9fdf37 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 693/781] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6ecad87476..4348b60296 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -343,8 +343,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -360,6 +363,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -371,12 +394,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(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]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -395,7 +418,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index cdd119c473..756f3ab062 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -227,10 +227,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From fa90864c14d9de28c201c08000ab71073bcaf640 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 694/781] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4348b60296..cc47d6834a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1566,6 +1566,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1575,9 +1576,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 3a5cb16bc85891f1a1c3c10ca00d378e5ed4ced6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 695/781] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 675773479a..5bacf2278c 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -310,4 +310,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 97f3e7f50e..e2379b8ad2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -777,6 +777,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 93c41c10cd006b89141c8d812efb7c15d86f7835 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 696/781] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index cc47d6834a..bbae2be946 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From 5bbaae2a6f79d828d18b4ddab55ad17ffff6bba8 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 697/781] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bbae2be946..7ec615c5ac 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -373,7 +373,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From bd21d65fd30ec1d47248e4b5ff82c101311cd31c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 698/781] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..4db4f42516 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,7 +444,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From 4dc7d3b9f940463810d66dcddd9ccee7dc8c2e99 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 699/781] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -154,6 +158,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -172,6 +180,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -219,6 +231,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a9df7ff7bd..e439b0f8ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -607,6 +607,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -623,6 +627,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -649,8 +657,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -665,6 +681,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -700,6 +720,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From 65b2c099be2ce7ac71f416c4d2e28752229e0bf4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 19:13:36 +0200 Subject: [PATCH 700/781] Fix rebase of grep-O grep no longer wants setup to be run already. Signed-off-by: Johannes Schindelin --- git.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git.c b/git.c index 6db05e0df8..19b45f29e1 100644 --- a/git.c +++ b/git.c @@ -320,7 +320,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, RUN_SETUP }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 0fff3fe82239a459f71a3af56994feafc35ed0e0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 16:47:51 +0200 Subject: [PATCH 701/781] Replace obsolete 'diff' call with 'test_cmp' Signed-off-by: Johannes Schindelin --- t/t7002-grep.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index e249c3ed41..8a6322765c 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -60,7 +60,7 @@ do echo ${HC}file:5:foo_mmap bar mmap baz } >expected && git grep -n -w -e mmap $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (w)" ' @@ -74,7 +74,7 @@ do echo ${HC}x:1:x x xx x } >expected && git grep -n -w -e "x xx* x" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-1)" ' @@ -82,7 +82,7 @@ do echo ${HC}y:1:y yy } >expected && git grep -n -w -e "^y" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-2)" ' @@ -93,7 +93,7 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' @@ -105,14 +105,14 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' test_expect_success "grep $L (t-1)" ' echo "${HC}t/t:1:test" >expected && git grep -n -e test $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-2)" ' @@ -121,7 +121,7 @@ do cd t && git grep -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-3)" ' @@ -130,7 +130,7 @@ do cd t && git grep --full-name -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -c $L (no /dev/null)" ' From 3bb030015f2f0f516fcb2c0deab34bcfaf3d39ba Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 702/781] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 56 +++++++++++++++++++++++++++++++++++++++- t/t5516-fetch-push.sh | 36 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 2df16315d6..dcf5e87fcc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1538,6 +1538,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0559fcc871..f35070358f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,6 +17,8 @@ enum deny_action { DENY_IGNORE, DENY_WARN, DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -78,7 +80,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2de98e6561..59caa61a52 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -710,4 +710,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 96cfcbb2278a36ab3aa09389a32466a8ca8993fd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 703/781] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..11c35afb9c 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 3998051fa34064f61e7387dfbaaa10563ab8dc77 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 704/781] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f0fe351df9..adcca6c97b 100644 --- a/Makefile +++ b/Makefile @@ -1853,6 +1853,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1860,6 +1861,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 11bcc68dc9565eb9a7b6b1e81eee9f649283fd12 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 705/781] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3347362632..a75094b257 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 7574d99881479f8d3659847d52703da7b2be9413 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 706/781] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index a75094b257..2082e3d2bd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 891b3d11b1dde30af7285705432ab49d38af48f1 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 707/781] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 626b19ac93..2df16315d6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..76e0fa0525 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 303c10771b..8ae215c6ef 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 30716903f5..34baee3115 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,23 +172,50 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2082e3d2bd..e090faa69e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -276,6 +273,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 9b6b1df212..67a82f055e 100644 --- a/config.c +++ b/config.c @@ -579,6 +579,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index b56c297b04..a4769334b1 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -490,4 +490,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From 38ab60d7e5c73d4c2cd1fcdd177ffa5043ccf3ea Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 708/781] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 34baee3115..921ca7c61f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From 41bc9dba9fc2e30b47384ebb1ce1f568ec5b4a0a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 709/781] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 11c35afb9c..1056075545 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 27156a29cc468692a15b4b6500e365ee839eb3f8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 710/781] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 67bb5597ea631d88b0e8eff4a0d3275a24f51d75 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 711/781] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index c582964b0d..97f3e7f50e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -782,6 +782,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 26c00eab4de541c9dba9bf883402ed1f00bd7e68 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 712/781] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From 87635ed04500887db49e4ce65f0b8df2c48c8210 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 713/781] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 921ca7c61f..095294ee80 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index e090faa69e..ff9611bf74 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 1de9be03d51ec386e38e3ef870dc16a18f67d7e5 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 714/781] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 095294ee80..25479604fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1224,7 +1240,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From fae5dc25a76afb61da854a1c3594166533c7576a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 715/781] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 2ec79df99047bc5cd66ca23b624aa23de1ee49c7 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 716/781] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From f0849bf8094b58193f5f0e835f158bcc8c24e328 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 717/781] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From 1c73b79894b2ae7e461ee0ae548d70e37e10e898 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 718/781] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From 4e3c3a570d3eb8ac29b50af376b245534d1e8120 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 719/781] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From ea928bad8604b14071aa509fdfe17facea791ac2 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 720/781] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 1de940e3997226c5e096644bd2fd92617255ac3e Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 721/781] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From 9da0cb5c86d833dcfda9a88e3c8cdaa58393ea92 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 722/781] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 25479604fa..78ad8f76fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1281,6 +1334,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 9b275e71be24ae9b0ed5c4b1a05cb94f2e9e350b Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 723/781] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 78ad8f76fb..6ecad87476 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ff9611bf74..cdd119c473 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 3876a4604add8888959320580d7e8435d3ee2860 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 724/781] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From 62cd93c1dfe0c43f5ff76ae4bf47b3e6ae1ce3dc Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 725/781] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1f36a3e815..50773a3d9d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2814,6 +2816,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From 493461349ded3479168ba99111615c9ec62716fc Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 726/781] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 3b4f6cbfce4be76dd7f3310e8b74933d178988e5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 727/781] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 50773a3d9d..2815f04328 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9399,7 +9399,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From faeb863a7f18ad4e7f671c68c637467169a497cc Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 728/781] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2815f04328..793c4373b4 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9400,11 +9400,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From 62f864990a57a8868e9ce51a6866eb30b685797b Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 729/781] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6ecad87476..4348b60296 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -343,8 +343,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -360,6 +363,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -371,12 +394,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(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]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -395,7 +418,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index cdd119c473..756f3ab062 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -227,10 +227,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From 85e55a6565259e249afcc31cbded86236d80d681 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 730/781] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4348b60296..cc47d6834a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1566,6 +1566,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1575,9 +1576,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From fd73c0b9bcb571fda706a47ac26636019b8f5161 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 731/781] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 675773479a..5bacf2278c 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -310,4 +310,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 97f3e7f50e..e2379b8ad2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -777,6 +777,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From acc5880a61d720e9b757561314eef510bf4af45a Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 732/781] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index cc47d6834a..bbae2be946 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From c8a1530575b76c6e444c683ef77b40fa005c6942 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 733/781] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bbae2be946..7ec615c5ac 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -373,7 +373,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 78d757687cab45251536d2daa3a8b5cae40e9508 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 734/781] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..4db4f42516 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,7 +444,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From c5fc0e52b417af5499621801c4880c060d763d6a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 735/781] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -154,6 +158,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -172,6 +180,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -219,6 +231,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a9df7ff7bd..e439b0f8ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -607,6 +607,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -623,6 +627,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -649,8 +657,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -665,6 +681,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -700,6 +720,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From f46fcc176a246cde86587b42752c4098ebb1c109 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 736/781] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index 8e928e2170..b2ac407ea8 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -590,7 +590,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1012,28 +1011,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From e1cf4f7b8bc8490a345bb0cf7c3e93025b414d72 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 737/781] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index b2ac407ea8..d85cb3f867 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include "thread-utils.h" @@ -556,6 +557,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -781,9 +807,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -867,6 +895,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -942,6 +972,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -1010,6 +1054,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1032,6 +1099,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 99f036302a..265fa09d8d 100644 --- a/git.c +++ b/git.c @@ -329,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 5bf7ce7bc9bc67f8257f9581824ea5e5f6d73b60 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 738/781] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index d85cb3f867..4b1c5fc879 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -807,7 +807,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -895,8 +895,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -973,16 +974,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From ac5636e11e99dc0406fe455b88da921d10a68dbf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 16:47:51 +0200 Subject: [PATCH 739/781] Replace obsolete 'diff' call with 'test_cmp' Signed-off-by: Johannes Schindelin --- t/t7002-grep.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index e249c3ed41..8a6322765c 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -60,7 +60,7 @@ do echo ${HC}file:5:foo_mmap bar mmap baz } >expected && git grep -n -w -e mmap $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (w)" ' @@ -74,7 +74,7 @@ do echo ${HC}x:1:x x xx x } >expected && git grep -n -w -e "x xx* x" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-1)" ' @@ -82,7 +82,7 @@ do echo ${HC}y:1:y yy } >expected && git grep -n -w -e "^y" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-2)" ' @@ -93,7 +93,7 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' @@ -105,14 +105,14 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' test_expect_success "grep $L (t-1)" ' echo "${HC}t/t:1:test" >expected && git grep -n -e test $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-2)" ' @@ -121,7 +121,7 @@ do cd t && git grep -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-3)" ' @@ -130,7 +130,7 @@ do cd t && git grep --full-name -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -c $L (no /dev/null)" ' From 8a0f36e7280394c71d7821c1c24b4ab1febe9d44 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 740/781] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 56 +++++++++++++++++++++++++++++++++++++++- t/t5516-fetch-push.sh | 36 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 2df16315d6..dcf5e87fcc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1538,6 +1538,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0559fcc871..f35070358f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,6 +17,8 @@ enum deny_action { DENY_IGNORE, DENY_WARN, DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -78,7 +80,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2de98e6561..59caa61a52 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -710,4 +710,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From 9c63503c926ca1135e6fa89041e3b47fab829d77 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 18:40:30 +0200 Subject: [PATCH 741/781] git am: accept patches downloaded from GMane GMane has this wonderful feature that you can download the raw mails, but the mails do not fully conform to the mbox format, as they do not start with a "From ..." line. But they start with another tell tale we can easily detect. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..11c35afb9c 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "*) + "From "* | "From: "* | "Path:news.gmane.org"*) patch_format=mbox ;; '# This series applies on GIT commit'*) From c99542f51b5a60e5bc33a28cbeb948237b90d8d6 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 22 Oct 2009 19:04:17 +0200 Subject: [PATCH 742/781] Avoid TAGS/tags warning from GNU Make Signed-off-by: Johannes Schindelin --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 87c90d6b80..1bb06bb8dc 100644 --- a/Makefile +++ b/Makefile @@ -1848,6 +1848,7 @@ info: pdf: $(MAKE) -C Documentation pdf +ifeq (,$(findstring MINGW,$(uname_S))) TAGS: $(RM) TAGS $(FIND) . -name '*.[hcS]' -print | xargs etags -a @@ -1855,6 +1856,7 @@ TAGS: tags: $(RM) tags $(FIND) . -name '*.[hcS]' -print | xargs ctags -a +endif cscope: $(RM) cscope* From 2ee859df0b8ef170d847af8651864d5248a4088d Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:04:21 +0100 Subject: [PATCH 743/781] MinGW: Use pid_t more consequently, introduce uid_t for greater compatibility Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/mingw.h b/compat/mingw.h index 3347362632..a75094b257 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -6,6 +6,7 @@ */ typedef int pid_t; +typedef int uid_t; #define hstrerror strerror #define S_IFLNK 0120000 /* Symbolic link */ @@ -75,17 +76,17 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } -static inline int fork(void) +static inline pid_t fork(void) { errno = ENOSYS; return -1; } static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return 0; } -static inline int getppid(void) +static inline pid_t getppid(void) { return 1; } static inline void sync(void) {} -static inline int getuid() +static inline uid_t getuid(void) { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } @@ -117,7 +118,7 @@ static inline int mingw_unlink(const char *pathname) } #define unlink mingw_unlink -static inline int waitpid(pid_t pid, int *status, unsigned options) +static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) return _cwait(status, pid, 0); @@ -158,7 +159,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); int getpagesize(void); /* defined in MinGW's libgcc.a */ -struct passwd *getpwuid(int uid); +struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); From 1cc3c02fdcc9a28dab23809503f2ec97486e7841 Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Mon, 28 Dec 2009 18:13:52 +0100 Subject: [PATCH 744/781] MinGW: Add missing file mode bit defines Signed-off-by: Sebastian Schuberth --- compat/mingw.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/compat/mingw.h b/compat/mingw.h index a75094b257..2082e3d2bd 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -12,12 +12,24 @@ typedef int uid_t; #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 + +#ifndef _STAT_H_ +#define S_IRUSR 0 +#define S_IWUSR 0 +#define S_IXUSR 0 +#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 -#define S_ISGID 0 +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) #define S_IROTH 0 +#define S_IWOTH 0 #define S_IXOTH 0 +#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 #define WIFEXITED(x) 1 #define WIFSIGNALED(x) 0 From 0a4d61c121f8a3e82ac9e8260f30c05b58aa78f4 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Wed, 16 Dec 2009 22:20:55 +0100 Subject: [PATCH 745/781] core.hidedotfiles: hide '.git' dir by default At least for cross-platform projects, it makes sense to hide the files starting with a dot, as this is the behavior on Unix/MacOSX. However, at least Eclipse has problems interpreting the hidden flag correctly, so the default is to hide only the .git/ directory. The config setting core.hideDotFiles therefore supports not only 'true' and 'false', but also 'dotGitOnly'. [jes: clarified the commit message, made git init respect the setting by marking the .git/ directory only after reading the config, and added documentation, and rebased on top of current junio/next] Signed-off-by: Erik Faye-Lund Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 6 ++++ builtin/init-db.c | 1 + cache.h | 7 +++++ compat/mingw.c | 66 ++++++++++++++++++++++++++++++++++++++-- compat/mingw.h | 8 ++--- config.c | 9 ++++++ environment.c | 1 + git-compat-util.h | 4 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 626b19ac93..2df16315d6 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -154,6 +154,12 @@ The default is true, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.fileMode false if appropriate when the repository is created. +core.hideDotFiles:: + (Windows-only) If true (which is the default), mark newly-created + directories and files whose name starts with a dot as hidden. + If 'dotGitOnly', only the .git/ directory is hidden, but no other + files starting with a dot. + core.ignoreCygwinFSTricks:: This option is only used by Cygwin implementation of Git. If false, the Cygwin stat() and lstat() functions are used. This may be useful diff --git a/builtin/init-db.c b/builtin/init-db.c index edc40ff574..76e0fa0525 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -312,6 +312,7 @@ int init_db(const char *template_dir, unsigned int flags) check_repository_format(); reinit = create_default_files(template_dir); + mark_as_git_dir(get_git_dir()); sha1_dir = get_object_directory(); len = strlen(sha1_dir); diff --git a/cache.h b/cache.h index 303c10771b..8ae215c6ef 100644 --- a/cache.h +++ b/cache.h @@ -553,6 +553,13 @@ extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +enum hide_dotfiles_type { + HIDE_DOTFILES_FALSE = 0, + HIDE_DOTFILES_TRUE, + HIDE_DOTFILES_DOTGITONLY, +}; +extern enum hide_dotfiles_type hide_dotfiles; + enum safe_crlf { SAFE_CRLF_FALSE = 0, SAFE_CRLF_FAIL = 1, diff --git a/compat/mingw.c b/compat/mingw.c index 30716903f5..34baee3115 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -2,6 +2,9 @@ #include "win32.h" #include #include "../strbuf.h" +#include "../cache.h" + +unsigned int _CRT_fmode = _O_BINARY; int err_win_to_posix(DWORD winerr) { @@ -116,6 +119,38 @@ int err_win_to_posix(DWORD winerr) return error; } +static int make_hidden(const char *path) +{ + DWORD attribs = GetFileAttributes(path); + if (SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN | attribs)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + +void mingw_mark_as_git_dir(const char *dir) +{ + if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + warning("Failed to make '%s' hidden", dir); +} + +#undef mkdir +int mingw_mkdir(const char *path, int mode) +{ + int ret = mkdir(path); + if (!ret && hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a directory is created. + */ + const char *start = basename((char*)path); + if (*start == '.') + return make_hidden(path); + } + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { @@ -137,23 +172,50 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && fd >= 0 && + hide_dotfiles == HIDE_DOTFILES_TRUE) { + /* + * In Windows a file or dir starting with a dot is not + * automatically hidden. So lets mark it as hidden when + * such a file is created. + */ + const char *start = basename((char*)filename); + if (*start == '.' && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + } return fd; } #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (!strcmp(filename, "/dev/null")) filename = "nul"; - return fopen(filename, otype); + file = fopen(filename, otype); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } #undef freopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = 0; + FILE *file; + if (hide_dotfiles == HIDE_DOTFILES_TRUE && + basename((char*)filename)[0] == '.') + hide = access(filename, F_OK); if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; - return freopen(filename, otype, stream); + file = freopen(filename, otype, stream); + if (file && hide && make_hidden(filename)) + warning("Could not mark '%s' as hidden.", filename); + return file; } /* diff --git a/compat/mingw.h b/compat/mingw.h index 2082e3d2bd..e090faa69e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -116,10 +116,7 @@ static inline int fcntl(int fd, int cmd, ...) * simple adaptors */ -static inline int mingw_mkdir(const char *path, int mode) -{ - return mkdir(path); -} +int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir static inline int mingw_unlink(const char *pathname) @@ -276,6 +273,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format void mingw_open_html(const char *path); #define open_html mingw_open_html +void mingw_mark_as_git_dir(const char *dir); +#define mark_as_git_dir mingw_mark_as_git_dir + /* * helpers */ diff --git a/config.c b/config.c index 9b6b1df212..67a82f055e 100644 --- a/config.c +++ b/config.c @@ -579,6 +579,15 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.hidedotfiles")) { + if (value && !strcasecmp(value, "dotgitonly")) { + hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; + return 0; + } + hide_dotfiles = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } diff --git a/environment.c b/environment.c index 876c5e5341..62172cc51e 100644 --- a/environment.c +++ b/environment.c @@ -52,6 +52,7 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE; char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; +enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; /* Parallel index stat data preload? */ int core_preload_index = 0; diff --git a/git-compat-util.h b/git-compat-util.h index 4ee8f86f7a..7b2902f9cb 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -492,4 +492,8 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +#ifndef mark_as_git_dir +#define mark_as_git_dir(x) /* noop */ +#endif + #endif From aa86b307a60e2a3f7677d99f00700159b742e7f7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 9 Jan 2010 19:33:25 +0100 Subject: [PATCH 746/781] When initializing .git/, record the current setting of core.hideDotFiles This is on Windows only, of course. Signed-off-by: Johannes Schindelin --- compat/mingw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 34baee3115..921ca7c61f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,6 +132,10 @@ void mingw_mark_as_git_dir(const char *dir) { if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) warning("Failed to make '%s' hidden", dir); + git_config_set("core.hideDotFiles", + hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : + (hide_dotfiles == HIDE_DOTFILES_DOTGITONLY ? + "dotGitOnly" : "true")); } #undef mkdir From a4b68625479e5697d4e3f85bf23441ed7f00c152 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 11 Jan 2010 18:16:25 +0100 Subject: [PATCH 747/781] Revert "git am: accept patches downloaded from GMane" This reverts commit 127aa63757870526b106c045310a3b6c4cee0324. As pointed out by Junio, this patch was obsoleted by 0fcb2ca. --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 11c35afb9c..1056075545 100755 --- a/git-am.sh +++ b/git-am.sh @@ -176,7 +176,7 @@ check_patch_format () { read l2 read l3 case "$l1" in - "From "* | "From: "* | "Path:news.gmane.org"*) + "From "* | "From: "*) patch_format=mbox ;; '# This series applies on GIT commit'*) From 98bd4ad4970eceb29a36af3fa75741aaaccaa1eb Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Wed, 16 Sep 2009 16:06:53 +0200 Subject: [PATCH 748/781] criss cross rename failure workaround Signed-off-by: Johannes Schindelin --- t/t4130-apply-criss-cross-rename.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t4130-apply-criss-cross-rename.sh b/t/t4130-apply-criss-cross-rename.sh index 7cfa2d6287..37f5c1a84c 100755 --- a/t/t4130-apply-criss-cross-rename.sh +++ b/t/t4130-apply-criss-cross-rename.sh @@ -14,8 +14,8 @@ create_file() { test_expect_success 'setup' ' create_file file1 "File1 contents" && - create_file file2 "File2 contents" && - create_file file3 "File3 contents" && + create_file file2 "File2 more contents" && + create_file file3 "File3 even more contents" && git add file1 file2 file3 && git commit -m 1 ' From 92d03c49d0f75fa04c218a40f3e23afff42a6b6a Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 15 Feb 2010 23:14:28 +0000 Subject: [PATCH 749/781] Skip t1300.70 and 71 on msysGit. These two tests fail on msysGit because /dev/null is an alias for nul on Windows and when reading the value back from git config the alias does not match the real filename. Also the HOME environment variable has a unix-style path but git returns a native equivalent path for '~'. As these are platform-dependent equivalent results it seems simplest to skip the test entirely. Signed-off-by: Pat Thoyts users.sourceforge.net> --- t/t1300-repo-config.sh | 6 +++--- t/test-lib.sh | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 64f05080b6..ae6bf7c219 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -701,7 +701,7 @@ cat >expect <<\EOF trailingtilde = foo~ EOF -test_expect_success 'set --path' ' +test_expect_success NONMINGW 'set --path' ' git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@ -713,14 +713,14 @@ $HOME/ foo~ EOF -test_expect_success 'get --path' ' +test_expect_success NONMINGW 'get --path' ' git config --get --path path.home > result && git config --get --path path.normal >> result && git config --get --path path.trailingtilde >> result && test_cmp expect result ' -rm .git/config +test_have_prereq NONMINGW && rm .git/config git config quote.leading " test" git config quote.ending "test " diff --git a/t/test-lib.sh b/t/test-lib.sh index c582964b0d..97f3e7f50e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -782,6 +782,7 @@ case $(uname -s) in test_set_prereq POSIXPERM test_set_prereq BSLASHPSPEC test_set_prereq EXECKEEPSPID + test_set_prereq NONMINGW ;; esac From 6192be5ce619dfaa70875ade9f13c262de0d9264 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 18 Feb 2010 18:27:27 +0100 Subject: [PATCH 750/781] Revert "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" This reverts commit a9fa11fe5bd5978bb175b3b5663f6477a345d428. --- git-gui/git-gui.sh | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 7d5451198c..05193a040a 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1192,9 +1192,6 @@ if {[lindex $_reponame end] eq {.git}} { set _reponame [lindex $_reponame end] } -set env(GIT_DIR) $_gitdir -set env(GIT_WORK_TREE) $_gitworktree - ###################################################################### ## ## global init @@ -1994,7 +1991,7 @@ set starting_gitk_msg [mc "Starting gitk... please wait..."] proc do_gitk {revs {is_submodule false}} { global current_diff_path file_states current_diff_side ui_index - global _gitdir _gitworktree + global _gitworktree # -- Always start gitk through whatever we were loaded with. This # lets us bypass using shell process on Windows systems. @@ -2006,12 +2003,19 @@ proc do_gitk {revs {is_submodule false}} { } else { global env + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + set pwd [pwd] if {!$is_submodule} { if {![is_bare]} { cd $_gitworktree } + set env(GIT_DIR) [file normalize [gitdir]] } else { cd $current_diff_path if {$revs eq {--}} { @@ -2032,18 +2036,15 @@ proc do_gitk {revs {is_submodule false}} { } set revs $old_sha1...$new_sha1 } - # GIT_DIR and GIT_WORK_TREE for the submodule are not the ones - # we've been using for the main repository, so unset them. - # TODO we could make life easier (start up faster?) for gitk - # by setting these to the appropriate values to allow gitk - # to skip the heuristics to find their proper value - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + unset env(GIT_DIR) + } } eval exec $cmd $revs "--" "--" & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg @@ -2064,20 +2065,22 @@ proc do_git_gui {} { error_popup [mc "Couldn't find git gui in PATH"] } else { global env - global _gitdir _gitworktree - # see note in do_gitk about unsetting these vars when - # running tools in a submodule - unset env(GIT_DIR) - unset env(GIT_WORK_TREE) + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + unset env(GIT_DIR) + } else { + set old_GIT_DIR {} + } set pwd [pwd] cd $current_diff_path eval exec $exe gui & - set env(GIT_DIR) $_gitdir - set env(GIT_WORK_TREE) $_gitworktree + if {$old_GIT_DIR ne {}} { + set env(GIT_DIR) $old_GIT_DIR + } cd $pwd ui_status $::starting_gitk_msg From a92d8e3484111d2a039d63f97d4df048c7e40c52 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:17:36 +0100 Subject: [PATCH 751/781] mingw: move unlink wrapper to mingw.c The next patch implements a workaround in case unlink fails on Windows. Signed-off-by: Heiko Voigt --- compat/mingw.c | 8 ++++++++ compat/mingw.h | 11 +++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 921ca7c61f..095294ee80 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -155,6 +155,14 @@ int mingw_mkdir(const char *path, int mode) return ret; } +#undef unlink +int mingw_unlink(const char *pathname) +{ + /* read-only files cannot be removed */ + chmod(pathname, 0666); + return unlink(pathname); +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index e090faa69e..ff9611bf74 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -119,14 +119,6 @@ static inline int fcntl(int fd, int cmd, ...) int mingw_mkdir(const char *path, int mode); #define mkdir mingw_mkdir -static inline int mingw_unlink(const char *pathname) -{ - /* read-only files cannot be removed */ - chmod(pathname, 0666); - return unlink(pathname); -} -#define unlink mingw_unlink - static inline pid_t waitpid(pid_t pid, int *status, unsigned options) { if (options == 0) @@ -177,6 +169,9 @@ int link(const char *oldpath, const char *newpath); * replacements of existing functions */ +int mingw_unlink(const char *pathname); +#define unlink mingw_unlink + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 88d1dbe6969ca038cd4551aa390985bfdf1b00ef Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Tue, 26 Jan 2010 21:48:45 +0100 Subject: [PATCH 752/781] mingw: work around irregular failures of unlink on windows If a file is opened by another process (e.g. indexing of an IDE) for reading it is not allowed to be deleted. So in case unlink fails retry after waiting for some time. This extends the workaround from 6ac6f878. Signed-off-by: Heiko Voigt --- compat/mingw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 095294ee80..25479604fa 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../cache.h" unsigned int _CRT_fmode = _O_BINARY; +static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) { @@ -158,9 +159,24 @@ int mingw_mkdir(const char *path, int mode) #undef unlink int mingw_unlink(const char *pathname) { + int ret, tries = 0; + /* read-only files cannot be removed */ chmod(pathname, 0666); - return unlink(pathname); + while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + return ret; } #undef open @@ -1224,7 +1240,6 @@ int mingw_rename(const char *pold, const char *pnew) { DWORD attrs, gle; int tries = 0; - static const int delay[] = { 0, 1, 10, 20, 40 }; /* * Try native rename() first to get errno right. From 4fd6984e82ebcbb4ef4a4913004ee7effe25cc91 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Feb 2010 02:11:21 +0000 Subject: [PATCH 753/781] Handle failure of core.worktree to identify the working directory. Commit 21985a11 'git-gui: handle non-standard worktree locations' attempts to use either GIT_WORK_TREE or core.worktree to set the _gitworktree variable but these may not be set which leads to a failure to launch gitk to review history. Use _gitdir to set the location for a standard git layout where the parent of the .git directory is the working tree. Signed-off-by: Pat Thoyts --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 05193a040a..b27c07b06e 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1155,6 +1155,9 @@ apply_config # try to set work tree from environment, falling back to core.worktree if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} { set _gitworktree [get_config core.worktree] + if {$_gitworktree eq ""} { + set _gitworktree [file dirname [file normalize $_gitdir]] + } } if {$_prefix ne {}} { if {$_gitworktree eq {}} { From 14bd66933609f312211fe89c6252fdc078e794ff Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 20 Feb 2010 14:38:38 +0100 Subject: [PATCH 754/781] git-gui: fix usage of themed widgets variable There was one forgotten global so NS was not visible to the method which resulted in an error. Signed-off-by: Heiko Voigt --- git-gui/lib/status_bar.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 5fe3aad382..95cb44991f 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -39,6 +39,7 @@ method _oneline_pack {} { } constructor two_line {path} { + global NS set w $path set w_l $w.l set w_c $w.c From 19c1cd04e4985e877760fc603432d072427efec9 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 7 Feb 2010 22:47:56 +0100 Subject: [PATCH 755/781] git-gui: check whether systems nice command works or disable it This fixes issue 394 from msysgit. It seems that the Gnuwin32 project provides a nice command but it returns a "not implemented" error. To help users we now try to execute once and disable it in case it fails. Signed-off-by: Heiko Voigt Signed-off-by: Shawn O. Pearce --- git-gui/git-gui.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index b27c07b06e..cd8da37f0f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -416,6 +416,9 @@ proc _lappend_nice {cmd_var} { if {![info exists _nice]} { set _nice [_which nice] + if {[catch {exec $_nice git version}]} { + set _nice {} + } } if {$_nice ne {}} { lappend cmd $_nice From a11a60a4f2d36a8b6cdefa614c2ac7f7c000dc06 Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Thu, 25 Feb 2010 01:14:22 +0100 Subject: [PATCH 756/781] git-gui: fix "Explore Working Copy" for Windows again It has already been fixed in commit 454efb47 (git-gui (Win): make "Explore Working Copy" more robust, 2009-04-01), but has been broken in commit 21985a11 (git-gui: handle non-standard worktree locations, 2010-01-23) by accidentally replacing too much with a new variable. The problem can be reproduced when starting git-gui from within a subdirectory. The solution is to convert the path name, explorer.exe is invoked with, to a platform native name. Signed-off-by: Markus Heidelberg --- git-gui/git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index cd8da37f0f..0e5cc89e6d 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -2107,7 +2107,7 @@ proc do_explore {} { # freedesktop.org-conforming system is our best shot set explorer "xdg-open" } - eval exec $explorer $_gitworktree & + eval exec $explorer [list [file nativename $_gitworktree]] & } set is_quitting 0 From a195394b832a2ea1f5ff142da3646f30cc3692df Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:45:51 +0100 Subject: [PATCH 757/781] git-gui: fix usage of _gitworktree when creating shortcut for windows This fixes msysGit issue 425. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/shortcut.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/shortcut.tcl b/git-gui/lib/shortcut.tcl index 79c1888e11..78878ef89d 100644 --- a/git-gui/lib/shortcut.tcl +++ b/git-gui/lib/shortcut.tcl @@ -16,7 +16,7 @@ proc do_windows_shortcut {} { [info nameofexecutable] \ [file normalize $::argv0] \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } @@ -57,7 +57,7 @@ proc do_cygwin_shortcut {} { $sh -c \ "CHERE_INVOKING=1 source /etc/profile;[sq $me] &" \ ] \ - [file normalize [$_gitworktree]] + [file normalize $_gitworktree] } err]} { error_popup [strcat [mc "Cannot write shortcut:"] "\n\n$err"] } From 435584e2a4fbfc7da74349049f92a1d2e78f97ef Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:47:42 +0100 Subject: [PATCH 758/781] git-gui: fix PATH environment for mingw development environment When creating a desktop shortcut from the gui the shortcut directly starts wish with the git-gui script. In the msysgit development environment some dll's reside in the mingw/bin directory which causes that git can not start because libiconv2.dll is not found. When using such a link the error is even more cryptic stating: "child killed: unknown signal" Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/windows/git-gui.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-gui/windows/git-gui.sh b/git-gui/windows/git-gui.sh index 66bbb2f8fa..b1845c5055 100644 --- a/git-gui/windows/git-gui.sh +++ b/git-gui/windows/git-gui.sh @@ -13,10 +13,11 @@ if { $argc >=2 && [lindex $argv 0] == "--working-dir" } { incr argc -2 } -set bindir [file dirname \ +set basedir [file dirname \ [file dirname \ [file dirname [info script]]]] -set bindir [file join $bindir bin] +set bindir [file join $basedir bin] +set bindir "$bindir;[file join $basedir mingw bin]" regsub -all ";" $bindir "\\;" bindir set env(PATH) "$bindir;$env(PATH)" unset bindir From 1a3910eb8c2aeb619580cf44b24733caac624871 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sat, 27 Feb 2010 21:48:48 +0100 Subject: [PATCH 759/781] git-gui: fix shortcut creation on cygwin When the user tried to create a desktop icon with git gui on cygwin wscript was complaining about an unknown option and displaying the non-native path as such. Signed-off-by: Heiko Voigt Signed-off-by: Johannes Schindelin --- git-gui/lib/win32.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-gui/lib/win32.tcl b/git-gui/lib/win32.tcl index d7f93d045d..db91ab84a5 100644 --- a/git-gui/lib/win32.tcl +++ b/git-gui/lib/win32.tcl @@ -18,9 +18,9 @@ proc win32_create_lnk {lnk_path lnk_exec lnk_dir} { eval [list exec wscript.exe \ /E:jscript \ /nologo \ - [file join $oguilib win32_shortcut.js] \ + [file nativename [file join $oguilib win32_shortcut.js]] \ $lnk_path \ - [file join $oguilib git-gui.ico] \ + [file nativename [file join $oguilib git-gui.ico]] \ $lnk_dir \ $lnk_exec] $lnk_args } From a2b220086ba1f27b42394fdf6e72c5105d568d74 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:19:42 +0100 Subject: [PATCH 760/781] mingw: make failures to unlink or move raise a question On Windows in case a program is accessing a file unlink or move operations may fail. To give the user a chance to correct this we simply wait until the user asks us to retry or fail. This is useful because of the following use case which seem to happen rarely but when it does it is a mess: After making some changes the user realizes that he was on the incorrect branch. When trying to change the branch some file is still in use by some other process and git stops in the middle of changing branches. Now the user has lots of files with changes mixed with his own. This is especially confusing on repositories that contain lots of files. Although the recent implementation of automatic retry makes this scenario much more unlikely lets provide a fallback as a last resort. Signed-off-by: Heiko Voigt --- compat/mingw.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 25479604fa..78ad8f76fb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,6 +3,7 @@ #include #include "../strbuf.h" #include "../cache.h" +#include "../run-command.h" unsigned int _CRT_fmode = _O_BINARY; static const int delay[] = { 0, 1, 10, 20, 40 }; @@ -156,6 +157,54 @@ int mingw_mkdir(const char *path, int mode) return ret; } +static int ask_user_yes_no(const char *format, ...) +{ + char answer[5]; + char question[4096]; + const char *retry_hook[] = { NULL, NULL, NULL }; + va_list args; + + if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) { + + va_start(args, format); + vsnprintf(question, sizeof(question), format, args); + va_end(args); + + retry_hook[1] = question; + return !run_command_v_opt(retry_hook, 0); + } + + if (!isatty(_fileno(stdin))) + return 0; + + while (1) { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, " (y/n)? "); + + if (fgets(answer, sizeof(answer), stdin)) { + /* remove the newline */ + if (answer[strlen(answer)-2] == '\r') + answer[strlen(answer)-2] = '\0'; + if (answer[strlen(answer)-1] == '\n') + answer[strlen(answer)-1] = '\0'; + } else + return 0; + + if (answer[0] == 'y' && strlen(answer) == 1) + return 1; + if (!strncasecmp(answer, "yes", sizeof(answer))) + return 1; + if (answer[0] == 'n' && strlen(answer) == 1) + return 0; + if (!strncasecmp(answer, "no", sizeof(answer))) + return 0; + fprintf(stderr, "I did not understand your answer: '%s'\n", + answer); + } +} + #undef unlink int mingw_unlink(const char *pathname) { @@ -176,6 +225,10 @@ int mingw_unlink(const char *pathname) Sleep(delay[tries]); tries++; } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Unlink of file '%s' failed. " + "Should I try again?", pathname)) + ret = unlink(pathname); return ret; } @@ -1281,6 +1334,11 @@ repeat: tries++; goto repeat; } + if (gle == ERROR_ACCESS_DENIED && + ask_user_yes_no("Rename from '%s' to '%s' failed. " + "Should I try again?", pold, pnew)) + goto repeat; + errno = EACCES; return -1; } From 2defae3462cfec17e2d5e51acdb1aa643acb4318 Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Thu, 25 Feb 2010 14:58:36 +0100 Subject: [PATCH 761/781] mingw: add fallback for rmdir in case directory is in use The same logic as for unlink and rename also applies to rmdir. For example in case you have a shell open in a git controlled folder. This will easily fail. So lets be nice for such cases as well. Signed-off-by: Heiko Voigt --- compat/mingw.c | 25 +++++++++++++++++++++++++ compat/mingw.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 78ad8f76fb..6ecad87476 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -232,6 +232,31 @@ int mingw_unlink(const char *pathname) return ret; } +#undef rmdir +int mingw_rmdir(const char *pathname) +{ + int ret, tries = 0; + + while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { + if (errno != EACCES) + break; + /* + * We assume that some other process had the source or + * destination file open at the wrong moment and retry. + * In order to give the other process a higher chance to + * complete its operation, we give up our time slice now. + * If we have to retry again, we do sleep a bit. + */ + Sleep(delay[tries]); + tries++; + } + while (ret == -1 && errno == EACCES && + ask_user_yes_no("Deletion of directory '%s' failed. " + "Should I try again?", pathname)) + ret = rmdir(pathname); + return ret; +} + #undef open int mingw_open (const char *filename, int oflags, ...) { diff --git a/compat/mingw.h b/compat/mingw.h index ff9611bf74..cdd119c473 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -172,6 +172,9 @@ int link(const char *oldpath, const char *newpath); int mingw_unlink(const char *pathname); #define unlink mingw_unlink +int mingw_rmdir(const char *path); +#define rmdir mingw_rmdir + int mingw_open (const char *filename, int oflags, ...); #define open mingw_open From 8fa3c5f743c6946ffd4902f133cebbd86271738d Mon Sep 17 00:00:00 2001 From: Heiko Voigt Date: Sun, 21 Feb 2010 21:05:04 +0100 Subject: [PATCH 762/781] git-gui: provide question helper for retry fallback on Windows Make use of the new environment variable GIT_ASK_YESNO to support the recently implemented fallback in case unlink, rename or rmdir fail for files in use on Windows. The added dialog will present a yes/no question to the the user which will currently be used by the windows compat layer to let the user retry a failed file operation. Signed-off-by: Heiko Voigt --- git-gui/Makefile | 2 ++ git-gui/git-gui--askyesno | 51 +++++++++++++++++++++++++++++++++++++++ git-gui/git-gui.sh | 3 +++ 3 files changed, 56 insertions(+) create mode 100755 git-gui/git-gui--askyesno diff --git a/git-gui/Makefile b/git-gui/Makefile index 197b55edf3..7d8b54101d 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -289,6 +289,7 @@ install: all $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1) $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(INSTALL_X0)git-gui--askpass $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(INSTALL_X0)git-gui--askyesno $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(INSTALL_R0)git-gui.tcl $(INSTALL_R1) '$(DESTDIR_SQ)$(gitexecdir_SQ)' @@ -307,6 +308,7 @@ uninstall: $(QUIET)$(CLEAN_DST) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui $(REMOVE_F1) $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askpass $(REMOVE_F1) + $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui--askyesno $(REMOVE_F1) $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/$p $(REMOVE_F1) &&) true ifdef GITGUI_WINDOWS_WRAPPER $(QUIET)$(REMOVE_F0)'$(DESTDIR_SQ)$(gitexecdir_SQ)'/git-gui.tcl $(REMOVE_F1) diff --git a/git-gui/git-gui--askyesno b/git-gui/git-gui--askyesno new file mode 100755 index 0000000000..2a6e6fd111 --- /dev/null +++ b/git-gui/git-gui--askyesno @@ -0,0 +1,51 @@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ +exec wish "$0" -- "$@" + +# This is an implementation of a simple yes no dialog +# which is injected into the git commandline by git gui +# in case a yesno question needs to be answered. + +set NS {} +set use_ttk [package vsatisfies [package provide Tk] 8.5] +if {$use_ttk} { + set NS ttk +} + +if {$argc < 1} { + puts stderr "Usage: $argv0 " + exit 1 +} else { + set prompt [join $argv " "] +} + +${NS}::frame .t +${NS}::label .t.m -text $prompt -justify center -width 40 +.t.m configure -wraplength 400 +pack .t.m -side top -fill x -padx 20 -pady 20 -expand 1 +pack .t -side top -fill x -ipadx 20 -ipady 20 -expand 1 + +${NS}::frame .b +${NS}::frame .b.left -width 200 +${NS}::button .b.yes -text Yes -command yes +${NS}::button .b.no -text No -command no + + +pack .b.left -side left -expand 1 -fill x +pack .b.yes -side left -expand 1 +pack .b.no -side right -expand 1 -ipadx 5 +pack .b -side bottom -fill x -ipadx 20 -ipady 15 + +bind . {exit 0} +bind . {exit 1} + +proc no {} { + exit 1 +} + +proc yes {} { + exit 0 +} + +wm title . "Question?" +tk::PlaceWindow . diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0e5cc89e6d..395cb2e35f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -1115,6 +1115,9 @@ set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] if {![info exists env(SSH_ASKPASS)]} { set env(SSH_ASKPASS) [gitexec git-gui--askpass] } +if {![info exists env(GIT_ASK_YESNO)]} { + set env(GIT_ASK_YESNO) [gitexec git-gui--askyesno] +} ###################################################################### ## From e7eaa7114a99a914152114dd1adf870c6ca59a5d Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Tue, 2 Feb 2010 23:03:24 +0100 Subject: [PATCH 763/781] gitk: Add shortcut Ctrl-W for closing the active window To make the user experience between git gui and gitk more homogeneous, use Ctrl-W in gitk too for closing the active window. When closing the main window doquit is called for proper cleanup. Signed-off-by: Jens Lehmann --- gitk-git/gitk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitk-git/gitk b/gitk-git/gitk index 1f36a3e815..50773a3d9d 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -2383,6 +2383,8 @@ proc makewindow {} { } bindall <$::BM> "canvscan mark %W %x %y" bindall "canvscan dragto %W %x %y" + bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} + bind . <$M1B-Key-w> doquit bindkey selfirstline bindkey sellastline bind . "selnextline -1" @@ -2814,6 +2816,7 @@ proc keys {} { [mc "Gitk key bindings:"] [mc "<%s-Q> Quit" $M1T] +[mc "<%s-W> Close window" $M1T] [mc " Move to first commit"] [mc " Move to last commit"] [mc ", p, i Move up one commit"] From 6f75a58a47a75d4ef5029128e031547c71e202bc Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Mon, 8 Mar 2010 12:43:27 +0000 Subject: [PATCH 764/781] git-gui: Avoid using the <> binding as a menu accelerator on win32 On Windows the Control-C binding is used to copy and is mapped to the Tk virtual event <>. In the initial git-gui dialog this is also bound as an accelerator for the Clone menu item. The effect is that both bindings run, copying the text but resetting the clone page or switching to the clone page when the user tries to copy text from one of the entry fields. This patch avoids this by using Control-L instead for Windows only. Signed-off-by: Pat Thoyts --- git-gui/lib/choose_repository.tcl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/git-gui/lib/choose_repository.tcl b/git-gui/lib/choose_repository.tcl index 64f06748b6..fae119286d 100644 --- a/git-gui/lib/choose_repository.tcl +++ b/git-gui/lib/choose_repository.tcl @@ -100,12 +100,17 @@ constructor pick {} { $opts insert end [mc "Clone Existing Repository"] link_clone $opts insert end "\n" if {$m_repo ne {}} { + if {[tk windowingsystem] eq "win32"} { + set key L + } else { + set key C + } $m_repo add command \ -command [cb _next clone] \ - -accelerator $M1T-C \ + -accelerator $M1T-$key \ -label [mc "Clone..."] - bind $top <$M1B-c> [cb _next clone] - bind $top <$M1B-C> [cb _next clone] + bind $top <$M1B-[string tolower $key]> [cb _next clone] + bind $top <$M1B-[string toupper $key]> [cb _next clone] } $opts tag conf link_open -foreground blue -underline 1 From 38cda0b0decd135fea7fcfc7fce75ab62e819c09 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 11 Aug 2009 02:22:33 +0200 Subject: [PATCH 765/781] gitk: work around ridiculous command line restriction on Windows On Windows, there are dramatic problems when a command line grows beyond PATH_MAX, which is restricted to 8191 characters on XP and later (according to http://support.microsoft.com/kb/830473). Work around this by just cutting off the command line at that length (actually, at a space boundary) in the hope that only negative refs are chucked: gitk will then do unnecessary work, but that is still better than flashing the gitk window and exiting with exit status 5 (which no Windows user is able to make sense of). This fixes msysGit issue 387. Signed-off-by: Johannes Schindelin --- gitk-git/gitk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 50773a3d9d..2815f04328 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9399,7 +9399,14 @@ proc getallcommits {} { } } if {$ids ne {}} { - set fd [open [concat $cmd $ids] r] + set cmd [concat $cmd $ids] + # XP and later accept up to 8191 characters in the command line + # see http://support.microsoft.com/kb/830473 + if {[tk windowingsystem] == "win32" && + [string length $cmd] > 8191} { + set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + } + set fd [open $cmd r] fconfigure $fd -blocking 0 incr allcommits nowbusy allcommits From c57b92c1a1733e42d8497156db5596620c3ea7ca Mon Sep 17 00:00:00 2001 From: Sebastian Schuberth Date: Wed, 10 Mar 2010 11:56:19 +0100 Subject: [PATCH 766/781] gitk: Second try to work around the command line limit on Windows The first fix caused Tcl to fail to compile the regexp, see msysGit issue 427. Here is another fix without using regexp, and using a more relaxed command line length limit to fix the original issue 387. Signed-off-by: Sebastian Schuberth Signed-off-by: Pat Thoyts --- gitk-git/gitk | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gitk-git/gitk b/gitk-git/gitk index 2815f04328..793c4373b4 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -9400,11 +9400,16 @@ proc getallcommits {} { } if {$ids ne {}} { set cmd [concat $cmd $ids] - # XP and later accept up to 8191 characters in the command line - # see http://support.microsoft.com/kb/830473 + # The maximum command line length for the CreateProcess function is 32767 characters, see + # http://blogs.msdn.com/oldnewthing/archive/2003/12/10/56028.aspx + # Be a little conservative in case Tcl adds some more stuff to the command line we do not + # know about and truncate the command line at a SHA1-boundary below 32000 characters. if {[tk windowingsystem] == "win32" && - [string length $cmd] > 8191} { - set cmd [regsub "^(.{1,8191}) .*\$" $cmd "\\1"] + [string length $cmd] > 32000} { + set ndx [string last " " $cmd 32000] + if {$ndx != -1} { + set cmd [string range $cmd 0 $ndx] + } } set fd [open $cmd r] fconfigure $fd -blocking 0 From 3a8fc9256d6fe6ed824c39e3b475b87dac9dc0fe Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 17 Mar 2010 15:17:34 +0000 Subject: [PATCH 767/781] fix mingw stat() and lstat() implementations for handling symlinks In msysGit the stat() function has been implemented using mingw_lstat which sets the st_mode member to S_IFLNK when a symbolic links is found. This causes the is_executable function to return when git attempts to build a list of available commands in the help code and we end up missing most git commands. (msysGit issue #445) This patch modifies the implementation so that lstat() will return the link flag but if we are called as stat() we read the size of the target and set the mode to that of a regular file. Signed-off-by: Pat Thoyts --- compat/mingw.c | 40 ++++++++++++++++++++++++++++++++++++---- compat/mingw.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 6ecad87476..4348b60296 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -343,8 +343,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. + * + * If follow is true then act like stat() and report on the link + * target. Otherwise report on the link itself. */ -static int do_lstat(const char *file_name, struct stat *buf) +static int do_lstat(int follow, const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -360,6 +363,26 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + WIN32_FIND_DATAA findbuf; + HANDLE handle = FindFirstFileA(file_name, &findbuf); + if (handle != INVALID_HANDLE_VALUE) { + if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && + (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { + if (follow) { + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + buf->st_mode = S_IFREG; + } else { + buf->st_mode = S_IFLNK; + } + buf->st_mode |= S_IREAD; + if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= S_IWRITE; + } + FindClose(handle); + } + } return 0; } return -1; @@ -371,12 +394,12 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(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]; - if (!do_lstat(file_name, buf)) + if (!do_lstat(follow, file_name, buf)) return 0; /* if file_name ended in a '/', Windows returned ENOENT; @@ -395,7 +418,16 @@ int mingw_lstat(const char *file_name, struct stat *buf) memcpy(alt_name, file_name, namelen); alt_name[namelen] = 0; - return do_lstat(alt_name, buf); + return do_lstat(follow, alt_name, buf); +} + +int mingw_lstat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(0, file_name, buf); +} +int mingw_stat(const char *file_name, struct stat *buf) +{ + return do_stat_internal(1, file_name, buf); } #undef fstat diff --git a/compat/mingw.h b/compat/mingw.h index cdd119c473..756f3ab062 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -227,10 +227,11 @@ int mingw_getpagesize(void); #ifndef ALREADY_DECLARED_STAT_FUNCS #define stat _stati64 int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_stat(const char *file_name, struct stat *buf); int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define _stati64(x,y) mingw_lstat(x,y) +#define _stati64(x,y) mingw_stat(x,y) #endif int mingw_utime(const char *file_name, const struct utimbuf *times); From f67e4f300f3b15e0b9f6f2e75c31804bf189b062 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 21:45:19 +0000 Subject: [PATCH 768/781] Report errors when failing to launch the html browser in mingw. The mingw function to launch the system html browser is silent if the target file does not exist leaving the user confused. Make it display something. Signed-off-by: Pat Thoyts Reviewed-by: Erik Faye-Lund --- compat/mingw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4348b60296..cc47d6834a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1566,6 +1566,7 @@ void mingw_open_html(const char *unixpath) const char *, const char *, const char *, INT); T ShellExecute; HMODULE shell32; + int r; shell32 = LoadLibrary("shell32.dll"); if (!shell32) @@ -1575,9 +1576,12 @@ void mingw_open_html(const char *unixpath) die("cannot run browser"); printf("Launching default browser to display HTML ...\n"); - ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); - + r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); FreeLibrary(shell32); + /* see the MSDN documentation referring to the result codes here */ + if (r <= 32) { + die("failed to launch browser for %.*s", MAX_PATH, unixpath); + } } int link(const char *oldpath, const char *newpath) From 4eb7315e3566083cd92ab12adb611034c93d207c Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 18 Mar 2010 11:48:50 +0000 Subject: [PATCH 769/781] mingw: add tests for the hidden attribute on the git directory With msysGit the .git directory is supposed to be hidden, unless it is a bare git repository. Test this. Signed-off-by: Pat Thoyts --- t/t0001-init.sh | 28 ++++++++++++++++++++++++++++ t/test-lib.sh | 1 + 2 files changed, 29 insertions(+) diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 675773479a..5bacf2278c 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -310,4 +310,32 @@ test_expect_success POSIXPERM 'init notices EPERM' ' ) ' +# Tests for the hidden file attribute on windows +is_hidden () { + test "1" -eq "$(echo puts [file attributes $1 -hidden]|tclsh)" +} + +test_expect_success MINGW 'plain hidden' ' + rm -rf newdir && + ( + unset GIT_DIR GIT_WORK_TREE + mkdir newdir && + cd newdir && + git init && + is_hidden .git + ) && + check_config newdir/.git false unset +' + +test_expect_success MINGW 'plain bare not hidden' ' + rm -rf newdir + ( + unset GIT_DIR GIT_WORK_TREE GIT_CONFIG + mkdir newdir && + cd newdir && + git --bare init + ) && + ! is_hidden newdir +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 97f3e7f50e..e2379b8ad2 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -777,6 +777,7 @@ case $(uname -s) in # no POSIX permissions # backslashes in pathspec are converted to '/' # exec does not inherit the PID + test_set_prereq MINGW ;; *) test_set_prereq POSIXPERM From 6e5ac68edf823e6441fbc227a20431d1976e6514 Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Thu, 18 Mar 2010 10:21:31 +0000 Subject: [PATCH 770/781] mingw: do not hide bare repositories As reported in msysGit issue 450 the recent change to set the windows hidden attribute on the .git directory is being applied to bare git directories. This patch excludes bare repositories. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index cc47d6834a..bbae2be946 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -132,7 +132,8 @@ static int make_hidden(const char *path) void mingw_mark_as_git_dir(const char *dir) { - if (hide_dotfiles != HIDE_DOTFILES_FALSE && make_hidden(dir)) + if (hide_dotfiles != HIDE_DOTFILES_FALSE && !is_bare_repository() && + make_hidden(dir)) warning("Failed to make '%s' hidden", dir); git_config_set("core.hideDotFiles", hide_dotfiles == HIDE_DOTFILES_FALSE ? "false" : From f971b944805779ff503093314b80e7cad9525d9f Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Sat, 20 Mar 2010 22:48:42 +0100 Subject: [PATCH 771/781] mingw: fix st_mode for symlink dirs When encountering symlinks, do_lstat() currently overwrites buf->st_mode with S_IFREG if follow is true. This is incorrect when the symlink points to a directory. get_file_attr calls GetFileAttributesExA, which follows symlinks already. So our st_mode should already be correct at this point. Tested-by: Pat Thoyts Signed-off-by: Erik Faye-Lund --- compat/mingw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index bbae2be946..7ec615c5ac 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -373,7 +373,6 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) if (follow) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); - buf->st_mode = S_IFREG; } else { buf->st_mode = S_IFLNK; } From 756a719c586c875980d321f96d3604ef1c8c0a55 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 7 Apr 2010 23:14:00 +0200 Subject: [PATCH 772/781] git-am: fix absolute path logic on Windows This fixes t4150 on msysGit. Signed-off-by: Johannes Schindelin --- git-am.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-am.sh b/git-am.sh index 1056075545..4db4f42516 100755 --- a/git-am.sh +++ b/git-am.sh @@ -444,7 +444,7 @@ else first= } case "$arg" in - /*) + /*|?:*) set "$@" "$arg" ;; *) set "$@" "$prefix$arg" ;; From d3c402ff43caf5b90895040cce2abb12e8012e23 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 00:18:07 +0200 Subject: [PATCH 773/781] Work around funny CR issue This is really a problem with shell scripts being called on msysGit, but there are more important bugs to fix for the moment. Signed-off-by: Johannes Schindelin --- t/t7401-submodule-summary.sh | 4 ++++ t/t7407-submodule-foreach.sh | 16 ++++++++++++++++ t/t7508-status.sh | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index cee319da0a..8a8a7bf47b 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -212,6 +212,10 @@ EOF test_expect_success '--for-status' " git submodule summary --for-status HEAD^ >actual && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp actual - < ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -154,6 +158,10 @@ test_expect_success 'test messages from "foreach --recursive"' ' cd clone2 && git submodule foreach --recursive "true" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -172,6 +180,10 @@ test_expect_success 'test "foreach --quiet --recursive"' ' cd clone2 && git submodule foreach -q --recursive "echo \$name-\$path" > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' @@ -219,6 +231,10 @@ test_expect_success 'test "status --recursive"' ' cd clone3 && git submodule status --recursive > ../actual ) && + if test_have_prereq MINGW + then + dos2unix actual + fi && test_cmp expect actual ' diff --git a/t/t7508-status.sh b/t/t7508-status.sh index a9df7ff7bd..e439b0f8ac 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -607,6 +607,10 @@ EOF test_expect_success 'status submodule summary' ' git config status.submodulesummary 10 && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -623,6 +627,10 @@ A sm EOF test_expect_success 'status -s submodule summary' ' git status -s >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -649,8 +657,16 @@ test_expect_success 'status submodule summary (clean submodule)' ' git commit -m "commit submodule" && git config status.submodulesummary 10 && test_must_fail git commit --dry-run >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output && git status >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -665,6 +681,10 @@ cat >expect <output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' @@ -700,6 +720,10 @@ EOF test_expect_success 'commit --dry-run submodule summary (--amend)' ' git config status.submodulesummary 10 && git commit --dry-run --amend >output && + if test_have_prereq MINGW + then + dos2unix output + fi && test_cmp expect output ' From e1a0ad012be06b3b1ae7a22b541de6a4bc991fae Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 7 Feb 2010 19:58:28 +0100 Subject: [PATCH 774/781] Unify code paths of threaded greps There were two awfully similar code paths ending the threaded grep. It is better to avoid duplicated code, though. This change might very well prevent a race, where the grep patterns were free()d before waiting that all threads finished. Signed-off-by: Johannes Schindelin --- builtin/grep.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/builtin/grep.c b/builtin/grep.c index b194ea3cea..a35ef71c27 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -590,7 +590,6 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) if (hit && opt->status_only) break; } - free_grep_patterns(opt); return hit; } @@ -1012,28 +1011,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (!list.nr) { - int hit; if (!cached) setup_work_tree(); hit = grep_cache(&opt, paths, cached); - if (use_threads) - hit |= wait_all(); - return !hit; } - - if (cached) + else if (cached) die("both --cached and trees are given."); - - for (i = 0; i < list.nr; i++) { - struct object *real_obj; - real_obj = deref_tag(list.objects[i].item, NULL, 0); - if (grep_object(&opt, paths, real_obj, list.objects[i].name)) { - hit = 1; - if (opt.status_only) - break; + else + for (i = 0; i < list.nr; i++) { + struct object *real_obj; + real_obj = deref_tag(list.objects[i].item, NULL, 0); + if (grep_object(&opt, paths, real_obj, + list.objects[i].name)) { + hit = 1; + if (opt.status_only) + break; + } } - } if (use_threads) hit |= wait_all(); From 6a5eac6a3150eb6bd650ea1eda0c24d273660ccc Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 23 Apr 2009 12:50:22 +0200 Subject: [PATCH 775/781] grep: Add the option '--open-files-in-pager' This adds an option to open the matching files in the pager, and if the pager happens to be "less" (or "vi") and there is only one grep pattern, it also jumps to the first match right away. The short option was chose as '-O' to avoid clashes with GNU grep's options (as suggested by Junio). So, 'git grep -O abc' is a short form for 'less +/abc $(grep -l abc)' except that it works also with spaces in file names, and it does not start the pager if there was no matching file. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 8 +++++ builtin/grep.c | 71 ++++++++++++++++++++++++++++++++++++++ git.c | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 4b32322a67..8fdd8e1e42 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,6 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] + [-O | --open-files-in-pager] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -104,6 +105,13 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. +-O:: +--open-files-in-pager:: + Open the matching files in the pager (not the output of 'grep'). + If the pager happens to be "less" or "vi", and the user + specified only one pattern, the first file is positioned at + the first match automatically. + -z:: --null:: Output \0 instead of the character that normally follows a diff --git a/builtin/grep.c b/builtin/grep.c index a35ef71c27..d0af900ded 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -15,6 +15,7 @@ #include "grep.h" #include "quote.h" #include "dir.h" +#include "string-list.h" #ifndef NO_PTHREADS #include @@ -556,6 +557,31 @@ static int grep_file(struct grep_opt *opt, const char *filename) } } +static void append_path(struct grep_opt *opt, const void *data, size_t len) +{ + struct string_list *path_list = opt->output_priv; + + if (len == 1 && *(char *)data == '\0') + return; + string_list_append(xstrndup(data, len), path_list); +} + +static void run_pager(struct grep_opt *opt, const char *prefix) +{ + struct string_list *path_list = opt->output_priv; + char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1)); + int i; + + for (i = 0; i < path_list->nr; i++) + argv[i] = path_list->items[i].string; + argv[path_list->nr] = NULL; + + if (prefix) + chdir(prefix); + execvp(argv[0], argv); + error("Could not run pager %s: %s", argv[0], strerror(errno)); +} + static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; @@ -781,9 +807,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; + int show_in_pager = 0; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; + struct string_list path_list = { NULL, 0, 0, 0 }; int i; int dummy; int nongit = 0, use_index = 1; @@ -867,6 +895,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), + OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, + "show matching files in the pager"), OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -942,6 +972,20 @@ int cmd_grep(int argc, const char **argv, const char *prefix) argc--; } + if (show_in_pager) { + const char *pager = getenv("GIT_PAGER"); + if (!pager) + pager = getenv("PAGER"); + if (!pager) + pager = "less"; + opt.name_only = 1; + opt.null_following_name = 1; + opt.output_priv = &path_list; + opt.output = append_path; + string_list_append(pager, &path_list); + use_threads = 0; + } + if (!opt.pattern_list) die("no pattern given."); if (!opt.fixed && opt.ignore_case) @@ -1010,6 +1054,29 @@ int cmd_grep(int argc, const char **argv, const char *prefix) return !hit; } + if (show_in_pager && (cached || list.nr)) + die ("--open-files-in-pager only works on the worktree"); + + if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) { + const char *pager = path_list.items[0].string; + int len = strlen(pager); + + if (len > 4 && is_dir_sep(pager[len - 5])) + pager += len - 4; + + if (!strcmp("less", pager) || !strcmp("vi", pager)) { + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "+/%s%s", + strcmp("less", pager) ? "" : "*", + opt.pattern_list->pattern); + string_list_append(buf.buf, &path_list); + strbuf_detach(&buf, NULL); + } + } + + if (!show_in_pager) + setup_pager(); + if (!list.nr) { if (!cached) setup_work_tree(); @@ -1032,6 +1099,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (use_threads) hit |= wait_all(); + + if (hit && show_in_pager) + run_pager(&opt, prefix); + free_grep_patterns(&opt); return !hit; } diff --git a/git.c b/git.c index 99f036302a..265fa09d8d 100644 --- a/git.c +++ b/git.c @@ -329,7 +329,7 @@ static void handle_internal_command(int argc, const char **argv) { "fsck-objects", cmd_fsck, RUN_SETUP }, { "gc", cmd_gc, RUN_SETUP }, { "get-tar-commit-id", cmd_get_tar_commit_id }, - { "grep", cmd_grep, USE_PAGER }, + { "grep", cmd_grep }, { "hash-object", cmd_hash_object }, { "help", cmd_help }, { "index-pack", cmd_index_pack }, From 78577c6a9f50761f3d08d654f72cb2ebdd953d99 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 2 Jul 2009 00:19:52 +0200 Subject: [PATCH 776/781] grep -O: allow optional argument specifying the pager (or editor) Suppose you want to edit all files that contain a specific search term. Of course, you can do something totally trivial such as git grep -z -e | xargs -0r vi +/ but maybe you are happy that the same will be achieved by git grep -Ovi now. Signed-off-by: Johannes Schindelin --- Documentation/git-grep.txt | 6 +++--- builtin/grep.c | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 8fdd8e1e42..d89ec32485 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -14,7 +14,7 @@ SYNOPSIS [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings] [-n] [-l | --files-with-matches] [-L | --files-without-match] - [-O | --open-files-in-pager] + [(-O | --open-files-in-pager) []] [-z | --null] [-c | --count] [--all-match] [-q | --quiet] [--max-depth ] @@ -105,8 +105,8 @@ OPTIONS For better compatibility with 'git diff', `--name-only` is a synonym for `--files-with-matches`. --O:: ---open-files-in-pager:: +-O []:: +--open-files-in-pager []:: Open the matching files in the pager (not the output of 'grep'). If the pager happens to be "less" or "vi", and the user specified only one pattern, the first file is positioned at diff --git a/builtin/grep.c b/builtin/grep.c index d0af900ded..c87db91cf4 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -807,7 +807,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int cached = 0; int seen_dashdash = 0; int external_grep_allowed__ignored; - int show_in_pager = 0; + const char *show_in_pager = NULL, *default_pager = "dummy"; struct grep_opt opt; struct object_array list = { 0, 0, NULL }; const char **paths = NULL; @@ -895,8 +895,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "all-match", &opt.all_match, "show only matches from files that match all patterns"), OPT_GROUP(""), - OPT_BOOLEAN('O', "open-files-in-pager", &show_in_pager, - "show matching files in the pager"), + { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, + "pager", "show matching files in the pager", + PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, "allow calling of grep(1) (ignored by this build)"), { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", @@ -973,16 +974,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } if (show_in_pager) { - const char *pager = getenv("GIT_PAGER"); - if (!pager) - pager = getenv("PAGER"); - if (!pager) - pager = "less"; + if (show_in_pager == default_pager) { + show_in_pager = getenv("GIT_PAGER"); + if (!show_in_pager) + show_in_pager = getenv("PAGER"); + if (!show_in_pager) + show_in_pager = "less"; + } opt.name_only = 1; opt.null_following_name = 1; opt.output_priv = &path_list; opt.output = append_path; - string_list_append(pager, &path_list); + string_list_append(show_in_pager, &path_list); use_threads = 0; } From 66eac8a91925744e19176f692c18daef47fdffd0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Apr 2010 16:47:51 +0200 Subject: [PATCH 777/781] Replace obsolete 'diff' call with 'test_cmp' Signed-off-by: Johannes Schindelin --- t/t7002-grep.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index e249c3ed41..8a6322765c 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -60,7 +60,7 @@ do echo ${HC}file:5:foo_mmap bar mmap baz } >expected && git grep -n -w -e mmap $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (w)" ' @@ -74,7 +74,7 @@ do echo ${HC}x:1:x x xx x } >expected && git grep -n -w -e "x xx* x" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-1)" ' @@ -82,7 +82,7 @@ do echo ${HC}y:1:y yy } >expected && git grep -n -w -e "^y" $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -w $L (y-2)" ' @@ -93,7 +93,7 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' @@ -105,14 +105,14 @@ do cat actual false else - diff expected actual + test_cmp expected actual fi ' test_expect_success "grep $L (t-1)" ' echo "${HC}t/t:1:test" >expected && git grep -n -e test $H >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-2)" ' @@ -121,7 +121,7 @@ do cd t && git grep -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep $L (t-3)" ' @@ -130,7 +130,7 @@ do cd t && git grep --full-name -n -e test $H ) >actual && - diff expected actual + test_cmp expected actual ' test_expect_success "grep -c $L (no /dev/null)" ' From b7955ea279cc8cac06de2be84d64a20b7d2a7ea9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Feb 2009 21:52:51 +0100 Subject: [PATCH 778/781] Add a few more values for receive.denyCurrentBranch For a long time, this developer thought that Git's insistence that pushing into the current branch is evil was completely merited. Just for fun, the original patch tried to show people that Git is right there, and that it causes more trouble than it does good when Git allows you to try to update the working tree for fast-forwards, or to detach the HEAD, depending on some config settings. Surprisingly, the opposite was shown. So here is the support for two new options you can give the config variable receive.denyCurrentBranch: 'updateInstead': Try to merge the working tree with the new tip of the branch (which can lead to really horrible merge conflicts). 'detachInstead': Detach the HEAD, thereby avoiding a disagreement between the HEAD and the index (as well as the working tree), possibly leaving the local user wondering how on earth her HEAD became so detached. Signed-off-by: Johannes Schindelin --- Documentation/config.txt | 5 ++++ builtin/receive-pack.c | 56 +++++++++++++++++++++++++++++++++++++++- t/t5516-fetch-push.sh | 36 ++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 2df16315d6..dcf5e87fcc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1538,6 +1538,11 @@ receive.denyCurrentBranch:: print a warning of such a push to stderr, but allow the push to proceed. If set to false or "ignore", allow such pushes with no message. Defaults to "refuse". ++ +There are two more options that are meant for Git experts: "updateInstead" +which will run `read-tree -u -m HEAD` and "detachInstead" which will detach +the HEAD so it does not need to change. Both options come with their own +set of possible *complications*, but can be appropriate in rare workflows. receive.denyNonFastForwards:: If set to true, git-receive-pack will deny a ref update which is diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0559fcc871..f35070358f 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -17,6 +17,8 @@ enum deny_action { DENY_IGNORE, DENY_WARN, DENY_REFUSE, + DENY_UPDATE_INSTEAD, + DENY_DETACH_INSTEAD, }; static int deny_deletes; @@ -78,7 +80,12 @@ static int receive_pack_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "receive.denycurrentbranch")) { - deny_current_branch = parse_deny_action(var, value); + if (value && !strcasecmp(value, "updateinstead")) + deny_current_branch = DENY_UPDATE_INSTEAD; + else if (value && !strcasecmp(value, "detachinstead")) + deny_current_branch = DENY_DETACH_INSTEAD; + else + deny_current_branch = parse_deny_action(var, value); return 0; } @@ -329,6 +336,44 @@ static void refuse_unconfigured_deny_delete_current(void) rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]); } +static void merge_worktree(unsigned char *sha1) +{ + const char *update_refresh[] = { + "update-index", "--refresh", NULL + }; + const char *read_tree[] = { + "read-tree", "-u", "-m", sha1_to_hex(sha1), NULL + }; + struct child_process child; + struct strbuf git_env = STRBUF_INIT; + const char *env[2]; + + if (is_bare_repository()) + die ("denyCurrentBranch = updateInstead needs a worktree"); + + strbuf_addf(&git_env, "GIT_DIR=%s", make_absolute_path(get_git_dir())); + env[0] = git_env.buf; + env[1] = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = update_refresh; + child.env = env; + child.dir = git_work_tree_cfg ? git_work_tree_cfg : ".."; + child.stdout_to_stderr = 1; + child.git_cmd = 1; + if (run_command(&child)) + die ("Could not refresh the index"); + + child.argv = read_tree; + child.no_stdin = 1; + child.no_stdout = 1; + child.stdout_to_stderr = 0; + if (run_command(&child)) + die ("Could not merge working tree with new HEAD. Good luck."); + + strbuf_release(&git_env); +} + static const char *update(struct command *cmd) { const char *name = cmd->ref_name; @@ -355,6 +400,13 @@ static const char *update(struct command *cmd) if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; + case DENY_UPDATE_INSTEAD: + merge_worktree(new_sha1); + break; + case DENY_DETACH_INSTEAD: + update_ref("push into current branch (detach)", "HEAD", + old_sha1, NULL, REF_NODEREF, DIE_ON_ERR); + break; } } @@ -383,6 +435,8 @@ static const char *update(struct command *cmd) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; + default: + die ("Invalid denyDeleteCurrent setting"); } } } diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 2de98e6561..59caa61a52 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -710,4 +710,40 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'receive.denyCurrentBranch = updateInstead' ' + git push testrepo master && + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch updateInstead + ) && + test_commit third path2 && + git push testrepo master && + test $(git rev-parse HEAD) = $(cd testrepo && git rev-parse HEAD) && + test third = "$(cat testrepo/path2)" && + (cd testrepo && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + +test_expect_success 'receive.denyCurrentBranch = detachInstead' ' + (cd testrepo && + git reset --hard && + git config receive.denyCurrentBranch detachInstead + ) && + OLDHEAD=$(cd testrepo && git rev-parse HEAD) && + test_commit fourth path2 && + test fourth = "$(cat path2)" && + git push testrepo master && + test $OLDHEAD = $(cd testrepo && git rev-parse HEAD) && + test fourth != "$(cat testrepo/path2)" && + (cd testrepo && + test_must_fail git symbolic-ref HEAD && + git update-index --refresh && + git diff-files --quiet && + git diff-index --cached HEAD -- + ) +' + test_done From ee59bcd37dec47d313d99e245f72d707cbde9aee Mon Sep 17 00:00:00 2001 From: Ian McLean Date: Mon, 1 Mar 2010 14:58:45 -0500 Subject: [PATCH 779/781] Fix for issue 365: "Out of memory? mmap failed" The git_mmap implementation was broken for file sizes that wouldn't fit into a size_t (32 bits). Changed 'len' to be stored in an off_t (64 bit) variable, and moved the xsize_t cast to only occur when an attempt is made to map past the end-of-file. --- compat/win32mmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compat/win32mmap.c b/compat/win32mmap.c index 1c5a14922f..b58aa69fa0 100644 --- a/compat/win32mmap.c +++ b/compat/win32mmap.c @@ -4,19 +4,19 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of { HANDLE hmap; void *temp; - size_t len; + off_t len; struct stat st; uint64_t o = offset; uint32_t l = o & 0xFFFFFFFF; uint32_t h = (o >> 32) & 0xFFFFFFFF; if (!fstat(fd, &st)) - len = xsize_t(st.st_size); + len = st.st_size; else die("mmap: could not determine filesize"); if ((length + offset) > len) - length = len - offset; + length = xsize_t(len - offset); if (!(flags & MAP_PRIVATE)) die("Invalid usage of mmap when built with USE_WIN32_MMAP"); From f6a2f432a248f6b65cdb43a29905716fd3365ebc Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:15:40 -0400 Subject: [PATCH 780/781] start_command: close cmd->err descriptor when fork/spawn fails Fix the problem where the cmd->err passed into start_command wasn't being properly closed when certain types of errors occurr. (Compare the affected code with the clean shutdown code later in the function.) On Windows, this problem would be triggered if mingw_spawnvpe() failed, which would happen if the command to be executed was malformed (e.g. a text file that didn't start with a #! line). If cmd->err was a pipe, the failure to close it could result in a hang while the other side was waiting (forever) for either input or pipe close, e.g. while trying to shove the output into the side band. On msysGit, this problem was causing a hang in t5516-fetch-push. I'm not sure why (or if) this problem hasn't cropped up under Linux. The non-Windows code *does* try to check for execve() failures in the child, in addition to the fork() failures. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- run-command.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-command.c b/run-command.c index e996b21426..c13072d77c 100644 --- a/run-command.c +++ b/run-command.c @@ -385,6 +385,8 @@ fail_pipe: close(cmd->out); if (need_err) close_pair(fderr); + else if (cmd->err) + close(cmd->err); errno = failed_errno; return -1; } From 95858c276b42719b19f17f68834092e615f58e3e Mon Sep 17 00:00:00 2001 From: bert Dvornik Date: Sun, 25 Apr 2010 21:22:31 -0400 Subject: [PATCH 781/781] mingw: Don't ask the user yes/no questions if they can't see the question. If the stdout of the command is connected to a terminal but the stderr has been redirected, the odds are good that the user can't see any question we print out to stderr. This will result in a "mysterious hang" while the app is waiting for user input. It seems better to be conservative, and avoid asking for input whenever the stderr is not a terminal, just like we do for stdin. Signed-off-by: bert Dvornik Signed-off-by: Johannes Schindelin --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 7ec615c5ac..643cb2473a 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -175,7 +175,7 @@ static int ask_user_yes_no(const char *format, ...) return !run_command_v_opt(retry_hook, 0); } - if (!isatty(_fileno(stdin))) + if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) return 0; while (1) {