]>
git.saurik.com Git - apt.git/blob - apt-pkg/aptconfiguration.cc
1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
5 Provide access methods to various configuration settings,
6 setup defaults and returns validate settings.
8 ##################################################################### */
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>
18 #include <sys/types.h>
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) {
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");
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");
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
);
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)
59 // ignore types we have no method ready to use
60 if (_config
->Exists(string("Acquire::CompressionTypes::").append(*o
)) == false)
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)
72 // default to preferring gzip, so that compressed indexes work
74 types
.push_back("gz");
76 // move again over the option tree to add all missing compression types
77 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
81 for (; Types
!= 0; Types
= Types
->Next
) {
82 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
84 // ignore types we already have in the vector
85 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
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)
94 types
.push_back(Types
->Tag
);
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
) {
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
;
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)
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());
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")
144 string
const c
= name
.substr(foundDash
+1);
145 if (unlikely(c
.empty() == true) || c
== "en")
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)
155 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
157 builtin
.push_back(c
);
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);
169 string envLong
= envMsg
.substr(0,lenLong
);
170 string
const envShort
= envLong
.substr(0,lenShort
);
171 bool envLongIncluded
= true;
173 // to save the servers from unneeded queries, we only try also long codes
174 // for languages it is realistic to have a long code translation fileā¦
175 // TODO: Improve translation acquire system to drop them dynamic
176 char const *needLong
[] = { "cs", "en", "pt", "sv", "zh", NULL
};
177 if (envLong
!= envShort
) {
178 for (char const **l
= needLong
; *l
!= NULL
; l
++)
179 if (envShort
.compare(*l
) == 0) {
180 envLongIncluded
= false;
185 // we don't add the long code, but we allow the user to do so
186 if (envLongIncluded
== true)
189 // FIXME: Remove support for the old APT::Acquire::Translation
190 // it was undocumented and so it should be not very widthly used
191 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
192 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
193 // TRANSLATORS: the two %s are APT configuration options
194 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
195 "APT::Acquire::Translation", "Acquire::Languages");
196 if (oldAcquire
!= "none")
197 codes
.push_back(oldAcquire
);
198 codes
.push_back("en");
200 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
201 b
!= builtin
.end(); ++b
)
202 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
203 allCodes
.push_back(*b
);
210 // It is very likely we will need to environment codes later,
211 // so let us generate them now from LC_MESSAGES and LANGUAGE
212 std::vector
<string
> environment
;
213 if (envShort
!= "C") {
214 // take care of LC_MESSAGES
215 if (envLongIncluded
== false)
216 environment
.push_back(envLong
);
217 environment
.push_back(envShort
);
218 // take care of LANGUAGE
219 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
220 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
221 if (envLang
.empty() == false) {
222 std::vector
<string
> env
= VectorizeString(envLang
,':');
223 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
224 for (std::vector
<string
>::const_iterator e
= env
.begin();
225 e
!= env
.end() && addedLangs
< 3; ++e
) {
226 if (unlikely(e
->empty() == true) || *e
== "en")
228 if (*e
== envLong
|| *e
== envShort
)
230 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
232 if (e
->find('_') != string::npos
) {
233 // Drop LongCodes here - ShortCodes are also included
234 string
const shorty
= e
->substr(0, e
->find('_'));
235 char const **n
= needLong
;
236 for (; *n
!= NULL
; ++n
)
243 environment
.push_back(*e
);
247 environment
.push_back("en");
250 // Support settings like Acquire::Translation=none on the command line to
251 // override the configuration settings vector of languages.
252 string
const forceLang
= _config
->Find("Acquire::Languages","");
253 if (forceLang
.empty() == false) {
254 if (forceLang
== "environment") {
256 } else if (forceLang
!= "none")
257 codes
.push_back(forceLang
);
259 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
260 b
!= builtin
.end(); ++b
)
261 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
262 allCodes
.push_back(*b
);
269 // cornercase: LANG=C, so we use only "en" Translation
270 if (envShort
== "C") {
271 allCodes
= codes
= environment
;
272 allCodes
.insert(allCodes
.end(), builtin
.begin(), builtin
.end());
279 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages");
280 // the default setting -> "environment, en"
281 if (lang
.empty() == true) {
283 if (envShort
!= "en")
284 codes
.push_back("en");
286 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
287 b
!= builtin
.end(); ++b
)
288 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
289 allCodes
.push_back(*b
);
296 // the configs define the order, so add the environment
297 // then needed and ensure the codes are not listed twice.
298 bool noneSeen
= false;
299 for (std::vector
<string
>::const_iterator l
= lang
.begin();
300 l
!= lang
.end(); l
++) {
301 if (*l
== "environment") {
302 for (std::vector
<string
>::const_iterator e
= environment
.begin();
303 e
!= environment
.end(); ++e
) {
304 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
306 if (noneSeen
== false)
308 allCodes
.push_back(*e
);
311 } else if (*l
== "none") {
314 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
317 if (noneSeen
== false)
319 allCodes
.push_back(*l
);
322 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
323 b
!= builtin
.end(); ++b
)
324 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
325 allCodes
.push_back(*b
);
333 // getArchitectures - Return Vector of prefered Architectures /*{{{*/
334 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
337 std::vector
<string
> static archs
;
338 if (likely(Cached
== true) && archs
.empty() == false)
341 archs
= _config
->FindVector("APT::Architectures");
342 string
const arch
= _config
->Find("APT::Architecture");
343 if (unlikely(arch
.empty() == true))
346 if (archs
.empty() == true ||
347 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
348 archs
.push_back(arch
);
350 // erase duplicates and empty strings
351 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
352 a
!= archs
.rend(); ++a
) {
353 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
354 archs
.erase(a
.base()-1);
355 if (a
== archs
.rend())
362 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
363 bool const Configuration::checkArchitecture(std::string
const &Arch
) {
366 std::vector
<std::string
> const archs
= getArchitectures(true);
367 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());