2 * Copyright (C) 2011-2014 Joel Rosdahl
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)
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
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
22 typedef bool (*conf_item_parser)(const char *str, void *result, char **errmsg);
23 typedef bool (*conf_item_verifier)(void *value, char **errmsg);
28 conf_item_parser parser;
30 conf_item_verifier verifier;
33 struct env_to_conf_item {
35 const char *conf_name;
39 parse_bool(const char *str, void *result, char **errmsg)
41 bool *value = (bool *)result;
43 if (str_eq(str, "true")) {
46 } else if (str_eq(str, "false")) {
50 *errmsg = format("not a boolean value: \"%s\"", str);
56 parse_env_string(const char *str, void *result, char **errmsg)
58 char **value = (char **)result;
60 *value = subst_env_in_string(str, errmsg);
61 return *value != NULL;
65 parse_size(const char *str, void *result, char **errmsg)
67 uint64_t *value = (uint64_t *)result;
70 if (parse_size_with_suffix(str, &size)) {
74 *errmsg = format("invalid size: \"%s\"", str);
80 parse_sloppiness(const char *str, void *result, char **errmsg)
82 unsigned *value = (unsigned *)result;
83 char *word, *p, *q, *saveptr = NULL;
90 while ((word = strtok_r(q, ", ", &saveptr))) {
91 if (str_eq(word, "file_macro")) {
92 *value |= SLOPPY_FILE_MACRO;
93 } else if (str_eq(word, "file_stat_matches")) {
94 *value |= SLOPPY_FILE_STAT_MATCHES;
95 } else if (str_eq(word, "include_file_ctime")) {
96 *value |= SLOPPY_INCLUDE_FILE_CTIME;
97 } else if (str_eq(word, "include_file_mtime")) {
98 *value |= SLOPPY_INCLUDE_FILE_MTIME;
99 } else if (str_eq(word, "pch_defines")) {
100 *value |= SLOPPY_PCH_DEFINES;
101 } else if (str_eq(word, "time_macros")) {
102 *value |= SLOPPY_TIME_MACROS;
104 *errmsg = format("unknown sloppiness: \"%s\"", word);
115 parse_string(const char *str, void *result, char **errmsg)
117 char **value = (char **)result;
120 *value = x_strdup(str);
125 parse_umask(const char *str, void *result, char **errmsg)
127 unsigned *value = (unsigned *)result;
129 if (str_eq(str, "")) {
134 *value = strtoul(str, &endptr, 8);
135 if (errno == 0 && *str != '\0' && *endptr == '\0') {
138 *errmsg = format("not an octal integer: \"%s\"", str);
144 parse_unsigned(const char *str, void *result, char **errmsg)
146 unsigned *value = (unsigned *)result;
150 x = strtol(str, &endptr, 10);
151 if (errno == 0 && x >= 0 && *str != '\0' && *endptr == '\0') {
155 *errmsg = format("invalid unsigned integer: \"%s\"", str);
161 bool_to_string(bool value)
163 return value ? "true" : "false";
167 verify_absolute_path(void *value, char **errmsg)
169 char **path = (char **)value;
171 if (str_eq(*path, "")) {
172 /* The empty string means "disable" in this case. */
174 } else if (is_absolute_path(*path)) {
177 *errmsg = format("not an absolute path: \"%s\"", *path);
183 verify_dir_levels(void *value, char **errmsg)
185 unsigned *levels = (unsigned *)value;
187 if (*levels >= 1 && *levels <= 8) {
190 *errmsg = format("cache directory levels must be between 1 and 8");
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
200 #include "confitems_lookup.c"
201 #include "envtoconfitems_lookup.c"
203 static const struct conf_item *
204 find_conf(const char *name)
206 return confitems_get(name, strlen(name));
209 static const struct env_to_conf_item *
210 find_env_to_conf(const char *name)
212 return envtoconfitems_get(name, strlen(name));
216 handle_conf_setting(struct conf *conf, const char *key, const char *value,
217 char **errmsg, bool from_env_variable, bool negate_boolean,
220 const struct conf_item *item;
222 item = find_conf(key);
224 *errmsg = format("unknown configuration option \"%s\"", key);
228 if (from_env_variable && item->parser == parse_bool) {
230 * Special rule for boolean settings from the environment: any value means
233 bool *value = (bool *)((char *)conf + item->offset);
234 *value = !negate_boolean;
238 if (!item->parser(value, (char *)conf + item->offset, errmsg)) {
241 if (item->verifier && !item->verifier((char *)conf + item->offset, errmsg)) {
246 conf->item_origins[item->number] = origin;
251 parse_line(const char *line, char **key, char **value, char **errmsg)
255 #define SKIP_WS(x) while (isspace(*x)) { ++x; }
262 if (*p == '\0' || *p == '#') {
266 while (isalpha(*q) || *q == '_') {
269 *key = x_strndup(p, q - p);
273 *errmsg = x_strdup("missing equal sign");
280 /* Skip leading whitespace. */
286 /* Skip trailing whitespace. */
287 while (isspace(q[-1])) {
290 *value = x_strndup(p, q - p);
297 /* Create a conf struct with default values. */
302 struct conf *conf = x_malloc(sizeof(*conf));
303 conf->base_dir = x_strdup("");
304 conf->cache_dir = format("%s/.ccache", get_home_directory());
305 conf->cache_dir_levels = 2;
306 conf->compiler = x_strdup("");
307 conf->compiler_check = x_strdup("mtime");
308 conf->compression = false;
309 conf->compression_level = 6;
310 conf->cpp_extension = x_strdup("");
311 conf->direct_mode = true;
312 conf->disable = false;
313 conf->extra_files_to_hash = x_strdup("");
314 conf->hard_link = false;
315 conf->hash_dir = false;
316 conf->log_file = x_strdup("");
318 conf->max_size = (uint64_t)5 * 1000 * 1000 * 1000;
319 conf->path = x_strdup("");
320 conf->prefix_command = x_strdup("");
321 conf->read_only = false;
322 conf->read_only_direct = false;
323 conf->recache = false;
324 conf->run_second_cpp = false;
325 conf->sloppiness = 0;
327 conf->temporary_dir = x_strdup("");
328 conf->umask = UINT_MAX; /* default: don't set umask */
330 conf->item_origins = x_malloc(CONFITEMS_TOTAL_KEYWORDS * sizeof(char *));
331 for (i = 0; i < CONFITEMS_TOTAL_KEYWORDS; ++i) {
332 conf->item_origins[i] = "default";
338 conf_free(struct conf *conf)
343 free(conf->base_dir);
344 free(conf->cache_dir);
345 free(conf->compiler);
346 free(conf->compiler_check);
347 free(conf->cpp_extension);
348 free(conf->extra_files_to_hash);
349 free(conf->log_file);
351 free(conf->prefix_command);
352 free(conf->temporary_dir);
353 free(conf->item_origins);
357 /* Note: The path pointer is stored in conf, so path must outlive conf. */
359 conf_read(struct conf *conf, const char *path, char **errmsg)
364 unsigned line_number;
369 f = fopen(path, "r");
371 *errmsg = format("%s: %s", path, strerror(errno));
376 while (fgets(buf, sizeof(buf), f)) {
377 char *errmsg2, *key, *value;
380 ok = parse_line(buf, &key, &value, &errmsg2);
381 if (ok && key) { /* key == NULL if comment or blank line */
382 ok = handle_conf_setting(conf, key, value, &errmsg2, false, false, path);
387 *errmsg = format("%s:%u: %s", path, line_number, errmsg2);
394 *errmsg = x_strdup(strerror(errno));
404 conf_update_from_environment(struct conf *conf, char **errmsg)
410 const struct env_to_conf_item *env_to_conf_item;
414 for (p = environ; *p; ++p) {
415 if (!str_startswith(*p, "CCACHE_")) {
423 if (str_startswith(*p + 7, "NO")) {
430 key = x_strndup(*p + key_start, q - *p - key_start);
432 ++q; /* Now points to the value. */
434 env_to_conf_item = find_env_to_conf(key);
435 if (!env_to_conf_item) {
440 if (!handle_conf_setting(
441 conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
443 *errmsg = format("%s: %s", key, errmsg2);
456 conf_set_value_in_file(const char *path, const char *key, const char *value,
459 FILE *infile, *outfile;
463 const struct conf_item *item;
465 item = find_conf(key);
467 *errmsg = format("unknown configuration option \"%s\"", key);
471 infile = fopen(path, "r");
473 *errmsg = format("%s: %s", path, strerror(errno));
477 outpath = format("%s.tmp", path);
478 outfile = create_tmp_file(&outpath, "w");
480 *errmsg = format("%s: %s", outpath, strerror(errno));
487 while (fgets(buf, sizeof(buf), infile)) {
488 char *errmsg2, *key2, *value2;
490 ok = parse_line(buf, &key2, &value2, &errmsg2);
491 if (ok && key2 && str_eq(key2, key)) {
493 fprintf(outfile, "%s = %s\n", key, value);
502 fprintf(outfile, "%s = %s\n", key, value);
507 if (x_rename(outpath, path) != 0) {
508 *errmsg = format("rename %s to %s: %s", outpath, path, strerror(errno));
517 conf_print_items(struct conf *conf,
518 void (*printer)(const char *descr, const char *origin,
522 char *s = x_strdup("");
525 reformat(&s, "base_dir = %s", conf->base_dir);
526 printer(s, conf->item_origins[find_conf("base_dir")->number], context);
528 reformat(&s, "cache_dir = %s", conf->cache_dir);
529 printer(s, conf->item_origins[find_conf("cache_dir")->number], context);
531 reformat(&s, "cache_dir_levels = %u", conf->cache_dir_levels);
532 printer(s, conf->item_origins[find_conf("cache_dir_levels")->number],
535 reformat(&s, "compiler = %s", conf->compiler);
536 printer(s, conf->item_origins[find_conf("compiler")->number], context);
538 reformat(&s, "compiler_check = %s", conf->compiler_check);
539 printer(s, conf->item_origins[find_conf("compiler_check")->number], context);
541 reformat(&s, "compression = %s", bool_to_string(conf->compression));
542 printer(s, conf->item_origins[find_conf("compression")->number], context);
544 reformat(&s, "compression_level = %u", conf->compression_level);
545 printer(s, conf->item_origins[find_conf("compression_level")->number],
548 reformat(&s, "cpp_extension = %s", conf->cpp_extension);
549 printer(s, conf->item_origins[find_conf("cpp_extension")->number], context);
551 reformat(&s, "direct_mode = %s", bool_to_string(conf->direct_mode));
552 printer(s, conf->item_origins[find_conf("direct_mode")->number], context);
554 reformat(&s, "disable = %s", bool_to_string(conf->disable));
555 printer(s, conf->item_origins[find_conf("disable")->number], context);
557 reformat(&s, "extra_files_to_hash = %s", conf->extra_files_to_hash);
558 printer(s, conf->item_origins[find_conf("extra_files_to_hash")->number],
561 reformat(&s, "hard_link = %s", bool_to_string(conf->hard_link));
562 printer(s, conf->item_origins[find_conf("hard_link")->number], context);
564 reformat(&s, "hash_dir = %s", bool_to_string(conf->hash_dir));
565 printer(s, conf->item_origins[find_conf("hash_dir")->number], context);
567 reformat(&s, "log_file = %s", conf->log_file);
568 printer(s, conf->item_origins[find_conf("log_file")->number], context);
570 reformat(&s, "max_files = %u", conf->max_files);
571 printer(s, conf->item_origins[find_conf("max_files")->number], context);
573 s2 = format_parsable_size_with_suffix(conf->max_size);
574 reformat(&s, "max_size = %s", s2);
575 printer(s, conf->item_origins[find_conf("max_size")->number], context);
578 reformat(&s, "path = %s", conf->path);
579 printer(s, conf->item_origins[find_conf("path")->number], context);
581 reformat(&s, "prefix_command = %s", conf->prefix_command);
582 printer(s, conf->item_origins[find_conf("prefix_command")->number], context);
584 reformat(&s, "read_only = %s", bool_to_string(conf->read_only));
585 printer(s, conf->item_origins[find_conf("read_only")->number], context);
587 reformat(&s, "read_only_direct = %s", bool_to_string(conf->read_only_direct));
588 printer(s, conf->item_origins[find_conf("read_only_direct")->number],
591 reformat(&s, "recache = %s", bool_to_string(conf->recache));
592 printer(s, conf->item_origins[find_conf("recache")->number], context);
594 reformat(&s, "run_second_cpp = %s", bool_to_string(conf->run_second_cpp));
595 printer(s, conf->item_origins[find_conf("run_second_cpp")->number], context);
597 reformat(&s, "sloppiness = ");
598 if (conf->sloppiness & SLOPPY_FILE_MACRO) {
599 reformat(&s, "%sfile_macro, ", s);
601 if (conf->sloppiness & SLOPPY_INCLUDE_FILE_MTIME) {
602 reformat(&s, "%sinclude_file_mtime, ", s);
604 if (conf->sloppiness & SLOPPY_INCLUDE_FILE_CTIME) {
605 reformat(&s, "%sinclude_file_ctime, ", s);
607 if (conf->sloppiness & SLOPPY_TIME_MACROS) {
608 reformat(&s, "%stime_macros, ", s);
610 if (conf->sloppiness & SLOPPY_PCH_DEFINES) {
611 reformat(&s, "%spch_defines, ", s);
613 if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
614 reformat(&s, "%sfile_stat_matches, ", s);
616 if (conf->sloppiness) {
617 /* Strip last ", ". */
618 s[strlen(s) - 2] = '\0';
620 printer(s, conf->item_origins[find_conf("sloppiness")->number], context);
622 reformat(&s, "stats = %s", bool_to_string(conf->stats));
623 printer(s, conf->item_origins[find_conf("stats")->number], context);
625 reformat(&s, "temporary_dir = %s", conf->temporary_dir);
626 printer(s, conf->item_origins[find_conf("temporary_dir")->number], context);
628 if (conf->umask == UINT_MAX) {
629 reformat(&s, "umask = ");
631 reformat(&s, "umask = %03o", conf->umask);
633 printer(s, conf->item_origins[find_conf("umask")->number], context);
635 reformat(&s, "unify = %s", bool_to_string(conf->unify));
636 printer(s, conf->item_origins[find_conf("unify")->number], context);