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 APT::StringView
debListParser::Architecture() {
76 auto const Arch
= Section
.Find("Architecture");
77 return Arch
.empty() ? "none" : Arch
;
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 APT::StringView
debListParser::Version()
94 return Section
.Find("Version");
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 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
;
157 const char * const Open
= (const char * const) memchr(Space
, '(', Stop
- Space
);
158 if (likely(Open
!= NULL
))
160 const char * const Close
= (const char * const) memchr(Open
, ')', Stop
- Open
);
161 if (likely(Close
!= NULL
))
163 APT::StringView
const version(Open
+ 1, (Close
- Open
) - 1);
164 if (version
!= Ver
.VerStr())
166 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, version
);
167 G
= Ver
.ParentPkg().Group();
168 Ver
->SourceVerStr
= idx
;
175 APT::StringView
const pkgname(Start
, Stop
- Start
);
176 if (pkgname
!= G
.Name())
178 for (pkgCache::PkgIterator P
= G
.PackageList(); P
.end() == false; P
= G
.NextPkg(P
))
180 for (V
= P
.VersionList(); V
.end() == false; ++V
)
182 if (pkgname
== V
.SourcePkgName())
184 Ver
->SourcePkgName
= V
->SourcePkgName
;
188 if (V
.end() == false)
193 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::PKGNAME
, pkgname
);
194 G
= Ver
.ParentPkg().Group();
195 Ver
->SourcePkgName
= idx
;
200 Ver
->MultiArch
= ParseMultiArch(true);
202 Ver
->Size
= Section
.FindULL("Size");
203 // Unpacked Size (in K)
204 Ver
->InstalledSize
= Section
.FindULL("Installed-Size");
205 Ver
->InstalledSize
*= 1024;
208 if (Section
.Find("Priority",Start
,Stop
) == true)
210 if (GrabWord(StringView(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
211 Ver
->Priority
= pkgCache::State::Extra
;
214 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
216 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
218 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
220 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
222 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
224 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
226 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
228 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
231 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
234 if (ParseProvides(Ver
) == false)
240 // ListParser::AvailableDescriptionLanguages /*{{{*/
241 std::vector
<std::string
> debListParser::AvailableDescriptionLanguages()
243 std::vector
<std::string
> const understood
= APT::Configuration::getLanguages();
244 std::vector
<std::string
> avail
;
245 static constexpr int prefixLen
= 12;
246 static constexpr int avgLanguageLen
= 5;
249 tagname
.reserve(prefixLen
+ avgLanguageLen
);
250 tagname
.assign("Description-");
251 if (Section
.Exists("Description") == true)
253 for (std::vector
<std::string
>::const_iterator lang
= understood
.begin(); lang
!= understood
.end(); ++lang
)
255 tagname
.resize(prefixLen
);
256 tagname
.append(*lang
);
257 if (Section
.Exists(tagname
) == true)
258 avail
.push_back(*lang
);
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
269 MD5SumValue
debListParser::Description_md5()
271 StringView
const value
= Section
.Find("Description-md5");
272 if (value
.empty() == true)
274 StringView
const desc
= Section
.Find("Description");
276 return MD5SumValue();
279 md5
.Add(desc
.data(), desc
.size());
283 else if (likely(value
.size() == 32))
285 MD5SumValue sumvalue
;
286 if (sumvalue
.Set(value
))
289 _error
->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value
.length(), value
.data());
290 return MD5SumValue();
292 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
293 return MD5SumValue();
296 // ListParser::UsePackage - Update a package structure /*{{{*/
297 // ---------------------------------------------------------------------
298 /* This is called to update the package with any new information
299 that might be found in the section */
300 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
301 pkgCache::VerIterator
&Ver
)
303 string
const static myArch
= _config
->Find("APT::Architecture");
304 // Possible values are: "all", "native", "installed" and "none"
305 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
306 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
307 if (essential
== "all" ||
308 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
309 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
311 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
314 if (strcmp(Pkg
.Name(),"apt") == 0)
316 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
318 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
320 Pkg
->Flags
|= pkgCache::Flag::Important
;
323 if (ParseStatus(Pkg
,Ver
) == false)
328 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
329 // ---------------------------------------------------------------------
331 unsigned short debListParser::VersionHash()
333 static const StringView Sections
[] ={"Installed-Size",
341 unsigned long Result
= INIT_FCS
;
343 for (StringView I
: Sections
)
347 if (Section
.Find(I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
350 /* Strip out any spaces from the text, this undoes dpkgs reformatting
351 of certain fields. dpkg also has the rather interesting notion of
352 reformatting depends operators < -> <= */
354 for (; Start
!= End
; ++Start
)
356 if (isspace_ascii(*Start
) != 0)
358 *J
++ = tolower_ascii(*Start
);
360 if ((*Start
== '<' || *Start
== '>') && Start
[1] != *Start
&& Start
[1] != '=')
364 Result
= AddCRC16(Result
,S
,J
- S
);
370 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
371 // ---------------------------------------------------------------------
372 /* Status lines are of the form,
373 Status: want flag status
374 want = unknown, install, hold, deinstall, purge
376 status = not-installed, config-files, half-installed, unpacked,
377 half-configured, triggers-awaited, triggers-pending, installed
379 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
380 pkgCache::VerIterator
&)
384 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
385 pkgCache::VerIterator
&Ver
)
389 if (Section
.Find("Status",Start
,Stop
) == false)
392 // UsePackage() is responsible for setting the flag in the default case
393 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
394 if (essential
== true &&
395 Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
398 // Isolate the first word
399 const char *I
= Start
;
400 for(; I
< Stop
&& *I
!= ' '; I
++);
401 if (I
>= Stop
|| *I
!= ' ')
402 return _error
->Error("Malformed Status line");
404 // Process the want field
405 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
406 {"install",pkgCache::State::Install
},
407 {"hold",pkgCache::State::Hold
},
408 {"deinstall",pkgCache::State::DeInstall
},
409 {"purge",pkgCache::State::Purge
},
411 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
412 return _error
->Error("Malformed 1st word in the Status line");
414 // Isloate the next word
417 for(; I
< Stop
&& *I
!= ' '; I
++);
418 if (I
>= Stop
|| *I
!= ' ')
419 return _error
->Error("Malformed status line, no 2nd word");
421 // Process the flag field
422 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
423 {"reinstreq",pkgCache::State::ReInstReq
},
424 {"hold",pkgCache::State::HoldInst
},
425 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
427 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
428 return _error
->Error("Malformed 2nd word in the Status line");
430 // Isloate the last word
433 for(; I
< Stop
&& *I
!= ' '; I
++);
435 return _error
->Error("Malformed Status line, no 3rd word");
437 // Process the flag field
438 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
439 {"config-files",pkgCache::State::ConfigFiles
},
440 {"half-installed",pkgCache::State::HalfInstalled
},
441 {"unpacked",pkgCache::State::UnPacked
},
442 {"half-configured",pkgCache::State::HalfConfigured
},
443 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
444 {"triggers-pending",pkgCache::State::TriggersPending
},
445 {"installed",pkgCache::State::Installed
},
447 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
448 return _error
->Error("Malformed 3rd word in the Status line");
450 /* A Status line marks the package as indicating the current
451 version as well. Only if it is actually installed.. Otherwise
452 the interesting dpkg handling of the status file creates bogus
454 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
455 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
457 if (Ver
.end() == true)
458 _error
->Warning("Encountered status field in a non-version description");
460 Pkg
->CurrentVer
= Ver
.Index();
466 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
468 // Determine the operator
476 Op
= pkgCache::Dep::LessEq
;
483 Op
= pkgCache::Dep::Less
;
487 // < is the same as <= and << is really Cs < for some reason
488 Op
= pkgCache::Dep::LessEq
;
496 Op
= pkgCache::Dep::GreaterEq
;
503 Op
= pkgCache::Dep::Greater
;
507 // > is the same as >= and >> is really Cs > for some reason
508 Op
= pkgCache::Dep::GreaterEq
;
512 Op
= pkgCache::Dep::Equals
;
516 // HACK around bad package definitions
518 Op
= pkgCache::Dep::Equals
;
524 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
525 // ---------------------------------------------------------------------
526 /* This parses the dependency elements out of a standard string in place,
528 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
529 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
530 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
531 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
532 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
533 bool const &ParseArchFlags
)
534 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
535 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
536 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
537 bool const &ParseArchFlags
, bool const &StripMultiArch
)
538 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
539 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
540 string
&Package
,string
&Ver
,
541 unsigned int &Op
, bool const &ParseArchFlags
,
542 bool const &StripMultiArch
,
543 bool const &ParseRestrictionsList
)
545 StringView PackageView
;
548 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
549 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
550 Package
= PackageView
.to_string();
551 Ver
= VerView
.to_string();
555 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
556 StringView
&Package
,StringView
&Ver
,
557 unsigned int &Op
, bool ParseArchFlags
,
559 bool ParseRestrictionsList
)
561 // Strip off leading space
562 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
564 // Parse off the package name
565 const char *I
= Start
;
566 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
567 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
568 *I
!= '<' && *I
!= '>'; ++I
);
571 if (I
!= Stop
&& *I
== ')')
577 // Stash the package name
578 Package
= StringView(Start
, I
- Start
);
580 // We don't want to confuse library users which can't handle MultiArch
581 if (StripMultiArch
== true) {
582 string
const arch
= _config
->Find("APT::Architecture");
583 size_t const found
= Package
.rfind(':');
584 if (found
!= StringView::npos
&&
585 (Package
.substr(found
) == ":any" ||
586 Package
.substr(found
) == ":native" ||
587 Package
.substr(found
+1) == arch
))
588 Package
= Package
.substr(0,found
);
591 // Skip white space to the '('
592 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
595 if (I
!= Stop
&& *I
== '(')
598 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
601 I
= ConvertRelation(I
,Op
);
604 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
606 I
= (const char*) memchr(I
, ')', Stop
- I
);
607 if (I
== NULL
|| Start
== I
)
610 // Skip trailing whitespace
612 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
614 Ver
= StringView(Start
,End
-Start
);
620 Op
= pkgCache::Dep::NoOp
;
624 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
626 if (unlikely(ParseArchFlags
== true))
628 string
const arch
= _config
->Find("APT::Architecture");
629 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
631 // Parse an architecture
632 if (I
!= Stop
&& *I
== '[')
636 if (unlikely(I
== Stop
))
641 bool NegArch
= false;
644 // look for whitespace or ending ']'
645 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
647 if (unlikely(End
== Stop
))
656 std::string
const arch(I
, End
);
657 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
662 // we found a match, so fast-forward to the end of the wildcards
663 for (; End
!= Stop
&& *End
!= ']'; ++End
);
672 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
679 Package
= ""; /* not for this arch */
683 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
686 if (unlikely(ParseRestrictionsList
== true))
688 // Parse a restrictions formula which is in disjunctive normal form:
689 // (foo AND bar) OR (blub AND bla)
691 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
693 // if the next character is a restriction list, then by default the
694 // dependency does not apply and the conditions have to be checked
695 // if the next character is not a restriction list, then by default the
696 // dependency applies
697 bool applies1
= (*I
!= '<');
705 if (unlikely(I
== Stop
))
710 // if of the prior restriction list is already fulfilled, then
711 // we can just skip to the end of the current list
713 for (;End
!= Stop
&& *End
!= '>'; ++End
);
716 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
718 bool applies2
= true;
719 // all the conditions inside a restriction list have to be
720 // met so once we find one that is not met, we can skip to
721 // the end of this list
724 // look for whitespace or ending '>'
725 // End now points to the character after the current term
726 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
728 if (unlikely(End
== Stop
))
731 bool NegRestriction
= false;
734 NegRestriction
= true;
738 std::string
const restriction(I
, End
);
739 if (restriction
.empty() == false && profiles
.empty() == false &&
740 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
742 if (NegRestriction
) {
744 // since one of the terms does not apply we don't have to check the others
745 for (; End
!= Stop
&& *End
!= '>'; ++End
);
748 if (!NegRestriction
) {
750 // since one of the terms does not apply we don't have to check the others
751 for (; End
!= Stop
&& *End
!= '>'; ++End
);
758 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
764 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
772 if (applies1
== false) {
773 Package
= ""; //not for this restriction
777 if (I
!= Stop
&& *I
== '|')
778 Op
|= pkgCache::Dep::Or
;
780 if (I
== Stop
|| *I
== ',' || *I
== '|')
783 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
790 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
791 // ---------------------------------------------------------------------
792 /* This is the higher level depends parser. It takes a tag and generates
793 a complete depends tree for the given version. */
794 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
795 StringView Tag
,unsigned int Type
)
799 if (Section
.Find(Tag
,Start
,Stop
) == false || Start
== Stop
)
802 string
const pkgArch
= Ver
.Arch();
810 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
812 return _error
->Error("Problem parsing dependency %.*s",(int)Tag
.length(), Tag
.data());
813 size_t const found
= Package
.rfind(':');
815 if (found
== string::npos
)
817 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
820 else if (Package
.substr(found
) == ":any")
822 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
827 // Such dependencies are not supposed to be accepted …
828 // … but this is probably the best thing to do anyway
829 if (Package
.substr(found
+ 1) == "native")
831 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
832 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
835 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
845 // ListParser::ParseProvides - Parse the provides list /*{{{*/
846 // ---------------------------------------------------------------------
848 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
850 /* it is unlikely, but while parsing dependencies, we might have already
851 picked up multi-arch implicit provides which we do not want to duplicate here */
852 bool hasProvidesAlready
= false;
853 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
855 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
857 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
859 if (spzName
!= Prv
.OwnerPkg().FullName(false))
861 hasProvidesAlready
= true;
866 string
const Arch
= Ver
.Arch();
869 if (Section
.Find("Provides",Start
,Stop
) == true)
877 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
878 const size_t archfound
= Package
.rfind(':');
880 return _error
->Error("Problem parsing Provides line");
881 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
882 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
883 } else if (archfound
!= string::npos
) {
884 StringView spzArch
= Package
.substr(archfound
+ 1);
885 if (spzArch
!= "any")
887 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
890 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
892 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
893 if (APT::Configuration::checkArchitecture(Arch
))
895 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
898 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
901 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
903 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
906 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
909 if (archfound
== std::string::npos
)
911 string spzName
= Package
.to_string();
912 spzName
.push_back(':');
913 spzName
.append(Ver
.ParentPkg().Arch());
914 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
915 if (spzPkg
.end() == false)
917 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
921 } while (Start
!= Stop
);
924 if (APT::Configuration::checkArchitecture(Arch
))
926 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
928 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
929 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
932 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
934 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
939 if (hasProvidesAlready
== false)
941 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
942 if (spzPkg
.end() == false)
944 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
951 // ListParser::GrabWord - Matches a word and returns /*{{{*/
952 // ---------------------------------------------------------------------
953 /* Looks for a word in a list of words - for ParseStatus */
954 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
956 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
958 if (Word
.length() == List
[C
].Str
.length() &&
959 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
968 // ListParser::Step - Move to the next section in the file /*{{{*/
969 // ---------------------------------------------------------------------
970 /* This has to be careful to only process the correct architecture */
971 bool debListParser::Step()
973 iOffset
= Tags
.Offset();
974 return Tags
.Step(Section
);
977 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
978 // ---------------------------------------------------------------------
980 unsigned char debListParser::GetPrio(string Str
)
983 if (GrabWord(Str
,PrioList
,Out
) == false)
984 Out
= pkgCache::State::Extra
;
989 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
990 pkgCache::VerIterator
const &Ver
)
992 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
994 // status file has no (Download)Size, but all others are fair game
995 // status file is parsed last, so the first version we encounter is
996 // probably also the version we have downloaded
997 unsigned long long const Size
= Section
.FindULL("Size");
998 if (Size
!= 0 && Size
!= Ver
->Size
)
1000 // available everywhere, but easier to check here than to include in VersionHash
1001 unsigned char MultiArch
= ParseMultiArch(false);
1002 if (MultiArch
!= Ver
->MultiArch
)
1004 // for all practical proposes (we can check): same version
1009 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1010 : debListParser(File
), DebFile(DebFile
)
1014 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1015 pkgCache::VerIterator
&Ver
)
1017 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1018 // we use the full file path as a provides so that the file is found
1020 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1025 debListParser::~debListParser() {}