/* Copyright (C) 2019, 2020 C. McEnroe * * 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, see . * * Additional permission under GNU GPL version 3 section 7: * * If you modify this Program, or any covered work, by linking or * combining it with LibreSSL (or a modified version of that library), * containing parts covered by the terms of the OpenSSL License and the * original SSLeay license, the licensors of this Program grant you * additional permission to convey the resulting work. Corresponding * Source for a non-source form of such a combination shall include the * source code for the parts of LibreSSL used as well as that of the * covered work. */ #include #include #include #include #include #include #include #include "chat.h" #define SUBDIR "catgirl" FILE *configOpen(const char *path, const char *mode) { if (path[0] == '/' || path[0] == '.') goto local; const char *home = getenv("HOME"); const char *configHome = getenv("XDG_CONFIG_HOME"); const char *configDirs = getenv("XDG_CONFIG_DIRS"); char buf[PATH_MAX]; if (configHome) { snprintf(buf, sizeof(buf), "%s/" SUBDIR "/%s", configHome, path); } else { if (!home) goto local; snprintf(buf, sizeof(buf), "%s/.config/" SUBDIR "/%s", home, path); } FILE *file = fopen(buf, mode); if (file) return file; if (errno != ENOENT) warn("%s", buf); if (!configDirs) configDirs = "/etc/xdg"; while (*configDirs) { size_t len = strcspn(configDirs, ":"); snprintf( buf, sizeof(buf), "%.*s/" SUBDIR "/%s", (int)len, configDirs, path ); file = fopen(buf, mode); if (file) return file; if (errno != ENOENT) warn("%s", buf); configDirs += len; if (*configDirs) configDirs++; } local: file = fopen(path, mode); if (!file) warn("%s", path); return file; } FILE *dataOpen(const char *path, const char *mode) { if (path[0] == '/' || path[0] == '.') goto local; const char *home = getenv("HOME"); const char *dataHome = getenv("XDG_DATA_HOME"); const char *dataDirs = getenv("XDG_DATA_DIRS"); char homePath[PATH_MAX]; if (dataHome) { snprintf( homePath, sizeof(homePath), "%s/" SUBDIR "/%s", dataHome, path ); } else { if (!home) goto local; snprintf( homePath, sizeof(homePath), "%s/.local/share/" SUBDIR "/%s", home, path ); } FILE *file = fopen(homePath, mode); if (file) return file; if (errno != ENOENT) warn("%s", homePath); char buf[PATH_MAX]; if (!dataDirs) dataDirs = "/usr/local/share:/usr/share"; while (*dataDirs) { size_t len = strcspn(dataDirs, ":"); snprintf( buf, sizeof(buf), "%.*s/" SUBDIR "/%s", (int)len, dataDirs, path ); file = fopen(buf, mode); if (file) return file; if (errno != ENOENT) warn("%s", buf); dataDirs += len; if (*dataDirs) dataDirs++; } if (mode[0] != 'r') { char *base = strrchr(homePath, '/'); *base = '\0'; int error = mkdir(homePath, S_IRWXU); if (error && errno != EEXIST) { warn("%s", homePath); return NULL; } *base = '/'; file = fopen(homePath, mode); if (!file) warn("%s", homePath); return file; } local: file = fopen(path, mode); if (!file) warn("%s", path); return file; } void dataMkdir(const char *path) { const char *home = getenv("HOME"); const char *dataHome = getenv("XDG_DATA_HOME"); char homePath[PATH_MAX]; if (dataHome) { snprintf( homePath, sizeof(homePath), "%s/" SUBDIR "/%s", dataHome, path ); } else { if (!home) return; snprintf( homePath, sizeof(homePath), "%s/.local/share/" SUBDIR "/%s", home, path ); } int error = mkdir(homePath, S_IRWXU); if (error && errno != EEXIST) warn("%s", homePath); }