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 || End 
- Start 
>= (signed)sizeof(S
)) 
 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
; ++Start
) 
 356          if (isspace_ascii(*Start
) != 0) 
 358          *J
++ = tolower_ascii(*Start
); 
 360          if ((*Start 
== '<' || *Start 
== '>') && Start
[1] != *Start 
&& Start
[1] != '=') 
 364       Result 
= AddCRC16(Result
,S
,J 
- S
); 
 370 // StatusListParser::ParseStatus - Parse the status field               /*{{{*/ 
 371 // --------------------------------------------------------------------- 
 372 /* Status lines are of the form, 
 373      Status: want flag status 
 374    want = unknown, install, hold, deinstall, purge 
 376    status = not-installed, config-files, half-installed, unpacked, 
 377             half-configured, triggers-awaited, triggers-pending, installed 
 379 bool debListParser::ParseStatus(pkgCache::PkgIterator 
&, 
 380                                 pkgCache::VerIterator 
&) 
 384 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator 
&Pkg
, 
 385                                 pkgCache::VerIterator 
&Ver
) 
 389    if (Section
.Find("Status",Start
,Stop
) == false) 
 392    // UsePackage() is responsible for setting the flag in the default case 
 393    bool const static essential 
= _config
->Find("pkgCacheGen::Essential", "") == "installed"; 
 394    if (essential 
== true && 
 395        Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false) 
 398    // Isolate the first word 
 399    const char *I 
= Start
; 
 400    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 401    if (I 
>= Stop 
|| *I 
!= ' ') 
 402       return _error
->Error("Malformed Status line"); 
 404    // Process the want field 
 405    WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
}, 
 406                           {"install",pkgCache::State::Install
}, 
 407                           {"hold",pkgCache::State::Hold
}, 
 408                           {"deinstall",pkgCache::State::DeInstall
}, 
 409                           {"purge",pkgCache::State::Purge
}, 
 411    if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false) 
 412       return _error
->Error("Malformed 1st word in the Status line"); 
 414    // Isloate the next word 
 417    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 418    if (I 
>= Stop 
|| *I 
!= ' ') 
 419       return _error
->Error("Malformed status line, no 2nd word"); 
 421    // Process the flag field 
 422    WordList FlagList
[] = {{"ok",pkgCache::State::Ok
}, 
 423                           {"reinstreq",pkgCache::State::ReInstReq
}, 
 424                           {"hold",pkgCache::State::HoldInst
}, 
 425                           {"hold-reinstreq",pkgCache::State::HoldReInstReq
}, 
 427    if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false) 
 428       return _error
->Error("Malformed 2nd word in the Status line"); 
 430    // Isloate the last word 
 433    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 435       return _error
->Error("Malformed Status line, no 3rd word"); 
 437    // Process the flag field 
 438    WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
}, 
 439                             {"config-files",pkgCache::State::ConfigFiles
}, 
 440                             {"half-installed",pkgCache::State::HalfInstalled
}, 
 441                             {"unpacked",pkgCache::State::UnPacked
}, 
 442                             {"half-configured",pkgCache::State::HalfConfigured
}, 
 443                             {"triggers-awaited",pkgCache::State::TriggersAwaited
}, 
 444                             {"triggers-pending",pkgCache::State::TriggersPending
}, 
 445                             {"installed",pkgCache::State::Installed
}, 
 447    if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false) 
 448       return _error
->Error("Malformed 3rd word in the Status line"); 
 450    /* A Status line marks the package as indicating the current 
 451       version as well. Only if it is actually installed.. Otherwise 
 452       the interesting dpkg handling of the status file creates bogus  
 454    if (!(Pkg
->CurrentState 
== pkgCache::State::NotInstalled 
|| 
 455          Pkg
->CurrentState 
== pkgCache::State::ConfigFiles
)) 
 457       if (Ver
.end() == true) 
 458          _error
->Warning("Encountered status field in a non-version description"); 
 460          Pkg
->CurrentVer 
= Ver
.Index(); 
 466 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
) 
 468    // Determine the operator 
 476          Op 
= pkgCache::Dep::LessEq
; 
 483          Op 
= pkgCache::Dep::Less
; 
 487       // < is the same as <= and << is really Cs < for some reason 
 488       Op 
= pkgCache::Dep::LessEq
; 
 496          Op 
= pkgCache::Dep::GreaterEq
; 
 503          Op 
= pkgCache::Dep::Greater
; 
 507       // > is the same as >= and >> is really Cs > for some reason 
 508       Op 
= pkgCache::Dep::GreaterEq
; 
 512       Op 
= pkgCache::Dep::Equals
; 
 516       // HACK around bad package definitions 
 518       Op 
= pkgCache::Dep::Equals
; 
 524 // ListParser::ParseDepends - Parse a dependency element                /*{{{*/ 
 525 // --------------------------------------------------------------------- 
 526 /* This parses the dependency elements out of a standard string in place, 
 528 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 529                std::string 
&Package
,std::string 
&Ver
,unsigned int &Op
) 
 530    { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); } 
 531 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 532                std::string 
&Package
,std::string 
&Ver
,unsigned int &Op
, 
 533                bool const &ParseArchFlags
) 
 534    { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, 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
, bool const &StripMultiArch
) 
 538    { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); } 
 539 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 540                                         string 
&Package
,string 
&Ver
, 
 541                                         unsigned int &Op
, bool const &ParseArchFlags
, 
 542                                         bool const &StripMultiArch
, 
 543                                         bool const &ParseRestrictionsList
) 
 545    StringView PackageView
; 
 548    auto res 
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
, 
 549    (bool) StripMultiArch
, (bool) ParseRestrictionsList
); 
 550    Package 
= PackageView
.to_string(); 
 551    Ver 
= VerView
.to_string(); 
 555 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 556                                         StringView 
&Package
,StringView 
&Ver
, 
 557                                         unsigned int &Op
, bool ParseArchFlags
, 
 559                                         bool ParseRestrictionsList
) 
 561    // Strip off leading space 
 562    for (;Start 
!= Stop 
&& isspace_ascii(*Start
) != 0; ++Start
); 
 564    // Parse off the package name 
 565    const char *I 
= Start
; 
 566    for (;I 
!= Stop 
&& isspace_ascii(*I
) == 0 && *I 
!= '(' && *I 
!= ')' && 
 567         *I 
!= ',' && *I 
!= '|' && *I 
!= '[' && *I 
!= ']' && 
 568         *I 
!= '<' && *I 
!= '>'; ++I
); 
 571    if (I 
!= Stop 
&& *I 
== ')') 
 577    // Stash the package name 
 578    Package 
= StringView(Start
, I 
- Start
); 
 580    // We don't want to confuse library users which can't handle MultiArch 
 581    if (StripMultiArch 
== true) { 
 582       string 
const arch 
= _config
->Find("APT::Architecture"); 
 583       size_t const found 
= Package
.rfind(':'); 
 584       if (found 
!= StringView::npos 
&& 
 585           (Package
.substr(found
) == ":any" || 
 586            Package
.substr(found
) == ":native" || 
 587            Package
.substr(found 
+1) == arch
)) 
 588          Package 
= Package
.substr(0,found
); 
 591    // Skip white space to the '(' 
 592    for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0 ; I
++); 
 595    if (I 
!= Stop 
&& *I 
== '(') 
 598       for (I
++; I 
!= Stop 
&& isspace_ascii(*I
) != 0 ; I
++); 
 601       I 
= ConvertRelation(I
,Op
); 
 604       for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 606       I 
= (const char*) memchr(I
, ')', Stop 
- I
); 
 607       if (I 
== NULL 
|| Start 
== I
) 
 610       // Skip trailing whitespace 
 612       for (; End 
> Start 
&& isspace_ascii(End
[-1]); End
--); 
 614       Ver 
= StringView(Start
,End
-Start
); 
 620       Op 
= pkgCache::Dep::NoOp
; 
 624    for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 626    if (unlikely(ParseArchFlags 
== true)) 
 628       string 
const arch 
= _config
->Find("APT::Architecture"); 
 629       APT::CacheFilter::PackageArchitectureMatchesSpecification 
matchesArch(arch
, false); 
 631       // Parse an architecture 
 632       if (I 
!= Stop 
&& *I 
== '[') 
 636          if (unlikely(I 
== Stop
)) 
 641          bool NegArch 
= false; 
 644             // look for whitespace or ending ']' 
 645             for (;End 
!= Stop 
&& !isspace_ascii(*End
) && *End 
!= ']'; ++End
); 
 647             if (unlikely(End 
== Stop
)) 
 656             std::string 
const arch(I
, End
); 
 657             if (arch
.empty() == false && matchesArch(arch
.c_str()) == true) 
 662                // we found a match, so fast-forward to the end of the wildcards 
 663                for (; End 
!= Stop 
&& *End 
!= ']'; ++End
); 
 672             for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 679             Package 
= ""; /* not for this arch */ 
 683       for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 686    if (unlikely(ParseRestrictionsList 
== true)) 
 688       // Parse a restrictions formula which is in disjunctive normal form: 
 689       // (foo AND bar) OR (blub AND bla) 
 691       std::vector
