]> git.proxmox.com Git - libgit2.git/blob - src/config.c
git_config_add_file should rethrow
[libgit2.git] / src / config.c
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"
30 #include "git2/config.h"
31 #include "vector.h"
32
33 #include <ctype.h>
34
35 typedef struct {
36 git_config_file *file;
37 int priority;
38 } file_internal;
39
40 void git_config_free(git_config *cfg)
41 {
42 unsigned int i;
43 git_config_file *file;
44 file_internal *internal;
45
46 for(i = 0; i < cfg->files.length; ++i){
47 internal = git_vector_get(&cfg->files, i);
48 file = internal->file;
49 file->free(file);
50 free(internal);
51 }
52
53 git_vector_free(&cfg->files);
54 free(cfg);
55 }
56
57 static int config_backend_cmp(const void *a, const void *b)
58 {
59 const file_internal *bk_a = *(const file_internal **)(a);
60 const file_internal *bk_b = *(const file_internal **)(b);
61
62 return bk_b->priority - bk_a->priority;
63 }
64
65 int git_config_new(git_config **out)
66 {
67 git_config *cfg;
68
69 cfg = git__malloc(sizeof(git_config));
70 if (cfg == NULL)
71 return GIT_ENOMEM;
72
73 memset(cfg, 0x0, sizeof(git_config));
74
75 if (git_vector_init(&cfg->files, 3, config_backend_cmp) < 0) {
76 free(cfg);
77 return GIT_ENOMEM;
78 }
79
80 *out = cfg;
81
82 return GIT_SUCCESS;
83 }
84
85 int git_config_add_file_ondisk(git_config *cfg, const char *path, int priority)
86 {
87 git_config_file *file = NULL;
88 int error;
89
90 error = git_config_file__ondisk(&file, path);
91 if (error < GIT_SUCCESS)
92 return error;
93
94 error = git_config_add_file(cfg, file, priority);
95 if (error < GIT_SUCCESS) {
96 /*
97 * free manually; the file is not owned by the config
98 * instance yet and will not be freed on cleanup
99 */
100 file->free(file);
101 return error;
102 }
103
104 return GIT_SUCCESS;
105 }
106
107 int git_config_open_ondisk(git_config **cfg, const char *path)
108 {
109 int error;
110
111 error = git_config_new(cfg);
112 if (error < GIT_SUCCESS)
113 return error;
114
115 error = git_config_add_file_ondisk(*cfg, path, 1);
116 if (error < GIT_SUCCESS)
117 git_config_free(*cfg);
118
119 return error;
120 }
121
122 int git_config_add_file(git_config *cfg, git_config_file *file, int priority)
123 {
124 file_internal *internal;
125 int error;
126
127 assert(cfg && file);
128
129 if ((error = file->open(file)) < GIT_SUCCESS)
130 return git__rethrow(error, "Failed to open config file");
131
132 internal = git__malloc(sizeof(file_internal));
133 if (internal == NULL)
134 return GIT_ENOMEM;
135
136 internal->file = file;
137 internal->priority = priority;
138
139 if (git_vector_insert(&cfg->files, internal) < 0) {
140 free(internal);
141 return GIT_ENOMEM;
142 }
143
144 git_vector_sort(&cfg->files);
145 internal->file->cfg = cfg;
146
147 return GIT_SUCCESS;
148 }
149
150 /*
151 * Loop over all the variables
152 */
153
154 int git_config_foreach(git_config *cfg, int (*fn)(const char *, const char *, void *), void *data)
155 {
156 int ret = GIT_SUCCESS;
157 unsigned int i;
158 file_internal *internal;
159 git_config_file *file;
160
161 for(i = 0; i < cfg->files.length && ret == 0; ++i) {
162 internal = git_vector_get(&cfg->files, i);
163 file = internal->file;
164 ret = file->foreach(file, fn, data);
165 }
166
167 return ret;
168 }
169
170 int git_config_del(git_config *cfg, const char *name)
171 {
172 return git_config_set_string(cfg, name, NULL);
173 }
174
175 /**************
176 * Setters
177 **************/
178
179 int git_config_set_long(git_config *cfg, const char *name, long int value)
180 {
181 char str_value[32]; /* All numbers should fit in here */
182 snprintf(str_value, sizeof(str_value), "%ld", value);
183 return git_config_set_string(cfg, name, str_value);
184 }
185
186 int git_config_set_int(git_config *cfg, const char *name, int value)
187 {
188 return git_config_set_long(cfg, name, value);
189 }
190
191 int git_config_set_bool(git_config *cfg, const char *name, int value)
192 {
193 return git_config_set_string(cfg, name, value ? "true" : "false");
194 }
195
196 int git_config_set_string(git_config *cfg, const char *name, const char *value)
197 {
198 file_internal *internal;
199 git_config_file *file;
200
201 if (cfg->files.length == 0)
202 return git__throw(GIT_EINVALIDARGS, "Cannot set variable value; no files open in the `git_config` instance");
203
204 internal = git_vector_get(&cfg->files, 0);
205 file = internal->file;
206
207 return file->set(file, name, value);
208 }
209
210 /***********
211 * Getters
212 ***********/
213
214 int git_config_get_long(git_config *cfg, const char *name, long int *out)
215 {
216 const char *value, *num_end;
217 int ret;
218 long int num;
219
220 ret = git_config_get_string(cfg, name, &value);
221 if (ret < GIT_SUCCESS)
222 return git__rethrow(ret, "Failed to get value for %s", name);
223
224 ret = git__strtol32(&num, value, &num_end, 0);
225 if (ret < GIT_SUCCESS)
226 return git__rethrow(ret, "Failed to get value for %s", name);
227
228 switch (*num_end) {
229 case '\0':
230 break;
231 case 'k':
232 case 'K':
233 num *= 1024;
234 break;
235 case 'm':
236 case 'M':
237 num *= 1024 * 1024;
238 break;
239 case 'g':
240 case 'G':
241 num *= 1024 * 1024 * 1024;
242 break;
243 default:
244 return git__throw(GIT_EINVALIDTYPE, "Failed to get value for %s. Value is of invalid type", name);
245 }
246
247 *out = num;
248
249 return GIT_SUCCESS;
250 }
251
252 int git_config_get_int(git_config *cfg, const char *name, int *out)
253 {
254 long int tmp;
255 int ret;
256
257 ret = git_config_get_long(cfg, name, &tmp);
258
259 *out = (int) tmp;
260
261 return ret;
262 }
263
264 int git_config_get_bool(git_config *cfg, const char *name, int *out)
265 {
266 const char *value;
267 int error = GIT_SUCCESS;
268
269 error = git_config_get_string(cfg, name, &value);
270 if (error < GIT_SUCCESS)
271 return git__rethrow(error, "Failed to get value for %s", name);
272
273 /* A missing value means true */
274 if (value == NULL) {
275 *out = 1;
276 return GIT_SUCCESS;
277 }
278
279 if (!strcasecmp(value, "true") ||
280 !strcasecmp(value, "yes") ||
281 !strcasecmp(value, "on")) {
282 *out = 1;
283 return GIT_SUCCESS;
284 }
285 if (!strcasecmp(value, "false") ||
286 !strcasecmp(value, "no") ||
287 !strcasecmp(value, "off")) {
288 *out = 0;
289 return GIT_SUCCESS;
290 }
291
292 /* Try to parse it as an integer */
293 error = git_config_get_int(cfg, name, out);
294 if (error == GIT_SUCCESS)
295 *out = !!(*out);
296
297 if (error < GIT_SUCCESS)
298 return git__rethrow(error, "Failed to get value for %s", name);
299 return error;
300 }
301
302 int git_config_get_string(git_config *cfg, const char *name, const char **out)
303 {
304 file_internal *internal;
305 git_config_file *file;
306 int error = GIT_ENOTFOUND;
307 unsigned int i;
308
309 if (cfg->files.length == 0)
310 return git__throw(GIT_EINVALIDARGS, "Cannot get variable value; no files open in the `git_config` instance");
311
312 for (i = 0; i < cfg->files.length; ++i) {
313 internal = git_vector_get(&cfg->files, i);
314 file = internal->file;
315 if ((error = file->get(file, name, out)) == GIT_SUCCESS)
316 return GIT_SUCCESS;
317 }
318
319 return git__throw(error, "Config value '%s' not found", name);
320 }
321
322 int git_config_find_global(char *global_config_path)
323 {
324 const char *home;
325
326 home = getenv("HOME");
327
328 #ifdef GIT_WIN32
329 if (home == NULL)
330 home = getenv("USERPROFILE");
331 #endif
332
333 if (home == NULL)
334 return git__throw(GIT_EOSERR, "Failed to open global config file. Cannot locate the user's home directory");
335
336 git_path_join(global_config_path, home, GIT_CONFIG_FILENAME);
337
338 if (git_futils_exists(global_config_path) < GIT_SUCCESS)
339 return git__throw(GIT_EOSERR, "Failed to open global config file. The file does not exist");
340
341 return GIT_SUCCESS;
342 }
343
344 int git_config_open_global(git_config **out)
345 {
346 int error;
347 char global_path[GIT_PATH_MAX];
348
349 if ((error = git_config_find_global(global_path)) < GIT_SUCCESS)
350 return error;
351
352 return git_config_open_ondisk(out, global_path);
353 }
354