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 typedef struct config_entries_iterator
{
18 git_config_iterator parent
;
19 git_config_entries
*entries
;
20 config_entry_list
*head
;
21 } config_entries_iterator
;
23 struct git_config_entries
{
26 config_entry_list
*list
;
29 int git_config_entries_new(git_config_entries
**out
)
31 git_config_entries
*entries
;
34 entries
= git__calloc(1, sizeof(git_config_entries
));
35 GIT_ERROR_CHECK_ALLOC(entries
);
36 GIT_REFCOUNT_INC(entries
);
38 if ((error
= git_strmap_new(&entries
->map
)) < 0)
46 int git_config_entries_dup_entry(git_config_entries
*entries
, const git_config_entry
*entry
)
48 git_config_entry
*duplicated
;
51 duplicated
= git__calloc(1, sizeof(git_config_entry
));
52 GIT_ERROR_CHECK_ALLOC(duplicated
);
54 duplicated
->name
= git__strdup(entry
->name
);
55 GIT_ERROR_CHECK_ALLOC(duplicated
->name
);
58 duplicated
->value
= git__strdup(entry
->value
);
59 GIT_ERROR_CHECK_ALLOC(duplicated
->value
);
61 duplicated
->level
= entry
->level
;
62 duplicated
->include_depth
= entry
->include_depth
;
64 if ((error
= git_config_entries_append(entries
, duplicated
)) < 0)
68 if (error
&& duplicated
) {
69 git__free((char *) duplicated
->name
);
70 git__free((char *) duplicated
->value
);
71 git__free(duplicated
);
76 int git_config_entries_dup(git_config_entries
**out
, git_config_entries
*entries
)
78 git_config_entries
*result
= NULL
;
79 config_entry_list
*head
;
82 if ((error
= git_config_entries_new(&result
)) < 0)
85 for (head
= entries
->list
; head
; head
= head
->next
)
86 if ((git_config_entries_dup_entry(result
, head
->entry
)) < 0)
93 git_config_entries_free(result
);
97 void git_config_entries_incref(git_config_entries
*entries
)
99 GIT_REFCOUNT_INC(entries
);
102 static void config_entries_free(git_config_entries
*entries
)
104 config_entry_list
*list
= NULL
, *next
;
106 git_strmap_free(entries
->map
);
108 list
= entries
->list
;
109 while (list
!= NULL
) {
112 git__free((char *) list
->entry
->name
);
113 git__free((char *) list
->entry
->value
);
114 git__free(list
->entry
);
122 void git_config_entries_free(git_config_entries
*entries
)
125 GIT_REFCOUNT_DEC(entries
, config_entries_free
);
128 int git_config_entries_append(git_config_entries
*entries
, git_config_entry
*entry
)
130 config_entry_list
*existing
, *head
;
132 head
= git__calloc(1, sizeof(config_entry_list
));
133 GIT_ERROR_CHECK_ALLOC(head
);
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.
142 if ((existing
= git_strmap_get(entries
->map
, entry
->name
)) != NULL
) {
143 git__free((char *) entry
->name
);
144 entry
->name
= existing
->entry
->name
;
150 entries
->list
->last
->next
= head
;
152 entries
->list
= head
;
153 entries
->list
->last
= head
;
155 if (git_strmap_set(entries
->map
, entry
->name
, head
) < 0)
161 int git_config_entries_get(git_config_entry
**out
, git_config_entries
*entries
, const char *key
)
163 config_entry_list
*entry
;
164 if ((entry
= git_strmap_get(entries
->map
, key
)) == NULL
)
165 return GIT_ENOTFOUND
;
170 int git_config_entries_get_unique(git_config_entry
**out
, git_config_entries
*entries
, const char *key
)
172 config_entry_list
*entry
;
174 if ((entry
= git_strmap_get(entries
->map
, key
)) == NULL
)
175 return GIT_ENOTFOUND
;
178 git_error_set(GIT_ERROR_CONFIG
, "entry is not unique due to being a multivar");
182 if (entry
->entry
->include_depth
) {
183 git_error_set(GIT_ERROR_CONFIG
, "entry is not unique due to being included");
192 static void config_iterator_free(git_config_iterator
*iter
)
194 config_entries_iterator
*it
= (config_entries_iterator
*) iter
;
195 git_config_entries_free(it
->entries
);
199 static int config_iterator_next(
200 git_config_entry
**entry
,
201 git_config_iterator
*iter
)
203 config_entries_iterator
*it
= (config_entries_iterator
*) iter
;
208 *entry
= it
->head
->entry
;
209 it
->head
= it
->head
->next
;
214 int git_config_entries_iterator_new(git_config_iterator
**out
, git_config_entries
*entries
)
216 config_entries_iterator
*it
;
218 it
= git__calloc(1, sizeof(config_entries_iterator
));
219 GIT_ERROR_CHECK_ALLOC(it
);
220 it
->parent
.next
= config_iterator_next
;
221 it
->parent
.free
= config_iterator_free
;
222 it
->head
= entries
->list
;
223 it
->entries
= entries
;
225 git_config_entries_incref(entries
);