<string
> const profiles 
= APT::Configuration::getBuildProfiles(); 
 693       // if the next character is a restriction list, then by default the 
 694       // dependency does not apply and the conditions have to be checked 
 695       // if the next character is not a restriction list, then by default the 
 696       // dependency applies 
 697       bool applies1 
= (*I 
!= '<'); 
 705          if (unlikely(I 
== Stop
)) 
 710          // if of the prior restriction list is already fulfilled, then 
 711          // we can just skip to the end of the current list 
 713             for (;End 
!= Stop 
&& *End 
!= '>'; ++End
); 
 716             for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 718             bool applies2 
= true; 
 719             // all the conditions inside a restriction list have to be 
 720             // met so once we find one that is not met, we can skip to 
 721             // the end of this list 
 724                // look for whitespace or ending '>' 
 725                // End now points to the character after the current term 
 726                for (;End 
!= Stop 
&& !isspace_ascii(*End
) && *End 
!= '>'; ++End
); 
 728                if (unlikely(End 
== Stop
)) 
 731                bool NegRestriction 
= false; 
 734                   NegRestriction 
= true; 
 738                std::string 
const restriction(I
, End
); 
 739                if (restriction
.empty() == false && profiles
.empty() == false && 
 740                   std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end()) 
 742                   if (NegRestriction
) { 
 744                      // since one of the terms does not apply we don't have to check the others 
 745                      for (; End 
!= Stop 
&& *End 
!= '>'; ++End
); 
 748                   if (!NegRestriction
) { 
 750                      // since one of the terms does not apply we don't have to check the others 
 751                      for (; End 
!= Stop 
&& *End 
!= '>'; ++End
); 
 758                   for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 764                for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 772       if (applies1 
== false) { 
 773          Package 
= ""; //not for this restriction 
 777    if (I 
!= Stop 
&& *I 
== '|') 
 778       Op 
|= pkgCache::Dep::Or
; 
 780    if (I 
== Stop 
|| *I 
== ',' || *I 
== '|') 
 783          for (I
++; I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 790 // ListParser::ParseDepends - Parse a dependency list                   /*{{{*/ 
 791 // --------------------------------------------------------------------- 
 792 /* This is the higher level depends parser. It takes a tag and generates 
 793    a complete depends tree for the given version. */ 
 794 bool debListParser::ParseDepends(pkgCache::VerIterator 
&Ver
, 
 795                                  StringView Tag
,unsigned int Type
) 
 799    if (Section
.Find(Tag
,Start
,Stop
) == false || Start 
== Stop
) 
 802    string 
const pkgArch 
= Ver
.Arch(); 
 810       Start 
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false); 
 812          return _error
->Error("Problem parsing dependency %.*s",(int)Tag
.length(), Tag
.data()); 
 813       size_t const found 
= Package
.rfind(':'); 
 815       if (found 
== string::npos
) 
 817          if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false) 
 820       else if (Package
.substr(found
) == ":any") 
 822          if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false) 
 827          // Such dependencies are not supposed to be accepted … 
 828          // … but this is probably the best thing to do anyway 
 829          if (Package
.substr(found 
+ 1) == "native") 
 831             std::string 
const Pkg 
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch(); 
 832             if (NewDepends(Ver
, Pkg
, "any", Version
, Op 
| pkgCache::Dep::ArchSpecific
, Type
) == false) 
 835          else if (NewDepends(Ver
, Package
, "any", Version
, Op 
| pkgCache::Dep::ArchSpecific
, Type
) == false) 
 845 // ListParser::ParseProvides - Parse the provides list                  /*{{{*/ 
 846 // --------------------------------------------------------------------- 
 848 bool debListParser::ParseProvides(pkgCache::VerIterator 
&Ver
) 
 850    /* it is unlikely, but while parsing dependencies, we might have already 
 851       picked up multi-arch implicit provides which we do not want to duplicate here */ 
 852    bool hasProvidesAlready 
= false; 
 853    std::string 
const spzName 
= Ver
.ParentPkg().FullName(false); 
 855       for (pkgCache::PrvIterator Prv 
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
) 
 857          if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags 
& pkgCache::Flag::ArchSpecific
) == 0) 
 859          if (spzName 
!= Prv
.OwnerPkg().FullName(false)) 
 861          hasProvidesAlready 
