]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: deblistparser.cc,v 1.24 2001/02/20 07:03:17 jgg 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                                                        /*{{{*/ 
  13 #include <apt-pkg/deblistparser.h> 
  14 #include <apt-pkg/error.h> 
  15 #include <apt-pkg/configuration.h> 
  16 #include <apt-pkg/strutl.h> 
  17 #include <apt-pkg/crc-16.h> 
  22 static debListParser::WordList PrioList
[] = {{"important",pkgCache::State::Important
}, 
  23                        {"required",pkgCache::State::Required
}, 
  24                        {"standard",pkgCache::State::Standard
}, 
  25                        {"optional",pkgCache::State::Optional
}, 
  26                        {"extra",pkgCache::State::Extra
}, 
  29 // ListParser::debListParser - Constructor                              /*{{{*/ 
  30 // --------------------------------------------------------------------- 
  32 debListParser::debListParser(FileFd 
*File
) : Tags(File
) 
  34    Arch 
= _config
->Find("APT::architecture"); 
  37 // ListParser::UniqFindTagWrite - Find the tag and write a unq string   /*{{{*/ 
  38 // --------------------------------------------------------------------- 
  40 unsigned long debListParser::UniqFindTagWrite(const char *Tag
) 
  44    if (Section
.Find(Tag
,Start
,Stop
) == false) 
  46    return WriteUniqString(Start
,Stop 
- Start
); 
  49 // ListParser::Package - Return the package name                        /*{{{*/ 
  50 // --------------------------------------------------------------------- 
  51 /* This is to return the name of the package this section describes */ 
  52 string 
debListParser::Package() 
  54    string Result 
= Section
.FindS("Package"); 
  55    if (Result
.empty() == true) 
  56       _error
->Error("Encountered a section with no Package: header"); 
  60 // ListParser::Version - Return the version string                      /*{{{*/ 
  61 // --------------------------------------------------------------------- 
  62 /* This is to return the string describing the version in debian form, 
  63    epoch:upstream-release. If this returns the blank string then the  
  64    entry is assumed to only describe package properties */ 
  65 string 
debListParser::Version() 
  67    return Section
.FindS("Version"); 
  70 // ListParser::NewVersion - Fill in the version structure               /*{{{*/ 
  71 // --------------------------------------------------------------------- 
  73 bool debListParser::NewVersion(pkgCache::VerIterator Ver
) 
  76    Ver
->Section 
= UniqFindTagWrite("Section"); 
  77    Ver
->Arch 
= UniqFindTagWrite("Architecture"); 
  80    Ver
->Size 
= (unsigned)Section
.FindI("Size"); 
  82    // Unpacked Size (in K) 
  83    Ver
->InstalledSize 
= (unsigned)Section
.FindI("Installed-Size"); 
  84    Ver
->InstalledSize 
*= 1024; 
  89    if (Section
.Find("Priority",Start
,Stop
) == true) 
  91       if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false) 
  92          Ver
->Priority 
= pkgCache::State::Extra
; 
  95    if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false) 
  97    if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false) 
  99    if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false) 
 101    if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false) 
 103    if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false) 
 105    if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false) 
 109    if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false) 
 112    if (ParseProvides(Ver
) == false) 
 118 // ListParser::UsePackage - Update a package structure                  /*{{{*/ 
 119 // --------------------------------------------------------------------- 
 120 /* This is called to update the package with any new information  
 121    that might be found in the section */ 
 122 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
, 
 123                                pkgCache::VerIterator Ver
) 
 125    if (Pkg
->Section 
== 0) 
 126       Pkg
->Section 
= UniqFindTagWrite("Section"); 
 127    if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false) 
 129    if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false) 
 132    if (strcmp(Pkg
.Name(),"apt") == 0) 
 133       Pkg
->Flags 
|= pkgCache::Flag::Important
; 
 135    if (ParseStatus(Pkg
,Ver
) == false) 
 140 // ListParser::VersionHash - Compute a unique hash for this version     /*{{{*/ 
 141 // --------------------------------------------------------------------- 
 143 unsigned short debListParser::VersionHash() 
 145    const char *Sections
