]> git.proxmox.com Git - libgit2.git/blame - src/config.c
Rewrite `git_config_open_global`
[libgit2.git] / src / config.c
CommitLineData
a69053c7
CMN
1/*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26#include "common.h"
27#include "fileops.h"
28#include "hashtable.h"
29#include "config.h"
c0335005
CMN
30#include "git2/config_backend.h"
31#include "vector.h"
a69053c7
CMN
32
33#include <ctype.h>
34
c0335005
CMN
35typedef struct {
36 git_config_backend *backend;
37 int priority;
38} backend_internal;
3d23b74a 39
c0335005 40int git_config_open_bare(git_config **out, const char *path)
a69053c7 41{
c0335005
CMN
42 git_config_backend *backend = NULL;
43 git_config *cfg = NULL;
44 int error = GIT_SUCCESS;
dadc0158 45
c0335005
CMN
46 error = git_config_new(&cfg);
47 if (error < GIT_SUCCESS)
48 goto error;
dadc0158 49
c0335005
CMN
50 error = git_config_backend_file(&backend, path);
51 if (error < GIT_SUCCESS)
52 goto error;
a69053c7 53
29dca088
CMN
54 error = git_config_add_backend(cfg, backend, 1);
55 if (error < GIT_SUCCESS)
56 goto error;
11d0e705 57
c0335005
CMN
58 error = backend->open(backend);
59 if (error < GIT_SUCCESS)
60 goto error;
11d0e705 61
c0335005 62 *out = cfg;
11d0e705 63
c0335005 64 return error;
11d0e705 65
c0335005
CMN
66 error:
67 if(backend)
68 backend->free(backend);
11d0e705 69
c0335005 70 return error;
11d0e705
CMN
71}
72
32234541
CMN
73int git_config_open_global(git_config **out)
74{
8adbf2ed
VM
75 char full_path[GIT_PATH_MAX];
76 const char *home;
32234541 77
8adbf2ed 78 home = getenv("HOME");
32234541 79 if (home == NULL)
8adbf2ed 80 return git__throw(GIT_EOSERR, "Failed to find $HOME variable");
32234541 81
8adbf2ed 82 git__joinpath(full_path, home, GIT_CONFIG_FILENAME);
32234541 83
8adbf2ed 84 return git_config_open_bare(out, filename);
32234541
CMN
85}
86
c0335005 87void git_config_free(git_config *cfg)
923fe455 88{
c0335005
CMN
89 unsigned int i;
90 git_config_backend *backend;
91 backend_internal *internal;
923fe455 92
c0335005
CMN
93 for(i = 0; i < cfg->backends.length; ++i){
94 internal = git_vector_get(&cfg->backends, i);
95 backend = internal->backend;
96 backend->free(backend);
97 free(internal);
923fe455 98 }
c0335005
CMN
99
100 git_vector_free(&cfg->backends);
101 free(cfg);
923fe455
CMN
102}
103
c0335005 104static int config_backend_cmp(const void *a, const void *b)
923fe455 105{
c0335005
CMN
106 const backend_internal *bk_a = *(const backend_internal **)(a);
107 const backend_internal *bk_b = *(const backend_internal **)(b);
108
109 return bk_b->priority - bk_a->priority;
923fe455
CMN
110}
111
c0335005 112int git_config_new(git_config **out)
a69053c7
CMN
113{
114 git_config *cfg;
a69053c7
CMN
115
116 cfg = git__malloc(sizeof(git_config));
117 if (cfg == NULL)
118 return GIT_ENOMEM;
119
120 memset(cfg, 0x0, sizeof(git_config));
121
c0335005
CMN
122 if (git_vector_init(&cfg->backends, 3, config_backend_cmp) < 0) {
123 free(cfg);
124 return GIT_ENOMEM;
e4c796f1 125 }
a69053c7 126
c0335005 127 *out = cfg;
e4c796f1 128
c0335005
CMN
129 return GIT_SUCCESS;
130}
9f7f4122 131
c0335005
CMN
132int git_config_add_backend(git_config *cfg, git_config_backend *backend, int priority)
133{
134 backend_internal *internal;
956ad0ed 135
c0335005 136 assert(cfg && backend);
e4c796f1 137
c0335005
CMN
138 internal = git__malloc(sizeof(backend_internal));
139 if (internal == NULL)
140 return GIT_ENOMEM;
e4c796f1 141
c0335005
CMN
142 internal->backend = backend;
143 internal->priority = priority;
a69053c7 144
c0335005
CMN
145 if (git_vector_insert(&cfg->backends, internal) < 0) {
146 free(internal);
147 return GIT_ENOMEM;
148 }
a69053c7 149
c0335005
CMN
150 git_vector_sort(&cfg->backends);
151 internal->backend->cfg = cfg;
a69053c7 152
c0335005 153 return GIT_SUCCESS;
a69053c7
CMN
154}
155
9a3c5e55
CMN
156/*
157 * Loop over all the variables
158 */
159
2974aa94 160int git_config_foreach(git_config *cfg, int (*fn)(const char *, void *), void *data)
9a3c5e55
CMN
161{
162 int ret = GIT_SUCCESS;
c0335005
CMN
163 unsigned int i;
164 backend_internal *internal;
165 git_config_backend *backend;
166
167 for(i = 0; i < cfg->backends.length && ret == 0; ++i) {
168 internal = git_vector_get(&cfg->backends, i);
169 backend = internal->backend;
170 ret = backend->foreach(backend, fn, data);
dadc0158 171 }
9a3c5e55
CMN
172
173 return ret;
174}
175
c0335005 176
2974aa94 177/**************
9a3c5e55 178 * Setters
2974aa94 179 **************/
9a3c5e55 180
2974aa94
CMN
181/*
182 * Internal function to actually set the string value of a variable
183 */
9a3c5e55 184
b075b991 185int git_config_set_long(git_config *cfg, const char *name, long int value)
9a3c5e55 186{
2974aa94
CMN
187 char str_value[5]; /* Most numbers should fit in here */
188 int buf_len = sizeof(str_value), ret;
dadc0158 189 char *help_buf = NULL;
2974aa94 190
b075b991 191 if ((ret = snprintf(str_value, buf_len, "%ld", value)) >= buf_len - 1){
2974aa94
CMN
192 /* The number is too large, we need to allocate more memory */
193 buf_len = ret + 1;
194 help_buf = git__malloc(buf_len);
b075b991 195 snprintf(help_buf, buf_len, "%ld", value);
c0335005 196 ret = git_config_set_string(cfg, name, help_buf);
dadc0158 197 free(help_buf);
8ecc5ae5 198 } else {
c0335005 199 ret = git_config_set_string(cfg, name, str_value);
8ecc5ae5 200 }
dadc0158
CMN
201
202 return ret;
2974aa94 203}
9a3c5e55 204
b075b991
CMN
205int git_config_set_int(git_config *cfg, const char *name, int value)
206{
207 return git_config_set_long(cfg, name, value);
208}
209
2974aa94
CMN
210int git_config_set_bool(git_config *cfg, const char *name, int value)
211{
212 const char *str_value;
9a3c5e55 213
aa793424 214 if (value == 0)
2974aa94
CMN
215 str_value = "false";
216 else
217 str_value = "true";
9a3c5e55 218
c0335005 219 return git_config_set_string(cfg, name, str_value);
2974aa94 220}
9a3c5e55 221
2974aa94
CMN
222int git_config_set_string(git_config *cfg, const char *name, const char *value)
223{
c0335005
CMN
224 backend_internal *internal;
225 git_config_backend *backend;
226
227 assert(cfg->backends.length > 0);
228
229 internal = git_vector_get(&cfg->backends, 0);
230 backend = internal->backend;
231
232 return backend->set(backend, name, value);
9a3c5e55
CMN
233}
234
2974aa94
CMN
235/***********
236 * Getters
237 ***********/
9a3c5e55 238
b075b991 239int git_config_get_long(git_config *cfg, const char *name, long int *out)
2974aa94 240{
a68cf94b 241 const char *value, *num_end;
2974aa94 242 int ret;
b075b991 243 long int num;
2974aa94 244
c0335005 245 ret = git_config_get_string(cfg, name, &value);
aa793424 246 if (ret < GIT_SUCCESS)
2974aa94
CMN
247 return ret;
248
52ca4f8a
CMN
249 ret = git__strtol32(&num, value, &num_end, 0);
250 if (ret < GIT_SUCCESS)
251 return ret;
b075b991
CMN
252
253 switch (*num_end) {
631752aa
CMN
254 case '\0':
255 break;
b075b991 256 case 'k':
a99264bf 257 case 'K':
b075b991
CMN
258 num *= 1024;
259 break;
260 case 'm':
a99264bf 261 case 'M':
b075b991
CMN
262 num *= 1024 * 1024;
263 break;
264 case 'g':
a99264bf 265 case 'G':
b075b991
CMN
266 num *= 1024 * 1024 * 1024;
267 break;
268 default:
2974aa94 269 return GIT_EINVALIDTYPE;
9a3c5e55 270 }
2974aa94 271
b075b991
CMN
272 *out = num;
273
2974aa94 274 return GIT_SUCCESS;
9a3c5e55
CMN
275}
276
b075b991
CMN
277int git_config_get_int(git_config *cfg, const char *name, int *out)
278{
279 long int tmp;
280 int ret;
281
282 ret = git_config_get_long(cfg, name, &tmp);
283
284 *out = (int) tmp;
285
286 return ret;
287}
288
2974aa94 289int git_config_get_bool(git_config *cfg, const char *name, int *out)
9a3c5e55 290{
2974aa94 291 const char *value;
9a3c5e55
CMN
292 int error = GIT_SUCCESS;
293
c0335005 294 error = git_config_get_string(cfg, name, &value);
2974aa94
CMN
295 if (error < GIT_SUCCESS)
296 return error;
297
298 /* A missing value means true */
299 if (value == NULL) {
300 *out = 1;
301 return GIT_SUCCESS;
9a3c5e55
CMN
302 }
303
2974aa94
CMN
304 if (!strcasecmp(value, "true") ||
305 !strcasecmp(value, "yes") ||
aa793424 306 !strcasecmp(value, "on")) {
2974aa94
CMN
307 *out = 1;
308 return GIT_SUCCESS;
309 }
310 if (!strcasecmp(value, "false") ||
311 !strcasecmp(value, "no") ||
aa793424 312 !strcasecmp(value, "off")) {
2974aa94
CMN
313 *out = 0;
314 return GIT_SUCCESS;
315 }
316
317 /* Try to parse it as an integer */
318 error = git_config_get_int(cfg, name, out);
319 if (error == GIT_SUCCESS)
320 *out = !!(*out);
9a3c5e55 321
9a3c5e55
CMN
322 return error;
323}
324
2974aa94
CMN
325int git_config_get_string(git_config *cfg, const char *name, const char **out)
326{
c0335005
CMN
327 backend_internal *internal;
328 git_config_backend *backend;
72946881 329
c0335005 330 assert(cfg->backends.length > 0);
72946881 331
c0335005
CMN
332 internal = git_vector_get(&cfg->backends, 0);
333 backend = internal->backend;
72946881 334
c0335005 335 return backend->get(backend, name, out);
72946881
CMN
336}
337