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 static constexpr int avgLanguageLen
= 5;
260 tagname
.reserve(prefixLen
+ avgLanguageLen
);
261 tagname
.assign("Description-");
262 if (Section
.Exists("Description") == true)
264 for (std::vector
<std::string
>::const_iterator lang
= understood
.begin(); lang
!= understood
.end(); ++lang
)
266 tagname
.resize(prefixLen
);
267 tagname
.append(*lang
);
268 if (Section
.Exists(tagname
) == true)
269 avail
.push_back(*lang
);
274 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
275 // ---------------------------------------------------------------------
276 /* This is to return the md5 string to allow the check if it is the right
277 description. If no Description-md5 is found in the section it will be
280 MD5SumValue
debListParser::Description_md5()
282 StringView
const value
= Section
.Find(pkgTagSection::Key::Description_md5
);
283 if (value
.empty() == true)
285 StringView
const desc
= Section
.Find(pkgTagSection::Key::Description
);
287 return MD5SumValue();
290 md5
.Add(desc
.data(), desc
.size());
294 else if (likely(value
.size() == 32))
296 MD5SumValue sumvalue
;
297 if (sumvalue
.Set(value
))
300 _error
->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value
.length(), value
.data());
301 return MD5SumValue();
303 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
304 return MD5SumValue();
307 // ListParser::UsePackage - Update a package structure /*{{{*/
308 // ---------------------------------------------------------------------
309 /* This is called to update the package with any new information
310 that might be found in the section */
311 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
312 pkgCache::VerIterator
&Ver
)
314 string
const static myArch
= _config
->Find("APT::Architecture");
315 // Possible values are: "all", "native", "installed" and "none"
316 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
317 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
318 if (essential
== "all" ||
319 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
320 if (Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
322 if (Section
.FindFlag(pkgTagSection::Key::Important
,Pkg
->Flags
,pkgCache::Flag::Important
) == false)
325 if (std::find(forceEssential
.begin(), forceEssential
.end(), Pkg
.Name()) != forceEssential
.end())
327 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
329 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
331 Pkg
->Flags
|= pkgCache::Flag::Important
;
333 else if (std::find(forceImportant
.begin(), forceImportant
.end(), Pkg
.Name()) != forceImportant
.end())
334 Pkg
->Flags
|= pkgCache::Flag::Important
;
336 if (ParseStatus(Pkg
,Ver
) == false)
341 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
342 // ---------------------------------------------------------------------
344 unsigned short debListParser::VersionHash()
346 static constexpr pkgTagSection::Key Sections
[] ={
347 pkgTagSection::Key::Installed_Size
,
348 pkgTagSection::Key::Depends
,
349 pkgTagSection::Key::Pre_Depends
,
350 // pkgTagSection::Key::Suggests,
351 // pkgTagSection::Key::Recommends",
352 pkgTagSection::Key::Conflicts
,
353 pkgTagSection::Key::Breaks
,
354 pkgTagSection::Key::Replaces
};
355 unsigned long Result
= INIT_FCS
;
357 for (auto I
: Sections
)
361 if (Section
.Find(I
,Start
,End
) == false)
364 /* Strip out any spaces from the text, this undoes dpkgs reformatting
365 of certain fields. dpkg also has the rather interesting notion of
366 reformatting depends operators < -> <= */
368 for (; Start
!= End
&& (J
- S
) < sizeof(S
); ++Start
)
370 if (isspace_ascii(*Start
) != 0)
372 *J
++ = tolower_ascii_unsafe(*Start
);
374 /* Normalize <= to < and >= to >. This is the wrong way around, but
375 * more efficient that the right way. And since we're only hashing
376 * it does not matter which way we normalize. */
377 if ((*Start
== '<' || *Start
== '>') && Start
[1] == '=') {
382 Result
= AddCRC16(Result
,S
,J
- S
);
388 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
389 // ---------------------------------------------------------------------
390 /* Status lines are of the form,
391 Status: want flag status
392 want = unknown, install, hold, deinstall, purge
394 status = not-installed, config-files, half-installed, unpacked,
395 half-configured, triggers-awaited, triggers-pending, installed
397 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
398 pkgCache::VerIterator
&)
402 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
403 pkgCache::VerIterator
&Ver
)
407 if (Section
.Find(pkgTagSection::Key::Status
,Start
,Stop
) == false)
410 // UsePackage() is responsible for setting the flag in the default case
411 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
412 if (essential
== true &&
413 Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
416 // Isolate the first word
417 const char *I
= Start
;
418 for(; I
< Stop
&& *I
!= ' '; I
++);
419 if (I
>= Stop
|| *I
!= ' ')
420 return _error
->Error("Malformed Status line");
422 // Process the want field
423 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
424 {"install",pkgCache::State::Install
},
425 {"hold",pkgCache::State::Hold
},
426 {"deinstall",pkgCache::State::DeInstall
},
427 {"purge",pkgCache::State::Purge
},
429 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
430 return _error
->Error("Malformed 1st word in the Status line");
432 // Isloate the next word
435 for(; I
< Stop
&& *I
!= ' '; I
++);
436 if (I
>= Stop
|| *I
!= ' ')
437 return _error
->Error("Malformed status line, no 2nd word");
439 // Process the flag field
440 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
441 {"reinstreq",pkgCache::State::ReInstReq
},
442 {"hold",pkgCache::State::HoldInst
},
443 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
445 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
446 return _error
->Error("Malformed 2nd word in the Status line");
448 // Isloate the last word
451 for(; I
< Stop
&& *I
!= ' '; I
++);
453 return _error
->Error("Malformed Status line, no 3rd word");
455 // Process the flag field
456 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
457 {"config-files",pkgCache::State::ConfigFiles
},
458 {"half-installed",pkgCache::State::HalfInstalled
},
459 {"unpacked",pkgCache::State::UnPacked
},
460 {"half-configured",pkgCache::State::HalfConfigured
},
461 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
462 {"triggers-pending",pkgCache::State::TriggersPending
},
463 {"installed",pkgCache::State::Installed
},
465 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
466 return _error
->Error("Malformed 3rd word in the Status line");
468 /* A Status line marks the package as indicating the current
469 version as well. Only if it is actually installed.. Otherwise
470 the interesting dpkg handling of the status file creates bogus
472 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
473 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
475 if (Ver
.end() == true)
476 _error
->Warning("Encountered status field in a non-version description");
478 Pkg
->CurrentVer
= Ver
.Index();
484 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
486 // Determine the operator
494 Op
= pkgCache::Dep::LessEq
;
501 Op
= pkgCache::Dep::Less
;
505 // < is the same as <= and << is really Cs < for some reason
506 Op
= pkgCache::Dep::LessEq
;
514 Op
= pkgCache::Dep::GreaterEq
;
521 Op
= pkgCache::Dep::Greater
;
525 // > is the same as >= and >> is really Cs > for some reason
526 Op
= pkgCache::Dep::GreaterEq
;
530 Op
= pkgCache::Dep::Equals
;
534 // HACK around bad package definitions
536 Op
= pkgCache::Dep::Equals
;
542 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
543 // ---------------------------------------------------------------------
544 /* This parses the dependency elements out of a standard string in place,
546 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
547 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
548 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
549 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
550 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
551 bool const &ParseArchFlags
)
552 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
553 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
554 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
555 bool const &ParseArchFlags
, bool const &StripMultiArch
)
556 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
557 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
558 string
&Package
,string
&Ver
,
559 unsigned int &Op
, bool const &ParseArchFlags
,
560 bool const &StripMultiArch
,
561 bool const &ParseRestrictionsList
)
563 StringView PackageView
;
566 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
567 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
568 Package
= PackageView
.to_string();
569 Ver
= VerView
.to_string();
573 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
574 StringView
&Package
,StringView
&Ver
,
575 unsigned int &Op
, bool ParseArchFlags
,
577 bool ParseRestrictionsList
)
579 // Strip off leading space
580 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
582 // Parse off the package name
583 const char *I
= Start
;
584 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
585 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
586 *I
!= '<' && *I
!= '>'; ++I
);
589 if (I
!= Stop
&& *I
== ')')
595 // Stash the package name
596 Package
= StringView(Start
, I
- Start
);
598 // We don't want to confuse library users which can't handle MultiArch
599 if (StripMultiArch
== true) {
600 string
const arch
= _config
->Find("APT::Architecture");
601 size_t const found
= Package
.rfind(':');
602 if (found
!= StringView::npos
&&
603 (Package
.substr(found
) == ":any" ||
604 Package
.substr(found
) == ":native" ||
605 Package
.substr(found
+1) == arch
))
606 Package
= Package
.substr(0,found
);
609 // Skip white space to the '('
610 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
613 if (I
!= Stop
&& *I
== '(')
616 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
619 I
= ConvertRelation(I
,Op
);
622 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
624 I
= (const char*) memchr(I
, ')', Stop
- I
);
625 if (I
== NULL
|| Start
== I
)
628 // Skip trailing whitespace
630 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
632 Ver
= StringView(Start
,End
-Start
);
638 Op
= pkgCache::Dep::NoOp
;
642 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
644 if (unlikely(ParseArchFlags
== true))
646 string
const arch
= _config
->Find("APT::Architecture");
647 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
649 // Parse an architecture
650 if (I
!= Stop
&& *I
== '[')
654 if (unlikely(I
== Stop
))
659 bool NegArch
= false;
662 // look for whitespace or ending ']'
663 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
665 if (unlikely(End
== Stop
))
674 std::string
const arch(I
, End
);
675 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
680 // we found a match, so fast-forward to the end of the wildcards
681 for (; End
!= Stop
&& *End
!= ']'; ++End
);
690 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
697 Package
= ""; /* not for this arch */
701 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
704 if (unlikely(ParseRestrictionsList
== true))
706 // Parse a restrictions formula which is in disjunctive normal form:
707 // (foo AND bar) OR (blub AND bla)
709 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
711 // if the next character is a restriction list, then by default the
712 // dependency does not apply and the conditions have to be checked
713 // if the next character is not a restriction list, then by default the
714 // dependency applies
715 bool applies1
= (*I
!= '<');
723 if (unlikely(I
== Stop
))
728 // if of the prior restriction list is already fulfilled, then
729 // we can just skip to the end of the current list
731 for (;End
!= Stop
&& *End
!= '>'; ++End
);
734 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
736 bool applies2
= true;
737 // all the conditions inside a restriction list have to be
738 // met so once we find one that is not met, we can skip to
739 // the end of this list
742 // look for whitespace or ending '>'
743 // End now points to the character after the current term
744 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
746 if (unlikely(End
== Stop
))
749 bool NegRestriction
= false;
752 NegRestriction
= true;
756 std::string
const restriction(I
, End
);
757 if (restriction
.empty() == false && profiles
.empty() == false &&
758 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
760 if (NegRestriction
) {
762 // since one of the terms does not apply we don't have to check the others
763 for (; End
!= Stop
&& *End
!= '>'; ++End
);
766 if (!NegRestriction
) {
768 // since one of the terms does not apply we don't have to check the others
769 for (; End
!= Stop
&& *End
!= '>'; ++End
);
776 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
782 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
790 if (applies1
== false) {
791 Package
= ""; //not for this restriction
795 if (I
!= Stop
&& *I
== '|')
796 Op
|= pkgCache::Dep::Or
;
798 if (I
== Stop
|| *I
== ',' || *I
== '|')
801 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
808 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
809 // ---------------------------------------------------------------------
810 /* This is the higher level depends parser. It takes a tag and generates
811 a complete depends tree for the given version. */
812 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
813 pkgTagSection::Key Key
,unsigned int Type
)
817 if (Section
.Find(Key
,Start
,Stop
) == false || Start
== Stop
)
820 string
const pkgArch
= Ver
.Arch();
828 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
830 return _error
->Error("Problem parsing dependency %zu",static_cast<size_t>(Key
)); // TODO
831 size_t const found
= Package
.rfind(':');
833 if (found
== string::npos
)
835 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
838 else if (Package
.substr(found
) == ":any")
840 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
845 // Such dependencies are not supposed to be accepted …
846 // … but this is probably the best thing to do anyway
847 if (Package
.substr(found
+ 1) == "native")
849 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
850 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
853 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
863 // ListParser::ParseProvides - Parse the provides list /*{{{*/
864 // ---------------------------------------------------------------------
866 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
868 /* it is unlikely, but while parsing dependencies, we might have already
869 picked up multi-arch implicit provides which we do not want to duplicate here */
870 bool hasProvidesAlready
= false;
871 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
873 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
875 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
877 if (spzName
!= Prv
.OwnerPkg().FullName(false))
879 hasProvidesAlready
= true;
884 string
const Arch
= Ver
.Arch();
887 if (Section
.Find(pkgTagSection::Key::Provides
,Start
,Stop
) == true)
895 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
896 const size_t archfound
= Package
.rfind(':');
898 return _error
->Error("Problem parsing Provides line");
899 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
900 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
901 } else if (archfound
!= string::npos
) {
902 StringView spzArch
= Package
.substr(archfound
+ 1);
903 if (spzArch
!= "any")
905 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
908 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
910 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
911 if (APT::Configuration::checkArchitecture(Arch
))
913 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
916 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
919 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
921 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
924 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
927 if (archfound
== std::string::npos
)
929 string spzName
= Package
.to_string();
930 spzName
.push_back(':');
931 spzName
.append(Ver
.ParentPkg().Arch());
932 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
933 if (spzPkg
.end() == false)
935 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
939 } while (Start
!= Stop
);
942 if (APT::Configuration::checkArchitecture(Arch
))
944 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
946 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
947 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
950 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
952 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
957 if (hasProvidesAlready
== false)
959 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
960 if (spzPkg
.end() == false)
962 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
969 // ListParser::GrabWord - Matches a word and returns /*{{{*/
970 // ---------------------------------------------------------------------
971 /* Looks for a word in a list of words - for ParseStatus */
972 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
974 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
976 if (Word
.length() == List
[C
].Str
.length() &&
977 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
986 // ListParser::Step - Move to the next section in the file /*{{{*/
987 // ---------------------------------------------------------------------
988 /* This has to be careful to only process the correct architecture */
989 bool debListParser::Step()
991 iOffset
= Tags
.Offset();
992 return Tags
.Step(Section
);
995 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
996 // ---------------------------------------------------------------------
998 unsigned char debListParser::GetPrio(string Str
)
1001 if (GrabWord(Str
,PrioList
,Out
) == false)
1002 Out
= pkgCache::State::Extra
;
1007 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1008 pkgCache::VerIterator
const &Ver
)
1010 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
1012 // status file has no (Download)Size, but all others are fair game
1013 // status file is parsed last, so the first version we encounter is
1014 // probably also the version we have downloaded
1015 unsigned long long const Size
= Section
.FindULL(pkgTagSection::Key::Size
);
1016 if (Size
!= 0 && Ver
->Size
!= 0 && Size
!= Ver
->Size
)
1018 // available everywhere, but easier to check here than to include in VersionHash
1019 unsigned char MultiArch
= ParseMultiArch(false);
1020 if (MultiArch
!= Ver
->MultiArch
)
1022 // for all practical proposes (we can check): same version
1027 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1028 : debListParser(File
), DebFile(DebFile
)
1032 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1033 pkgCache::VerIterator
&Ver
)
1035 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1036 // we use the full file path as a provides so that the file is found
1038 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1043 debListParser::~debListParser() {}