[] ={"Installed-Size", 
 152    unsigned long Result 
= INIT_FCS
; 
 154    for (const char **I 
= Sections
; *I 
!= 0; I
++) 
 158       if (Section
.Find(*I
,Start
,End
) == false || End 
- Start 
>= (signed)sizeof(S
)) 
 161       /* Strip out any spaces from the text, this undoes dpkgs reformatting 
 162          of certain fields. dpkg also has the rather interesting notion of 
 163          reformatting depends operators < -> <= */ 
 165       for (; Start 
!= End
; Start
++) 
 167          if (isspace(*Start
) == 0) 
 168             *I
++ = tolower(*Start
); 
 169          if (*Start 
== '<' && Start
[1] != '<' && Start
[1] != '=') 
 171          if (*Start 
== '>' && Start
[1] != '>' && Start
[1] != '=') 
 175       Result 
= AddCRC16(Result
,S
,I 
- S
); 
 181 // ListParser::ParseStatus - Parse the status field                     /*{{{*/ 
 182 // --------------------------------------------------------------------- 
 183 /* Status lines are of the form, 
 184      Status: want flag status 
 185    want = unknown, install, hold, deinstall, purge 
 186    flag = ok, reinstreq, hold, hold-reinstreq 
 187    status = not-installed, unpacked, half-configured, 
 188             half-installed, config-files, post-inst-failed,  
 189             removal-failed, installed 
 191    Some of the above are obsolete (I think?) flag = hold-* and  
 192    status = post-inst-failed, removal-failed at least. 
 194 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
, 
 195                                 pkgCache::VerIterator Ver
) 
 199    if (Section
.Find("Status",Start
,Stop
) == false) 
 202    // Isolate the first word 
 203    const char *I 
= Start
; 
 204    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 205    if (I 
>= Stop 
|| *I 
!= ' ') 
 206       return _error
->Error("Malformed Status line"); 
 208    // Process the want field 
 209    WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
}, 
 210                           {"install",pkgCache::State::Install
}, 
 211                           {"hold",pkgCache::State::Hold
}, 
 212                           {"deinstall",pkgCache::State::DeInstall
}, 
 213                           {"purge",pkgCache::State::Purge
}, 
 215    if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false) 
 216       return _error
->Error("Malformed 1st word in the Status line"); 
 218    // Isloate the next word 
 221    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 222    if (I 
>= Stop 
|| *I 
!= ' ') 
 223       return _error
->Error("Malformed status line, no 2nd word"); 
 225    // Process the flag field 
 226    WordList FlagList
[] = {{"ok",pkgCache::State::Ok
}, 
 227                           {"reinstreq",pkgCache::State::ReInstReq
}, 
 228                           {"hold",pkgCache::State::HoldInst
}, 
 229                           {"hold-reinstreq",pkgCache::State::HoldReInstReq
}, 
 231    if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false) 
 232       return _error
->Error("Malformed 2nd word in the Status line"); 
 234    // Isloate the last word 
 237    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 239       return _error
->Error("Malformed Status line, no 3rd word"); 
 241    // Process the flag field 
 242    WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
}, 
 243                             {"unpacked",pkgCache::State::UnPacked
}, 
 244                             {"half-configured",pkgCache::State::HalfConfigured
}, 
 245                             {"installed",pkgCache::State::Installed
}, 
 246                             {"half-installed",pkgCache::State::HalfInstalled
}, 
 247                             {"config-files",pkgCache::State::ConfigFiles
}, 
 248                             {"post-inst-failed",pkgCache::State::HalfConfigured
}, 
 249                             {"removal-failed",pkgCache::State::HalfInstalled
}, 
 251    if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false) 
 252       return _error
->Error("Malformed 3rd word in the Status line"); 
 254    /* A Status line marks the package as indicating the current 
 255       version as well. Only if it is actually installed.. Otherwise 
 256       the interesting dpkg handling of the status file creates bogus  
 258    if (!(Pkg
->CurrentState 
== pkgCache::State::NotInstalled 
|| 
 259          Pkg
->CurrentState 
== pkgCache::State::ConfigFiles
)) 
 261       if (Ver
.end() == true) 
 262          _error
->Warning("Encountered status field in a non-version description"); 
 264          Pkg
->CurrentVer 
= Ver
.Index(); 
 270 // ListParser::ParseDepends - Parse a dependency element                /*{{{*/ 
 271 // --------------------------------------------------------------------- 
 272 /* This parses the dependency elements out of a standard string in place, 
 274 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
) 
 276    // Determine the operator 
 284          Op 
= pkgCache::Dep::LessEq
; 
 291          Op 
= pkgCache::Dep::Less
; 
 295       // < is the same as <= and << is really Cs < for some reason 
 296       Op 
= pkgCache::Dep::LessEq
; 
 304          Op 
= pkgCache::Dep::GreaterEq
; 
 311          Op 
= pkgCache::Dep::Greater
; 
 315       // > is the same as >= and >> is really Cs > for some reason 
 316       Op 
= pkgCache::Dep::GreaterEq
; 
 320       Op 
= pkgCache::Dep::Equals
; 
 324       // HACK around bad package definitions 
 326       Op 
= pkgCache::Dep::Equals
; 
 332 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 333                                         string 
&Package
,string 
&Ver
, 
 334                                         unsigned int &Op
, bool ParseArchFlags
) 
 336    // Strip off leading space 
 337    for (;Start 
!= Stop 
&& isspace(*Start
) != 0; Start
++); 
 339    // Parse off the package name 
 340    const char *I 
= Start
; 
 341    for (;I 
!= Stop 
&& isspace(*I
) == 0 && *I 
!= '(' && *I 
!= ')' && 
 342         *I 
!= ',' && *I 
!= '|'; I
++); 
 345    if (I 
!= Stop 
&& *I 
== ')') 
 351    // Stash the package name 
 352    Package
.assign(Start
,I 
- Start
); 
 354    // Skip white space to the '(' 
 355    for (;I 
!= Stop 
&& isspace(*I
) != 0 ; I
++); 
 358    if (I 
!= Stop 
&& *I 
== '(') 
 361       for (I
++; I 
!= Stop 
&& isspace(*I
) != 0 ; I
++); 
 364       I 
= ConvertRelation(I
,Op
); 
 367       for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 369       for (;I 
!= Stop 
&& *I 
!= ')'; I
++); 
 370       if (I 
== Stop 
|| Start 
== I
) 
 373       // Skip trailing whitespace 
 375       for (; End 
> Start 
&& isspace(End
[-1]); End
--); 
 377       Ver 
= string(Start
,End
-Start
); 
 383       Op 
= pkgCache::Dep::NoOp
; 
 387    for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 389    if (ParseArchFlags 
== true) 
 391       string arch 
= _config
->Find("APT::Architecture"); 
 393       // Parse an architecture 
 394       if (I 
!= Stop 
&& *I 
== '[') 
 405             // look for whitespace or ending ']' 
 406             while (End 
!= Stop 
&& !isspace(*End
) && *End 
!= ']')  
 412             if (stringcmp(I
,End
,arch
.begin(),arch
.end()) == 0) 
 421             for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 425             Package 
= ""; /* not for this arch */ 
 429       for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 432    if (I 
!= Stop 
&& *I 
== '|') 
 433       Op 
|= pkgCache::Dep::Or
; 
 435    if (I 
== Stop 
|| *I 
== ',' || *I 
== '|') 
 438          for (I
++; I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 445 // ListParser::ParseDepends - Parse a dependency list                   /*{{{*/ 
 446 // --------------------------------------------------------------------- 
 447 /* This is the higher level depends parser. It takes a tag and generates 
 448    a complete depends tree for the given version. */ 
 449 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
, 
 450                                  const char *Tag
,unsigned int Type
) 
 454    if (Section
.Find(Tag
,Start
,Stop
) == false) 
 463       Start 
= ParseDepends(Start
,Stop
,Package
,Version
,Op
); 
 465          return _error
->Error("Problem parsing dependency %s",Tag
); 
 467       if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false) 
 475 // ListParser::ParseProvides - Parse the provides list                  /*{{{*/ 
 476 // --------------------------------------------------------------------- 
 478 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
) 
 482    if (Section
.Find("Provides",Start
,Stop
) == false) 
 491       Start 