= true; 
 866    string 
const Arch 
= Ver
.Arch(); 
 869    if (Section
.Find("Provides",Start
,Stop
) == true) 
 877          Start 
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false); 
 878          const size_t archfound 
= Package
.rfind(':'); 
 880             return _error
->Error("Problem parsing Provides line"); 
 881          if (unlikely(Op 
!= pkgCache::Dep::NoOp 
&& Op 
!= pkgCache::Dep::Equals
)) { 
 882             _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str()); 
 883          } else if (archfound 
!= string::npos
) { 
 884             StringView spzArch 
= Package
.substr(archfound 
+ 1); 
 885             if (spzArch 
!= "any") 
 887                if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit 
| pkgCache::Flag::ArchSpecific
) == false) 
 890             if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false) 
 892          } else if ((Ver
->MultiArch 
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) { 
 893             if (APT::Configuration::checkArchitecture(Arch
)) 
 895                if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false) 
 898             else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false) 
 901             if ((Ver
->MultiArch 
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
) 
 903                if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false) 
 906             if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false) 
 909          if (archfound 
== std::string::npos
) 
 911             string spzName 
= Package
.to_string(); 
 912             spzName
.push_back(':'); 
 913             spzName
.append(Ver
.ParentPkg().Arch()); 
 914             pkgCache::PkgIterator 
