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 
const 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                   Ver
->SourceVerStr 
= idx
; 
 174       APT::StringView 
const pkgname(Start
, Stop 
- Start
); 
 175       if (pkgname 
!= G
.Name()) 
 177          for (pkgCache::PkgIterator P 
= G
.PackageList(); P
.end() == false; P 
= G
.NextPkg(P
)) 
 179             for (V 
= P
.VersionList(); V
.end() == false; ++V
) 
 181                if (pkgname 
== V
.SourcePkgName()) 
 183                   Ver
->SourcePkgName 
= V
->SourcePkgName
; 
 187             if (V
.end() == false) 
 192             map_stringitem_t 
const idx 
= StoreString(pkgCacheGenerator::PKGNAME
, pkgname
); 
 193             Ver
->SourcePkgName 
= idx
; 
 198    Ver
->MultiArch 
= ParseMultiArch(true); 
 200    Ver
->Size 
= Section
.FindULL("Size"); 
 201    // Unpacked Size (in K) 
 202    Ver
->InstalledSize 
= Section
.FindULL("Installed-Size"); 
 203    Ver
->InstalledSize 
*= 1024; 
 206    if (Section
.Find("Priority",Start
,Stop
) == true) 
 208       if (GrabWord(StringView(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false) 
 209          Ver
->Priority 
= pkgCache::State::Extra
; 
 212    if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false) 
 214    if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false) 
 216    if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false) 
 218    if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false) 
 220    if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false) 
 222    if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false) 
 224    if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false) 
 226    if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false) 
 229    if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false) 
 232    if (ParseProvides(Ver
) == false) 
 238 // ListParser::AvailableDescriptionLanguages                            /*{{{*/ 
 239 std::vector
<std::string
> debListParser::AvailableDescriptionLanguages() 
 241    std::vector
<std::string
> const understood 
= APT::Configuration::getLanguages(); 
 242    std::vector
<std::string
> avail
; 
 243    static constexpr int prefixLen 
= 12; 
 244    static constexpr int avgLanguageLen 
= 5; 
 247    tagname
.reserve(prefixLen 
+ avgLanguageLen
); 
 248    tagname
.assign("Description-"); 
 249    if (Section
.Exists("Description") == true) 
 251    for (std::vector
<std::string
>::const_iterator lang 
= understood
.begin(); lang 
!= understood
.end(); ++lang
) 
 253       tagname
.resize(prefixLen
); 
 254       tagname
.append(*lang
); 
 255       if (Section
.Exists(tagname
) == true) 
 256          avail
.push_back(*lang
); 
 261 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/ 
 262 // --------------------------------------------------------------------- 
 263 /* This is to return the md5 string to allow the check if it is the right 
 264    description. If no Description-md5 is found in the section it will be 
 267 MD5SumValue 
debListParser::Description_md5() 
 269    StringView 
const value 
= Section
.Find("Description-md5"); 
 270    if (value
.empty() == true) 
 272       StringView 
const desc 
= Section
.Find("Description"); 
 274          return MD5SumValue(); 
 277       md5
.Add(desc
.data(), desc
.size()); 
 281    else if (likely(value
.size() == 32)) 
 283       MD5SumValue sumvalue
; 
 284       if (sumvalue
.Set(value
)) 
 287       _error
->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value
.length(), value
.data()); 
 288       return MD5SumValue(); 
 290    _error
->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value
.size(), (int)value
.length(), value
.data()); 
 291    return MD5SumValue(); 
 294 // ListParser::UsePackage - Update a package structure                  /*{{{*/ 
 295 // --------------------------------------------------------------------- 
 296 /* This is called to update the package with any new information  
 297    that might be found in the section */ 
 298 bool debListParser::UsePackage(pkgCache::PkgIterator 
&Pkg
, 
 299                                pkgCache::VerIterator 
&Ver
) 
 301    string 
const static myArch 
= _config
->Find("APT::Architecture"); 
 302    // Possible values are: "all", "native", "installed" and "none" 
 303    // The "installed" mode is handled by ParseStatus(), See #544481 and friends. 
 304    string 
