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