const spzPkg 
= Ver
.Cache()->FindPkg(spzName
, "any"); 
 915             if (spzPkg
.end() == false) 
 917                if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit 
| pkgCache::Flag::ArchSpecific
) == false) 
 921       } while (Start 
!= Stop
); 
 924    if (APT::Configuration::checkArchitecture(Arch
)) 
 926       if ((Ver
->MultiArch 
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
) 
 928          string 
const Package 
= string(Ver
.ParentPkg().Name()).append(":").append("any"); 
 929          if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false) 
 932       else if ((Ver
->MultiArch 
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) 
 934          if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false) 
 939    if (hasProvidesAlready 
== false) 
 941       pkgCache::PkgIterator 
const spzPkg 
= Ver
.Cache()->FindPkg(spzName
, "any"); 
 942       if (spzPkg
.end() == false) 
 944          if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit 
| pkgCache::Flag::ArchSpecific
) == false) 
 951 // ListParser::GrabWord - Matches a word and returns                    /*{{{*/ 
 952 // --------------------------------------------------------------------- 
 953 /* Looks for a word in a list of words - for ParseStatus */ 
 954 bool debListParser::GrabWord(StringView Word
, WordList 
const *List
, unsigned char &Out
) 
 956    for (unsigned int C 
= 0; List
[C
].Str
.empty() == false; C
++) 
 958       if (Word
.length() == List
[C
].Str
.length() && 
 959           strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0) 
 968 // ListParser::Step - Move to the next section in the file              /*{{{*/ 
 969 // --------------------------------------------------------------------- 
 970 /* This has to be careful to only process the correct architecture */ 
 971 bool debListParser::Step() 
 973    iOffset 
= Tags
.Offset(); 
 974    return Tags
.Step(Section
); 
 977 // ListParser::GetPrio - Convert the priority from a string             /*{{{*/ 
 978 // --------------------------------------------------------------------- 
 980 unsigned char debListParser::GetPrio(string Str
) 
 983    if (GrabWord(Str
,PrioList
,Out
) == false) 
 984       Out 
= pkgCache::State::Extra
; 
 989 bool debListParser::SameVersion(unsigned short const Hash
,              /*{{{*/ 
 990       pkgCache::VerIterator 
const &Ver
) 
 992    if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false) 
 994    // status file has no (Download)Size, but all others are fair game 
 995    // status file is parsed last, so the first version we encounter is 
 996    // probably also the version we have downloaded 
 997    unsigned long long const Size 
= Section
.FindULL("Size"); 
 998    if (Size 
!= 0 && Size 
!= Ver
->Size
) 
1000    // available everywhere, but easier to check here than to include in VersionHash 
1001    unsigned char MultiArch 
= ParseMultiArch(false); 
1002    if (MultiArch 
!= Ver
->MultiArch
) 
1004    // for all practical proposes (we can check): same version 
1009 debDebFileParser::debDebFileParser(FileFd 
*File
, std::string 
const &DebFile
) 
1010    : debListParser(File
), DebFile(DebFile
) 
1014 bool debDebFileParser::UsePackage(pkgCache::PkgIterator 
&Pkg
, 
1015                                   pkgCache::VerIterator 
&Ver
) 
1017    bool res 
= debListParser::UsePackage(Pkg
, Ver
); 
1018    // we use the full file path as a provides so that the file is found 
1020    if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false) 
1025 debListParser::~debListParser() {}