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
;
356 for (auto I
: Sections
)
360 if (Section
.Find(I
,Start
,End
) == false)
363 /* Strip out any spaces from the text, this undoes dpkgs reformatting
364 of certain fields. dpkg also has the rather interesting notion of
365 reformatting depends operators < -> <=, so we drop all = from the
366 string to make that not matter. */
367 for (; Start
!= End
; ++Start
)
369 if (isspace_ascii(*Start
) != 0 || *Start
== '=')
371 Result
= AddCRC16Byte(Result
, tolower_ascii_unsafe(*Start
));
380 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
381 // ---------------------------------------------------------------------
382 /* Status lines are of the form,
383 Status: want flag status
384 want = unknown, install, hold, deinstall, purge
386 status = not-installed, config-files, half-installed, unpacked,
387 half-configured, triggers-awaited, triggers-pending, installed
389 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
390 pkgCache::VerIterator
&)
394 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
395 pkgCache::VerIterator
&Ver
)
399 if (Section
.Find(pkgTagSection::Key::Status
,Start
,Stop
) == false)
402 // UsePackage() is responsible for setting the flag in the default case
403 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
404 if (essential
== true &&
405 Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
408 // Isolate the first word
409 const char *I
= Start
;
410 for(; I
< Stop
&& *I
!= ' '; I
++);
411 if (I
>= Stop
|| *I
!= ' ')
412 return _error
->Error("Malformed Status line");
414 // Process the want field
415 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
416 {"install",pkgCache::State::Install
},
417 {"hold",pkgCache::State::Hold
},
418 {"deinstall",pkgCache::State::DeInstall
},
419 {"purge",pkgCache::State::Purge
},
421 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
422 return _error
->Error("Malformed 1st word in the Status line");
424 // Isloate the next word
427 for(; I
< Stop
&& *I
!= ' '; I
++);
428 if (I
>= Stop
|| *I
!= ' ')
429 return _error
->Error("Malformed status line, no 2nd word");
431 // Process the flag field
432 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
433 {"reinstreq",pkgCache::State::ReInstReq
},
434 {"hold",pkgCache::State::HoldInst
},
435 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
437 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
438 return _error
->Error("Malformed 2nd word in the Status line");
440 // Isloate the last word
443 for(; I
< Stop
&& *I
!= ' '; I
++);
445 return _error
->Error("Malformed Status line, no 3rd word");
447 // Process the flag field
448 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
449 {"config-files",pkgCache::State::ConfigFiles
},
450 {"half-installed",pkgCache::State::HalfInstalled
},
451 {"unpacked",pkgCache::State::UnPacked
},
452 {"half-configured",pkgCache::State::HalfConfigured
},
453 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
454 {"triggers-pending",pkgCache::State::TriggersPending
},
455 {"installed",pkgCache::State::Installed
},
457 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
458 return _error
->Error("Malformed 3rd word in the Status line");
460 /* A Status line marks the package as indicating the current
461 version as well. Only if it is actually installed.. Otherwise
462 the interesting dpkg handling of the status file creates bogus
464 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
465 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
467 if (Ver
.end() == true)
468 _error
->Warning("Encountered status field in a non-version description");
470 Pkg
->CurrentVer
= Ver
.Index();
476 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
478 // Determine the operator
486 Op
= pkgCache::Dep::LessEq
;
493 Op
= pkgCache::Dep::Less
;
497 // < is the same as <= and << is really Cs < for some reason
498 Op
= pkgCache::Dep::LessEq
;
506 Op
= pkgCache::Dep::GreaterEq
;
513 Op
= pkgCache::Dep::Greater
;
517 // > is the same as >= and >> is really Cs > for some reason
518 Op
= pkgCache::Dep::GreaterEq
;
522 Op
= pkgCache::Dep::Equals
;
526 // HACK around bad package definitions
528 Op
= pkgCache::Dep::Equals
;
534 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
535 // ---------------------------------------------------------------------
536 /* This parses the dependency elements out of a standard string in place,
538 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
539 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
540 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
541 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
542 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
543 bool const &ParseArchFlags
)
544 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
545 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
546 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
547 bool const &ParseArchFlags
, bool const &StripMultiArch
)
548 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
549 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
550 string
&Package
,string
&Ver
,
551 unsigned int &Op
, bool const &ParseArchFlags
,
552 bool const &StripMultiArch
,
553 bool const &ParseRestrictionsList
)
555 StringView PackageView
;
558 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
559 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
560 Package
= PackageView
.to_string();
561 Ver
= VerView
.to_string();
565 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
566 StringView
&Package
,StringView
&Ver
,
567 unsigned int &Op
, bool ParseArchFlags
,
569 bool ParseRestrictionsList
)
571 // Strip off leading space
572 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
574 // Parse off the package name
575 const char *I
= Start
;
576 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
577 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
578 *I
!= '<' && *I
!= '>'; ++I
);
581 if (I
!= Stop
&& *I
== ')')
587 // Stash the package name
588 Package
= StringView(Start
, I
- Start
);
590 // We don't want to confuse library users which can't handle MultiArch
591 if (StripMultiArch
== true) {
592 string
const arch
= _config
->Find("APT::Architecture");
593 size_t const found
= Package
.rfind(':');
594 if (found
!= StringView::npos
&&
595 (Package
.substr(found
) == ":any" ||
596 Package
.substr(found
) == ":native" ||
597 Package
.substr(found
+1) == arch
))
598 Package
= Package
.substr(0,found
);
601 // Skip white space to the '('
602 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
605 if (I
!= Stop
&& *I
== '(')
608 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
611 I
= ConvertRelation(I
,Op
);
614 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
616 I
= (const char*) memchr(I
, ')', Stop
- I
);
617 if (I
== NULL
|| Start
== I
)
620 // Skip trailing whitespace
622 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
624 Ver
= StringView(Start
,End
-Start
);
630 Op
= pkgCache::Dep::NoOp
;
634 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
636 if (unlikely(ParseArchFlags
== true))
638 string
const arch
= _config
->Find("APT::Architecture");
639 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
641 // Parse an architecture
642 if (I
!= Stop
&& *I
== '[')
646 if (unlikely(I
== Stop
))
651 bool NegArch
= false;
654 // look for whitespace or ending ']'
655 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
657 if (unlikely(End
== Stop
))
666 std::string
const arch(I
, End
);
667 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
672 // we found a match, so fast-forward to the end of the wildcards
673 for (; End
!= Stop
&& *End
!= ']'; ++End
);
682 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
689 Package
= ""; /* not for this arch */
693 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
696 if (unlikely(ParseRestrictionsList
== true))
698 // Parse a restrictions formula which is in disjunctive normal form:
699 // (foo AND bar) OR (blub AND bla)
701 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
703 // if the next character is a restriction list, then by default the
704 // dependency does not apply and the conditions have to be checked
705 // if the next character is not a restriction list, then by default the
706 // dependency applies
707 bool applies1
= (*I
!= '<');
715 if (unlikely(I
== Stop
))
720 // if of the prior restriction list is already fulfilled, then
721 // we can just skip to the end of the current list
723 for (;End
!= Stop
&& *End
!= '>'; ++End
);
726 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
728 bool applies2
= true;
729 // all the conditions inside a restriction list have to be
730 // met so once we find one that is not met, we can skip to
731 // the end of this list
734 // look for whitespace or ending '>'
735 // End now points to the character after the current term
736 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
738 if (unlikely(End
== Stop
))
741 bool NegRestriction
= false;
744 NegRestriction
= true;
748 std::string
const restriction(I
, End
);
749 if (restriction
.empty() == false && profiles
.empty() == false &&
750 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
752 if (NegRestriction
) {
754 // since one of the terms does not apply we don't have to check the others
755 for (; End
!= Stop
&& *End
!= '>'; ++End
);
758 if (!NegRestriction
) {
760 // since one of the terms does not apply we don't have to check the others
761 for (; End
!= Stop
&& *End
!= '>'; ++End
);
768 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
774 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
782 if (applies1
== false) {
783 Package
= ""; //not for this restriction
787 if (I
!= Stop
&& *I
== '|')
788 Op
|= pkgCache::Dep::Or
;
790 if (I
== Stop
|| *I
== ',' || *I
== '|')
793 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
800 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
801 // ---------------------------------------------------------------------
802 /* This is the higher level depends parser. It takes a tag and generates
803 a complete depends tree for the given version. */
804 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
805 pkgTagSection::Key Key
,unsigned int Type
)
809 if (Section
.Find(Key
,Start
,Stop
) == false || Start
== Stop
)
812 string
const pkgArch
= Ver
.Arch();
820 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
822 return _error
->Error("Problem parsing dependency %zu",static_cast<size_t>(Key
)); // TODO
823 size_t const found
= Package
.rfind(':');
825 if (found
== string::npos
)
827 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
830 else if (Package
.substr(found
) == ":any")
832 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
837 // Such dependencies are not supposed to be accepted …
838 // … but this is probably the best thing to do anyway
839 if (Package
.substr(found
+ 1) == "native")
841 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
842 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
845 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
855 // ListParser::ParseProvides - Parse the provides list /*{{{*/
856 // ---------------------------------------------------------------------
858 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
860 /* it is unlikely, but while parsing dependencies, we might have already
861 picked up multi-arch implicit provides which we do not want to duplicate here */
862 bool hasProvidesAlready
= false;
863 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
865 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
867 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
869 if (spzName
!= Prv
.OwnerPkg().FullName(false))
871 hasProvidesAlready
= true;
876 string
const Arch
= Ver
.Arch();
879 if (Section
.Find(pkgTagSection::Key::Provides
,Start
,Stop
) == true)
887 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
888 const size_t archfound
= Package
.rfind(':');
890 return _error
->Error("Problem parsing Provides line");
891 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
892 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
893 } else if (archfound
!= string::npos
) {
894 StringView spzArch
= Package
.substr(archfound
+ 1);
895 if (spzArch
!= "any")
897 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
900 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
902 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
903 if (APT::Configuration::checkArchitecture(Arch
))
905 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
908 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
911 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
913 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
916 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
919 if (archfound
== std::string::npos
)
921 string spzName
= Package
.to_string();
922 spzName
.push_back(':');
923 spzName
.append(Ver
.ParentPkg().Arch());
924 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
925 if (spzPkg
.end() == false)
927 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
931 } while (Start
!= Stop
);
934 if (APT::Configuration::checkArchitecture(Arch
))
936 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
938 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
939 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
942 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
944 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
949 if (hasProvidesAlready
== false)
951 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
952 if (spzPkg
.end() == false)
954 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
961 // ListParser::GrabWord - Matches a word and returns /*{{{*/
962 // ---------------------------------------------------------------------
963 /* Looks for a word in a list of words - for ParseStatus */
964 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
966 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
968 if (Word
.length() == List
[C
].Str
.length() &&
969 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
978 // ListParser::Step - Move to the next section in the file /*{{{*/
979 // ---------------------------------------------------------------------
980 /* This has to be careful to only process the correct architecture */
981 bool debListParser::Step()
983 iOffset
= Tags
.Offset();
984 return Tags
.Step(Section
);
987 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
988 // ---------------------------------------------------------------------
990 unsigned char debListParser::GetPrio(string Str
)
993 if (GrabWord(Str
,PrioList
,Out
) == false)
994 Out
= pkgCache::State::Extra
;
999 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1000 pkgCache::VerIterator
const &Ver
)
1002 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
1004 // status file has no (Download)Size, but all others are fair game
1005 // status file is parsed last, so the first version we encounter is
1006 // probably also the version we have downloaded
1007 unsigned long long const Size
= Section
.FindULL(pkgTagSection::Key::Size
);
1008 if (Size
!= 0 && Ver
->Size
!= 0 && Size
!= Ver
->Size
)
1010 // available everywhere, but easier to check here than to include in VersionHash
1011 unsigned char MultiArch
= ParseMultiArch(false);
1012 if (MultiArch
!= Ver
->MultiArch
)
1014 // for all practical proposes (we can check): same version
1019 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1020 : debListParser(File
), DebFile(DebFile
)
1024 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1025 pkgCache::VerIterator
&Ver
)
1027 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1028 // we use the full file path as a provides so that the file is found
1030 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1035 debListParser::~debListParser() {}