1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
12 // Include Files /*{{{*/
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/crc-16.h>
22 #include <apt-pkg/md5.h>
23 #include <apt-pkg/pkgcache.h>
24 #include <apt-pkg/cacheiterators.h>
25 #include <apt-pkg/tagfile.h>
26 #include <apt-pkg/macros.h>
37 using APT::StringView
;
39 static const debListParser::WordList PrioList
[] = {
40 {"required",pkgCache::State::Required
},
41 {"important",pkgCache::State::Important
},
42 {"standard",pkgCache::State::Standard
},
43 {"optional",pkgCache::State::Optional
},
44 {"extra",pkgCache::State::Extra
},
47 // ListParser::debListParser - Constructor /*{{{*/
48 // ---------------------------------------------------------------------
49 /* Provide an architecture and only this one and "all" will be accepted
50 in Step(), if no Architecture is given we will accept every arch
51 we would accept in general with checkArchitecture() */
52 debListParser::debListParser(FileFd
*File
) :
53 pkgCacheListParser(), d(NULL
), Tags(File
)
57 // ListParser::Package - Return the package name /*{{{*/
58 // ---------------------------------------------------------------------
59 /* This is to return the name of the package this section describes */
60 string
debListParser::Package() {
61 string Result
= Section
.Find("Package").to_string();
63 // Normalize mixed case package names to lower case, like dpkg does
64 // See Bug#807012 for details
65 std::transform(Result
.begin(), Result
.end(), Result
.begin(), tolower_ascii
);
67 if(unlikely(Result
.empty() == true))
68 _error
->Error("Encountered a section with no Package: header");
72 // ListParser::Architecture - Return the package arch /*{{{*/
73 // ---------------------------------------------------------------------
74 /* This will return the Architecture of the package this section describes */
75 string
debListParser::Architecture() {
76 auto const Arch
= Section
.Find("Architecture");
77 return Arch
.empty() ? "none" : Arch
.to_string();
80 // ListParser::ArchitectureAll /*{{{*/
81 // ---------------------------------------------------------------------
83 bool debListParser::ArchitectureAll() {
84 return Section
.Find("Architecture") == "all";
87 // ListParser::Version - Return the version string /*{{{*/
88 // ---------------------------------------------------------------------
89 /* This is to return the string describing the version in debian form,
90 epoch:upstream-release. If this returns the blank string then the
91 entry is assumed to only describe package properties */
92 string
debListParser::Version()
94 return Section
.Find("Version").to_string();
97 unsigned char debListParser::ParseMultiArch(bool const showErrors
) /*{{{*/
100 auto const MultiArch
= Section
.Find("Multi-Arch");
101 if (MultiArch
.empty() == true || MultiArch
== "no")
102 MA
= pkgCache::Version::No
;
103 else if (MultiArch
== "same") {
104 if (ArchitectureAll() == true)
106 if (showErrors
== true)
107 _error
->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
108 Section
.FindS("Package").c_str());
109 MA
= pkgCache::Version::No
;
112 MA
= pkgCache::Version::Same
;
114 else if (MultiArch
== "foreign")
115 MA
= pkgCache::Version::Foreign
;
116 else if (MultiArch
== "allowed")
117 MA
= pkgCache::Version::Allowed
;
120 if (showErrors
== true)
121 _error
->Warning("Unknown Multi-Arch type '%s' for package '%s'",
122 MultiArch
.to_string().c_str(), Section
.FindS("Package").c_str());
123 MA
= pkgCache::Version::No
;
126 if (ArchitectureAll() == true)
127 MA
|= pkgCache::Version::All
;
132 // ListParser::NewVersion - Fill in the version structure /*{{{*/
133 // ---------------------------------------------------------------------
135 bool debListParser::NewVersion(pkgCache::VerIterator
&Ver
)
141 if (Section
.Find("Section",Start
,Stop
) == true)
143 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::SECTION
, Start
, Stop
- Start
);
146 // Parse the source package name
147 pkgCache::GrpIterator
const G
= Ver
.ParentPkg().Group();
148 Ver
->SourcePkgName
= G
->Name
;
149 Ver
->SourceVerStr
= Ver
->VerStr
;
150 if (Section
.Find("Source",Start
,Stop
) == true)
152 const char * const Space
= (const char * const) memchr(Start
, ' ', Stop
- Start
);
153 pkgCache::VerIterator V
;
158 const char * const Open
= (const char * const) memchr(Space
, '(', Stop
- Space
);
159 if (likely(Open
!= NULL
))
161 const char * const Close
= (const char * const) memchr(Open
, ')', Stop
- Open
);
162 if (likely(Close
!= NULL
))
164 std::string
const version(Open
+ 1, (Close
- Open
) - 1);
165 if (version
!= Ver
.VerStr())
167 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, version
);
168 Ver
->SourceVerStr
= idx
;
174 std::string
const pkgname(Start
, Stop
- Start
);
175 if (pkgname
!= G
.Name())
177 for (pkgCache::PkgIterator P
= G
.PackageList(); P
.end() == false; P
= G
.NextPkg(P
))
179 for (V
= P
.VersionList(); V
.end() == false; ++V
)
181 if (pkgname
== V
.SourcePkgName())
183 Ver
->SourcePkgName
= V
->SourcePkgName
;
187 if (V
.end() == false)
192 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::PKGNAME
, pkgname
);
193 Ver
->SourcePkgName
= idx
;
198 Ver
->MultiArch
= ParseMultiArch(true);
200 Ver
->Size
= Section
.FindULL("Size");
201 // Unpacked Size (in K)
202 Ver
->InstalledSize
= Section
.FindULL("Installed-Size");
203 Ver
->InstalledSize
*= 1024;
206 if (Section
.Find("Priority",Start
,Stop
) == true)
208 if (GrabWord(StringView(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
209 Ver
->Priority
= pkgCache::State::Extra
;
212 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
214 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
216 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
218 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
220 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
222 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
224 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
226 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
229 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
232 if (ParseProvides(Ver
) == false)
238 // ListParser::Description - Return the description string /*{{{*/
239 // ---------------------------------------------------------------------
240 /* This is to return the string describing the package in debian
241 form. If this returns the blank string then the entry is assumed to
242 only describe package properties */
243 string
debListParser::Description(std::string
const &lang
)
245 return Description(StringView(lang
)).to_string();
248 StringView
debListParser::Description(StringView lang
)
251 return Section
.Find("Description");
253 return Section
.Find(string("Description-").append(lang
.data(), lang
.size()));
256 // ListParser::AvailableDescriptionLanguages /*{{{*/
257 std::vector
<std::string
> debListParser::AvailableDescriptionLanguages()
259 std::vector
<std::string
> const understood
= APT::Configuration::getLanguages();
260 std::vector
<std::string
> avail
;
261 if (Section
.Exists("Description") == true)
263 for (std::vector
<std::string
>::const_iterator lang
= understood
.begin(); lang
!= understood
.end(); ++lang
)
265 std::string
const tagname
= "Description-" + *lang
;
266 if (Section
.Exists(tagname
.c_str()) == true)
267 avail
.push_back(*lang
);
272 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
273 // ---------------------------------------------------------------------
274 /* This is to return the md5 string to allow the check if it is the right
275 description. If no Description-md5 is found in the section it will be
278 MD5SumValue
debListParser::Description_md5()
280 auto const value
= Section
.Find("Description-md5");
281 if (value
.empty() == true)
283 StringView desc
= Description(StringView("", 0));
285 return MD5SumValue();
288 md5
.Add(desc
.data(), desc
.size());
292 else if (likely(value
.size() == 32))
294 MD5SumValue sumvalue
;
295 if (sumvalue
.Set(value
))
298 _error
->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value
.length(), value
.data());
299 return MD5SumValue();
301 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
302 return MD5SumValue();
305 // ListParser::UsePackage - Update a package structure /*{{{*/
306 // ---------------------------------------------------------------------
307 /* This is called to update the package with any new information
308 that might be found in the section */
309 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
310 pkgCache::VerIterator
&Ver
)
312 string
const static myArch
= _config
->Find("APT::Architecture");
313 // Possible values are: "all", "native", "installed" and "none"
314 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
315 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
316 if (essential
== "all" ||
317 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
318 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
320 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
323 if (strcmp(Pkg
.Name(),"apt") == 0)
325 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
327 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
329 Pkg
->Flags
|= pkgCache::Flag::Important
;
332 if (ParseStatus(Pkg
,Ver
) == false)
337 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
338 // ---------------------------------------------------------------------
340 unsigned short debListParser::VersionHash()
342 static const StringView Sections
[] ={"Installed-Size",
350 unsigned long Result
= INIT_FCS
;
352 for (StringView I
: Sections
)
356 if (Section
.Find(I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
359 /* Strip out any spaces from the text, this undoes dpkgs reformatting
360 of certain fields. dpkg also has the rather interesting notion of
361 reformatting depends operators < -> <= */
363 for (; Start
!= End
; ++Start
)
365 if (isspace_ascii(*Start
) != 0)
367 *J
++ = tolower_ascii(*Start
);
369 if ((*Start
== '<' || *Start
== '>') && Start
[1] != *Start
&& Start
[1] != '=')
373 Result
= AddCRC16(Result
,S
,J
- S
);
379 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
380 // ---------------------------------------------------------------------
381 /* Status lines are of the form,
382 Status: want flag status
383 want = unknown, install, hold, deinstall, purge
385 status = not-installed, config-files, half-installed, unpacked,
386 half-configured, triggers-awaited, triggers-pending, installed
388 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
389 pkgCache::VerIterator
&)
393 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
394 pkgCache::VerIterator
&Ver
)
398 if (Section
.Find("Status",Start
,Stop
) == false)
401 // UsePackage() is responsible for setting the flag in the default case
402 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
403 if (essential
== true &&
404 Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
407 // Isolate the first word
408 const char *I
= Start
;
409 for(; I
< Stop
&& *I
!= ' '; I
++);
410 if (I
>= Stop
|| *I
!= ' ')
411 return _error
->Error("Malformed Status line");
413 // Process the want field
414 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
415 {"install",pkgCache::State::Install
},
416 {"hold",pkgCache::State::Hold
},
417 {"deinstall",pkgCache::State::DeInstall
},
418 {"purge",pkgCache::State::Purge
},
420 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
421 return _error
->Error("Malformed 1st word in the Status line");
423 // Isloate the next word
426 for(; I
< Stop
&& *I
!= ' '; I
++);
427 if (I
>= Stop
|| *I
!= ' ')
428 return _error
->Error("Malformed status line, no 2nd word");
430 // Process the flag field
431 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
432 {"reinstreq",pkgCache::State::ReInstReq
},
433 {"hold",pkgCache::State::HoldInst
},
434 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
436 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
437 return _error
->Error("Malformed 2nd word in the Status line");
439 // Isloate the last word
442 for(; I
< Stop
&& *I
!= ' '; I
++);
444 return _error
->Error("Malformed Status line, no 3rd word");
446 // Process the flag field
447 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
448 {"config-files",pkgCache::State::ConfigFiles
},
449 {"half-installed",pkgCache::State::HalfInstalled
},
450 {"unpacked",pkgCache::State::UnPacked
},
451 {"half-configured",pkgCache::State::HalfConfigured
},
452 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
453 {"triggers-pending",pkgCache::State::TriggersPending
},
454 {"installed",pkgCache::State::Installed
},
456 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
457 return _error
->Error("Malformed 3rd word in the Status line");
459 /* A Status line marks the package as indicating the current
460 version as well. Only if it is actually installed.. Otherwise
461 the interesting dpkg handling of the status file creates bogus
463 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
464 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
466 if (Ver
.end() == true)
467 _error
->Warning("Encountered status field in a non-version description");
469 Pkg
->CurrentVer
= Ver
.Index();
475 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
477 // Determine the operator
485 Op
= pkgCache::Dep::LessEq
;
492 Op
= pkgCache::Dep::Less
;
496 // < is the same as <= and << is really Cs < for some reason
497 Op
= pkgCache::Dep::LessEq
;
505 Op
= pkgCache::Dep::GreaterEq
;
512 Op
= pkgCache::Dep::Greater
;
516 // > is the same as >= and >> is really Cs > for some reason
517 Op
= pkgCache::Dep::GreaterEq
;
521 Op
= pkgCache::Dep::Equals
;
525 // HACK around bad package definitions
527 Op
= pkgCache::Dep::Equals
;
533 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
534 // ---------------------------------------------------------------------
535 /* This parses the dependency elements out of a standard string in place,
537 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
538 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
539 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
540 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
541 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
542 bool const &ParseArchFlags
)
543 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
544 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
545 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
546 bool const &ParseArchFlags
, bool const &StripMultiArch
)
547 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
548 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
549 string
&Package
,string
&Ver
,
550 unsigned int &Op
, bool const &ParseArchFlags
,
551 bool const &StripMultiArch
,
552 bool const &ParseRestrictionsList
)
554 StringView PackageView
;
557 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
558 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
559 Package
= PackageView
.to_string();
560 Ver
= VerView
.to_string();
564 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
565 StringView
&Package
,StringView
&Ver
,
566 unsigned int &Op
, bool ParseArchFlags
,
568 bool ParseRestrictionsList
)
570 // Strip off leading space
571 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
573 // Parse off the package name
574 const char *I
= Start
;
575 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
576 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
577 *I
!= '<' && *I
!= '>'; ++I
);
580 if (I
!= Stop
&& *I
== ')')
586 // Stash the package name
587 Package
= StringView(Start
, I
- Start
);
589 // We don't want to confuse library users which can't handle MultiArch
590 if (StripMultiArch
== true) {
591 string
const arch
= _config
->Find("APT::Architecture");
592 size_t const found
= Package
.rfind(':');
593 if (found
!= StringView::npos
&&
594 (Package
.substr(found
) == ":any" ||
595 Package
.substr(found
) == ":native" ||
596 Package
.substr(found
+1) == arch
))
597 Package
= Package
.substr(0,found
);
600 // Skip white space to the '('
601 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
604 if (I
!= Stop
&& *I
== '(')
607 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
610 I
= ConvertRelation(I
,Op
);
613 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
615 I
= (const char*) memchr(I
, ')', Stop
- I
);
616 if (I
== NULL
|| Start
== I
)
619 // Skip trailing whitespace
621 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
623 Ver
= StringView(Start
,End
-Start
);
629 Op
= pkgCache::Dep::NoOp
;
633 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
635 if (unlikely(ParseArchFlags
== true))
637 string
const arch
= _config
->Find("APT::Architecture");
638 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
640 // Parse an architecture
641 if (I
!= Stop
&& *I
== '[')
645 if (unlikely(I
== Stop
))
650 bool NegArch
= false;
653 // look for whitespace or ending ']'
654 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
656 if (unlikely(End
== Stop
))
665 std::string
arch(I
, End
);
666 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
671 // we found a match, so fast-forward to the end of the wildcards
672 for (; End
!= Stop
&& *End
!= ']'; ++End
);
681 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
688 Package
= ""; /* not for this arch */
692 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
695 if (unlikely(ParseRestrictionsList
== true))
697 // Parse a restrictions formula which is in disjunctive normal form:
698 // (foo AND bar) OR (blub AND bla)
700 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
702 // if the next character is a restriction list, then by default the
703 // dependency does not apply and the conditions have to be checked
704 // if the next character is not a restriction list, then by default the
705 // dependency applies
706 bool applies1
= (*I
!= '<');
714 if (unlikely(I
== Stop
))
719 // if of the prior restriction list is already fulfilled, then
720 // we can just skip to the end of the current list
722 for (;End
!= Stop
&& *End
!= '>'; ++End
);
725 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
727 bool applies2
= true;
728 // all the conditions inside a restriction list have to be
729 // met so once we find one that is not met, we can skip to
730 // the end of this list
733 // look for whitespace or ending '>'
734 // End now points to the character after the current term
735 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
737 if (unlikely(End
== Stop
))
740 bool NegRestriction
= false;
743 NegRestriction
= true;
747 std::string
restriction(I
, End
);
749 if (restriction
.empty() == false && profiles
.empty() == false &&
750 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
752 if (NegRestriction
) {
754 // since one of the terms does not apply we don't have to check the others
755 for (; End
!= Stop
&& *End
!= '>'; ++End
);
758 if (!NegRestriction
) {
760 // since one of the terms does not apply we don't have to check the others
761 for (; End
!= Stop
&& *End
!= '>'; ++End
);
768 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
774 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
782 if (applies1
== false) {
783 Package
= ""; //not for this restriction
787 if (I
!= Stop
&& *I
== '|')
788 Op
|= pkgCache::Dep::Or
;
790 if (I
== Stop
|| *I
== ',' || *I
== '|')
793 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
800 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
801 // ---------------------------------------------------------------------
802 /* This is the higher level depends parser. It takes a tag and generates
803 a complete depends tree for the given version. */
804 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
805 const char *Tag
,unsigned int Type
)
809 if (Section
.Find(Tag
,Start
,Stop
) == false)
812 string
const pkgArch
= Ver
.Arch();
820 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
822 return _error
->Error("Problem parsing dependency %s",Tag
);
823 size_t const found
= Package
.rfind(':');
825 if (found
== string::npos
)
827 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
830 else if (Package
.substr(found
) == ":any")
832 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
837 // Such dependencies are not supposed to be accepted …
838 // … but this is probably the best thing to do anyway
840 if (Package
.substr(found
+ 1) == "native")
841 Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
843 Pkg
= Package
.to_string();
844 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
854 // ListParser::ParseProvides - Parse the provides list /*{{{*/
855 // ---------------------------------------------------------------------
857 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
859 /* it is unlikely, but while parsing dependencies, we might have already
860 picked up multi-arch implicit provides which we do not want to duplicate here */
861 bool hasProvidesAlready
= false;
862 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
864 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
866 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
868 if (spzName
!= Prv
.OwnerPkg().FullName(false))
870 hasProvidesAlready
= true;
875 string
const Arch
= Ver
.Arch();
878 if (Section
.Find("Provides",Start
,Stop
) == true)
886 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
887 const size_t archfound
= Package
.rfind(':');
889 return _error
->Error("Problem parsing Provides line");
890 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
891 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
892 } else if (archfound
!= string::npos
) {
893 StringView spzArch
= Package
.substr(archfound
+ 1);
894 if (spzArch
!= "any")
896 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
899 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
901 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
902 if (APT::Configuration::checkArchitecture(Arch
))
903 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
906 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
908 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
911 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
914 if (archfound
== std::string::npos
)
916 string spzName
= Package
.to_string();
917 spzName
.push_back(':');
918 spzName
.append(Ver
.ParentPkg().Arch());
919 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
920 if (spzPkg
.end() == false)
922 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
926 } while (Start
!= Stop
);
929 if (APT::Configuration::checkArchitecture(Arch
))
931 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
933 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
934 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
937 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
939 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
944 if (hasProvidesAlready
== false)
946 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
947 if (spzPkg
.end() == false)
949 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
956 // ListParser::GrabWord - Matches a word and returns /*{{{*/
957 // ---------------------------------------------------------------------
958 /* Looks for a word in a list of words - for ParseStatus */
959 bool debListParser::GrabWord(StringView Word
,const WordList
*List
,unsigned char &Out
)
961 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
963 if (Word
.length() == strlen(List
[C
].Str
) &&
964 strncasecmp(Word
.data(),List
[C
].Str
,Word
.length()) == 0)
973 // ListParser::Step - Move to the next section in the file /*{{{*/
974 // ---------------------------------------------------------------------
975 /* This has to be careful to only process the correct architecture */
976 bool debListParser::Step()
978 iOffset
= Tags
.Offset();
979 return Tags
.Step(Section
);
982 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
983 // ---------------------------------------------------------------------
985 unsigned char debListParser::GetPrio(string Str
)
988 if (GrabWord(Str
,PrioList
,Out
) == false)
989 Out
= pkgCache::State::Extra
;
994 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
995 pkgCache::VerIterator
const &Ver
)
997 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
999 // status file has no (Download)Size, but all others are fair game
1000 // status file is parsed last, so the first version we encounter is
1001 // probably also the version we have downloaded
1002 unsigned long long const Size
= Section
.FindULL("Size");
1003 if (Size
!= 0 && Size
!= Ver
->Size
)
1005 // available everywhere, but easier to check here than to include in VersionHash
1006 unsigned char MultiArch
= ParseMultiArch(false);
1007 if (MultiArch
!= Ver
->MultiArch
)
1009 // for all practical proposes (we can check): same version
1014 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1015 : debListParser(File
), DebFile(DebFile
)
1019 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1020 pkgCache::VerIterator
&Ver
)
1022 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1023 // we use the full file path as a provides so that the file is found
1025 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1030 debListParser::~debListParser() {}