File Coverage

deps/libgit2/src/config_entries.c
Criterion Covered Total %
statement 98 110 89.0
branch 36 54 66.6
condition n/a
subroutine n/a
pod n/a
total 134 164 81.7


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             bool first;
15             } config_entry_list;
16              
17             typedef struct config_entries_iterator {
18             git_config_iterator parent;
19             git_config_entries *entries;
20             config_entry_list *head;
21             } config_entries_iterator;
22              
23             struct git_config_entries {
24             git_refcount rc;
25             git_strmap *map;
26             config_entry_list *list;
27             };
28              
29 2200           int git_config_entries_new(git_config_entries **out)
30             {
31             git_config_entries *entries;
32             int error;
33              
34 2200           entries = git__calloc(1, sizeof(git_config_entries));
35 2200 50         GIT_ERROR_CHECK_ALLOC(entries);
36 2200           GIT_REFCOUNT_INC(entries);
37              
38 2200 50         if ((error = git_strmap_new(&entries->map)) < 0)
39 0           git__free(entries);
40             else
41 2200           *out = entries;
42              
43 2200           return error;
44             }
45              
46 14124           int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry)
47             {
48             git_config_entry *duplicated;
49             int error;
50              
51 14124           duplicated = git__calloc(1, sizeof(git_config_entry));
52 14124 50         GIT_ERROR_CHECK_ALLOC(duplicated);
53              
54 14124           duplicated->name = git__strdup(entry->name);
55 14124 50         GIT_ERROR_CHECK_ALLOC(duplicated->name);
56              
57 14124 50         if (entry->value) {
58 14124           duplicated->value = git__strdup(entry->value);
59 14124 50         GIT_ERROR_CHECK_ALLOC(duplicated->value);
60             }
61 14124           duplicated->level = entry->level;
62 14124           duplicated->include_depth = entry->include_depth;
63              
64 14124 50         if ((error = git_config_entries_append(entries, duplicated)) < 0)
65 0           goto out;
66              
67             out:
68 14124 50         if (error && duplicated) {
    0          
69 0           git__free((char *) duplicated->name);
70 0           git__free((char *) duplicated->value);
71 0           git__free(duplicated);
72             }
73 14124           return error;
74             }
75              
76 1070           int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
77             {
78 1070           git_config_entries *result = NULL;
79             config_entry_list *head;
80             int error;
81              
82 1070 50         if ((error = git_config_entries_new(&result)) < 0)
83 0           goto out;
84              
85 8564 100         for (head = entries->list; head; head = head->next)
86 7494 50         if ((git_config_entries_dup_entry(result, head->entry)) < 0)
87 0           goto out;
88              
89 1070           *out = result;
90 1070           result = NULL;
91              
92             out:
93 1070           git_config_entries_free(result);
94 1070           return error;
95             }
96              
97 7134           void git_config_entries_incref(git_config_entries *entries)
98             {
99 7134           GIT_REFCOUNT_INC(entries);
100 7134           }
101              
102 2200           static void config_entries_free(git_config_entries *entries)
103             {
104 2200           config_entry_list *list = NULL, *next;
105              
106 2200           git_strmap_free(entries->map);
107              
108 2200           list = entries->list;
109 17540 100         while (list != NULL) {
110 15340           next = list->next;
111 15340 100         if (list->first)
112 14483           git__free((char *) list->entry->name);
113 15340           git__free((char *) list->entry->value);
114 15340           git__free(list->entry);
115 15340           git__free(list);
116 15340           list = next;
117             }
118              
119 2200           git__free(entries);
120 2200           }
121              
122 10472           void git_config_entries_free(git_config_entries *entries)
123             {
124 10472 100         if (entries)
125 9334 100         GIT_REFCOUNT_DEC(entries, config_entries_free);
    50          
126 10472           }
127              
128 15340           int git_config_entries_append(git_config_entries *entries, git_config_entry *entry)
129             {
130             config_entry_list *existing, *head;
131              
132 15340           head = git__calloc(1, sizeof(config_entry_list));
133 15340 50         GIT_ERROR_CHECK_ALLOC(head);
134 15340           head->entry = entry;
135              
136             /*
137             * This is a micro-optimization for configuration files
138             * with a lot of same keys. As for multivars the entry's
139             * key will be the same for all entries, we can just free
140             * all except the first entry's name and just re-use it.
141             */
142 15340 100         if ((existing = git_strmap_get(entries->map, entry->name)) != NULL) {
143 857           git__free((char *) entry->name);
144 857           entry->name = existing->entry->name;
145             } else {
146 14483           head->first = 1;
147             }
148              
149 15340 100         if (entries->list)
150 14210           entries->list->last->next = head;
151             else
152 1130           entries->list = head;
153 15340           entries->list->last = head;
154              
155 15340 50         if (git_strmap_set(entries->map, entry->name, head) < 0)
156 0           return -1;
157              
158 15340           return 0;
159             }
160              
161 5015           int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key)
162             {
163             config_entry_list *entry;
164 5015 100         if ((entry = git_strmap_get(entries->map, key)) == NULL)
165 4160           return GIT_ENOTFOUND;
166 855           *out = entry->entry;
167 855           return 0;
168             }
169              
170 55           int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key)
171             {
172             config_entry_list *entry;
173              
174 55 100         if ((entry = git_strmap_get(entries->map, key)) == NULL)
175 46           return GIT_ENOTFOUND;
176              
177 9 50         if (!entry->first) {
178 0           git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being a multivar");
179 0           return -1;
180             }
181              
182 9 50         if (entry->entry->include_depth) {
183 0           git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included");
184 0           return -1;
185             }
186              
187 9           *out = entry->entry;
188              
189 9           return 0;
190             }
191              
192 1070           static void config_iterator_free(git_config_iterator *iter)
193             {
194 1070           config_entries_iterator *it = (config_entries_iterator *) iter;
195 1070           git_config_entries_free(it->entries);
196 1070           git__free(it);
197 1070           }
198              
199 8553           static int config_iterator_next(
200             git_config_entry **entry,
201             git_config_iterator *iter)
202             {
203 8553           config_entries_iterator *it = (config_entries_iterator *) iter;
204              
205 8553 100         if (!it->head)
206 1069           return GIT_ITEROVER;
207              
208 7484           *entry = it->head->entry;
209 7484           it->head = it->head->next;
210              
211 7484           return 0;
212             }
213              
214 1070           int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries)
215             {
216             config_entries_iterator *it;
217              
218 1070           it = git__calloc(1, sizeof(config_entries_iterator));
219 1070 50         GIT_ERROR_CHECK_ALLOC(it);
220 1070           it->parent.next = config_iterator_next;
221 1070           it->parent.free = config_iterator_free;
222 1070           it->head = entries->list;
223 1070           it->entries = entries;
224              
225 1070           git_config_entries_incref(entries);
226 1070           *out = &it->parent;
227              
228 1070           return 0;
229             }