= ParseDepends(Start
,Stop
,Package
,Version
,Op
); 
 493          return _error
->Error("Problem parsing Provides line"); 
 494       if (Op 
!= pkgCache::Dep::NoOp
) 
 495          return _error
->Error("Malformed provides line"); 
 497       if (NewProvides(Ver
,Package
,Version
) == false) 
 507 // ListParser::GrabWord - Matches a word and returns                    /*{{{*/ 
 508 // --------------------------------------------------------------------- 
 509 /* Looks for a word in a list of words - for ParseStatus */ 
 510 bool debListParser::GrabWord(string Word
,WordList 
*List
,unsigned char &Out
) 
 512    for (unsigned int C 
= 0; List
[C
].Str 
!= 0; C
++) 
 514       if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0) 
 523 // ListParser::Step - Move to the next section in the file              /*{{{*/ 
 524 // --------------------------------------------------------------------- 
 525 /* This has to be carefull to only process the correct architecture */ 
 526 bool debListParser::Step() 
 528    iOffset 
= Tags
.Offset(); 
 529    while (Tags
.Step(Section
) == true) 
 531       /* See if this is the correct Architecture, if it isn't then we 
 532          drop the whole section. A missing arch tag only happens (in theory) 
 533          inside the Status file, so that is a positive return */ 
 536       if (Section
.Find("Architecture",Start
,Stop
) == false) 
 539       if (stringcmp(Start
,Stop
,Arch
.begin(),Arch
.end()) == 0) 
 542       if (stringcmp(Start
,Stop
,"all") == 0) 
 545       iOffset 
