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/tagfile-keys.h>
27 #include <apt-pkg/macros.h>
38 using APT::StringView
;
40 static const 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
},
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() */
53 debListParser::debListParser(FileFd
*File
) :
54 pkgCacheListParser(), Tags(File
)
56 // this dance allows an empty value to override the default
57 if (_config
->Exists("pkgCacheGen::ForceEssential"))
59 forceEssential
= _config
->FindVector("pkgCacheGen::ForceEssential");
60 if (forceEssential
.empty() == false && _config
->Find("pkgCacheGen::ForceEssential").empty())
61 forceEssential
.emplace_back("apt");
64 forceEssential
.emplace_back("apt");
65 forceImportant
= _config
->FindVector("pkgCacheGen::ForceImportant");
68 // ListParser::Package - Return the package name /*{{{*/
69 // ---------------------------------------------------------------------
70 /* This is to return the name of the package this section describes */
71 string
debListParser::Package() {
72 string Result
= Section
.Find(pkgTagSection::Key::Package
).to_string();
74 // Normalize mixed case package names to lower case, like dpkg does
75 // See Bug#807012 for details
76 std::transform(Result
.begin(), Result
.end(), Result
.begin(), tolower_ascii
);
78 if(unlikely(Result
.empty() == true))
79 _error
->Error("Encountered a section with no Package: header");
83 // ListParser::Architecture - Return the package arch /*{{{*/
84 // ---------------------------------------------------------------------
85 /* This will return the Architecture of the package this section describes */
86 APT::StringView
debListParser::Architecture() {
87 auto const Arch
= Section
.Find(pkgTagSection::Key::Architecture
);
88 return Arch
.empty() ? "none" : Arch
;
91 // ListParser::ArchitectureAll /*{{{*/
92 // ---------------------------------------------------------------------
94 bool debListParser::ArchitectureAll() {
95 return Section
.Find(pkgTagSection::Key::Architecture
) == "all";
98 // ListParser::Version - Return the version string /*{{{*/
99 // ---------------------------------------------------------------------
100 /* This is to return the string describing the version in debian form,
101 epoch:upstream-release. If this returns the blank string then the
102 entry is assumed to only describe package properties */
103 APT::StringView
debListParser::Version()
105 return Section
.Find(pkgTagSection::Key::Version
);
108 unsigned char debListParser::ParseMultiArch(bool const showErrors
) /*{{{*/
111 auto const MultiArch
= Section
.Find(pkgTagSection::Key::Multi_Arch
);
112 if (MultiArch
.empty() == true || MultiArch
== "no")
113 MA
= pkgCache::Version::No
;
114 else if (MultiArch
== "same") {
115 if (ArchitectureAll() == true)
117 if (showErrors
== true)
118 _error
->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
119 Section
.FindS("Package").c_str());
120 MA
= pkgCache::Version::No
;
123 MA
= pkgCache::Version::Same
;
125 else if (MultiArch
== "foreign")
126 MA
= pkgCache::Version::Foreign
;
127 else if (MultiArch
== "allowed")
128 MA
= pkgCache::Version::Allowed
;
131 if (showErrors
== true)
132 _error
->Warning("Unknown Multi-Arch type '%s' for package '%s'",
133 MultiArch
.to_string().c_str(), Section
.FindS("Package").c_str());
134 MA
= pkgCache::Version::No
;
137 if (ArchitectureAll() == true)
138 MA
|= pkgCache::Version::All
;
143 // ListParser::NewVersion - Fill in the version structure /*{{{*/
144 // ---------------------------------------------------------------------
146 bool debListParser::NewVersion(pkgCache::VerIterator
&Ver
)
152 if (Section
.Find(pkgTagSection::Key::Section
,Start
,Stop
) == true)
154 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::SECTION
, Start
, Stop
- Start
);
157 // Parse the source package name
158 pkgCache::GrpIterator G
= Ver
.ParentPkg().Group();
159 Ver
->SourcePkgName
= G
->Name
;
160 Ver
->SourceVerStr
= Ver
->VerStr
;
161 if (Section
.Find(pkgTagSection::Key::Source
,Start
,Stop
) == true)
163 const char * const Space
= (const char * const) memchr(Start
, ' ', Stop
- Start
);
164 pkgCache::VerIterator V
;
168 const char * const Open
= (const char * const) memchr(Space
, '(', Stop
- Space
);
169 if (likely(Open
!= NULL
))
171 const char * const Close
= (const char * const) memchr(Open
, ')', Stop
- Open
);
172 if (likely(Close
!= NULL
))
174 APT::StringView
const version(Open
+ 1, (Close
- Open
) - 1);
175 if (version
!= Ver
.VerStr())
177 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, version
);
178 G
= Ver
.ParentPkg().Group();
179 Ver
->SourceVerStr
= idx
;
186 APT::StringView
const pkgname(Start
, Stop
- Start
);
187 if (pkgname
!= G
.Name())
189 for (pkgCache::PkgIterator P
= G
.PackageList(); P
.end() == false; P
= G
.NextPkg(P
))
191 for (V
= P
.VersionList(); V
.end() == false; ++V
)
193 if (pkgname
== V
.SourcePkgName())
195 Ver
->SourcePkgName
= V
->SourcePkgName
;
199 if (V
.end() == false)
204 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::PKGNAME
, pkgname
);
205 G
= Ver
.ParentPkg().Group();
206 Ver
->SourcePkgName
= idx
;
211 Ver
->MultiArch
= ParseMultiArch(true);
213 Ver
->Size
= Section
.FindULL(pkgTagSection::Key::Size
);
214 // Unpacked Size (in K)
215 Ver
->InstalledSize
= Section
.FindULL(pkgTagSection::Key::Installed_Size
);
216 Ver
->InstalledSize
*= 1024;
219 if (Section
.Find(pkgTagSection::Key::Priority
,Start
,Stop
) == true)
221 if (GrabWord(StringView(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
222 Ver
->Priority
= pkgCache::State::Extra
;
225 if (ParseDepends(Ver
,pkgTagSection::Key::Pre_Depends
,pkgCache::Dep::PreDepends
) == false)
227 if (ParseDepends(Ver
,pkgTagSection::Key::Depends
,pkgCache::Dep::Depends
) == false)
229 if (ParseDepends(Ver
,pkgTagSection::Key::Conflicts
,pkgCache::Dep::Conflicts
) == false)
231 if (ParseDepends(Ver
,pkgTagSection::Key::Breaks
,pkgCache::Dep::DpkgBreaks
) == false)
233 if (ParseDepends(Ver
,pkgTagSection::Key::Recommends
,pkgCache::Dep::Recommends
) == false)
235 if (ParseDepends(Ver
,pkgTagSection::Key::Suggests
,pkgCache::Dep::Suggests
) == false)
237 if (ParseDepends(Ver
,pkgTagSection::Key::Replaces
,pkgCache::Dep::Replaces
) == false)
239 if (ParseDepends(Ver
,pkgTagSection::Key::Enhances
,pkgCache::Dep::Enhances
) == false)
242 if (ParseDepends(Ver
,pkgTagSection::Key::Optional
,pkgCache::Dep::Suggests
) == false)
245 if (ParseProvides(Ver
) == false)
251 // ListParser::AvailableDescriptionLanguages /*{{{*/
252 std::vector
<std::string
> debListParser::AvailableDescriptionLanguages()
254 std::vector
<std::string
> const understood
= APT::Configuration::getLanguages();
255 std::vector
<std::string
> avail
;
256 static constexpr int prefixLen
= 12;
257 char buf
[32] = "Description-";
258 if (Section
.Exists("Description") == true)
260 for (std::vector
<std::string
>::const_iterator lang
= understood
.begin(); lang
!= understood
.end(); ++lang
)
262 if (unlikely(lang
->size() > sizeof(buf
) - prefixLen
)) {
263 _error
->Warning("Ignoring translated description %s", lang
->c_str());
266 memcpy(buf
+ prefixLen
, lang
->c_str(), lang
->size());
267 if (Section
.Exists(StringView(buf
, prefixLen
+ lang
->size())) == true)
268 avail
.push_back(*lang
);
273 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
274 // ---------------------------------------------------------------------
275 /* This is to return the md5 string to allow the check if it is the right
276 description. If no Description-md5 is found in the section it will be
279 APT::StringView
debListParser::Description_md5()
281 StringView
const value
= Section
.Find(pkgTagSection::Key::Description_md5
);
282 if (unlikely(value
.empty() == true))
284 StringView
const desc
= Section
.Find(pkgTagSection::Key::Description
);
289 md5
.Add(desc
.data(), desc
.size());
291 MD5Buffer
= md5
.Result();
292 return StringView(MD5Buffer
);
294 else if (likely(value
.size() == 32))
298 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
302 // ListParser::UsePackage - Update a package structure /*{{{*/
303 // ---------------------------------------------------------------------
304 /* This is called to update the package with any new information
305 that might be found in the section */
306 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
307 pkgCache::VerIterator
&Ver
)
309 string
const static myArch
= _config
->Find("APT::Architecture");
310 // Possible values are: "all", "native", "installed" and "none"
311 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
312 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
313 if (essential
== "all" ||
314 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
315 if (Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
317 if (Section
.FindFlag(pkgTagSection::Key::Important
,Pkg
->Flags
,pkgCache::Flag::Important
) == false)
320 if (std::find(forceEssential
.begin(), forceEssential
.end(), Pkg
.Name()) != forceEssential
.end())
322 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
324 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
326 Pkg
->Flags
|= pkgCache::Flag::Important
;
328 else if (std::find(forceImportant
.begin(), forceImportant
.end(), Pkg
.Name()) != forceImportant
.end())
329 Pkg
->Flags
|= pkgCache::Flag::Important
;
331 if (ParseStatus(Pkg
,Ver
) == false)
336 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
337 // ---------------------------------------------------------------------
339 unsigned short debListParser::VersionHash()
341 static constexpr pkgTagSection::Key Sections
[] ={
342 pkgTagSection::Key::Installed_Size
,
343 pkgTagSection::Key::Depends
,
344 pkgTagSection::Key::Pre_Depends
,
345 // pkgTagSection::Key::Suggests,
346 // pkgTagSection::Key::Recommends",
347 pkgTagSection::Key::Conflicts
,
348 pkgTagSection::Key::Breaks
,
349 pkgTagSection::Key::Replaces
};
350 unsigned long Result
= INIT_FCS
;
351 for (auto I
: Sections
)
355 if (Section
.Find(I
,Start
,End
) == false)
358 /* Strip out any spaces from the text, this undoes dpkgs reformatting
359 of certain fields. dpkg also has the rather interesting notion of
360 reformatting depends operators < -> <=, so we drop all = from the
361 string to make that not matter. */
362 for (; Start
!= End
; ++Start
)
364 if (isspace_ascii(*Start
) != 0 || *Start
== '=')
366 Result
= AddCRC16Byte(Result
, tolower_ascii_unsafe(*Start
));
375 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
376 // ---------------------------------------------------------------------
377 /* Status lines are of the form,
378 Status: want flag status
379 want = unknown, install, hold, deinstall, purge
381 status = not-installed, config-files, half-installed, unpacked,
382 half-configured, triggers-awaited, triggers-pending, installed
384 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
385 pkgCache::VerIterator
&)
389 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
390 pkgCache::VerIterator
&Ver
)
394 if (Section
.Find(pkgTagSection::Key::Status
,Start
,Stop
) == false)
397 // UsePackage() is responsible for setting the flag in the default case
398 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
399 if (essential
== true &&
400 Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
403 // Isolate the first word
404 const char *I
= Start
;
405 for(; I
< Stop
&& *I
!= ' '; I
++);
406 if (I
>= Stop
|| *I
!= ' ')
407 return _error
->Error("Malformed Status line");
409 // Process the want field
410 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
411 {"install",pkgCache::State::Install
},
412 {"hold",pkgCache::State::Hold
},
413 {"deinstall",pkgCache::State::DeInstall
},
414 {"purge",pkgCache::State::Purge
},
416 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
417 return _error
->Error("Malformed 1st word in the Status line");
419 // Isloate the next word
422 for(; I
< Stop
&& *I
!= ' '; I
++);
423 if (I
>= Stop
|| *I
!= ' ')
424 return _error
->Error("Malformed status line, no 2nd word");
426 // Process the flag field
427 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
428 {"reinstreq",pkgCache::State::ReInstReq
},
429 {"hold",pkgCache::State::HoldInst
},
430 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
432 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
433 return _error
->Error("Malformed 2nd word in the Status line");
435 // Isloate the last word
438 for(; I
< Stop
&& *I
!= ' '; I
++);
440 return _error
->Error("Malformed Status line, no 3rd word");
442 // Process the flag field
443 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
444 {"config-files",pkgCache::State::ConfigFiles
},
445 {"half-installed",pkgCache::State::HalfInstalled
},
446 {"unpacked",pkgCache::State::UnPacked
},
447 {"half-configured",pkgCache::State::HalfConfigured
},
448 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
449 {"triggers-pending",pkgCache::State::TriggersPending
},
450 {"installed",pkgCache::State::Installed
},
452 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
453 return _error
->Error("Malformed 3rd word in the Status line");
455 /* A Status line marks the package as indicating the current
456 version as well. Only if it is actually installed.. Otherwise
457 the interesting dpkg handling of the status file creates bogus
459 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
460 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
462 if (Ver
.end() == true)
463 _error
->Warning("Encountered status field in a non-version description");
465 Pkg
->CurrentVer
= Ver
.Index();
471 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
473 // Determine the operator
481 Op
= pkgCache::Dep::LessEq
;
488 Op
= pkgCache::Dep::Less
;
492 // < is the same as <= and << is really Cs < for some reason
493 Op
= pkgCache::Dep::LessEq
;
501 Op
= pkgCache::Dep::GreaterEq
;
508 Op
= pkgCache::Dep::Greater
;
512 // > is the same as >= and >> is really Cs > for some reason
513 Op
= pkgCache::Dep::GreaterEq
;
517 Op
= pkgCache::Dep::Equals
;
521 // HACK around bad package definitions
523 Op
= pkgCache::Dep::Equals
;
529 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
530 // ---------------------------------------------------------------------
531 /* This parses the dependency elements out of a standard string in place,
533 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
534 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
535 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
536 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
537 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
538 bool const &ParseArchFlags
)
539 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, 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
, bool const &StripMultiArch
)
543 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
544 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
545 string
&Package
,string
&Ver
,
546 unsigned int &Op
, bool const &ParseArchFlags
,
547 bool const &StripMultiArch
,
548 bool const &ParseRestrictionsList
)
550 StringView PackageView
;
553 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
554 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
555 Package
= PackageView
.to_string();
556 Ver
= VerView
.to_string();
560 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
561 StringView
&Package
,StringView
&Ver
,
562 unsigned int &Op
, bool ParseArchFlags
,
564 bool ParseRestrictionsList
)
566 // Strip off leading space
567 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
569 // Parse off the package name
570 const char *I
= Start
;
571 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
572 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
573 *I
!= '<' && *I
!= '>'; ++I
);
576 if (I
!= Stop
&& *I
== ')')
582 // Stash the package name
583 Package
= StringView(Start
, I
- Start
);
585 // We don't want to confuse library users which can't handle MultiArch
586 if (StripMultiArch
== true) {
587 string
const arch
= _config
->Find("APT::Architecture");
588 size_t const found
= Package
.rfind(':');
589 if (found
!= StringView::npos
&&
590 (Package
.substr(found
) == ":any" ||
591 Package
.substr(found
) == ":native" ||
592 Package
.substr(found
+1) == arch
))
593 Package
= Package
.substr(0,found
);
596 // Skip white space to the '('
597 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
600 if (I
!= Stop
&& *I
== '(')
603 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
606 I
= ConvertRelation(I
,Op
);
609 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
611 I
= (const char*) memchr(I
, ')', Stop
- I
);
612 if (I
== NULL
|| Start
== I
)
615 // Skip trailing whitespace
617 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
619 Ver
= StringView(Start
,End
-Start
);
625 Op
= pkgCache::Dep::NoOp
;
629 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
631 if (unlikely(ParseArchFlags
== true))
633 string
const arch
= _config
->Find("APT::Architecture");
634 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
636 // Parse an architecture
637 if (I
!= Stop
&& *I
== '[')
641 if (unlikely(I
== Stop
))
646 bool NegArch
= false;
649 // look for whitespace or ending ']'
650 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
652 if (unlikely(End
== Stop
))
661 std::string
const arch(I
, End
);
662 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
667 // we found a match, so fast-forward to the end of the wildcards
668 for (; End
!= Stop
&& *End
!= ']'; ++End
);
677 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
684 Package
= ""; /* not for this arch */
688 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
691 if (unlikely(ParseRestrictionsList
== true))
693 // Parse a restrictions formula which is in disjunctive normal form:
694 // (foo AND bar) OR (blub AND bla)
696 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
698 // if the next character is a restriction list, then by default the
699 // dependency does not apply and the conditions have to be checked
700 // if the next character is not a restriction list, then by default the
701 // dependency applies
702 bool applies1
= (*I
!= '<');
710 if (unlikely(I
== Stop
))
715 // if of the prior restriction list is already fulfilled, then
716 // we can just skip to the end of the current list
718 for (;End
!= Stop
&& *End
!= '>'; ++End
);
721 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
723 bool applies2
= true;
724 // all the conditions inside a restriction list have to be
725 // met so once we find one that is not met, we can skip to
726 // the end of this list
729 // look for whitespace or ending '>'
730 // End now points to the character after the current term
731 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
733 if (unlikely(End
== Stop
))
736 bool NegRestriction
= false;
739 NegRestriction
= true;
743 std::string
const restriction(I
, End
);
744 if (restriction
.empty() == false && profiles
.empty() == false &&
745 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
747 if (NegRestriction
) {
749 // since one of the terms does not apply we don't have to check the others
750 for (; End
!= Stop
&& *End
!= '>'; ++End
);
753 if (!NegRestriction
) {
755 // since one of the terms does not apply we don't have to check the others
756 for (; End
!= Stop
&& *End
!= '>'; ++End
);
763 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
769 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
777 if (applies1
== false) {
778 Package
= ""; //not for this restriction
782 if (I
!= Stop
&& *I
== '|')
783 Op
|= pkgCache::Dep::Or
;
785 if (I
== Stop
|| *I
== ',' || *I
== '|')
788 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
795 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
796 // ---------------------------------------------------------------------
797 /* This is the higher level depends parser. It takes a tag and generates
798 a complete depends tree for the given version. */
799 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
800 pkgTagSection::Key Key
,unsigned int Type
)
804 if (Section
.Find(Key
,Start
,Stop
) == false || Start
== Stop
)
807 string
const pkgArch
= Ver
.Arch();
815 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
817 return _error
->Error("Problem parsing dependency %zu",static_cast<size_t>(Key
)); // TODO
818 size_t const found
= Package
.rfind(':');
820 if (found
== string::npos
)
822 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
825 else if (Package
.substr(found
) == ":any")
827 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
832 // Such dependencies are not supposed to be accepted …
833 // … but this is probably the best thing to do anyway
834 if (Package
.substr(found
+ 1) == "native")
836 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
837 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
840 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
850 // ListParser::ParseProvides - Parse the provides list /*{{{*/
851 // ---------------------------------------------------------------------
853 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
855 /* it is unlikely, but while parsing dependencies, we might have already
856 picked up multi-arch implicit provides which we do not want to duplicate here */
857 bool hasProvidesAlready
= false;
858 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
860 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
862 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
864 if (spzName
!= Prv
.OwnerPkg().FullName(false))
866 hasProvidesAlready
= true;
871 string
const Arch
= Ver
.Arch();
874 if (Section
.Find(pkgTagSection::Key::Provides
,Start
,Stop
) == true)
882 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
883 const size_t archfound
= Package
.rfind(':');
885 return _error
->Error("Problem parsing Provides line");
886 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
887 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
888 } else if (archfound
!= string::npos
) {
889 StringView spzArch
= Package
.substr(archfound
+ 1);
890 if (spzArch
!= "any")
892 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
895 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
897 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
898 if (APT::Configuration::checkArchitecture(Arch
))
900 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
903 else if (NewProvides(Ver
, Package
, Arch
, 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
, WordList
const *List
, unsigned char &Out
)
961 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
963 if (Word
.length() == List
[C
].Str
.length() &&
964 strncasecmp(Word
.data(), List
[C
].Str
.data(), 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(pkgTagSection::Key::Size
);
1003 if (Size
!= 0 && Ver
->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() {}