aboutsummaryrefslogtreecommitdiffstats
path: root/src/config-ini.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/config-ini.c')
-rw-r--r--src/config-ini.c80
1 files changed, 69 insertions, 11 deletions
diff --git a/src/config-ini.c b/src/config-ini.c
index 015668f..d5056dc 100644
--- a/src/config-ini.c
+++ b/src/config-ini.c
@@ -55,23 +55,29 @@ static const struct env_path paths[] = {
/**
* 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 path
- * @param pathbuf_out Output parameter for the memory allocation for `*path_out`;
- * 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`
+ * @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 path
+ * @param pathbuf_out Output parameter for the memory allocation for `*path_out`;
+ * will be set to `NULL` unless `path` is `NULL`; shall be
+ * free(3)d by the caller
+ * @param should_close_out Output parameter for whether the file should be closed
+ * @return `FILE` object for the reading the file; `NULL` if not
+ * found and `path` is `NULL`
*/
static FILE *
-open_config_file(const char *path, const char **path_out, char **pathbuf_out)
+open_config_file(const char *path, const char **path_out, char **pathbuf_out, int *should_close_out)
{
FILE *f = NULL;
size_t i;
+#ifndef WINDOWS
+ const char *s;
+ int fd, old_fd = -1;
+#endif
*path_out = path;
*pathbuf_out = NULL;
+ *should_close_out = 1;
if (!path) {
for (i = 0; !f && i < ELEMSOF(paths); i++)
@@ -80,7 +86,57 @@ open_config_file(const char *path, const char **path_out, char **pathbuf_out)
weprintf(_("Found configuration file `%s'."), *path_out);
else
weprintf(_("No configuration file found."));
+ } else if (!strcmp(path, "/dev/null")) { /* needed to allow /dev/null to be specified on Windows */
+ return NULL;
+ } else if (!strcmp(path, "-")) {
+ *should_close_out = 0;
+ return stdin;
+#ifndef WINDOWS
+ } else if (!strcmp(path, "/dev/stdin")) {
+ *should_close_out = 0;
+ return stdin;
+ } else if (!strcmp(path, "/dev/stdout")) {
+ fd = STDOUT_FILENO;
+ goto use_fd;
+ } else if (!strcmp(path, "/dev/stderr")) {
+ fd = STDERR_FILENO;
+ goto use_fd;
+ } else if (!strncmp(path, "/dev/fd/", sizeof("/dev/fd/") - 1U)) {
+ s = &path[sizeof("/dev/fd/") - 1U];
+# if defined(__linux__)
+ goto parse_fd;
+ } else if (!strncmp(path, "/proc/self/fd/", sizeof("/proc/self/fd/") - 1U)) {
+ s = &path[sizeof("/proc/self/fd/") - 1U];
+ parse_fd:
+# endif
+ fd = 0;
+ if (!*s)
+ goto fallback;
+ while (isdigit(*s)) {
+ if (fd > (INT_MAX - (*s & 15)) / 10)
+ goto fallback;
+ fd = fd * 10 + (*s & 15);
+ }
+ if (*s)
+ goto fallback;
+ use_fd:
+ if (fd > 2) {
+ fd = dup(old_fd = fd);
+ if (fd < 0)
+ eprintf("dup %i:", old_fd);
+ }
+ f = fdopen(fd, "r");
+ if (!f) {
+ if (old_fd < 0)
+ eprintf("fdopen %i \"r\":", fd);
+ else
+ eprintf("fdopen <duplicate of %i> \"r\":", old_fd);
+ }
+#endif
} else {
+#ifndef WINDOWS
+ fallback:
+#endif
f = fopen(path, "r");
if (!f)
eprintf("fopen %s \"r\":", path);
@@ -100,10 +156,11 @@ config_ini_init(struct config_ini_state *state, const char *path)
size_t size = 0;
ssize_t len = 0; /* initialised to silence false warning from clang */
FILE *f;
+ int should_close;
state->sections = NULL;
- f = open_config_file(path, &path, &pathbuf);
+ f = open_config_file(path, &path, &pathbuf, &should_close);
if (!f)
return;
@@ -172,7 +229,8 @@ again:
free(pathbuf);
free(line);
- fclose(f);
+ if (should_close)
+ fclose(f);
}