const static essential 
= _config
->Find("pkgCacheGen::Essential", "all"); 
 305    if (essential 
== "all" || 
 306        (essential 
== "native" && Pkg
->Arch 
!= 0 && myArch 
== Pkg
.Arch())) 
 307       if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false) 
 309    if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false) 
 312    if (strcmp(Pkg
.Name(),"apt") == 0) 
 314       if ((essential 
== "native" && Pkg
->Arch 
!= 0 && myArch 
== Pkg
.Arch()) || 
 316          Pkg
->Flags 
|= pkgCache::Flag::Essential 
| pkgCache::Flag::Important
; 
 318          Pkg
->Flags 
|= pkgCache::Flag::Important
; 
 321    if (ParseStatus(Pkg
,Ver
) == false) 
 326 // ListParser::VersionHash - Compute a unique hash for this version     /*{{{*/ 
 327 // --------------------------------------------------------------------- 
 329 unsigned short debListParser::VersionHash() 
 331    static const StringView Sections
[] ={"Installed-Size", 
 339    unsigned long Result 
= INIT_FCS
; 
 341    for (StringView I 
: Sections
) 
 345       if (Section
.Find(I
,Start
,End
) == false || End 
- Start 
>= (signed)sizeof(S
)) 
 348       /* Strip out any spaces from the text, this undoes dpkgs reformatting 
 349          of certain fields. dpkg also has the rather interesting notion of 
 350          reformatting depends operators < -> <= */ 
 352       for (; Start 
!= End
; ++Start
) 
 354          if (isspace_ascii(*Start
) != 0) 
 356          *J
++ = tolower_ascii(*Start
); 
 358          if ((*Start 
== '<' || *Start 
== '>') && Start
[1] != *Start 
&& Start
[1] != '=') 
 362       Result 
= AddCRC16(Result
,S
,J 
- S
); 
 368 // StatusListParser::ParseStatus - Parse the status field               /*{{{*/ 
 369 // --------------------------------------------------------------------- 
 370 /* Status lines are of the form, 
 371      Status: want flag status 
 372    want = unknown, install, hold, deinstall, purge 
 374    status = not-installed, config-files, half-installed, unpacked, 
 375             half-configured, triggers-awaited, triggers-pending, installed 
 377 bool debListParser::ParseStatus(pkgCache::PkgIterator 
&, 
 378                                 pkgCache::VerIterator 
&) 
 382 bool debStatusListParser::ParseStatus(pkgCache::PkgIterator 
&Pkg
, 
 383                                 pkgCache::VerIterator 
&Ver
) 
 387    if (Section
.Find("Status",Start
,Stop
) == false) 
 390    // UsePackage() is responsible for setting the flag in the default case 
 391    bool const static essential 
= _config
->Find("pkgCacheGen::Essential", "") == "installed"; 
 392    if (essential 
== true && 
 393        Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false) 
 396    // Isolate the first word 
 397    const char *I 
= Start
; 
 398    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 399    if (I 
>= Stop 
|| *I 
!= ' ') 
 400       return _error
->Error("Malformed Status line"); 
 402    // Process the want field 
 403    WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
}, 
 404                           {"install",pkgCache::State::Install
}, 
 405                           {"hold",pkgCache::State::Hold
}, 
 406                           {"deinstall",pkgCache::State::DeInstall
}, 
 407                           {"purge",pkgCache::State::Purge
}, 
 409    if (GrabWord(StringView(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false) 
 410       return _error
->Error("Malformed 1st word in the Status line"); 
 412    // Isloate the next word 
 415    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 416    if (I 
>= Stop 
|| *I 
!= ' ') 
 417       return _error
->Error("Malformed status line, no 2nd word"); 
 419    // Process the flag field 
 420    WordList FlagList
[] = {{"ok",pkgCache::State::Ok
}, 
 421                           {"reinstreq",pkgCache::State::ReInstReq
}, 
 422                           {"hold",pkgCache::State::HoldInst
}, 
 423                           {"hold-reinstreq",pkgCache::State::HoldReInstReq
}, 
 425    if (GrabWord(StringView(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false) 
 426       return _error
->Error("Malformed 2nd word in the Status line"); 
 428    // Isloate the last word 
 431    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 433       return _error
->Error("Malformed Status line, no 3rd word"); 
 435    // Process the flag field 
 436    WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
}, 
 437                             {"config-files",pkgCache::State::ConfigFiles
}, 
 438                             {"half-installed",pkgCache::State::HalfInstalled
}, 
 439                             {"unpacked",pkgCache::State::UnPacked
}, 
 440                             {"half-configured",pkgCache::State::HalfConfigured
}, 
 441                             {"triggers-awaited",pkgCache::State::TriggersAwaited
}, 
 442                             {"triggers-pending",pkgCache::State::TriggersPending
}, 
 443                             {"installed",pkgCache::State::Installed
}, 
 445    if (GrabWord(StringView(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false) 
 446       return _error
->Error("Malformed 3rd word in the Status line"); 
 448    /* A Status line marks the package as indicating the current 
 449       version as well. Only if it is actually installed.. Otherwise 
 450       the interesting dpkg handling of the status file creates bogus  
 452    if (!(Pkg
->CurrentState 
== pkgCache::State::NotInstalled 
|| 
 453          Pkg
->CurrentState 
== pkgCache::State::ConfigFiles
)) 
 455       if (Ver
.end() == true) 
 456          _error
->Warning("Encountered status field in a non-version description"); 
 458          Pkg
->CurrentVer 
= Ver
.Index(); 
 464 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
) 
 466    // Determine the operator 
 474          Op 
= pkgCache::Dep::LessEq
; 
 481          Op 
= pkgCache::Dep::Less
; 
 485       // < is the same as <= and << is really Cs < for some reason 
 486       Op 
= pkgCache::Dep::LessEq
; 
 494          Op 
= pkgCache::Dep::GreaterEq
; 
 501          Op 
= pkgCache::Dep::Greater
; 
 505       // > is the same as >= and >> is really Cs > for some reason 
 506       Op 
= pkgCache::Dep::GreaterEq
; 
 510       Op 
= pkgCache::Dep::Equals
; 
 514       // HACK around bad package definitions 
 516       Op 
= pkgCache::Dep::Equals
; 
 522 // ListParser::ParseDepends - Parse a dependency element                /*{{{*/ 
 523 // --------------------------------------------------------------------- 
 524 /* This parses the dependency elements out of a standard string in place, 
 526 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 527                std::string 
&Package
,std::string 
&Ver
,unsigned int &Op
) 
 528    { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, false, true, false); } 
 529 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 530                std::string 
&Package
,std::string 
&Ver
,unsigned int &Op
, 
 531                bool const &ParseArchFlags
) 
 532    { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, true, false); } 
 533 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 534                std::string 
&Package
,std::string 
&Ver
,unsigned int &Op
, 
 535                bool const &ParseArchFlags
, bool const &StripMultiArch
) 
 536    { return ParseDepends(Start
, Stop
, Package
, Ver
, Op
, ParseArchFlags
, StripMultiArch
, false); } 
 537 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 538                                         string 
&Package
,string 
&Ver
, 
 539                                         unsigned int &Op
, bool const &ParseArchFlags
, 
 540                                         bool const &StripMultiArch
, 
 541                                         bool const &ParseRestrictionsList
) 
 543    StringView PackageView
; 
 546    auto res 
= ParseDepends(Start
, Stop
, PackageView
, VerView
, Op
, (bool)ParseArchFlags
, 
 547    (bool) StripMultiArch
, (bool) ParseRestrictionsList
); 
 548    Package 
= PackageView
.to_string(); 
 549    Ver 
= VerView
.to_string(); 
 553 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 554                                         StringView 
&Package
,StringView 
&Ver
, 
 555                                         unsigned int &Op
, bool ParseArchFlags
, 
 557                                         bool ParseRestrictionsList
) 
 559    // Strip off leading space 
 560    for (;Start 
!= Stop 
&& isspace_ascii(*Start
) != 0; ++Start
); 
 562    // Parse off the package name 
 563    const char *I 
= Start
; 
 564    for (;I 
!= Stop 
&& isspace_ascii(*I
) == 0 && *I 
!= '(' && *I 
!= ')' && 
 565         *I 
!= ',' && *I 
!= '|' && *I 
!= '[' && *I 
!= ']' && 
 566         *I 
!= '<' && *I 
!= '>'; ++I
); 
 569    if (I 
!= Stop 
&& *I 
== ')') 
 575    // Stash the package name 
 576    Package 
= StringView(Start
, I 
- Start
); 
 578    // We don't want to confuse library users which can't handle MultiArch 
 579    if (StripMultiArch 
== true) { 
 580       string 
const arch 
= _config
->Find("APT::Architecture"); 
 581       size_t const found 
= Package
.rfind(':'); 
 582       if (found 
!= StringView::npos 
&& 
 583           (Package
.substr(found
) == ":any" || 
 584            Package
.substr(found
) == ":native" || 
 585            Package
.substr(found 
+1) == arch
)) 
 586          Package 
= Package
.substr(0,found
); 
 589    // Skip white space to the '(' 
 590    for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0 ; I
++); 
 593    if (I 
!= Stop 
&& *I 
== '(') 
 596       for (I
++; I 
!= Stop 
&& isspace_ascii(*I
) != 0 ; I
++); 
 599       I 
= ConvertRelation(I
,Op
); 
 602       for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 604       I 
= (const char*) memchr(I
, ')', Stop 
- I
); 
 605       if (I 
== NULL 
|| Start 
== I
) 
 608       // Skip trailing whitespace 
 610       for (; End 
> Start 
&& isspace_ascii(End
[-1]); End
--); 
 612       Ver 
= StringView(Start
,End
-Start
); 
 618       Op 
= pkgCache::Dep::NoOp
; 
 622    for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 624    if (unlikely(ParseArchFlags 
== true)) 
 626       string 
const arch 
= _config
->Find("APT::Architecture"); 
 627       APT::CacheFilter::PackageArchitectureMatchesSpecification 
matchesArch(arch
, false); 
 629       // Parse an architecture 
 630       if (I 
!= Stop 
&& *I 
== '[') 
 634          if (unlikely(I 
== Stop
)) 
 639          bool NegArch 
= false; 
 642             // look for whitespace or ending ']' 
 643             for (;End 
!= Stop 
&& !isspace_ascii(*End
) && *End 
!= ']'; ++End
); 
 645             if (unlikely(End 
== Stop
)) 
 654             std::string 
const arch(I
, End
); 
 655             if (arch
.empty() == false && matchesArch(arch
.c_str()) == true) 
 660                // we found a match, so fast-forward to the end of the wildcards 
 661                for (; End 
!= Stop 
&& *End 
!= ']'; ++End
); 
 670             for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 677             Package 
= ""; /* not for this arch */ 
 681       for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 684    if (unlikely(ParseRestrictionsList 
== true)) 
 686       // Parse a restrictions formula which is in disjunctive normal form: 
 687       // (foo AND bar) OR (blub AND bla) 
 689       std::vector
<string
> const profiles 
= APT::Configuration::getBuildProfiles(); 
 691       // if the next character is a restriction list, then by default the 
 692       // dependency does not apply and the conditions have to be checked 
 693       // if the next character is not a restriction list, then by default the 
 694       // dependency applies 
 695       bool applies1 
= (*I 
!= '<'); 
 703          if (unlikely(I 
== Stop
)) 
 708          // if of the prior restriction list is already fulfilled, then 
 709          // we can just skip to the end of the current list 
 711             for (;End 
!= Stop 
&& *End 
!= '>'; ++End
); 
 714             for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 716             bool applies2 
= true; 
 717             // all the conditions inside a restriction list have to be 
 718             // met so once we find one that is not met, we can skip to 
 719             // the end of this list 
 722                // look for whitespace or ending '>' 
 723                // End now points to the character after the current term 
 724                for (;End 
!= Stop 
&& !isspace_ascii(*End
) && *End 
!= '>'; ++End
); 
 726                if (unlikely(End 
== Stop
)) 
 729                bool NegRestriction 
= false; 
 732                   NegRestriction 
= true; 
 736                std::string 
const restriction(I
, End
); 
 737                if (restriction
.empty() == false && profiles
.empty() == false && 
 738                   std::find(profiles
.begin(), profiles
.end(), restriction
) != profiles
.end()) 
 740                   if (NegRestriction
) { 
 742                      // since one of the terms does not apply we don't have to check the others 
 743                      for (; End 
!= Stop 
&& *End 
!= '>'; ++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
); 
 756                   for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 762                for (;I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 770       if (applies1 
== false) { 
 771          Package 
= ""; //not for this restriction 
 775    if (I 
!= Stop 
&& *I 
== '|') 
 776       Op 
|= pkgCache::Dep::Or
; 
 778    if (I 
== Stop 
|| *I 
== ',' || *I 
== '|') 
 781          for (I
++; I 
!= Stop 
&& isspace_ascii(*I
) != 0; I
++); 
 788 // ListParser::ParseDepends - Parse a dependency list                   /*{{{*/ 
 789 // --------------------------------------------------------------------- 
 790 /* This is the higher level depends parser. It takes a tag and generates 
 791    a complete depends tree for the given version. */ 
 792 bool debListParser::ParseDepends(pkgCache::VerIterator 
&Ver
, 
 793                                  StringView Tag
,unsigned int Type
) 
 797    if (Section
.Find(Tag
,Start
,Stop
) == false || Start 
== Stop
) 
 800    string 
const pkgArch 
= Ver
.Arch(); 
 808       Start 
= ParseDepends(Start
, Stop
, Package
, Version
, Op
, false, false, false); 
 810          return _error
->Error("Problem parsing dependency %.*s",(int)Tag
.length(), Tag
.data()); 
 811       size_t const found 
= Package
.rfind(':'); 
 813       if (found 
== string::npos
) 
 815          if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false) 
 818       else if (Package
.substr(found
) == ":any") 
 820          if (NewDepends(Ver
,Package
,"any",Version
,Op
,Type
) == false) 
 825          // Such dependencies are not supposed to be accepted … 
 826          // … but this is probably the best thing to do anyway 
 827          if (Package
.substr(found 
+ 1) == "native") 
 829             std::string 
const Pkg 
= Package
.substr(0, found
).to_string() + ':' + Ver
.Cache()->NativeArch(); 
 830             if (NewDepends(Ver
, Pkg
, "any", Version
, Op 
| pkgCache::Dep::ArchSpecific
, Type
) == false) 
 833          else if (NewDepends(Ver
, Package
, "any", Version
, Op 
| pkgCache::Dep::ArchSpecific
, Type
) == false) 
 843 // ListParser::ParseProvides - Parse the provides list                  /*{{{*/ 
 844 // --------------------------------------------------------------------- 
 846 bool debListParser::ParseProvides(pkgCache::VerIterator 
&Ver
) 
 848    /* it is unlikely, but while parsing dependencies, we might have already 
 849       picked up multi-arch implicit provides which we do not want to duplicate here */ 
 850    bool hasProvidesAlready 
= false; 
 851    std::string 
const spzName 
= Ver
.ParentPkg().FullName(false); 
 853       for (pkgCache::PrvIterator Prv 
= Ver
.ProvidesList(); Prv
.end() == false; ++Prv
) 
 855          if (Prv
.IsMultiArchImplicit() == false || (Prv
->Flags 
& pkgCache::Flag::ArchSpecific
) == 0) 
 857          if (spzName 
!= Prv
.OwnerPkg().FullName(false)) 
 859          hasProvidesAlready 
= true; 
 864    string 
const Arch 
= Ver
.Arch(); 
 867    if (Section
.Find("Provides",Start
,Stop
) == true) 
 875          Start 
= ParseDepends(Start
,Stop
,Package
,Version
,Op
, false, false, false); 
 876          const size_t archfound 
= Package
.rfind(':'); 
 878             return _error
->Error("Problem parsing Provides line"); 
 879          if (unlikely(Op 
!= pkgCache::Dep::NoOp 
&& Op 
!= pkgCache::Dep::Equals
)) { 
 880             _error
->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package
.to_string().c_str()); 
 881          } else if (archfound 
!= string::npos
) { 
 882             StringView spzArch 
= Package
.substr(archfound 
+ 1); 
 883             if (spzArch 
!= "any") 
 885                if (NewProvides(Ver
, Package
.substr(0, archfound
), spzArch
, Version
, pkgCache::Flag::MultiArchImplicit 
| pkgCache::Flag::ArchSpecific
) == false) 
 888             if (NewProvides(Ver
, Package
, "any", Version
, pkgCache::Flag::ArchSpecific
) == false) 
 890          } else if ((Ver
->MultiArch 
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) { 
 891             if (APT::Configuration::checkArchitecture(Arch
)) 
 893                if (NewProvidesAllArch(Ver
, Package
, Version
, 0) == false) 
 896             else if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false) 
 899             if ((Ver
->MultiArch 
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
) 
 901                if (NewProvides(Ver
, Package
.to_string().append(":any"), "any", Version
, pkgCache::Flag::MultiArchImplicit
) == false) 
 904             if (NewProvides(Ver
, Package
, Arch
, Version
, 0) == false) 
 907          if (archfound 
== std::string::npos
) 
 909             string spzName 
= Package
.to_string(); 
 910             spzName
.push_back(':'); 
 911             spzName
.append(Ver
.ParentPkg().Arch()); 
 912             pkgCache::PkgIterator 
const spzPkg 
= Ver
.Cache()->FindPkg(spzName
, "any"); 
 913             if (spzPkg
.end() == false) 
 915                if (NewProvides(Ver
, spzName
, "any", Version
, pkgCache::Flag::MultiArchImplicit 
| pkgCache::Flag::ArchSpecific
) == false) 
 919       } while (Start 
!= Stop
); 
 922    if (APT::Configuration::checkArchitecture(Arch
)) 
 924       if ((Ver
->MultiArch 
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
) 
 926          string 
const Package 
= string(Ver
.ParentPkg().Name()).append(":").append("any"); 
 927          if (NewProvides(Ver
, Package
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false) 
 930       else if ((Ver
->MultiArch 
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
) 
 932          if (NewProvidesAllArch(Ver
, Ver
.ParentPkg().Name(), Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit
) == false) 
 937    if (hasProvidesAlready 
== false) 
 939       pkgCache::PkgIterator 
const spzPkg 
= Ver
.Cache()->FindPkg(spzName
, "any"); 
 940       if (spzPkg
.end() == false) 
 942          if (NewProvides(Ver
, spzName
, "any", Ver
.VerStr(), pkgCache::Flag::MultiArchImplicit 
| pkgCache::Flag::ArchSpecific
) == false) 
 949 // ListParser::GrabWord - Matches a word and returns                    /*{{{*/ 
 950 // --------------------------------------------------------------------- 
 951 /* Looks for a word in a list of words - for ParseStatus */ 
 952 bool debListParser::GrabWord(StringView Word
, WordList 
const *List
, unsigned char &Out
) 
 954    for (unsigned int C 
= 0; List
[C
].Str
.empty() == false; C
++) 
 956       if (Word
.length() == List
[C
].Str
.length() && 
 957           strncasecmp(Word
.data(), List
[C
].Str
.data(), Word
.length()) == 0) 
 966 // ListParser::Step - Move to the next section in the file              /*{{{*/ 
 967 // --------------------------------------------------------------------- 
 968 /* This has to be careful to only process the correct architecture */ 
 969 bool debListParser::Step() 
 971    iOffset 
= Tags
.Offset(); 
 972    return Tags
.Step(Section
); 
 975 // ListParser::GetPrio - Convert the priority from a string             /*{{{*/ 
 976 // --------------------------------------------------------------------- 
 978 unsigned char debListParser::GetPrio(string Str
) 
 981    if (GrabWord(Str
,PrioList
,Out
) == false) 
 982       Out 
= pkgCache::State::Extra
; 
 987 bool debListParser::SameVersion(unsigned short const Hash
,              /*{{{*/ 
 988       pkgCache::VerIterator 
const &Ver
) 
 990    if (pkgCacheListParser::SameVersion(Hash
, Ver
) == false) 
 992    // status file has no (Download)Size, but all others are fair game 
 993    // status file is parsed last, so the first version we encounter is 
 994    // probably also the version we have downloaded 
 995    unsigned long long const Size 
= Section
.FindULL("Size"); 
 996    if (Size 
!= 0 && Size 
!= Ver
->Size
) 
 998    // available everywhere, but easier to check here than to include in VersionHash 
 999    unsigned char MultiArch 
= ParseMultiArch(false); 
1000    if (MultiArch 
!= Ver
->MultiArch
) 
1002    // for all practical proposes (we can check): same version 
1007 debDebFileParser::debDebFileParser(FileFd 
*File
, std::string 
const &DebFile
) 
1008    : debListParser(File
), DebFile(DebFile
) 
1012 bool debDebFileParser::UsePackage(pkgCache::PkgIterator 
&Pkg
, 
1013                                   pkgCache::VerIterator 
&Ver
) 
1015    bool res 
= debListParser::UsePackage(Pkg
, Ver
); 
1016    // we use the full file path as a provides so that the file is found 
1018    if(NewProvides(Ver
, DebFile
, Pkg
.Cache()->NativeArch(), Ver
.VerStr(), 0) == false) 
1023 debListParser::~debListParser() {}