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.
10 #include "git2/config.h"
11 #include "git2/sys/config.h"
14 #include "config_backend.h"
17 #include "transaction.h"
25 void git_config_entry_free(git_config_entry
*entry
)
36 git_config_backend
*backend
;
37 git_config_level_t level
;
40 static void backend_internal_free(backend_internal
*internal
)
42 git_config_backend
*backend
;
44 backend
= internal
->backend
;
45 backend
->free(backend
);
49 static void config_free(git_config
*cfg
)
52 backend_internal
*internal
;
54 for (i
= 0; i
< cfg
->backends
.length
; ++i
) {
55 internal
= git_vector_get(&cfg
->backends
, i
);
56 GIT_REFCOUNT_DEC(internal
, backend_internal_free
);
59 git_vector_free(&cfg
->backends
);
61 git__memzero(cfg
, sizeof(*cfg
));
65 void git_config_free(git_config
*cfg
)
70 GIT_REFCOUNT_DEC(cfg
, config_free
);
73 static int config_backend_cmp(const void *a
, const void *b
)
75 const backend_internal
*bk_a
= (const backend_internal
*)(a
);
76 const backend_internal
*bk_b
= (const backend_internal
*)(b
);
78 return bk_b
->level
- bk_a
->level
;
81 int git_config_new(git_config
**out
)
85 cfg
= git__malloc(sizeof(git_config
));
86 GIT_ERROR_CHECK_ALLOC(cfg
);
88 memset(cfg
, 0x0, sizeof(git_config
));
90 if (git_vector_init(&cfg
->backends
, 3, config_backend_cmp
) < 0) {
96 GIT_REFCOUNT_INC(cfg
);
100 int git_config_add_file_ondisk(
103 git_config_level_t level
,
104 const git_repository
*repo
,
107 git_config_backend
*file
= NULL
;
113 res
= p_stat(path
, &st
);
114 if (res
< 0 && errno
!= ENOENT
&& errno
!= ENOTDIR
) {
115 git_error_set(GIT_ERROR_CONFIG
, "failed to stat '%s'", path
);
119 if (git_config_backend_from_file(&file
, path
) < 0)
122 if ((res
= git_config_add_backend(cfg
, file
, level
, repo
, force
)) < 0) {
124 * free manually; the file is not owned by the config
125 * instance yet and will not be freed on cleanup
134 int git_config_open_ondisk(git_config
**out
, const char *path
)
141 if (git_config_new(&config
) < 0)
144 if ((error
= git_config_add_file_ondisk(config
, path
, GIT_CONFIG_LEVEL_LOCAL
, NULL
, 0)) < 0)
145 git_config_free(config
);
152 int git_config_snapshot(git_config
**out
, git_config
*in
)
156 backend_internal
*internal
;
161 if (git_config_new(&config
) < 0)
164 git_vector_foreach(&in
->backends
, i
, internal
) {
165 git_config_backend
*b
;
167 if ((error
= internal
->backend
->snapshot(&b
, internal
->backend
)) < 0)
170 if ((error
= git_config_add_backend(config
, b
, internal
->level
, NULL
, 0)) < 0) {
177 git_config_free(config
);
184 static int find_backend_by_level(
185 backend_internal
**out
,
186 const git_config
*cfg
,
187 git_config_level_t level
)
190 backend_internal
*internal
;
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
198 if (level
== GIT_CONFIG_HIGHEST_LEVEL
) {
201 git_vector_foreach(&cfg
->backends
, i
, internal
) {
202 if (internal
->level
== level
)
208 git_error_set(GIT_ERROR_CONFIG
,
209 "no configuration exists for the given level '%i'", (int)level
);
210 return GIT_ENOTFOUND
;
213 *out
= git_vector_get(&cfg
->backends
, pos
);
218 static int duplicate_level(void **old_raw
, void *new_raw
)
220 backend_internal
**old
= (backend_internal
**)old_raw
;
224 git_error_set(GIT_ERROR_CONFIG
, "there already exists a configuration for the given level (%i)", (int)(*old
)->level
);
228 static void try_remove_existing_backend(
230 git_config_level_t level
)
233 backend_internal
*internal
;
236 git_vector_foreach(&cfg
->backends
, i
, internal
) {
237 if (internal
->level
== level
)
244 internal
= git_vector_get(&cfg
->backends
, pos
);
246 if (git_vector_remove(&cfg
->backends
, pos
) < 0)
249 GIT_REFCOUNT_DEC(internal
, backend_internal_free
);
252 static int git_config__add_internal(
254 backend_internal
*internal
,
255 git_config_level_t level
,
260 /* delete existing config backend for level if it exists */
262 try_remove_existing_backend(cfg
, level
);
264 if ((result
= git_vector_insert_sorted(&cfg
->backends
,
265 internal
, &duplicate_level
)) < 0)
268 git_vector_sort(&cfg
->backends
);
269 internal
->backend
->cfg
= cfg
;
271 GIT_REFCOUNT_INC(internal
);
276 int git_config_open_global(git_config
**cfg_out
, git_config
*cfg
)
278 if (!git_config_open_level(cfg_out
, cfg
, GIT_CONFIG_LEVEL_XDG
))
281 return git_config_open_level(cfg_out
, cfg
, GIT_CONFIG_LEVEL_GLOBAL
);
284 int git_config_open_level(
285 git_config
**cfg_out
,
286 const git_config
*cfg_parent
,
287 git_config_level_t level
)
290 backend_internal
*internal
;
293 if ((res
= find_backend_by_level(&internal
, cfg_parent
, level
)) < 0)
296 if ((res
= git_config_new(&cfg
)) < 0)
299 if ((res
= git_config__add_internal(cfg
, internal
, level
, true)) < 0) {
300 git_config_free(cfg
);
309 int git_config_add_backend(
311 git_config_backend
*backend
,
312 git_config_level_t level
,
313 const git_repository
*repo
,
316 backend_internal
*internal
;
319 assert(cfg
&& backend
);
321 GIT_ERROR_CHECK_VERSION(backend
, GIT_CONFIG_BACKEND_VERSION
, "git_config_backend");
323 if ((result
= backend
->open(backend
, level
, repo
)) < 0)
326 internal
= git__malloc(sizeof(backend_internal
));
327 GIT_ERROR_CHECK_ALLOC(internal
);
329 memset(internal
, 0x0, sizeof(backend_internal
));
331 internal
->backend
= backend
;
332 internal
->level
= level
;
334 if ((result
= git_config__add_internal(cfg
, internal
, level
, force
)) < 0) {
343 * Loop over all the variables
347 git_config_iterator parent
;
348 git_config_iterator
*current
;
349 const git_config
*cfg
;
354 static int find_next_backend(size_t *out
, const git_config
*cfg
, size_t i
)
356 backend_internal
*internal
;
359 internal
= git_vector_get(&cfg
->backends
, i
- 1);
360 if (!internal
|| !internal
->backend
)
370 static int all_iter_next(git_config_entry
**entry
, git_config_iterator
*_iter
)
372 all_iter
*iter
= (all_iter
*) _iter
;
373 backend_internal
*internal
;
374 git_config_backend
*backend
;
378 if (iter
->current
!= NULL
&&
379 (error
= iter
->current
->next(entry
, iter
->current
)) == 0) {
383 if (error
< 0 && error
!= GIT_ITEROVER
)
387 if (find_next_backend(&i
, iter
->cfg
, iter
->i
) < 0)
390 internal
= git_vector_get(&iter
->cfg
->backends
, i
- 1);
391 backend
= internal
->backend
;
395 iter
->current
->free(iter
->current
);
397 iter
->current
= NULL
;
398 error
= backend
->iterator(&iter
->current
, backend
);
399 if (error
== GIT_ENOTFOUND
)
405 error
= iter
->current
->next(entry
, iter
->current
);
406 /* If this backend is empty, then keep going */
407 if (error
== GIT_ITEROVER
)
417 static int all_iter_glob_next(git_config_entry
**entry
, git_config_iterator
*_iter
)
420 all_iter
*iter
= (all_iter
*) _iter
;
423 * We use the "normal" function to grab the next one across
424 * backends and then apply the regex
426 while ((error
= all_iter_next(entry
, _iter
)) == 0) {
427 /* skip non-matching keys if regexp was provided */
428 if (git_regexp_match(&iter
->regex
, (*entry
)->name
) != 0)
431 /* and simply return if we like the entry's name */
438 static void all_iter_free(git_config_iterator
*_iter
)
440 all_iter
*iter
= (all_iter
*) _iter
;
443 iter
->current
->free(iter
->current
);
448 static void all_iter_glob_free(git_config_iterator
*_iter
)
450 all_iter
*iter
= (all_iter
*) _iter
;
452 git_regexp_dispose(&iter
->regex
);
453 all_iter_free(_iter
);
456 int git_config_iterator_new(git_config_iterator
**out
, const git_config
*cfg
)
460 iter
= git__calloc(1, sizeof(all_iter
));
461 GIT_ERROR_CHECK_ALLOC(iter
);
463 iter
->parent
.free
= all_iter_free
;
464 iter
->parent
.next
= all_iter_next
;
466 iter
->i
= cfg
->backends
.length
;
469 *out
= (git_config_iterator
*) iter
;
474 int git_config_iterator_glob_new(git_config_iterator
**out
, const git_config
*cfg
, const char *regexp
)
480 return git_config_iterator_new(out
, cfg
);
482 iter
= git__calloc(1, sizeof(all_iter
));
483 GIT_ERROR_CHECK_ALLOC(iter
);
485 if ((result
= git_regexp_compile(&iter
->regex
, regexp
, 0)) < 0) {
490 iter
->parent
.next
= all_iter_glob_next
;
491 iter
->parent
.free
= all_iter_glob_free
;
492 iter
->i
= cfg
->backends
.length
;
495 *out
= (git_config_iterator
*) iter
;
500 int git_config_foreach(
501 const git_config
*cfg
, git_config_foreach_cb cb
, void *payload
)
503 return git_config_foreach_match(cfg
, NULL
, cb
, payload
);
506 int git_config_backend_foreach_match(
507 git_config_backend
*backend
,
509 git_config_foreach_cb cb
,
512 git_config_entry
*entry
;
513 git_config_iterator
* iter
;
517 assert(backend
&& cb
);
519 if (regexp
&& git_regexp_compile(®ex
, regexp
, 0) < 0)
522 if ((error
= backend
->iterator(&iter
, backend
)) < 0) {
527 while (!(iter
->next(&entry
, iter
) < 0)) {
528 /* skip non-matching keys if regexp was provided */
529 if (regexp
&& git_regexp_match(®ex
, entry
->name
) != 0)
532 /* abort iterator on non-zero return value */
533 if ((error
= cb(entry
, payload
)) != 0) {
534 git_error_set_after_callback(error
);
540 git_regexp_dispose(®ex
);
547 int git_config_foreach_match(
548 const git_config
*cfg
,
550 git_config_foreach_cb cb
,
554 git_config_iterator
*iter
;
555 git_config_entry
*entry
;
557 if ((error
= git_config_iterator_glob_new(&iter
, cfg
, regexp
)) < 0)
560 while (!(error
= git_config_next(&entry
, iter
))) {
561 if ((error
= cb(entry
, payload
)) != 0) {
562 git_error_set_after_callback(error
);
567 git_config_iterator_free(iter
);
569 if (error
== GIT_ITEROVER
)
584 static const char *uses
[] = {
589 static int get_backend_for_use(git_config_backend
**out
,
590 git_config
*cfg
, const char *name
, backend_use use
)
593 backend_internal
*backend
;
597 if (git_vector_length(&cfg
->backends
) == 0) {
598 git_error_set(GIT_ERROR_CONFIG
,
599 "cannot %s value for '%s' when no config backends exist",
601 return GIT_ENOTFOUND
;
604 git_vector_foreach(&cfg
->backends
, i
, backend
) {
605 if (!backend
->backend
->readonly
) {
606 *out
= backend
->backend
;
611 git_error_set(GIT_ERROR_CONFIG
,
612 "cannot %s value for '%s' when all config backends are readonly",
614 return GIT_ENOTFOUND
;
617 int git_config_delete_entry(git_config
*cfg
, const char *name
)
619 git_config_backend
*backend
;
621 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_DELETE
) < 0)
622 return GIT_ENOTFOUND
;
624 return backend
->del(backend
, name
);
627 int git_config_set_int64(git_config
*cfg
, const char *name
, int64_t value
)
629 char str_value
[32]; /* All numbers should fit in here */
630 p_snprintf(str_value
, sizeof(str_value
), "%" PRId64
, value
);
631 return git_config_set_string(cfg
, name
, str_value
);
634 int git_config_set_int32(git_config
*cfg
, const char *name
, int32_t value
)
636 return git_config_set_int64(cfg
, name
, (int64_t)value
);
639 int git_config_set_bool(git_config
*cfg
, const char *name
, int value
)
641 return git_config_set_string(cfg
, name
, value
? "true" : "false");
644 int git_config_set_string(git_config
*cfg
, const char *name
, const char *value
)
647 git_config_backend
*backend
;
650 git_error_set(GIT_ERROR_CONFIG
, "the value to set cannot be NULL");
654 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_SET
) < 0)
655 return GIT_ENOTFOUND
;
657 error
= backend
->set(backend
, name
, value
);
659 if (!error
&& GIT_REFCOUNT_OWNER(cfg
) != NULL
)
660 git_repository__configmap_lookup_cache_clear(GIT_REFCOUNT_OWNER(cfg
));
665 int git_config__update_entry(
669 bool overwrite_existing
,
670 bool only_if_existing
)
673 git_config_entry
*ce
= NULL
;
675 if ((error
= git_config__lookup_entry(&ce
, config
, key
, false)) < 0)
678 if (!ce
&& only_if_existing
) /* entry doesn't exist */
680 if (ce
&& !overwrite_existing
) /* entry would be overwritten */
682 if (value
&& ce
&& ce
->value
&& !strcmp(ce
->value
, value
)) /* no change */
684 if (!value
&& (!ce
|| !ce
->value
)) /* asked to delete absent entry */
688 error
= git_config_delete_entry(config
, key
);
690 error
= git_config_set_string(config
, key
, value
);
692 git_config_entry_free(ce
);
700 static int config_error_notfound(const char *name
)
702 git_error_set(GIT_ERROR_CONFIG
, "config value '%s' was not found", name
);
703 return GIT_ENOTFOUND
;
712 static int get_entry(
713 git_config_entry
**out
,
714 const git_config
*cfg
,
719 int res
= GIT_ENOTFOUND
;
720 const char *key
= name
;
721 char *normalized
= NULL
;
723 backend_internal
*internal
;
727 if (normalize_name
) {
728 if ((res
= git_config__normalize_name(name
, &normalized
)) < 0)
734 git_vector_foreach(&cfg
->backends
, i
, internal
) {
735 if (!internal
|| !internal
->backend
)
738 res
= internal
->backend
->get(internal
->backend
, key
, out
);
739 if (res
!= GIT_ENOTFOUND
)
743 git__free(normalized
);
746 if (res
== GIT_ENOTFOUND
)
747 res
= (want_errors
> GET_ALL_ERRORS
) ? 0 : config_error_notfound(name
);
748 else if (res
&& (want_errors
== GET_NO_ERRORS
)) {
756 int git_config_get_entry(
757 git_config_entry
**out
, const git_config
*cfg
, const char *name
)
759 return get_entry(out
, cfg
, name
, true, GET_ALL_ERRORS
);
762 int git_config__lookup_entry(
763 git_config_entry
**out
,
764 const git_config
*cfg
,
769 out
, cfg
, key
, false, no_errors
? GET_NO_ERRORS
: GET_NO_MISSING
);
772 int git_config_get_mapped(
774 const git_config
*cfg
,
776 const git_configmap
*maps
,
779 git_config_entry
*entry
;
782 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
785 ret
= git_config_lookup_map_value(out
, maps
, map_n
, entry
->value
);
786 git_config_entry_free(entry
);
791 int git_config_get_int64(int64_t *out
, const git_config
*cfg
, const char *name
)
793 git_config_entry
*entry
;
796 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
799 ret
= git_config_parse_int64(out
, entry
->value
);
800 git_config_entry_free(entry
);
805 int git_config_get_int32(int32_t *out
, const git_config
*cfg
, const char *name
)
807 git_config_entry
*entry
;
810 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
813 ret
= git_config_parse_int32(out
, entry
->value
);
814 git_config_entry_free(entry
);
819 int git_config_get_bool(int *out
, const git_config
*cfg
, const char *name
)
821 git_config_entry
*entry
;
824 if ((ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
827 ret
= git_config_parse_bool(out
, entry
->value
);
828 git_config_entry_free(entry
);
833 static int is_readonly(const git_config
*cfg
)
836 backend_internal
*internal
;
838 git_vector_foreach(&cfg
->backends
, i
, internal
) {
839 if (!internal
|| !internal
->backend
)
842 if (!internal
->backend
->readonly
)
849 int git_config_get_path(git_buf
*out
, const git_config
*cfg
, const char *name
)
851 git_config_entry
*entry
;
854 if ((error
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
)) < 0)
857 error
= git_config_parse_path(out
, entry
->value
);
858 git_config_entry_free(entry
);
863 int git_config_get_string(
864 const char **out
, const git_config
*cfg
, const char *name
)
866 git_config_entry
*entry
;
869 if (!is_readonly(cfg
)) {
870 git_error_set(GIT_ERROR_CONFIG
, "get_string called on a live config object");
874 ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
);
875 *out
= !ret
? (entry
->value
? entry
->value
: "") : NULL
;
877 git_config_entry_free(entry
);
882 int git_config_get_string_buf(
883 git_buf
*out
, const git_config
*cfg
, const char *name
)
885 git_config_entry
*entry
;
889 git_buf_sanitize(out
);
891 ret
= get_entry(&entry
, cfg
, name
, true, GET_ALL_ERRORS
);
892 str
= !ret
? (entry
->value
? entry
->value
: "") : NULL
;
895 ret
= git_buf_puts(out
, str
);
897 git_config_entry_free(entry
);
902 char *git_config__get_string_force(
903 const git_config
*cfg
, const char *key
, const char *fallback_value
)
905 git_config_entry
*entry
;
908 get_entry(&entry
, cfg
, key
, false, GET_NO_ERRORS
);
909 ret
= (entry
&& entry
->value
) ? git__strdup(entry
->value
) : fallback_value
? git__strdup(fallback_value
) : NULL
;
910 git_config_entry_free(entry
);
915 int git_config__get_bool_force(
916 const git_config
*cfg
, const char *key
, int fallback_value
)
918 int val
= fallback_value
;
919 git_config_entry
*entry
;
921 get_entry(&entry
, cfg
, key
, false, GET_NO_ERRORS
);
923 if (entry
&& git_config_parse_bool(&val
, entry
->value
) < 0)
926 git_config_entry_free(entry
);
930 int git_config__get_int_force(
931 const git_config
*cfg
, const char *key
, int fallback_value
)
933 int32_t val
= (int32_t)fallback_value
;
934 git_config_entry
*entry
;
936 get_entry(&entry
, cfg
, key
, false, GET_NO_ERRORS
);
938 if (entry
&& git_config_parse_int32(&val
, entry
->value
) < 0)
941 git_config_entry_free(entry
);
945 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
)
950 git_config_iterator
*iter
;
951 git_config_entry
*entry
;
953 if ((err
= git_config_multivar_iterator_new(&iter
, cfg
, name
, regexp
)) < 0)
957 while ((err
= iter
->next(&entry
, iter
)) == 0) {
960 if ((err
= cb(entry
, payload
)) != 0) {
961 git_error_set_after_callback(err
);
967 if (err
== GIT_ITEROVER
)
970 if (found
== 0 && err
== 0)
971 err
= config_error_notfound(name
);
977 git_config_iterator parent
;
978 git_config_iterator
*iter
;
984 static int multivar_iter_next(git_config_entry
**entry
, git_config_iterator
*_iter
)
986 multivar_iter
*iter
= (multivar_iter
*) _iter
;
989 while ((error
= iter
->iter
->next(entry
, iter
->iter
)) == 0) {
990 if (git__strcmp(iter
->name
, (*entry
)->name
))
993 if (!iter
->have_regex
)
996 if (git_regexp_match(&iter
->regex
, (*entry
)->value
) == 0)
1003 void multivar_iter_free(git_config_iterator
*_iter
)
1005 multivar_iter
*iter
= (multivar_iter
*) _iter
;
1007 iter
->iter
->free(iter
->iter
);
1009 git__free(iter
->name
);
1010 if (iter
->have_regex
)
1011 git_regexp_dispose(&iter
->regex
);
1015 int git_config_multivar_iterator_new(git_config_iterator
**out
, const git_config
*cfg
, const char *name
, const char *regexp
)
1017 multivar_iter
*iter
= NULL
;
1018 git_config_iterator
*inner
= NULL
;
1021 if ((error
= git_config_iterator_new(&inner
, cfg
)) < 0)
1024 iter
= git__calloc(1, sizeof(multivar_iter
));
1025 GIT_ERROR_CHECK_ALLOC(iter
);
1027 if ((error
= git_config__normalize_name(name
, &iter
->name
)) < 0)
1030 if (regexp
!= NULL
) {
1031 if ((error
= git_regexp_compile(&iter
->regex
, regexp
, 0)) < 0)
1034 iter
->have_regex
= 1;
1038 iter
->parent
.free
= multivar_iter_free
;
1039 iter
->parent
.next
= multivar_iter_next
;
1041 *out
= (git_config_iterator
*) iter
;
1052 int git_config_set_multivar(git_config
*cfg
, const char *name
, const char *regexp
, const char *value
)
1054 git_config_backend
*backend
;
1056 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_DELETE
) < 0)
1057 return GIT_ENOTFOUND
;
1059 return backend
->set_multivar(backend
, name
, regexp
, value
);
1062 int git_config_delete_multivar(git_config
*cfg
, const char *name
, const char *regexp
)
1064 git_config_backend
*backend
;
1066 if (get_backend_for_use(&backend
, cfg
, name
, BACKEND_USE_DELETE
) < 0)
1067 return GIT_ENOTFOUND
;
1069 return backend
->del_multivar(backend
, name
, regexp
);
1072 int git_config_next(git_config_entry
**entry
, git_config_iterator
*iter
)
1074 return iter
->next(entry
, iter
);
1077 void git_config_iterator_free(git_config_iterator
*iter
)
1085 int git_config_find_global(git_buf
*path
)
1087 git_buf_sanitize(path
);
1088 return git_sysdir_find_global_file(path
, GIT_CONFIG_FILENAME_GLOBAL
);
1091 int git_config_find_xdg(git_buf
*path
)
1093 git_buf_sanitize(path
);
1094 return git_sysdir_find_xdg_file(path
, GIT_CONFIG_FILENAME_XDG
);
1097 int git_config_find_system(git_buf
*path
)
1099 git_buf_sanitize(path
);
1100 return git_sysdir_find_system_file(path
, GIT_CONFIG_FILENAME_SYSTEM
);
1103 int git_config_find_programdata(git_buf
*path
)
1107 git_buf_sanitize(path
);
1108 ret
= git_sysdir_find_programdata_file(path
,
1109 GIT_CONFIG_FILENAME_PROGRAMDATA
);
1113 return git_path_validate_system_file_ownership(path
->ptr
);
1116 int git_config__global_location(git_buf
*buf
)
1118 const git_buf
*paths
;
1119 const char *sep
, *start
;
1121 if (git_sysdir_get(&paths
, GIT_SYSDIR_GLOBAL
) < 0)
1124 /* no paths, so give up */
1125 if (!paths
|| !git_buf_len(paths
))
1128 /* find unescaped separator or end of string */
1129 for (sep
= start
= git_buf_cstr(paths
); *sep
; ++sep
) {
1130 if (*sep
== GIT_PATH_LIST_SEPARATOR
&&
1131 (sep
<= start
|| sep
[-1] != '\\'))
1135 if (git_buf_set(buf
, start
, (size_t)(sep
- start
)) < 0)
1138 return git_buf_joinpath(buf
, buf
->ptr
, GIT_CONFIG_FILENAME_GLOBAL
);
1141 int git_config_open_default(git_config
**out
)
1144 git_config
*cfg
= NULL
;
1145 git_buf buf
= GIT_BUF_INIT
;
1147 if ((error
= git_config_new(&cfg
)) < 0)
1150 if (!git_config_find_global(&buf
) || !git_config__global_location(&buf
)) {
1151 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1152 GIT_CONFIG_LEVEL_GLOBAL
, NULL
, 0);
1155 if (!error
&& !git_config_find_xdg(&buf
))
1156 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1157 GIT_CONFIG_LEVEL_XDG
, NULL
, 0);
1159 if (!error
&& !git_config_find_system(&buf
))
1160 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1161 GIT_CONFIG_LEVEL_SYSTEM
, NULL
, 0);
1163 if (!error
&& !git_config_find_programdata(&buf
))
1164 error
= git_config_add_file_ondisk(cfg
, buf
.ptr
,
1165 GIT_CONFIG_LEVEL_PROGRAMDATA
, NULL
, 0);
1167 git_buf_dispose(&buf
);
1170 git_config_free(cfg
);
1179 int git_config_lock(git_transaction
**out
, git_config
*cfg
)
1182 git_config_backend
*backend
;
1183 backend_internal
*internal
;
1187 internal
= git_vector_get(&cfg
->backends
, 0);
1188 if (!internal
|| !internal
->backend
) {
1189 git_error_set(GIT_ERROR_CONFIG
, "cannot lock; the config has no backends");
1192 backend
= internal
->backend
;
1194 if ((error
= backend
->lock(backend
)) < 0)
1197 return git_transaction_config_new(out
, cfg
);
1200 int git_config_unlock(git_config
*cfg
, int commit
)
1202 git_config_backend
*backend
;
1203 backend_internal
*internal
;
1207 internal
= git_vector_get(&cfg
->backends
, 0);
1208 if (!internal
|| !internal
->backend
) {
1209 git_error_set(GIT_ERROR_CONFIG
, "cannot lock; the config has no backends");
1213 backend
= internal
->backend
;
1215 return backend
->unlock(backend
, commit
);
1222 int git_config_lookup_map_value(
1224 const git_configmap
*maps
,
1233 for (i
= 0; i
< map_n
; ++i
) {
1234 const git_configmap
*m
= maps
+ i
;
1237 case GIT_CONFIGMAP_FALSE
:
1238 case GIT_CONFIGMAP_TRUE
: {
1241 if (git__parse_bool(&bool_val
, value
) == 0 &&
1242 bool_val
== (int)m
->type
) {
1243 *out
= m
->map_value
;
1249 case GIT_CONFIGMAP_INT32
:
1250 if (git_config_parse_int32(out
, value
) == 0)
1254 case GIT_CONFIGMAP_STRING
:
1255 if (strcasecmp(value
, m
->str_match
) == 0) {
1256 *out
= m
->map_value
;
1264 git_error_set(GIT_ERROR_CONFIG
, "failed to map '%s'", value
);
1268 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
)
1273 for (i
= 0; i
< map_n
; i
++) {
1274 const git_configmap
*m
= &maps
[i
];
1276 if (m
->map_value
!= enum_val
)
1279 *type_out
= m
->type
;
1280 *str_out
= m
->str_match
;
1284 git_error_set(GIT_ERROR_CONFIG
, "invalid enum value");
1285 return GIT_ENOTFOUND
;
1288 int git_config_parse_bool(int *out
, const char *value
)
1290 if (git__parse_bool(out
, value
) == 0)
1293 if (git_config_parse_int32(out
, value
) == 0) {
1298 git_error_set(GIT_ERROR_CONFIG
, "failed to parse '%s' as a boolean value", value
);
1302 int git_config_parse_int64(int64_t *out
, const char *value
)
1304 const char *num_end
;
1307 if (!value
|| git__strntol64(&num
, value
, strlen(value
), &num_end
, 0) < 0)
1325 /* check that that there are no more characters after the
1326 * given modifier suffix */
1327 if (num_end
[1] != '\0')
1341 git_error_set(GIT_ERROR_CONFIG
, "failed to parse '%s' as an integer", value
? value
: "(null)");
1345 int git_config_parse_int32(int32_t *out
, const char *value
)
1350 if (git_config_parse_int64(&tmp
, value
) < 0)
1353 truncate
= tmp
& 0xFFFFFFFF;
1354 if (truncate
!= tmp
)
1361 git_error_set(GIT_ERROR_CONFIG
, "failed to parse '%s' as a 32-bit integer", value
? value
: "(null)");
1365 int git_config_parse_path(git_buf
*out
, const char *value
)
1367 assert(out
&& value
);
1369 git_buf_sanitize(out
);
1371 if (value
[0] == '~') {
1372 if (value
[1] != '\0' && value
[1] != '/') {
1373 git_error_set(GIT_ERROR_CONFIG
, "retrieving a homedir by name is not supported");
1377 return git_sysdir_expand_global_file(out
, value
[1] ? &value
[2] : NULL
);
1380 return git_buf_sets(out
, value
);
1383 static int normalize_section(char *start
, char *end
)
1388 return GIT_EINVALIDSPEC
;
1390 /* Validate and downcase range */
1391 for (scan
= start
; *scan
; ++scan
) {
1392 if (end
&& scan
>= end
)
1395 *scan
= (char)git__tolower(*scan
);
1396 else if (*scan
!= '-' || scan
== start
)
1397 return GIT_EINVALIDSPEC
;
1401 return GIT_EINVALIDSPEC
;
1407 /* Take something the user gave us and make it nice for our hash function */
1408 int git_config__normalize_name(const char *in
, char **out
)
1410 char *name
, *fdot
, *ldot
;
1414 name
= git__strdup(in
);
1415 GIT_ERROR_CHECK_ALLOC(name
);
1417 fdot
= strchr(name
, '.');
1418 ldot
= strrchr(name
, '.');
1420 if (fdot
== NULL
|| fdot
== name
|| ldot
== NULL
|| !ldot
[1])
1423 /* Validate and downcase up to first dot and after last dot */
1424 if (normalize_section(name
, fdot
) < 0 ||
1425 normalize_section(ldot
+ 1, NULL
) < 0)
1428 /* If there is a middle range, make sure it doesn't have newlines */
1430 if (*fdot
++ == '\n')
1438 git_error_set(GIT_ERROR_CONFIG
, "invalid config item name '%s'", in
);
1439 return GIT_EINVALIDSPEC
;
1442 struct rename_data
{
1448 static int rename_config_entries_cb(
1449 const git_config_entry
*entry
,
1453 struct rename_data
*data
= (struct rename_data
*)payload
;
1454 size_t base_len
= git_buf_len(data
->name
);
1457 !(error
= git_buf_puts(data
->name
, entry
->name
+ data
->old_len
)))
1459 error
= git_config_set_string(
1460 data
->config
, git_buf_cstr(data
->name
), entry
->value
);
1462 git_buf_truncate(data
->name
, base_len
);
1466 error
= git_config_delete_entry(data
->config
, entry
->name
);
1471 int git_config_rename_section(
1472 git_repository
*repo
,
1473 const char *old_section_name
,
1474 const char *new_section_name
)
1477 git_buf pattern
= GIT_BUF_INIT
, replace
= GIT_BUF_INIT
;
1479 struct rename_data data
;
1481 git_buf_text_puts_escape_regex(&pattern
, old_section_name
);
1483 if ((error
= git_buf_puts(&pattern
, "\\..+")) < 0)
1486 if ((error
= git_repository_config__weakptr(&config
, repo
)) < 0)
1489 data
.config
= config
;
1490 data
.name
= &replace
;
1491 data
.old_len
= strlen(old_section_name
) + 1;
1493 if ((error
= git_buf_join(&replace
, '.', new_section_name
, "")) < 0)
1496 if (new_section_name
!= NULL
&&
1497 (error
= normalize_section(replace
.ptr
, strchr(replace
.ptr
, '.'))) < 0)
1500 GIT_ERROR_CONFIG
, "invalid config section '%s'", new_section_name
);
1504 error
= git_config_foreach_match(
1505 config
, git_buf_cstr(&pattern
), rename_config_entries_cb
, &data
);
1508 git_buf_dispose(&pattern
);
1509 git_buf_dispose(&replace
);
1514 int git_config_init_backend(git_config_backend
*backend
, unsigned int version
)
1516 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1517 backend
, version
, git_config_backend
, GIT_CONFIG_BACKEND_INIT
);