File Coverage

deps/libgit2/src/libgit2/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 2350           int git_config_entries_new(git_config_entries **out)
34             {
35             git_config_entries *entries;
36             int error;
37              
38 2350           entries = git__calloc(1, sizeof(git_config_entries));
39 2350 50         GIT_ERROR_CHECK_ALLOC(entries);
40 2350           GIT_REFCOUNT_INC(entries);
41              
42 2350 50         if ((error = git_strmap_new(&entries->map)) < 0)
43 0           git__free(entries);
44             else
45 2350           *out = entries;
46              
47 2350           return error;
48             }
49              
50 16000           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 16000           duplicated = git__calloc(1, sizeof(git_config_entry));
56 16000 50         GIT_ERROR_CHECK_ALLOC(duplicated);
57              
58 16000           duplicated->name = git__strdup(entry->name);
59 16000 50         GIT_ERROR_CHECK_ALLOC(duplicated->name);
60              
61 16000 50         if (entry->value) {
62 16000           duplicated->value = git__strdup(entry->value);
63 16000 50         GIT_ERROR_CHECK_ALLOC(duplicated->value);
64             }
65 16000           duplicated->level = entry->level;
66 16000           duplicated->include_depth = entry->include_depth;
67              
68 16000 50         if ((error = git_config_entries_append(entries, duplicated)) < 0)
69 0           goto out;
70              
71             out:
72 16000 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 16000           return error;
78             }
79              
80 1137           int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
81             {
82 1137           git_config_entries *result = NULL;
83             config_entry_list *head;
84             int error;
85              
86 1137 50         if ((error = git_config_entries_new(&result)) < 0)
87 0           goto out;
88              
89 9726 100         for (head = entries->list; head; head = head->next)
90 8589 50         if ((git_config_entries_dup_entry(result, head->entry)) < 0)
91 0           goto out;
92              
93 1137           *out = result;
94 1137           result = NULL;
95              
96             out:
97 1137           git_config_entries_free(result);
98 1137           return error;
99             }
100              
101 7399           void git_config_entries_incref(git_config_entries *entries)
102             {
103 7399           GIT_REFCOUNT_INC(entries);
104 7399           }
105              
106 2350           static void config_entries_free(git_config_entries *entries)
107             {
108 2350           config_entry_list *list = NULL, *next;
109             config_entry_map_head *head;
110              
111 19001 100         git_strmap_foreach_value(entries->map, head,
112             git__free((char *) head->entry->name); git__free(head)
113             );
114 2350           git_strmap_free(entries->map);
115              
116 2350           list = entries->list;
117 19911 100         while (list != NULL) {
118 17561           next = list->next;
119 17561           git__free((char *) list->entry->value);
120 17561           git__free(list->entry);
121 17561           git__free(list);
122 17561           list = next;
123             }
124              
125 2350           git__free(entries);
126 2350           }
127              
128 10955           void git_config_entries_free(git_config_entries *entries)
129             {
130 10955 100         if (entries)
131 9749 100         GIT_REFCOUNT_DEC(entries, config_entries_free);
    50          
132 10955           }
133              
134 17561           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 17561 100         if ((map_head = git_strmap_get(entries->map, entry->name)) != NULL) {
140 910           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 910           git__free((char *) entry->name);
148 910           entry->name = map_head->entry->name;
149             } else {
150 16651           map_head = git__calloc(1, sizeof(*map_head));
151 16651 50         if ((git_strmap_set(entries->map, entry->name, map_head)) < 0)
152 0           return -1;
153             }
154 17561           map_head->entry = entry;
155              
156 17561           list_head = git__calloc(1, sizeof(config_entry_list));
157 17561 50         GIT_ERROR_CHECK_ALLOC(list_head);
158 17561           list_head->entry = entry;
159              
160 17561 100         if (entries->list)
161 15219           entries->list->last->next = list_head;
162             else
163 2342           entries->list = list_head;
164 17561           entries->list->last = list_head;
165              
166 17561           return 0;
167             }
168              
169 5175           int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key)
170             {
171             config_entry_map_head *entry;
172 5175 100         if ((entry = git_strmap_get(entries->map, key)) == NULL)
173 4283           return GIT_ENOTFOUND;
174 892           *out = entry->entry;
175 892           return 0;
176             }
177              
178 56           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 56 100         if ((entry = git_strmap_get(entries->map, key)) == NULL)
183 47           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 1137           static void config_iterator_free(git_config_iterator *iter)
201             {
202 1137           config_entries_iterator *it = (config_entries_iterator *) iter;
203 1137           git_config_entries_free(it->entries);
204 1137           git__free(it);
205 1137           }
206              
207 9725           static int config_iterator_next(
208             git_config_entry **entry,
209             git_config_iterator *iter)
210             {
211 9725           config_entries_iterator *it = (config_entries_iterator *) iter;
212              
213 9725 100         if (!it->head)
214 1136           return GIT_ITEROVER;
215              
216 8589           *entry = it->head->entry;
217 8589           it->head = it->head->next;
218              
219 8589           return 0;
220             }
221              
222 1137           int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries)
223             {
224             config_entries_iterator *it;
225              
226 1137           it = git__calloc(1, sizeof(config_entries_iterator));
227 1137 50         GIT_ERROR_CHECK_ALLOC(it);
228 1137           it->parent.next = config_iterator_next;
229 1137           it->parent.free = config_iterator_free;
230 1137           it->head = entries->list;
231 1137           it->entries = entries;
232              
233 1137           git_config_entries_incref(entries);
234 1137           *out = &it->parent;
235              
236 1137           return 0;
237             }