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
)
151 if (Section
.Find("Name",Start
,Stop
) == true)
153 Ver
->Display
= WriteString(Start
, Stop
- Start
);
155 else if (Section
.Find("Maemo-Display-Name",Start
,Stop
) == true)
157 Ver
->Display
= WriteString(Start
, Stop
- Start
);
161 if (Section
.Find(pkgTagSection::Key::Section
,Start
,Stop
) == true)
163 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::SECTION
, Start
, Stop
- Start
);
166 // Parse the source package name
167 pkgCache::GrpIterator G
= Ver
.ParentPkg().Group();
168 Ver
->SourcePkgName
= G
->Name
;
169 Ver
->SourceVerStr
= Ver
->VerStr
;
170 if (Section
.Find(pkgTagSection::Key::Source
,Start
,Stop
) == true)
172 const char * const Space
= (const char * const) memchr(Start
, ' ', Stop
- Start
);
173 pkgCache::VerIterator V
;
177 const char * const Open
= (const char * const) memchr(Space
, '(', Stop
- Space
);
178 if (likely(Open
!= NULL
))
180 const char * const Close
= (const char * const) memchr(Open
, ')', Stop
- Open
);
181 if (likely(Close
!= NULL
))
183 APT::StringView
const version(Open
+ 1, (Close
- Open
) - 1);
184 if (version
!= Ver
.VerStr())
186 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, version
);
187 G
= Ver
.ParentPkg().Group();
188 Ver
->SourceVerStr
= idx
;
195 APT::StringView
const pkgname(Start
, Stop
- Start
);
196 if (pkgname
!= G
.Name())
198 for (pkgCache::PkgIterator P
= G
.PackageList(); P
.end() == false; P
= G
.NextPkg(P
))
200 for (V
= P
.VersionList(); V
.end() == false; ++V
)
202 if (pkgname
== V
.SourcePkgName())
204 Ver
->SourcePkgName
= V
->SourcePkgName
;
208 if (V
.end() == false)
213 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::PKGNAME
, pkgname
);
214 G
= Ver
.ParentPkg().Group();
215 Ver
->SourcePkgName
= idx
;
220 Ver
->MultiArch
= ParseMultiArch(true);
222 Ver
->Size
= Section
.FindULL(pkgTagSection::Key::Size
);
223 // Unpacked Size (in K)
224 Ver
->InstalledSize
= Section
.FindULL(pkgTagSection::Key::Installed_Size
);
225 Ver
->InstalledSize
*= 1024;
228 if (Section
.Find(pkgTagSection::Key::Priority
,Start
,Stop
) == true)
230 if (GrabWord(StringView(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
231 Ver
->Priority
= pkgCache::State::Extra
;
234 if (ParseDepends(Ver
,pkgTagSection::Key::Pre_Depends
,pkgCache::Dep::PreDepends
) == false)
236 if (ParseDepends(Ver
,pkgTagSection::Key::Depends
,pkgCache::Dep::Depends
) == false)
238 if (ParseDepends(Ver
,pkgTagSection::Key::Conflicts
,pkgCache::Dep::Conflicts
) == false)
240 if (ParseDepends(Ver
,pkgTagSection::Key::Breaks
,pkgCache::Dep::DpkgBreaks
) == false)
242 if (ParseDepends(Ver
,pkgTagSection::Key::Recommends
,pkgCache::Dep::Recommends
) == false)
244 if (ParseDepends(Ver
,pkgTagSection::Key::Suggests
,pkgCache::Dep::Suggests
) == false)
246 if (ParseDepends(Ver
,pkgTagSection::Key::Replaces
,pkgCache::Dep::Replaces
) == false)
248 if (ParseDepends(Ver
,pkgTagSection::Key::Enhances
,pkgCache::Dep::Enhances
) == false)
251 if (ParseDepends(Ver
,pkgTagSection::Key::Optional
,pkgCache::Dep::Suggests
) == false)
254 if (ParseProvides(Ver
) == false)
256 if (ParseTag(Ver
) == false)
262 // ListParser::AvailableDescriptionLanguages /*{{{*/
263 std::vector
<std::string
> debListParser::AvailableDescriptionLanguages()
265 std::vector
<std::string
> const understood
= APT::Configuration::getLanguages();
266 std::vector
<std::string
> avail
;
267 static constexpr int prefixLen
= 12;
268 char buf
[32] = "Description-";
269 if (Section
.Exists("Description") == true)
271 for (std::vector
<std::string
>::const_iterator lang
= understood
.begin(); lang
!= understood
.end(); ++lang
)
273 if (unlikely(lang
->size() > sizeof(buf
) - prefixLen
)) {
274 _error
->Warning("Ignoring translated description %s", lang
->c_str());
277 memcpy(buf
+ prefixLen
, lang
->c_str(), lang
->size());
278 if (Section
.Exists(StringView(buf
, prefixLen
+ lang
->size())) == true)
279 avail
.push_back(*lang
);
284 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
285 // ---------------------------------------------------------------------
286 /* This is to return the md5 string to allow the check if it is the right
287 description. If no Description-md5 is found in the section it will be
290 APT::StringView
debListParser::Description_md5()
292 StringView
const value
= Section
.Find(pkgTagSection::Key::Description_md5
);
293 if (unlikely(value
.empty() == true))
295 StringView
const desc
= Section
.Find(pkgTagSection::Key::Description
);
300 md5
.Add(desc
.data(), desc
.size());
302 MD5Buffer
= md5
.Result();
303 return StringView(MD5Buffer
);
305 else if (likely(value
.size() == 32))
309 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
313 // ListParser::UsePackage - Update a package structure /*{{{*/
314 // ---------------------------------------------------------------------
315 /* This is called to update the package with any new information
316 that might be found in the section */
317 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
318 pkgCache::VerIterator
&Ver
)
320 string
const static myArch
= _config
->Find("APT::Architecture");
321 // Possible values are: "all", "native", "installed" and "none"
322 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
323 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
324 if (essential
== "all" ||
325 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
326 if (Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
328 if (Section
.FindFlag(pkgTagSection::Key::Important
,Pkg
->Flags
,pkgCache::Flag::Important
) == false)
331 if (std::find(forceEssential
.begin(), forceEssential
.end(), Pkg
.Name()) != forceEssential
.end())
333 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
335 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
337 Pkg
->Flags
|= pkgCache::Flag::Important
;
339 else if (std::find(forceImportant
.begin(), forceImportant
.end(), Pkg
.Name()) != forceImportant
.end())
340 Pkg
->Flags
|= pkgCache::Flag::Important
;
342 if (ParseStatus(Pkg
,Ver
) == false)
347 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
348 // ---------------------------------------------------------------------
350 unsigned short debListParser::VersionHash()
352 static constexpr pkgTagSection::Key Sections
[] ={
353 pkgTagSection::Key::Installed_Size
,
354 pkgTagSection::Key::Depends
,
355 pkgTagSection::Key::Pre_Depends
,
356 // pkgTagSection::Key::Suggests,
357 // pkgTagSection::Key::Recommends",
358 pkgTagSection::Key::Conflicts
,
359 pkgTagSection::Key::Breaks
,
360 pkgTagSection::Key::Replaces
};
361 unsigned long Result
= INIT_FCS
;
362 for (auto I
: Sections
)
366 if (Section
.Find(I
,Start
,End
) == false)
369 /* Strip out any spaces from the text, this undoes dpkgs reformatting
370 of certain fields. dpkg also has the rather interesting notion of
371 reformatting depends operators < -> <=, so we drop all = from the
372 string to make that not matter. */
373 for (; Start
!= End
; ++Start
)
375 if (isspace_ascii(*Start
) != 0 || *Start
== '=')
377 Result
= AddCRC16Byte(Result
, tolower_ascii_unsafe(*Start
));
386 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
387 // ---------------------------------------------------------------------
388 /* Status lines are of the form,
389 Status: want flag status
390 want = unknown, install, hold, deinstall, purge
392 status = not-installed, config-files, half-installed, unpacked,
393 half-configured, triggers-awaited, triggers-pending, installed
395 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
396 pkgCache::VerIterator
&)
400 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
401 pkgCache::VerIterator
&Ver
)
405 if (Section
.Find(pkgTagSection::Key::Status
,Start
,Stop
) == false)
408 // UsePackage() is responsible for setting the flag in the default case
409 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
410 if (essential
== true &&
411 Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
414 // Isolate the first word
415 const char *I
= Start
;
416 for(; I
< Stop
&& *I
!= ' '; I
++);
417 if (I
>= Stop
|| *I
!= ' ')
418 return _error
->Error("Malformed Status line");
420 // Process the want field
421 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
422 {"install",pkgCache::State::Install
},
423 {"hold",pkgCache::State::Hold
},
424 {"deinstall",pkgCache::State::DeInstall
},
425 {"purge",pkgCache::State::Purge
},
427 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
428 return _error
->Error("Malformed 1st word in the Status line");
430 // Isloate the next word
433 for(; I
< Stop
&& *I
!= ' '; I
++);
434 if (I
>= Stop
|| *I
!= ' ')
435 return _error
->Error("Malformed status line, no 2nd word");
437 // Process the flag field
438 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
439 {"reinstreq",pkgCache::State::ReInstReq
},
440 {"hold",pkgCache::State::HoldInst
},
441 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
443 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
444 return _error
->Error("Malformed 2nd word in the Status line");
446 // Isloate the last word
449 for(; I
< Stop
&& *I
!= ' '; I
++);
451 return _error
->Error("Malformed Status line, no 3rd word");
453 // Process the flag field
454 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
455 {"config-files",pkgCache::State::ConfigFiles
},
456 {"half-installed",pkgCache::State::HalfInstalled
},
457 {"unpacked",pkgCache::State::UnPacked
},
458 {"half-configured",pkgCache::State::HalfConfigured
},
459 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
460 {"triggers-pending",pkgCache::State::TriggersPending
},
461 {"installed",pkgCache::State::Installed
},
463 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
464 return _error
->Error("Malformed 3rd word in the Status line");
466 /* A Status line marks the package as indicating the current
467 version as well. Only if it is actually installed.. Otherwise
468 the interesting dpkg handling of the status file creates bogus
470 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
471 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
473 if (Ver
.end() == true)
474 _error
->Warning("Encountered status field in a non-version description");
476 Pkg
->CurrentVer
= Ver
.Index();
482 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
484 // Determine the operator
492 Op
= pkgCache::Dep::LessEq
;
499 Op
= pkgCache::Dep::Less
;
503 // < is the same as <= and << is really Cs < for some reason
504 Op
= pkgCache::Dep::LessEq
;
512 Op
= pkgCache::Dep::GreaterEq
;
519 Op
= pkgCache::Dep::Greater
;
523 // > is the same as >= and >> is really Cs > for some reason
524 Op
= pkgCache::Dep::GreaterEq
;
528 Op
= pkgCache::Dep::Equals
;
532 // HACK around bad package definitions
534 Op
= pkgCache::Dep::Equals
;
540 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
541 // ---------------------------------------------------------------------
542 /* This parses the dependency elements out of a standard string in place,
544 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
545 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
546 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
547 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
548 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
549 bool const &ParseArchFlags
)
550 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
551 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
552 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
553 bool const &ParseArchFlags
, bool const &StripMultiArch
)
554 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
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
)
561 StringView PackageView
;
564 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
565 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
566 Package
= PackageView
.to_string();
567 Ver
= VerView
.to_string();
571 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
572 StringView
&Package
,StringView
&Ver
,
573 unsigned int &Op
, bool ParseArchFlags
,
575 bool ParseRestrictionsList
)
577 // Strip off leading space
578 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
580 // Parse off the package name
581 const char *I
= Start
;
582 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
583 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
584 *I
!= '<' && *I
!= '>'; ++I
);
587 if (I
!= Stop
&& *I
== ')')
593 // Stash the package name
594 Package
= StringView(Start
, I
- Start
);
596 // We don't want to confuse library users which can't handle MultiArch
597 if (StripMultiArch
== true) {
598 string
const arch
= _config
->Find("APT::Architecture");
599 size_t const found
= Package
.rfind(':');
600 if (found
!= StringView::npos
&&
601 (Package
.substr(found
) == ":any" ||
602 Package
.substr(found
) == ":native" ||
603 Package
.substr(found
+1) == arch
))
604 Package
= Package
.substr(0,found
);
607 // Skip white space to the '('
608 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
611 if (I
!= Stop
&& *I
== '(')
614 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
617 I
= ConvertRelation(I
,Op
);
620 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
622 I
= (const char*) memchr(I
, ')', Stop
- I
);
623 if (I
== NULL
|| Start
== I
)
626 // Skip trailing whitespace
628 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
630 Ver
= StringView(Start
,End
-Start
);
636 Op
= pkgCache::Dep::NoOp
;
640 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
642 if (unlikely(ParseArchFlags
== true))
644 string
const arch
= _config
->Find("APT::Architecture");
645 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
647 // Parse an architecture
648 if (I
!= Stop
&& *I
== '[')
652 if (unlikely(I
== Stop
))
657 bool NegArch
= false;
660 // look for whitespace or ending ']'
661 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
663 if (unlikely(End
== Stop
))
672 std::string
const arch(I
, End
);
673 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
678 // we found a match, so fast-forward to the end of the wildcards
679 for (; End
!= Stop
&& *End
!= ']'; ++End
);
688 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
695 Package
= ""; /* not for this arch */
699 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
702 if (unlikely(ParseRestrictionsList
== true))
704 // Parse a restrictions formula which is in disjunctive normal form:
705 // (foo AND bar) OR (blub AND bla)
707 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
709 // if the next character is a restriction list, then by default the
710 // dependency does not apply and the conditions have to be checked
711 // if the next character is not a restriction list, then by default the
712 // dependency applies
713 bool applies1
= (*I
!= '<');
721 if (unlikely(I
== Stop
))
726 // if of the prior restriction list is already fulfilled, then
727 // we can just skip to the end of the current list
729 for (;End
!= Stop
&& *End
!= '>'; ++End
);
732 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
734 bool applies2
= true;
735 // all the conditions inside a restriction list have to be
736 // met so once we find one that is not met, we can skip to
737 // the end of this list
740 // look for whitespace or ending '>'
741 // End now points to the character after the current term
742 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
744 if (unlikely(End
== Stop
))
747 bool NegRestriction
= false;
750 NegRestriction
= true;
754 std::string
const restriction(I
, End
);
755 if (restriction
.empty() == false && profiles
.empty() == false &&
756 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.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
);
764 if (!NegRestriction
) {
766 // since one of the terms does not apply we don't have to check the others
767 for (; End
!= Stop
&& *End
!= '>'; ++End
);
774 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
780 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
788 if (applies1
== false) {
789 Package
= ""; //not for this restriction
793 if (I
!= Stop
&& *I
== '|')
794 Op
|= pkgCache::Dep::Or
;
796 if (I
== Stop
|| *I
== ',' || *I
== '|')
799 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
806 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
807 // ---------------------------------------------------------------------
808 /* This is the higher level depends parser. It takes a tag and generates
809 a complete depends tree for the given version. */
810 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
811 pkgTagSection::Key Key
,unsigned int Type
)
815 if (Section
.Find(Key
,Start
,Stop
) == false || Start
== Stop
)
818 string
const pkgArch
= Ver
.Arch();
826 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
828 return _error
->Error("Problem parsing dependency %zu",static_cast<size_t>(Key
)); // TODO
829 size_t const found
= Package
.rfind(':');
831 if (found
== string::npos
)
833 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
836 else if (Package
.substr(found
) == ":any")
838 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
843 // Such dependencies are not supposed to be accepted …
844 // … but this is probably the best thing to do anyway
845 if (Package
.substr(found
+ 1) == "native")
847 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
848 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
851 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
861 // ListParser::ParseProvides - Parse the provides list /*{{{*/
862 // ---------------------------------------------------------------------
864 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
866 /* it is unlikely, but while parsing dependencies, we might have already
867 picked up multi-arch implicit provides which we do not want to duplicate here */
868 bool hasProvidesAlready
= false;
869 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
871 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
873 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
875 if (spzName
!= Prv
.OwnerPkg().FullName(false))
877 hasProvidesAlready
= true;
882 string
const Arch
= Ver
.Arch();
885 if (Section
.Find(pkgTagSection::Key::Provides
,Start
,Stop
) == true)
893 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
894 const size_t archfound
= Package
.rfind(':');
896 return _error
->Error("Problem parsing Provides line");
897 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
898 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
899 } else if (archfound
!= string::npos
) {
900 StringView spzArch
= Package
.substr(archfound
+ 1);
901 if (spzArch
!= "any")
903 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
906 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
908 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
909 if (APT::Configuration::checkArchitecture(Arch
))
911 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
914 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
917 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
919 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
922 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
925 if (archfound
== std::string::npos
)
927 string spzName
= Package
.to_string();
928 spzName
.push_back(':');
929 spzName
.append(Ver
.ParentPkg().Arch());
930 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
931 if (spzPkg
.end() == false)
933 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
937 } while (Start
!= Stop
);
940 if (APT::Configuration::checkArchitecture(Arch
))
942 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
944 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
945 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
948 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
950 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
955 if (hasProvidesAlready
== false)
957 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
958 if (spzPkg
.end() == false)
960 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
967 // ListParser::ParseTag - Parse the tag list /*{{{*/
968 // ---------------------------------------------------------------------
970 bool debListParser::ParseTag(pkgCache::VerIterator
&Ver
)
974 if (Section
.Find("Tag",Start
,Stop
) == false)
981 if (Stop
[-1] != ' ' && Stop
[-1] != '\t')
986 const char *Begin
= Stop
- 1;
987 while (Begin
!= Start
&& Begin
[-1] != ' ' && Begin
[-1] != ',')
990 if (NewTag(Ver
, Begin
, Stop
- Begin
) == false)
996 if (Begin
[-1] == ',')
1007 // ListParser::GrabWord - Matches a word and returns /*{{{*/
1008 // ---------------------------------------------------------------------
1009 /* Looks for a word in a list of words - for ParseStatus */
1010 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
1012 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
1014 if (Word
.length() == List
[C
].Str
.length() &&
1015 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
1024 // ListParser::Step - Move to the next section in the file /*{{{*/
1025 // ---------------------------------------------------------------------
1026 /* This has to be careful to only process the correct architecture */
1027 bool debListParser::Step()
1029 iOffset
= Tags
.Offset();
1030 return Tags
.Step(Section
);
1033 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
1034 // ---------------------------------------------------------------------
1036 unsigned char debListParser::GetPrio(string Str
)
1039 if (GrabWord(Str
,PrioList
,Out
) == false)
1040 Out
= pkgCache::State::Extra
;
1045 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1046 pkgCache::VerIterator
const &Ver
)
1048 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
1050 // status file has no (Download)Size, but all others are fair game
1051 // status file is parsed last, so the first version we encounter is
1052 // probably also the version we have downloaded
1053 unsigned long long const Size
= Section
.FindULL(pkgTagSection::Key::Size
);
1054 if (Size
!= 0 && Ver
->Size
!= 0 && Size
!= Ver
->Size
)
1056 // available everywhere, but easier to check here than to include in VersionHash
1057 unsigned char MultiArch
= ParseMultiArch(false);
1058 if (MultiArch
!= Ver
->MultiArch
)
1060 // for all practical proposes (we can check): same version
1065 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1066 : debListParser(File
), DebFile(DebFile
)
1070 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1071 pkgCache::VerIterator
&Ver
)
1073 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1074 // we use the full file path as a provides so that the file is found
1076 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1081 debListParser::~debListParser() {}