Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2011-2014 Joel Rosdahl
3 : : *
4 : : * This program is free software; you can redistribute it and/or modify it
5 : : * under the terms of the GNU General Public License as published by the Free
6 : : * Software Foundation; either version 3 of the License, or (at your option)
7 : : * any later version.
8 : : *
9 : : * This program is distributed in the hope that it will be useful, but WITHOUT
10 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 : : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 : : * more details.
13 : : *
14 : : * You should have received a copy of the GNU General Public License along with
15 : : * this program; if not, write to the Free Software Foundation, Inc., 51
16 : : * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 : : */
18 : :
19 : : #include "conf.h"
20 : : #include "ccache.h"
21 : :
22 : : typedef bool (*conf_item_parser)(const char *str, void *result, char **errmsg);
23 : : typedef bool (*conf_item_verifier)(void *value, char **errmsg);
24 : :
25 : : struct conf_item {
26 : : const char *name;
27 : : size_t number;
28 : : conf_item_parser parser;
29 : : size_t offset;
30 : : conf_item_verifier verifier;
31 : : };
32 : :
33 : : struct env_to_conf_item {
34 : : const char *env_name;
35 : : const char *conf_name;
36 : : };
37 : :
38 : : static bool
39 : 13 : parse_bool(const char *str, void *result, char **errmsg)
40 : : {
41 : 13 : bool *value = (bool *)result;
42 : :
43 [ + + ]: 13 : if (str_eq(str, "true")) {
44 : 9 : *value = true;
45 : 9 : return true;
46 [ + + ]: 4 : } else if (str_eq(str, "false")) {
47 : 2 : *value = false;
48 : 2 : return true;
49 : : } else {
50 : 2 : *errmsg = format("not a boolean value: \"%s\"", str);
51 : 13 : return false;
52 : : }
53 : : }
54 : :
55 : : static bool
56 : 25 : parse_env_string(const char *str, void *result, char **errmsg)
57 : : {
58 : 25 : char **value = (char **)result;
59 : 25 : free(*value);
60 : 25 : *value = subst_env_in_string(str, errmsg);
61 : 25 : return *value;
62 : : }
63 : :
64 : : static bool
65 : 2 : parse_size(const char *str, void *result, char **errmsg)
66 : : {
67 : 2 : uint64_t *value = (uint64_t *)result;
68 : : uint64_t size;
69 : 2 : *errmsg = NULL;
70 [ + + ]: 2 : if (parse_size_with_suffix(str, &size)) {
71 : 1 : *value = size;
72 : 1 : return true;
73 : : } else {
74 : 1 : *errmsg = format("invalid size: \"%s\"", str);
75 : 2 : return false;
76 : : }
77 : : }
78 : :
79 : : static bool
80 : 9 : parse_sloppiness(const char *str, void *result, char **errmsg)
81 : : {
82 : 9 : unsigned *value = (unsigned *)result;
83 : 9 : char *word, *p, *q, *saveptr = NULL;
84 : :
85 [ - + ]: 9 : if (!str) {
86 : 0 : return *value;
87 : : }
88 : 9 : p = x_strdup(str);
89 : 9 : q = p;
90 [ + + ]: 23 : while ((word = strtok_r(q, ", ", &saveptr))) {
91 [ + + ]: 15 : if (str_eq(word, "file_macro")) {
92 : 2 : *value |= SLOPPY_FILE_MACRO;
93 [ + + ]: 13 : } else if (str_eq(word, "file_stat_matches")) {
94 : 1 : *value |= SLOPPY_FILE_STAT_MATCHES;
95 [ + + ]: 12 : } else if (str_eq(word, "include_file_ctime")) {
96 : 8 : *value |= SLOPPY_INCLUDE_FILE_CTIME;
97 [ + + ]: 4 : } else if (str_eq(word, "include_file_mtime")) {
98 : 1 : *value |= SLOPPY_INCLUDE_FILE_MTIME;
99 [ + + ]: 3 : } else if (str_eq(word, "pch_defines")) {
100 : 1 : *value |= SLOPPY_PCH_DEFINES;
101 [ + + ]: 2 : } else if (str_eq(word, "time_macros")) {
102 : 1 : *value |= SLOPPY_TIME_MACROS;
103 : : } else {
104 : 1 : *errmsg = format("unknown sloppiness: \"%s\"", word);
105 : 1 : free(p);
106 : 1 : return false;
107 : : }
108 : 14 : q = NULL;
109 : : }
110 : 8 : free(p);
111 : 9 : return true;
112 : : }
113 : :
114 : : static bool
115 : 3 : parse_string(const char *str, void *result, char **errmsg)
116 : : {
117 : 3 : char **value = (char **)result;
118 : : (void)errmsg;
119 : 3 : free(*value);
120 : 3 : *value = x_strdup(str);
121 : 3 : return true;
122 : : }
123 : :
124 : : static bool
125 : 2 : parse_umask(const char *str, void *result, char **errmsg)
126 : : {
127 : 2 : unsigned *value = (unsigned *)result;
128 : : char *endptr;
129 [ + + ]: 2 : if (str_eq(str, "")) {
130 : 1 : *value = UINT_MAX;
131 : 1 : return true;
132 : : }
133 : 1 : errno = 0;
134 : 1 : *value = strtoul(str, &endptr, 8);
135 [ + - ][ + - ]: 1 : if (errno == 0 && *str != '\0' && *endptr == '\0') {
[ + - ]
136 : 1 : return true;
137 : : } else {
138 : 0 : *errmsg = format("not an octal integer: \"%s\"", str);
139 : 2 : return false;
140 : : }
141 : : }
142 : :
143 : : static bool
144 : 8 : parse_unsigned(const char *str, void *result, char **errmsg)
145 : : {
146 : 8 : unsigned *value = (unsigned *)result;
147 : : long x;
148 : : char *endptr;
149 : 8 : errno = 0;
150 : 8 : x = strtol(str, &endptr, 10);
151 [ + - ][ + + ]: 8 : if (errno == 0 && x >= 0 && *str != '\0' && *endptr == '\0') {
[ + + ][ + + ]
152 : 5 : *value = x;
153 : 5 : return true;
154 : : } else {
155 : 3 : *errmsg = format("invalid unsigned integer: \"%s\"", str);
156 : 8 : return false;
157 : : }
158 : : }
159 : :
160 : : static const char*
161 : 22 : bool_to_string(bool value)
162 : : {
163 [ + + ]: 22 : return value ? "true" : "false";
164 : : }
165 : :
166 : : static bool
167 : 3 : verify_absolute_path(void *value, char **errmsg)
168 : : {
169 : 3 : char **path = (char **)value;
170 [ - + ]: 3 : assert(*path);
171 [ + + ]: 3 : if (str_eq(*path, "")) {
172 : : /* The empty string means "disable" in this case. */
173 : 1 : return true;
174 [ + + ]: 2 : } else if (is_absolute_path(*path)) {
175 : 1 : return true;
176 : : } else {
177 : 1 : *errmsg = format("not an absolute path: \"%s\"", *path);
178 : 3 : return false;
179 : : }
180 : : }
181 : :
182 : : static bool
183 : 3 : verify_dir_levels(void *value, char **errmsg)
184 : : {
185 : 3 : unsigned *levels = (unsigned *)value;
186 [ - + ]: 3 : assert(levels);
187 [ + + ][ + + ]: 3 : if (*levels >= 1 && *levels <= 8) {
188 : 1 : return true;
189 : : } else {
190 : 2 : *errmsg = format("cache directory levels must be between 1 and 8");
191 : 3 : return false;
192 : : }
193 : : }
194 : :
195 : : #define ITEM(name, type) \
196 : : parse_##type, offsetof(struct conf, name), NULL
197 : : #define ITEM_V(name, type, verification) \
198 : : parse_##type, offsetof(struct conf, name), verify_##verification
199 : :
200 : : #include "confitems_lookup.c"
201 : : #include "envtoconfitems_lookup.c"
202 : :
203 : : static const struct conf_item *
204 : 130 : find_conf(const char *name)
205 : : {
206 : 130 : return confitems_get(name, strlen(name));
207 : : }
208 : :
209 : : static const struct env_to_conf_item *
210 : 41 : find_env_to_conf(const char *name)
211 : : {
212 : 41 : return envtoconfitems_get(name, strlen(name));
213 : : }
214 : :
215 : : static bool
216 : 74 : handle_conf_setting(struct conf *conf, const char *key, const char *value,
217 : : char **errmsg, bool from_env_variable, bool negate_boolean,
218 : : const char *origin)
219 : : {
220 : : const struct conf_item *item;
221 : :
222 : 74 : item = find_conf(key);
223 [ + + ]: 74 : if (!item) {
224 : 1 : *errmsg = format("unknown configuration option \"%s\"", key);
225 : 1 : return false;
226 : : }
227 : :
228 [ + + ][ + + ]: 73 : if (from_env_variable && item->parser == parse_bool) {
229 : : /*
230 : : * Special rule for boolean settings from the environment: any value means
231 : : * true.
232 : : */
233 : 11 : bool *value = (bool *)((char *)conf + item->offset);
234 : 11 : *value = !negate_boolean;
235 : 11 : goto out;
236 : : }
237 : :
238 [ + + ]: 62 : if (!item->parser(value, (char *)conf + item->offset, errmsg)) {
239 : 8 : return false;
240 : : }
241 [ + + ][ + + ]: 54 : if (item->verifier && !item->verifier((char *)conf + item->offset, errmsg)) {
242 : 3 : return false;
243 : : }
244 : :
245 : : out:
246 : 62 : conf->item_origins[item->number] = origin;
247 : 74 : return true;
248 : : }
249 : :
250 : : static bool
251 : 50 : parse_line(const char *line, char **key, char **value, char **errmsg)
252 : : {
253 : : const char *p, *q;
254 : :
255 : : #define SKIP_WS(x) while (isspace(*x)) { ++x; }
256 : :
257 : 50 : *key = NULL;
258 : 50 : *value = NULL;
259 : :
260 : 50 : p = line;
261 [ + + ]: 57 : SKIP_WS(p);
262 [ + + ][ + + ]: 50 : if (*p == '\0' || *p == '#') {
263 : 4 : return true;
264 : : }
265 : 46 : q = p;
266 [ + + ][ + + ]: 470 : while (isalpha(*q) || *q == '_') {
267 : 424 : ++q;
268 : : }
269 : 46 : *key = x_strndup(p, q - p);
270 : 46 : p = q;
271 [ + + ]: 87 : SKIP_WS(p);
272 [ + + ]: 46 : if (*p != '=') {
273 : 1 : *errmsg = x_strdup("missing equal sign");
274 : 1 : free(*key);
275 : 1 : *key = NULL;
276 : 1 : return false;
277 : : }
278 : 45 : ++p;
279 : :
280 : : /* Skip leading whitespace. */
281 [ + + ]: 90 : SKIP_WS(p);
282 : 45 : q = p;
283 [ + + ]: 404 : while (*q) {
284 : 359 : ++q;
285 : : }
286 : : /* Skip trailing whitespace. */
287 [ + + ]: 80 : while (isspace(q[-1])) {
288 : 35 : --q;
289 : : }
290 : 45 : *value = x_strndup(p, q - p);
291 : :
292 : 50 : return true;
293 : :
294 : : #undef SKIP_WS
295 : : }
296 : :
297 : : /* Create a conf struct with default values. */
298 : : struct conf *
299 : 108 : conf_create(void)
300 : : {
301 : : size_t i;
302 : 108 : struct conf *conf = x_malloc(sizeof(*conf));
303 : 108 : conf->base_dir = x_strdup("");
304 : 108 : conf->cache_dir = format("%s/.ccache", get_home_directory());
305 : 108 : conf->cache_dir_levels = 2;
306 : 108 : conf->compiler = x_strdup("");
307 : 108 : conf->compiler_check = x_strdup("mtime");
308 : 108 : conf->compression = false;
309 : 108 : conf->compression_level = 6;
310 : 108 : conf->cpp_extension = x_strdup("");
311 : 108 : conf->direct_mode = true;
312 : 108 : conf->disable = false;
313 : 108 : conf->extra_files_to_hash = x_strdup("");
314 : 108 : conf->hard_link = false;
315 : 108 : conf->hash_dir = false;
316 : 108 : conf->log_file = x_strdup("");
317 : 108 : conf->max_files = 0;
318 : 108 : conf->max_size = (uint64_t)5 * 1000 * 1000 * 1000;
319 : 108 : conf->path = x_strdup("");
320 : 108 : conf->prefix_command = x_strdup("");
321 : 108 : conf->read_only = false;
322 : 108 : conf->read_only_direct = false;
323 : 108 : conf->recache = false;
324 : 108 : conf->run_second_cpp = false;
325 : 108 : conf->sloppiness = 0;
326 : 108 : conf->stats = true;
327 : 108 : conf->temporary_dir = x_strdup("");
328 : 108 : conf->umask = UINT_MAX; /* default: don't set umask */
329 : 108 : conf->unify = false;
330 : 108 : conf->item_origins = x_malloc(CONFITEMS_TOTAL_KEYWORDS * sizeof(char *));
331 [ + + ]: 3024 : for (i = 0; i < CONFITEMS_TOTAL_KEYWORDS; ++i) {
332 : 2916 : conf->item_origins[i] = "default";
333 : : }
334 : 108 : return conf;
335 : : }
336 : :
337 : : void
338 : 108 : conf_free(struct conf *conf)
339 : : {
340 [ + + ]: 108 : if (!conf) {
341 : 8 : return;
342 : : }
343 : 100 : free(conf->base_dir);
344 : 100 : free(conf->cache_dir);
345 : 100 : free(conf->compiler);
346 : 100 : free(conf->compiler_check);
347 : 100 : free(conf->cpp_extension);
348 : 100 : free(conf->extra_files_to_hash);
349 : 100 : free(conf->log_file);
350 : 100 : free(conf->path);
351 : 100 : free(conf->prefix_command);
352 : 100 : free(conf->temporary_dir);
353 : 100 : free(conf->item_origins);
354 : 108 : free(conf);
355 : : }
356 : :
357 : : /* Note: The path pointer is stored in conf, so path must outlive conf. */
358 : : bool
359 : 23 : conf_read(struct conf *conf, const char *path, char **errmsg)
360 : : {
361 : : FILE *f;
362 : : char buf[10000];
363 : 23 : bool result = true;
364 : : unsigned line_number;
365 : :
366 [ - + ]: 23 : assert(errmsg);
367 : 23 : *errmsg = NULL;
368 : :
369 : 23 : f = fopen(path, "r");
370 [ - + ]: 23 : if (!f) {
371 : 0 : *errmsg = format("%s: %s", path, strerror(errno));
372 : 0 : return false;
373 : : }
374 : :
375 : 23 : line_number = 0;
376 [ + + ]: 57 : while (fgets(buf, sizeof(buf), f)) {
377 : : char *errmsg2, *key, *value;
378 : : bool ok;
379 : 47 : ++line_number;
380 : 47 : ok = parse_line(buf, &key, &value, &errmsg2);
381 [ + + ][ + + ]: 47 : if (ok && key) { /* key == NULL if comment or blank line */
382 : 42 : ok = handle_conf_setting(conf, key, value, &errmsg2, false, false, path);
383 : : }
384 : 47 : free(key);
385 : 47 : free(value);
386 [ + + ]: 47 : if (!ok) {
387 : 13 : *errmsg = format("%s:%u: %s", path, line_number, errmsg2);
388 : 13 : free(errmsg2);
389 : 13 : result = false;
390 : 13 : goto out;
391 : : }
392 : : }
393 [ - + ]: 10 : if (ferror(f)) {
394 : 0 : *errmsg = x_strdup(strerror(errno));
395 : 0 : result = false;
396 : : }
397 : :
398 : : out:
399 : 23 : fclose(f);
400 : 23 : return result;
401 : : }
402 : :
403 : : bool
404 : 9 : conf_update_from_environment(struct conf *conf, char **errmsg)
405 : : {
406 : : char **p;
407 : : char *q;
408 : : char *key;
409 : : char *errmsg2;
410 : : const struct env_to_conf_item *env_to_conf_item;
411 : : bool negate;
412 : : size_t key_start;
413 : :
414 [ + + ]: 282 : for (p = environ; *p; ++p) {
415 [ + + ]: 273 : if (!str_startswith(*p, "CCACHE_")) {
416 : 232 : continue;
417 : : }
418 : 41 : q = strchr(*p, '=');
419 [ - + ]: 41 : if (!q) {
420 : 0 : continue;
421 : : }
422 : :
423 [ + + ]: 41 : if (str_startswith(*p + 7, "NO")) {
424 : 8 : negate = true;
425 : 8 : key_start = 9;
426 : : } else {
427 : 33 : negate = false;
428 : 33 : key_start = 7;
429 : : }
430 : 41 : key = x_strndup(*p + key_start, q - *p - key_start);
431 : :
432 : 41 : ++q; /* Now points to the value. */
433 : :
434 : 41 : env_to_conf_item = find_env_to_conf(key);
435 [ + + ]: 41 : if (!env_to_conf_item) {
436 : 9 : free(key);
437 : 9 : continue;
438 : : }
439 : :
440 [ - + ]: 32 : if (!handle_conf_setting(
441 : : conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
442 : : "environment")) {
443 : 0 : *errmsg = format("%s: %s", key, errmsg2);
444 : 0 : free(errmsg2);
445 : 0 : free(key);
446 : 0 : return false;
447 : : }
448 : :
449 : 32 : free(key);
450 : : }
451 : :
452 : 9 : return true;
453 : : }
454 : :
455 : : bool
456 : 2 : conf_set_value_in_file(const char *path, const char *key, const char *value,
457 : : char **errmsg)
458 : : {
459 : : FILE *infile, *outfile;
460 : : char *outpath;
461 : : char buf[10000];
462 : : bool found;
463 : : const struct conf_item *item;
464 : :
465 : 2 : item = find_conf(key);
466 [ - + ]: 2 : if (!item) {
467 : 0 : *errmsg = format("unknown configuration option \"%s\"", key);
468 : 0 : return false;
469 : : }
470 : :
471 : 2 : infile = fopen(path, "r");
472 [ - + ]: 2 : if (!infile) {
473 : 0 : *errmsg = format("%s: %s", path, strerror(errno));
474 : 0 : return false;
475 : : }
476 : :
477 : 2 : outpath = format("%s.tmp", path);
478 : 2 : outfile = create_tmp_file(&outpath, "w");
479 [ - + ]: 2 : if (!outfile) {
480 : 0 : *errmsg = format("%s: %s", outpath, strerror(errno));
481 : 0 : free(outpath);
482 : 0 : fclose(infile);
483 : 0 : return false;
484 : : }
485 : :
486 : 2 : found = false;
487 [ + + ]: 5 : while (fgets(buf, sizeof(buf), infile)) {
488 : : char *errmsg2, *key2, *value2;
489 : : bool ok;
490 : 3 : ok = parse_line(buf, &key2, &value2, &errmsg2);
491 [ + - ][ + - ]: 4 : if (ok && key2 && str_eq(key2, key)) {
[ + + ]
492 : 1 : found = true;
493 : 1 : fprintf(outfile, "%s = %s\n", key, value);
494 : : } else {
495 : 2 : fputs(buf, outfile);
496 : : }
497 : 3 : free(key2);
498 : 3 : free(value2);
499 : : }
500 : :
501 [ + + ]: 2 : if (!found) {
502 : 1 : fprintf(outfile, "%s = %s\n", key, value);
503 : : }
504 : :
505 : 2 : fclose(infile);
506 : 2 : fclose(outfile);
507 [ - + ]: 2 : if (x_rename(outpath, path) != 0) {
508 : 0 : *errmsg = format("rename %s to %s: %s", outpath, path, strerror(errno));
509 : 0 : return false;
510 : : }
511 : 2 : free(outpath);
512 : :
513 : 2 : return true;
514 : : }
515 : :
516 : : bool
517 : 2 : conf_print_items(struct conf *conf,
518 : : void (*printer)(const char *descr, const char *origin,
519 : : void *context),
520 : : void *context)
521 : : {
522 : 2 : char *s = x_strdup("");
523 : : char *s2;
524 : :
525 : 2 : reformat(&s, "base_dir = %s", conf->base_dir);
526 : 2 : printer(s, conf->item_origins[find_conf("base_dir")->number], context);
527 : :
528 : 2 : reformat(&s, "cache_dir = %s", conf->cache_dir);
529 : 2 : printer(s, conf->item_origins[find_conf("cache_dir")->number], context);
530 : :
531 : 2 : reformat(&s, "cache_dir_levels = %u", conf->cache_dir_levels);
532 : 2 : printer(s, conf->item_origins[find_conf("cache_dir_levels")->number],
533 : : context);
534 : :
535 : 2 : reformat(&s, "compiler = %s", conf->compiler);
536 : 2 : printer(s, conf->item_origins[find_conf("compiler")->number], context);
537 : :
538 : 2 : reformat(&s, "compiler_check = %s", conf->compiler_check);
539 : 2 : printer(s, conf->item_origins[find_conf("compiler_check")->number], context);
540 : :
541 : 2 : reformat(&s, "compression = %s", bool_to_string(conf->compression));
542 : 2 : printer(s, conf->item_origins[find_conf("compression")->number], context);
543 : :
544 : 2 : reformat(&s, "compression_level = %u", conf->compression_level);
545 : 2 : printer(s, conf->item_origins[find_conf("compression_level")->number],
546 : : context);
547 : :
548 : 2 : reformat(&s, "cpp_extension = %s", conf->cpp_extension);
549 : 2 : printer(s, conf->item_origins[find_conf("cpp_extension")->number], context);
550 : :
551 : 2 : reformat(&s, "direct_mode = %s", bool_to_string(conf->direct_mode));
552 : 2 : printer(s, conf->item_origins[find_conf("direct_mode")->number], context);
553 : :
554 : 2 : reformat(&s, "disable = %s", bool_to_string(conf->disable));
555 : 2 : printer(s, conf->item_origins[find_conf("disable")->number], context);
556 : :
557 : 2 : reformat(&s, "extra_files_to_hash = %s", conf->extra_files_to_hash);
558 : 2 : printer(s, conf->item_origins[find_conf("extra_files_to_hash")->number],
559 : : context);
560 : :
561 : 2 : reformat(&s, "hard_link = %s", bool_to_string(conf->hard_link));
562 : 2 : printer(s, conf->item_origins[find_conf("hard_link")->number], context);
563 : :
564 : 2 : reformat(&s, "hash_dir = %s", bool_to_string(conf->hash_dir));
565 : 2 : printer(s, conf->item_origins[find_conf("hash_dir")->number], context);
566 : :
567 : 2 : reformat(&s, "log_file = %s", conf->log_file);
568 : 2 : printer(s, conf->item_origins[find_conf("log_file")->number], context);
569 : :
570 : 2 : reformat(&s, "max_files = %u", conf->max_files);
571 : 2 : printer(s, conf->item_origins[find_conf("max_files")->number], context);
572 : :
573 : 2 : s2 = format_parsable_size_with_suffix(conf->max_size);
574 : 2 : reformat(&s, "max_size = %s", s2);
575 : 2 : printer(s, conf->item_origins[find_conf("max_size")->number], context);
576 : 2 : free(s2);
577 : :
578 : 2 : reformat(&s, "path = %s", conf->path);
579 : 2 : printer(s, conf->item_origins[find_conf("path")->number], context);
580 : :
581 : 2 : reformat(&s, "prefix_command = %s", conf->prefix_command);
582 : 2 : printer(s, conf->item_origins[find_conf("prefix_command")->number], context);
583 : :
584 : 2 : reformat(&s, "read_only = %s", bool_to_string(conf->read_only));
585 : 2 : printer(s, conf->item_origins[find_conf("read_only")->number], context);
586 : :
587 : 2 : reformat(&s, "read_only_direct = %s", bool_to_string(conf->read_only_direct));
588 : 2 : printer(s, conf->item_origins[find_conf("read_only_direct")->number],
589 : : context);
590 : :
591 : 2 : reformat(&s, "recache = %s", bool_to_string(conf->recache));
592 : 2 : printer(s, conf->item_origins[find_conf("recache")->number], context);
593 : :
594 : 2 : reformat(&s, "run_second_cpp = %s", bool_to_string(conf->run_second_cpp));
595 : 2 : printer(s, conf->item_origins[find_conf("run_second_cpp")->number], context);
596 : :
597 : 2 : reformat(&s, "sloppiness = ");
598 [ + + ]: 2 : if (conf->sloppiness & SLOPPY_FILE_MACRO) {
599 : 1 : reformat(&s, "%sfile_macro, ", s);
600 : : }
601 [ + + ]: 2 : if (conf->sloppiness & SLOPPY_INCLUDE_FILE_MTIME) {
602 : 1 : reformat(&s, "%sinclude_file_mtime, ", s);
603 : : }
604 [ + - ]: 2 : if (conf->sloppiness & SLOPPY_INCLUDE_FILE_CTIME) {
605 : 2 : reformat(&s, "%sinclude_file_ctime, ", s);
606 : : }
607 [ + + ]: 2 : if (conf->sloppiness & SLOPPY_TIME_MACROS) {
608 : 1 : reformat(&s, "%stime_macros, ", s);
609 : : }
610 [ + + ]: 2 : if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
611 : 1 : reformat(&s, "%sfile_stat_matches, ", s);
612 : : }
613 [ + - ]: 2 : if (conf->sloppiness) {
614 : : /* Strip last ", ". */
615 : 2 : s[strlen(s) - 2] = '\0';
616 : : }
617 : 2 : printer(s, conf->item_origins[find_conf("sloppiness")->number], context);
618 : :
619 : 2 : reformat(&s, "stats = %s", bool_to_string(conf->stats));
620 : 2 : printer(s, conf->item_origins[find_conf("stats")->number], context);
621 : :
622 : 2 : reformat(&s, "temporary_dir = %s", conf->temporary_dir);
623 : 2 : printer(s, conf->item_origins[find_conf("temporary_dir")->number], context);
624 : :
625 [ + + ]: 2 : if (conf->umask == UINT_MAX) {
626 : 1 : reformat(&s, "umask = ");
627 : : } else {
628 : 1 : reformat(&s, "umask = %03o", conf->umask);
629 : : }
630 : 2 : printer(s, conf->item_origins[find_conf("umask")->number], context);
631 : :
632 : 2 : reformat(&s, "unify = %s", bool_to_string(conf->unify));
633 : 2 : printer(s, conf->item_origins[find_conf("unify")->number], context);
634 : :
635 : 2 : free(s);
636 : 2 : return true;
637 : : }
|