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 MD5SumValue
debListParser::Description_md5()
281 StringView
const value
= Section
.Find(pkgTagSection::Key::Description_md5
);
282 if (value
.empty() == true)
284 StringView
const desc
= Section
.Find(pkgTagSection::Key::Description
);
286 return MD5SumValue();
289 md5
.Add(desc
.data(), desc
.size());
293 else if (likely(value
.size() == 32))
295 MD5SumValue sumvalue
;
296 if (sumvalue
.Set(value
))
299 _error
->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value
.length(), value
.data());
300 return MD5SumValue();
302 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
303 return MD5SumValue();
306 // ListParser::UsePackage - Update a package structure /*{{{*/
307 // ---------------------------------------------------------------------
308 /* This is called to update the package with any new information
309 that might be found in the section */
310 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
311 pkgCache::VerIterator
&Ver
)
313 string
const static myArch
= _config
->Find("APT::Architecture");
314 // Possible values are: "all", "native", "installed" and "none"
315 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
316 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
317 if (essential
== "all" ||
318 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
319 if (Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
321 if (Section
.FindFlag(pkgTagSection::Key::Important
,Pkg
->Flags
,pkgCache::Flag::Important
) == false)
324 if (std::find(forceEssential
.begin(), forceEssential
.end(), Pkg
.Name()) != forceEssential
.end())
326 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
328 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
330 Pkg
->Flags
|= pkgCache::Flag::Important
;
332 else if (std::find(forceImportant
.begin(), forceImportant
.end(), Pkg
.Name()) != forceImportant
.end())
333 Pkg
->Flags
|= pkgCache::Flag::Important
;
335 if (ParseStatus(Pkg
,Ver
) == false)
340 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
341 // ---------------------------------------------------------------------
343 unsigned short debListParser::VersionHash()
345 static constexpr pkgTagSection::Key Sections
[] ={
346 pkgTagSection::Key::Installed_Size
,
347 pkgTagSection::Key::Depends
,
348 pkgTagSection::Key::Pre_Depends
,
349 // pkgTagSection::Key::Suggests,
350 // pkgTagSection::Key::Recommends",
351 pkgTagSection::Key::Conflicts
,
352 pkgTagSection::Key::Breaks
,
353 pkgTagSection::Key::Replaces
};
354 unsigned long Result
= INIT_FCS
;
355 for (auto I
: Sections
)
359 if (Section
.Find(I
,Start
,End
) == false)
362 /* Strip out any spaces from the text, this undoes dpkgs reformatting
363 of certain fields. dpkg also has the rather interesting notion of
364 reformatting depends operators < -> <=, so we drop all = from the
365 string to make that not matter. */
366 for (; Start
!= End
; ++Start
)
368 if (isspace_ascii(*Start
) != 0 || *Start
== '=')
370 Result
= AddCRC16Byte(Result
, tolower_ascii_unsafe(*Start
));
379 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
380 // ---------------------------------------------------------------------
381 /* Status lines are of the form,
382 Status: want flag status
383 want = unknown, install, hold, deinstall, purge
385 status = not-installed, config-files, half-installed, unpacked,
386 half-configured, triggers-awaited, triggers-pending, installed
388 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
389 pkgCache::VerIterator
&)
393 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
394 pkgCache::VerIterator
&Ver
)
398 if (Section
.Find(pkgTagSection::Key::Status
,Start
,Stop
) == false)
401 // UsePackage() is responsible for setting the flag in the default case
402 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
403 if (essential
== true &&
404 Section
.FindFlag(pkgTagSection::Key::Essential
,Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
407 // Isolate the first word
408 const char *I
= Start
;
409 for(; I
< Stop
&& *I
!= ' '; I
++);
410 if (I
>= Stop
|| *I
!= ' ')
411 return _error
->Error("Malformed Status line");
413 // Process the want field
414 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
415 {"install",pkgCache::State::Install
},
416 {"hold",pkgCache::State::Hold
},
417 {"deinstall",pkgCache::State::DeInstall
},
418 {"purge",pkgCache::State::Purge
},
420 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
421 return _error
->Error("Malformed 1st word in the Status line");
423 // Isloate the next word
426 for(; I
< Stop
&& *I
!= ' '; I
++);
427 if (I
>= Stop
|| *I
!= ' ')
428 return _error
->Error("Malformed status line, no 2nd word");
430 // Process the flag field
431 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
432 {"reinstreq",pkgCache::State::ReInstReq
},
433 {"hold",pkgCache::State::HoldInst
},
434 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
436 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
437 return _error
->Error("Malformed 2nd word in the Status line");
439 // Isloate the last word
442 for(; I
< Stop
&& *I
!= ' '; I
++);
444 return _error
->Error("Malformed Status line, no 3rd word");
446 // Process the flag field
447 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
448 {"config-files",pkgCache::State::ConfigFiles
},
449 {"half-installed",pkgCache::State::HalfInstalled
},
450 {"unpacked",pkgCache::State::UnPacked
},
451 {"half-configured",pkgCache::State::HalfConfigured
},
452 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
453 {"triggers-pending",pkgCache::State::TriggersPending
},
454 {"installed",pkgCache::State::Installed
},
456 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
457 return _error
->Error("Malformed 3rd word in the Status line");
459 /* A Status line marks the package as indicating the current
460 version as well. Only if it is actually installed.. Otherwise
461 the interesting dpkg handling of the status file creates bogus
463 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
464 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
466 if (Ver
.end() == true)
467 _error
->Warning("Encountered status field in a non-version description");
469 Pkg
->CurrentVer
= Ver
.Index();
475 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
477 // Determine the operator
485 Op
= pkgCache::Dep::LessEq
;
492 Op
= pkgCache::Dep::Less
;
496 // < is the same as <= and << is really Cs < for some reason
497 Op
= pkgCache::Dep::LessEq
;
505 Op
= pkgCache::Dep::GreaterEq
;
512 Op
= pkgCache::Dep::Greater
;
516 // > is the same as >= and >> is really Cs > for some reason
517 Op
= pkgCache::Dep::GreaterEq
;
521 Op
= pkgCache::Dep::Equals
;
525 // HACK around bad package definitions
527 Op
= pkgCache::Dep::Equals
;
533 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
534 // ---------------------------------------------------------------------
535 /* This parses the dependency elements out of a standard string in place,
537 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
538 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
539 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, 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
)
543 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
544 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
545 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
546 bool const &ParseArchFlags
, bool const &StripMultiArch
)
547 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
548 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
549 string
&Package
,string
&Ver
,
550 unsigned int &Op
, bool const &ParseArchFlags
,
551 bool const &StripMultiArch
,
552 bool const &ParseRestrictionsList
)
554 StringView PackageView
;
557 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
558 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
559 Package
= PackageView
.to_string();
560 Ver
= VerView
.to_string();
564 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
565 StringView
&Package
,StringView
&Ver
,
566 unsigned int &Op
, bool ParseArchFlags
,
568 bool ParseRestrictionsList
)
570 // Strip off leading space
571 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
573 // Parse off the package name
574 const char *I
= Start
;
575 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
576 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
577 *I
!= '<' && *I
!= '>'; ++I
);
580 if (I
!= Stop
&& *I
== ')')
586 // Stash the package name
587 Package
= StringView(Start
, I
- Start
);
589 // We don't want to confuse library users which can't handle MultiArch
590 if (StripMultiArch
== true) {
591 string
const arch
= _config
->Find("APT::Architecture");
592 size_t const found
= Package
.rfind(':');
593 if (found
!= StringView::npos
&&
594 (Package
.substr(found
) == ":any" ||
595 Package
.substr(found
) == ":native" ||
596 Package
.substr(found
+1) == arch
))
597 Package
= Package
.substr(0,found
);
600 // Skip white space to the '('
601 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
604 if (I
!= Stop
&& *I
== '(')
607 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
610 I
= ConvertRelation(I
,Op
);
613 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
615 I
= (const char*) memchr(I
, ')', Stop
- I
);
616 if (I
== NULL
|| Start
== I
)
619 // Skip trailing whitespace
621 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
623 Ver
= StringView(Start
,End
-Start
);
629 Op
= pkgCache::Dep::NoOp
;
633 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
635 if (unlikely(ParseArchFlags
== true))
637 string
const arch
= _config
->Find("APT::Architecture");
638 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
640 // Parse an architecture
641 if (I
!= Stop
&& *I
== '[')
645 if (unlikely(I
== Stop
))
650 bool NegArch
= false;
653 // look for whitespace or ending ']'
654 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
656 if (unlikely(End
== Stop
))
665 std::string
const arch(I
, End
);
666 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
671 // we found a match, so fast-forward to the end of the wildcards
672 for (; End
!= Stop
&& *End
!= ']'; ++End
);
681 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
688 Package
= ""; /* not for this arch */
692 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
695 if (unlikely(ParseRestrictionsList
== true))
697 // Parse a restrictions formula which is in disjunctive normal form:
698 // (foo AND bar) OR (blub AND bla)
700 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
702 // if the next character is a restriction list, then by default the
703 // dependency does not apply and the conditions have to be checked
704 // if the next character is not a restriction list, then by default the
705 // dependency applies
706 bool applies1
= (*I
!= '<');
714 if (unlikely(I
== Stop
))
719 // if of the prior restriction list is already fulfilled, then
720 // we can just skip to the end of the current list
722 for (;End
!= Stop
&& *End
!= '>'; ++End
);
725 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
727 bool applies2
= true;
728 // all the conditions inside a restriction list have to be
729 // met so once we find one that is not met, we can skip to
730 // the end of this list
733 // look for whitespace or ending '>'
734 // End now points to the character after the current term
735 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
737 if (unlikely(End
== Stop
))
740 bool NegRestriction
= false;
743 NegRestriction
= true;
747 std::string
const restriction(I
, End
);
748 if (restriction
.empty() == false && profiles
.empty() == false &&
749 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
751 if (NegRestriction
) {
753 // since one of the terms does not apply we don't have to check the others
754 for (; End
!= Stop
&& *End
!= '>'; ++End
);
757 if (!NegRestriction
) {
759 // since one of the terms does not apply we don't have to check the others
760 for (; End
!= Stop
&& *End
!= '>'; ++End
);
767 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
773 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
781 if (applies1
== false) {
782 Package
= ""; //not for this restriction
786 if (I
!= Stop
&& *I
== '|')
787 Op
|= pkgCache::Dep::Or
;
789 if (I
== Stop
|| *I
== ',' || *I
== '|')
792 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
799 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
800 // ---------------------------------------------------------------------
801 /* This is the higher level depends parser. It takes a tag and generates
802 a complete depends tree for the given version. */
803 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
804 pkgTagSection::Key Key
,unsigned int Type
)
808 if (Section
.Find(Key
,Start
,Stop
) == false || Start
== Stop
)
811 string
const pkgArch
= Ver
.Arch();
819 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
821 return _error
->Error("Problem parsing dependency %zu",static_cast<size_t>(Key
)); // TODO
822 size_t const found
= Package
.rfind(':');
824 if (found
== string::npos
)
826 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
829 else if (Package
.substr(found
) == ":any")
831 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
836 // Such dependencies are not supposed to be accepted …
837 // … but this is probably the best thing to do anyway
838 if (Package
.substr(found
+ 1) == "native")
840 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
841 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
844 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
854 // ListParser::ParseProvides - Parse the provides list /*{{{*/
855 // ---------------------------------------------------------------------
857 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
859 /* it is unlikely, but while parsing dependencies, we might have already
860 picked up multi-arch implicit provides which we do not want to duplicate here */
861 bool hasProvidesAlready
= false;
862 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
864 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
866 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
868 if (spzName
!= Prv
.OwnerPkg().FullName(false))
870 hasProvidesAlready
= true;
875 string
const Arch
= Ver
.Arch();
878 if (Section
.Find(pkgTagSection::Key::Provides
,Start
,Stop
) == true)
886 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
887 const size_t archfound
= Package
.rfind(':');
889 return _error
->Error("Problem parsing Provides line");
890 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
891 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
892 } else if (archfound
!= string::npos
) {
893 StringView spzArch
= Package
.substr(archfound
+ 1);
894 if (spzArch
!= "any")
896 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
899 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
901 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
902 if (APT::Configuration::checkArchitecture(Arch
))
904 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
907 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
910 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
912 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
915 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
918 if (archfound
== std::string::npos
)
920 string spzName
= Package
.to_string();
921 spzName
.push_back(':');
922 spzName
.append(Ver
.ParentPkg().Arch());
923 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
924 if (spzPkg
.end() == false)
926 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
930 } while (Start
!= Stop
);
933 if (APT::Configuration::checkArchitecture(Arch
))
935 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
937 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
938 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
941 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
943 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
948 if (hasProvidesAlready
== false)
950 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
951 if (spzPkg
.end() == false)
953 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
960 // ListParser::GrabWord - Matches a word and returns /*{{{*/
961 // ---------------------------------------------------------------------
962 /* Looks for a word in a list of words - for ParseStatus */
963 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
965 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
967 if (Word
.length() == List
[C
].Str
.length() &&
968 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
977 // ListParser::Step - Move to the next section in the file /*{{{*/
978 // ---------------------------------------------------------------------
979 /* This has to be careful to only process the correct architecture */
980 bool debListParser::Step()
982 iOffset
= Tags
.Offset();
983 return Tags
.Step(Section
);
986 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
987 // ---------------------------------------------------------------------
989 unsigned char debListParser::GetPrio(string Str
)
992 if (GrabWord(Str
,PrioList
,Out
) == false)
993 Out
= pkgCache::State::Extra
;
998 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
999 pkgCache::VerIterator
const &Ver
)
1001 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
1003 // status file has no (Download)Size, but all others are fair game
1004 // status file is parsed last, so the first version we encounter is
1005 // probably also the version we have downloaded
1006 unsigned long long const Size
= Section
.FindULL(pkgTagSection::Key::Size
);
1007 if (Size
!= 0 && Ver
->Size
!= 0 && Size
!= Ver
->Size
)
1009 // available everywhere, but easier to check here than to include in VersionHash
1010 unsigned char MultiArch
= ParseMultiArch(false);
1011 if (MultiArch
!= Ver
->MultiArch
)
1013 // for all practical proposes (we can check): same version
1018 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1019 : debListParser(File
), DebFile(DebFile
)
1023 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1024 pkgCache::VerIterator
&Ver
)
1026 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1027 // we use the full file path as a provides so that the file is found
1029 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1034 debListParser::~debListParser() {}