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 return debListParser::ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
,
551 StripMultiArch
, ParseRestrictionsList
,
552 _config
->Find("APT::Architecture"));
555 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
556 string
&Package
,string
&Ver
,
557 unsigned int &Op
, bool const &ParseArchFlags
,
558 bool const &StripMultiArch
,
559 bool const &ParseRestrictionsList
,
562 StringView PackageView
;
565 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
566 (bool) StripMultiArch
, (bool) ParseRestrictionsList
, Arch
);
567 Package
= PackageView
.to_string();
568 Ver
= VerView
.to_string();
572 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
573 StringView
&Package
,StringView
&Ver
,
574 unsigned int &Op
, bool ParseArchFlags
,
576 bool ParseRestrictionsList
)
578 return debListParser::ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
,
579 StripMultiArch
, ParseRestrictionsList
,
580 _config
->Find("APT::Architecture"));
583 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
584 StringView
&Package
,StringView
&Ver
,
585 unsigned int &Op
, bool ParseArchFlags
,
587 bool ParseRestrictionsList
, string
const &Arch
)
589 // Strip off leading space
590 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
592 // Parse off the package name
593 const char *I
= Start
;
594 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
595 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
596 *I
!= '<' && *I
!= '>'; ++I
);
599 if (I
!= Stop
&& *I
== ')')
605 // Stash the package name
606 Package
= StringView(Start
, I
- Start
);
608 // We don't want to confuse library users which can't handle MultiArch
609 if (StripMultiArch
== true) {
610 string
const arch
= _config
->Find("APT::Architecture");
611 size_t const found
= Package
.rfind(':');
612 if (found
!= StringView::npos
&&
613 (Package
.substr(found
) == ":any" ||
614 Package
.substr(found
) == ":native" ||
615 Package
.substr(found
+1) == arch
))
616 Package
= Package
.substr(0,found
);
619 // Skip white space to the '('
620 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
623 if (I
!= Stop
&& *I
== '(')
626 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
629 I
= ConvertRelation(I
,Op
);
632 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
634 I
= (const char*) memchr(I
, ')', Stop
- I
);
635 if (I
== NULL
|| Start
== I
)
638 // Skip trailing whitespace
640 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
642 Ver
= StringView(Start
,End
-Start
);
648 Op
= pkgCache::Dep::NoOp
;
652 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
654 if (unlikely(ParseArchFlags
== true))
656 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(Arch
, false);
658 // Parse an architecture
659 if (I
!= Stop
&& *I
== '[')
663 if (unlikely(I
== Stop
))
668 bool NegArch
= false;
671 // look for whitespace or ending ']'
672 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
674 if (unlikely(End
== Stop
))
683 std::string
const arch(I
, End
);
684 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
689 // we found a match, so fast-forward to the end of the wildcards
690 for (; End
!= Stop
&& *End
!= ']'; ++End
);
699 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
706 Package
= ""; /* not for this arch */
710 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
713 if (unlikely(ParseRestrictionsList
== true))
715 // Parse a restrictions formula which is in disjunctive normal form:
716 // (foo AND bar) OR (blub AND bla)
718 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
720 // if the next character is a restriction list, then by default the
721 // dependency does not apply and the conditions have to be checked
722 // if the next character is not a restriction list, then by default the
723 // dependency applies
724 bool applies1
= (*I
!= '<');
732 if (unlikely(I
== Stop
))
737 // if of the prior restriction list is already fulfilled, then
738 // we can just skip to the end of the current list
740 for (;End
!= Stop
&& *End
!= '>'; ++End
);
743 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
745 bool applies2
= true;
746 // all the conditions inside a restriction list have to be
747 // met so once we find one that is not met, we can skip to
748 // the end of this list
751 // look for whitespace or ending '>'
752 // End now points to the character after the current term
753 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
755 if (unlikely(End
== Stop
))
758 bool NegRestriction
= false;
761 NegRestriction
= true;
765 std::string
const restriction(I
, End
);
766 if (restriction
.empty() == false && profiles
.empty() == false &&
767 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
769 if (NegRestriction
) {
771 // since one of the terms does not apply we don't have to check the others
772 for (; End
!= Stop
&& *End
!= '>'; ++End
);
775 if (!NegRestriction
) {
777 // since one of the terms does not apply we don't have to check the others
778 for (; End
!= Stop
&& *End
!= '>'; ++End
);
785 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
791 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
799 if (applies1
== false) {
800 Package
= ""; //not for this restriction
804 if (I
!= Stop
&& *I
== '|')
805 Op
|= pkgCache::Dep::Or
;
807 if (I
== Stop
|| *I
== ',' || *I
== '|')
810 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
817 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
818 // ---------------------------------------------------------------------
819 /* This is the higher level depends parser. It takes a tag and generates
820 a complete depends tree for the given version. */
821 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
822 pkgTagSection::Key Key
,unsigned int Type
)
826 if (Section
.Find(Key
,Start
,Stop
) == false || Start
== Stop
)
829 string
const pkgArch
= Ver
.Arch();
837 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
839 return _error
->Error("Problem parsing dependency %zu",static_cast<size_t>(Key
)); // TODO
840 size_t const found
= Package
.rfind(':');
842 if (found
== string::npos
)
844 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
847 else if (Package
.substr(found
) == ":any")
849 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
854 // Such dependencies are not supposed to be accepted …
855 // … but this is probably the best thing to do anyway
856 if (Package
.substr(found
+ 1) == "native")
858 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
859 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
862 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
872 // ListParser::ParseProvides - Parse the provides list /*{{{*/
873 // ---------------------------------------------------------------------
875 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
877 /* it is unlikely, but while parsing dependencies, we might have already
878 picked up multi-arch implicit provides which we do not want to duplicate here */
879 bool hasProvidesAlready
= false;
880 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
882 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
884 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
886 if (spzName
!= Prv
.OwnerPkg().FullName(false))
888 hasProvidesAlready
= true;
893 string
const Arch
= Ver
.Arch();
896 if (Section
.Find(pkgTagSection::Key::Provides
,Start
,Stop
) == true)
904 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
905 const size_t archfound
= Package
.rfind(':');
907 return _error
->Error("Problem parsing Provides line");
908 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
909 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
910 } else if (archfound
!= string::npos
) {
911 StringView spzArch
= Package
.substr(archfound
+ 1);
912 if (spzArch
!= "any")
914 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
917 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
919 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
920 if (APT::Configuration::checkArchitecture(Arch
))
922 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
925 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
928 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
930 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
933 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
936 if (archfound
== std::string::npos
)
938 string spzName
= Package
.to_string();
939 spzName
.push_back(':');
940 spzName
.append(Ver
.ParentPkg().Arch());
941 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
942 if (spzPkg
.end() == false)
944 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
948 } while (Start
!= Stop
);
951 if (APT::Configuration::checkArchitecture(Arch
))
953 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
955 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
956 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
959 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
961 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
966 if (hasProvidesAlready
== false)
968 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
969 if (spzPkg
.end() == false)
971 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
978 // ListParser::GrabWord - Matches a word and returns /*{{{*/
979 // ---------------------------------------------------------------------
980 /* Looks for a word in a list of words - for ParseStatus */
981 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
983 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
985 if (Word
.length() == List
[C
].Str
.length() &&
986 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
995 // ListParser::Step - Move to the next section in the file /*{{{*/
996 // ---------------------------------------------------------------------
997 /* This has to be careful to only process the correct architecture */
998 bool debListParser::Step()
1000 iOffset
= Tags
.Offset();
1001 return Tags
.Step(Section
);
1004 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
1005 // ---------------------------------------------------------------------
1007 unsigned char debListParser::GetPrio(string Str
)
1010 if (GrabWord(Str
,PrioList
,Out
) == false)
1011 Out
= pkgCache::State::Extra
;
1016 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1017 pkgCache::VerIterator
const &Ver
)
1019 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
1021 // status file has no (Download)Size, but all others are fair game
1022 // status file is parsed last, so the first version we encounter is
1023 // probably also the version we have downloaded
1024 unsigned long long const Size
= Section
.FindULL(pkgTagSection::Key::Size
);
1025 if (Size
!= 0 && Ver
->Size
!= 0 && Size
!= Ver
->Size
)
1027 // available everywhere, but easier to check here than to include in VersionHash
1028 unsigned char MultiArch
= ParseMultiArch(false);
1029 if (MultiArch
!= Ver
->MultiArch
)
1031 // for all practical proposes (we can check): same version
1036 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1037 : debListParser(File
), DebFile(DebFile
)
1041 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1042 pkgCache::VerIterator
&Ver
)
1044 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1045 // we use the full file path as a provides so that the file is found
1047 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1052 debListParser::~debListParser() {}