0
|
1 /* |
|
2 * Xdg.cpp -- XDG directory specifications |
|
3 * |
|
4 * Copyright (c) 2013, 2014, 2015 David Demelier <markand@malikania.fr> |
|
5 * |
|
6 * Permission to use, copy, modify, and/or distribute this software for any |
|
7 * purpose with or without fee is hereby granted, provided that the above |
|
8 * copyright notice and this permission notice appear in all copies. |
|
9 * |
|
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
17 */ |
|
18 |
|
19 #include <cstdlib> |
|
20 #include <stdexcept> |
|
21 #include <sstream> |
|
22 |
|
23 #include "xdg.h" |
|
24 |
|
25 namespace irccd { |
|
26 |
|
27 namespace { |
|
28 |
|
29 bool isabsolute(const std::string &path) |
|
30 { |
|
31 return path.length() > 0 && path[0] == '/'; |
|
32 } |
|
33 |
|
34 std::vector<std::string> split(const std::string &arg) |
|
35 { |
|
36 std::stringstream iss(arg); |
|
37 std::string item; |
|
38 std::vector<std::string> elems; |
|
39 |
|
40 while (std::getline(iss, item, ':')) |
|
41 if (isabsolute(item)) |
|
42 elems.push_back(item); |
|
43 |
|
44 return elems; |
|
45 } |
|
46 |
|
47 std::string envOrHome(const std::string &var, const std::string &repl) |
|
48 { |
|
49 auto value = getenv(var.c_str()); |
|
50 |
|
51 if (value == nullptr || !isabsolute(value)) { |
|
52 auto home = getenv("HOME"); |
|
53 |
|
54 if (home == nullptr) |
|
55 throw std::runtime_error("could not get home directory"); |
|
56 |
|
57 return std::string(home) + "/" + repl; |
|
58 } |
|
59 |
|
60 return value; |
|
61 } |
|
62 |
|
63 std::vector<std::string> listOrDefaults(const std::string &var, const std::vector<std::string> &list) |
|
64 { |
|
65 auto value = getenv(var.c_str()); |
|
66 |
|
67 if (!value) |
|
68 return list; |
|
69 |
|
70 // No valid item at all? Use defaults |
|
71 auto result = split(value); |
|
72 |
|
73 return (result.size() == 0) ? list : result; |
|
74 } |
|
75 |
|
76 } // !namespace |
|
77 |
|
78 Xdg::Xdg() |
|
79 { |
|
80 m_configHome = envOrHome("XDG_CONFIG_HOME", ".config"); |
|
81 m_dataHome = envOrHome("XDG_DATA_HOME", ".local/share"); |
|
82 m_cacheHome = envOrHome("XDG_CACHE_HOME", ".cache"); |
|
83 |
|
84 m_configDirs = listOrDefaults("XDG_CONFIG_DIRS", { "/etc/xdg" }); |
|
85 m_dataDirs = listOrDefaults("XDG_DATA_DIRS", { "/usr/local/share", "/usr/share" }); |
|
86 |
|
87 /* |
|
88 * Runtime directory is a special case and does not have a replacement, the |
|
89 * application should manage this by itself. |
|
90 */ |
|
91 auto runtime = getenv("XDG_RUNTIME_DIR"); |
|
92 if (runtime && isabsolute(runtime)) |
|
93 m_runtimeDir = runtime; |
|
94 } |
|
95 |
|
96 const std::string &Xdg::configHome() const noexcept |
|
97 { |
|
98 return m_configHome; |
|
99 } |
|
100 |
|
101 const std::string &Xdg::dataHome() const noexcept |
|
102 { |
|
103 return m_dataHome; |
|
104 } |
|
105 |
|
106 const std::string &Xdg::cacheHome() const noexcept |
|
107 { |
|
108 return m_cacheHome; |
|
109 } |
|
110 |
|
111 const std::string &Xdg::runtimeDir() const |
|
112 { |
|
113 if (m_runtimeDir.size() == 0) |
|
114 throw std::runtime_error("XDG_RUNTIME_DIR is not set"); |
|
115 |
|
116 return m_runtimeDir; |
|
117 } |
|
118 |
|
119 const Xdg::List &Xdg::configDirs() const noexcept |
|
120 { |
|
121 return m_configDirs; |
|
122 } |
|
123 |
|
124 const Xdg::List &Xdg::dataDirs() const noexcept |
|
125 { |
|
126 return m_dataDirs; |
|
127 } |
|
128 |
|
129 } // !irccd |