Commit 2fe54afa2a8f87d03d2d550dcde7718f27e40967

Russell Belfer 2013-09-30T16:58:33

Put hooks in place for precompose in dirload fn This doesn't actual do string precompose but it puts the hooks in place into the iterators and the git_path_dirload function so that the actual precompose work is ready to go.

diff --git a/src/config_cache.c b/src/config_cache.c
index 84de3a5..6808521 100644
--- a/src/config_cache.c
+++ b/src/config_cache.c
@@ -67,6 +67,7 @@ static struct map_data _cvar_maps[] = {
 	{"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT },
 	{"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT },
 	{"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT },
+	{"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT },
 };
 
 int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
diff --git a/src/iterator.c b/src/iterator.c
index bdc98d2..9467904 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -986,7 +986,10 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
 	GITERR_CHECK_ALLOC(ff);
 
 	error = git_path_dirload_with_stat(
-		fi->path.ptr, fi->root_len, iterator__ignore_case(fi),
+		fi->path.ptr, fi->root_len,
+		(iterator__ignore_case(fi) ? GIT_PATH_DIRLOAD_IGNORE_CASE : 0) |
+		(iterator__flag(fi, PRECOMPOSE_UNICODE) ?
+			GIT_PATH_DIRLOAD_PRECOMPOSE_UNICODE : 0),
 		fi->base.start, fi->base.end, &ff->entries);
 
 	if (error < 0) {
@@ -1356,6 +1359,15 @@ int git_iterator_for_workdir_ext(
 		return error;
 	}
 
+	/* try to look up precompose and set flag if appropriate */
+	{
+		int precompose = 0;
+		if (git_repository__cvar(&precompose, repo, GIT_CVAR_PRECOMPOSE) < 0)
+			giterr_clear();
+		else if (precompose)
+			wi->fi.base.flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
+	}
+
 	return fs_iterator__initialize(out, &wi->fi, repo_workdir);
 }
 
diff --git a/src/iterator.h b/src/iterator.h
index ea88fa6..751e139 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -24,13 +24,15 @@ typedef enum {
 
 typedef enum {
 	/** ignore case for entry sort order */
-	GIT_ITERATOR_IGNORE_CASE = (1 << 0),
+	GIT_ITERATOR_IGNORE_CASE = (1u << 0),
 	/** force case sensitivity for entry sort order */
-	GIT_ITERATOR_DONT_IGNORE_CASE = (1 << 1),
+	GIT_ITERATOR_DONT_IGNORE_CASE = (1u << 1),
 	/** return tree items in addition to blob items */
-	GIT_ITERATOR_INCLUDE_TREES    = (1 << 2),
+	GIT_ITERATOR_INCLUDE_TREES    = (1u << 2),
 	/** don't flatten trees, requiring advance_into (implies INCLUDE_TREES) */
-	GIT_ITERATOR_DONT_AUTOEXPAND  = (1 << 3),
+	GIT_ITERATOR_DONT_AUTOEXPAND  = (1u << 3),
+	/** convert precomposed unicode to decomposed unicode */
+	GIT_ITERATOR_PRECOMPOSE_UNICODE = (1u << 4),
 } git_iterator_flag_t;
 
 typedef struct {
diff --git a/src/path.c b/src/path.c
index 9d8e903..c4ab571 100644
--- a/src/path.c
+++ b/src/path.c
@@ -781,6 +781,7 @@ int git_path_dirload(
 	const char *path,
 	size_t prefix_len,
 	size_t alloc_extra,
+	unsigned int flags,
 	git_vector *contents)
 {
 	int error, need_slash;
@@ -816,6 +817,12 @@ int git_path_dirload(
 
 		entry_len = strlen(de->d_name);
 
+		/* if we read decomposed unicode and precompose flag is set,
+		 * then precompose it now so app code sees it as precomposed
+		 */
+		if ((flags & GIT_PATH_DIRLOAD_PRECOMPOSE_UNICODE) != 0) {
+		}
+
 		entry_path = git__malloc(
 			path_len + need_slash + entry_len + 1 + alloc_extra);
 		GITERR_CHECK_ALLOC(entry_path);
@@ -858,7 +865,7 @@ int git_path_with_stat_cmp_icase(const void *a, const void *b)
 int git_path_dirload_with_stat(
 	const char *path,
 	size_t prefix_len,
-	bool ignore_case,
+	unsigned int flags,
 	const char *start_stat,
 	const char *end_stat,
 	git_vector *contents)
@@ -875,13 +882,14 @@ int git_path_dirload_with_stat(
 		return -1;
 
 	error = git_path_dirload(
-		path, prefix_len, sizeof(git_path_with_stat) + 1, contents);
+		path, prefix_len, sizeof(git_path_with_stat) + 1, flags, contents);
 	if (error < 0) {
 		git_buf_free(&full);
 		return error;
 	}
 
-	strncomp = ignore_case ? git__strncasecmp : git__strncmp;
+	strncomp = (flags & GIT_PATH_DIRLOAD_IGNORE_CASE) != 0 ?
+		git__strncasecmp : git__strncmp;
 
 	/* stat struct at start of git_path_with_stat, so shift path text */
 	git_vector_foreach(contents, i, ps) {
diff --git a/src/path.h b/src/path.h
index b2899e9..feacc99 100644
--- a/src/path.h
+++ b/src/path.h
@@ -290,6 +290,11 @@ extern int git_path_walk_up(
 	int (*fn)(void *state, git_buf *),
 	void *state);
 
+enum {
+	GIT_PATH_DIRLOAD_IGNORE_CASE = (1u << 0),
+	GIT_PATH_DIRLOAD_PRECOMPOSE_UNICODE = (1u << 1),
+};
+
 /**
  * Load all directory entries (except '.' and '..') into a vector.
  *
@@ -310,6 +315,7 @@ extern int git_path_dirload(
 	const char *path,
 	size_t prefix_len,
 	size_t alloc_extra,
+	unsigned int flags,
 	git_vector *contents);
 
 
@@ -336,7 +342,7 @@ extern int git_path_with_stat_cmp_icase(const void *a, const void *b);
  *
  * @param path The directory to read from
  * @param prefix_len The trailing part of path to prefix to entry paths
- * @param ignore_case How to sort and compare paths with start/end limits
+ * @param flags GIT_PATH_DIRLOAD flags from above
  * @param start_stat As optimization, only stat values after this prefix
  * @param end_stat As optimization, only stat values before this prefix
  * @param contents Vector to fill with git_path_with_stat structures
@@ -344,7 +350,7 @@ extern int git_path_with_stat_cmp_icase(const void *a, const void *b);
 extern int git_path_dirload_with_stat(
 	const char *path,
 	size_t prefix_len,
-	bool ignore_case,
+	unsigned int flags,
 	const char *start_stat,
 	const char *end_stat,
 	git_vector *contents);
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 0ba711e..715b311 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -458,17 +458,23 @@ static void refdb_fs_backend__iterator_free(git_reference_iterator *_iter)
 
 static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
 {
-	int error = 0;
+	int error = 0, t;
 	git_buf path = GIT_BUF_INIT;
+	git_iterator_flag_t flags = 0;
 	git_iterator *fsit = NULL;
 	const git_index_entry *entry = NULL;
 
 	if (!backend->path) /* do nothing if no path for loose refs */
 		return 0;
 
+	if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_IGNORECASE) && t)
+		flags |= GIT_ITERATOR_IGNORE_CASE;
+	if (!git_repository__cvar(&t, backend->repo, GIT_CVAR_PRECOMPOSE) && t)
+		flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
+
 	if ((error = git_buf_printf(&path, "%s/refs", backend->path)) < 0 ||
 		(error = git_iterator_for_filesystem(
-			&fsit, git_buf_cstr(&path), 0, NULL, NULL)) < 0) {
+			&fsit, git_buf_cstr(&path), flags, NULL, NULL)) < 0) {
 		git_buf_free(&path);
 		return error;
 	}
diff --git a/src/repository.h b/src/repository.h
index 12dc50d..832df3b 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -37,6 +37,7 @@ typedef enum {
 	GIT_CVAR_IGNORESTAT,    /* core.ignorestat */
 	GIT_CVAR_TRUSTCTIME,    /* core.trustctime */
 	GIT_CVAR_ABBREV,        /* core.abbrev */
+	GIT_CVAR_PRECOMPOSE,    /* core.precomposeunicode */
 	GIT_CVAR_CACHE_MAX
 } git_cvar_cached;
 
@@ -86,6 +87,8 @@ typedef enum {
 	GIT_TRUSTCTIME_DEFAULT = GIT_CVAR_TRUE,
 	/* core.abbrev */
 	GIT_ABBREV_DEFAULT = 7,
+	/* core.precomposeunicode */
+	GIT_PRECOMPOSE_DEFAULT = GIT_CVAR_FALSE,
 
 } git_cvar_value;