2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
8 #include "config_entries.h"
10 typedef struct config_entry_list
{
11 struct config_entry_list
*next
;
12 struct config_entry_list
*last
;
13 git_config_entry
*entry
;
17 git_config_entry
*entry
;
19 } config_entry_map_head
;
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
;
27 struct git_config_entries
{
30 config_entry_list
*list
;
33 int git_config_entries_new(git_config_entries
**out
)
35 git_config_entries
*entries
;
38 entries
= git__calloc(1, sizeof(git_config_entries
));
39 GIT_ERROR_CHECK_ALLOC(entries
);
40 GIT_REFCOUNT_INC(entries
);
42 if ((error
= git_strmap_new(&entries
->map
)) < 0)
50 int git_config_entries_dup_entry(git_config_entries
*entries
, const git_config_entry
*entry
)
52 git_config_entry
*duplicated
;
55 duplicated
= git__calloc(1, sizeof(git_config_entry
));
56 GIT_ERROR_CHECK_ALLOC(duplicated
);
58 duplicated
->name
= git__strdup(entry
->name
);
59 GIT_ERROR_CHECK_ALLOC(duplicated
->name
);
62 duplicated
->value
= git__strdup(entry
->value
);
63 GIT_ERROR_CHECK_ALLOC(duplicated
->value
);
65 duplicated
->level
= entry
->level
;
66 duplicated
->include_depth
= entry
->include_depth
;
68 if ((error
= git_config_entries_append(entries
, duplicated
)) < 0)
72 if (error
&& duplicated
) {
73 git__free((char *) duplicated
->name
);
74 git__free((char *) duplicated
->value
);
75 git__free(duplicated
);
80 int git_config_entries_dup(git_config_entries
**out
, git_config_entries
*entries
)
82 git_config_entries
*result
= NULL
;
83 config_entry_list
*head
;
86 if ((error
= git_config_entries_new(&result
)) < 0)
89 for (head
= entries
->list
; head
; head
= head
->next
)
90 if ((git_config_entries_dup_entry(result
, head
->entry
)) < 0)
97 git_config_entries_free(result
);
101 void git_config_entries_incref(git_config_entries
*entries
)
103 GIT_REFCOUNT_INC(entries
);
106 static void config_entries_free(git_config_entries
*entries
)
108 config_entry_list
*list
= NULL
, *next
;
109 config_entry_map_head
*head
;
111 git_strmap_foreach_value(entries
->map
, head
,
112 git__free((char *) head
->entry
->name
); git__free(head
)
114 git_strmap_free(entries
->map
);
116 list
= entries
->list
;
117 while (list
!= NULL
) {
119 git__free((char *) list
->entry
->value
);
120 git__free(list
->entry
);
128 void git_config_entries_free(git_config_entries
*entries
)
131 GIT_REFCOUNT_DEC(entries
, config_entries_free
);
134 int git_config_entries_append(git_config_entries
*entries
, git_config_entry
*entry
)
136 config_entry_list
*list_head
;
137 config_entry_map_head
*map_head
;
139 if ((map_head
= git_strmap_get(entries
->map
, entry
->name
)) != NULL
) {
140 map_head
->multivar
= true;
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.
147 git__free((char *) entry
->name
);
148 entry
->name
= map_head
->entry
->name
;
150 map_head
= git__calloc(1, sizeof(*map_head
));
151 if ((git_strmap_set(entries
->map
, entry
->name
, map_head
)) < 0)
154 map_head
->entry
= entry
;
156 list_head
= git__calloc(1, sizeof(config_entry_list
));
157 GIT_ERROR_CHECK_ALLOC(list_head
);
158 list_head
->entry
= entry
;
161 entries
->list
->last
->next
= list_head
;
163 entries
->list
= list_head
;
164 entries
->list
->last
= list_head
;
169 int git_config_entries_get(git_config_entry
**out
, git_config_entries
*entries
, const char *key
)
171 config_entry_map_head
*entry
;
172 if ((entry
= git_strmap_get(entries
->map
, key
)) == NULL
)
173 return GIT_ENOTFOUND
;
178 int git_config_entries_get_unique(git_config_entry
**out
, git_config_entries
*entries
, const char *key
)
180 config_entry_map_head
*entry
;
182 if ((entry
= git_strmap_get(entries
->map
, key
)) == NULL
)
183 return GIT_ENOTFOUND
;
185 if (entry
->multivar
) {
186 git_error_set(GIT_ERROR_CONFIG
, "entry is not unique due to being a multivar");
190 if (entry
->entry
->include_depth
) {
191 git_error_set(GIT_ERROR_CONFIG
, "entry is not unique due to being included");
200 static void config_iterator_free(git_config_iterator
*iter
)
202 config_entries_iterator
*it
= (config_entries_iterator
*) iter
;
203 git_config_entries_free(it
->entries
);
207 static int config_iterator_next(
208 git_config_entry
**entry
,
209 git_config_iterator
*iter
)
211 config_entries_iterator
*it
= (config_entries_iterator
*) iter
;
216 *entry
= it
->head
->entry
;
217 it
->head
= it
->head
->next
;
222 int git_config_entries_iterator_new(git_config_iterator
**out
, git_config_entries
*entries
)
224 config_entries_iterator
*it
;
226 it
= git__calloc(1, sizeof(config_entries_iterator
));
227 GIT_ERROR_CHECK_ALLOC(it
);
228 it
->parent
.next
= config_iterator_next
;
229 it
->parent
.free
= config_iterator_free
;
230 it
->head
= entries
->list
;
231 it
->entries
= entries
;
233 git_config_entries_incref(entries
);