]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/deb/deblistparser.cc
doc/files.dbk: Improve documentation for {src,}pkgcache.bin
[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) :
54 pkgCacheListParser(), d(NULL), Tags(File)
55{
56}
57 /*}}}*/
58// ListParser::Package - Return the package name /*{{{*/
59// ---------------------------------------------------------------------
60/* This is to return the name of the package this section describes */
61string debListParser::Package() {
62 string const Result = Section.FindS("Package");
63 if(unlikely(Result.empty() == true))
64 _error->Error("Encountered a section with no Package: header");
65 return Result;
66}
67 /*}}}*/
68// ListParser::Architecture - Return the package arch /*{{{*/
69// ---------------------------------------------------------------------
70/* This will return the Architecture of the package this section describes */
71string debListParser::Architecture() {
72 std::string const Arch = Section.FindS("Architecture");
73 return Arch.empty() ? "none" : Arch;
74}
75 /*}}}*/
76// ListParser::ArchitectureAll /*{{{*/
77// ---------------------------------------------------------------------
78/* */
79bool debListParser::ArchitectureAll() {
80 return Section.FindS("Architecture") == "all";
81}
82 /*}}}*/
83// ListParser::Version - Return the version string /*{{{*/
84// ---------------------------------------------------------------------
85/* This is to return the string describing the version in debian form,
86 epoch:upstream-release. If this returns the blank string then the
87 entry is assumed to only describe package properties */
88string debListParser::Version()
89{
90 return Section.FindS("Version");
91}
92 /*}}}*/
93unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/
94{
95 unsigned char MA;
96 string const MultiArch = Section.FindS("Multi-Arch");
97 if (MultiArch.empty() == true || MultiArch == "no")
98 MA = pkgCache::Version::No;
99 else if (MultiArch == "same") {
100 if (ArchitectureAll() == true)
101 {
102 if (showErrors == true)
103 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
104 Section.FindS("Package").c_str());
105 MA = pkgCache::Version::No;
106 }
107 else
108 MA = pkgCache::Version::Same;
109 }
110 else if (MultiArch == "foreign")
111 MA = pkgCache::Version::Foreign;
112 else if (MultiArch == "allowed")
113 MA = pkgCache::Version::Allowed;
114 else
115 {
116 if (showErrors == true)
117 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
118 MultiArch.c_str(), Section.FindS("Package").c_str());
119 MA = pkgCache::Version::No;
120 }
121
122 if (ArchitectureAll() == true)
123 MA |= pkgCache::Version::All;
124
125 return MA;
126}
127 /*}}}*/
128// ListParser::NewVersion - Fill in the version structure /*{{{*/
129// ---------------------------------------------------------------------
130/* */
131bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
132{
133 const char *Start;
134 const char *Stop;
135
136 // Parse the section
137 if (Section.Find("Section",Start,Stop) == true)
138 {
139 map_stringitem_t const idx = StoreString(pkgCacheGenerator::SECTION, Start, Stop - Start);
140 Ver->Section = idx;
141 }
142 // Parse the source package name
143 pkgCache::GrpIterator const G = Ver.ParentPkg().Group();
144 Ver->SourcePkgName = G->Name;
145 Ver->SourceVerStr = Ver->VerStr;
146 if (Section.Find("Source",Start,Stop) == true)
147 {
148 const char * const Space = (const char * const) memchr(Start, ' ', Stop - Start);
149 pkgCache::VerIterator V;
150
151 if (Space != NULL)
152 {
153 Stop = Space;
154 const char * const Open = (const char * const) memchr(Space, '(', Stop - Space);
155 if (likely(Open != NULL))
156 {
157 const char * const Close = (const char * const) memchr(Open, ')', Stop - Open);
158 if (likely(Close != NULL))
159 {
160 std::string const version(Open + 1, (Close - Open) - 1);
161 if (version != Ver.VerStr())
162 {
163 map_stringitem_t const idx = StoreString(pkgCacheGenerator::VERSIONNUMBER, version);
164 Ver->SourceVerStr = idx;
165 }
166 }
167 }
168 }
169
170 std::string const pkgname(Start, Stop - Start);
171 if (pkgname != G.Name())
172 {
173 for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
174 {
175 for (V = P.VersionList(); V.end() == false; ++V)
176 {
177 if (pkgname == V.SourcePkgName())
178 {
179 Ver->SourcePkgName = V->SourcePkgName;
180 break;
181 }
182 }
183 if (V.end() == false)
184 break;
185 }
186 if (V.end() == true)
187 {
188 map_stringitem_t const idx = StoreString(pkgCacheGenerator::PKGNAME, pkgname);
189 Ver->SourcePkgName = idx;
190 }
191 }
192 }
193
194 Ver->MultiArch = ParseMultiArch(true);
195 // Archive Size
196 Ver->Size = Section.FindULL("Size");
197 // Unpacked Size (in K)
198 Ver->InstalledSize = Section.FindULL("Installed-Size");
199 Ver->InstalledSize *= 1024;
200
201 // Priority
202 if (Section.Find("Priority",Start,Stop) == true)
203 {
204 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
205 Ver->Priority = pkgCache::State::Extra;
206 }
207
208 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
209 return false;
210 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
211 return false;
212 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
213 return false;
214 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
215 return false;
216 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
217 return false;
218 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
219 return false;
220 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
221 return false;
222 if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
223 return false;
224 // Obsolete.
225 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
226 return false;
227
228 if (ParseProvides(Ver) == false)
229 return false;
230
231 return true;
232}
233 /*}}}*/
234// ListParser::Description - Return the description string /*{{{*/
235// ---------------------------------------------------------------------
236/* This is to return the string describing the package in debian
237 form. If this returns the blank string then the entry is assumed to
238 only describe package properties */
239string debListParser::Description(std::string const &lang)
240{
241 if (lang.empty())
242 return Section.FindS("Description");
243 else
244 return Section.FindS(string("Description-").append(lang).c_str());
245}
246 /*}}}*/
247// ListParser::AvailableDescriptionLanguages /*{{{*/
248std::vector<std::string> debListParser::AvailableDescriptionLanguages()
249{
250 std::vector<std::string> const understood = APT::Configuration::getLanguages();
251 std::vector<std::string> avail;
252 if (Section.Exists("Description") == true)
253 avail.push_back("");
254 for (std::vector<std::string>::const_iterator lang = understood.begin(); lang != understood.end(); ++lang)
255 {
256 std::string const tagname = "Description-" + *lang;
257 if (Section.Exists(tagname.c_str()) == true)
258 avail.push_back(*lang);
259 }
260 return avail;
261}
262 /*}}}*/
263// ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
264// ---------------------------------------------------------------------
265/* This is to return the md5 string to allow the check if it is the right
266 description. If no Description-md5 is found in the section it will be
267 calculated.
268 */
269MD5SumValue debListParser::Description_md5()
270{
271 string const value = Section.FindS("Description-md5");
272 if (value.empty() == true)
273 {
274 std::string const desc = Description("") + "\n";
275 if (desc == "\n")
276 return MD5SumValue();
277
278 MD5Summation md5;
279 md5.Add(desc.c_str());
280 return md5.Result();
281 }
282 else if (likely(value.size() == 32))
283 {
284 if (likely(value.find_first_not_of("0123456789abcdefABCDEF") == string::npos))
285 return MD5SumValue(value);
286 _error->Error("Malformed Description-md5 line; includes invalid character '%s'", value.c_str());
287 return MD5SumValue();
288 }
289 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%s'", (int)value.size(), value.c_str());
290 return MD5SumValue();
291}
292 /*}}}*/
293// ListParser::UsePackage - Update a package structure /*{{{*/
294// ---------------------------------------------------------------------
295/* This is called to update the package with any new information
296 that might be found in the section */
297bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
298 pkgCache::VerIterator &Ver)
299{
300 string const static myArch = _config->Find("APT::Architecture");
301 // Possible values are: "all", "native", "installed" and "none"
302 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
303 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
304 if (essential == "all" ||
305 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
306 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
307 return false;
308 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
309 return false;
310
311 if (strcmp(Pkg.Name(),"apt") == 0)
312 {
313 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
314 essential == "all")
315 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
316 else
317 Pkg->Flags |= pkgCache::Flag::Important;
318 }
319
320 if (ParseStatus(Pkg,Ver) == false)
321 return false;
322 return true;
323}
324 /*}}}*/
325// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
326// ---------------------------------------------------------------------
327/* */
328unsigned short debListParser::VersionHash()
329{
330 const char *Sections[] ={"Installed-Size",
331 "Depends",
332 "Pre-Depends",
333// "Suggests",
334// "Recommends",
335 "Conflicts",
336 "Breaks",
337 "Replaces",0};
338 unsigned long Result = INIT_FCS;
339 char S[1024];
340 for (const char * const *I = Sections; *I != 0; ++I)
341 {
342 const char *Start;
343 const char *End;
344 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
345 continue;
346
347 /* Strip out any spaces from the text, this undoes dpkgs reformatting
348 of certain fields. dpkg also has the rather interesting notion of
349 reformatting depends operators < -> <= */
350 char *J = S;
351 for (; Start != End; ++Start)
352 {
353 if (isspace(*Start) != 0)
354 continue;
355 *J++ = tolower_ascii(*Start);
356
357 if ((*Start == '<' || *Start == '>') && Start[1] != *Start && Start[1] != '=')
358 *J++ = '=';
359 }
360
361 Result = AddCRC16(Result,S,J - S);
362 }
363
364 return Result;
365}
366 /*}}}*/
367// ListParser::ParseStatus - Parse the status field /*{{{*/
368// ---------------------------------------------------------------------
369/* Status lines are of the form,
370 Status: want flag status
371 want = unknown, install, hold, deinstall, purge
372 flag = ok, reinstreq
373 status = not-installed, config-files, half-installed, unpacked,
374 half-configured, triggers-awaited, triggers-pending, installed
375 */
376bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
377 pkgCache::VerIterator &Ver)
378{
379 const char *Start;
380 const char *Stop;
381 if (Section.Find("Status",Start,Stop) == false)
382 return true;
383
384 // UsePackage() is responsible for setting the flag in the default case
385 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
386 if (essential == true &&
387 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
388 return false;
389
390 // Isolate the first word
391 const char *I = Start;
392 for(; I < Stop && *I != ' '; I++);
393 if (I >= Stop || *I != ' ')
394 return _error->Error("Malformed Status line");
395
396 // Process the want field
397 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
398 {"install",pkgCache::State::Install},
399 {"hold",pkgCache::State::Hold},
400 {"deinstall",pkgCache::State::DeInstall},
401 {"purge",pkgCache::State::Purge},
402 {NULL, 0}};
403 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
404 return _error->Error("Malformed 1st word in the Status line");
405
406 // Isloate the next word
407 I++;
408 Start = I;
409 for(; I < Stop && *I != ' '; I++);
410 if (I >= Stop || *I != ' ')
411 return _error->Error("Malformed status line, no 2nd word");
412
413 // Process the flag field
414 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
415 {"reinstreq",pkgCache::State::ReInstReq},
416 {"hold",pkgCache::State::HoldInst},
417 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
418 {NULL, 0}};
419 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
420 return _error->Error("Malformed 2nd word in the Status line");
421
422 // Isloate the last word
423 I++;
424 Start = I;
425 for(; I < Stop && *I != ' '; I++);
426 if (I != Stop)
427 return _error->Error("Malformed Status line, no 3rd word");
428
429 // Process the flag field
430 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
431 {"config-files",pkgCache::State::ConfigFiles},
432 {"half-installed",pkgCache::State::HalfInstalled},
433 {"unpacked",pkgCache::State::UnPacked},
434 {"half-configured",pkgCache::State::HalfConfigured},
435 {"triggers-awaited",pkgCache::State::TriggersAwaited},
436 {"triggers-pending",pkgCache::State::TriggersPending},
437 {"installed",pkgCache::State::Installed},
438 {NULL, 0}};
439 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
440 return _error->Error("Malformed 3rd word in the Status line");
441
442 /* A Status line marks the package as indicating the current
443 version as well. Only if it is actually installed.. Otherwise
444 the interesting dpkg handling of the status file creates bogus
445 entries. */
446 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
447 Pkg->CurrentState == pkgCache::State::ConfigFiles))
448 {
449 if (Ver.end() == true)
450 _error->Warning("Encountered status field in a non-version description");
451 else
452 Pkg->CurrentVer = Ver.Index();
453 }
454
455 return true;
456}
457
458const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
459{
460 // Determine the operator
461 switch (*I)
462 {
463 case '<':
464 I++;
465 if (*I == '=')
466 {
467 I++;
468 Op = pkgCache::Dep::LessEq;
469 break;
470 }
471
472 if (*I == '<')
473 {
474 I++;
475 Op = pkgCache::Dep::Less;
476 break;
477 }
478
479 // < is the same as <= and << is really Cs < for some reason
480 Op = pkgCache::Dep::LessEq;
481 break;
482
483 case '>':
484 I++;
485 if (*I == '=')
486 {
487 I++;
488 Op = pkgCache::Dep::GreaterEq;
489 break;
490 }
491
492 if (*I == '>')
493 {
494 I++;
495 Op = pkgCache::Dep::Greater;
496 break;
497 }
498
499 // > is the same as >= and >> is really Cs > for some reason
500 Op = pkgCache::Dep::GreaterEq;
501 break;
502
503 case '=':
504 Op = pkgCache::Dep::Equals;
505 I++;
506 break;
507
508 // HACK around bad package definitions
509 default:
510 Op = pkgCache::Dep::Equals;
511 break;
512 }
513 return I;
514}
515 /*}}}*/
516// ListParser::ParseDepends - Parse a dependency element /*{{{*/
517// ---------------------------------------------------------------------
518/* This parses the dependency elements out of a standard string in place,
519 bit by bit. */
520const char *debListParser::ParseDepends(const char *Start,const char *Stop,
521 std::string &Package,std::string &Ver,unsigned int &Op)
522 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
523const char *debListParser::ParseDepends(const char *Start,const char *Stop,
524 std::string &Package,std::string &Ver,unsigned int &Op,
525 bool const &ParseArchFlags)
526 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
527const char *debListParser::ParseDepends(const char *Start,const char *Stop,
528 std::string &Package,std::string &Ver,unsigned int &Op,
529 bool const &ParseArchFlags, bool const &StripMultiArch)
530 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
531const char *debListParser::ParseDepends(const char *Start,const char *Stop,
532 string &Package,string &Ver,
533 unsigned int &Op, bool const &ParseArchFlags,
534 bool const &StripMultiArch,
535 bool const &ParseRestrictionsList)
536{
537 // Strip off leading space
538 for (;Start != Stop && isspace(*Start) != 0; ++Start);
539
540 // Parse off the package name
541 const char *I = Start;
542 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
543 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
544 *I != '<' && *I != '>'; ++I);
545
546 // Malformed, no '('
547 if (I != Stop && *I == ')')
548 return 0;
549
550 if (I == Start)
551 return 0;
552
553 // Stash the package name
554 Package.assign(Start,I - Start);
555
556 // We don't want to confuse library users which can't handle MultiArch
557 string const arch = _config->Find("APT::Architecture");
558 if (StripMultiArch == true) {
559 size_t const found = Package.rfind(':');
560 if (found != string::npos &&
561 (strcmp(Package.c_str() + found, ":any") == 0 ||
562 strcmp(Package.c_str() + found, ":native") == 0 ||
563 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
564 Package = Package.substr(0,found);
565 }
566
567 // Skip white space to the '('
568 for (;I != Stop && isspace(*I) != 0 ; I++);
569
570 // Parse a version
571 if (I != Stop && *I == '(')
572 {
573 // Skip the '('
574 for (I++; I != Stop && isspace(*I) != 0 ; I++);
575 if (I + 3 >= Stop)
576 return 0;
577 I = ConvertRelation(I,Op);
578
579 // Skip whitespace
580 for (;I != Stop && isspace(*I) != 0; I++);
581 Start = I;
582 I = (const char*) memchr(I, ')', Stop - I);
583 if (I == NULL || Start == I)
584 return 0;
585
586 // Skip trailing whitespace
587 const char *End = I;
588 for (; End > Start && isspace(End[-1]); End--);
589
590 Ver.assign(Start,End-Start);
591 I++;
592 }
593 else
594 {
595 Ver.clear();
596 Op = pkgCache::Dep::NoOp;
597 }
598
599 // Skip whitespace
600 for (;I != Stop && isspace(*I) != 0; I++);
601
602 if (ParseArchFlags == true)
603 {
604 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
605
606 // Parse an architecture
607 if (I != Stop && *I == '[')
608 {
609 ++I;
610 // malformed
611 if (unlikely(I == Stop))
612 return 0;
613
614 const char *End = I;
615 bool Found = false;
616 bool NegArch = false;
617 while (I != Stop)
618 {
619 // look for whitespace or ending ']'
620 for (;End != Stop && !isspace(*End) && *End != ']'; ++End);
621
622 if (unlikely(End == Stop))
623 return 0;
624
625 if (*I == '!')
626 {
627 NegArch = true;
628 ++I;
629 }
630
631 std::string arch(I, End);
632 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
633 {
634 Found = true;
635 if (I[-1] != '!')
636 NegArch = false;
637 // we found a match, so fast-forward to the end of the wildcards
638 for (; End != Stop && *End != ']'; ++End);
639 }
640
641 if (*End++ == ']') {
642 I = End;
643 break;
644 }
645
646 I = End;
647 for (;I != Stop && isspace(*I) != 0; I++);
648 }
649
650 if (NegArch == true)
651 Found = !Found;
652
653 if (Found == false)
654 Package = ""; /* not for this arch */
655 }
656
657 // Skip whitespace
658 for (;I != Stop && isspace(*I) != 0; I++);
659 }
660
661 if (ParseRestrictionsList == true)
662 {
663 // Parse a restrictions formula which is in disjunctive normal form:
664 // (foo AND bar) OR (blub AND bla)
665
666 std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
667
668 // if the next character is a restriction list, then by default the
669 // dependency does not apply and the conditions have to be checked
670 // if the next character is not a restriction list, then by default the
671 // dependency applies
672 bool applies1 = (*I != '<');
673 while (I != Stop)
674 {
675 if (*I != '<')
676 break;
677
678 ++I;
679 // malformed
680 if (unlikely(I == Stop))
681 return 0;
682
683 const char *End = I;
684
685 // if of the prior restriction list is already fulfilled, then
686 // we can just skip to the end of the current list
687 if (applies1) {
688 for (;End != Stop && *End != '>'; ++End);
689 I = ++End;
690 // skip whitespace
691 for (;I != Stop && isspace(*I) != 0; I++);
692 } else {
693 bool applies2 = true;
694 // all the conditions inside a restriction list have to be
695 // met so once we find one that is not met, we can skip to
696 // the end of this list
697 while (I != Stop)
698 {
699 // look for whitespace or ending '>'
700 // End now points to the character after the current term
701 for (;End != Stop && !isspace(*End) && *End != '>'; ++End);
702
703 if (unlikely(End == Stop))
704 return 0;
705
706 bool NegRestriction = false;
707 if (*I == '!')
708 {
709 NegRestriction = true;
710 ++I;
711 }
712
713 std::string restriction(I, End);
714
715 if (restriction.empty() == false && profiles.empty() == false &&
716 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
717 {
718 if (NegRestriction) {
719 applies2 = false;
720 // since one of the terms does not apply we don't have to check the others
721 for (; End != Stop && *End != '>'; ++End);
722 }
723 } else {
724 if (!NegRestriction) {
725 applies2 = false;
726 // since one of the terms does not apply we don't have to check the others
727 for (; End != Stop && *End != '>'; ++End);
728 }
729 }
730
731 if (*End++ == '>') {
732 I = End;
733 // skip whitespace
734 for (;I != Stop && isspace(*I) != 0; I++);
735 break;
736 }
737
738 I = End;
739 // skip whitespace
740 for (;I != Stop && isspace(*I) != 0; I++);
741 }
742 if (applies2) {
743 applies1 = true;
744 }
745 }
746 }
747
748 if (applies1 == false) {
749 Package = ""; //not for this restriction
750 }
751 }
752
753 if (I != Stop && *I == '|')
754 Op |= pkgCache::Dep::Or;
755
756 if (I == Stop || *I == ',' || *I == '|')
757 {
758 if (I != Stop)
759 for (I++; I != Stop && isspace(*I) != 0; I++);
760 return I;
761 }
762
763 return 0;
764}
765 /*}}}*/
766// ListParser::ParseDepends - Parse a dependency list /*{{{*/
767// ---------------------------------------------------------------------
768/* This is the higher level depends parser. It takes a tag and generates
769 a complete depends tree for the given version. */
770bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
771 const char *Tag,unsigned int Type)
772{
773 const char *Start;
774 const char *Stop;
775 if (Section.Find(Tag,Start,Stop) == false)
776 return true;
777
778 string const pkgArch = Ver.Arch();
779
780 while (1)
781 {
782 string Package;
783 string Version;
784 unsigned int Op;
785
786 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
787 if (Start == 0)
788 return _error->Error("Problem parsing dependency %s",Tag);
789 size_t const found = Package.rfind(':');
790
791 if (found == string::npos || strcmp(Package.c_str() + found, ":any") == 0)
792 {
793 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
794 return false;
795 }
796 else
797 {
798 string Arch = Package.substr(found+1, string::npos);
799 Package = Package.substr(0, found);
800 // Such dependencies are not supposed to be accepted …
801 // … but this is probably the best thing to do anyway
802 if (Arch == "native")
803 Arch = _config->Find("APT::Architecture");
804 if (NewDepends(Ver,Package,Arch,Version,Op | pkgCache::Dep::ArchSpecific,Type) == false)
805 return false;
806 }
807
808 if (Start == Stop)
809 break;
810 }
811 return true;
812}
813 /*}}}*/
814// ListParser::ParseProvides - Parse the provides list /*{{{*/
815// ---------------------------------------------------------------------
816/* */
817bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
818{
819 const char *Start;
820 const char *Stop;
821 if (Section.Find("Provides",Start,Stop) == true)
822 {
823 string Package;
824 string Version;
825 string const Arch = Ver.Arch();
826 unsigned int Op;
827
828 while (1)
829 {
830 Start = ParseDepends(Start,Stop,Package,Version,Op);
831 const size_t archfound = Package.rfind(':');
832 if (Start == 0)
833 return _error->Error("Problem parsing Provides line");
834 if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) {
835 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str());
836 } else if (archfound != string::npos) {
837 string OtherArch = Package.substr(archfound+1, string::npos);
838 Package = Package.substr(0, archfound);
839 if (NewProvides(Ver, Package, OtherArch, Version, pkgCache::Flag::ArchSpecific) == false)
840 return false;
841 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
842 if (NewProvidesAllArch(Ver, Package, Version, 0) == false)
843 return false;
844 } else {
845 if (NewProvides(Ver, Package, Arch, Version, 0) == false)
846 return false;
847 }
848
849 if (Start == Stop)
850 break;
851 }
852 }
853
854 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
855 {
856 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
857 return NewProvidesAllArch(Ver, Package, Ver.VerStr(), pkgCache::Flag::MultiArchImplicit);
858 }
859 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
860 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit);
861
862 return true;
863}
864 /*}}}*/
865// ListParser::GrabWord - Matches a word and returns /*{{{*/
866// ---------------------------------------------------------------------
867/* Looks for a word in a list of words - for ParseStatus */
868bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
869{
870 for (unsigned int C = 0; List[C].Str != 0; C++)
871 {
872 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
873 {
874 Out = List[C].Val;
875 return true;
876 }
877 }
878 return false;
879}
880 /*}}}*/
881// ListParser::Step - Move to the next section in the file /*{{{*/
882// ---------------------------------------------------------------------
883/* This has to be careful to only process the correct architecture */
884bool debListParser::Step()
885{
886 iOffset = Tags.Offset();
887 return Tags.Step(Section);
888}
889 /*}}}*/
890// ListParser::GetPrio - Convert the priority from a string /*{{{*/
891// ---------------------------------------------------------------------
892/* */
893unsigned char debListParser::GetPrio(string Str)
894{
895 unsigned char Out;
896 if (GrabWord(Str,PrioList,Out) == false)
897 Out = pkgCache::State::Extra;
898
899 return Out;
900}
901 /*}}}*/
902bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
903 pkgCache::VerIterator const &Ver)
904{
905 if (pkgCacheListParser::SameVersion(Hash, Ver) == false)
906 return false;
907 // status file has no (Download)Size, but all others are fair game
908 // status file is parsed last, so the first version we encounter is
909 // probably also the version we have downloaded
910 unsigned long long const Size = Section.FindULL("Size");
911 if (Size != 0 && Size != Ver->Size)
912 return false;
913 // available everywhere, but easier to check here than to include in VersionHash
914 unsigned char MultiArch = ParseMultiArch(false);
915 if (MultiArch != Ver->MultiArch)
916 return false;
917 // for all practical proposes (we can check): same version
918 return true;
919}
920 /*}}}*/
921
922debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile)
923 : debListParser(File), DebFile(DebFile)
924{
925}
926
927bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
928 pkgCache::VerIterator &Ver)
929{
930 bool res = debListParser::UsePackage(Pkg, Ver);
931 // we use the full file path as a provides so that the file is found
932 // by its name
933 if(NewProvides(Ver, DebFile, Pkg.Cache()->NativeArch(), Ver.VerStr(), 0) == false)
934 return false;
935 return res;
936}
937
938debListParser::~debListParser() {}