File Coverage

deps/libgit2/src/config_entries.c
Criterion Covered Total %
statement 99 111 89.1
branch 36 54 66.6
condition n/a
subroutine n/a
pod n/a
total 135 165 81.8


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7              
8             #include "config_entries.h"
9              
10             typedef struct config_entry_list {
11             struct config_entry_list *next;
12             struct config_entry_list *last;
13             git_config_entry *entry;
14             } config_entry_list;
15              
16             typedef struct {
17             git_config_entry *entry;
18             bool multivar;
19             } config_entry_map_head;
20              
21             typedef struct config_entries_iterator {
22             git_config_iterator parent;
23             git_config_entries *entries;
24             config_entry_list *head;
25             } config_entries_iterator;
26              
27             struct git_config_entries {
28             git_refcount rc;
29             git_strmap *map;
30             config_entry_list *list;
31             };
32              
33 2314           int git_config_entries_new(git_config_entries **out)
34             {
35             git_config_entries *entries;
36             int error;
37              
38 2314           entries = git__calloc(1, sizeof(git_config_entries));
39 2314 50         GIT_ERROR_CHECK_ALLOC(entries);
40 2314           GIT_REFCOUNT_INC(entries);
41              
42 2314 50         if ((error = git_strmap_new(&entries->map)) < 0)
43 0           git__free(entries);
44             else
45 2314           *out = entries;
46              
47 2314           return error;
48             }
49              
50 14674           int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry)
51             {
52             git_config_entry *duplicated;
53             int error;
54              
55 14674           duplicated = git__calloc(1, sizeof(git_config_entry));
56 14674 50         GIT_ERROR_CHECK_ALLOC(duplicated);
57              
58 14674           duplicated->name = git__strdup(entry->name);
59 14674 50         GIT_ERROR_CHECK_ALLOC(duplicated->name);
60              
61 14674 50         if (entry->value) {
62 14674           duplicated->value = git__strdup(entry->value);
63 14674 50         GIT_ERROR_CHECK_ALLOC(duplicated->value);
64             }
65 14674           duplicated->level = entry->level;
66 14674           duplicated->include_depth = entry->include_depth;
67              
68 14674 50         if ((error = git_config_entries_append(entries, duplicated)) < 0)
69 0           goto out;
70              
71             out:
72 14674 50         if (error && duplicated) {
    0          
73 0           git__free((char *) duplicated->name);
74 0           git__free((char *) duplicated->value);
75 0           git__free(duplicated);
76             }
77 14674           return error;
78             }
79              
80 1108           int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
81             {
82 1108           git_config_entries *result = NULL;
83             config_entry_list *head;
84             int error;
85              
86 1108 50         if ((error = git_config_entries_new(&result)) < 0)
87 0           goto out;
88              
89 8877 100         for (head = entries->list; head; head = head->next)
90 7769 50         if ((git_config_entries_dup_entry(result, head->entry)) < 0)
91 0           goto out;
92              
93 1108           *out = result;
94 1108           result = NULL;
95              
96             out:
97 1108           git_config_entries_free(result);
98 1108           return error;
99             }
100              
101 7400           void git_config_entries_incref(git_config_entries *entries)
102             {
103 7400           GIT_REFCOUNT_INC(entries);
104 7400           }
105              
106 2310           static void config_entries_free(git_config_entries *entries)
107             {
108 2310           config_entry_list *list = NULL, *next;
109             config_entry_map_head *head;
110              
111 17573 100         git_strmap_foreach_value(entries->map, head,
112             git__free((char *) head->entry->name); git__free(head)
113             );
114 2310           git_strmap_free(entries->map);
115              
116 2310           list = entries->list;
117 18469 100         while (list != NULL) {
118 16159           next = list->next;
119 16159           git__free((char *) list->entry->value);
120 16159           git__free(list->entry);
121 16159           git__free(list);
122 16159           list = next;
123             }
124              
125 2310           git__free(entries);
126 2310           }
127              
128 10886           void git_config_entries_free(git_config_entries *entries)
129             {
130 10886 100         if (entries)
131 9710 100         GIT_REFCOUNT_DEC(entries, config_entries_free);
    50          
132 10886           }
133              
134 16165           int git_config_entries_append(git_config_entries *entries, git_config_entry *entry)
135             {
136             config_entry_list *list_head;
137             config_entry_map_head *map_head;
138              
139 16165 100         if ((map_head = git_strmap_get(entries->map, entry->name)) != NULL) {
140 896           map_head->multivar = true;
141             /*
142             * This is a micro-optimization for configuration files
143             * with a lot of same keys. As for multivars the entry's
144             * key will be the same for all entries, we can just free
145             * all except the first entry's name and just re-use it.
146             */
147 896           git__free((char *) entry->name);
148 896           entry->name = map_head->entry->name;
149             } else {
150 15269           map_head = git__calloc(1, sizeof(*map_head));
151 15269 50         if ((git_strmap_set(entries->map, entry->name, map_head)) < 0)
152 0           return -1;
153             }
154 16165           map_head->entry = entry;
155              
156 16165           list_head = git__calloc(1, sizeof(config_entry_list));
157 16165 50         GIT_ERROR_CHECK_ALLOC(list_head);
158 16165           list_head->entry = entry;
159              
160 16165 100         if (entries->list)
161 14978           entries->list->last->next = list_head;
162             else
163 1187           entries->list = list_head;
164 16165           entries->list->last = list_head;
165              
166 16165           return 0;
167             }
168              
169 5205           int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key)
170             {
171             config_entry_map_head *entry;
172 5205 100         if ((entry = git_strmap_get(entries->map, key)) == NULL)
173 4312           return GIT_ENOTFOUND;
174 893           *out = entry->entry;
175 893           return 0;
176             }
177              
178 55           int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key)
179             {
180             config_entry_map_head *entry;
181              
182 55 100         if ((entry = git_strmap_get(entries->map, key)) == NULL)
183 46           return GIT_ENOTFOUND;
184              
185 9 50         if (entry->multivar) {
186 0           git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being a multivar");
187 0           return -1;
188             }
189              
190 9 50         if (entry->entry->include_depth) {
191 0           git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included");
192 0           return -1;
193             }
194              
195 9           *out = entry->entry;
196              
197 9           return 0;
198             }
199              
200 1108           static void config_iterator_free(git_config_iterator *iter)
201             {
202 1108           config_entries_iterator *it = (config_entries_iterator *) iter;
203 1108           git_config_entries_free(it->entries);
204 1108           git__free(it);
205 1108           }
206              
207 8866           static int config_iterator_next(
208             git_config_entry **entry,
209             git_config_iterator *iter)
210             {
211 8866           config_entries_iterator *it = (config_entries_iterator *) iter;
212              
213 8866 100         if (!it->head)
214 1107           return GIT_ITEROVER;
215              
216 7759           *entry = it->head->entry;
217 7759           it->head = it->head->next;
218              
219 7759           return 0;
220             }
221              
222 1108           int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries)
223             {
224             config_entries_iterator *it;
225              
226 1108           it = git__calloc(1, sizeof(config_entries_iterator));
227 1108 50         GIT_ERROR_CHECK_ALLOC(it);
228 1108           it->parent.next = config_iterator_next;
229 1108           it->parent.free = config_iterator_free;
230 1108           it->head = entries->list;
231 1108           it->entries = entries;
232              
233 1108           git_config_entries_incref(entries);
234 1108           *out = &it->parent;
235              
236 1108           return 0;
237             }