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