source src/config.c
Line | Flow | Count | Block(s) | Source |
---|---|---|---|---|
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.h" | ||
9 | - | |||
10 | - | #include "git2/config.h" | ||
11 | - | #include "git2/sys/config.h" | ||
12 | - | |||
13 | - | #include "buf_text.h" | ||
14 | - | #include "config_backend.h" | ||
15 | - | #include "regexp.h" | ||
16 | - | #include "sysdir.h" | ||
17 | - | #include "transaction.h" | ||
18 | - | #include "vector.h" | ||
19 | - | #if GIT_WIN32 | ||
20 | - | # include <windows.h> | ||
21 | - | #endif | ||
22 | - | |||
23 | - | #include <ctype.h> | ||
24 | - | |||
25 | 98370 | 2 | void git_config_entry_free(git_config_entry *entry) | |
26 | - | { | ||
27 | 98370 | 2 | if (!entry) | |
28 | 98370 | 3,5 | return; | |
29 | - | |||
30 | 22433 | 4 | entry->free(entry); | |
31 | - | } | ||
32 | - | |||
33 | - | typedef struct { | ||
34 | - | git_refcount rc; | ||
35 | - | |||
36 | - | git_config_backend *backend; | ||
37 | - | git_config_level_t level; | ||
38 | - | } backend_internal; | ||
39 | - | |||
40 | 63255 | 2 | static void backend_internal_free(backend_internal *internal) | |
41 | - | { | ||
42 | - | git_config_backend *backend; | ||
43 | - | |||
44 | 63255 | 2 | backend = internal->backend; | |
45 | 63255 | 2 | backend->free(backend); | |
46 | 63254 | 3 | git__free(internal); | |
47 | 63254 | 4 | } | |
48 | - | |||
49 | 24942 | 2 | static void config_free(git_config *cfg) | |
50 | - | { | ||
51 | - | size_t i; | ||
52 | - | backend_internal *internal; | ||
53 | - | |||
54 | 90626 | 2,8,9 | for (i = 0; i < cfg->backends.length; ++i) { | |
55 | 65684 | 3 | internal = git_vector_get(&cfg->backends, i); | |
56 | 65686 | 4-7 | GIT_REFCOUNT_DEC(internal, backend_internal_free); | |
57 | - | } | ||
58 | - | |||
59 | 24942 | 10 | git_vector_free(&cfg->backends); | |
60 | - | |||
61 | 24943 | 11 | git__memzero(cfg, sizeof(*cfg)); | |
62 | 24943 | 12 | git__free(cfg); | |
63 | 24943 | 13 | } | |
64 | - | |||
65 | 31130 | 2 | void git_config_free(git_config *cfg) | |
66 | - | { | ||
67 | 31130 | 2 | if (cfg == NULL) | |
68 | 31130 | 3,8 | return; | |
69 | - | |||
70 | 28070 | 4-7 | GIT_REFCOUNT_DEC(cfg, config_free); | |
71 | - | } | ||
72 | - | |||
73 | 48556 | 2 | static int config_backend_cmp(const void *a, const void *b) | |
74 | - | { | ||
75 | 48556 | 2 | const backend_internal *bk_a = (const backend_internal *)(a); | |
76 | 48556 | 2 | const backend_internal *bk_b = (const backend_internal *)(b); | |
77 | - | |||
78 | 48556 | 2 | return bk_b->level - bk_a->level; | |
79 | - | } | ||
80 | - | |||
81 | 24939 | 2 | int git_config_new(git_config **out) | |
82 | - | { | ||
83 | - | git_config *cfg; | ||
84 | - | |||
85 | 24939 | 2 | cfg = git__malloc(sizeof(git_config)); | |
86 | 24940 | 3,4 | GIT_ERROR_CHECK_ALLOC(cfg); | |
87 | - | |||
88 | 24940 | 5 | memset(cfg, 0x0, sizeof(git_config)); | |
89 | - | |||
90 | 24943 | 5,6 | if (git_vector_init(&cfg->backends, 3, config_backend_cmp) < 0) { | |
91 | ##### | 7 | git__free(cfg); | |
92 | ##### | 8 | return -1; | |
93 | - | } | ||
94 | - | |||
95 | 24943 | 9 | *out = cfg; | |
96 | 24943 | 9 | GIT_REFCOUNT_INC(cfg); | |
97 | 24941 | 10 | return 0; | |
98 | - | } | ||
99 | - | |||
100 | 15276 | 2 | int git_config_add_file_ondisk( | |
101 | - | git_config *cfg, | ||
102 | - | const char *path, | ||
103 | - | git_config_level_t level, | ||
104 | - | const git_repository *repo, | ||
105 | - | int force) | ||
106 | - | { | ||
107 | 15276 | 2 | git_config_backend *file = NULL; | |
108 | - | struct stat st; | ||
109 | - | int res; | ||
110 | - | |||
111 | 15276 | 2-4 | assert(cfg && path); | |
112 | - | |||
113 | 15276 | 5 | res = p_stat(path, &st); | |
114 | 15273 | 6-10 | if (res < 0 && errno != ENOENT && errno != ENOTDIR) { | |
115 | ##### | 11 | git_error_set(GIT_ERROR_CONFIG, "failed to stat '%s'", path); | |
116 | ##### | 12 | return -1; | |
117 | - | } | ||
118 | - | |||
119 | 15274 | 13,14 | if (git_config_backend_from_file(&file, path) < 0) | |
120 | ##### | 15 | return -1; | |
121 | - | |||
122 | 15275 | 16,17 | if ((res = git_config_add_backend(cfg, file, level, repo, force)) < 0) { | |
123 | - | /* | ||
124 | - | * free manually; the file is not owned by the config | ||
125 | - | * instance yet and will not be freed on cleanup | ||
126 | - | */ | ||
127 | 18 | 18 | file->free(file); | |
128 | 18 | 19 | return res; | |
129 | - | } | ||
130 | - | |||
131 | 15257 | 20 | return 0; | |
132 | - | } | ||
133 | - | |||
134 | 1572 | 2 | int git_config_open_ondisk(git_config **out, const char *path) | |
135 | - | { | ||
136 | - | int error; | ||
137 | - | git_config *config; | ||
138 | - | |||
139 | 1572 | 2 | *out = NULL; | |
140 | - | |||
141 | 1572 | 2,3 | if (git_config_new(&config) < 0) | |
142 | ##### | 4 | return -1; | |
143 | - | |||
144 | 1572 | 5,6 | if ((error = git_config_add_file_ondisk(config, path, GIT_CONFIG_LEVEL_LOCAL, NULL, 0)) < 0) | |
145 | 17 | 7 | git_config_free(config); | |
146 | - | else | ||
147 | 1555 | 8 | *out = config; | |
148 | - | |||
149 | 1572 | 9 | return error; | |
150 | - | } | ||
151 | - | |||
152 | 16823 | 2 | int git_config_snapshot(git_config **out, git_config *in) | |
153 | - | { | ||
154 | 16823 | 2 | int error = 0; | |
155 | - | size_t i; | ||
156 | - | backend_internal *internal; | ||
157 | - | git_config *config; | ||
158 | - | |||
159 | 16823 | 2 | *out = NULL; | |
160 | - | |||
161 | 16823 | 2,3 | if (git_config_new(&config) < 0) | |
162 | ##### | 4 | return -1; | |
163 | - | |||
164 | 64808 | 5,12,15,16 | git_vector_foreach(&in->backends, i, internal) { | |
165 | - | git_config_backend *b; | ||
166 | - | |||
167 | 47985 | 6,7 | if ((error = internal->backend->snapshot(&b, internal->backend)) < 0) | |
168 | ##### | 8,14 | break; | |
169 | - | |||
170 | 47989 | 9,10 | if ((error = git_config_add_backend(config, b, internal->level, NULL, 0)) < 0) { | |
171 | ##### | 11 | b->free(b); | |
172 | ##### | 13 | break; | |
173 | - | } | ||
174 | - | } | ||
175 | - | |||
176 | 16823 | 17 | if (error < 0) | |
177 | ##### | 18 | git_config_free(config); | |
178 | - | else | ||
179 | 16823 | 19 | *out = config; | |
180 | - | |||
181 | 16823 | 20 | return error; | |
182 | - | } | ||
183 | - | |||
184 | 2439 | 2 | static int find_backend_by_level( | |
185 | - | backend_internal **out, | ||
186 | - | const git_config *cfg, | ||
187 | - | git_config_level_t level) | ||
188 | - | { | ||
189 | 2439 | 2 | int pos = -1; | |
190 | - | backend_internal *internal; | ||
191 | - | size_t i; | ||
192 | - | |||
193 | - | /* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config backend | ||
194 | - | * which has the highest level. As config backends are stored in a vector | ||
195 | - | * sorted by decreasing order of level, getting the backend at position 0 | ||
196 | - | * will do the job. | ||
197 | - | */ | ||
198 | 2439 | 2 | if (level == GIT_CONFIG_HIGHEST_LEVEL) { | |
199 | ##### | 3 | pos = 0; | |
200 | - | } else { | ||
201 | 10557 | 4,7-9 | git_vector_foreach(&cfg->backends, i, internal) { | |
202 | 8118 | 5 | if (internal->level == level) | |
203 | 2434 | 6 | pos = (int)i; | |
204 | - | } | ||
205 | - | } | ||
206 | - | |||
207 | 2439 | 10 | if (pos == -1) { | |
208 | 5 | 11 | git_error_set(GIT_ERROR_CONFIG, | |
209 | - | "no configuration exists for the given level '%i'", (int)level); | ||
210 | 5 | 12 | return GIT_ENOTFOUND; | |
211 | - | } | ||
212 | - | |||
213 | 2434 | 13 | *out = git_vector_get(&cfg->backends, pos); | |
214 | - | |||
215 | 2434 | 14 | return 0; | |
216 | - | } | ||
217 | - | |||
218 | 1 | 2 | static int duplicate_level(void **old_raw, void *new_raw) | |
219 | - | { | ||
220 | 1 | 2 | backend_internal **old = (backend_internal **)old_raw; | |
221 | - | |||
222 | - | GIT_UNUSED(new_raw); | ||
223 | - | |||
224 | 1 | 2 | git_error_set(GIT_ERROR_CONFIG, "there already exists a configuration for the given level (%i)", (int)(*old)->level); | |
225 | 1 | 3 | return GIT_EEXISTS; | |
226 | - | } | ||
227 | - | |||
228 | 2442 | 2 | static void try_remove_existing_backend( | |
229 | - | git_config *cfg, | ||
230 | - | git_config_level_t level) | ||
231 | - | { | ||
232 | 2442 | 2 | int pos = -1; | |
233 | - | backend_internal *internal; | ||
234 | - | size_t i; | ||
235 | - | |||
236 | 2461 | 2,5-7 | git_vector_foreach(&cfg->backends, i, internal) { | |
237 | 19 | 3 | if (internal->level == level) | |
238 | 4 | 4 | pos = (int)i; | |
239 | - | } | ||
240 | - | |||
241 | 2442 | 8 | if (pos == -1) | |
242 | 2438 | 9 | return; | |
243 | - | |||
244 | 4 | 10 | internal = git_vector_get(&cfg->backends, pos); | |
245 | - | |||
246 | 4 | 11,12 | if (git_vector_remove(&cfg->backends, pos) < 0) | |
247 | ##### | 13 | return; | |
248 | - | |||
249 | 4 | 14 | GIT_REFCOUNT_DEC(internal, backend_internal_free); | |
250 | - | } | ||
251 | - | |||
252 | 65683 | 2 | static int git_config__add_internal( | |
253 | - | git_config *cfg, | ||
254 | - | backend_internal *internal, | ||
255 | - | git_config_level_t level, | ||
256 | - | int force) | ||
257 | - | { | ||
258 | - | int result; | ||
259 | - | |||
260 | - | /* delete existing config backend for level if it exists */ | ||
261 | 65683 | 2 | if (force) | |
262 | 2442 | 3 | try_remove_existing_backend(cfg, level); | |
263 | - | |||
264 | 65683 | 4,5 | if ((result = git_vector_insert_sorted(&cfg->backends, | |
265 | - | internal, &duplicate_level)) < 0) | ||
266 | 1 | 6 | return result; | |
267 | - | |||
268 | 65671 | 7 | git_vector_sort(&cfg->backends); | |
269 | 65670 | 8 | internal->backend->cfg = cfg; | |
270 | - | |||
271 | 65670 | 8 | GIT_REFCOUNT_INC(internal); | |
272 | - | |||
273 | 65687 | 9 | return 0; | |
274 | - | } | ||
275 | - | |||
276 | 2 | 2 | int git_config_open_global(git_config **cfg_out, git_config *cfg) | |
277 | - | { | ||
278 | 2 | 2,3 | if (!git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_XDG)) | |
279 | 1 | 4 | return 0; | |
280 | - | |||
281 | 1 | 5 | return git_config_open_level(cfg_out, cfg, GIT_CONFIG_LEVEL_GLOBAL); | |
282 | - | } | ||
283 | - | |||
284 | 2439 | 2 | int git_config_open_level( | |
285 | - | git_config **cfg_out, | ||
286 | - | const git_config *cfg_parent, | ||
287 | - | git_config_level_t level) | ||
288 | - | { | ||
289 | - | git_config *cfg; | ||
290 | - | backend_internal *internal; | ||
291 | - | int res; | ||
292 | - | |||
293 | 2439 | 2,3 | if ((res = find_backend_by_level(&internal, cfg_parent, level)) < 0) | |
294 | 5 | 4 | return res; | |
295 | - | |||
296 | 2434 | 5,6 | if ((res = git_config_new(&cfg)) < 0) | |
297 | ##### | 7 | return res; | |
298 | - | |||
299 | 2434 | 8,9 | if ((res = git_config__add_internal(cfg, internal, level, true)) < 0) { | |
300 | ##### | 10 | git_config_free(cfg); | |
301 | ##### | 11 | return res; | |
302 | - | } | ||
303 | - | |||
304 | 2434 | 12 | *cfg_out = cfg; | |
305 | - | |||
306 | 2434 | 12 | return 0; | |
307 | - | } | ||
308 | - | |||
309 | 63262 | 2 | int git_config_add_backend( | |
310 | - | git_config *cfg, | ||
311 | - | git_config_backend *backend, | ||
312 | - | git_config_level_t level, | ||
313 | - | const git_repository *repo, | ||
314 | - | int force) | ||
315 | - | { | ||
316 | - | backend_internal *internal; | ||
317 | - | int result; | ||
318 | - | |||
319 | 63262 | 2-4 | assert(cfg && backend); | |
320 | - | |||
321 | 63261 | 5-7 | GIT_ERROR_CHECK_VERSION(backend, GIT_CONFIG_BACKEND_VERSION, "git_config_backend"); | |
322 | - | |||
323 | 63259 | 8,9 | if ((result = backend->open(backend, level, repo)) < 0) | |
324 | 17 | 10 | return result; | |
325 | - | |||
326 | 63241 | 11 | internal = git__malloc(sizeof(backend_internal)); | |
327 | 63251 | 12,13 | GIT_ERROR_CHECK_ALLOC(internal); | |
328 | - | |||
329 | 63251 | 14 | memset(internal, 0x0, sizeof(backend_internal)); | |
330 | - | |||
331 | 63251 | 14 | internal->backend = backend; | |
332 | 63251 | 14 | internal->level = level; | |
333 | - | |||
334 | 63253 | 14,15 | if ((result = git_config__add_internal(cfg, internal, level, force)) < 0) { | |
335 | 1 | 16 | git__free(internal); | |
336 | 1 | 17 | return result; | |
337 | - | } | ||
338 | - | |||
339 | 63252 | 18 | return 0; | |
340 | - | } | ||
341 | - | |||
342 | - | /* | ||
343 | - | * Loop over all the variables | ||
344 | - | */ | ||
345 | - | |||
346 | - | typedef struct { | ||
347 | - | git_config_iterator parent; | ||
348 | - | git_config_iterator *current; | ||
349 | - | const git_config *cfg; | ||
350 | - | git_regexp regex; | ||
351 | - | size_t i; | ||
352 | - | } all_iter; | ||
353 | - | |||
354 | 6671 | 2 | static int find_next_backend(size_t *out, const git_config *cfg, size_t i) | |
355 | - | { | ||
356 | - | backend_internal *internal; | ||
357 | - | |||
358 | 6671 | 2,6,8 | for (; i > 0; --i) { | |
359 | 4338 | 3 | internal = git_vector_get(&cfg->backends, i - 1); | |
360 | 4338 | 4,5 | if (!internal || !internal->backend) | |
361 | ##### | 6 | continue; | |
362 | - | |||
363 | 4338 | 7 | *out = i; | |
364 | 4338 | 7 | return 0; | |
365 | - | } | ||
366 | - | |||
367 | 2333 | 9 | return -1; | |
368 | - | } | ||
369 | - | |||
370 | 19910 | 2 | static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter) | |
371 | - | { | ||
372 | 19910 | 2 | all_iter *iter = (all_iter *) _iter; | |
373 | - | backend_internal *internal; | ||
374 | - | git_config_backend *backend; | ||
375 | - | size_t i; | ||
376 | 19910 | 2 | int error = 0; | |
377 | - | |||
378 | 19910 | 2-4 | if (iter->current != NULL && | |
379 | 17561 | 3 | (error = iter->current->next(entry, iter->current)) == 0) { | |
380 | 15092 | 5 | return 0; | |
381 | - | } | ||
382 | - | |||
383 | 4818 | 6,7 | if (error < 0 && error != GIT_ITEROVER) | |
384 | ##### | 8 | return error; | |
385 | - | |||
386 | - | do { | ||
387 | 6671 | 9,10 | if (find_next_backend(&i, iter->cfg, iter->i) < 0) | |
388 | 2333 | 11 | return GIT_ITEROVER; | |
389 | - | |||
390 | 4338 | 12 | internal = git_vector_get(&iter->cfg->backends, i - 1); | |
391 | 4338 | 13 | backend = internal->backend; | |
392 | 4338 | 13 | iter->i = i - 1; | |
393 | - | |||
394 | 4338 | 13 | if (iter->current) | |
395 | 1989 | 14 | iter->current->free(iter->current); | |
396 | - | |||
397 | 4338 | 15 | iter->current = NULL; | |
398 | 4338 | 15 | error = backend->iterator(&iter->current, backend); | |
399 | 4338 | 16 | if (error == GIT_ENOTFOUND) | |
400 | ##### | 17 | continue; | |
401 | - | |||
402 | 4338 | 18 | if (error < 0) | |
403 | ##### | 19 | return error; | |
404 | - | |||
405 | 4338 | 20 | error = iter->current->next(entry, iter->current); | |
406 | - | /* If this backend is empty, then keep going */ | ||
407 | 4338 | 21 | if (error == GIT_ITEROVER) | |
408 | 1853 | 22 | continue; | |
409 | - | |||
410 | 2485 | 23 | return error; | |
411 | - | |||
412 | 1853 | 24 | } while(1); | |
413 | - | |||
414 | - | return GIT_ITEROVER; | ||
415 | - | } | ||
416 | - | |||
417 | 2928 | 2 | static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_iter) | |
418 | - | { | ||
419 | - | int error; | ||
420 | 2928 | 2 | all_iter *iter = (all_iter *) _iter; | |
421 | - | |||
422 | - | /* | ||
423 | - | * We use the "normal" function to grab the next one across | ||
424 | - | * backends and then apply the regex | ||
425 | - | */ | ||
426 | 10759 | 2,7,8 | while ((error = all_iter_next(entry, _iter)) == 0) { | |
427 | - | /* skip non-matching keys if regexp was provided */ | ||
428 | 9320 | 3,4 | if (git_regexp_match(&iter->regex, (*entry)->name) != 0) | |
429 | 7831 | 5 | continue; | |
430 | - | |||
431 | - | /* and simply return if we like the entry's name */ | ||
432 | 1489 | 6 | return 0; | |
433 | - | } | ||
434 | - | |||
435 | 1439 | 9 | return error; | |
436 | - | } | ||
437 | - | |||
438 | 2359 | 2 | static void all_iter_free(git_config_iterator *_iter) | |
439 | - | { | ||
440 | 2359 | 2 | all_iter *iter = (all_iter *) _iter; | |
441 | - | |||
442 | 2359 | 2 | if (iter->current) | |
443 | 2349 | 3 | iter->current->free(iter->current); | |
444 | - | |||
445 | 2359 | 4 | git__free(iter); | |
446 | 2359 | 5 | } | |
447 | - | |||
448 | 1454 | 2 | static void all_iter_glob_free(git_config_iterator *_iter) | |
449 | - | { | ||
450 | 1454 | 2 | all_iter *iter = (all_iter *) _iter; | |
451 | - | |||
452 | 1454 | 2 | git_regexp_dispose(&iter->regex); | |
453 | 1454 | 3 | all_iter_free(_iter); | |
454 | 1454 | 4 | } | |
455 | - | |||
456 | 905 | 2 | int git_config_iterator_new(git_config_iterator **out, const git_config *cfg) | |
457 | - | { | ||
458 | - | all_iter *iter; | ||
459 | - | |||
460 | 905 | 2 | iter = git__calloc(1, sizeof(all_iter)); | |
461 | 905 | 3,4 | GIT_ERROR_CHECK_ALLOC(iter); | |
462 | - | |||
463 | 905 | 5 | iter->parent.free = all_iter_free; | |
464 | 905 | 5 | iter->parent.next = all_iter_next; | |
465 | - | |||
466 | 905 | 5 | iter->i = cfg->backends.length; | |
467 | 905 | 5 | iter->cfg = cfg; | |
468 | - | |||
469 | 905 | 5 | *out = (git_config_iterator *) iter; | |
470 | - | |||
471 | 905 | 5 | return 0; | |
472 | - | } | ||
473 | - | |||
474 | 1961 | 2 | int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp) | |
475 | - | { | ||
476 | - | all_iter *iter; | ||
477 | - | int result; | ||
478 | - | |||
479 | 1961 | 2 | if (regexp == NULL) | |
480 | 506 | 3 | return git_config_iterator_new(out, cfg); | |
481 | - | |||
482 | 1455 | 4 | iter = git__calloc(1, sizeof(all_iter)); | |
483 | 1455 | 5,6 | GIT_ERROR_CHECK_ALLOC(iter); | |
484 | - | |||
485 | 1455 | 7,8 | if ((result = git_regexp_compile(&iter->regex, regexp, 0)) < 0) { | |
486 | 1 | 9 | git__free(iter); | |
487 | 1 | 10 | return -1; | |
488 | - | } | ||
489 | - | |||
490 | 1454 | 11 | iter->parent.next = all_iter_glob_next; | |
491 | 1454 | 11 | iter->parent.free = all_iter_glob_free; | |
492 | 1454 | 11 | iter->i = cfg->backends.length; | |
493 | 1454 | 11 | iter->cfg = cfg; | |
494 | - | |||
495 | 1454 | 11 | *out = (git_config_iterator *) iter; | |
496 | - | |||
497 | 1454 | 11 | return 0; | |
498 | - | } | ||
499 | - | |||
500 | 506 | 2 | int git_config_foreach( | |
501 | - | const git_config *cfg, git_config_foreach_cb cb, void *payload) | ||
502 | - | { | ||
503 | 506 | 2 | return git_config_foreach_match(cfg, NULL, cb, payload); | |
504 | - | } | ||
505 | - | |||
506 | 73 | 2 | int git_config_backend_foreach_match( | |
507 | - | git_config_backend *backend, | ||
508 | - | const char *regexp, | ||
509 | - | git_config_foreach_cb cb, | ||
510 | - | void *payload) | ||
511 | - | { | ||
512 | - | git_config_entry *entry; | ||
513 | - | git_config_iterator* iter; | ||
514 | - | git_regexp regex; | ||
515 | 73 | 2 | int error = 0; | |
516 | - | |||
517 | 73 | 2-4 | assert(backend && cb); | |
518 | - | |||
519 | 73 | 5-7 | if (regexp && git_regexp_compile(®ex, regexp, 0) < 0) | |
520 | ##### | 8 | return -1; | |
521 | - | |||
522 | 73 | 9,10 | if ((error = backend->iterator(&iter, backend)) < 0) { | |
523 | ##### | 11 | iter = NULL; | |
524 | ##### | 11 | return -1; | |
525 | - | } | ||
526 | - | |||
527 | 1179 | 12,21,22 | while (!(iter->next(&entry, iter) < 0)) { | |
528 | - | /* skip non-matching keys if regexp was provided */ | ||
529 | 1106 | 13-15 | if (regexp && git_regexp_match(®ex, entry->name) != 0) | |
530 | 553 | 16 | continue; | |
531 | - | |||
532 | - | /* abort iterator on non-zero return value */ | ||
533 | 553 | 17,18 | if ((error = cb(entry, payload)) != 0) { | |
534 | ##### | 19 | git_error_set_after_callback(error); | |
535 | ##### | 20 | break; | |
536 | - | } | ||
537 | - | } | ||
538 | - | |||
539 | 73 | 23 | if (regexp != NULL) | |
540 | 72 | 24 | git_regexp_dispose(®ex); | |
541 | - | |||
542 | 73 | 25 | iter->free(iter); | |
543 | - | |||
544 | 73 | 26 | return error; | |
545 | - | } | ||
546 | - | |||
547 | 611 | 2 | int git_config_foreach_match( | |
548 | - | const git_config *cfg, | ||
549 | - | const char *regexp, | ||
550 | - | git_config_foreach_cb cb, | ||
551 | - | void *payload) | ||
552 | - | { | ||
553 | - | int error; | ||
554 | - | git_config_iterator *iter; | ||
555 | - | git_config_entry *entry; | ||
556 | - | |||
557 | 611 | 2,3 | if ((error = git_config_iterator_glob_new(&iter, cfg, regexp)) < 0) | |
558 | ##### | 4 | return error; | |
559 | - | |||
560 | 2034 | 5,10,11 | while (!(error = git_config_next(&entry, iter))) { | |
561 | 1425 | 6,7 | if ((error = cb(entry, payload)) != 0) { | |
562 | 2 | 8 | git_error_set_after_callback(error); | |
563 | 2 | 9 | break; | |
564 | - | } | ||
565 | - | } | ||
566 | - | |||
567 | 611 | 12 | git_config_iterator_free(iter); | |
568 | - | |||
569 | 611 | 13 | if (error == GIT_ITEROVER) | |
570 | 609 | 14 | error = 0; | |
571 | - | |||
572 | 611 | 15 | return error; | |
573 | - | } | ||
574 | - | |||
575 | - | /************** | ||
576 | - | * Setters | ||
577 | - | **************/ | ||
578 | - | |||
579 | - | typedef enum { | ||
580 | - | BACKEND_USE_SET, | ||
581 | - | BACKEND_USE_DELETE | ||
582 | - | } backend_use; | ||
583 | - | |||
584 | - | static const char *uses[] = { | ||
585 | - | "set", | ||
586 | - | "delete" | ||
587 | - | }; | ||
588 | - | |||
589 | 10794 | 2 | static int get_backend_for_use(git_config_backend **out, | |
590 | - | git_config *cfg, const char *name, backend_use use) | ||
591 | - | { | ||
592 | - | size_t i; | ||
593 | - | backend_internal *backend; | ||
594 | - | |||
595 | 10794 | 2 | *out = NULL; | |
596 | - | |||
597 | 10794 | 2,3 | if (git_vector_length(&cfg->backends) == 0) { | |
598 | ##### | 4 | git_error_set(GIT_ERROR_CONFIG, | |
599 | - | "cannot %s value for '%s' when no config backends exist", | ||
600 | - | uses[use], name); | ||
601 | ##### | 5 | return GIT_ENOTFOUND; | |
602 | - | } | ||
603 | - | |||
604 | 10796 | 6,9-11 | git_vector_foreach(&cfg->backends, i, backend) { | |
605 | 10795 | 7 | if (!backend->backend->readonly) { | |
606 | 10793 | 8 | *out = backend->backend; | |
607 | 10793 | 8 | return 0; | |
608 | - | } | ||
609 | - | } | ||
610 | - | |||
611 | 1 | 12 | git_error_set(GIT_ERROR_CONFIG, | |
612 | - | "cannot %s value for '%s' when all config backends are readonly", | ||
613 | - | uses[use], name); | ||
614 | 1 | 13 | return GIT_ENOTFOUND; | |
615 | - | } | ||
616 | - | |||
617 | 5689 | 2 | int git_config_delete_entry(git_config *cfg, const char *name) | |
618 | - | { | ||
619 | - | git_config_backend *backend; | ||
620 | - | |||
621 | 5689 | 2,3 | if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) | |
622 | ##### | 4 | return GIT_ENOTFOUND; | |
623 | - | |||
624 | 5689 | 5 | return backend->del(backend, name); | |
625 | - | } | ||
626 | - | |||
627 | 418 | 2 | int git_config_set_int64(git_config *cfg, const char *name, int64_t value) | |
628 | - | { | ||
629 | - | char str_value[32]; /* All numbers should fit in here */ | ||
630 | 418 | 2 | p_snprintf(str_value, sizeof(str_value), "%" PRId64, value); | |
631 | 418 | 2 | return git_config_set_string(cfg, name, str_value); | |
632 | - | } | ||
633 | - | |||
634 | 415 | 2 | int git_config_set_int32(git_config *cfg, const char *name, int32_t value) | |
635 | - | { | ||
636 | 415 | 2 | return git_config_set_int64(cfg, name, (int64_t)value); | |
637 | - | } | ||
638 | - | |||
639 | 3650 | 2 | int git_config_set_bool(git_config *cfg, const char *name, int value) | |
640 | - | { | ||
641 | 3650 | 2 | return git_config_set_string(cfg, name, value ? "true" : "false"); | |
642 | - | } | ||
643 | - | |||
644 | 4920 | 2 | int git_config_set_string(git_config *cfg, const char *name, const char *value) | |
645 | - | { | ||
646 | - | int error; | ||
647 | - | git_config_backend *backend; | ||
648 | - | |||
649 | 4920 | 2 | if (!value) { | |
650 | 1 | 3 | git_error_set(GIT_ERROR_CONFIG, "the value to set cannot be NULL"); | |
651 | 1 | 4 | return -1; | |
652 | - | } | ||
653 | - | |||
654 | 4919 | 5,6 | if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_SET) < 0) | |
655 | 1 | 7 | return GIT_ENOTFOUND; | |
656 | - | |||
657 | 4918 | 8 | error = backend->set(backend, name, value); | |
658 | - | |||
659 | 4918 | 9,10 | if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) | |
660 | 961 | 11 | git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(cfg)); | |
661 | - | |||
662 | 4918 | 12 | return error; | |
663 | - | } | ||
664 | - | |||
665 | 86 | 2 | int git_config__update_entry( | |
666 | - | git_config *config, | ||
667 | - | const char *key, | ||
668 | - | const char *value, | ||
669 | - | bool overwrite_existing, | ||
670 | - | bool only_if_existing) | ||
671 | - | { | ||
672 | 86 | 2 | int error = 0; | |
673 | 86 | 2 | git_config_entry *ce = NULL; | |
674 | - | |||
675 | 86 | 2,3 | if ((error = git_config__lookup_entry(&ce, config, key, false)) < 0) | |
676 | ##### | 4 | return error; | |
677 | - | |||
678 | 86 | 5,6 | if (!ce && only_if_existing) /* entry doesn't exist */ | |
679 | 4 | 7 | return 0; | |
680 | 82 | 8,9 | if (ce && !overwrite_existing) /* entry would be overwritten */ | |
681 | ##### | 10 | return 0; | |
682 | 82 | 11-14 | if (value && ce && ce->value && !strcmp(ce->value, value)) /* no change */ | |
683 | ##### | 15 | return 0; | |
684 | 82 | 16-18 | if (!value && (!ce || !ce->value)) /* asked to delete absent entry */ | |
685 | 33 | 19 | return 0; | |
686 | - | |||
687 | 49 | 20 | if (!value) | |
688 | ##### | 21 | error = git_config_delete_entry(config, key); | |
689 | - | else | ||
690 | 49 | 22 | error = git_config_set_string(config, key, value); | |
691 | - | |||
692 | 49 | 23 | git_config_entry_free(ce); | |
693 | 49 | 24 | return error; | |
694 | - | } | ||
695 | - | |||
696 | - | /*********** | ||
697 | - | * Getters | ||
698 | - | ***********/ | ||
699 | - | |||
700 | 9645 | 2 | static int config_error_notfound(const char *name) | |
701 | - | { | ||
702 | 9645 | 2 | git_error_set(GIT_ERROR_CONFIG, "config value '%s' was not found", name); | |
703 | 9645 | 3 | return GIT_ENOTFOUND; | |
704 | - | } | ||
705 | - | |||
706 | - | enum { | ||
707 | - | GET_ALL_ERRORS = 0, | ||
708 | - | GET_NO_MISSING = 1, | ||
709 | - | GET_NO_ERRORS = 2 | ||
710 | - | }; | ||
711 | - | |||
712 | - | 2 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files)static int get_entry( | |
713 | - | git_config_entry **out, | ||
714 | - | const git_config *cfg, | ||
715 | - | const char *name, | ||
716 | - | bool normalize_name, | ||
717 | - | int want_errors) | ||
718 | - | { | ||
719 | - | 2 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) int res = GIT_ENOTFOUND; | |
720 | - | 2 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) const char *key = name; | |
721 | - | 2 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) char *normalized = NULL; | |
722 | - | size_t i; | ||
723 | - | backend_internal *internal; | ||
724 | - | |||
725 | - | 2 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) *out = NULL; | |
726 | - | |||
727 | - | 2 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) if (normalize_name) { | |
728 | - | 3,4 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) if ((res = git_config__normalize_name(name, &normalized)) < 0) | |
729 | - | 5 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) goto cleanup; | |
730 | - | 6 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) key = normalized; | |
731 | - | } | ||
732 | - | |||
733 | - | 7 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) res = GIT_ENOTFOUND; | |
734 | - | 7,14-16 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) git_vector_foreach(&cfg->backends, i, internal) { | |
735 | - | 8,9 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) if (!internal || !internal->backend) | |
736 | - | 10 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) continue; | |
737 | - | |||
738 | - | 11 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) res = internal->backend->get(internal->backend, key, out); | |
739 | - | 12 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) if (res != GIT_ENOTFOUND) | |
740 | - | 13 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) break; | |
741 | - | } | ||
742 | - | |||
743 | - | 17 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) git__free(normalized); | |
744 | - | |||
745 | - | cleanup: | ||
746 | - | 18 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) if (res == GIT_ENOTFOUND) | |
747 | - | 19-22 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) res = (want_errors > GET_ALL_ERRORS) ? 0 : config_error_notfound(name); | |
748 | - | 23,24 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) else if (res && (want_errors == GET_NO_ERRORS)) { | |
749 | - | 25 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) git_error_clear(); | |
750 | - | 26 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) res = 0; | |
751 | - | } | ||
752 | - | |||
753 | - | 27 | suppressed: function cannot be solved get_entry (automatic due to inconsistent arc counts in .gcda files) return res; | |
754 | - | } | ||
755 | - | |||
756 | 1200 | 2 | int git_config_get_entry( | |
757 | - | git_config_entry **out, const git_config *cfg, const char *name) | ||
758 | - | { | ||
759 | 1200 | 2 | return get_entry(out, cfg, name, true, GET_ALL_ERRORS); | |
760 | - | } | ||
761 | - | |||
762 | 63308 | 2 | int git_config__lookup_entry( | |
763 | - | git_config_entry **out, | ||
764 | - | const git_config *cfg, | ||
765 | - | const char *key, | ||
766 | - | bool no_errors) | ||
767 | - | { | ||
768 | 63308 | 2 | return get_entry( | |
769 | - | out, cfg, key, false, no_errors ? GET_NO_ERRORS : GET_NO_MISSING); | ||
770 | - | } | ||
771 | - | |||
772 | ##### | 2 | int git_config_get_mapped( | |
773 | - | int *out, | ||
774 | - | const git_config *cfg, | ||
775 | - | const char *name, | ||
776 | - | const git_configmap *maps, | ||
777 | - | size_t map_n) | ||
778 | - | { | ||
779 | - | git_config_entry *entry; | ||
780 | - | int ret; | ||
781 | - | |||
782 | ##### | 2,3 | if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) | |
783 | ##### | 4 | return ret; | |
784 | - | |||
785 | ##### | 5 | ret = git_config_lookup_map_value(out, maps, map_n, entry->value); | |
786 | ##### | 6 | git_config_entry_free(entry); | |
787 | - | |||
788 | ##### | 7 | return ret; | |
789 | - | } | ||
790 | - | |||
791 | 234 | 2 | int git_config_get_int64(int64_t *out, const git_config *cfg, const char *name) | |
792 | - | { | ||
793 | - | git_config_entry *entry; | ||
794 | - | int ret; | ||
795 | - | |||
796 | 234 | 2,3 | if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) | |
797 | 224 | 4 | return ret; | |
798 | - | |||
799 | 10 | 5 | ret = git_config_parse_int64(out, entry->value); | |
800 | 10 | 6 | git_config_entry_free(entry); | |
801 | - | |||
802 | 10 | 7 | return ret; | |
803 | - | } | ||
804 | - | |||
805 | 4143 | 2 | int git_config_get_int32(int32_t *out, const git_config *cfg, const char *name) | |
806 | - | { | ||
807 | - | git_config_entry *entry; | ||
808 | - | int ret; | ||
809 | - | |||
810 | 4143 | 2,3 | if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) | |
811 | 130 | 4 | return ret; | |
812 | - | |||
813 | 4013 | 5 | ret = git_config_parse_int32(out, entry->value); | |
814 | 4013 | 6 | git_config_entry_free(entry); | |
815 | - | |||
816 | 4013 | 7 | return ret; | |
817 | - | } | ||
818 | - | |||
819 | 4685 | 2 | int git_config_get_bool(int *out, const git_config *cfg, const char *name) | |
820 | - | { | ||
821 | - | git_config_entry *entry; | ||
822 | - | int ret; | ||
823 | - | |||
824 | 4685 | 2,3 | if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) | |
825 | 796 | 4 | return ret; | |
826 | - | |||
827 | 3889 | 5 | ret = git_config_parse_bool(out, entry->value); | |
828 | 3889 | 6 | git_config_entry_free(entry); | |
829 | - | |||
830 | 3889 | 7 | return ret; | |
831 | - | } | ||
832 | - | |||
833 | 9357 | 2 | static int is_readonly(const git_config *cfg) | |
834 | - | { | ||
835 | - | size_t i; | ||
836 | - | backend_internal *internal; | ||
837 | - | |||
838 | 24763 | 2,8-10 | git_vector_foreach(&cfg->backends, i, internal) { | |
839 | 15406 | 3,4 | if (!internal || !internal->backend) | |
840 | ##### | 5 | continue; | |
841 | - | |||
842 | 15406 | 6 | if (!internal->backend->readonly) | |
843 | ##### | 7 | return 0; | |
844 | - | } | ||
845 | - | |||
846 | 9357 | 11 | return 1; | |
847 | - | } | ||
848 | - | |||
849 | 14 | 2 | int git_config_get_path(git_buf *out, const git_config *cfg, const char *name) | |
850 | - | { | ||
851 | - | git_config_entry *entry; | ||
852 | - | int error; | ||
853 | - | |||
854 | 14 | 2,3 | if ((error = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) | |
855 | 5 | 4 | return error; | |
856 | - | |||
857 | 9 | 5 | error = git_config_parse_path(out, entry->value); | |
858 | 9 | 6 | git_config_entry_free(entry); | |
859 | - | |||
860 | 9 | 7 | return error; | |
861 | - | } | ||
862 | - | |||
863 | 9357 | 2 | int git_config_get_string( | |
864 | - | const char **out, const git_config *cfg, const char *name) | ||
865 | - | { | ||
866 | - | git_config_entry *entry; | ||
867 | - | int ret; | ||
868 | - | |||
869 | 9357 | 2,3 | if (!is_readonly(cfg)) { | |
870 | ##### | 4 | git_error_set(GIT_ERROR_CONFIG, "get_string called on a live config object"); | |
871 | ##### | 5 | return -1; | |
872 | - | } | ||
873 | - | |||
874 | 9357 | 6 | ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS); | |
875 | 9357 | 7-12 | *out = !ret ? (entry->value ? entry->value : "") : NULL; | |
876 | - | |||
877 | 9357 | 13 | git_config_entry_free(entry); | |
878 | - | |||
879 | 9357 | 14 | return ret; | |
880 | - | } | ||
881 | - | |||
882 | 314 | 2 | int git_config_get_string_buf( | |
883 | - | git_buf *out, const git_config *cfg, const char *name) | ||
884 | - | { | ||
885 | - | git_config_entry *entry; | ||
886 | - | int ret; | ||
887 | - | const char *str; | ||
888 | - | |||
889 | 314 | 2 | git_buf_sanitize(out); | |
890 | - | |||
891 | 314 | 3 | ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS); | |
892 | 314 | 4-9 | str = !ret ? (entry->value ? entry->value : "") : NULL; | |
893 | - | |||
894 | 314 | 10 | if (str) | |
895 | 202 | 11 | ret = git_buf_puts(out, str); | |
896 | - | |||
897 | 314 | 12 | git_config_entry_free(entry); | |
898 | - | |||
899 | 314 | 13 | return ret; | |
900 | - | } | ||
901 | - | |||
902 | 27 | 2 | char *git_config__get_string_force( | |
903 | - | const git_config *cfg, const char *key, const char *fallback_value) | ||
904 | - | { | ||
905 | - | git_config_entry *entry; | ||
906 | - | char *ret; | ||
907 | - | |||
908 | 27 | 2 | get_entry(&entry, cfg, key, false, GET_NO_ERRORS); | |
909 | 27 | 3-9 | ret = (entry && entry->value) ? git__strdup(entry->value) : fallback_value ? git__strdup(fallback_value) : NULL; | |
910 | 27 | 10 | git_config_entry_free(entry); | |
911 | - | |||
912 | 27 | 11 | return ret; | |
913 | - | } | ||
914 | - | |||
915 | 15161 | 2 | int git_config__get_bool_force( | |
916 | - | const git_config *cfg, const char *key, int fallback_value) | ||
917 | - | { | ||
918 | 15161 | 2 | int val = fallback_value; | |
919 | - | git_config_entry *entry; | ||
920 | - | |||
921 | 15161 | 2 | get_entry(&entry, cfg, key, false, GET_NO_ERRORS); | |
922 | - | |||
923 | 15163 | 3-5 | if (entry && git_config_parse_bool(&val, entry->value) < 0) | |
924 | ##### | 6 | git_error_clear(); | |
925 | - | |||
926 | 15163 | 7 | git_config_entry_free(entry); | |
927 | 15163 | 8 | return val; | |
928 | - | } | ||
929 | - | |||
930 | 1137 | 2 | int git_config__get_int_force( | |
931 | - | const git_config *cfg, const char *key, int fallback_value) | ||
932 | - | { | ||
933 | 1137 | 2 | int32_t val = (int32_t)fallback_value; | |
934 | - | git_config_entry *entry; | ||
935 | - | |||
936 | 1137 | 2 | get_entry(&entry, cfg, key, false, GET_NO_ERRORS); | |
937 | - | |||
938 | 1137 | 3-5 | if (entry && git_config_parse_int32(&val, entry->value) < 0) | |
939 | ##### | 6 | git_error_clear(); | |
940 | - | |||
941 | 1137 | 7 | git_config_entry_free(entry); | |
942 | 1137 | 8 | return (int)val; | |
943 | - | } | ||
944 | - | |||
945 | 396 | 2 | int git_config_get_multivar_foreach( | |
946 | - | const git_config *cfg, const char *name, const char *regexp, | ||
947 | - | git_config_foreach_cb cb, void *payload) | ||
948 | - | { | ||
949 | - | int err, found; | ||
950 | - | git_config_iterator *iter; | ||
951 | - | git_config_entry *entry; | ||
952 | - | |||
953 | 396 | 2,3 | if ((err = git_config_multivar_iterator_new(&iter, cfg, name, regexp)) < 0) | |
954 | 9 | 4 | return err; | |
955 | - | |||
956 | 387 | 5 | found = 0; | |
957 | 610 | 5,10,11 | while ((err = iter->next(&entry, iter)) == 0) { | |
958 | 223 | 6 | found = 1; | |
959 | - | |||
960 | 223 | 6,7 | if ((err = cb(entry, payload)) != 0) { | |
961 | ##### | 8 | git_error_set_after_callback(err); | |
962 | ##### | 9 | break; | |
963 | - | } | ||
964 | - | } | ||
965 | - | |||
966 | 387 | 12 | iter->free(iter); | |
967 | 387 | 13 | if (err == GIT_ITEROVER) | |
968 | 387 | 14 | err = 0; | |
969 | - | |||
970 | 387 | 15,16 | if (found == 0 && err == 0) | |
971 | 198 | 17 | err = config_error_notfound(name); | |
972 | - | |||
973 | 387 | 18 | return err; | |
974 | - | } | ||
975 | - | |||
976 | - | typedef struct { | ||
977 | - | git_config_iterator parent; | ||
978 | - | git_config_iterator *iter; | ||
979 | - | char *name; | ||
980 | - | git_regexp regex; | ||
981 | - | int have_regex; | ||
982 | - | } multivar_iter; | ||
983 | - | |||
984 | 613 | 2 | static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter) | |
985 | - | { | ||
986 | 613 | 2 | multivar_iter *iter = (multivar_iter *) _iter; | |
987 | 613 | 2 | int error = 0; | |
988 | - | |||
989 | 7507 | 2,10,11 | while ((error = iter->iter->next(entry, iter->iter)) == 0) { | |
990 | 7119 | 3 | if (git__strcmp(iter->name, (*entry)->name)) | |
991 | 6885 | 4 | continue; | |
992 | - | |||
993 | 234 | 5 | if (!iter->have_regex) | |
994 | 210 | 6 | return 0; | |
995 | - | |||
996 | 24 | 7,8 | if (git_regexp_match(&iter->regex, (*entry)->value) == 0) | |
997 | 15 | 9 | return 0; | |
998 | - | } | ||
999 | - | |||
1000 | 388 | 12 | return error; | |
1001 | - | } | ||
1002 | - | |||
1003 | 388 | 2 | static void multivar_iter_free(git_config_iterator *_iter) | |
1004 | - | { | ||
1005 | 388 | 2 | multivar_iter *iter = (multivar_iter *) _iter; | |
1006 | - | |||
1007 | 388 | 2 | iter->iter->free(iter->iter); | |
1008 | - | |||
1009 | 388 | 3 | git__free(iter->name); | |
1010 | 388 | 4 | if (iter->have_regex) | |
1011 | 11 | 5 | git_regexp_dispose(&iter->regex); | |
1012 | 388 | 6 | git__free(iter); | |
1013 | 388 | 7 | } | |
1014 | - | |||
1015 | 397 | 2 | int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp) | |
1016 | - | { | ||
1017 | 397 | 2 | multivar_iter *iter = NULL; | |
1018 | 397 | 2 | git_config_iterator *inner = NULL; | |
1019 | - | int error; | ||
1020 | - | |||
1021 | 397 | 2,3 | if ((error = git_config_iterator_new(&inner, cfg)) < 0) | |
1022 | ##### | 4 | return error; | |
1023 | - | |||
1024 | 397 | 5 | iter = git__calloc(1, sizeof(multivar_iter)); | |
1025 | 397 | 6,7 | GIT_ERROR_CHECK_ALLOC(iter); | |
1026 | - | |||
1027 | 397 | 8,9 | if ((error = git_config__normalize_name(name, &iter->name)) < 0) | |
1028 | 9 | 10 | goto on_error; | |
1029 | - | |||
1030 | 388 | 11 | if (regexp != NULL) { | |
1031 | 11 | 12,13 | if ((error = git_regexp_compile(&iter->regex, regexp, 0)) < 0) | |
1032 | ##### | 14 | goto on_error; | |
1033 | - | |||
1034 | 11 | 15 | iter->have_regex = 1; | |
1035 | - | } | ||
1036 | - | |||
1037 | 388 | 16 | iter->iter = inner; | |
1038 | 388 | 16 | iter->parent.free = multivar_iter_free; | |
1039 | 388 | 16 | iter->parent.next = multivar_iter_next; | |
1040 | - | |||
1041 | 388 | 16 | *out = (git_config_iterator *) iter; | |
1042 | - | |||
1043 | 388 | 16 | return 0; | |
1044 | - | |||
1045 | - | on_error: | ||
1046 | - | |||
1047 | 9 | 17 | inner->free(inner); | |
1048 | 9 | 18 | git__free(iter); | |
1049 | 9 | 19 | return error; | |
1050 | - | } | ||
1051 | - | |||
1052 | 181 | 2 | int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) | |
1053 | - | { | ||
1054 | - | git_config_backend *backend; | ||
1055 | - | |||
1056 | 181 | 2,3 | if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) | |
1057 | ##### | 4 | return GIT_ENOTFOUND; | |
1058 | - | |||
1059 | 181 | 5 | return backend->set_multivar(backend, name, regexp, value); | |
1060 | - | } | ||
1061 | - | |||
1062 | 5 | 2 | int git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp) | |
1063 | - | { | ||
1064 | - | git_config_backend *backend; | ||
1065 | - | |||
1066 | 5 | 2,3 | if (get_backend_for_use(&backend, cfg, name, BACKEND_USE_DELETE) < 0) | |
1067 | ##### | 4 | return GIT_ENOTFOUND; | |
1068 | - | |||
1069 | 5 | 5 | return backend->del_multivar(backend, name, regexp); | |
1070 | - | } | ||
1071 | - | |||
1072 | 201837 | 2 | int git_config_next(git_config_entry **entry, git_config_iterator *iter) | |
1073 | - | { | ||
1074 | 201837 | 2 | return iter->next(entry, iter); | |
1075 | - | } | ||
1076 | - | |||
1077 | 49943 | 2 | void git_config_iterator_free(git_config_iterator *iter) | |
1078 | - | { | ||
1079 | 49943 | 2 | if (iter == NULL) | |
1080 | 49950 | 3,5 | return; | |
1081 | - | |||
1082 | 49943 | 4 | iter->free(iter); | |
1083 | - | } | ||
1084 | - | |||
1085 | 4092 | 2 | int git_config_find_global(git_buf *path) | |
1086 | - | { | ||
1087 | 4092 | 2 | git_buf_sanitize(path); | |
1088 | 4092 | 3 | return git_sysdir_find_global_file(path, GIT_CONFIG_FILENAME_GLOBAL); | |
1089 | - | } | ||
1090 | - | |||
1091 | 4091 | 2 | int git_config_find_xdg(git_buf *path) | |
1092 | - | { | ||
1093 | 4091 | 2 | git_buf_sanitize(path); | |
1094 | 4091 | 3 | return git_sysdir_find_xdg_file(path, GIT_CONFIG_FILENAME_XDG); | |
1095 | - | } | ||
1096 | - | |||
1097 | 4091 | 2 | int git_config_find_system(git_buf *path) | |
1098 | - | { | ||
1099 | 4091 | 2 | git_buf_sanitize(path); | |
1100 | 4091 | 3 | return git_sysdir_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); | |
1101 | - | } | ||
1102 | - | |||
1103 | 4090 | 2 | int git_config_find_programdata(git_buf *path) | |
1104 | - | { | ||
1105 | - | int ret; | ||
1106 | - | |||
1107 | 4090 | 2 | git_buf_sanitize(path); | |
1108 | 4090 | 3 | ret = git_sysdir_find_programdata_file(path, | |
1109 | - | GIT_CONFIG_FILENAME_PROGRAMDATA); | ||
1110 | 4091 | 4 | if (ret != GIT_OK) | |
1111 | 725 | 5 | return ret; | |
1112 | - | |||
1113 | 3366 | 6 | return git_path_validate_system_file_ownership(path->ptr); | |
1114 | - | } | ||
1115 | - | |||
1116 | 4076 | 2 | int git_config__global_location(git_buf *buf) | |
1117 | - | { | ||
1118 | - | const git_buf *paths; | ||
1119 | - | const char *sep, *start; | ||
1120 | - | |||
1121 | 4076 | 2,3 | if (git_sysdir_get(&paths, GIT_SYSDIR_GLOBAL) < 0) | |
1122 | ##### | 4 | return -1; | |
1123 | - | |||
1124 | - | /* no paths, so give up */ | ||
1125 | 4076 | 5-7 | if (!paths || !git_buf_len(paths)) | |
1126 | 1233 | 8 | return -1; | |
1127 | - | |||
1128 | - | /* find unescaped separator or end of string */ | ||
1129 | 99461 | 9,10,14,15 | for (sep = start = git_buf_cstr(paths); *sep; ++sep) { | |
1130 | 96620 | 11,12 | if (*sep == GIT_PATH_LIST_SEPARATOR && | |
1131 | 1 | 13 | (sep <= start || sep[-1] != '\\')) | |
1132 | - | break; | ||
1133 | - | } | ||
1134 | - | |||
1135 | 2842 | 16,17 | if (git_buf_set(buf, start, (size_t)(sep - start)) < 0) | |
1136 | ##### | 18 | return -1; | |
1137 | - | |||
1138 | 2842 | 19 | return git_buf_joinpath(buf, buf->ptr, GIT_CONFIG_FILENAME_GLOBAL); | |
1139 | - | } | ||
1140 | - | |||
1141 | 11 | 2 | int git_config_open_default(git_config **out) | |
1142 | - | { | ||
1143 | - | int error; | ||
1144 | 11 | 2 | git_config *cfg = NULL; | |
1145 | 11 | 2 | git_buf buf = GIT_BUF_INIT; | |
1146 | - | |||
1147 | 11 | 2,3 | if ((error = git_config_new(&cfg)) < 0) | |
1148 | ##### | 4 | return error; | |
1149 | - | |||
1150 | 11 | 5-8 | if (!git_config_find_global(&buf) || !git_config__global_location(&buf)) { | |
1151 | 11 | 9 | error = git_config_add_file_ondisk(cfg, buf.ptr, | |
1152 | - | GIT_CONFIG_LEVEL_GLOBAL, NULL, 0); | ||
1153 | - | } | ||
1154 | - | |||
1155 | 11 | 10-12 | if (!error && !git_config_find_xdg(&buf)) | |
1156 | 6 | 13 | error = git_config_add_file_ondisk(cfg, buf.ptr, | |
1157 | - | GIT_CONFIG_LEVEL_XDG, NULL, 0); | ||
1158 | - | |||
1159 | 11 | 14-16 | if (!error && !git_config_find_system(&buf)) | |
1160 | ##### | 17 | error = git_config_add_file_ondisk(cfg, buf.ptr, | |
1161 | - | GIT_CONFIG_LEVEL_SYSTEM, NULL, 0); | ||
1162 | - | |||
1163 | 11 | 18-20 | if (!error && !git_config_find_programdata(&buf)) | |
1164 | 6 | 21 | error = git_config_add_file_ondisk(cfg, buf.ptr, | |
1165 | - | GIT_CONFIG_LEVEL_PROGRAMDATA, NULL, 0); | ||
1166 | - | |||
1167 | 11 | 22 | git_buf_dispose(&buf); | |
1168 | - | |||
1169 | 11 | 23 | if (error) { | |
1170 | ##### | 24 | git_config_free(cfg); | |
1171 | ##### | 25 | cfg = NULL; | |
1172 | - | } | ||
1173 | - | |||
1174 | 11 | 26 | *out = cfg; | |
1175 | - | |||
1176 | 11 | 26 | return error; | |
1177 | - | } | ||
1178 | - | |||
1179 | 2 | 2 | int git_config_lock(git_transaction **out, git_config *cfg) | |
1180 | - | { | ||
1181 | - | int error; | ||
1182 | - | git_config_backend *backend; | ||
1183 | - | backend_internal *internal; | ||
1184 | - | |||
1185 | 2 | 2,3 | assert(cfg); | |
1186 | - | |||
1187 | 2 | 4 | internal = git_vector_get(&cfg->backends, 0); | |
1188 | 2 | 5,6 | if (!internal || !internal->backend) { | |
1189 | ##### | 7 | git_error_set(GIT_ERROR_CONFIG, "cannot lock; the config has no backends"); | |
1190 | ##### | 8 | return -1; | |
1191 | - | } | ||
1192 | 2 | 9 | backend = internal->backend; | |
1193 | - | |||
1194 | 2 | 9,10 | if ((error = backend->lock(backend)) < 0) | |
1195 | ##### | 11 | return error; | |
1196 | - | |||
1197 | 2 | 12 | return git_transaction_config_new(out, cfg); | |
1198 | - | } | ||
1199 | - | |||
1200 | 2 | 2 | int git_config_unlock(git_config *cfg, int commit) | |
1201 | - | { | ||
1202 | - | git_config_backend *backend; | ||
1203 | - | backend_internal *internal; | ||
1204 | - | |||
1205 | 2 | 2,3 | assert(cfg); | |
1206 | - | |||
1207 | 2 | 4 | internal = git_vector_get(&cfg->backends, 0); | |
1208 | 2 | 5,6 | if (!internal || !internal->backend) { | |
1209 | ##### | 7 | git_error_set(GIT_ERROR_CONFIG, "cannot lock; the config has no backends"); | |
1210 | ##### | 8 | return -1; | |
1211 | - | } | ||
1212 | - | |||
1213 | 2 | 9 | backend = internal->backend; | |
1214 | - | |||
1215 | 2 | 9 | return backend->unlock(backend, commit); | |
1216 | - | } | ||
1217 | - | |||
1218 | - | /*********** | ||
1219 | - | * Parsers | ||
1220 | - | ***********/ | ||
1221 | - | |||
1222 | 904 | 2 | int git_config_lookup_map_value( | |
1223 | - | int *out, | ||
1224 | - | const git_configmap *maps, | ||
1225 | - | size_t map_n, | ||
1226 | - | const char *value) | ||
1227 | - | { | ||
1228 | - | size_t i; | ||
1229 | - | |||
1230 | 904 | 2 | if (!value) | |
1231 | ##### | 3 | goto fail_parse; | |
1232 | - | |||
1233 | 1731 | 4,18,19 | for (i = 0; i < map_n; ++i) { | |
1234 | 1731 | 5 | const git_configmap *m = maps + i; | |
1235 | - | |||
1236 | 1731 | 5 | switch (m->type) { | |
1237 | - | case GIT_CONFIGMAP_FALSE: | ||
1238 | - | case GIT_CONFIGMAP_TRUE: { | ||
1239 | - | int bool_val; | ||
1240 | - | |||
1241 | 1559 | 6-8 | if (git__parse_bool(&bool_val, value) == 0 && | |
1242 | 1389 | 8 | bool_val == (int)m->type) { | |
1243 | 776 | 9 | *out = m->map_value; | |
1244 | 776 | 9 | return 0; | |
1245 | - | } | ||
1246 | 783 | 10 | break; | |
1247 | - | } | ||
1248 | - | |||
1249 | - | case GIT_CONFIGMAP_INT32: | ||
1250 | 7 | 11,12 | if (git_config_parse_int32(out, value) == 0) | |
1251 | 7 | 13 | return 0; | |
1252 | ##### | 14 | break; | |
1253 | - | |||
1254 | - | case GIT_CONFIGMAP_STRING: | ||
1255 | 165 | 15 | if (strcasecmp(value, m->str_match) == 0) { | |
1256 | 121 | 16 | *out = m->map_value; | |
1257 | 121 | 16 | return 0; | |
1258 | - | } | ||
1259 | 44 | 17 | break; | |
1260 | - | } | ||
1261 | - | } | ||
1262 | - | |||
1263 | - | fail_parse: | ||
1264 | ##### | 20 | git_error_set(GIT_ERROR_CONFIG, "failed to map '%s'", value); | |
1265 | ##### | 21 | return -1; | |
1266 | - | } | ||
1267 | - | |||
1268 | 17 | 2 | int git_config_lookup_map_enum(git_configmap_t *type_out, const char **str_out, | |
1269 | - | const git_configmap *maps, size_t map_n, int enum_val) | ||
1270 | - | { | ||
1271 | - | size_t i; | ||
1272 | - | |||
1273 | 39 | 2,4,6 | for (i = 0; i < map_n; i++) { | |
1274 | 39 | 3 | const git_configmap *m = &maps[i]; | |
1275 | - | |||
1276 | 39 | 3 | if (m->map_value != enum_val) | |
1277 | 22 | 4 | continue; | |
1278 | - | |||
1279 | 17 | 5 | *type_out = m->type; | |
1280 | 17 | 5 | *str_out = m->str_match; | |
1281 | 17 | 5 | return 0; | |
1282 | - | } | ||
1283 | - | |||
1284 | ##### | 7 | git_error_set(GIT_ERROR_CONFIG, "invalid enum value"); | |
1285 | ##### | 8 | return GIT_ENOTFOUND; | |
1286 | - | } | ||
1287 | - | |||
1288 | 14346 | 2 | int git_config_parse_bool(int *out, const char *value) | |
1289 | - | { | ||
1290 | 14346 | 2,3 | if (git__parse_bool(out, value) == 0) | |
1291 | 14342 | 4 | return 0; | |
1292 | - | |||
1293 | 3 | 5,6 | if (git_config_parse_int32(out, value) == 0) { | |
1294 | 1 | 7 | *out = !!(*out); | |
1295 | 1 | 7 | return 0; | |
1296 | - | } | ||
1297 | - | |||
1298 | 2 | 8 | git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as a boolean value", value); | |
1299 | 2 | 9 | return -1; | |
1300 | - | } | ||
1301 | - | |||
1302 | 4035 | 2 | int git_config_parse_int64(int64_t *out, const char *value) | |
1303 | - | { | ||
1304 | - | const char *num_end; | ||
1305 | - | int64_t num; | ||
1306 | - | |||
1307 | 4035 | 2-4 | if (!value || git__strntol64(&num, value, strlen(value), &num_end, 0) < 0) | |
1308 | - | goto fail_parse; | ||
1309 | - | |||
1310 | 4032 | 5 | switch (*num_end) { | |
1311 | - | case 'g': | ||
1312 | - | case 'G': | ||
1313 | 2 | 6 | num *= 1024; | |
1314 | - | /* fallthrough */ | ||
1315 | - | |||
1316 | - | case 'm': | ||
1317 | - | case 'M': | ||
1318 | 4 | 7 | num *= 1024; | |
1319 | - | /* fallthrough */ | ||
1320 | - | |||
1321 | - | case 'k': | ||
1322 | - | case 'K': | ||
1323 | 6 | 8 | num *= 1024; | |
1324 | - | |||
1325 | - | /* check that that there are no more characters after the | ||
1326 | - | * given modifier suffix */ | ||
1327 | 6 | 8 | if (num_end[1] != '\0') | |
1328 | ##### | 9 | return -1; | |
1329 | - | |||
1330 | - | /* fallthrough */ | ||
1331 | - | |||
1332 | - | case '\0': | ||
1333 | 4032 | 10 | *out = num; | |
1334 | 4032 | 10 | return 0; | |
1335 | - | |||
1336 | - | default: | ||
1337 | ##### | 11 | goto fail_parse; | |
1338 | - | } | ||
1339 | - | |||
1340 | - | fail_parse: | ||
1341 | 3 | 12-15 | git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as an integer", value ? value : "(null)"); | |
1342 | 3 | 16 | return -1; | |
1343 | - | } | ||
1344 | - | |||
1345 | 4025 | 2 | int git_config_parse_int32(int32_t *out, const char *value) | |
1346 | - | { | ||
1347 | - | int64_t tmp; | ||
1348 | - | int32_t truncate; | ||
1349 | - | |||
1350 | 4025 | 2,3 | if (git_config_parse_int64(&tmp, value) < 0) | |
1351 | 3 | 4 | goto fail_parse; | |
1352 | - | |||
1353 | 4022 | 5 | truncate = tmp & 0xFFFFFFFF; | |
1354 | 4022 | 5 | if (truncate != tmp) | |
1355 | 1 | 6 | goto fail_parse; | |
1356 | - | |||
1357 | 4021 | 7 | *out = truncate; | |
1358 | 4021 | 7 | return 0; | |
1359 | - | |||
1360 | - | fail_parse: | ||
1361 | 4 | 8-11 | git_error_set(GIT_ERROR_CONFIG, "failed to parse '%s' as a 32-bit integer", value ? value : "(null)"); | |
1362 | 4 | 12 | return -1; | |
1363 | - | } | ||
1364 | - | |||
1365 | 9 | 2 | int git_config_parse_path(git_buf *out, const char *value) | |
1366 | - | { | ||
1367 | 9 | 2-4 | assert(out && value); | |
1368 | - | |||
1369 | 9 | 5 | git_buf_sanitize(out); | |
1370 | - | |||
1371 | 9 | 6 | if (value[0] == '~') { | |
1372 | 4 | 7,8 | if (value[1] != '\0' && value[1] != '/') { | |
1373 | 1 | 9 | git_error_set(GIT_ERROR_CONFIG, "retrieving a homedir by name is not supported"); | |
1374 | 1 | 10 | return -1; | |
1375 | - | } | ||
1376 | - | |||
1377 | 3 | 11-14 | return git_sysdir_expand_global_file(out, value[1] ? &value[2] : NULL); | |
1378 | - | } | ||
1379 | - | |||
1380 | 5 | 15 | return git_buf_sets(out, value); | |
1381 | - | } | ||
1382 | - | |||
1383 | - | 2 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files)static int normalize_section(char *start, char *end) | |
1384 | - | { | ||
1385 | - | char *scan; | ||
1386 | - | |||
1387 | - | 2 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) if (start == end) | |
1388 | - | 3 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) return GIT_EINVALIDSPEC; | |
1389 | - | |||
1390 | - | /* Validate and downcase range */ | ||
1391 | - | 4,14,15 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) for (scan = start; *scan; ++scan) { | |
1392 | - | 5,6 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) if (end && scan >= end) | |
1393 | - | 7 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) break; | |
1394 | - | 8,9 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) if (isalnum(*scan)) | |
1395 | - | 10 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) *scan = (char)git__tolower(*scan); | |
1396 | - | 11,12 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) else if (*scan != '-' || scan == start) | |
1397 | - | 13 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) return GIT_EINVALIDSPEC; | |
1398 | - | } | ||
1399 | - | |||
1400 | - | 16 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) if (scan == start) | |
1401 | - | 17 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) return GIT_EINVALIDSPEC; | |
1402 | - | |||
1403 | - | 18 | suppressed: function cannot be solved normalize_section (automatic due to inconsistent arc counts in .gcda files) return 0; | |
1404 | - | } | ||
1405 | - | |||
1406 | - | |||
1407 | - | /* Take something the user gave us and make it nice for our hash function */ | ||
1408 | 31188 | 2 | int git_config__normalize_name(const char *in, char **out) | |
1409 | - | { | ||
1410 | - | char *name, *fdot, *ldot; | ||
1411 | - | |||
1412 | 31188 | 2-4 | assert(in && out); | |
1413 | - | |||
1414 | 31188 | 5 | name = git__strdup(in); | |
1415 | 31187 | 6,7 | GIT_ERROR_CHECK_ALLOC(name); | |
1416 | - | |||
1417 | 31187 | 8 | fdot = strchr(name, '.'); | |
1418 | 31187 | 8 | ldot = strrchr(name, '.'); | |
1419 | - | |||
1420 | 31187 | 8-11 | if (fdot == NULL || fdot == name || ldot == NULL || !ldot[1]) | |
1421 | - | goto invalid; | ||
1422 | - | |||
1423 | - | /* Validate and downcase up to first dot and after last dot */ | ||
1424 | 31167 | 12,13,15 | if (normalize_section(name, fdot) < 0 || | |
1425 | 31157 | 14 | normalize_section(ldot + 1, NULL) < 0) | |
1426 | - | goto invalid; | ||
1427 | - | |||
1428 | - | /* If there is a middle range, make sure it doesn't have newlines */ | ||
1429 | 152721 | 16,19 | while (fdot < ldot) | |
1430 | 121580 | 17 | if (*fdot++ == '\n') | |
1431 | 5 | 18 | goto invalid; | |
1432 | - | |||
1433 | 31141 | 20 | *out = name; | |
1434 | 31141 | 20 | return 0; | |
1435 | - | |||
1436 | - | invalid: | ||
1437 | 45 | 21 | git__free(name); | |
1438 | 46 | 22 | git_error_set(GIT_ERROR_CONFIG, "invalid config item name '%s'", in); | |
1439 | 46 | 23 | return GIT_EINVALIDSPEC; | |
1440 | - | } | ||
1441 | - | |||
1442 | - | struct rename_data { | ||
1443 | - | git_config *config; | ||
1444 | - | git_buf *name; | ||
1445 | - | size_t old_len; | ||
1446 | - | }; | ||
1447 | - | |||
1448 | 45 | 2 | static int rename_config_entries_cb( | |
1449 | - | const git_config_entry *entry, | ||
1450 | - | void *payload) | ||
1451 | - | { | ||
1452 | 45 | 2 | int error = 0; | |
1453 | 45 | 2 | struct rename_data *data = (struct rename_data *)payload; | |
1454 | 45 | 2 | size_t base_len = git_buf_len(data->name); | |
1455 | - | |||
1456 | 45 | 3-5 | if (base_len > 0 && | |
1457 | 31 | 4 | !(error = git_buf_puts(data->name, entry->name + data->old_len))) | |
1458 | - | { | ||
1459 | 31 | 6,6,7 | error = git_config_set_string( | |
1460 | 31 | 6 | data->config, git_buf_cstr(data->name), entry->value); | |
1461 | - | |||
1462 | 31 | 8 | git_buf_truncate(data->name, base_len); | |
1463 | - | } | ||
1464 | - | |||
1465 | 45 | 9 | if (!error) | |
1466 | 45 | 10 | error = git_config_delete_entry(data->config, entry->name); | |
1467 | - | |||
1468 | 45 | 11 | return error; | |
1469 | - | } | ||
1470 | - | |||
1471 | 53 | 2 | int git_config_rename_section( | |
1472 | - | git_repository *repo, | ||
1473 | - | const char *old_section_name, | ||
1474 | - | const char *new_section_name) | ||
1475 | - | { | ||
1476 | - | git_config *config; | ||
1477 | 53 | 2 | git_buf pattern = GIT_BUF_INIT, replace = GIT_BUF_INIT; | |
1478 | 53 | 2 | int error = 0; | |
1479 | - | struct rename_data data; | ||
1480 | - | |||
1481 | 53 | 2 | git_buf_text_puts_escape_regex(&pattern, old_section_name); | |
1482 | - | |||
1483 | 53 | 3,4 | if ((error = git_buf_puts(&pattern, "\\..+")) < 0) | |
1484 | ##### | 5 | goto cleanup; | |
1485 | - | |||
1486 | 53 | 6,7 | if ((error = git_repository_config__weakptr(&config, repo)) < 0) | |
1487 | ##### | 8 | goto cleanup; | |
1488 | - | |||
1489 | 53 | 9 | data.config = config; | |
1490 | 53 | 9 | data.name = &replace; | |
1491 | 53 | 9 | data.old_len = strlen(old_section_name) + 1; | |
1492 | - | |||
1493 | 53 | 9,10 | if ((error = git_buf_join(&replace, '.', new_section_name, "")) < 0) | |
1494 | ##### | 11 | goto cleanup; | |
1495 | - | |||
1496 | 53 | 12-14 | if (new_section_name != NULL && | |
1497 | 28 | 13 | (error = normalize_section(replace.ptr, strchr(replace.ptr, '.'))) < 0) | |
1498 | - | { | ||
1499 | 5 | 15 | git_error_set( | |
1500 | - | GIT_ERROR_CONFIG, "invalid config section '%s'", new_section_name); | ||
1501 | 5 | 16 | goto cleanup; | |
1502 | - | } | ||
1503 | - | |||
1504 | 48 | 17,18 | error = git_config_foreach_match( | |
1505 | - | config, git_buf_cstr(&pattern), rename_config_entries_cb, &data); | ||
1506 | - | |||
1507 | - | cleanup: | ||
1508 | 53 | 19 | git_buf_dispose(&pattern); | |
1509 | 53 | 20 | git_buf_dispose(&replace); | |
1510 | - | |||
1511 | 53 | 21 | return error; | |
1512 | - | } | ||
1513 | - | |||
1514 | 1 | 2 | int git_config_init_backend(git_config_backend *backend, unsigned int version) | |
1515 | - | { | ||
1516 | 1 | 2-4 | GIT_INIT_STRUCTURE_FROM_TEMPLATE( | |
1517 | - | backend, version, git_config_backend, GIT_CONFIG_BACKEND_INIT); | ||
1518 | 1 | 5 | return 0; | |
1519 | - | } |