= Tags
.Offset(); 
 550 // ListParser::LoadReleaseInfo - Load the release information           /*{{{*/ 
 551 // --------------------------------------------------------------------- 
 553 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
, 
 556    pkgTagFile 
Tags(&File
); 
 557    pkgTagSection Section
; 
 558    if (Tags
.Step(Section
) == false) 
 563    if (Section
.Find("Archive",Start
,Stop
) == true) 
 564       FileI
->Archive 
= WriteUniqString(Start
,Stop 
- Start
); 
 565    if (Section
.Find("Component",Start
,Stop
) == true) 
 566       FileI
->Component 
= WriteUniqString(Start
,Stop 
- Start
); 
 567    if (Section
.Find("Version",Start
,Stop
) == true) 
 568       FileI
->Version 
= WriteUniqString(Start
,Stop 
- Start
); 
 569    if (Section
.Find("Origin",Start
,Stop
) == true) 
 570       FileI
->Origin 
= WriteUniqString(Start
,Stop 
- Start
); 
 571    if (Section
.Find("Label",Start
,Stop
) == true) 
 572       FileI
->Label 
= WriteUniqString(Start
,Stop 
- Start
); 
 573    if (Section
.Find("Architecture",Start
,Stop
) == true) 
 574       FileI
->Architecture 
= WriteUniqString(Start
,Stop 
- Start
); 
 576    if (Section
.FindFlag("NotAutomatic",FileI
->Flags
, 
 577                         pkgCache::Flag::NotAutomatic
) == false) 
 578       _error
->Warning("Bad NotAutomatic flag"); 
 580    return !_error
->PendingError(); 
 583 // ListParser::GetPrio - Convert the priority from a string             /*{{{*/ 
 584 // --------------------------------------------------------------------- 
 586 unsigned char debListParser::GetPrio(string Str
) 
 589    if (GrabWord(Str
,PrioList
,Out
) == false) 
 590       Out 
= pkgCache::State::Extra
;