diff options
Diffstat (limited to 'redshift/util.c')
-rw-r--r-- | redshift/util.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/redshift/util.c b/redshift/util.c new file mode 100644 index 0000000..26e09a7 --- /dev/null +++ b/redshift/util.c @@ -0,0 +1,317 @@ +/*- + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * redshift-ng 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 redshift-ng. If not, see <http://www.gnu.org/licenses/>. + */ +#include "common.h" + + +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; +} + + +char * +ltrim(char *s) +{ + while (*s == ' ' || *s == '\t') + s++; + return s; +} + + +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 in some manner + * + * @param path_spec Specification for the path to try + * @param path_out Output parameter for the found file + * @param pathbuf_out Output parameter for the memory allocation for `*path_out`; + * shall be free(3)d by the caller + * @param open_cb Pointer to function used to open the file, unless it + * returns `NULL` it's return value is returned by the + * function (`try_path`); `NULL` shall be returned if the + * file `path` does not exist + * @return File access object to the found file; `NULL` if not found + */ +static void * +try_path(const struct env_path *path_spec, const char **path_out, char **pathbuf_out, void *(*open_cb)(const char *path)) +{ + const char *prefix, *p, *q; + char *path; + size_t len; + void *f = NULL; + + *path_out = NULL; + *pathbuf_out = NULL; + + if (!path_spec->prefix_env) { + prefix = get_home(); + } else if (*path_spec->prefix_env) { + prefix = getenv(path_spec->prefix_env); + } else { + f = (*open_cb)(path_spec->suffix); + if (f) + *path_out = path_spec->suffix; + return f; + } + if (!prefix || !*prefix) + return NULL; + + path = emalloc(strlen(prefix) + strlen(path_spec->suffix) + 1U); + + if (path_spec->multidir_env) { + for (p = prefix; !f && *p; p = &q[!!*q]) { +#ifdef strchrnul + q = strchrnul(p, PATH_DELIMITER); +#else + q = strchr(p, PATH_DELIMITER); + 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 = (*open_cb)(path); + } + } else { + stpcpy(stpcpy(path, prefix), path_spec->suffix); + f = (*open_cb)(path); + } + + if (f) + *path_out = *pathbuf_out = path; + else + free(path); + return f; +} + + +/** + * Open a file for reading, if it exists + * + * @param path The path to the file + * @return `FILE` object for reading the file, + * `NULL` if it doesn't exist + */ +static void * +open_file(const char *path) +{ + FILE *f = fopen(path, "r"); + if (!f && errno != ENOENT) + eprintf("fopen %s \"r\":", path); + return f; +} + + +FILE * +try_path_fopen(const struct env_path *path_spec, const char **path_out, char **pathbuf_out) +{ + return try_path(path_spec, path_out, pathbuf_out, &open_file); +} + + +/** + * Open a directory for reading, if it exists + * + * @param path The path to the directory + * @return `DIR` object for reading the directory, + * `NULL` if it doesn't exist + */ +static void * +open_dir(const char *path) +{ + DIR *f = opendir(path); + if (!f && errno != ENOENT) + eprintf("opendir %s:", path); + return f; +} + + +DIR * +try_path_opendir(const struct env_path *path_spec, const char **path_out, char **pathbuf_out) +{ + return try_path(path_spec, path_out, pathbuf_out, &open_dir); +} + + + +#ifndef WINDOWS +void +pipe_rdnonblock(int pipefds[2]) +{ + int i, flags; + + /* Try to use pipe2(2) create O_CLOEXEC pipe */ +# if defined(__linux__) && !defined(MISSING_PIPE2) + if (!pipe2(pipefds, O_CLOEXEC)) + goto apply_nonblock; + else if (errno != ENOSYS) + eprintf("pipe2 <buffer> O_CLOEXEC:"); +# endif + + /* Fallback for when pipe2(2) is not available */ + if (pipe(pipefds)) + eprintf("pipe:"); + for (i = 0; i < 2; i++) { + flags = fcntl(pipefds[i], F_GETFD); + if (flags == -1) + eprintf("fcntl <pipe> F_GETFD:"); + if (fcntl(pipefds[i], F_SETFD, flags | O_CLOEXEC)) + eprintf("fcntl <pipe> F_SETFD +O_CLOEXEC:"); + } + + /* Make the read-end non-blocking */ +# if defined(__linux__) && !defined(MISSING_PIPE2) +apply_nonblock: +# endif + flags = fcntl(pipefds[0], F_GETFL); + if (flags == -1) + eprintf("fcntl <pipe> F_GETFL:"); + if (fcntl(pipefds[0], F_SETFL, flags | O_NONBLOCK)) + eprintf("fcntl <pipe> F_SETFL +O_NONBLOCK:"); +} +#endif + + +void * +ecalloc(size_t n, size_t m) +{ + char *ret = calloc(n, m); + if (!ret) + eprintf("calloc:"); + return ret; +} + + +void * +emalloc(size_t n) +{ + char *ret = malloc(n); + if (!ret) + eprintf("malloc:"); + return ret; +} + + +void * +erealloc(void *ptr, size_t n) +{ + char *ret = realloc(ptr, n); + if (!ret) + eprintf("realloc:"); + return ret; +} + + +char * +estrdup(const char *s) +{ + char *ret = strdup(s); + if (!ret) + eprintf("strdup:"); + return ret; +} + + +void +vweprintf(const char *fmt, va_list args) +{ + int saved_errno; + const char *errstrprefix, *errstr; + + saved_errno = errno; + if (!*fmt) { + errstrprefix = ""; + errstr = strerror(saved_errno); + } else if (strchr(fmt, '\0')[-1] == '\n') { + errstrprefix = ""; + errstr = NULL; + } else if (strchr(fmt, '\0')[-1] == ':') { + errstrprefix = " "; + errstr = strerror(saved_errno); + } else { + errstrprefix = ""; + errstr = ""; + } + + fprintf(stderr, "%s: ", argv0); + vfprintf(stderr, fmt, args); + if (errstr) + fprintf(stderr, "%s%s\n", errstrprefix, errstr); + + errno = saved_errno; +} + + +void +weprintf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vweprintf(fmt, args); + va_end(args); +} + + +void +eprintf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vweprintf(fmt, args); + va_end(args); + exit(1); +} |