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
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
;
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 Ver
->SourceVerStr
= idx
;
174 APT::StringView
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::AvailableDescriptionLanguages /*{{{*/
239 std::vector
<std::string
> debListParser::AvailableDescriptionLanguages()
241 std::vector
<std::string
> const understood
= APT::Configuration::getLanguages();
242 std::vector
<std::string
> avail
;
243 static constexpr int prefixLen
= 12;
244 static constexpr int avgLanguageLen
= 5;
247 tagname
.reserve(prefixLen
+ avgLanguageLen
);
248 tagname
.assign("Description-");
249 if (Section
.Exists("Description") == true)
251 for (std::vector
<std::string
>::const_iterator lang
= understood
.begin(); lang
!= understood
.end(); ++lang
)
253 tagname
.resize(prefixLen
);
254 tagname
.append(*lang
);
255 if (Section
.Exists(tagname
) == true)
256 avail
.push_back(*lang
);
261 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
262 // ---------------------------------------------------------------------
263 /* This is to return the md5 string to allow the check if it is the right
264 description. If no Description-md5 is found in the section it will be
267 MD5SumValue
debListParser::Description_md5()
269 StringView
const value
= Section
.Find("Description-md5");
270 if (value
.empty() == true)
272 StringView
const desc
= Section
.Find("Description");
274 return MD5SumValue();
277 md5
.Add(desc
.data(), desc
.size());
281 else if (likely(value
.size() == 32))
283 MD5SumValue sumvalue
;
284 if (sumvalue
.Set(value
))
287 _error
->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value
.length(), value
.data());
288 return MD5SumValue();
290 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
291 return MD5SumValue();
294 // ListParser::UsePackage - Update a package structure /*{{{*/
295 // ---------------------------------------------------------------------
296 /* This is called to update the package with any new information
297 that might be found in the section */
298 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
299 pkgCache::VerIterator
&Ver
)
301 string
const static myArch
= _config
->Find("APT::Architecture");
302 // Possible values are: "all", "native", "installed" and "none"
303 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
304 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
305 if (essential
== "all" ||
306 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
307 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
309 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
312 if (strcmp(Pkg
.Name(),"apt") == 0)
314 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
316 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
318 Pkg
->Flags
|= pkgCache::Flag::Important
;
321 if (ParseStatus(Pkg
,Ver
) == false)
326 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
327 // ---------------------------------------------------------------------
329 unsigned short debListParser::VersionHash()
331 static const StringView Sections
[] ={"Installed-Size",
339 unsigned long Result
= INIT_FCS
;
341 for (StringView I
: Sections
)
345 if (Section
.Find(I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
348 /* Strip out any spaces from the text, this undoes dpkgs reformatting
349 of certain fields. dpkg also has the rather interesting notion of
350 reformatting depends operators < -> <= */
352 for (; Start
!= End
; ++Start
)
354 if (isspace_ascii(*Start
) != 0)
356 *J
++ = tolower_ascii(*Start
);
358 if ((*Start
== '<' || *Start
== '>') && Start
[1] != *Start
&& Start
[1] != '=')
362 Result
= AddCRC16(Result
,S
,J
- S
);
368 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
369 // ---------------------------------------------------------------------
370 /* Status lines are of the form,
371 Status: want flag status
372 want = unknown, install, hold, deinstall, purge
374 status = not-installed, config-files, half-installed, unpacked,
375 half-configured, triggers-awaited, triggers-pending, installed
377 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
378 pkgCache::VerIterator
&)
382 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
383 pkgCache::VerIterator
&Ver
)
387 if (Section
.Find("Status",Start
,Stop
) == false)
390 // UsePackage() is responsible for setting the flag in the default case
391 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
392 if (essential
== true &&
393 Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
396 // Isolate the first word
397 const char *I
= Start
;
398 for(; I
< Stop
&& *I
!= ' '; I
++);
399 if (I
>= Stop
|| *I
!= ' ')
400 return _error
->Error("Malformed Status line");
402 // Process the want field
403 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
404 {"install",pkgCache::State::Install
},
405 {"hold",pkgCache::State::Hold
},
406 {"deinstall",pkgCache::State::DeInstall
},
407 {"purge",pkgCache::State::Purge
},
409 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
410 return _error
->Error("Malformed 1st word in the Status line");
412 // Isloate the next word
415 for(; I
< Stop
&& *I
!= ' '; I
++);
416 if (I
>= Stop
|| *I
!= ' ')
417 return _error
->Error("Malformed status line, no 2nd word");
419 // Process the flag field
420 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
421 {"reinstreq",pkgCache::State::ReInstReq
},
422 {"hold",pkgCache::State::HoldInst
},
423 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
425 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
426 return _error
->Error("Malformed 2nd word in the Status line");
428 // Isloate the last word
431 for(; I
< Stop
&& *I
!= ' '; I
++);
433 return _error
->Error("Malformed Status line, no 3rd word");
435 // Process the flag field
436 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
437 {"config-files",pkgCache::State::ConfigFiles
},
438 {"half-installed",pkgCache::State::HalfInstalled
},
439 {"unpacked",pkgCache::State::UnPacked
},
440 {"half-configured",pkgCache::State::HalfConfigured
},
441 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
442 {"triggers-pending",pkgCache::State::TriggersPending
},
443 {"installed",pkgCache::State::Installed
},
445 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
446 return _error
->Error("Malformed 3rd word in the Status line");
448 /* A Status line marks the package as indicating the current
449 version as well. Only if it is actually installed.. Otherwise
450 the interesting dpkg handling of the status file creates bogus
452 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
453 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
455 if (Ver
.end() == true)
456 _error
->Warning("Encountered status field in a non-version description");
458 Pkg
->CurrentVer
= Ver
.Index();
464 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
466 // Determine the operator
474 Op
= pkgCache::Dep::LessEq
;
481 Op
= pkgCache::Dep::Less
;
485 // < is the same as <= and << is really Cs < for some reason
486 Op
= pkgCache::Dep::LessEq
;
494 Op
= pkgCache::Dep::GreaterEq
;
501 Op
= pkgCache::Dep::Greater
;
505 // > is the same as >= and >> is really Cs > for some reason
506 Op
= pkgCache::Dep::GreaterEq
;
510 Op
= pkgCache::Dep::Equals
;
514 // HACK around bad package definitions
516 Op
= pkgCache::Dep::Equals
;
522 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
523 // ---------------------------------------------------------------------
524 /* This parses the dependency elements out of a standard string in place,
526 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
527 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
528 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
529 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
530 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
531 bool const &ParseArchFlags
)
532 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
533 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
534 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
535 bool const &ParseArchFlags
, bool const &StripMultiArch
)
536 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
537 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
538 string
&Package
,string
&Ver
,
539 unsigned int &Op
, bool const &ParseArchFlags
,
540 bool const &StripMultiArch
,
541 bool const &ParseRestrictionsList
)
543 StringView PackageView
;
546 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
547 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
548 Package
= PackageView
.to_string();
549 Ver
= VerView
.to_string();
553 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
554 StringView
&Package
,StringView
&Ver
,
555 unsigned int &Op
, bool ParseArchFlags
,
557 bool ParseRestrictionsList
)
559 // Strip off leading space
560 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
562 // Parse off the package name
563 const char *I
= Start
;
564 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
565 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
566 *I
!= '<' && *I
!= '>'; ++I
);
569 if (I
!= Stop
&& *I
== ')')
575 // Stash the package name
576 Package
= StringView(Start
, I
- Start
);
578 // We don't want to confuse library users which can't handle MultiArch
579 if (StripMultiArch
== true) {
580 string
const arch
= _config
->Find("APT::Architecture");
581 size_t const found
= Package
.rfind(':');
582 if (found
!= StringView::npos
&&
583 (Package
.substr(found
) == ":any" ||
584 Package
.substr(found
) == ":native" ||
585 Package
.substr(found
+1) == arch
))
586 Package
= Package
.substr(0,found
);
589 // Skip white space to the '('
590 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
593 if (I
!= Stop
&& *I
== '(')
596 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
599 I
= ConvertRelation(I
,Op
);
602 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
604 I
= (const char*) memchr(I
, ')', Stop
- I
);
605 if (I
== NULL
|| Start
== I
)
608 // Skip trailing whitespace
610 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
612 Ver
= StringView(Start
,End
-Start
);
618 Op
= pkgCache::Dep::NoOp
;
622 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
624 if (unlikely(ParseArchFlags
== true))
626 string
const arch
= _config
->Find("APT::Architecture");
627 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
629 // Parse an architecture
630 if (I
!= Stop
&& *I
== '[')
634 if (unlikely(I
== Stop
))
639 bool NegArch
= false;
642 // look for whitespace or ending ']'
643 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
645 if (unlikely(End
== Stop
))
654 std::string
const arch(I
, End
);
655 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
660 // we found a match, so fast-forward to the end of the wildcards
661 for (; End
!= Stop
&& *End
!= ']'; ++End
);
670 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
677 Package
= ""; /* not for this arch */
681 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
684 if (unlikely(ParseRestrictionsList
== true))
686 // Parse a restrictions formula which is in disjunctive normal form:
687 // (foo AND bar) OR (blub AND bla)
689 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
691 // if the next character is a restriction list, then by default the
692 // dependency does not apply and the conditions have to be checked
693 // if the next character is not a restriction list, then by default the
694 // dependency applies
695 bool applies1
= (*I
!= '<');
703 if (unlikely(I
== Stop
))
708 // if of the prior restriction list is already fulfilled, then
709 // we can just skip to the end of the current list
711 for (;End
!= Stop
&& *End
!= '>'; ++End
);
714 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
716 bool applies2
= true;
717 // all the conditions inside a restriction list have to be
718 // met so once we find one that is not met, we can skip to
719 // the end of this list
722 // look for whitespace or ending '>'
723 // End now points to the character after the current term
724 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
726 if (unlikely(End
== Stop
))
729 bool NegRestriction
= false;
732 NegRestriction
= true;
736 std::string
const restriction(I
, End
);
737 if (restriction
.empty() == false && profiles
.empty() == false &&
738 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
740 if (NegRestriction
) {
742 // since one of the terms does not apply we don't have to check the others
743 for (; End
!= Stop
&& *End
!= '>'; ++End
);
746 if (!NegRestriction
) {
748 // since one of the terms does not apply we don't have to check the others
749 for (; End
!= Stop
&& *End
!= '>'; ++End
);
756 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
762 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
770 if (applies1
== false) {
771 Package
= ""; //not for this restriction
775 if (I
!= Stop
&& *I
== '|')
776 Op
|= pkgCache::Dep::Or
;
778 if (I
== Stop
|| *I
== ',' || *I
== '|')
781 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
788 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
789 // ---------------------------------------------------------------------
790 /* This is the higher level depends parser. It takes a tag and generates
791 a complete depends tree for the given version. */
792 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
793 StringView Tag
,unsigned int Type
)
797 if (Section
.Find(Tag
,Start
,Stop
) == false || Start
== Stop
)
800 string
const pkgArch
= Ver
.Arch();
808 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
810 return _error
->Error("Problem parsing dependency %.*s",(int)Tag
.length(), Tag
.data());
811 size_t const found
= Package
.rfind(':');
813 if (found
== string::npos
)
815 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
818 else if (Package
.substr(found
) == ":any")
820 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
825 // Such dependencies are not supposed to be accepted …
826 // … but this is probably the best thing to do anyway
827 if (Package
.substr(found
+ 1) == "native")
829 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
830 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
833 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
843 // ListParser::ParseProvides - Parse the provides list /*{{{*/
844 // ---------------------------------------------------------------------
846 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
848 /* it is unlikely, but while parsing dependencies, we might have already
849 picked up multi-arch implicit provides which we do not want to duplicate here */
850 bool hasProvidesAlready
= false;
851 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
853 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
855 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
857 if (spzName
!= Prv
.OwnerPkg().FullName(false))
859 hasProvidesAlready
= true;
864 string
const Arch
= Ver
.Arch();
867 if (Section
.Find("Provides",Start
,Stop
) == true)
875 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
876 const size_t archfound
= Package
.rfind(':');
878 return _error
->Error("Problem parsing Provides line");
879 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
880 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
881 } else if (archfound
!= string::npos
) {
882 StringView spzArch
= Package
.substr(archfound
+ 1);
883 if (spzArch
!= "any")
885 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
888 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
890 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
891 if (APT::Configuration::checkArchitecture(Arch
))
893 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
896 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
899 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
901 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
904 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
907 if (archfound
== std::string::npos
)
909 string spzName
= Package
.to_string();
910 spzName
.push_back(':');
911 spzName
.append(Ver
.ParentPkg().Arch());
912 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
913 if (spzPkg
.end() == false)
915 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
919 } while (Start
!= Stop
);
922 if (APT::Configuration::checkArchitecture(Arch
))
924 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
926 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
927 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
930 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
932 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
937 if (hasProvidesAlready
== false)
939 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
940 if (spzPkg
.end() == false)
942 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
949 // ListParser::GrabWord - Matches a word and returns /*{{{*/
950 // ---------------------------------------------------------------------
951 /* Looks for a word in a list of words - for ParseStatus */
952 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
954 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
956 if (Word
.length() == List
[C
].Str
.length() &&
957 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
966 // ListParser::Step - Move to the next section in the file /*{{{*/
967 // ---------------------------------------------------------------------
968 /* This has to be careful to only process the correct architecture */
969 bool debListParser::Step()
971 iOffset
= Tags
.Offset();
972 return Tags
.Step(Section
);
975 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
976 // ---------------------------------------------------------------------
978 unsigned char debListParser::GetPrio(string Str
)
981 if (GrabWord(Str
,PrioList
,Out
) == false)
982 Out
= pkgCache::State::Extra
;
987 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
988 pkgCache::VerIterator
const &Ver
)
990 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
992 // status file has no (Download)Size, but all others are fair game
993 // status file is parsed last, so the first version we encounter is
994 // probably also the version we have downloaded
995 unsigned long long const Size
= Section
.FindULL("Size");
996 if (Size
!= 0 && Size
!= Ver
->Size
)
998 // available everywhere, but easier to check here than to include in VersionHash
999 unsigned char MultiArch
= ParseMultiArch(false);
1000 if (MultiArch
!= Ver
->MultiArch
)
1002 // for all practical proposes (we can check): same version
1007 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1008 : debListParser(File
), DebFile(DebFile
)
1012 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1013 pkgCache::VerIterator
&Ver
)
1015 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1016 // we use the full file path as a provides so that the file is found
1018 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1023 debListParser::~debListParser() {}