File indexing completed on 2024-04-28 05:46:49

0001 /*****************************************************************************
0002  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0003  *                                                                           *
0004  *   This program is free software; you can redistribute it and/or modify    *
0005  *   it under the terms of the GNU Lesser General Public License as          *
0006  *   published by the Free Software Foundation; either version 2.1 of the    *
0007  *   License, or (at your option) version 3, or any later version accepted   *
0008  *   by the membership of KDE e.V. (or its successor approved by the         *
0009  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0010  *   Section 6 of version 3 of the license.                                  *
0011  *                                                                           *
0012  *   This program is distributed in the hope that it will be useful,         *
0013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0015  *   Lesser General Public License for more details.                         *
0016  *                                                                           *
0017  *   You should have received a copy of the GNU Lesser General Public        *
0018  *   License along with this library. If not,                                *
0019  *   see <http://www.gnu.org/licenses/>.                                     *
0020  *****************************************************************************/
0021 
0022 #include "dirs.h"
0023 #include "log.h"
0024 #include "strs.h"
0025 
0026 #include <config.h>
0027 
0028 #include <forward_list>
0029 
0030 #include <sys/types.h>
0031 #include <pwd.h>
0032 #include <sys/types.h>
0033 #include <dirent.h>
0034 #include <libgen.h>
0035 
0036 namespace QtCurve {
0037 
0038 QTC_EXPORT void
0039 makePath(const char *path, int mode)
0040 {
0041     if (isDir(path)) {
0042         return;
0043     }
0044     Str::Buff<1024> opath(path);
0045     size_t len = opath.size() - 1;
0046     while (opath[len - 1] == '/') {
0047         opath[len - 1] = '\0';
0048         len--;
0049     }
0050     char *p = opath.get() + strspn(opath, "/");
0051     if (!*p) {
0052         return;
0053     }
0054     p += 1;
0055     for (;*p;p++) {
0056         if (*p == '/') {
0057             *p = '\0';
0058             if (access(opath, F_OK)) {
0059                 mkdir(opath, mode | 0300);
0060             }
0061             *p = '/';
0062         }
0063     }
0064     if (access(opath, F_OK)) {
0065         mkdir(opath, mode);
0066     }
0067 }
0068 
0069 // Home
0070 QTC_EXPORT const char*
0071 getHome()
0072 {
0073     static uniqueStr dir = [] {
0074         const char *env_home = getenv("HOME");
0075         if (qtcLikely(env_home && *env_home == '/')) {
0076             return Str::cat(env_home, "/");
0077         } else {
0078             struct passwd *pw = getpwuid(getuid());
0079             if (qtcLikely(pw && pw->pw_dir && *pw->pw_dir == '/')) {
0080                 return Str::cat(pw->pw_dir, "/");
0081             }
0082         }
0083         return strdup("/tmp/");
0084     };
0085     return dir.get();
0086 }
0087 
0088 // XDG dirs
0089 QTC_EXPORT const char*
0090 getXDGConfigHome()
0091 {
0092     static uniqueStr dir = [] {
0093         const char *env_home = getenv("XDG_CONFIG_HOME");
0094         if (env_home && *env_home == '/') {
0095             return Str::cat(env_home, "/");
0096         } else {
0097             return Str::cat(getHome(), ".config/");
0098         }
0099     };
0100     return dir.get();
0101 }
0102 
0103 QTC_EXPORT const char*
0104 getXDGDataHome()
0105 {
0106     static uniqueStr dir = [] {
0107         const char *env_home = getenv("XDG_DATA_HOME");
0108         if (env_home && *env_home == '/') {
0109             return Str::cat(env_home, "/");
0110         } else {
0111             return Str::cat(getHome(), ".local/share/");
0112         }
0113     };
0114     return dir.get();
0115 }
0116 
0117 // TODO
0118 const std::forward_list<uniqueStr>&
0119 getKDE4Home()
0120 {
0121     static const std::forward_list<uniqueStr> homes = [] {
0122         std::forward_list<uniqueStr> res;
0123         auto add_dir = [&] (char *dir) {
0124             if (isDir(dir)) {
0125                 res.emplace_front(dir);
0126             } else {
0127                 free(dir);
0128             }
0129         };
0130         add_dir(Str::cat(getHome(), ".kde/"));
0131         add_dir(Str::cat(getHome(), ".kde4/"));
0132         char *env = getenv(getuid() ? "KDEHOME" : "KDEROOTHOME");
0133         if (env && env[0] == '/') {
0134             add_dir(Str::cat(env, "/"));
0135         } else {
0136 #ifndef QTC_KDE4_DEFAULT_HOME_DEFAULT
0137             add_dir(Str::cat(getHome(), QTC_KDE4_DEFAULT_HOME "/"));
0138 #endif
0139         }
0140         return res;
0141     }();
0142     return homes;
0143 }
0144 
0145 QTC_EXPORT const char*
0146 getConfDir()
0147 {
0148     static uniqueStr dir = [] {
0149         const char *env_home = getenv("QTCURVE_CONFIG_DIR");
0150         char *res = ((env_home && *env_home == '/') ? Str::cat(env_home, "/") :
0151                      Str::cat(getXDGConfigHome(), "qtcurve/"));
0152         makePath(res, 0700);
0153         return res;
0154     };
0155     return dir.get();
0156 }
0157 
0158 QTC_EXPORT char*
0159 getConfFile(const char *file, char *buff)
0160 {
0161     if (file[0] == '/')
0162         return Str::fill(buff, file);
0163     return Str::fill(buff, getConfDir(), file);
0164 }
0165 
0166 static const std::forward_list<std::string>&
0167 getPresetDirs()
0168 {
0169     static const std::forward_list<std::string> dirs = [] {
0170         std::forward_list<std::string> res;
0171         auto add_dir = [&] (const char *dir, bool needfree=true) {
0172             if (isDir(dir)) {
0173                 res.emplace_front(dir);
0174             }
0175             if (needfree) {
0176                 free(const_cast<char*>(dir));
0177             }
0178         };
0179         for (auto &kde_home: getKDE4Home()) {
0180             add_dir(Str::cat(kde_home.get(), "share/apps/QtCurve/"));
0181         }
0182         if (auto xdg_data_dirs = getenv("XDG_DATA_DIRS")) {
0183             while (true) {
0184                 auto delim = strchr(xdg_data_dirs, ':');
0185                 if (delim) {
0186                     auto origin = xdg_data_dirs;
0187                     xdg_data_dirs = delim + 1;
0188                     if (origin[0] != '/')
0189                         continue;
0190                     std::string dir(origin, delim - origin);
0191                     dir += "/QtCurve/";
0192                     if (isDir(dir.c_str())) {
0193                         res.push_front(std::move(dir));
0194                     }
0195                 } else if (xdg_data_dirs[0] == '/') {
0196                     std::string dir(xdg_data_dirs);
0197                     dir += "/QtCurve/";
0198                     if (isDir(dir.c_str()))
0199                         res.push_front(std::move(dir));
0200                     break;
0201                 } else {
0202                     break;
0203                 }
0204             }
0205         } else {
0206             add_dir("/usr/local/share/QtCurve/", false);
0207             add_dir("/usr/share/QtCurve/", false);
0208         }
0209         auto xdg_home = Str::cat(getXDGDataHome(), "QtCurve/");
0210         makePath(xdg_home, 0700);
0211         add_dir(xdg_home);
0212         return res;
0213     }();
0214     return dirs;
0215 }
0216 
0217 QTC_EXPORT std::map<std::string, std::string>
0218 getPresets()
0219 {
0220     std::map<std::string, std::string> presets;
0221 
0222     for (auto &dir_name: getPresetDirs()) {
0223         DIR *dir = opendir(dir_name.c_str());
0224         if (!dir)
0225             continue;
0226         while (auto ent = readdir(dir)) {
0227             auto fname = ent->d_name;
0228             // Non preset files
0229             if (!Str::endsWith(fname, ".qtcurve"))
0230                 continue;
0231             size_t name_len = strlen(fname) - strlen(".qtcurve");
0232             std::string name(fname, name_len);
0233             // preset already loaded
0234             if (presets.find(name) != presets.end())
0235                 continue;
0236             presets[name] = dir_name + fname;
0237         }
0238         closedir(dir);
0239     }
0240 
0241     return presets;
0242 }
0243 
0244 }