#define _GNU_SOURCE #include "rcfile.h" #include #include #include #include /* Suffixes appended to the resolved base directory to form the rc-file * path -- kept as two separate constants (rather than one shared tail) * since the XDG_CONFIG_HOME branch is already rooted at a "config home" * directory while the HOME fallback still needs the "/.config" segment. */ #define RCFILE_XDG_SUFFIX "/xce_test/rc" #define RCFILE_HOME_SUFFIX "/.config/xce_test/rc" char* rcfile_resolve_path(void) { const char* xdg_config_home = getenv("XDG_CONFIG_HOME"); if (xdg_config_home && *xdg_config_home) { size_t len = strlen(xdg_config_home) + strlen(RCFILE_XDG_SUFFIX) + 1; char* path = (char*)malloc(len); if (!path) return NULL; snprintf(path, len, "%s%s", xdg_config_home, RCFILE_XDG_SUFFIX); return path; } const char* home = getenv("HOME"); if (home && *home) { size_t len = strlen(home) + strlen(RCFILE_HOME_SUFFIX) + 1; char* path = (char*)malloc(len); if (!path) return NULL; snprintf(path, len, "%s%s", home, RCFILE_HOME_SUFFIX); return path; } return NULL; } int rcfile_load(const char* path, int (*runner)(char* line)) { if (!path) return 0; FILE* f = fopen(path, "r"); if (!f) { if (errno == ENOENT) return 0; /* missing rc file: silent no-op success */ fprintf(stderr, "xce_test: warning: could not open rc file %s: %s\n", path, strerror(errno)); return 0; /* present but unreadable: non-fatal warning */ } int rc = 0; char* line = NULL; size_t cap = 0; ssize_t n; while ((n = getline(&line, &cap, f)) != -1) { if (n > 0 && line[n - 1] == '\n') line[n - 1] = '\0'; rc = runner(line); if (rc != 0) break; } /* fopen() succeeds on a directory on this platform -- the failure only * surfaces on the first read (getline() returns -1 with errno==EISDIR * and ferror(f) set, feof(f) NOT set). Treat that the same as an open * failure: one non-fatal stderr warning, no runner calls attributed to * it (rc is still 0 here since no line was ever successfully read). */ if (rc == 0 && ferror(f)) { fprintf(stderr, "xce_test: warning: could not read rc file %s: %s\n", path, strerror(errno)); } free(line); fclose(f); return rc; }