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