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