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