]> git.proxmox.com Git - libgit2.git/blame - src/config_entries.c
Update d/ch for 0.28.4+dfsg.1-4 release
[libgit2.git] / src / config_entries.c
CommitLineData
ac3d33df
JK
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
10typedef 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
16typedef struct config_entries_iterator {
17 git_config_iterator parent;
18 git_config_entries *entries;
19 config_entry_list *head;
20} config_entries_iterator;
21
22struct git_config_entries {
23 git_refcount rc;
24 git_strmap *map;
25 config_entry_list *list;
26};
27
28static void config_entry_list_free(config_entry_list *list)
29{
30 config_entry_list *next;
31
32 while (list != NULL) {
33 next = list->next;
34
35 git__free((char*) list->entry->name);
36 git__free((char *) list->entry->value);
37 git__free(list->entry);
38 git__free(list);
39
40 list = next;
41 };
42}
43
44static void config_entry_list_append(config_entry_list **list, config_entry_list *entry)
45{
46 if (*list)
47 (*list)->last->next = entry;
48 else
49 *list = entry;
50 (*list)->last = entry;
51}
52
53int git_config_entries_new(git_config_entries **out)
54{
55 git_config_entries *entries;
56 int error;
57
58 entries = git__calloc(1, sizeof(git_config_entries));
59 GIT_ERROR_CHECK_ALLOC(entries);
60 GIT_REFCOUNT_INC(entries);
61
62 if ((error = git_strmap_alloc(&entries->map)) < 0)
63 git__free(entries);
64 else
65 *out = entries;
66
67 return error;
68}
69
70int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
71{
72 git_config_entries *result = NULL;
73 config_entry_list *head;
74 int error;
75
76 if ((error = git_config_entries_new(&result)) < 0)
77 goto out;
78
79 for (head = entries->list; head; head = head->next) {
80 git_config_entry *dup;
81
82 dup = git__calloc(1, sizeof(git_config_entry));
83 dup->name = git__strdup(head->entry->name);
84 GIT_ERROR_CHECK_ALLOC(dup->name);
85 if (head->entry->value) {
86 dup->value = git__strdup(head->entry->value);
87 GIT_ERROR_CHECK_ALLOC(dup->value);
88 }
89 dup->level = head->entry->level;
90 dup->include_depth = head->entry->include_depth;
91
92 if ((error = git_config_entries_append(result, dup)) < 0)
93 goto out;
94 }
95
96 *out = result;
97 result = NULL;
98
99out:
100 git_config_entries_free(result);
101 return error;
102}
103
104void git_config_entries_incref(git_config_entries *entries)
105{
106 GIT_REFCOUNT_INC(entries);
107}
108
109static void config_entries_free(git_config_entries *entries)
110{
111 config_entry_list *list = NULL, *next;
112
113 git_strmap_foreach_value(entries->map, list, config_entry_list_free(list));
114 git_strmap_free(entries->map);
115
116 list = entries->list;
117 while (list != NULL) {
118 next = list->next;
119 git__free(list);
120 list = next;
121 }
122
123 git__free(entries);
124}
125
126void git_config_entries_free(git_config_entries *entries)
127{
128 if (entries)
129 GIT_REFCOUNT_DEC(entries, config_entries_free);
130}
131
132int git_config_entries_append(git_config_entries *entries, git_config_entry *entry)
133{
134 config_entry_list *existing, *var;
135 int error = 0;
136 size_t pos;
137
138 var = git__calloc(1, sizeof(config_entry_list));
139 GIT_ERROR_CHECK_ALLOC(var);
140 var->entry = entry;
141
142 pos = git_strmap_lookup_index(entries->map, entry->name);
143 if (!git_strmap_valid_index(entries->map, pos)) {
144 /*
145 * We only ever inspect `last` from the first config
146 * entry in a multivar. In case where this new entry is
147 * the first one in the entry map, it will also be the
148 * last one at the time of adding it, which is
149 * why we set `last` here to itself. Otherwise we
150 * do not have to set `last` and leave it set to
151 * `NULL`.
152 */
153 var->last = var;
154
155 git_strmap_insert(entries->map, entry->name, var, &error);
156
157 if (error > 0)
158 error = 0;
159 } else {
160 existing = git_strmap_value_at(entries->map, pos);
161 config_entry_list_append(&existing, var);
162 }
163
164 var = git__calloc(1, sizeof(config_entry_list));
165 GIT_ERROR_CHECK_ALLOC(var);
166 var->entry = entry;
167 config_entry_list_append(&entries->list, var);
168
169 return error;
170}
171
172int config_entry_get(config_entry_list **out, git_config_entries *entries, const char *key)
173{
174 size_t pos;
175
176 pos = git_strmap_lookup_index(entries->map, key);
177
178 /* no error message; the config system will write one */
179 if (!git_strmap_valid_index(entries->map, pos))
180 return GIT_ENOTFOUND;
181
182 *out = git_strmap_value_at(entries->map, pos);
183
184 return 0;
185}
186
187int git_config_entries_get(git_config_entry **out, git_config_entries *entries, const char *key)
188{
189 config_entry_list *entry;
190 int error;
191
192 if ((error = config_entry_get(&entry, entries, key)) < 0)
193 return error;
194 *out = entry->last->entry;
195
196 return 0;
197}
198
199int git_config_entries_get_unique(git_config_entry **out, git_config_entries *entries, const char *key)
200{
201 config_entry_list *entry;
202 int error;
203
204 if ((error = config_entry_get(&entry, entries, key)) < 0)
205 return error;
206
207 if (entry->next != NULL) {
208 git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being a multivar");
209 return -1;
210 }
211
212 if (entry->entry->include_depth) {
213 git_error_set(GIT_ERROR_CONFIG, "entry is not unique due to being included");
214 return -1;
215 }
216
217 *out = entry->entry;
218
219 return 0;
220}
221
222void config_iterator_free(git_config_iterator *iter)
223{
224 config_entries_iterator *it = (config_entries_iterator *) iter;
225 git_config_entries_free(it->entries);
226 git__free(it);
227}
228
229int config_iterator_next(
230 git_config_entry **entry,
231 git_config_iterator *iter)
232{
233 config_entries_iterator *it = (config_entries_iterator *) iter;
234
235 if (!it->head)
236 return GIT_ITEROVER;
237
238 *entry = it->head->entry;
239 it->head = it->head->next;
240
241 return 0;
242}
243
244int git_config_entries_iterator_new(git_config_iterator **out, git_config_entries *entries)
245{
246 config_entries_iterator *it;
247
248 it = git__calloc(1, sizeof(config_entries_iterator));
249 GIT_ERROR_CHECK_ALLOC(it);
250 it->parent.next = config_iterator_next;
251 it->parent.free = config_iterator_free;
252 it->head = entries->list;
253 it->entries = entries;
254
255 git_config_entries_incref(entries);
256 *out = &it->parent;
257
258 return 0;
259}