]> git.saurik.com Git - apt.git/blob - apt-pkg/aptconfiguration.cc
releasing version 0.8.8ubuntu3
[apt.git] / apt-pkg / aptconfiguration.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4
5 Provide access methods to various configuration settings,
6 setup defaults and returns validate settings.
7
8 ##################################################################### */
9 /*}}}*/
10 // Include Files /*{{{*/
11 #include <apt-pkg/aptconfiguration.h>
12 #include <apt-pkg/configuration.h>
13 #include <apt-pkg/error.h>
14 #include <apt-pkg/fileutl.h>
15 #include <apt-pkg/macros.h>
16 #include <apt-pkg/strutl.h>
17
18 #include <sys/types.h>
19 #include <dirent.h>
20
21 #include <algorithm>
22 #include <string>
23 #include <vector>
24 /*}}}*/
25 namespace APT {
26 // getCompressionTypes - Return Vector of usbale compressiontypes /*{{{*/
27 // ---------------------------------------------------------------------
28 /* return a vector of compression types in the prefered order. */
29 std::vector<std::string>
30 const Configuration::getCompressionTypes(bool const &Cached) {
31 static std::vector<std::string> types;
32 if (types.empty() == false) {
33 if (Cached == true)
34 return types;
35 else
36 types.clear();
37 }
38
39 // setup the defaults for the compressiontypes => method mapping
40 _config->CndSet("Acquire::CompressionTypes::bz2","bzip2");
41 _config->CndSet("Acquire::CompressionTypes::lzma","lzma");
42 _config->CndSet("Acquire::CompressionTypes::gz","gzip");
43
44 // Set default application paths to check for optional compression types
45 _config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
46 _config->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
47
48 // accept non-list order as override setting for config settings on commandline
49 std::string const overrideOrder = _config->Find("Acquire::CompressionTypes::Order","");
50 if (overrideOrder.empty() == false)
51 types.push_back(overrideOrder);
52
53 // load the order setting into our vector
54 std::vector<std::string> const order = _config->FindVector("Acquire::CompressionTypes::Order");
55 for (std::vector<std::string>::const_iterator o = order.begin();
56 o != order.end(); o++) {
57 if ((*o).empty() == true)
58 continue;
59 // ignore types we have no method ready to use
60 if (_config->Exists(string("Acquire::CompressionTypes::").append(*o)) == false)
61 continue;
62 // ignore types we have no app ready to use
63 string const appsetting = string("Dir::Bin::").append(*o);
64 if (_config->Exists(appsetting) == true) {
65 std::string const app = _config->FindFile(appsetting.c_str(), "");
66 if (app.empty() == false && FileExists(app) == false)
67 continue;
68 }
69 types.push_back(*o);
70 }
71
72 // default to preferring gzip, so that compressed indexes work
73 if (order.empty())
74 types.push_back("gz");
75
76 // move again over the option tree to add all missing compression types
77 ::Configuration::Item const *Types = _config->Tree("Acquire::CompressionTypes");
78 if (Types != 0)
79 Types = Types->Child;
80
81 for (; Types != 0; Types = Types->Next) {
82 if (Types->Tag == "Order" || Types->Tag.empty() == true)
83 continue;
84 // ignore types we already have in the vector
85 if (std::find(types.begin(),types.end(),Types->Tag) != types.end())
86 continue;
87 // ignore types we have no app ready to use
88 string const appsetting = string("Dir::Bin::").append(Types->Value);
89 if (appsetting.empty() == false && _config->Exists(appsetting) == true) {
90 std::string const app = _config->FindFile(appsetting.c_str(), "");
91 if (app.empty() == false && FileExists(app) == false)
92 continue;
93 }
94 types.push_back(Types->Tag);
95 }
96
97 return types;
98 }
99 /*}}}*/
100 // GetLanguages - Return Vector of Language Codes /*{{{*/
101 // ---------------------------------------------------------------------
102 /* return a vector of language codes in the prefered order.
103 the special word "environment" will be replaced with the long and the short
104 code of the local settings and it will be insured that this will not add
105 duplicates. So in an german local the setting "environment, de_DE, en, de"
106 will result in "de_DE, de, en".
107 The special word "none" is the stopcode for the not-All code vector */
108 std::vector<std::string> const Configuration::getLanguages(bool const &All,
109 bool const &Cached, char const ** const Locale) {
110 using std::string;
111
112 // The detection is boring and has a lot of cornercases,
113 // so we cache the results to calculated it only once.
114 std::vector<string> static allCodes;
115 std::vector<string> static codes;
116
117 // we have something in the cache
118 if (codes.empty() == false || allCodes.empty() == false) {
119 if (Cached == true) {
120 if(All == true && allCodes.empty() == false)
121 return allCodes;
122 else
123 return codes;
124 } else {
125 allCodes.clear();
126 codes.clear();
127 }
128 }
129
130 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
131 // so they will be all included in the Cache.
132 std::vector<string> builtin;
133 DIR *D = opendir(_config->FindDir("Dir::State::lists").c_str());
134 if (D != 0) {
135 builtin.push_back("none");
136 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
137 string const name = Ent->d_name;
138 size_t const foundDash = name.rfind("-");
139 size_t const foundUnderscore = name.rfind("_");
140 if (foundDash == string::npos || foundUnderscore == string::npos ||
141 foundDash <= foundUnderscore ||
142 name.substr(foundUnderscore+1, foundDash-(foundUnderscore+1)) != "Translation")
143 continue;
144 string const c = name.substr(foundDash+1);
145 if (unlikely(c.empty() == true) || c == "en")
146 continue;
147 // Skip unusual files, like backups or that alike
148 string::const_iterator s = c.begin();
149 for (;s != c.end(); ++s) {
150 if (isalpha(*s) == 0)
151 break;
152 }
153 if (s != c.end())
154 continue;
155 if (std::find(builtin.begin(), builtin.end(), c) != builtin.end())
156 continue;
157 builtin.push_back(c);
158 }
159 }
160 closedir(D);
161
162 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
163 // we extract both, a long and a short code and then we will
164 // check if we actually need both (rare) or if the short is enough
165 string const envMsg = string(Locale == 0 ? std::setlocale(LC_MESSAGES, NULL) : *Locale);
166 size_t const lenShort = (envMsg.find('_') != string::npos) ? envMsg.find('_') : 2;
167 size_t const lenLong = (envMsg.find_first_of(".@") != string::npos) ? envMsg.find_first_of(".@") : (lenShort + 3);
168
169 string envLong = envMsg.substr(0,lenLong);
170 string const envShort = envLong.substr(0,lenShort);
171 bool envLongIncluded = true;
172
173 // first cornercase: LANG=C, so we use only "en" Translation
174 if (envLong == "C") {
175 codes.push_back("en");
176 allCodes = codes;
177 allCodes.insert(allCodes.end(), builtin.begin(), builtin.end());
178 if (All == true)
179 return allCodes;
180 else
181 return codes;
182 }
183
184 // to save the servers from unneeded queries, we only try also long codes
185 // for languages it is realistic to have a long code translation file…
186 // TODO: Improve translation acquire system to drop them dynamic
187 char const *needLong[] = { "cs", "en", "pt", "sv", "zh", NULL };
188 if (envLong != envShort) {
189 for (char const **l = needLong; *l != NULL; l++)
190 if (envShort.compare(*l) == 0) {
191 envLongIncluded = false;
192 break;
193 }
194 }
195
196 // we don't add the long code, but we allow the user to do so
197 if (envLongIncluded == true)
198 envLong.clear();
199
200 // FIXME: Remove support for the old APT::Acquire::Translation
201 // it was undocumented and so it should be not very widthly used
202 string const oldAcquire = _config->Find("APT::Acquire::Translation","");
203 if (oldAcquire.empty() == false && oldAcquire != "environment") {
204 // TRANSLATORS: the two %s are APT configuration options
205 _error->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
206 "APT::Acquire::Translation", "Acquire::Languages");
207 if (oldAcquire != "none")
208 codes.push_back(oldAcquire);
209 codes.push_back("en");
210 allCodes = codes;
211 for (std::vector<string>::const_iterator b = builtin.begin();
212 b != builtin.end(); ++b)
213 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
214 allCodes.push_back(*b);
215 if (All == true)
216 return allCodes;
217 else
218 return codes;
219 }
220
221 // It is very likely we will need to environment codes later,
222 // so let us generate them now from LC_MESSAGES and LANGUAGE
223 std::vector<string> environment;
224 // take care of LC_MESSAGES
225 if (envLongIncluded == false)
226 environment.push_back(envLong);
227 environment.push_back(envShort);
228 // take care of LANGUAGE
229 const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
230 string envLang = Locale == 0 ? language_env : *(Locale+1);
231 if (envLang.empty() == false) {
232 std::vector<string> env = VectorizeString(envLang,':');
233 short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
234 for (std::vector<string>::const_iterator e = env.begin();
235 e != env.end() && addedLangs < 3; ++e) {
236 if (unlikely(e->empty() == true) || *e == "en")
237 continue;
238 if (*e == envLong || *e == envShort)
239 continue;
240 if (std::find(environment.begin(), environment.end(), *e) != environment.end())
241 continue;
242 if (e->find('_') != string::npos) {
243 // Drop LongCodes here - ShortCodes are also included
244 string const shorty = e->substr(0, e->find('_'));
245 char const **n = needLong;
246 for (; *n != NULL; ++n)
247 if (shorty == *n)
248 break;
249 if (*n == NULL)
250 continue;
251 }
252 ++addedLangs;
253 environment.push_back(*e);
254 }
255 }
256
257 // Support settings like Acquire::Translation=none on the command line to
258 // override the configuration settings vector of languages.
259 string const forceLang = _config->Find("Acquire::Languages","");
260 if (forceLang.empty() == false) {
261 if (forceLang == "environment") {
262 codes = environment;
263 } else if (forceLang != "none")
264 codes.push_back(forceLang);
265 allCodes = codes;
266 for (std::vector<string>::const_iterator b = builtin.begin();
267 b != builtin.end(); ++b)
268 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
269 allCodes.push_back(*b);
270 if (All == true)
271 return allCodes;
272 else
273 return codes;
274 }
275
276 std::vector<string> const lang = _config->FindVector("Acquire::Languages");
277 // the default setting -> "environment, en"
278 if (lang.empty() == true) {
279 codes = environment;
280 if (envShort != "en")
281 codes.push_back("en");
282 allCodes = codes;
283 for (std::vector<string>::const_iterator b = builtin.begin();
284 b != builtin.end(); ++b)
285 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
286 allCodes.push_back(*b);
287 if (All == true)
288 return allCodes;
289 else
290 return codes;
291 }
292
293 // the configs define the order, so add the environment
294 // then needed and ensure the codes are not listed twice.
295 bool noneSeen = false;
296 for (std::vector<string>::const_iterator l = lang.begin();
297 l != lang.end(); l++) {
298 if (*l == "environment") {
299 for (std::vector<string>::const_iterator e = environment.begin();
300 e != environment.end(); ++e) {
301 if (std::find(allCodes.begin(), allCodes.end(), *e) != allCodes.end())
302 continue;
303 if (noneSeen == false)
304 codes.push_back(*e);
305 allCodes.push_back(*e);
306 }
307 continue;
308 } else if (*l == "none") {
309 noneSeen = true;
310 continue;
311 } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end())
312 continue;
313
314 if (noneSeen == false)
315 codes.push_back(*l);
316 allCodes.push_back(*l);
317 }
318
319 for (std::vector<string>::const_iterator b = builtin.begin();
320 b != builtin.end(); ++b)
321 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
322 allCodes.push_back(*b);
323
324 if (All == true)
325 return allCodes;
326 else
327 return codes;
328 }
329 /*}}}*/
330 // getArchitectures - Return Vector of prefered Architectures /*{{{*/
331 std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
332 using std::string;
333
334 std::vector<string> static archs;
335 if (likely(Cached == true) && archs.empty() == false)
336 return archs;
337
338 archs = _config->FindVector("APT::Architectures");
339 string const arch = _config->Find("APT::Architecture");
340 if (unlikely(arch.empty() == true))
341 return archs;
342
343 if (archs.empty() == true ||
344 std::find(archs.begin(), archs.end(), arch) == archs.end())
345 archs.push_back(arch);
346
347 // erase duplicates and empty strings
348 for (std::vector<string>::reverse_iterator a = archs.rbegin();
349 a != archs.rend(); ++a) {
350 if (a->empty() == true || std::find(a + 1, archs.rend(), *a) != archs.rend())
351 archs.erase(a.base()-1);
352 if (a == archs.rend())
353 break;
354 }
355
356 return archs;
357 }
358 /*}}}*/
359 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
360 bool const Configuration::checkArchitecture(std::string const &Arch) {
361 if (Arch == "all")
362 return true;
363 std::vector<std::string> const archs = getArchitectures(true);
364 return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
365 }
366 /*}}}*/
367 }