--
--
-*CCACHE_COMPRESS*::
-
- If you set the environment variable *CCACHE_COMPRESS* then ccache will
- compress object files and other compiler output it puts in the cache.
- However, this setting has no effect on how files are retrieved from the
- cache; compressed and uncompressed results will still be usable regardless
- of this setting.
-
-*CCACHE_COMPRESS_LEVEL*::
-
- This environment variable determines the level at which ccache will
- compress object files. It only has effect if *CCACHE_COMPRESS* is also
- set. The value defaults to 6, and must be no lower than 1 (fastest, worst
- compression) and no higher than 9 (slowest, best compression).
-
-*CCACHE_CPP2*::
-
- If you set the environment variable *CCACHE_CPP2* then ccache will not use
- the optimisation of avoiding the second call to the preprocessor by
- compiling the preprocessed output that was used for finding the hash in the
- case of a cache miss. This is primarily a debugging option, although it is
- possible that some unusual compilers will have problems with the
- intermediate filename extensions used in this optimisation, in which case
- this option could allow ccache to be used anyway.
-
-*CCACHE_DETECT_SHEBANG*::
+*compression* (*CCACHE_COMPRESS*) [boolean]::
- The *CCACHE_DETECT_SHEBANG* environment variable only has meaning on
- Windows. It instructs ccache to open the executable file to detect the
- *#!/bin/sh* string, in which case ccache will search for *sh.exe* in
- *PATH* and use that to launch the executable.
+ If true, ccache will compress object files and other compiler output it
+ puts in the cache. However, this setting has no effect on how files are
+ retrieved from the cache; compressed and uncompressed results will still be
+ usable regardless of this setting. The default is false.
-*CCACHE_DIR*::
++*compression_level* (*CCACHE_COMPRESSLEVEL*)::
+
- The *CCACHE_DIR* environment variable specifies where ccache will keep its
- cached compiler output. The default is *$HOME/.ccache*.
++ This setting determines the level at which ccache will compress object
++ files. It only has effect if *compression* is enabled. The value defaults
++ to 6, and must be no lower than 1 (fastest, worst compression) and no
++ higher than 9 (slowest, best compression).
+
-*CCACHE_DISABLE*::
+*cpp_extension* (*CCACHE_EXTENSION*)::
- If you set the environment variable *CCACHE_DISABLE* then ccache will just
- call the real compiler, bypassing the cache completely.
+ This setting can be used to force a certain extension for the intermediate
+ preprocessed file. The default is to automatically determine the extension
+ to use for intermediate preprocessor files based on the type of file being
+ compiled, but that sometimes doesn't work. For example, when using the
+ ``aCC'' compiler on HP-UX, set the cpp extension to *i*.
-*CCACHE_EXTENSION*::
+*direct_mode* (*CCACHE_DIRECT*) [boolean]::
- ccache tries to automatically determine the extension to use for
- intermediate preprocessor files based on the type of file being compiled.
- Unfortunately this sometimes doesn't work, for example when using the
- ``aCC'' compiler on HP-UX. On systems like this you can use the
- *CCACHE_EXTENSION* option to override the default. On HP-UX set this
- environment variable to *i* if you use the ``aCC'' compiler.
+ If true, the direct mode will be used. The default is true.
-*CCACHE_EXTRAFILES*::
+*disable* (*CCACHE_DISABLE*) [boolean]::
- If you set the environment variable *CCACHE_EXTRAFILES* to a list of paths
- then ccache will include the contents of those files when calculating the
- hash sum. The list separator is semicolon in Windows systems and colon on
- other systems.
+ When true, ccache will just call the real compiler, bypassing the cache
+ completely. The default is false.
-*CCACHE_HARDLINK*::
+*extra_files_to_hash* (*CCACHE_EXTRAFILES*)::
- If you set the environment variable *CCACHE_HARDLINK* then ccache will
- attempt to use hard links from the cache directory when creating the
- compiler output rather than using a file copy. Using hard links may be
- slightly faster in some situations, but can confuse programs like ``make''
- that rely on modification times. Another thing to keep in mind is that if
- the resulting object file is modified in any way, this corrupts the cached
- object file as well. Hard links are never made for compressed cache files.
- This means that you should not set the *CCACHE_COMPRESS* variable if you
- want to use hard links.
+ This setting is a list of paths to files that ccache will include in the
+ the hash sum that idetifies the build. The list separator is semicolon on
+ Windows systems and colon on other systems.
-*CCACHE_HASHDIR*::
+*hard_link* (*CCACHE_HARDLINK*) [boolean]::
- This tells ccache to hash the current working directory when calculating
- the hash that is used to distinguish two compilations. This prevents a
- problem with the storage of the current working directory in the debug info
- of a object file, which can lead ccache to give a cached object file that
- has the working directory in the debug info set incorrectly. This option is
- off by default as the incorrect setting of this debug info rarely causes
- problems. If you strike problems with GDB not using the correct directory
- then enable this option.
+ If true, ccache will attempt to use hard links from the cache directory
+ when creating the compiler output rather than using a file copy. Using hard
+ links may be slightly faster in some situations, but can confuse programs
+ like ``make'' that rely on modification times. Another thing to keep in
+ mind is that if the resulting object file is modified in any way, this
+ corrupts the cached object file as well. Hard links are never made for
+ compressed cache files. This means that you should not enable compression
+ if you want to use hard links. The default is false.
-*CCACHE_LOGFILE*::
+*hash_dir* (*CCACHE_HASHDIR*) [boolean]::
- If you set the *CCACHE_LOGFILE* environment variable then ccache will write
- information on what it is doing to the specified file. This is useful for
- tracking down problems.
+ If true, ccache will include the current working directory in the hash that
+ is used to distinguish two compilations. This prevents a problem with the
+ storage of the current working directory in the debug info of a object
+ file, which can lead ccache to give a cached object file that has the
+ working directory in the debug info set incorrectly. This option is off by
+ default as the incorrect setting of this debug info rarely causes problems.
+ If you strike problems with GDB not using the correct directory then enable
+ this option.
-*CCACHE_NLEVELS*::
+*log_file* (*CCACHE_LOGFILE*)::
- The environment variable *CCACHE_NLEVELS* allows you to choose the number
- of levels of hash in the cache directory. The default is 2. The minimum is
- 1 and the maximum is 8.
+ If set to a file path, ccache will write information on what it is doing to
+ the specified file. This is useful for tracking down problems.
-*CCACHE_NODIRECT*::
+*stats* (*CCACHE_STATS*) [boolean]::
- If you set the environment variable *CCACHE_NODIRECT* then ccache will not
- use the direct mode.
+ If true, ccache will update the statistics counters on each compilation.
+ The default is true.
-*CCACHE_NOSTATS*::
+*path* (*CCACHE_PATH*)::
- If you set the environment variable *CCACHE_NOSTATS* then ccache will not
- update the statistics files on each compilation.
+ If set, ccache will search directories in this list when looking for the
+ real compiler. The list separator is semicolon on Windows systems and colon
+ on other systems. If not set, ccache will look for the first executable
+ matching the compiler name in the normal *PATH* that isn't a symbolic link
+ to ccache itself.
-*CCACHE_PATH*::
+*prefix_command* (*CCACHE_PREFIX*)::
- You can optionally set *CCACHE_PATH* to a colon-separated path where ccache
- will look for the real compilers. If you don't do this then ccache will
- look for the first executable matching the compiler name in the normal
- *PATH* that isn't a symbolic link to ccache itself.
+ This option adds a list of prefixes (separated by space) to the command
+ line that ccache uses when invoking the compiler. See also
+ <<_using_ccache_with_other_compiler_wrappers,USING CCACHE WITH OTHER
+ COMPILER WRAPPERS>>.
-*CCACHE_PREFIX*::
+*read_only* (*CCACHE_READONLY*) [boolean]::
- This option adds a prefix to the command line that ccache runs when
- invoking the compiler. Also see the section below on using ccache with
- ``distcc''.
+ If true, ccache will attempt to use existing cached object files, but it
+ will not to try to add anything new to the cache. If you are using this
+ because your ccache directory is read-only, then you need to set
+ *temporary_dir* as otherwise ccache will fail to create temporary files.
-*CCACHE_READONLY*::
+*reache* (*CCACHE_RECACHE*) [boolean]::
- The *CCACHE_READONLY* environment variable tells ccache to attempt to use
- existing cached object files, but not to try to add anything new to the
- cache. If you are using this because your *CCACHE_DIR* is read-only, then
- you may find that you also need to set *CCACHE_TEMPDIR* as otherwise ccache
- will fail to create temporary files.
+ If true, ccache will not use any previously stored result. New results will
+ still be cached, possibly overwriting any pre-existing results.
-*CCACHE_RECACHE*::
+*run_second_cpp* (*CCACHE_CPP2*) [boolean]::
- This forces ccache to not use any cached results, even if it finds them.
- New results are still cached, but existing cache entries are ignored.
+ If true, ccache will not use the optimisation of avoiding the second call
+ to the preprocessor by compiling the preprocessed output that was used for
+ finding the hash in the case of a cache miss. This is primarily a debugging
+ option, although it is possible that some unusual compilers will have
+ problems with compiling the preprocessed output, in which case this option
+ could allow ccache to be used anyway.
-*CCACHE_SLOPPINESS*::
+*sloppiness* (*CCACHE_SLOPPINESS*)::
By default, ccache tries to give as few false cache hits as possible.
However, in certain situations it's possible that you know things that
-----------------
ccache can optionally compress all files it puts into the cache using the
-compression library zlib. While this involves a negligible performance
-slowdown, it significantly increases the number of files that fit in the cache.
-You can turn on compression by setting the *CCACHE_COMPRESS* environment
-variable.
+compression library zlib. While this may involve a tiny performance slowdown,
+it increases the number of files that fit in the cache. You can turn on
- compression with the *compress* configuration setting.
++compression with the *compression* configuration setting and you can also tweak
++the compression level with *compression_level*.
How ccache works
failed();
}
if (st.st_size > 0) {
-- if (move_uncompressed_file(tmp_stderr, cached_stderr,
- conf->compression) != 0) {
- enable_compression) != 0) {
++ if (move_uncompressed_file(
++ tmp_stderr, cached_stderr,
++ conf->compression ? conf->compression_level : 0) != 0) {
cc_log("Failed to move %s to %s: %s", tmp_stderr, cached_stderr,
strerror(errno));
stats_update(STATS_ERROR);
stats_update(STATS_ERROR);
failed();
}
- } else if (move_uncompressed_file(tmp_obj, cached_obj, conf->compression) != 0) {
- } else if (move_uncompressed_file(tmp_obj, cached_obj, enable_compression) != 0) {
++ } else if (move_uncompressed_file(
++ tmp_obj, cached_obj,
++ conf->compression ? conf->compression_level : 0) != 0) {
cc_log("Failed to move %s to %s: %s", tmp_obj, cached_obj, strerror(errno));
stats_update(STATS_ERROR);
failed();
--- /dev/null
+/*
+ * Copyright (C) 2011-2012 Joel Rosdahl
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "conf.h"
+#include "ccache.h"
+
+typedef bool (*conf_item_parser)(const char *str, void *result, char **errmsg);
+typedef bool (*conf_item_verifier)(void *value, char **errmsg);
+
+struct conf_item {
+ const char *name;
+ size_t number;
+ conf_item_parser parser;
+ size_t offset;
+ conf_item_verifier verifier;
+};
+
+struct env_to_conf_item {
+ const char *env_name;
+ const char *conf_name;
+};
+
+static bool
+parse_bool(const char *str, void *result, char **errmsg)
+{
+ bool *value = (bool *)result;
+
+ if (str_eq(str, "true")) {
+ *value = true;
+ return true;
+ } else if (str_eq(str, "false")) {
+ *value = false;
+ return true;
+ } else {
+ *errmsg = format("not a boolean value: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+parse_env_string(const char *str, void *result, char **errmsg)
+{
+ char **value = (char **)result;
+ free(*value);
+ *value = subst_env_in_string(str, errmsg);
+ return *value;
+}
+
+static bool
+parse_size(const char *str, void *result, char **errmsg)
+{
+ uint64_t *value = (uint64_t *)result;
+ uint64_t size;
+ *errmsg = NULL;
+ if (parse_size_with_suffix(str, &size)) {
+ *value = size;
+ return true;
+ } else {
+ *errmsg = format("invalid size: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+parse_sloppiness(const char *str, void *result, char **errmsg)
+{
+ unsigned *value = (unsigned *)result;
+ char *word, *p, *q, *saveptr = NULL;
+
+ if (!str) {
+ return *value;
+ }
+ p = x_strdup(str);
+ q = p;
+ while ((word = strtok_r(q, ", ", &saveptr))) {
+ if (str_eq(word, "file_macro")) {
+ *value |= SLOPPY_FILE_MACRO;
+ } else if (str_eq(word, "include_file_mtime")) {
+ *value |= SLOPPY_INCLUDE_FILE_MTIME;
+ } else if (str_eq(word, "time_macros")) {
+ *value |= SLOPPY_TIME_MACROS;
+ } else {
+ *errmsg = format("unknown sloppiness: \"%s\"", word);
+ free(p);
+ return false;
+ }
+ q = NULL;
+ }
+ free(p);
+ return true;
+}
+
+static bool
+parse_string(const char *str, void *result, char **errmsg)
+{
+ char **value = (char **)result;
+ (void)errmsg;
+ free(*value);
+ *value = x_strdup(str);
+ return true;
+}
+
+static bool
+parse_umask(const char *str, void *result, char **errmsg)
+{
+ unsigned *value = (unsigned *)result;
+ char *endptr;
+ if (str_eq(str, "")) {
+ *value = UINT_MAX;
+ return true;
+ }
+ errno = 0;
+ *value = strtoul(str, &endptr, 8);
+ if (errno == 0 && *str != '\0' && *endptr == '\0') {
+ return true;
+ } else {
+ *errmsg = format("not an octal integer: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+parse_unsigned(const char *str, void *result, char **errmsg)
+{
+ unsigned *value = (unsigned *)result;
+ long x;
+ char *endptr;
+ errno = 0;
+ x = strtol(str, &endptr, 10);
+ if (errno == 0 && x >= 0 && x <= (unsigned)-1 && *str != '\0'
+ && *endptr == '\0') {
+ *value = x;
+ return true;
+ } else {
+ *errmsg = format("invalid unsigned integer: \"%s\"", str);
+ return false;
+ }
+}
+
+static bool
+verify_absolute_path(void *value, char **errmsg)
+{
+ char **path = (char **)value;
+ assert(*path);
+ if (str_eq(*path, "")) {
+ /* The empty string means "disable" in this case. */
+ return true;
+ } else if (is_absolute_path(*path)) {
+ return true;
+ } else {
+ *errmsg = format("not an absolute path: \"%s\"", *path);
+ return false;
+ }
+}
+
+static bool
+verify_dir_levels(void *value, char **errmsg)
+{
+ unsigned *levels = (unsigned *)value;
+ assert(levels);
+ if (*levels >= 1 && *levels <= 8) {
+ return true;
+ } else {
+ *errmsg = format("cache directory levels must be between 1 and 8");
+ return false;
+ }
+}
+
+#define ITEM(name, type) \
+ parse_##type, offsetof(struct conf, name), NULL
+#define ITEM_V(name, type, verification) \
+ parse_##type, offsetof(struct conf, name), verify_##verification
+
+#include "confitems_lookup.c"
+#include "envtoconfitems_lookup.c"
+
+static const struct conf_item *
+find_conf(const char *name)
+{
+ return confitems_get(name, strlen(name));
+}
+
+static const struct env_to_conf_item *
+find_env_to_conf(const char *name)
+{
+ return envtoconfitems_get(name, strlen(name));
+}
+
+static bool
+handle_conf_setting(struct conf *conf, const char *key, const char *value,
+ char **errmsg, bool from_env_variable, bool negate_boolean,
+ const char *origin)
+{
+ const struct conf_item *item;
+
+ item = find_conf(key);
+ if (!item) {
+ *errmsg = format("unknown configuration option \"%s\"", key);
+ return false;
+ }
+
+ if (from_env_variable && item->parser == parse_bool) {
+ /*
+ * Special rule for boolean settings from the environment: any value means
+ * true.
+ */
+ bool *value = (bool *)((void *)conf + item->offset);
+ *value = !negate_boolean;
+ goto out;
+ }
+
+ if (!item->parser(value, (void *)conf + item->offset, errmsg)) {
+ return false;
+ }
+ if (item->verifier && !item->verifier((void *)conf + item->offset, errmsg)) {
+ return false;
+ }
+
+out:
+ conf->item_origins[item->number] = origin;
+ return true;
+}
+
+static bool
+parse_line(const char *line, char **key, char **value, char **errmsg)
+{
+ const char *p, *q;
+
+#define SKIP_WS(x) while (isspace(*x)) { ++x; }
+
+ *key = NULL;
+ *value = NULL;
+
+ p = line;
+ SKIP_WS(p);
+ if (*p == '\0' || *p == '#') {
+ return true;
+ }
+ q = p;
+ while (isalpha(*q) || *q == '_') {
+ ++q;
+ }
+ *key = x_strndup(p, q - p);
+ p = q;
+ SKIP_WS(p);
+ if (*p != '=') {
+ *errmsg = x_strdup("missing equal sign");
+ free(*key);
+ *key = NULL;
+ return false;
+ }
+ ++p;
+
+ /* Skip leading whitespace. */
+ SKIP_WS(p);
+ q = p;
+ while (*q) {
+ ++q;
+ }
+ /* Skip trailing whitespace. */
+ while (isspace(q[-1])) {
+ --q;
+ }
+ *value = x_strndup(p, q - p);
+
+ return true;
+
+#undef SKIP_WS
+}
+
+/* Create a conf struct with default values. */
+struct conf *
+conf_create(void)
+{
+ size_t i;
+ struct conf *conf = x_malloc(sizeof(*conf));
+ conf->base_dir = x_strdup("");
+ conf->cache_dir = format("%s/.ccache", get_home_directory());
+ conf->cache_dir_levels = 2;
+ conf->compiler = x_strdup("");
+ conf->compiler_check = x_strdup("mtime");
+ conf->compression = false;
++ conf->compression_level = 6;
+ conf->cpp_extension = x_strdup("");
+ conf->direct_mode = true;
+ conf->disable = false;
+ conf->extra_files_to_hash = x_strdup("");
+ conf->hard_link = false;
+ conf->hash_dir = false;
+ conf->log_file = x_strdup("");
+ conf->max_files = 0;
+ conf->max_size = (uint64_t)5 * 1000 * 1000 * 1000;
+ conf->path = x_strdup("");
+ conf->prefix_command = x_strdup("");
+ conf->read_only = false;
+ conf->recache = false;
+ conf->run_second_cpp = false;
+ conf->sloppiness = 0;
+ conf->stats = true;
+ conf->temporary_dir = x_strdup("");
+ conf->umask = UINT_MAX; /* default: don't set umask */
+ conf->unify = false;
+ conf->item_origins = x_malloc(CONFITEMS_TOTAL_KEYWORDS * sizeof(char*));
+ for (i = 0; i < CONFITEMS_TOTAL_KEYWORDS; ++i) {
+ conf->item_origins[i] = "default";
+ }
+ return conf;
+}
+
+void
+conf_free(struct conf *conf)
+{
+ if (!conf) {
+ return;
+ }
+ free(conf->base_dir);
+ free(conf->cache_dir);
+ free(conf->compiler);
+ free(conf->compiler_check);
+ free(conf->cpp_extension);
+ free(conf->extra_files_to_hash);
+ free(conf->log_file);
+ free(conf->path);
+ free(conf->prefix_command);
+ free(conf->temporary_dir);
+ free(conf->item_origins);
+ free(conf);
+}
+
+/* Note: The path pointer is stored in conf, so path must outlive conf. */
+bool
+conf_read(struct conf *conf, const char *path, char **errmsg)
+{
+ FILE *f;
+ char buf[10000];
+ bool result = true;
+ unsigned line_number;
+
+ assert(errmsg);
+ *errmsg = NULL;
+
+ f = fopen(path, "r");
+ if (!f) {
+ *errmsg = format("%s: %s", path, strerror(errno));
+ return false;
+ }
+
+ line_number = 0;
+ while (fgets(buf, sizeof(buf), f)) {
+ char *errmsg2, *key, *value;
+ bool ok;
+ ++line_number;
+ ok = parse_line(buf, &key, &value, &errmsg2);
+ if (ok && key) { /* key == NULL if comment or blank line */
+ ok = handle_conf_setting(conf, key, value, &errmsg2, false, false, path);
+ }
+ free(key);
+ free(value);
+ if (!ok) {
+ *errmsg = format("%s:%u: %s", path, line_number, errmsg2);
+ free(errmsg2);
+ result = false;
+ goto out;
+ }
+ }
+ if (ferror(f)) {
+ *errmsg = x_strdup(strerror(errno));
+ result = false;
+ }
+
+out:
+ fclose(f);
+ return result;
+}
+
+bool
+conf_update_from_environment(struct conf *conf, char **errmsg)
+{
+ char **p;
+ char *q;
+ char *key;
+ char *errmsg2;
+ const struct env_to_conf_item *env_to_conf_item;
+ bool negate;
+ size_t key_start;
+
+ for (p = environ; *p; ++p) {
+ if (!str_startswith(*p, "CCACHE_")) {
+ continue;
+ }
+ q = strchr(*p, '=');
+ if (!q) {
+ continue;
+ }
+
+ if (str_startswith(*p + 7, "NO")) {
+ negate = true;
+ key_start = 9;
+ } else {
+ negate = false;
+ key_start = 7;
+ }
+ key = x_strndup(*p + key_start, q - *p - key_start);
+
+ ++q; /* Now points to the value. */
+
+ env_to_conf_item = find_env_to_conf(key);
+ if (!env_to_conf_item) {
+ free(key);
+ continue;
+ }
+
+ if (!handle_conf_setting(
+ conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
+ "environment")) {
+ *errmsg = format("%s: %s", key, errmsg2);
+ free(errmsg2);
+ free(key);
+ return false;
+ }
+
+ free(key);
+ }
+
+ return true;
+}
+
+bool
+conf_set_value_in_file(const char *path, const char *key, const char *value,
+ char **errmsg)
+{
+ FILE *infile, *outfile;
+ char *outpath;
+ char buf[10000];
+ bool found;
+ const struct conf_item *item;
+
+ item = find_conf(key);
+ if (!item) {
+ *errmsg = format("unknown configuration option \"%s\"", key);
+ return false;
+ }
+
+ infile = fopen(path, "r");
+ if (!infile) {
+ *errmsg = format("%s: %s", path, strerror(errno));
+ return false;
+ }
+
+ outpath = format("%s.tmp.%s", path, tmp_string());
+ outfile = fopen(outpath, "w");
+ if (!outfile) {
+ *errmsg = format("%s: %s", outpath, strerror(errno));
+ free(outpath);
+ fclose(infile);
+ return false;
+ }
+
+ found = false;
+ while (fgets(buf, sizeof(buf), infile)) {
+ char *errmsg2, *key2, *value2;
+ bool ok;
+ ok = parse_line(buf, &key2, &value2, &errmsg2);
+ if (ok && key2 && str_eq(key2, key)) {
+ found = true;
+ fprintf(outfile, "%s = %s\n", key, value);
+ } else {
+ fputs(buf, outfile);
+ }
+ free(key2);
+ free(value2);
+ }
+
+ if (!found) {
+ fprintf(outfile, "%s = %s\n", key, value);
+ }
+
+ fclose(infile);
+ fclose(outfile);
+ if (x_rename(outpath, path) != 0) {
+ *errmsg = format("rename %s to %s: %s", outpath, path, strerror(errno));
+ return false;
+ }
+ free(outpath);
+
+ return true;
+}
+
+bool
+conf_print_items(struct conf *conf,
+ void (*printer)(const char *descr, const char *origin,
+ void *context),
+ void *context)
+{
+ char *s = x_strdup("");
+ char *s2;
+
+ reformat(&s, "base_dir = %s", conf->base_dir);
+ printer(s, conf->item_origins[find_conf("base_dir")->number], context);
+
+ reformat(&s, "cache_dir = %s", conf->cache_dir);
+ printer(s, conf->item_origins[find_conf("cache_dir")->number], context);
+
+ reformat(&s, "cache_dir_levels = %u", conf->cache_dir_levels);
+ printer(s, conf->item_origins[find_conf("cache_dir_levels")->number],
+ context);
+
+ reformat(&s, "compiler = %s", conf->compiler);
+ printer(s, conf->item_origins[find_conf("compiler")->number], context);
+
+ reformat(&s, "compiler_check = %s", conf->compiler_check);
+ printer(s, conf->item_origins[find_conf("compiler_check")->number], context);
+
+ reformat(&s, "compression = %s", conf->compression ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("compression")->number], context);
++
++ reformat(&s, "compression_level = %u", conf->compression_level);
++ printer(s, conf->item_origins[find_conf("compression_level")->number],
++ context);
+
+ reformat(&s, "cpp_extension = %s", conf->cpp_extension);
+ printer(s, conf->item_origins[find_conf("cpp_extension")->number], context);
+
+ reformat(&s, "direct_mode = %s", conf->direct_mode ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("direct_mode")->number], context);
+
+ reformat(&s, "disable = %s", conf->disable ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("disable")->number], context);
+
+ reformat(&s, "extra_files_to_hash = %s", conf->extra_files_to_hash);
+ printer(s, conf->item_origins[find_conf("extra_files_to_hash")->number],
+ context);
+
+ reformat(&s, "hard_link = %s", conf->hard_link ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("hard_link")->number], context);
+
+ reformat(&s, "hash_dir = %s", conf->hash_dir ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("hash_dir")->number], context);
+
+ reformat(&s, "log_file = %s", conf->log_file);
+ printer(s, conf->item_origins[find_conf("log_file")->number], context);
+
+ reformat(&s, "max_files = %u", conf->max_files);
+ printer(s, conf->item_origins[find_conf("max_files")->number], context);
+
+ s2 = format_parsable_size_with_suffix(conf->max_size);
+ reformat(&s, "max_size = %s", s2);
+ printer(s, conf->item_origins[find_conf("max_size")->number], context);
+ free(s2);
+
+ reformat(&s, "path = %s", conf->path);
+ printer(s, conf->item_origins[find_conf("path")->number], context);
+
+ reformat(&s, "prefix_command = %s", conf->prefix_command);
+ printer(s, conf->item_origins[find_conf("prefix_command")->number], context);
+
+ reformat(&s, "read_only = %s", conf->read_only ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("read_only")->number], context);
+
+ reformat(&s, "recache = %s", conf->recache ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("recache")->number], context);
+
+ reformat(&s, "run_second_cpp = %s", conf->run_second_cpp ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("run_second_cpp")->number], context);
+
+ reformat(&s, "sloppiness = ");
+ if (conf->sloppiness & SLOPPY_FILE_MACRO) {
+ reformat(&s, "%sfile_macro, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_INCLUDE_FILE_MTIME) {
+ reformat(&s, "%sinclude_file_mtime, ", s);
+ }
+ if (conf->sloppiness & SLOPPY_TIME_MACROS) {
+ reformat(&s, "%stime_macros, ", s);
+ }
+ if (conf->sloppiness) {
+ /* Strip last ", ". */
+ s[strlen(s) - 2] = '\0';
+ }
+ printer(s, conf->item_origins[find_conf("sloppiness")->number], context);
+
+ reformat(&s, "stats = %s", conf->stats ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("stats")->number], context);
+
+ reformat(&s, "temporary_dir = %s", conf->temporary_dir);
+ printer(s, conf->item_origins[find_conf("temporary_dir")->number], context);
+
+ if (conf->umask == UINT_MAX) {
+ reformat(&s, "umask = ");
+ } else {
+ reformat(&s, "umask = %03o", conf->umask);
+ }
+ printer(s, conf->item_origins[find_conf("umask")->number], context);
+
+ reformat(&s, "unify = %s", conf->unify ? "true" : "false");
+ printer(s, conf->item_origins[find_conf("unify")->number], context);
+
+ free(s);
+ return true;
+}
--- /dev/null
+#ifndef CONF_H
+#define CONF_H
+
+#include "system.h"
+
+struct conf {
+ char *base_dir;
+ char *cache_dir;
+ unsigned cache_dir_levels;
+ char *compiler;
+ char *compiler_check;
+ bool compression;
++ unsigned compression_level;
+ char *cpp_extension;
+ bool direct_mode;
+ bool disable;
+ char *extra_files_to_hash;
+ bool hard_link;
+ bool hash_dir;
+ char *log_file;
+ unsigned max_files;
+ uint64_t max_size;
+ char *path;
+ char *prefix_command;
+ bool read_only;
+ bool recache;
+ bool run_second_cpp;
+ unsigned sloppiness;
+ bool stats;
+ char *temporary_dir;
+ unsigned umask;
+ bool unify;
+
+ const char **item_origins;
+};
+
+struct conf *conf_create(void);
+void conf_free(struct conf *conf);
+bool conf_read(struct conf *conf, const char *path, char **errmsg);
+bool conf_update_from_environment(struct conf *conf, char **errmsg);
+bool conf_set_value_in_file(const char *path, const char *key,
+ const char *value, char **errmsg);
+bool conf_print_items(struct conf *conf,
+ void (*printer)(const char *descr, const char *origin,
+ void *context),
+ void *context);
+
+#endif
--- /dev/null
- cpp_extension, 6, ITEM(cpp_extension, string)
- direct_mode, 7, ITEM(direct_mode, bool)
- disable, 8, ITEM(disable, bool)
- extra_files_to_hash, 9, ITEM(extra_files_to_hash, env_string)
- hard_link, 10, ITEM(hard_link, bool)
- hash_dir, 11, ITEM(hash_dir, bool)
- log_file, 12, ITEM(log_file, env_string)
- max_files, 13, ITEM(max_files, unsigned)
- max_size, 14, ITEM(max_size, size)
- path, 15, ITEM(path, env_string)
- prefix_command, 16, ITEM(prefix_command, env_string)
- read_only, 17, ITEM(read_only, bool)
- recache, 18, ITEM(recache, bool)
- run_second_cpp, 19, ITEM(run_second_cpp, bool)
- sloppiness, 20, ITEM(sloppiness, sloppiness)
- stats, 21, ITEM(stats, bool)
- temporary_dir, 22, ITEM(temporary_dir, env_string)
- umask, 23, ITEM(umask, umask)
- unify, 24, ITEM(unify, bool)
+%language=ANSI-C
+%enum
+%struct-type
+%readonly-tables
+%define hash-function-name confitems_hash
+%define lookup-function-name confitems_get
+%define initializer-suffix ,0,NULL,0,NULL
+struct conf_item;
+%%
+base_dir, 0, ITEM_V(base_dir, env_string, absolute_path)
+cache_dir, 1, ITEM(cache_dir, env_string)
+cache_dir_levels, 2, ITEM_V(cache_dir_levels, unsigned, dir_levels)
+compiler, 3, ITEM(compiler, string)
+compiler_check, 4, ITEM(compiler_check, string)
+compression, 5, ITEM(compression, bool)
++compression_level, 6, ITEM(compression_level, unsigned)
++cpp_extension, 7, ITEM(cpp_extension, string)
++direct_mode, 8, ITEM(direct_mode, bool)
++disable, 9, ITEM(disable, bool)
++extra_files_to_hash, 10, ITEM(extra_files_to_hash, env_string)
++hard_link, 11, ITEM(hard_link, bool)
++hash_dir, 12, ITEM(hash_dir, bool)
++log_file, 13, ITEM(log_file, env_string)
++max_files, 14, ITEM(max_files, unsigned)
++max_size, 15, ITEM(max_size, size)
++path, 16, ITEM(path, env_string)
++prefix_command, 17, ITEM(prefix_command, env_string)
++read_only, 18, ITEM(read_only, bool)
++recache, 19, ITEM(recache, bool)
++run_second_cpp, 20, ITEM(run_second_cpp, bool)
++sloppiness, 21, ITEM(sloppiness, sloppiness)
++stats, 22, ITEM(stats, bool)
++temporary_dir, 23, ITEM(temporary_dir, env_string)
++umask, 24, ITEM(umask, umask)
++unify, 25, ITEM(unify, bool)
--- /dev/null
- 5, 15, 45, 45, 30, 5, 45, 45, 15, 10,
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf confitems.gperf */
+/* Computed positions: -k'1-2' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 8 "confitems.gperf"
+struct conf_item;
+/* maximum key range = 41, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+confitems_hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 0, 25, 0,
- TOTAL_KEYWORDS = 25,
++ 10, 15, 45, 45, 30, 5, 45, 45, 15, 10,
+ 0, 0, 0, 45, 10, 0, 0, 5, 45, 45,
+ 10, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45
+ };
+ return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
+}
+
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const struct conf_item *
+confitems_get (register const char *str, register unsigned int len)
+{
+ enum
+ {
- #line 25 "confitems.gperf"
- {"path", 15, ITEM(path, env_string)},
- #line 31 "confitems.gperf"
- {"stats", 21, ITEM(stats, bool)},
++ TOTAL_KEYWORDS = 26,
+ MIN_WORD_LENGTH = 4,
+ MAX_WORD_LENGTH = 19,
+ MIN_HASH_VALUE = 4,
+ MAX_HASH_VALUE = 44
+ };
+
+ static const struct conf_item wordlist[] =
+ {
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
- #line 34 "confitems.gperf"
- {"unify", 24, ITEM(unify, bool)},
++#line 26 "confitems.gperf"
++ {"path", 16, ITEM(path, env_string)},
++#line 32 "confitems.gperf"
++ {"stats", 22, ITEM(stats, bool)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+#line 13 "confitems.gperf"
+ {"compiler", 3, ITEM(compiler, string)},
+#line 11 "confitems.gperf"
+ {"cache_dir", 1, ITEM(cache_dir, env_string)},
- #line 16 "confitems.gperf"
- {"cpp_extension", 6, ITEM(cpp_extension, string)},
++#line 35 "confitems.gperf"
++ {"unify", 25, ITEM(unify, bool)},
+#line 15 "confitems.gperf"
+ {"compression", 5, ITEM(compression, bool)},
+ {"",0,NULL,0,NULL},
- #line 18 "confitems.gperf"
- {"disable", 8, ITEM(disable, bool)},
++#line 17 "confitems.gperf"
++ {"cpp_extension", 7, ITEM(cpp_extension, string)},
+#line 14 "confitems.gperf"
+ {"compiler_check", 4, ITEM(compiler_check, string)},
+ {"",0,NULL,0,NULL},
+#line 12 "confitems.gperf"
+ {"cache_dir_levels", 2, ITEM_V(cache_dir_levels, unsigned, dir_levels)},
- {"max_size", 14, ITEM(max_size, size)},
++#line 16 "confitems.gperf"
++ {"compression_level", 6, ITEM(compression_level, unsigned)},
++#line 25 "confitems.gperf"
++ {"max_size", 15, ITEM(max_size, size)},
+#line 24 "confitems.gperf"
- {"max_files", 13, ITEM(max_files, unsigned)},
- #line 33 "confitems.gperf"
- {"umask", 23, ITEM(umask, umask)},
- #line 17 "confitems.gperf"
- {"direct_mode", 7, ITEM(direct_mode, bool)},
++ {"max_files", 14, ITEM(max_files, unsigned)},
++#line 34 "confitems.gperf"
++ {"umask", 24, ITEM(umask, umask)},
++ {"",0,NULL,0,NULL},
++#line 19 "confitems.gperf"
++ {"disable", 9, ITEM(disable, bool)},
+#line 23 "confitems.gperf"
- #line 22 "confitems.gperf"
- {"log_file", 12, ITEM(log_file, env_string)},
- #line 26 "confitems.gperf"
- {"prefix_command", 16, ITEM(prefix_command, env_string)},
++ {"log_file", 13, ITEM(log_file, env_string)},
++#line 27 "confitems.gperf"
++ {"prefix_command", 17, ITEM(prefix_command, env_string)},
++#line 31 "confitems.gperf"
++ {"sloppiness", 21, ITEM(sloppiness, sloppiness)},
++#line 18 "confitems.gperf"
++ {"direct_mode", 8, ITEM(direct_mode, bool)},
+ {"",0,NULL,0,NULL},
- {"sloppiness", 20, ITEM(sloppiness, sloppiness)},
++#line 33 "confitems.gperf"
++ {"temporary_dir", 23, ITEM(temporary_dir, env_string)},
+#line 30 "confitems.gperf"
- #line 32 "confitems.gperf"
- {"temporary_dir", 22, ITEM(temporary_dir, env_string)},
++ {"run_second_cpp", 20, ITEM(run_second_cpp, bool)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
- {"run_second_cpp", 19, ITEM(run_second_cpp, bool)},
- {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
- #line 28 "confitems.gperf"
- {"recache", 18, ITEM(recache, bool)},
+#line 29 "confitems.gperf"
- #line 27 "confitems.gperf"
- {"read_only", 17, ITEM(read_only, bool)},
++ {"recache", 19, ITEM(recache, bool)},
+#line 10 "confitems.gperf"
+ {"base_dir", 0, ITEM_V(base_dir, env_string, absolute_path)},
- {"hash_dir", 11, ITEM(hash_dir, bool)},
- #line 20 "confitems.gperf"
- {"hard_link", 10, ITEM(hard_link, bool)},
++#line 28 "confitems.gperf"
++ {"read_only", 18, ITEM(read_only, bool)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+ {"",0,NULL,0,NULL},
++#line 22 "confitems.gperf"
++ {"hash_dir", 12, ITEM(hash_dir, bool)},
+#line 21 "confitems.gperf"
- #line 19 "confitems.gperf"
- {"extra_files_to_hash", 9, ITEM(extra_files_to_hash, env_string)}
++ {"hard_link", 11, ITEM(hard_link, bool)},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
+ {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
- static const size_t CONFITEMS_TOTAL_KEYWORDS = 25;
++#line 20 "confitems.gperf"
++ {"extra_files_to_hash", 10, ITEM(extra_files_to_hash, env_string)}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = confitems_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
++static const size_t CONFITEMS_TOTAL_KEYWORDS = 26;
--- /dev/null
+%language=ANSI-C
+%enum
+%struct-type
+%readonly-tables
+%define hash-function-name envtoconfitems_hash
+%define lookup-function-name envtoconfitems_get
+%define slot-name env_name
+%define initializer-suffix ,""
+struct env_to_conf_item;
+%%
+BASEDIR, "base_dir"
+CC, "compiler"
+COMPILERCHECK, "compiler_check"
+COMPRESS, "compression"
++COMPRESSLEVEL, "compression_level"
+CPP2, "run_second_cpp"
+DIR, "cache_dir"
+DIRECT, "direct_mode"
+DISABLE, "disable"
+EXTENSION, "cpp_extension"
+EXTRAFILES, "extra_files_to_hash"
+HARDLINK, "hard_link"
+HASHDIR, "hash_dir"
+LOGFILE, "log_file"
+MAXFILES, "max_files"
+MAXSIZE, "max_size"
+NLEVELS, "cache_dir_levels"
+PATH, "path"
+PREFIX, "prefix_command"
+READONLY, "read_only"
+RECACHE, "recache"
+SLOPPINESS, "sloppiness"
+STATS, "stats"
+TEMPDIR, "temporary_dir"
+UMASK, "umask"
+UNIFY, "unify"
--- /dev/null
- /* Computed positions: -k'1-2' */
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf envtoconfitems.gperf */
- 43, 43, 43, 43, 43, 10, 5, 0, 0, 0,
- 43, 43, 20, 0, 43, 43, 15, 10, 20, 10,
- 0, 43, 5, 0, 10, 5, 43, 43, 0, 43,
++/* Computed positions: -k'1,5' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 9 "envtoconfitems.gperf"
+struct env_to_conf_item;
+/* maximum key range = 41, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+envtoconfitems_hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43
++ 43, 43, 43, 43, 43, 43, 5, 0, 0, 10,
++ 20, 43, 15, 43, 10, 43, 20, 10, 15, 0,
++ 5, 5, 5, 0, 0, 5, 43, 43, 43, 43,
++ 0, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
++ 43, 43, 43, 43, 43, 43, 43
+ };
- TOTAL_KEYWORDS = 25,
++ register int hval = len;
++
++ switch (hval)
++ {
++ default:
++ hval += asso_values[(unsigned char)str[4]+1];
++ /*FALLTHROUGH*/
++ case 4:
++ case 3:
++ case 2:
++ case 1:
++ hval += asso_values[(unsigned char)str[0]];
++ break;
++ }
++ return hval;
+}
+
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+const struct env_to_conf_item *
+envtoconfitems_get (register const char *str, register unsigned int len)
+{
+ enum
+ {
- #line 16 "envtoconfitems.gperf"
++ TOTAL_KEYWORDS = 26,
+ MIN_WORD_LENGTH = 2,
+ MAX_WORD_LENGTH = 13,
+ MIN_HASH_VALUE = 2,
+ MAX_HASH_VALUE = 42
+ };
+
+ static const struct env_to_conf_item wordlist[] =
+ {
+ {"",""}, {"",""},
+#line 12 "envtoconfitems.gperf"
+ {"CC", "compiler"},
- #line 15 "envtoconfitems.gperf"
++#line 17 "envtoconfitems.gperf"
+ {"DIR", "cache_dir"},
- {"",""},
- #line 17 "envtoconfitems.gperf"
- {"DIRECT", "direct_mode"},
++#line 16 "envtoconfitems.gperf"
+ {"CPP2", "run_second_cpp"},
- {"DISABLE", "disable"},
- {"",""},
++#line 33 "envtoconfitems.gperf"
++ {"STATS", "stats"},
+#line 18 "envtoconfitems.gperf"
- {"EXTENSION", "cpp_extension"},
- #line 20 "envtoconfitems.gperf"
- {"EXTRAFILES", "extra_files_to_hash"},
++ {"DIRECT", "direct_mode"},
+#line 19 "envtoconfitems.gperf"
- {"PREFIX", "prefix_command"},
- #line 30 "envtoconfitems.gperf"
- {"RECACHE", "recache"},
- #line 29 "envtoconfitems.gperf"
- {"READONLY", "read_only"},
- #line 27 "envtoconfitems.gperf"
++ {"DISABLE", "disable"},
++#line 14 "envtoconfitems.gperf"
++ {"COMPRESS", "compression"},
+#line 28 "envtoconfitems.gperf"
- #line 32 "envtoconfitems.gperf"
- {"STATS", "stats"},
+ {"PATH", "path"},
- #line 33 "envtoconfitems.gperf"
- {"TEMPDIR", "temporary_dir"},
- #line 14 "envtoconfitems.gperf"
- {"COMPRESS", "compression"},
++#line 36 "envtoconfitems.gperf"
++ {"UNIFY", "unify"},
+ {"",""},
- {"UMASK", "umask"},
++#line 31 "envtoconfitems.gperf"
++ {"RECACHE", "recache"},
++#line 15 "envtoconfitems.gperf"
++ {"COMPRESSLEVEL", "compression_level"},
++ {"",""},
++#line 32 "envtoconfitems.gperf"
++ {"SLOPPINESS", "sloppiness"},
+ {"",""},
+#line 34 "envtoconfitems.gperf"
- #line 31 "envtoconfitems.gperf"
- {"SLOPPINESS", "sloppiness"},
++ {"TEMPDIR", "temporary_dir"},
++#line 30 "envtoconfitems.gperf"
++ {"READONLY", "read_only"},
++#line 20 "envtoconfitems.gperf"
++ {"EXTENSION", "cpp_extension"},
+ {"",""},
++#line 29 "envtoconfitems.gperf"
++ {"PREFIX", "prefix_command"},
+#line 11 "envtoconfitems.gperf"
+ {"BASEDIR", "base_dir"},
+#line 13 "envtoconfitems.gperf"
+ {"COMPILERCHECK", "compiler_check"},
+ {"",""},
- #line 25 "envtoconfitems.gperf"
++#line 21 "envtoconfitems.gperf"
++ {"EXTRAFILES", "extra_files_to_hash"},
+ {"",""},
- #line 24 "envtoconfitems.gperf"
++#line 26 "envtoconfitems.gperf"
+ {"MAXSIZE", "max_size"},
- {"UNIFY", "unify"},
++#line 25 "envtoconfitems.gperf"
+ {"MAXFILES", "max_files"},
+ {"",""},
+#line 35 "envtoconfitems.gperf"
- {"LOGFILE", "log_file"},
- {"",""}, {"",""}, {"",""}, {"",""},
- #line 22 "envtoconfitems.gperf"
++ {"UMASK", "umask"},
+ {"",""},
+#line 23 "envtoconfitems.gperf"
- #line 21 "envtoconfitems.gperf"
+ {"HASHDIR", "hash_dir"},
- #line 26 "envtoconfitems.gperf"
++#line 22 "envtoconfitems.gperf"
+ {"HARDLINK", "hard_link"},
+ {"",""}, {"",""}, {"",""},
- static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 25;
++#line 24 "envtoconfitems.gperf"
++ {"LOGFILE", "log_file"},
++ {"",""}, {"",""}, {"",""}, {"",""},
++#line 27 "envtoconfitems.gperf"
+ {"NLEVELS", "cache_dir_levels"}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = envtoconfitems_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register const char *s = wordlist[key].env_name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
++static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 26;
--- /dev/null
- * Copyright (C) 2011 Joel Rosdahl
+/*
- #define N_CONFIG_ITEMS 25
++ * Copyright (C) 2011-2012 Joel Rosdahl
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "conf.h"
+#include "test/framework.h"
+#include "test/util.h"
+
- CHECK_INT_EQ(25, n_received_conf_items);
++#define N_CONFIG_ITEMS 26
+static struct {
+ char *descr;
+ const char *origin;
+} received_conf_items[N_CONFIG_ITEMS];
+static size_t n_received_conf_items = 0;
+
+static void
+conf_item_receiver(const char *descr, const char *origin, void *context)
+{
+ (void)context;
+ received_conf_items[n_received_conf_items].descr = x_strdup(descr);
+ received_conf_items[n_received_conf_items].origin = origin;
+ ++n_received_conf_items;
+}
+
+static void
+free_received_conf_items(void)
+{
+ while (n_received_conf_items > 0) {
+ --n_received_conf_items;
+ free(received_conf_items[n_received_conf_items].descr);
+ }
+}
+
+TEST_SUITE(conf)
+
+TEST(conf_create)
+{
+ struct conf *conf = conf_create();
+ CHECK_STR_EQ("", conf->base_dir);
+ CHECK_STR_EQ_FREE1(format("%s/.ccache", get_home_directory()),
+ conf->cache_dir);
+ CHECK_INT_EQ(2, conf->cache_dir_levels);
+ CHECK_STR_EQ("", conf->compiler);
+ CHECK_STR_EQ("mtime", conf->compiler_check);
+ CHECK(!conf->compression);
++ CHECK_INT_EQ(6, conf->compression_level);
+ CHECK_STR_EQ("", conf->cpp_extension);
+ CHECK(conf->direct_mode);
+ CHECK(!conf->disable);
+ CHECK_STR_EQ("", conf->extra_files_to_hash);
+ CHECK(!conf->hard_link);
+ CHECK(!conf->hash_dir);
+ CHECK_STR_EQ("", conf->log_file);
+ CHECK_INT_EQ(0, conf->max_files);
+ CHECK_INT_EQ((uint64_t)5 * 1000 * 1000 * 1000, conf->max_size);
+ CHECK_STR_EQ("", conf->path);
+ CHECK_STR_EQ("", conf->prefix_command);
+ CHECK(!conf->read_only);
+ CHECK(!conf->recache);
+ CHECK(!conf->run_second_cpp);
+ CHECK_INT_EQ(0, conf->sloppiness);
+ CHECK(conf->stats);
+ CHECK_STR_EQ("", conf->temporary_dir);
+ CHECK_INT_EQ(UINT_MAX, conf->umask);
+ CHECK(!conf->unify);
+ conf_free(conf);
+}
+
+TEST(conf_read_valid_config)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ const char *user = getenv("USER");
+ CHECK(user);
+ create_file(
+ "ccache.conf",
+ "base_dir = /$USER/foo/${USER} \n"
+ "cache_dir=\n"
+ "cache_dir = $USER$/${USER}/.ccache\n"
+ "\n"
+ "\n"
+ " #A comment\n"
+ " cache_dir_levels = 4\n"
+ "\t compiler = foo\n"
+ "compiler_check = none\n"
+ "compression=true\n"
++ "compression_level= 2\n"
+ "cpp_extension = .foo\n"
+ "direct_mode = false\n"
+ "disable = true\n"
+ "extra_files_to_hash = a:b c:$USER\n"
+ "hard_link = true\n"
+ "hash_dir = true\n"
+ "log_file = $USER${USER} \n"
+ "max_files = 17\n"
+ "max_size = 123M\n"
+ "path = $USER.x\n"
+ "prefix_command = x$USER\n"
+ "read_only = true\n"
+ "recache = true\n"
+ "run_second_cpp = true\n"
+ "sloppiness = file_macro ,time_macros, include_file_mtime \n"
+ "stats = false\n"
+ "temporary_dir = ${USER}_foo\n"
+ "umask = 777\n"
+ "unify = true"); /* Note: no newline */
+ CHECK(conf_read(conf, "ccache.conf", &errmsg));
+ CHECK(!errmsg);
+
+ CHECK_STR_EQ_FREE1(format("/%s/foo/%s", user, user), conf->base_dir);
+ CHECK_STR_EQ_FREE1(format("%s$/%s/.ccache", user, user), conf->cache_dir);
+ CHECK_INT_EQ(4, conf->cache_dir_levels);
+ CHECK_STR_EQ("foo", conf->compiler);
+ CHECK_STR_EQ("none", conf->compiler_check);
+ CHECK(conf->compression);
++ CHECK_INT_EQ(2, conf->compression_level);
+ CHECK_STR_EQ(".foo", conf->cpp_extension);
+ CHECK(!conf->direct_mode);
+ CHECK(conf->disable);
+ CHECK_STR_EQ_FREE1(format("a:b c:%s", user), conf->extra_files_to_hash);
+ CHECK(conf->hard_link);
+ CHECK(conf->hash_dir);
+ CHECK_STR_EQ_FREE1(format("%s%s", user, user), conf->log_file);
+ CHECK_INT_EQ(17, conf->max_files);
+ CHECK_INT_EQ(123 * 1000 * 1000, conf->max_size);
+ CHECK_STR_EQ_FREE1(format("%s.x", user), conf->path);
+ CHECK_STR_EQ_FREE1(format("x%s", user), conf->prefix_command);
+ CHECK(conf->read_only);
+ CHECK(conf->recache);
+ CHECK(conf->run_second_cpp);
+ CHECK_INT_EQ(SLOPPY_INCLUDE_FILE_MTIME|SLOPPY_FILE_MACRO|SLOPPY_TIME_MACROS,
+ conf->sloppiness);
+ CHECK(!conf->stats);
+ CHECK_STR_EQ_FREE1(format("%s_foo", user), conf->temporary_dir);
+ CHECK_INT_EQ(0777, conf->umask);
+ CHECK(conf->unify);
+
+ conf_free(conf);
+}
+
+TEST(conf_read_with_missing_equal_sign)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "no equal sign");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: missing equal sign",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_with_bad_config_key)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "# Comment\nfoo = bar");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:2: unknown configuration option \"foo\"",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_bool)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "disable=");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: not a boolean value: \"\"",
+ errmsg);
+
+ create_file("ccache.conf", "disable=foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: not a boolean value: \"foo\"",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_env_string)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "base_dir = ${foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: syntax error: missing '}' after \"foo\"",
+ errmsg);
+ /* Other cases tested in test_util.c. */
+ conf_free(conf);
+}
+
+TEST(conf_read_empty_umask)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "umask = ");
+ CHECK(conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_INT_EQ(conf->umask, UINT_MAX);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_size)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "max_size = foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid size: \"foo\"",
+ errmsg);
+ /* Other cases tested in test_util.c. */
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_sloppiness)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+ create_file("ccache.conf", "sloppiness = file_macro, foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: unknown sloppiness: \"foo\"",
+ errmsg);
+ conf_free(conf);
+}
+
+TEST(conf_read_invalid_unsigned)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "max_files =");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid unsigned integer: \"\"",
+ errmsg);
+
+ create_file("ccache.conf", "max_files = -42");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid unsigned integer: \"-42\"",
+ errmsg);
+
+ create_file("ccache.conf", "max_files = 4294967296");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid unsigned integer: \"4294967296\"",
+ errmsg);
+
+ create_file("ccache.conf", "max_files = foo");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: invalid unsigned integer: \"foo\"",
+ errmsg);
+
+ conf_free(conf);
+}
+
+TEST(verify_absolute_base_dir)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "base_dir = relative/path");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: not an absolute path: \"relative/path\"",
+ errmsg);
+
+ create_file("ccache.conf", "base_dir =");
+ CHECK(conf_read(conf, "ccache.conf", &errmsg));
+
+ conf_free(conf);
+}
+
+TEST(verify_dir_levels)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ create_file("ccache.conf", "cache_dir_levels = 0");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: cache directory levels must be between 1 and 8",
+ errmsg);
+ create_file("ccache.conf", "cache_dir_levels = 9");
+ CHECK(!conf_read(conf, "ccache.conf", &errmsg));
+ CHECK_STR_EQ_FREE2("ccache.conf:1: cache directory levels must be between 1 and 8",
+ errmsg);
+
+ conf_free(conf);
+}
+
+TEST(conf_update_from_environment)
+{
+ struct conf *conf = conf_create();
+ char *errmsg;
+
+ putenv("CCACHE_COMPRESS=1");
+ CHECK(conf_update_from_environment(conf, &errmsg));
+ CHECK(conf->compression);
+
+ unsetenv("CCACHE_COMPRESS");
+ putenv("CCACHE_NOCOMPRESS=1");
+ CHECK(conf_update_from_environment(conf, &errmsg));
+ CHECK(!conf->compression);
+
+ conf_free(conf);
+}
+
+TEST(conf_set_new_value)
+{
+ char *errmsg;
+ char *data;
+
+ create_file("ccache.conf", "path = vanilla\n");
+ CHECK(conf_set_value_in_file("ccache.conf", "stats", "chocolate", &errmsg));
+ data = read_text_file("ccache.conf", 0);
+ CHECK(data);
+ CHECK_STR_EQ_FREE2("path = vanilla\nstats = chocolate\n", data);
+}
+
+TEST(conf_set_existing_value)
+{
+ char *errmsg;
+ char *data;
+
+ create_file("ccache.conf", "path = chocolate\nstats = chocolate\n");
+ CHECK(conf_set_value_in_file("ccache.conf", "path", "vanilla", &errmsg));
+ data = read_text_file("ccache.conf", 0);
+ CHECK(data);
+ CHECK_STR_EQ_FREE2("path = vanilla\nstats = chocolate\n", data);
+}
+
+TEST(conf_print_items)
+{
+ size_t i;
+ struct conf conf = {
+ "bd",
+ "cd",
+ 7,
+ "c",
+ "cc",
+ true,
++ 8,
+ "ce",
+ false,
+ true,
+ "efth",
+ true,
+ true,
+ "lf",
+ 4711,
+ 98.7 * 1000 * 1000,
+ "p",
+ "pc",
+ true,
+ true,
+ true,
+ SLOPPY_FILE_MACRO|SLOPPY_INCLUDE_FILE_MTIME|SLOPPY_TIME_MACROS,
+ false,
+ "td",
+ 022,
+ true,
+ NULL
+ };
+ size_t n = 0;
+
+ conf.item_origins = x_malloc(N_CONFIG_ITEMS * sizeof(char *));
+ for (i = 0; i < N_CONFIG_ITEMS; ++i) {
+ conf.item_origins[i] = format("origin%zu", i);
+ }
+
+ conf_print_items(&conf, conf_item_receiver, NULL);
++ CHECK_INT_EQ(N_CONFIG_ITEMS, n_received_conf_items);
+ CHECK_STR_EQ("base_dir = bd", received_conf_items[n++].descr);
+ CHECK_STR_EQ("cache_dir = cd", received_conf_items[n++].descr);
+ CHECK_STR_EQ("cache_dir_levels = 7", received_conf_items[n++].descr);
+ CHECK_STR_EQ("compiler = c", received_conf_items[n++].descr);
+ CHECK_STR_EQ("compiler_check = cc", received_conf_items[n++].descr);
+ CHECK_STR_EQ("compression = true", received_conf_items[n++].descr);
++ CHECK_STR_EQ("compression_level = 8", received_conf_items[n++].descr);
+ CHECK_STR_EQ("cpp_extension = ce", received_conf_items[n++].descr);
+ CHECK_STR_EQ("direct_mode = false", received_conf_items[n++].descr);
+ CHECK_STR_EQ("disable = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("extra_files_to_hash = efth", received_conf_items[n++].descr);
+ CHECK_STR_EQ("hard_link = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("hash_dir = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("log_file = lf", received_conf_items[n++].descr);
+ CHECK_STR_EQ("max_files = 4711", received_conf_items[n++].descr);
+ CHECK_STR_EQ("max_size = 98.7M", received_conf_items[n++].descr);
+ CHECK_STR_EQ("path = p", received_conf_items[n++].descr);
+ CHECK_STR_EQ("prefix_command = pc", received_conf_items[n++].descr);
+ CHECK_STR_EQ("read_only = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("recache = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("run_second_cpp = true", received_conf_items[n++].descr);
+ CHECK_STR_EQ("sloppiness = file_macro, include_file_mtime, time_macros",
+ received_conf_items[n++].descr);
+ CHECK_STR_EQ("stats = false", received_conf_items[n++].descr);
+ CHECK_STR_EQ("temporary_dir = td", received_conf_items[n++].descr);
+ CHECK_STR_EQ("umask = 022", received_conf_items[n++].descr);
+ CHECK_STR_EQ("unify = true", received_conf_items[n++].descr);
+
+ for (i = 0; i < N_CONFIG_ITEMS; ++i) {
+ char *expected = format("origin%zu", i);
+ CHECK_STR_EQ(expected, received_conf_items[i].origin);
+ }
+
+ free_received_conf_items();
+ free(conf.item_origins);
+}
+
+TEST_SUITE_END