]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/deblistparser.cc
Merge remote-tracking branch 'upstream/debian/sid' into debian/sid
[apt.git] / apt-pkg / deb / deblistparser.cc
CommitLineData
f55a958f
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz Exp $
f55a958f
AL
4/* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
ea542140
DK
13#include <config.h>
14
094a497d
AL
15#include <apt-pkg/deblistparser.h>
16#include <apt-pkg/error.h>
17#include <apt-pkg/configuration.h>
424ff669 18#include <apt-pkg/cachefilter.h>
45df0ad2 19#include <apt-pkg/aptconfiguration.h>
cdcc6d34 20#include <apt-pkg/strutl.h>
472ff00e 21#include <apt-pkg/fileutl.h>
204fbdcc 22#include <apt-pkg/crc-16.h>
a52f938b 23#include <apt-pkg/md5.h>
453b82a3
DK
24#include <apt-pkg/mmap.h>
25#include <apt-pkg/pkgcache.h>
26#include <apt-pkg/cacheiterators.h>
27#include <apt-pkg/tagfile.h>
5c0d3668 28#include <apt-pkg/macros.h>
9c14e3d6 29
453b82a3
DK
30#include <stddef.h>
31#include <string.h>
32#include <algorithm>
33#include <string>
34#include <vector>
e7b470ee 35#include <ctype.h>
f55a958f
AL
36 /*}}}*/
37
8f3ba4e8
DK
38using std::string;
39
84de0cea
MV
40static debListParser::WordList PrioList[] = {
41 {"required",pkgCache::State::Required},
42 {"important",pkgCache::State::Important},
43 {"standard",pkgCache::State::Standard},
44 {"optional",pkgCache::State::Optional},
45 {"extra",pkgCache::State::Extra},
67c3067f 46 {NULL, 0}};
b2e465d6 47
f55a958f
AL
48// ListParser::debListParser - Constructor /*{{{*/
49// ---------------------------------------------------------------------
5dd4c8b8
DK
50/* Provide an architecture and only this one and "all" will be accepted
51 in Step(), if no Architecture is given we will accept every arch
52 we would accept in general with checkArchitecture() */
53debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
54 Arch(Arch) {
33dd02e3
DK
55 if (Arch == "native")
56 this->Arch = _config->Find("APT::Architecture");
dcfa253f
DK
57 Architectures = APT::Configuration::getArchitectures();
58 MultiArchEnabled = Architectures.size() > 1;
0149949b
AL
59}
60 /*}}}*/
f55a958f
AL
61// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
62// ---------------------------------------------------------------------
63/* */
64unsigned long debListParser::UniqFindTagWrite(const char *Tag)
65{
66 const char *Start;
67 const char *Stop;
68 if (Section.Find(Tag,Start,Stop) == false)
69 return 0;
70 return WriteUniqString(Start,Stop - Start);
71}
72 /*}}}*/
f55a958f
AL
73// ListParser::Package - Return the package name /*{{{*/
74// ---------------------------------------------------------------------
75/* This is to return the name of the package this section describes */
5bf15716 76string debListParser::Package() {
33dd02e3
DK
77 string const Result = Section.FindS("Package");
78 if(unlikely(Result.empty() == true))
79 _error->Error("Encountered a section with no Package: header");
80 return Result;
5bf15716
DK
81}
82 /*}}}*/
83// ListParser::Architecture - Return the package arch /*{{{*/
84// ---------------------------------------------------------------------
28166356 85/* This will return the Architecture of the package this section describes */
5bf15716 86string debListParser::Architecture() {
99a2ea5a 87 return Section.FindS("Architecture");
f55a958f
AL
88}
89 /*}}}*/
857e9c13
DK
90// ListParser::ArchitectureAll /*{{{*/
91// ---------------------------------------------------------------------
92/* */
93bool debListParser::ArchitectureAll() {
33dd02e3 94 return Section.FindS("Architecture") == "all";
f55a958f
AL
95}
96 /*}}}*/
97// ListParser::Version - Return the version string /*{{{*/
98// ---------------------------------------------------------------------
99/* This is to return the string describing the version in debian form,
100 epoch:upstream-release. If this returns the blank string then the
101 entry is assumed to only describe package properties */
102string debListParser::Version()
103{
b0b4efb9 104 return Section.FindS("Version");
f55a958f
AL
105}
106 /*}}}*/
e33dbfe5 107unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/
0149949b 108{
e33dbfe5 109 unsigned char MA;
28166356 110 string const MultiArch = Section.FindS("Multi-Arch");
8f617600 111 if (MultiArch.empty() == true || MultiArch == "no")
e33dbfe5 112 MA = pkgCache::Version::None;
28166356 113 else if (MultiArch == "same") {
ca238ede 114 if (ArchitectureAll() == true)
25396fb0 115 {
e33dbfe5
DK
116 if (showErrors == true)
117 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
118 Section.FindS("Package").c_str());
119 MA = pkgCache::Version::None;
25396fb0 120 }
28166356 121 else
e33dbfe5 122 MA = pkgCache::Version::Same;
28166356
DK
123 }
124 else if (MultiArch == "foreign")
e33dbfe5 125 MA = pkgCache::Version::Foreign;
28166356 126 else if (MultiArch == "allowed")
e33dbfe5 127 MA = pkgCache::Version::Allowed;
28166356
DK
128 else
129 {
e33dbfe5
DK
130 if (showErrors == true)
131 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
132 MultiArch.c_str(), Section.FindS("Package").c_str());
133 MA = pkgCache::Version::None;
25396fb0
DK
134 }
135
ca238ede 136 if (ArchitectureAll() == true)
e33dbfe5 137 MA |= pkgCache::Version::All;
ca238ede 138
e33dbfe5
DK
139 return MA;
140}
141 /*}}}*/
142// ListParser::NewVersion - Fill in the version structure /*{{{*/
143// ---------------------------------------------------------------------
144/* */
145bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
146{
147 // Parse the section
4ea471ec
DK
148 unsigned long const idxSection = UniqFindTagWrite("Section");
149 Ver->Section = idxSection;
e33dbfe5 150 Ver->MultiArch = ParseMultiArch(true);
0149949b 151 // Archive Size
e2c66de5 152 Ver->Size = Section.FindULL("Size");
0149949b 153 // Unpacked Size (in K)
e2c66de5 154 Ver->InstalledSize = Section.FindULL("Installed-Size");
0149949b
AL
155 Ver->InstalledSize *= 1024;
156
157 // Priority
158 const char *Start;
159 const char *Stop;
160 if (Section.Find("Priority",Start,Stop) == true)
b2e465d6
AL
161 {
162 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
421c8d10 163 Ver->Priority = pkgCache::State::Extra;
0149949b 164 }
dcb79bae 165
6c139d6e 166 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
dcb79bae 167 return false;
8efa2a3b 168 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
dcb79bae 169 return false;
6c139d6e 170 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
dcb79bae 171 return false;
6c139d6e 172 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
dcb79bae 173 return false;
6c139d6e 174 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
dcb79bae 175 return false;
308c7d30
IJ
176 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
177 return false;
f55ece0e 178 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
dcb79bae 179 return false;
f8ae7e8b 180 if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
181 return false;
dcb79bae 182
b2e465d6
AL
183 // Obsolete.
184 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
185 return false;
186
dcb79bae
AL
187 if (ParseProvides(Ver) == false)
188 return false;
0149949b 189
f55a958f
AL
190 return true;
191}
192 /*}}}*/
a52f938b
OS
193// ListParser::Description - Return the description string /*{{{*/
194// ---------------------------------------------------------------------
195/* This is to return the string describing the package in debian
196 form. If this returns the blank string then the entry is assumed to
197 only describe package properties */
198string debListParser::Description()
199{
45df0ad2
DK
200 string const lang = DescriptionLanguage();
201 if (lang.empty())
a52f938b
OS
202 return Section.FindS("Description");
203 else
45df0ad2 204 return Section.FindS(string("Description-").append(lang).c_str());
a52f938b
OS
205}
206 /*}}}*/
207// ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
208// ---------------------------------------------------------------------
209/* This is to return the string describing the language of
210 description. If this returns the blank string then the entry is
211 assumed to describe original description. */
212string debListParser::DescriptionLanguage()
213{
45df0ad2
DK
214 if (Section.FindS("Description").empty() == false)
215 return "";
216
85c26e8c 217 std::vector<string> const lang = APT::Configuration::getLanguages(true);
45df0ad2 218 for (std::vector<string>::const_iterator l = lang.begin();
f7f0d6c7 219 l != lang.end(); ++l)
45df0ad2
DK
220 if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false)
221 return *l;
222
223 return "";
a52f938b
OS
224}
225 /*}}}*/
226// ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
227// ---------------------------------------------------------------------
770c32ec
MV
228/* This is to return the md5 string to allow the check if it is the right
229 description. If no Description-md5 is found in the section it will be
230 calculated.
231 */
a52f938b
OS
232MD5SumValue debListParser::Description_md5()
233{
fc691496
DK
234 string const value = Section.FindS("Description-md5");
235 if (value.empty() == true)
770c32ec 236 {
99359751
DK
237 std::string const desc = Description() + "\n";
238 if (desc == "\n")
239 return MD5SumValue();
240
a52f938b 241 MD5Summation md5;
99359751 242 md5.Add(desc.c_str());
a52f938b 243 return md5.Result();
fc691496
DK
244 }
245 else if (likely(value.size() == 32))
246 {
247 if (likely(value.find_first_not_of("0123456789abcdefABCDEF") == string::npos))
248 return MD5SumValue(value);
249 _error->Error("Malformed Description-md5 line; includes invalid character '%s'", value.c_str());
250 return MD5SumValue();
251 }
252 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%s'", (int)value.size(), value.c_str());
253 return MD5SumValue();
a52f938b
OS
254}
255 /*}}}*/
f55a958f
AL
256// ListParser::UsePackage - Update a package structure /*{{{*/
257// ---------------------------------------------------------------------
258/* This is called to update the package with any new information
259 that might be found in the section */
32b9a14c
DK
260bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
261 pkgCache::VerIterator &Ver)
f55a958f
AL
262{
263 if (Pkg->Section == 0)
4ea471ec
DK
264 {
265 unsigned long const idxSection = UniqFindTagWrite("Section");
266 Pkg->Section = idxSection;
267 }
5dd4c8b8 268
5dd4c8b8 269 string const static myArch = _config->Find("APT::Architecture");
e5a91f7e
DK
270 // Possible values are: "all", "native", "installed" and "none"
271 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
272 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
273 if (essential == "all" ||
274 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
5dd4c8b8
DK
275 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
276 return false;
138d4b3d 277 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
f55a958f 278 return false;
138d4b3d
AL
279
280 if (strcmp(Pkg.Name(),"apt") == 0)
a552f37e
DK
281 {
282 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
283 essential == "all")
284 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
285 else
286 Pkg->Flags |= pkgCache::Flag::Important;
287 }
288
f55a958f
AL
289 if (ParseStatus(Pkg,Ver) == false)
290 return false;
291 return true;
292}
293 /*}}}*/
204fbdcc
AL
294// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
295// ---------------------------------------------------------------------
296/* */
297unsigned short debListParser::VersionHash()
298{
299 const char *Sections[] ={"Installed-Size",
300 "Depends",
301 "Pre-Depends",
f78439bf
AL
302// "Suggests",
303// "Recommends",
204fbdcc 304 "Conflicts",
308c7d30 305 "Breaks",
204fbdcc
AL
306 "Replaces",0};
307 unsigned long Result = INIT_FCS;
418a471f 308 char S[1024];
d9682cf8 309 for (const char * const *I = Sections; *I != 0; ++I)
204fbdcc
AL
310 {
311 const char *Start;
312 const char *End;
313 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
314 continue;
315
316 /* Strip out any spaces from the text, this undoes dpkgs reformatting
421c8d10
AL
317 of certain fields. dpkg also has the rather interesting notion of
318 reformatting depends operators < -> <= */
470a5c38 319 char *J = S;
d9682cf8 320 for (; Start != End; ++Start)
421c8d10 321 {
d9682cf8
DK
322 if (isspace(*Start) != 0)
323 continue;
324 *J++ = tolower_ascii(*Start);
325
326 if ((*Start == '<' || *Start == '>') && Start[1] != *Start && Start[1] != '=')
470a5c38 327 *J++ = '=';
421c8d10 328 }
418a471f 329
470a5c38 330 Result = AddCRC16(Result,S,J - S);
204fbdcc
AL
331 }
332
333 return Result;
334}
335 /*}}}*/
dcb79bae 336// ListParser::ParseStatus - Parse the status field /*{{{*/
f55a958f
AL
337// ---------------------------------------------------------------------
338/* Status lines are of the form,
339 Status: want flag status
340 want = unknown, install, hold, deinstall, purge
9227645d
GJ
341 flag = ok, reinstreq
342 status = not-installed, config-files, half-installed, unpacked,
343 half-configured, triggers-awaited, triggers-pending, installed
f55a958f 344 */
32b9a14c
DK
345bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
346 pkgCache::VerIterator &Ver)
f55a958f
AL
347{
348 const char *Start;
349 const char *Stop;
350 if (Section.Find("Status",Start,Stop) == false)
351 return true;
6bc703c2
DK
352
353 // UsePackage() is responsible for setting the flag in the default case
354 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
355 if (essential == true &&
356 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
357 return false;
358
f55a958f
AL
359 // Isolate the first word
360 const char *I = Start;
361 for(; I < Stop && *I != ' '; I++);
362 if (I >= Stop || *I != ' ')
363 return _error->Error("Malformed Status line");
364
365 // Process the want field
6c139d6e
AL
366 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
367 {"install",pkgCache::State::Install},
368 {"hold",pkgCache::State::Hold},
369 {"deinstall",pkgCache::State::DeInstall},
b2e465d6 370 {"purge",pkgCache::State::Purge},
67c3067f 371 {NULL, 0}};
b2e465d6 372 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
f55a958f
AL
373 return _error->Error("Malformed 1st word in the Status line");
374
375 // Isloate the next word
376 I++;
377 Start = I;
378 for(; I < Stop && *I != ' '; I++);
379 if (I >= Stop || *I != ' ')
380 return _error->Error("Malformed status line, no 2nd word");
381
382 // Process the flag field
6c139d6e
AL
383 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
384 {"reinstreq",pkgCache::State::ReInstReq},
385 {"hold",pkgCache::State::HoldInst},
b2e465d6 386 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
67c3067f 387 {NULL, 0}};
b2e465d6 388 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
f55a958f
AL
389 return _error->Error("Malformed 2nd word in the Status line");
390
391 // Isloate the last word
392 I++;
393 Start = I;
394 for(; I < Stop && *I != ' '; I++);
395 if (I != Stop)
396 return _error->Error("Malformed Status line, no 3rd word");
397
398 // Process the flag field
6c139d6e 399 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
9227645d
GJ
400 {"config-files",pkgCache::State::ConfigFiles},
401 {"half-installed",pkgCache::State::HalfInstalled},
6c139d6e
AL
402 {"unpacked",pkgCache::State::UnPacked},
403 {"half-configured",pkgCache::State::HalfConfigured},
9d06bc80
MV
404 {"triggers-awaited",pkgCache::State::TriggersAwaited},
405 {"triggers-pending",pkgCache::State::TriggersPending},
9227645d 406 {"installed",pkgCache::State::Installed},
67c3067f 407 {NULL, 0}};
b2e465d6 408 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
f55a958f
AL
409 return _error->Error("Malformed 3rd word in the Status line");
410
411 /* A Status line marks the package as indicating the current
412 version as well. Only if it is actually installed.. Otherwise
413 the interesting dpkg handling of the status file creates bogus
414 entries. */
6c139d6e
AL
415 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
416 Pkg->CurrentState == pkgCache::State::ConfigFiles))
f55a958f
AL
417 {
418 if (Ver.end() == true)
419 _error->Warning("Encountered status field in a non-version description");
420 else
421 Pkg->CurrentVer = Ver.Index();
422 }
423
dcb79bae
AL
424 return true;
425}
a1826878 426
b2e465d6
AL
427const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
428{
429 // Determine the operator
430 switch (*I)
431 {
432 case '<':
433 I++;
434 if (*I == '=')
435 {
436 I++;
437 Op = pkgCache::Dep::LessEq;
438 break;
439 }
440
441 if (*I == '<')
442 {
443 I++;
444 Op = pkgCache::Dep::Less;
445 break;
446 }
447
448 // < is the same as <= and << is really Cs < for some reason
449 Op = pkgCache::Dep::LessEq;
450 break;
451
452 case '>':
453 I++;
454 if (*I == '=')
455 {
456 I++;
457 Op = pkgCache::Dep::GreaterEq;
458 break;
459 }
460
461 if (*I == '>')
462 {
463 I++;
464 Op = pkgCache::Dep::Greater;
465 break;
466 }
467
468 // > is the same as >= and >> is really Cs > for some reason
469 Op = pkgCache::Dep::GreaterEq;
470 break;
471
472 case '=':
473 Op = pkgCache::Dep::Equals;
474 I++;
475 break;
476
477 // HACK around bad package definitions
478 default:
479 Op = pkgCache::Dep::Equals;
480 break;
481 }
482 return I;
483}
a1826878
AL
484 /*}}}*/
485// ListParser::ParseDepends - Parse a dependency element /*{{{*/
486// ---------------------------------------------------------------------
487/* This parses the dependency elements out of a standard string in place,
488 bit by bit. */
565ded7b
JS
489const char *debListParser::ParseDepends(const char *Start,const char *Stop,
490 std::string &Package,std::string &Ver,unsigned int &Op)
491 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
492const char *debListParser::ParseDepends(const char *Start,const char *Stop,
493 std::string &Package,std::string &Ver,unsigned int &Op,
494 bool const &ParseArchFlags)
495 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
496const char *debListParser::ParseDepends(const char *Start,const char *Stop,
497 std::string &Package,std::string &Ver,unsigned int &Op,
498 bool const &ParseArchFlags, bool const &StripMultiArch)
499 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
dcb79bae
AL
500const char *debListParser::ParseDepends(const char *Start,const char *Stop,
501 string &Package,string &Ver,
41c81fd8 502 unsigned int &Op, bool const &ParseArchFlags,
565ded7b
JS
503 bool const &StripMultiArch,
504 bool const &ParseRestrictionsList)
dcb79bae
AL
505{
506 // Strip off leading space
565ded7b 507 for (;Start != Stop && isspace(*Start) != 0; ++Start);
dcb79bae
AL
508
509 // Parse off the package name
510 const char *I = Start;
511 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
565ded7b
JS
512 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
513 *I != '<' && *I != '>'; ++I);
dcb79bae
AL
514
515 // Malformed, no '('
516 if (I != Stop && *I == ')')
517 return 0;
518
519 if (I == Start)
520 return 0;
521
522 // Stash the package name
523 Package.assign(Start,I - Start);
41c81fd8
DK
524
525 // We don't want to confuse library users which can't handle MultiArch
550f6493 526 string const arch = _config->Find("APT::Architecture");
41c81fd8
DK
527 if (StripMultiArch == true) {
528 size_t const found = Package.rfind(':');
550f6493
DK
529 if (found != string::npos &&
530 (strcmp(Package.c_str() + found, ":any") == 0 ||
531 strcmp(Package.c_str() + found, ":native") == 0 ||
532 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
41c81fd8
DK
533 Package = Package.substr(0,found);
534 }
535
dcb79bae
AL
536 // Skip white space to the '('
537 for (;I != Stop && isspace(*I) != 0 ; I++);
538
539 // Parse a version
540 if (I != Stop && *I == '(')
541 {
542 // Skip the '('
543 for (I++; I != Stop && isspace(*I) != 0 ; I++);
544 if (I + 3 >= Stop)
545 return 0;
b2e465d6 546 I = ConvertRelation(I,Op);
dcb79bae
AL
547
548 // Skip whitespace
549 for (;I != Stop && isspace(*I) != 0; I++);
550 Start = I;
404528bd
DK
551 I = (const char*) memchr(I, ')', Stop - I);
552 if (I == NULL || Start == I)
553 return 0;
dcb79bae 554
02f000a9
AL
555 // Skip trailing whitespace
556 const char *End = I;
557 for (; End > Start && isspace(End[-1]); End--);
558
171c75f1 559 Ver.assign(Start,End-Start);
dcb79bae
AL
560 I++;
561 }
562 else
563 {
171c75f1 564 Ver.clear();
6c139d6e 565 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
566 }
567
568 // Skip whitespace
569 for (;I != Stop && isspace(*I) != 0; I++);
b2e465d6
AL
570
571 if (ParseArchFlags == true)
572 {
424ff669 573 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
9e10ad8a 574
b2e465d6
AL
575 // Parse an architecture
576 if (I != Stop && *I == '[')
577 {
cd9694bf 578 ++I;
b2e465d6 579 // malformed
cd9694bf
DK
580 if (unlikely(I == Stop))
581 return 0;
582
583 const char *End = I;
584 bool Found = false;
585 bool NegArch = false;
586 while (I != Stop)
b2e465d6 587 {
cd9694bf
DK
588 // look for whitespace or ending ']'
589 for (;End != Stop && !isspace(*End) && *End != ']'; ++End);
590
591 if (unlikely(End == Stop))
b2e465d6 592 return 0;
9e10ad8a
AL
593
594 if (*I == '!')
cd9694bf 595 {
9e10ad8a 596 NegArch = true;
cd9694bf
DK
597 ++I;
598 }
9e10ad8a 599
424ff669
DK
600 std::string arch(I, End);
601 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
cd9694bf 602 {
424ff669 603 Found = true;
cd9694bf
DK
604 if (I[-1] != '!')
605 NegArch = false;
606 // we found a match, so fast-forward to the end of the wildcards
607 for (; End != Stop && *End != ']'; ++End);
608 }
609
b2e465d6
AL
610 if (*End++ == ']') {
611 I = End;
612 break;
613 }
cd9694bf 614
b2e465d6
AL
615 I = End;
616 for (;I != Stop && isspace(*I) != 0; I++);
cd9694bf 617 }
9e10ad8a 618
cd9694bf 619 if (NegArch == true)
9e10ad8a 620 Found = !Found;
cd9694bf
DK
621
622 if (Found == false)
b2e465d6
AL
623 Package = ""; /* not for this arch */
624 }
cd9694bf 625
b2e465d6
AL
626 // Skip whitespace
627 for (;I != Stop && isspace(*I) != 0; I++);
628 }
629
565ded7b
JS
630 if (ParseRestrictionsList == true)
631 {
ac81c0f9 632 // Parse a restrictions formula which is in disjunctive normal form:
633 // (foo AND bar) OR (blub AND bla)
634
635 std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
636
637 // if the next character is a restriction list, then by default the
638 // dependency does not apply and the conditions have to be checked
639 // if the next character is not a restriction list, then by default the
640 // dependency applies
641 bool applies1 = (*I != '<');
642 while (I != Stop)
565ded7b 643 {
ac81c0f9 644 if (*I != '<')
645 break;
646
565ded7b
JS
647 ++I;
648 // malformed
649 if (unlikely(I == Stop))
650 return 0;
651
565ded7b 652 const char *End = I;
565ded7b 653
ac81c0f9 654 // if of the prior restriction list is already fulfilled, then
655 // we can just skip to the end of the current list
656 if (applies1) {
657 for (;End != Stop && *End != '>'; ++End);
658 I = ++End;
659 // skip whitespace
660 for (;I != Stop && isspace(*I) != 0; I++);
661 } else {
662 bool applies2 = true;
663 // all the conditions inside a restriction list have to be
664 // met so once we find one that is not met, we can skip to
665 // the end of this list
666 while (I != Stop)
565ded7b 667 {
ac81c0f9 668 // look for whitespace or ending '>'
669 // End now points to the character after the current term
670 for (;End != Stop && !isspace(*End) && *End != '>'; ++End);
565ded7b 671
ac81c0f9 672 if (unlikely(End == Stop))
673 return 0;
565ded7b 674
ac81c0f9 675 bool NegRestriction = false;
676 if (*I == '!')
677 {
678 NegRestriction = true;
679 ++I;
680 }
681
682 std::string restriction(I, End);
565ded7b
JS
683
684 if (restriction.empty() == false && profiles.empty() == false &&
ac81c0f9 685 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
565ded7b 686 {
ac81c0f9 687 if (NegRestriction) {
688 applies2 = false;
689 // since one of the terms does not apply we don't have to check the others
690 for (; End != Stop && *End != '>'; ++End);
691 }
692 } else {
693 if (!NegRestriction) {
694 applies2 = false;
695 // since one of the terms does not apply we don't have to check the others
696 for (; End != Stop && *End != '>'; ++End);
697 }
698 }
699
700 if (*End++ == '>') {
701 I = End;
702 // skip whitespace
703 for (;I != Stop && isspace(*I) != 0; I++);
704 break;
565ded7b 705 }
565ded7b 706
565ded7b 707 I = End;
ac81c0f9 708 // skip whitespace
709 for (;I != Stop && isspace(*I) != 0; I++);
710 }
711 if (applies2) {
712 applies1 = true;
565ded7b 713 }
565ded7b 714 }
565ded7b
JS
715 }
716
ac81c0f9 717 if (applies1 == false) {
718 Package = ""; //not for this restriction
719 }
565ded7b
JS
720 }
721
dcb79bae 722 if (I != Stop && *I == '|')
6c139d6e 723 Op |= pkgCache::Dep::Or;
dcb79bae
AL
724
725 if (I == Stop || *I == ',' || *I == '|')
726 {
727 if (I != Stop)
728 for (I++; I != Stop && isspace(*I) != 0; I++);
729 return I;
730 }
731
732 return 0;
733}
734 /*}}}*/
735// ListParser::ParseDepends - Parse a dependency list /*{{{*/
736// ---------------------------------------------------------------------
737/* This is the higher level depends parser. It takes a tag and generates
738 a complete depends tree for the given version. */
32b9a14c 739bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
dcb79bae
AL
740 const char *Tag,unsigned int Type)
741{
742 const char *Start;
743 const char *Stop;
744 if (Section.Find(Tag,Start,Stop) == false)
745 return true;
306eacf6 746
28166356 747 string const pkgArch = Ver.Arch();
dcb79bae 748
8efa2a3b 749 while (1)
dcb79bae 750 {
0f485ee5
TG
751 string Package;
752 string Version;
753 unsigned int Op;
754
565ded7b 755 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
dcb79bae
AL
756 if (Start == 0)
757 return _error->Error("Problem parsing dependency %s",Tag);
0f485ee5 758 size_t const found = Package.rfind(':');
306eacf6 759
cef094c2
DK
760 // If negative is unspecific it needs to apply on all architectures
761 if (MultiArchEnabled == true && found == string::npos &&
306eacf6
DK
762 (Type == pkgCache::Dep::Conflicts ||
763 Type == pkgCache::Dep::DpkgBreaks ||
764 Type == pkgCache::Dep::Replaces))
765 {
dcfa253f
DK
766 for (std::vector<std::string>::const_iterator a = Architectures.begin();
767 a != Architectures.end(); ++a)
306eacf6
DK
768 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
769 return false;
c919ad6e
DK
770 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
771 return false;
306eacf6 772 }
0f485ee5
TG
773 else if (MultiArchEnabled == true && found != string::npos &&
774 strcmp(Package.c_str() + found, ":any") != 0)
775 {
776 string Arch = Package.substr(found+1, string::npos);
777 Package = Package.substr(0, found);
778 // Such dependencies are not supposed to be accepted …
779 // … but this is probably the best thing to do.
780 if (Arch == "native")
781 Arch = _config->Find("APT::Architecture");
782 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
783 return false;
784 }
c919ad6e
DK
785 else
786 {
787 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
788 return false;
789 if ((Type == pkgCache::Dep::Conflicts ||
790 Type == pkgCache::Dep::DpkgBreaks ||
791 Type == pkgCache::Dep::Replaces) &&
792 NewDepends(Ver, Package,
793 (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"),
794 Version,Op,Type) == false)
795 return false;
796 }
8efa2a3b
AL
797 if (Start == Stop)
798 break;
dcb79bae
AL
799 }
800 return true;
801}
802 /*}}}*/
803// ListParser::ParseProvides - Parse the provides list /*{{{*/
804// ---------------------------------------------------------------------
805/* */
32b9a14c 806bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae
AL
807{
808 const char *Start;
809 const char *Stop;
67e0766f 810 if (Section.Find("Provides",Start,Stop) == true)
dcb79bae 811 {
67e0766f
DK
812 string Package;
813 string Version;
28166356 814 string const Arch = Ver.Arch();
67e0766f
DK
815 unsigned int Op;
816
817 while (1)
818 {
819 Start = ParseDepends(Start,Stop,Package,Version,Op);
820 if (Start == 0)
821 return _error->Error("Problem parsing Provides line");
40faab46
DK
822 if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) {
823 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str());
04340db3
DK
824 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
825 if (NewProvidesAllArch(Ver, Package, Version) == false)
826 return false;
67e0766f
DK
827 } else {
828 if (NewProvides(Ver, Package, Arch, Version) == false)
829 return false;
830 }
831
832 if (Start == Stop)
833 break;
b63380b0 834 }
67e0766f 835 }
dcb79bae 836
b4140ecf 837 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
4d174dc8
DK
838 {
839 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
60dcec6d 840 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
dcb79bae 841 }
894d672e 842 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
60dcec6d 843 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
dcb79bae 844
60dcec6d
DK
845 return true;
846}
847 /*}}}*/
848// ListParser::NewProvides - add provides for all architectures /*{{{*/
849bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
850 string const &Version) {
dcfa253f
DK
851 for (std::vector<string>::const_iterator a = Architectures.begin();
852 a != Architectures.end(); ++a)
67e0766f
DK
853 {
854 if (NewProvides(Ver, Package, *a, Version) == false)
855 return false;
dcb79bae 856 }
f55a958f
AL
857 return true;
858}
859 /*}}}*/
860// ListParser::GrabWord - Matches a word and returns /*{{{*/
861// ---------------------------------------------------------------------
862/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 863bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 864{
b2e465d6 865 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
866 {
867 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
868 {
869 Out = List[C].Val;
870 return true;
871 }
872 }
873 return false;
874}
875 /*}}}*/
876// ListParser::Step - Move to the next section in the file /*{{{*/
877// ---------------------------------------------------------------------
1e3f4083 878/* This has to be careful to only process the correct architecture */
f55a958f
AL
879bool debListParser::Step()
880{
dcb79bae 881 iOffset = Tags.Offset();
0149949b 882 while (Tags.Step(Section) == true)
ddc1d8d0
AL
883 {
884 /* See if this is the correct Architecture, if it isn't then we
885 drop the whole section. A missing arch tag only happens (in theory)
886 inside the Status file, so that is a positive return */
5dd4c8b8 887 string const Architecture = Section.FindS("Architecture");
9c14e3d6 888
dd13742e 889 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
5dd4c8b8
DK
890 {
891 if (APT::Configuration::checkArchitecture(Architecture) == true)
892 return true;
c919ad6e
DK
893 /* parse version stanzas without an architecture only in the status file
894 (and as misfortune bycatch flat-archives) */
895 if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true)
896 return true;
5dd4c8b8
DK
897 }
898 else
899 {
900 if (Architecture == Arch)
901 return true;
0149949b 902
28166356 903 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
5dd4c8b8
DK
904 return true;
905 }
dcb79bae
AL
906
907 iOffset = Tags.Offset();
0149949b
AL
908 }
909 return false;
f55a958f
AL
910}
911 /*}}}*/
b0b4efb9
AL
912// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
913// ---------------------------------------------------------------------
914/* */
32b9a14c 915bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
f2152f03 916 FileFd &File, string component)
b0b4efb9 917{
f2152f03
MV
918 // apt-secure does no longer download individual (per-section) Release
919 // file. to provide Component pinning we use the section name now
2b803d40
DK
920 map_ptrloc const storage = WriteUniqString(component);
921 FileI->Component = storage;
f2152f03 922
233d79a5 923 pkgTagFile TagFile(&File, File.Size());
e9737c7f
DK
924 pkgTagSection Section;
925 if (_error->PendingError() == true || TagFile.Step(Section) == false)
fe0f7911
DK
926 return false;
927
e9737c7f
DK
928 std::string data;
929 #define APT_INRELEASE(TAG, STORE) \
930 data = Section.FindS(TAG); \
931 if (data.empty() == false) \
932 { \
933 map_ptrloc const storage = WriteUniqString(data); \
934 STORE = storage; \
fe0f7911 935 }
e9737c7f
DK
936 APT_INRELEASE("Suite", FileI->Archive)
937 APT_INRELEASE("Component", FileI->Component)
938 APT_INRELEASE("Version", FileI->Version)
939 APT_INRELEASE("Origin", FileI->Origin)
940 APT_INRELEASE("Codename", FileI->Codename)
941 APT_INRELEASE("Label", FileI->Label)
942 #undef APT_INRELEASE
943 Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic);
944 Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades);
f2152f03 945
b0b4efb9
AL
946 return !_error->PendingError();
947}
948 /*}}}*/
b2e465d6
AL
949// ListParser::GetPrio - Convert the priority from a string /*{{{*/
950// ---------------------------------------------------------------------
951/* */
952unsigned char debListParser::GetPrio(string Str)
953{
954 unsigned char Out;
955 if (GrabWord(Str,PrioList,Out) == false)
956 Out = pkgCache::State::Extra;
957
958 return Out;
959}
960 /*}}}*/
68134bda
DK
961#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
962bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
963 pkgCache::VerIterator const &Ver)
964{
965 if (pkgCacheGenerator::ListParser::SameVersion(Hash, Ver) == false)
966 return false;
967 // status file has no (Download)Size, but all others are fair game
968 // status file is parsed last, so the first version we encounter is
969 // probably also the version we have downloaded
970 unsigned long long const Size = Section.FindULL("Size");
971 if (Size != 0 && Size != Ver->Size)
972 return false;
973 // available everywhere, but easier to check here than to include in VersionHash
974 unsigned char MultiArch = ParseMultiArch(false);
975 if (MultiArch != Ver->MultiArch)
976 return false;
977 // for all practical proposes (we can check): same version
978 return true;
979}
980 /*}}}*/
981#endif