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/macros.h>
37 using APT::StringView
;
39 static const debListParser::WordList PrioList
[] = {
40 {"required",pkgCache::State::Required
},
41 {"important",pkgCache::State::Important
},
42 {"standard",pkgCache::State::Standard
},
43 {"optional",pkgCache::State::Optional
},
44 {"extra",pkgCache::State::Extra
},
47 // ListParser::debListParser - Constructor /*{{{*/
48 // ---------------------------------------------------------------------
49 /* Provide an architecture and only this one and "all" will be accepted
50 in Step(), if no Architecture is given we will accept every arch
51 we would accept in general with checkArchitecture() */
52 debListParser::debListParser(FileFd
*File
) :
53 pkgCacheListParser(), d(NULL
), Tags(File
)
57 // ListParser::Package - Return the package name /*{{{*/
58 // ---------------------------------------------------------------------
59 /* This is to return the name of the package this section describes */
60 string
debListParser::Package() {
61 string Result
= Section
.Find("Package").to_string();
63 // Normalize mixed case package names to lower case, like dpkg does
64 // See Bug#807012 for details
65 std::transform(Result
.begin(), Result
.end(), Result
.begin(), tolower_ascii
);
67 if(unlikely(Result
.empty() == true))
68 _error
->Error("Encountered a section with no Package: header");
72 // ListParser::Architecture - Return the package arch /*{{{*/
73 // ---------------------------------------------------------------------
74 /* This will return the Architecture of the package this section describes */
75 APT::StringView
debListParser::Architecture() {
76 auto const Arch
= Section
.Find("Architecture");
77 return Arch
.empty() ? "none" : Arch
;
80 // ListParser::ArchitectureAll /*{{{*/
81 // ---------------------------------------------------------------------
83 bool debListParser::ArchitectureAll() {
84 return Section
.Find("Architecture") == "all";
87 // ListParser::Version - Return the version string /*{{{*/
88 // ---------------------------------------------------------------------
89 /* This is to return the string describing the version in debian form,
90 epoch:upstream-release. If this returns the blank string then the
91 entry is assumed to only describe package properties */
92 APT::StringView
debListParser::Version()
94 return Section
.Find("Version");
97 unsigned char debListParser::ParseMultiArch(bool const showErrors
) /*{{{*/
100 auto const MultiArch
= Section
.Find("Multi-Arch");
101 if (MultiArch
.empty() == true || MultiArch
== "no")
102 MA
= pkgCache::Version::No
;
103 else if (MultiArch
== "same") {
104 if (ArchitectureAll() == true)
106 if (showErrors
== true)
107 _error
->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
108 Section
.FindS("Package").c_str());
109 MA
= pkgCache::Version::No
;
112 MA
= pkgCache::Version::Same
;
114 else if (MultiArch
== "foreign")
115 MA
= pkgCache::Version::Foreign
;
116 else if (MultiArch
== "allowed")
117 MA
= pkgCache::Version::Allowed
;
120 if (showErrors
== true)
121 _error
->Warning("Unknown Multi-Arch type '%s' for package '%s'",
122 MultiArch
.to_string().c_str(), Section
.FindS("Package").c_str());
123 MA
= pkgCache::Version::No
;
126 if (ArchitectureAll() == true)
127 MA
|= pkgCache::Version::All
;
132 // ListParser::NewVersion - Fill in the version structure /*{{{*/
133 // ---------------------------------------------------------------------
135 bool debListParser::NewVersion(pkgCache::VerIterator
&Ver
)
141 if (Section
.Find("Section",Start
,Stop
) == true)
143 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::SECTION
, Start
, Stop
- Start
);
146 // Parse the source package name
147 pkgCache::GrpIterator G
= Ver
.ParentPkg().Group();
148 Ver
->SourcePkgName
= G
->Name
;
149 Ver
->SourceVerStr
= Ver
->VerStr
;
150 if (Section
.Find("Source",Start
,Stop
) == true)
152 const char * const Space
= (const char * const) memchr(Start
, ' ', Stop
- Start
);
153 pkgCache::VerIterator V
;
157 const char * const Open
= (const char * const) memchr(Space
, '(', Stop
- Space
);
158 if (likely(Open
!= NULL
))
160 const char * const Close
= (const char * const) memchr(Open
, ')', Stop
- Open
);
161 if (likely(Close
!= NULL
))
163 APT::StringView
const version(Open
+ 1, (Close
- Open
) - 1);
164 if (version
!= Ver
.VerStr())
166 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, version
);
167 G
= Ver
.ParentPkg().Group();
168 Ver
->SourceVerStr
= idx
;
175 APT::StringView
const pkgname(Start
, Stop
- Start
);
176 if (pkgname
!= G
.Name())
178 for (pkgCache::PkgIterator P
= G
.PackageList(); P
.end() == false; P
= G
.NextPkg(P
))
180 for (V
= P
.VersionList(); V
.end() == false; ++V
)
182 if (pkgname
== V
.SourcePkgName())
184 Ver
->SourcePkgName
= V
->SourcePkgName
;
188 if (V
.end() == false)
193 map_stringitem_t
const idx
= StoreString(pkgCacheGenerator::PKGNAME
, pkgname
);
194 G
= Ver
.ParentPkg().Group();
195 Ver
->SourcePkgName
= idx
;
200 Ver
->MultiArch
= ParseMultiArch(true);
202 Ver
->Size
= Section
.FindULL("Size");
203 // Unpacked Size (in K)
204 Ver
->InstalledSize
= Section
.FindULL("Installed-Size");
205 Ver
->InstalledSize
*= 1024;
208 if (Section
.Find("Priority",Start
,Stop
) == true)
210 if (GrabWord(StringView(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
211 Ver
->Priority
= pkgCache::State::Extra
;
214 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
216 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
218 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
220 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
222 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
224 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
226 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
228 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
231 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
234 if (ParseProvides(Ver
) == false)
240 // ListParser::AvailableDescriptionLanguages /*{{{*/
241 std::vector
<std::string
> debListParser::AvailableDescriptionLanguages()
243 std::vector
<std::string
> const understood
= APT::Configuration::getLanguages();
244 std::vector
<std::string
> avail
;
245 static constexpr int prefixLen
= 12;
246 static constexpr int avgLanguageLen
= 5;
249 tagname
.reserve(prefixLen
+ avgLanguageLen
);
250 tagname
.assign("Description-");
251 if (Section
.Exists("Description") == true)
253 for (std::vector
<std::string
>::const_iterator lang
= understood
.begin(); lang
!= understood
.end(); ++lang
)
255 tagname
.resize(prefixLen
);
256 tagname
.append(*lang
);
257 if (Section
.Exists(tagname
) == true)
258 avail
.push_back(*lang
);
263 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
264 // ---------------------------------------------------------------------
265 /* This is to return the md5 string to allow the check if it is the right
266 description. If no Description-md5 is found in the section it will be
269 MD5SumValue
debListParser::Description_md5()
271 StringView
const value
= Section
.Find("Description-md5");
272 if (value
.empty() == true)
274 StringView
const desc
= Section
.Find("Description");
276 return MD5SumValue();
279 md5
.Add(desc
.data(), desc
.size());
283 else if (likely(value
.size() == 32))
285 MD5SumValue sumvalue
;
286 if (sumvalue
.Set(value
))
289 _error
->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value
.length(), value
.data());
290 return MD5SumValue();
292 _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data());
293 return MD5SumValue();
296 // ListParser::UsePackage - Update a package structure /*{{{*/
297 // ---------------------------------------------------------------------
298 /* This is called to update the package with any new information
299 that might be found in the section */
300 bool debListParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
301 pkgCache::VerIterator
&Ver
)
303 string
const static myArch
= _config
->Find("APT::Architecture");
304 // Possible values are: "all", "native", "installed" and "none"
305 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
306 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "all");
307 if (essential
== "all" ||
308 (essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()))
309 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
311 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
314 if (strcmp(Pkg
.Name(),"apt") == 0)
316 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
318 Pkg
->Flags
|= pkgCache::Flag::Essential
| pkgCache::Flag::Important
;
320 Pkg
->Flags
|= pkgCache::Flag::Important
;
323 if (ParseStatus(Pkg
,Ver
) == false)
328 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
329 // ---------------------------------------------------------------------
331 unsigned short debListParser::VersionHash()
333 static const StringView Sections
[] ={"Installed-Size",
341 unsigned long Result
= INIT_FCS
;
343 for (StringView I
: Sections
)
347 if (Section
.Find(I
,Start
,End
) == false)
350 /* Strip out any spaces from the text, this undoes dpkgs reformatting
351 of certain fields. dpkg also has the rather interesting notion of
352 reformatting depends operators < -> <= */
354 for (; Start
!= End
&& (J
- S
) < sizeof(S
); ++Start
)
356 if (isspace_ascii(*Start
) != 0)
358 *J
++ = tolower_ascii(*Start
);
360 /* Normalize <= to < and >= to >. This is the wrong way around, but
361 * more efficient that the right way. And since we're only hashing
362 * it does not matter which way we normalize. */
363 if ((*Start
== '<' || *Start
== '>') && Start
[1] == '=') {
368 Result
= AddCRC16(Result
,S
,J
- S
);
374 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
375 // ---------------------------------------------------------------------
376 /* Status lines are of the form,
377 Status: want flag status
378 want = unknown, install, hold, deinstall, purge
380 status = not-installed, config-files, half-installed, unpacked,
381 half-configured, triggers-awaited, triggers-pending, installed
383 bool debListParser::ParseStatus(pkgCache::PkgIterator
&,
384 pkgCache::VerIterator
&)
388 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator
&Pkg
,
389 pkgCache::VerIterator
&Ver
)
393 if (Section
.Find("Status",Start
,Stop
) == false)
396 // UsePackage() is responsible for setting the flag in the default case
397 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
398 if (essential
== true &&
399 Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
402 // Isolate the first word
403 const char *I
= Start
;
404 for(; I
< Stop
&& *I
!= ' '; I
++);
405 if (I
>= Stop
|| *I
!= ' ')
406 return _error
->Error("Malformed Status line");
408 // Process the want field
409 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
410 {"install",pkgCache::State::Install
},
411 {"hold",pkgCache::State::Hold
},
412 {"deinstall",pkgCache::State::DeInstall
},
413 {"purge",pkgCache::State::Purge
},
415 if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
416 return _error
->Error("Malformed 1st word in the Status line");
418 // Isloate the next word
421 for(; I
< Stop
&& *I
!= ' '; I
++);
422 if (I
>= Stop
|| *I
!= ' ')
423 return _error
->Error("Malformed status line, no 2nd word");
425 // Process the flag field
426 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
427 {"reinstreq",pkgCache::State::ReInstReq
},
428 {"hold",pkgCache::State::HoldInst
},
429 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
431 if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
432 return _error
->Error("Malformed 2nd word in the Status line");
434 // Isloate the last word
437 for(; I
< Stop
&& *I
!= ' '; I
++);
439 return _error
->Error("Malformed Status line, no 3rd word");
441 // Process the flag field
442 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
443 {"config-files",pkgCache::State::ConfigFiles
},
444 {"half-installed",pkgCache::State::HalfInstalled
},
445 {"unpacked",pkgCache::State::UnPacked
},
446 {"half-configured",pkgCache::State::HalfConfigured
},
447 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
448 {"triggers-pending",pkgCache::State::TriggersPending
},
449 {"installed",pkgCache::State::Installed
},
451 if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
452 return _error
->Error("Malformed 3rd word in the Status line");
454 /* A Status line marks the package as indicating the current
455 version as well. Only if it is actually installed.. Otherwise
456 the interesting dpkg handling of the status file creates bogus
458 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
459 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
461 if (Ver
.end() == true)
462 _error
->Warning("Encountered status field in a non-version description");
464 Pkg
->CurrentVer
= Ver
.Index();
470 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
472 // Determine the operator
480 Op
= pkgCache::Dep::LessEq
;
487 Op
= pkgCache::Dep::Less
;
491 // < is the same as <= and << is really Cs < for some reason
492 Op
= pkgCache::Dep::LessEq
;
500 Op
= pkgCache::Dep::GreaterEq
;
507 Op
= pkgCache::Dep::Greater
;
511 // > is the same as >= and >> is really Cs > for some reason
512 Op
= pkgCache::Dep::GreaterEq
;
516 Op
= pkgCache::Dep::Equals
;
520 // HACK around bad package definitions
522 Op
= pkgCache::Dep::Equals
;
528 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
529 // ---------------------------------------------------------------------
530 /* This parses the dependency elements out of a standard string in place,
532 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
533 std::string
&Package
,std::string
&Ver
,unsigned int &Op
)
534 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); }
535 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
536 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
537 bool const &ParseArchFlags
)
538 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); }
539 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
540 std::string
&Package
,std::string
&Ver
,unsigned int &Op
,
541 bool const &ParseArchFlags
, bool const &StripMultiArch
)
542 { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); }
543 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
544 string
&Package
,string
&Ver
,
545 unsigned int &Op
, bool const &ParseArchFlags
,
546 bool const &StripMultiArch
,
547 bool const &ParseRestrictionsList
)
549 StringView PackageView
;
552 auto res
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
,
553 (bool) StripMultiArch
, (bool) ParseRestrictionsList
);
554 Package
= PackageView
.to_string();
555 Ver
= VerView
.to_string();
559 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
560 StringView
&Package
,StringView
&Ver
,
561 unsigned int &Op
, bool ParseArchFlags
,
563 bool ParseRestrictionsList
)
565 // Strip off leading space
566 for (;Start
!= Stop
&& isspace_ascii(*Start
) != 0; ++Start
);
568 // Parse off the package name
569 const char *I
= Start
;
570 for (;I
!= Stop
&& isspace_ascii(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
571 *I
!= ',' && *I
!= '|' && *I
!= '[' && *I
!= ']' &&
572 *I
!= '<' && *I
!= '>'; ++I
);
575 if (I
!= Stop
&& *I
== ')')
581 // Stash the package name
582 Package
= StringView(Start
, I
- Start
);
584 // We don't want to confuse library users which can't handle MultiArch
585 if (StripMultiArch
== true) {
586 string
const arch
= _config
->Find("APT::Architecture");
587 size_t const found
= Package
.rfind(':');
588 if (found
!= StringView::npos
&&
589 (Package
.substr(found
) == ":any" ||
590 Package
.substr(found
) == ":native" ||
591 Package
.substr(found
+1) == arch
))
592 Package
= Package
.substr(0,found
);
595 // Skip white space to the '('
596 for (;I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
599 if (I
!= Stop
&& *I
== '(')
602 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0 ; I
++);
605 I
= ConvertRelation(I
,Op
);
608 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
610 I
= (const char*) memchr(I
, ')', Stop
- I
);
611 if (I
== NULL
|| Start
== I
)
614 // Skip trailing whitespace
616 for (; End
> Start
&& isspace_ascii(End
[-1]); End
--);
618 Ver
= StringView(Start
,End
-Start
);
624 Op
= pkgCache::Dep::NoOp
;
628 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
630 if (unlikely(ParseArchFlags
== true))
632 string
const arch
= _config
->Find("APT::Architecture");
633 APT::CacheFilter::PackageArchitectureMatchesSpecification
matchesArch(arch
, false);
635 // Parse an architecture
636 if (I
!= Stop
&& *I
== '[')
640 if (unlikely(I
== Stop
))
645 bool NegArch
= false;
648 // look for whitespace or ending ']'
649 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= ']'; ++End
);
651 if (unlikely(End
== Stop
))
660 std::string
const arch(I
, End
);
661 if (arch
.empty() == false && matchesArch(arch
.c_str()) == true)
666 // we found a match, so fast-forward to the end of the wildcards
667 for (; End
!= Stop
&& *End
!= ']'; ++End
);
676 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
683 Package
= ""; /* not for this arch */
687 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
690 if (unlikely(ParseRestrictionsList
== true))
692 // Parse a restrictions formula which is in disjunctive normal form:
693 // (foo AND bar) OR (blub AND bla)
695 std::vector
<string
> const profiles
= APT::Configuration::getBuildProfiles();
697 // if the next character is a restriction list, then by default the
698 // dependency does not apply and the conditions have to be checked
699 // if the next character is not a restriction list, then by default the
700 // dependency applies
701 bool applies1
= (*I
!= '<');
709 if (unlikely(I
== Stop
))
714 // if of the prior restriction list is already fulfilled, then
715 // we can just skip to the end of the current list
717 for (;End
!= Stop
&& *End
!= '>'; ++End
);
720 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
722 bool applies2
= true;
723 // all the conditions inside a restriction list have to be
724 // met so once we find one that is not met, we can skip to
725 // the end of this list
728 // look for whitespace or ending '>'
729 // End now points to the character after the current term
730 for (;End
!= Stop
&& !isspace_ascii(*End
) && *End
!= '>'; ++End
);
732 if (unlikely(End
== Stop
))
735 bool NegRestriction
= false;
738 NegRestriction
= true;
742 std::string
const restriction(I
, End
);
743 if (restriction
.empty() == false && profiles
.empty() == false &&
744 std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end())
746 if (NegRestriction
) {
748 // since one of the terms does not apply we don't have to check the others
749 for (; End
!= Stop
&& *End
!= '>'; ++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
);
762 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
768 for (;I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
776 if (applies1
== false) {
777 Package
= ""; //not for this restriction
781 if (I
!= Stop
&& *I
== '|')
782 Op
|= pkgCache::Dep::Or
;
784 if (I
== Stop
|| *I
== ',' || *I
== '|')
787 for (I
++; I
!= Stop
&& isspace_ascii(*I
) != 0; I
++);
794 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
795 // ---------------------------------------------------------------------
796 /* This is the higher level depends parser. It takes a tag and generates
797 a complete depends tree for the given version. */
798 bool debListParser::ParseDepends(pkgCache::VerIterator
&Ver
,
799 StringView Tag
,unsigned int Type
)
803 if (Section
.Find(Tag
,Start
,Stop
) == false || Start
== Stop
)
806 string
const pkgArch
= Ver
.Arch();
814 Start
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false);
816 return _error
->Error("Problem parsing dependency %.*s",(int)Tag
.length(), Tag
.data());
817 size_t const found
= Package
.rfind(':');
819 if (found
== string::npos
)
821 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
824 else if (Package
.substr(found
) == ":any")
826 if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false)
831 // Such dependencies are not supposed to be accepted …
832 // … but this is probably the best thing to do anyway
833 if (Package
.substr(found
+ 1) == "native")
835 std::string
const Pkg
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch();
836 if (NewDepends(Ver
, Pkg
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
839 else if (NewDepends(Ver
, Package
, "any", Version
, Op
| pkgCache::Dep::ArchSpecific
, Type
) == false)
849 // ListParser::ParseProvides - Parse the provides list /*{{{*/
850 // ---------------------------------------------------------------------
852 bool debListParser::ParseProvides(pkgCache::VerIterator
&Ver
)
854 /* it is unlikely, but while parsing dependencies, we might have already
855 picked up multi-arch implicit provides which we do not want to duplicate here */
856 bool hasProvidesAlready
= false;
857 std::string
const spzName
= Ver
.ParentPkg().FullName(false);
859 for (pkgCache::PrvIterator Prv
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
)
861 if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags
& pkgCache::Flag::ArchSpecific
) == 0)
863 if (spzName
!= Prv
.OwnerPkg().FullName(false))
865 hasProvidesAlready
= true;
870 string
const Arch
= Ver
.Arch();
873 if (Section
.Find("Provides",Start
,Stop
) == true)
881 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false);
882 const size_t archfound
= Package
.rfind(':');
884 return _error
->Error("Problem parsing Provides line");
885 if (unlikely(Op
!= pkgCache::Dep::NoOp
&& Op
!= pkgCache::Dep::Equals
)) {
886 _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str());
887 } else if (archfound
!= string::npos
) {
888 StringView spzArch
= Package
.substr(archfound
+ 1);
889 if (spzArch
!= "any")
891 if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
894 if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false)
896 } else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) {
897 if (APT::Configuration::checkArchitecture(Arch
))
899 if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false)
902 else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
905 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
907 if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false)
910 if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false)
913 if (archfound
== std::string::npos
)
915 string spzName
= Package
.to_string();
916 spzName
.push_back(':');
917 spzName
.append(Ver
.ParentPkg().Arch());
918 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
919 if (spzPkg
.end() == false)
921 if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
925 } while (Start
!= Stop
);
928 if (APT::Configuration::checkArchitecture(Arch
))
930 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
)
932 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
933 if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
936 else if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
938 if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false)
943 if (hasProvidesAlready
== false)
945 pkgCache::PkgIterator
const spzPkg
= Ver
.Cache()->FindPkg(spzName
, "any");
946 if (spzPkg
.end() == false)
948 if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
955 // ListParser::GrabWord - Matches a word and returns /*{{{*/
956 // ---------------------------------------------------------------------
957 /* Looks for a word in a list of words - for ParseStatus */
958 bool debListParser::GrabWord(StringView Word
, WordList
const *List
, unsigned char &Out
)
960 for (unsigned int C
= 0; List
[C
].Str
.empty() == false; C
++)
962 if (Word
.length() == List
[C
].Str
.length() &&
963 strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0)
972 // ListParser::Step - Move to the next section in the file /*{{{*/
973 // ---------------------------------------------------------------------
974 /* This has to be careful to only process the correct architecture */
975 bool debListParser::Step()
977 iOffset
= Tags
.Offset();
978 return Tags
.Step(Section
);
981 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
982 // ---------------------------------------------------------------------
984 unsigned char debListParser::GetPrio(string Str
)
987 if (GrabWord(Str
,PrioList
,Out
) == false)
988 Out
= pkgCache::State::Extra
;
993 bool debListParser::SameVersion(unsigned short const Hash
, /*{{{*/
994 pkgCache::VerIterator
const &Ver
)
996 if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false)
998 // status file has no (Download)Size, but all others are fair game
999 // status file is parsed last, so the first version we encounter is
1000 // probably also the version we have downloaded
1001 unsigned long long const Size
= Section
.FindULL("Size");
1002 if (Size
!= 0 && Ver
->Size
!= 0 && Size
!= Ver
->Size
)
1004 // available everywhere, but easier to check here than to include in VersionHash
1005 unsigned char MultiArch
= ParseMultiArch(false);
1006 if (MultiArch
!= Ver
->MultiArch
)
1008 // for all practical proposes (we can check): same version
1013 debDebFileParser::debDebFileParser(FileFd
*File
, std::string
const &DebFile
)
1014 : debListParser(File
), DebFile(DebFile
)
1018 bool debDebFileParser::UsePackage(pkgCache::PkgIterator
&Pkg
,
1019 pkgCache::VerIterator
&Ver
)
1021 bool res
= debListParser::UsePackage(Pkg
, Ver
);
1022 // we use the full file path as a provides so that the file is found
1024 if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false)
1029 debListParser::~debListParser() {}