]>
Commit | Line | Data |
---|---|---|
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 |
35 | typedef struct { |
36 | git_config_backend *backend; | |
37 | int priority; | |
38 | } backend_internal; | |
3d23b74a | 39 | |
c0335005 | 40 | int 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 |
73 | int 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 | 87 | void 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 | 104 | static 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 | 112 | int 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 |
132 | int 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 | 160 | int 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 | 185 | int 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 |
205 | int 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 |
210 | int 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 |
222 | int 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 | 239 | int 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 |
277 | int 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 | 289 | int 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 |
325 | int 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 |