Commit 3a82475f327775f0320f7e9ff333c43944ec63ff

Patrick Steinhardt 2018-02-09T12:49:45

config_file: add list holding config entries in order of appearance Right now, we only keep all configuration entries in a string map. This is required to efficiently access configuration entries by keys. It has the disadvantage of not being able to iterate through configuration entries in the order they were read, though. Instead, we only iterate through entries in a seemingly random order. Extend `diskfile_entries` by another list holding configuration entries. Like this, we maintain all entries in two data structures and can use the required one based on the current use case.

diff --git a/src/config_file.c b/src/config_file.c
index 0f0ee74..4909ce1 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -40,6 +40,7 @@ typedef struct git_config_file_iter {
 typedef struct {
 	git_atomic refcount;
 	git_strmap *map;
+	config_entry_list *list;
 } diskfile_entries;
 
 typedef struct {
@@ -129,6 +130,19 @@ int git_config_file_normalize_section(char *start, char *end)
 	return 0;
 }
 
+static void config_entry_list_append(config_entry_list **list, config_entry_list *entry)
+{
+	config_entry_list *head = *list;
+
+	if (head) {
+		while (head->next != NULL)
+			head = head->next;
+		head->next = entry;
+	} else {
+		*list = entry;
+	}
+}
+
 /* Add or append the new config option */
 static int diskfile_entries_append(diskfile_entries *entries, git_config_entry *entry)
 {
@@ -143,23 +157,25 @@ static int diskfile_entries_append(diskfile_entries *entries, git_config_entry *
 	pos = git_strmap_lookup_index(entries->map, entry->name);
 	if (!git_strmap_valid_index(entries->map, pos)) {
 		git_strmap_insert(entries->map, entry->name, var, &error);
+
+		if (error > 0)
+			error = 0;
 	} else {
 		existing = git_strmap_value_at(entries->map, pos);
-		while (existing->next != NULL) {
-			existing = existing->next;
-		}
-		existing->next = var;
+		config_entry_list_append(&existing, var);
 	}
 
-	if (error > 0)
-		error = 0;
+	var = git__calloc(1, sizeof(config_entry_list));
+	GITERR_CHECK_ALLOC(var);
+	var->entry = entry;
+	config_entry_list_append(&entries->list, var);
 
 	return error;
 }
 
 static void diskfile_entries_free(diskfile_entries *entries)
 {
-	config_entry_list *list = NULL;
+	config_entry_list *list = NULL, *next;
 
 	if (!entries)
 		return;
@@ -169,6 +185,14 @@ static void diskfile_entries_free(diskfile_entries *entries)
 
 	git_strmap_foreach_value(entries->map, list, config_entry_list_free(list));
 	git_strmap_free(entries->map);
+
+	list = entries->list;
+	while (list != NULL) {
+		next = list->next;
+		git__free(list);
+		list = next;
+	}
+
 	git__free(entries);
 }