diff options
Diffstat (limited to 'src/config-ini.c')
-rw-r--r-- | src/config-ini.c | 209 |
1 files changed, 28 insertions, 181 deletions
diff --git a/src/config-ini.c b/src/config-ini.c index c524605..1a78903 100644 --- a/src/config-ini.c +++ b/src/config-ini.c @@ -1,5 +1,7 @@ -/* config-ini.c -- INI config file parser - * This file is part of redshift-ng. +/* redshift-ng - Automatically adjust display colour temperature according the Sun + * + * Copyright (c) 2009-2018 Jon Lund Steffensen <jonlst@gmail.com> + * Copyright (c) 2014-2016, 2025 Mattias Andrée <m@maandree.se> * * redshift-ng is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,43 +15,11 @@ * * You should have received a copy of the GNU General Public License * along with redshift-ng. If not, see <http://www.gnu.org/licenses/>. - * - * Copyright (c) 2010-2018 Jon Lund Steffensen <jonlst@gmail.com> - * Copyright (c) 2025 Mattias Andrée <m@maandree.se> */ #include "common.h" /** - * Specification for a path that consists of a two parts: - * the first being defined by the environment, and the - * seocnd being a static string - */ -struct env_path { - /** - * Whether the environment variable referenced by `.prefix` - * should be split at each colon (:) into multiple paths to - * test - */ - int multidir_env; - - /** - * Environment variable to use as the first part of the path - * - * `NULL` if the user's home directory should be used - * - * The empty string if `.suffix` should be used as is - */ - const char *prefix_env; - - /** - * The second part of the path - */ - const char *suffix; -}; - - -/** * Paths, in order of priority, to test when looking for * the configuration file for redshift */ @@ -80,152 +50,14 @@ static const struct env_path paths[] = { /** - * Remove trailing whitespace - * - * @param s The string to trim, will be truncated - * @param end The current end of `s`; will be looked up if `NULL` - * @return `s` - */ -static char * -rtrim(char *s, char *end) -{ - end = end ? end : strchr(s, '\0'); - while (end != s && (end[-1] == ' ' || end[-1] == '\t')) - end--; - *end = '\0'; - return s; -} - - -/** - * Remove leading whitespace - * - * @param s The string to trim (will not be modified) - * @return An offset of `s` - */ -GCC_ONLY(__attribute__((__warn_unused_result__))) -static char * -ltrim(char *s) -{ - return &s[strspn(s, " \t")]; -} - - -/** - * Get the user's home directory - * - * This function looks up the user's home directory - * once and caches the result, later calls to this - * function will use the cached result - * - * @param The user's home directory; the empty string if not found - */ -static const char * -get_home(void) -{ -#ifdef WINDOWS - return NULL; -#else - static const char *home = NULL; - struct passwd *pw; - if (!home) { - pw = getpwuid(getuid()); - if (pw) { - home = pw->pw_dir; - if (home && *home) - return home; - weprintf(_("Cannot determine your home directory, " - "it is from the system's user table.")); - } else if (errno) { - weprintf("getpwuid:"); - } else { - weprintf(_("Cannot determine your home directory, your" - " user ID is missing from the system's user table.")); - /* `errno` can either be set to any number of error codes, - * or be zero if the user does not have a passwd entry */ - } - home = ""; - } - return home; -#endif -} - - -/** - * Search for a file and open it for reading - * - * @param path_spec Specification for the path to try - * @param path_out Output parameter for the file path - * @return `FILE` object for the reading the file; `NULL` if not found - */ -static FILE * -try_path(const struct env_path *path_spec, char **path_out) -{ - const char *prefix, *p, *q; - char *path; - size_t len; - FILE *f; - - if (!path_spec->prefix_env) - prefix = get_home(); - else if (!*path_spec->prefix_env) - return fopen(path_spec->suffix, "r"); - else - prefix = getenv(path_spec->prefix_env); - if (!prefix || !*prefix) - return NULL; - - path = emalloc(strlen(prefix) + strlen(path_spec->suffix) + 1U); - - if (path_spec->multidir_env) { - for (p = prefix; *p; p = &q[!!*q]) { -#ifdef strchrnul - q = strchrnul(p, ':'); -#else - q = strchr(p, ':'); - q = q ? q : strchr(p, '\0'); -#endif - len = (size_t)(q - p); - if (!len) - continue; - - memcpy(path, p, len); - stpcpy(&path[len], path_spec->suffix); - f = fopen(path, "r"); - if (f) { - weprintf(_("Found configuration file `%s'."), path); - break; - } else if (errno != ENOENT) { - eprintf("fopen %s \"r\":", path); - } - } - } else { - stpcpy(stpcpy(path, prefix), path_spec->suffix); - f = fopen(path, "r"); - if (f) - weprintf(_("Found configuration file `%s'."), path); - else if (errno != ENOENT) - eprintf("fopen %s \"r\":", path); - } - - if (f) { - *path_out = path; - } else { - free(path); - *path_out = NULL; - } - return f; -} - - -/** * Open the configuration file for reading * * @param path The path to the configuration file, or `NULL` if the * application should look for it in the default paths - * @param path_out Output parameter for the configuration file + * @param path_out Output parameter for the configuration file path * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; - * will be set to `NULL` unless `path` is `NULL` + * will be set to `NULL` unless `path` is `NULL`; shall be + * free(3)d by the caller * @return `FILE` object for the reading the file; `NULL` if not * found and `path` is `NULL` */ @@ -235,18 +67,20 @@ open_config_file(const char *path, const char **path_out, char **pathbuf_out) FILE *f = NULL; size_t i; + *path_out = path; + *pathbuf_out = NULL; + if (!path) { for (i = 0; !f && i < ELEMSOF(paths); i++) - f = try_path(&paths[i], pathbuf_out); - if (!f) + f = try_path_fopen(&paths[i], path_out, pathbuf_out); + if (f) + weprintf(_("Found configuration file `%s'."), *path_out); + else weprintf(_("No configuration file found.")); - *path_out = *pathbuf_out; } else { f = fopen(path, "r"); if (!f) eprintf("fopen %s \"r\":", path); - *path_out = path; - *pathbuf_out = NULL; } return f; @@ -269,6 +103,10 @@ config_ini_init(struct config_ini_state *state, const char *path) f = open_config_file(path, &path, &pathbuf); if (!f) return; + +#ifndef WINDOWS +again: +#endif while ((s = next_line) || (len = getline(&line, &size, f)) >= 0) { if (!s && (s = line, strlen(s) != (size_t)len)) eprintf(_("Config file contains NUL byte.")); @@ -319,8 +157,16 @@ config_ini_init(struct config_ini_state *state, const char *path) break; } } - if (ferror(f)) + if (ferror(f)) { +#ifndef WINDOWS + if (errno == EINTR) { + clearerr(f); + goto again; + } +#endif eprintf("getline %s:", path); + } + free(pathbuf); free(line); fclose(f); @@ -349,6 +195,7 @@ config_ini_free(struct config_ini_state *state) struct config_ini_section * config_ini_get_section(struct config_ini_state *state, const char *name) { + /* TODO deal with multiple section definitions */ struct config_ini_section *section; for (section = state->sections; section; section = section->next) if (!strcasecmp(section->name, name)) |