implement the updated build profile spec
[ntk/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
341 flag = ok, reinstreq, hold, hold-reinstreq
a005475e 342 status = not-installed, unpacked, half-configured,
f55a958f
AL
343 half-installed, config-files, post-inst-failed,
344 removal-failed, installed
345
346 Some of the above are obsolete (I think?) flag = hold-* and
347 status = post-inst-failed, removal-failed at least.
348 */
32b9a14c
DK
349bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
350 pkgCache::VerIterator &Ver)
f55a958f
AL
351{
352 const char *Start;
353 const char *Stop;
354 if (Section.Find("Status",Start,Stop) == false)
355 return true;
6bc703c2
DK
356
357 // UsePackage() is responsible for setting the flag in the default case
358 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
359 if (essential == true &&
360 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
361 return false;
362
f55a958f
AL
363 // Isolate the first word
364 const char *I = Start;
365 for(; I < Stop && *I != ' '; I++);
366 if (I >= Stop || *I != ' ')
367 return _error->Error("Malformed Status line");
368
369 // Process the want field
6c139d6e
AL
370 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
371 {"install",pkgCache::State::Install},
372 {"hold",pkgCache::State::Hold},
373 {"deinstall",pkgCache::State::DeInstall},
b2e465d6 374 {"purge",pkgCache::State::Purge},
67c3067f 375 {NULL, 0}};
b2e465d6 376 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
f55a958f
AL
377 return _error->Error("Malformed 1st word in the Status line");
378
379 // Isloate the next word
380 I++;
381 Start = I;
382 for(; I < Stop && *I != ' '; I++);
383 if (I >= Stop || *I != ' ')
384 return _error->Error("Malformed status line, no 2nd word");
385
386 // Process the flag field
6c139d6e
AL
387 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
388 {"reinstreq",pkgCache::State::ReInstReq},
389 {"hold",pkgCache::State::HoldInst},
b2e465d6 390 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
67c3067f 391 {NULL, 0}};
b2e465d6 392 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
f55a958f
AL
393 return _error->Error("Malformed 2nd word in the Status line");
394
395 // Isloate the last word
396 I++;
397 Start = I;
398 for(; I < Stop && *I != ' '; I++);
399 if (I != Stop)
400 return _error->Error("Malformed Status line, no 3rd word");
401
402 // Process the flag field
6c139d6e
AL
403 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
404 {"unpacked",pkgCache::State::UnPacked},
405 {"half-configured",pkgCache::State::HalfConfigured},
406 {"installed",pkgCache::State::Installed},
6c139d6e
AL
407 {"half-installed",pkgCache::State::HalfInstalled},
408 {"config-files",pkgCache::State::ConfigFiles},
9d06bc80
MV
409 {"triggers-awaited",pkgCache::State::TriggersAwaited},
410 {"triggers-pending",pkgCache::State::TriggersPending},
6c139d6e 411 {"post-inst-failed",pkgCache::State::HalfConfigured},
b2e465d6 412 {"removal-failed",pkgCache::State::HalfInstalled},
67c3067f 413 {NULL, 0}};
b2e465d6 414 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
f55a958f
AL
415 return _error->Error("Malformed 3rd word in the Status line");
416
417 /* A Status line marks the package as indicating the current
418 version as well. Only if it is actually installed.. Otherwise
419 the interesting dpkg handling of the status file creates bogus
420 entries. */
6c139d6e
AL
421 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
422 Pkg->CurrentState == pkgCache::State::ConfigFiles))
f55a958f
AL
423 {
424 if (Ver.end() == true)
425 _error->Warning("Encountered status field in a non-version description");
426 else
427 Pkg->CurrentVer = Ver.Index();
428 }
429
dcb79bae
AL
430 return true;
431}
a1826878 432
b2e465d6
AL
433const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
434{
435 // Determine the operator
436 switch (*I)
437 {
438 case '<':
439 I++;
440 if (*I == '=')
441 {
442 I++;
443 Op = pkgCache::Dep::LessEq;
444 break;
445 }
446
447 if (*I == '<')
448 {
449 I++;
450 Op = pkgCache::Dep::Less;
451 break;
452 }
453
454 // < is the same as <= and << is really Cs < for some reason
455 Op = pkgCache::Dep::LessEq;
456 break;
457
458 case '>':
459 I++;
460 if (*I == '=')
461 {
462 I++;
463 Op = pkgCache::Dep::GreaterEq;
464 break;
465 }
466
467 if (*I == '>')
468 {
469 I++;
470 Op = pkgCache::Dep::Greater;
471 break;
472 }
473
474 // > is the same as >= and >> is really Cs > for some reason
475 Op = pkgCache::Dep::GreaterEq;
476 break;
477
478 case '=':
479 Op = pkgCache::Dep::Equals;
480 I++;
481 break;
482
483 // HACK around bad package definitions
484 default:
485 Op = pkgCache::Dep::Equals;
486 break;
487 }
488 return I;
489}
a1826878
AL
490 /*}}}*/
491// ListParser::ParseDepends - Parse a dependency element /*{{{*/
492// ---------------------------------------------------------------------
493/* This parses the dependency elements out of a standard string in place,
494 bit by bit. */
565ded7b
JS
495const char *debListParser::ParseDepends(const char *Start,const char *Stop,
496 std::string &Package,std::string &Ver,unsigned int &Op)
497 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
498const char *debListParser::ParseDepends(const char *Start,const char *Stop,
499 std::string &Package,std::string &Ver,unsigned int &Op,
500 bool const &ParseArchFlags)
501 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
502const char *debListParser::ParseDepends(const char *Start,const char *Stop,
503 std::string &Package,std::string &Ver,unsigned int &Op,
504 bool const &ParseArchFlags, bool const &StripMultiArch)
505 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
dcb79bae
AL
506const char *debListParser::ParseDepends(const char *Start,const char *Stop,
507 string &Package,string &Ver,
41c81fd8 508 unsigned int &Op, bool const &ParseArchFlags,
565ded7b
JS
509 bool const &StripMultiArch,
510 bool const &ParseRestrictionsList)
dcb79bae
AL
511{
512 // Strip off leading space
565ded7b 513 for (;Start != Stop && isspace(*Start) != 0; ++Start);
dcb79bae
AL
514
515 // Parse off the package name
516 const char *I = Start;
517 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
565ded7b
JS
518 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
519 *I != '<' && *I != '>'; ++I);
dcb79bae
AL
520
521 // Malformed, no '('
522 if (I != Stop && *I == ')')
523 return 0;
524
525 if (I == Start)
526 return 0;
527
528 // Stash the package name
529 Package.assign(Start,I - Start);
41c81fd8
DK
530
531 // We don't want to confuse library users which can't handle MultiArch
550f6493 532 string const arch = _config->Find("APT::Architecture");
41c81fd8
DK
533 if (StripMultiArch == true) {
534 size_t const found = Package.rfind(':');
550f6493
DK
535 if (found != string::npos &&
536 (strcmp(Package.c_str() + found, ":any") == 0 ||
537 strcmp(Package.c_str() + found, ":native") == 0 ||
538 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
41c81fd8
DK
539 Package = Package.substr(0,found);
540 }
541
dcb79bae
AL
542 // Skip white space to the '('
543 for (;I != Stop && isspace(*I) != 0 ; I++);
544
545 // Parse a version
546 if (I != Stop && *I == '(')
547 {
548 // Skip the '('
549 for (I++; I != Stop && isspace(*I) != 0 ; I++);
550 if (I + 3 >= Stop)
551 return 0;
b2e465d6 552 I = ConvertRelation(I,Op);
dcb79bae
AL
553
554 // Skip whitespace
555 for (;I != Stop && isspace(*I) != 0; I++);
556 Start = I;
404528bd
DK
557 I = (const char*) memchr(I, ')', Stop - I);
558 if (I == NULL || Start == I)
559 return 0;
dcb79bae 560
02f000a9
AL
561 // Skip trailing whitespace
562 const char *End = I;
563 for (; End > Start && isspace(End[-1]); End--);
564
171c75f1 565 Ver.assign(Start,End-Start);
dcb79bae
AL
566 I++;
567 }
568 else
569 {
171c75f1 570 Ver.clear();
6c139d6e 571 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
572 }
573
574 // Skip whitespace
575 for (;I != Stop && isspace(*I) != 0; I++);
b2e465d6
AL
576
577 if (ParseArchFlags == true)
578 {
424ff669 579 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
9e10ad8a 580
b2e465d6
AL
581 // Parse an architecture
582 if (I != Stop && *I == '[')
583 {
cd9694bf 584 ++I;
b2e465d6 585 // malformed
cd9694bf
DK
586 if (unlikely(I == Stop))
587 return 0;
588
589 const char *End = I;
590 bool Found = false;
591 bool NegArch = false;
592 while (I != Stop)
b2e465d6 593 {
cd9694bf
DK
594 // look for whitespace or ending ']'
595 for (;End != Stop && !isspace(*End) && *End != ']'; ++End);
596
597 if (unlikely(End == Stop))
b2e465d6 598 return 0;
9e10ad8a
AL
599
600 if (*I == '!')
cd9694bf 601 {
9e10ad8a 602 NegArch = true;
cd9694bf
DK
603 ++I;
604 }
9e10ad8a 605
424ff669
DK
606 std::string arch(I, End);
607 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
cd9694bf 608 {
424ff669 609 Found = true;
cd9694bf
DK
610 if (I[-1] != '!')
611 NegArch = false;
612 // we found a match, so fast-forward to the end of the wildcards
613 for (; End != Stop && *End != ']'; ++End);
614 }
615
b2e465d6
AL
616 if (*End++ == ']') {
617 I = End;
618 break;
619 }
cd9694bf 620
b2e465d6
AL
621 I = End;
622 for (;I != Stop && isspace(*I) != 0; I++);
cd9694bf 623 }
9e10ad8a 624
cd9694bf 625 if (NegArch == true)
9e10ad8a 626 Found = !Found;
cd9694bf
DK
627
628 if (Found == false)
b2e465d6
AL
629 Package = ""; /* not for this arch */
630 }
cd9694bf 631
b2e465d6
AL
632 // Skip whitespace
633 for (;I != Stop && isspace(*I) != 0; I++);
634 }
635
565ded7b
JS
636 if (ParseRestrictionsList == true)
637 {
ac81c0f9 638 // Parse a restrictions formula which is in disjunctive normal form:
639 // (foo AND bar) OR (blub AND bla)
640
641 std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
642
643 // if the next character is a restriction list, then by default the
644 // dependency does not apply and the conditions have to be checked
645 // if the next character is not a restriction list, then by default the
646 // dependency applies
647 bool applies1 = (*I != '<');
648 while (I != Stop)
565ded7b 649 {
ac81c0f9 650 if (*I != '<')
651 break;
652
565ded7b
JS
653 ++I;
654 // malformed
655 if (unlikely(I == Stop))
656 return 0;
657
565ded7b 658 const char *End = I;
565ded7b 659
ac81c0f9 660 // if of the prior restriction list is already fulfilled, then
661 // we can just skip to the end of the current list
662 if (applies1) {
663 for (;End != Stop && *End != '>'; ++End);
664 I = ++End;
665 // skip whitespace
666 for (;I != Stop && isspace(*I) != 0; I++);
667 } else {
668 bool applies2 = true;
669 // all the conditions inside a restriction list have to be
670 // met so once we find one that is not met, we can skip to
671 // the end of this list
672 while (I != Stop)
565ded7b 673 {
ac81c0f9 674 // look for whitespace or ending '>'
675 // End now points to the character after the current term
676 for (;End != Stop && !isspace(*End) && *End != '>'; ++End);
565ded7b 677
ac81c0f9 678 if (unlikely(End == Stop))
679 return 0;
565ded7b 680
ac81c0f9 681 bool NegRestriction = false;
682 if (*I == '!')
683 {
684 NegRestriction = true;
685 ++I;
686 }
687
688 std::string restriction(I, End);
565ded7b
JS
689
690 if (restriction.empty() == false && profiles.empty() == false &&
ac81c0f9 691 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
565ded7b 692 {
ac81c0f9 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 } else {
699 if (!NegRestriction) {
700 applies2 = false;
701 // since one of the terms does not apply we don't have to check the others
702 for (; End != Stop && *End != '>'; ++End);
703 }
704 }
705
706 if (*End++ == '>') {
707 I = End;
708 // skip whitespace
709 for (;I != Stop && isspace(*I) != 0; I++);
710 break;
565ded7b 711 }
565ded7b 712
565ded7b 713 I = End;
ac81c0f9 714 // skip whitespace
715 for (;I != Stop && isspace(*I) != 0; I++);
716 }
717 if (applies2) {
718 applies1 = true;
565ded7b 719 }
565ded7b 720 }
565ded7b
JS
721 }
722
ac81c0f9 723 if (applies1 == false) {
724 Package = ""; //not for this restriction
725 }
565ded7b
JS
726 }
727
dcb79bae 728 if (I != Stop && *I == '|')
6c139d6e 729 Op |= pkgCache::Dep::Or;
dcb79bae
AL
730
731 if (I == Stop || *I == ',' || *I == '|')
732 {
733 if (I != Stop)
734 for (I++; I != Stop && isspace(*I) != 0; I++);
735 return I;
736 }
737
738 return 0;
739}
740 /*}}}*/
741// ListParser::ParseDepends - Parse a dependency list /*{{{*/
742// ---------------------------------------------------------------------
743/* This is the higher level depends parser. It takes a tag and generates
744 a complete depends tree for the given version. */
32b9a14c 745bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
dcb79bae
AL
746 const char *Tag,unsigned int Type)
747{
748 const char *Start;
749 const char *Stop;
750 if (Section.Find(Tag,Start,Stop) == false)
751 return true;
306eacf6 752
28166356 753 string const pkgArch = Ver.Arch();
dcb79bae 754
8efa2a3b 755 while (1)
dcb79bae 756 {
0f485ee5
TG
757 string Package;
758 string Version;
759 unsigned int Op;
760
565ded7b 761 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
dcb79bae
AL
762 if (Start == 0)
763 return _error->Error("Problem parsing dependency %s",Tag);
0f485ee5 764 size_t const found = Package.rfind(':');
306eacf6 765
cef094c2
DK
766 // If negative is unspecific it needs to apply on all architectures
767 if (MultiArchEnabled == true && found == string::npos &&
306eacf6
DK
768 (Type == pkgCache::Dep::Conflicts ||
769 Type == pkgCache::Dep::DpkgBreaks ||
770 Type == pkgCache::Dep::Replaces))
771 {
dcfa253f
DK
772 for (std::vector<std::string>::const_iterator a = Architectures.begin();
773 a != Architectures.end(); ++a)
306eacf6
DK
774 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
775 return false;
c919ad6e
DK
776 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
777 return false;
306eacf6 778 }
0f485ee5
TG
779 else if (MultiArchEnabled == true && found != string::npos &&
780 strcmp(Package.c_str() + found, ":any") != 0)
781 {
782 string Arch = Package.substr(found+1, string::npos);
783 Package = Package.substr(0, found);
784 // Such dependencies are not supposed to be accepted …
785 // … but this is probably the best thing to do.
786 if (Arch == "native")
787 Arch = _config->Find("APT::Architecture");
788 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
789 return false;
790 }
c919ad6e
DK
791 else
792 {
793 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
794 return false;
795 if ((Type == pkgCache::Dep::Conflicts ||
796 Type == pkgCache::Dep::DpkgBreaks ||
797 Type == pkgCache::Dep::Replaces) &&
798 NewDepends(Ver, Package,
799 (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"),
800 Version,Op,Type) == false)
801 return false;
802 }
8efa2a3b
AL
803 if (Start == Stop)
804 break;
dcb79bae
AL
805 }
806 return true;
807}
808 /*}}}*/
809// ListParser::ParseProvides - Parse the provides list /*{{{*/
810// ---------------------------------------------------------------------
811/* */
32b9a14c 812bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae
AL
813{
814 const char *Start;
815 const char *Stop;
67e0766f 816 if (Section.Find("Provides",Start,Stop) == true)
dcb79bae 817 {
67e0766f
DK
818 string Package;
819 string Version;
28166356 820 string const Arch = Ver.Arch();
67e0766f
DK
821 unsigned int Op;
822
823 while (1)
824 {
825 Start = ParseDepends(Start,Stop,Package,Version,Op);
826 if (Start == 0)
827 return _error->Error("Problem parsing Provides line");
40faab46
DK
828 if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) {
829 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str());
04340db3
DK
830 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
831 if (NewProvidesAllArch(Ver, Package, Version) == false)
832 return false;
67e0766f
DK
833 } else {
834 if (NewProvides(Ver, Package, Arch, Version) == false)
835 return false;
836 }
837
838 if (Start == Stop)
839 break;
b63380b0 840 }
67e0766f 841 }
dcb79bae 842
b4140ecf 843 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
4d174dc8
DK
844 {
845 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
60dcec6d 846 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
dcb79bae 847 }
894d672e 848 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
60dcec6d 849 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
dcb79bae 850
60dcec6d
DK
851 return true;
852}
853 /*}}}*/
854// ListParser::NewProvides - add provides for all architectures /*{{{*/
855bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
856 string const &Version) {
dcfa253f
DK
857 for (std::vector<string>::const_iterator a = Architectures.begin();
858 a != Architectures.end(); ++a)
67e0766f
DK
859 {
860 if (NewProvides(Ver, Package, *a, Version) == false)
861 return false;
dcb79bae 862 }
f55a958f
AL
863 return true;
864}
865 /*}}}*/
866// ListParser::GrabWord - Matches a word and returns /*{{{*/
867// ---------------------------------------------------------------------
868/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 869bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 870{
b2e465d6 871 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
872 {
873 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
874 {
875 Out = List[C].Val;
876 return true;
877 }
878 }
879 return false;
880}
881 /*}}}*/
882// ListParser::Step - Move to the next section in the file /*{{{*/
883// ---------------------------------------------------------------------
1e3f4083 884/* This has to be careful to only process the correct architecture */
f55a958f
AL
885bool debListParser::Step()
886{
dcb79bae 887 iOffset = Tags.Offset();
0149949b 888 while (Tags.Step(Section) == true)
ddc1d8d0
AL
889 {
890 /* See if this is the correct Architecture, if it isn't then we
891 drop the whole section. A missing arch tag only happens (in theory)
892 inside the Status file, so that is a positive return */
5dd4c8b8 893 string const Architecture = Section.FindS("Architecture");
9c14e3d6 894
dd13742e 895 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
5dd4c8b8
DK
896 {
897 if (APT::Configuration::checkArchitecture(Architecture) == true)
898 return true;
c919ad6e
DK
899 /* parse version stanzas without an architecture only in the status file
900 (and as misfortune bycatch flat-archives) */
901 if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true)
902 return true;
5dd4c8b8
DK
903 }
904 else
905 {
906 if (Architecture == Arch)
907 return true;
0149949b 908
28166356 909 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
5dd4c8b8
DK
910 return true;
911 }
dcb79bae
AL
912
913 iOffset = Tags.Offset();
0149949b
AL
914 }
915 return false;
f55a958f
AL
916}
917 /*}}}*/
b0b4efb9
AL
918// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
919// ---------------------------------------------------------------------
920/* */
32b9a14c 921bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
f2152f03 922 FileFd &File, string component)
b0b4efb9 923{
f2152f03
MV
924 // apt-secure does no longer download individual (per-section) Release
925 // file. to provide Component pinning we use the section name now
2b803d40
DK
926 map_ptrloc const storage = WriteUniqString(component);
927 FileI->Component = storage;
f2152f03 928
233d79a5 929 pkgTagFile TagFile(&File, File.Size());
e9737c7f
DK
930 pkgTagSection Section;
931 if (_error->PendingError() == true || TagFile.Step(Section) == false)
fe0f7911
DK
932 return false;
933
e9737c7f
DK
934 std::string data;
935 #define APT_INRELEASE(TAG, STORE) \
936 data = Section.FindS(TAG); \
937 if (data.empty() == false) \
938 { \
939 map_ptrloc const storage = WriteUniqString(data); \
940 STORE = storage; \
fe0f7911 941 }
e9737c7f
DK
942 APT_INRELEASE("Suite", FileI->Archive)
943 APT_INRELEASE("Component", FileI->Component)
944 APT_INRELEASE("Version", FileI->Version)
945 APT_INRELEASE("Origin", FileI->Origin)
946 APT_INRELEASE("Codename", FileI->Codename)
947 APT_INRELEASE("Label", FileI->Label)
948 #undef APT_INRELEASE
949 Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic);
950 Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades);
f2152f03 951
b0b4efb9
AL
952 return !_error->PendingError();
953}
954 /*}}}*/
b2e465d6
AL
955// ListParser::GetPrio - Convert the priority from a string /*{{{*/
956// ---------------------------------------------------------------------
957/* */
958unsigned char debListParser::GetPrio(string Str)
959{
960 unsigned char Out;
961 if (GrabWord(Str,PrioList,Out) == false)
962 Out = pkgCache::State::Extra;
963
964 return Out;
965}
966 /*}}}*/
68134bda
DK
967#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
968bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
969 pkgCache::VerIterator const &Ver)
970{
971 if (pkgCacheGenerator::ListParser::SameVersion(Hash, Ver) == false)
972 return false;
973 // status file has no (Download)Size, but all others are fair game
974 // status file is parsed last, so the first version we encounter is
975 // probably also the version we have downloaded
976 unsigned long long const Size = Section.FindULL("Size");
977 if (Size != 0 && Size != Ver->Size)
978 return false;
979 // available everywhere, but easier to check here than to include in VersionHash
980 unsigned char MultiArch = ParseMultiArch(false);
981 if (MultiArch != Ver->MultiArch)
982 return false;
983 // for all practical proposes (we can check): same version
984 return true;
985}
986 /*}}}*/
987#endif