]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
   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                                                        /*{{{*/ 
  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> 
  18 #include <apt-pkg/md5.h> 
  25 static debListParser::WordList PrioList
[] = {{"important",pkgCache::State::Important
}, 
  26                        {"required",pkgCache::State::Required
}, 
  27                        {"standard",pkgCache::State::Standard
}, 
  28                        {"optional",pkgCache::State::Optional
}, 
  29                        {"extra",pkgCache::State::Extra
}, 
  32 // ListParser::debListParser - Constructor                              /*{{{*/ 
  33 // --------------------------------------------------------------------- 
  35 debListParser::debListParser(FileFd 
*File
) : Tags(File
) 
  37    Arch 
= _config
->Find("APT::architecture"); 
  40 // ListParser::UniqFindTagWrite - Find the tag and write a unq string   /*{{{*/ 
  41 // --------------------------------------------------------------------- 
  43 unsigned long debListParser::UniqFindTagWrite(const char *Tag
) 
  47    if (Section
.Find(Tag
,Start
,Stop
) == false) 
  49    return WriteUniqString(Start
,Stop 
- Start
); 
  52 // ListParser::Package - Return the package name                        /*{{{*/ 
  53 // --------------------------------------------------------------------- 
  54 /* This is to return the name of the package this section describes */ 
  55 string 
debListParser::Package() 
  57    string Result 
= Section
.FindS("Package"); 
  58    if (Result
.empty() == true) 
  59       _error
->Error("Encountered a section with no Package: header"); 
  63 // ListParser::Version - Return the version string                      /*{{{*/ 
  64 // --------------------------------------------------------------------- 
  65 /* This is to return the string describing the version in debian form, 
  66    epoch:upstream-release. If this returns the blank string then the  
  67    entry is assumed to only describe package properties */ 
  68 string 
debListParser::Version() 
  70    return Section
.FindS("Version"); 
  73 // ListParser::NewVersion - Fill in the version structure               /*{{{*/ 
  74 // --------------------------------------------------------------------- 
  76 bool debListParser::NewVersion(pkgCache::VerIterator Ver
) 
  79    Ver
->Section 
= UniqFindTagWrite("Section"); 
  80    Ver
->Arch 
= UniqFindTagWrite("Architecture"); 
  83    Ver
->Size 
= (unsigned)Section
.FindI("Size"); 
  85    // Unpacked Size (in K) 
  86    Ver
->InstalledSize 
= (unsigned)Section
.FindI("Installed-Size"); 
  87    Ver
->InstalledSize 
*= 1024; 
  92    if (Section
.Find("Priority",Start
,Stop
) == true) 
  94       if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false) 
  95          Ver
->Priority 
= pkgCache::State::Extra
; 
  98    if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false) 
 100    if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false) 
 102    if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false) 
 104    if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false) 
 106    if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false) 
 108    if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false) 
 110    if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false) 
 114    if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false) 
 117    if (ParseProvides(Ver
) == false) 
 123 // ListParser::Description - Return the description string              /*{{{*/ 
 124 // --------------------------------------------------------------------- 
 125 /* This is to return the string describing the package in debian 
 126    form. If this returns the blank string then the entry is assumed to 
 127    only describe package properties */ 
 128 string 
debListParser::Description() 
 130    if (DescriptionLanguage().empty()) 
 131       return Section
.FindS("Description"); 
 133       return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str()); 
 136 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/ 
 137 // --------------------------------------------------------------------- 
 138 /* This is to return the string describing the language of 
 139    description. If this returns the blank string then the entry is 
 140    assumed to describe original description. */ 
 141 string 
debListParser::DescriptionLanguage() 
 143    return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : ""; 
 146 // ListParser::Description - Return the description_md5 MD5SumValue     /*{{{*/ 
 147 // --------------------------------------------------------------------- 
 148 /* This is to return the md5 string to allow the check if it is the right 
 149    description. If no Description-md5 is found in the section it will be 
 152 MD5SumValue 
debListParser::Description_md5() 
 154    string value 
= Section
.FindS("Description-md5"); 
 159       md5
.Add((Description() + "\n").c_str()); 
 162       return MD5SumValue(value
); 
 165 // ListParser::UsePackage - Update a package structure                  /*{{{*/ 
 166 // --------------------------------------------------------------------- 
 167 /* This is called to update the package with any new information  
 168    that might be found in the section */ 
 169 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
, 
 170                                pkgCache::VerIterator Ver
) 
 172    if (Pkg
->Section 
== 0) 
 173       Pkg
->Section 
= UniqFindTagWrite("Section"); 
 174    if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false) 
 176    if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false) 
 179    if (strcmp(Pkg
.Name(),"apt") == 0) 
 180       Pkg
->Flags 
|= pkgCache::Flag::Important
; 
 182    if (ParseStatus(Pkg
,Ver
) == false) 
 187 // ListParser::VersionHash - Compute a unique hash for this version     /*{{{*/ 
 188 // --------------------------------------------------------------------- 
 190 unsigned short debListParser::VersionHash() 
 192    const char *Sections
[] ={"Installed-Size", 
 200    unsigned long Result 
= INIT_FCS
; 
 202    for (const char **I 
= Sections
; *I 
!= 0; I
++) 
 206       if (Section
.Find(*I
,Start
,End
) == false || End 
- Start 
>= (signed)sizeof(S
)) 
 209       /* Strip out any spaces from the text, this undoes dpkgs reformatting 
 210          of certain fields. dpkg also has the rather interesting notion of 
 211          reformatting depends operators < -> <= */ 
 213       for (; Start 
!= End
; Start
++) 
 215          if (isspace(*Start
) == 0) 
 216             *I
++ = tolower(*Start
); 
 217          if (*Start 
== '<' && Start
[1] != '<' && Start
[1] != '=') 
 219          if (*Start 
== '>' && Start
[1] != '>' && Start
[1] != '=') 
 223       Result 
= AddCRC16(Result
,S
,I 
- S
); 
 229 // ListParser::ParseStatus - Parse the status field                     /*{{{*/ 
 230 // --------------------------------------------------------------------- 
 231 /* Status lines are of the form, 
 232      Status: want flag status 
 233    want = unknown, install, hold, deinstall, purge 
 234    flag = ok, reinstreq, hold, hold-reinstreq 
 235    status = not-installed, unpacked, half-configured, 
 236             half-installed, config-files, post-inst-failed,  
 237             removal-failed, installed 
 239    Some of the above are obsolete (I think?) flag = hold-* and  
 240    status = post-inst-failed, removal-failed at least. 
 242 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
, 
 243                                 pkgCache::VerIterator Ver
) 
 247    if (Section
.Find("Status",Start
,Stop
) == false) 
 250    // Isolate the first word 
 251    const char *I 
= Start
; 
 252    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 253    if (I 
>= Stop 
|| *I 
!= ' ') 
 254       return _error
->Error("Malformed Status line"); 
 256    // Process the want field 
 257    WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
}, 
 258                           {"install",pkgCache::State::Install
}, 
 259                           {"hold",pkgCache::State::Hold
}, 
 260                           {"deinstall",pkgCache::State::DeInstall
}, 
 261                           {"purge",pkgCache::State::Purge
}, 
 263    if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false) 
 264       return _error
->Error("Malformed 1st word in the Status line"); 
 266    // Isloate the next word 
 269    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 270    if (I 
>= Stop 
|| *I 
!= ' ') 
 271       return _error
->Error("Malformed status line, no 2nd word"); 
 273    // Process the flag field 
 274    WordList FlagList
[] = {{"ok",pkgCache::State::Ok
}, 
 275                           {"reinstreq",pkgCache::State::ReInstReq
}, 
 276                           {"hold",pkgCache::State::HoldInst
}, 
 277                           {"hold-reinstreq",pkgCache::State::HoldReInstReq
}, 
 279    if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false) 
 280       return _error
->Error("Malformed 2nd word in the Status line"); 
 282    // Isloate the last word 
 285    for(; I 
< Stop 
&& *I 
!= ' '; I
++); 
 287       return _error
->Error("Malformed Status line, no 3rd word"); 
 289    // Process the flag field 
 290    WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
}, 
 291                             {"unpacked",pkgCache::State::UnPacked
}, 
 292                             {"half-configured",pkgCache::State::HalfConfigured
}, 
 293                             {"installed",pkgCache::State::Installed
}, 
 294                             {"half-installed",pkgCache::State::HalfInstalled
}, 
 295                             {"config-files",pkgCache::State::ConfigFiles
}, 
 296                             {"triggers-awaited",pkgCache::State::TriggersAwaited
}, 
 297                             {"triggers-pending",pkgCache::State::TriggersPending
}, 
 298                             {"post-inst-failed",pkgCache::State::HalfConfigured
}, 
 299                             {"removal-failed",pkgCache::State::HalfInstalled
}, 
 301    if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false) 
 302       return _error
->Error("Malformed 3rd word in the Status line"); 
 304    /* A Status line marks the package as indicating the current 
 305       version as well. Only if it is actually installed.. Otherwise 
 306       the interesting dpkg handling of the status file creates bogus  
 308    if (!(Pkg
->CurrentState 
== pkgCache::State::NotInstalled 
|| 
 309          Pkg
->CurrentState 
== pkgCache::State::ConfigFiles
)) 
 311       if (Ver
.end() == true) 
 312          _error
->Warning("Encountered status field in a non-version description"); 
 314          Pkg
->CurrentVer 
= Ver
.Index(); 
 320 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
) 
 322    // Determine the operator 
 330          Op 
= pkgCache::Dep::LessEq
; 
 337          Op 
= pkgCache::Dep::Less
; 
 341       // < is the same as <= and << is really Cs < for some reason 
 342       Op 
= pkgCache::Dep::LessEq
; 
 350          Op 
= pkgCache::Dep::GreaterEq
; 
 357          Op 
= pkgCache::Dep::Greater
; 
 361       // > is the same as >= and >> is really Cs > for some reason 
 362       Op 
= pkgCache::Dep::GreaterEq
; 
 366       Op 
= pkgCache::Dep::Equals
; 
 370       // HACK around bad package definitions 
 372       Op 
= pkgCache::Dep::Equals
; 
 379 // ListParser::ParseDepends - Parse a dependency element                /*{{{*/ 
 380 // --------------------------------------------------------------------- 
 381 /* This parses the dependency elements out of a standard string in place, 
 383 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
, 
 384                                         string 
&Package
,string 
&Ver
, 
 385                                         unsigned int &Op
, bool ParseArchFlags
) 
 387    // Strip off leading space 
 388    for (;Start 
!= Stop 
&& isspace(*Start
) != 0; Start
++); 
 390    // Parse off the package name 
 391    const char *I 
= Start
; 
 392    for (;I 
!= Stop 
&& isspace(*I
) == 0 && *I 
!= '(' && *I 
!= ')' && 
 393         *I 
!= ',' && *I 
!= '|'; I
++); 
 396    if (I 
!= Stop 
&& *I 
== ')') 
 402    // Stash the package name 
 403    Package
.assign(Start
,I 
- Start
); 
 405    // Skip white space to the '(' 
 406    for (;I 
!= Stop 
&& isspace(*I
) != 0 ; I
++); 
 409    if (I 
!= Stop 
&& *I 
== '(') 
 412       for (I
++; I 
!= Stop 
&& isspace(*I
) != 0 ; I
++); 
 415       I 
= ConvertRelation(I
,Op
); 
 418       for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 420       for (;I 
!= Stop 
&& *I 
!= ')'; I
++); 
 421       if (I 
== Stop 
|| Start 
== I
) 
 424       // Skip trailing whitespace 
 426       for (; End 
> Start 
&& isspace(End
[-1]); End
--); 
 428       Ver
.assign(Start
,End
-Start
); 
 434       Op 
= pkgCache::Dep::NoOp
; 
 438    for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 440    if (ParseArchFlags 
== true) 
 442       string arch 
= _config
->Find("APT::Architecture"); 
 444       // Parse an architecture 
 445       if (I 
!= Stop 
&& *I 
== '[') 
 454          bool NegArch 
= false; 
 457             // look for whitespace or ending ']' 
 458             while (End 
!= Stop 
&& !isspace(*End
) && *End 
!= ']')  
 470             if (stringcmp(arch
,I
,End
) == 0) 
 479             for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 486             Package 
= ""; /* not for this arch */ 
 490       for (;I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 493    if (I 
!= Stop 
&& *I 
== '|') 
 494       Op 
|= pkgCache::Dep::Or
; 
 496    if (I 
== Stop 
|| *I 
== ',' || *I 
== '|') 
 499          for (I
++; I 
!= Stop 
&& isspace(*I
) != 0; I
++); 
 506 // ListParser::ParseDepends - Parse a dependency list                   /*{{{*/ 
 507 // --------------------------------------------------------------------- 
 508 /* This is the higher level depends parser. It takes a tag and generates 
 509    a complete depends tree for the given version. */ 
 510 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
, 
 511                                  const char *Tag
,unsigned int Type
) 
 515    if (Section
.Find(Tag
,Start
,Stop
) == false) 
 524       Start 
= ParseDepends(Start
,Stop
,Package
,Version
,Op
); 
 526          return _error
->Error("Problem parsing dependency %s",Tag
); 
 528       if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false) 
 536 // ListParser::ParseProvides - Parse the provides list                  /*{{{*/ 
 537 // --------------------------------------------------------------------- 
 539 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
) 
 543    if (Section
.Find("Provides",Start
,Stop
) == false) 
 552       Start 
= ParseDepends(Start
,Stop
,Package
,Version
,Op
); 
 554          return _error
->Error("Problem parsing Provides line"); 
 555       if (Op 
!= pkgCache::Dep::NoOp
) { 
 556          _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str()); 
 558          if (NewProvides(Ver
,Package
,Version
) == false) 
 569 // ListParser::GrabWord - Matches a word and returns                    /*{{{*/ 
 570 // --------------------------------------------------------------------- 
 571 /* Looks for a word in a list of words - for ParseStatus */ 
 572 bool debListParser::GrabWord(string Word
,WordList 
*List
,unsigned char &Out
) 
 574    for (unsigned int C 
= 0; List
[C
].Str 
!= 0; C
++) 
 576       if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0) 
 585 // ListParser::Step - Move to the next section in the file              /*{{{*/ 
 586 // --------------------------------------------------------------------- 
 587 /* This has to be carefull to only process the correct architecture */ 
 588 bool debListParser::Step() 
 590    iOffset 
= Tags
.Offset(); 
 591    while (Tags
.Step(Section
) == true) 
 593       /* See if this is the correct Architecture, if it isn't then we 
 594          drop the whole section. A missing arch tag only happens (in theory) 
 595          inside the Status file, so that is a positive return */ 
 598       if (Section
.Find("Architecture",Start
,Stop
) == false) 
 601       if (stringcmp(Arch
,Start
,Stop
) == 0) 
 604       if (stringcmp(Start
,Stop
,"all") == 0) 
 607       iOffset 
= Tags
.Offset(); 
 612 // ListParser::LoadReleaseInfo - Load the release information           /*{{{*/ 
 613 // --------------------------------------------------------------------- 
 615 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
, 
 616                                     FileFd 
&File
, string component
) 
 618    pkgTagFile 
Tags(&File
, File
.Size() + 256); // XXX 
 619    pkgTagSection Section
; 
 620    if (Tags
.Step(Section
) == false) 
 623    //mvo: I don't think we need to fill that in (it's unused since apt-0.6) 
 624    //FileI->Architecture = WriteUniqString(Arch); 
 626    // apt-secure does no longer download individual (per-section) Release 
 627    // file. to provide Component pinning we use the section name now 
 628    FileI
->Component 
= WriteUniqString(component
); 
 632    if (Section
.Find("Suite",Start
,Stop
) == true) 
 633       FileI
->Archive 
= WriteUniqString(Start
,Stop 
- Start
); 
 634    if (Section
.Find("Component",Start
,Stop
) == true) 
 635       FileI
->Component 
= WriteUniqString(Start
,Stop 
- Start
); 
 636    if (Section
.Find("Version",Start
,Stop
) == true) 
 637       FileI
->Version 
= WriteUniqString(Start
,Stop 
- Start
); 
 638    if (Section
.Find("Origin",Start
,Stop
) == true) 
 639       FileI
->Origin 
= WriteUniqString(Start
,Stop 
- Start
); 
 640    if (Section
.Find("Label",Start
,Stop
) == true) 
 641       FileI
->Label 
= WriteUniqString(Start
,Stop 
- Start
); 
 642    if (Section
.Find("Architecture",Start
,Stop
) == true) 
 643       FileI
->Architecture 
= WriteUniqString(Start
,Stop 
- Start
); 
 645    if (Section
.FindFlag("NotAutomatic",FileI
->Flags
, 
 646                         pkgCache::Flag::NotAutomatic
) == false) 
 647       _error
->Warning("Bad NotAutomatic flag"); 
 649    return !_error
->PendingError(); 
 652 // ListParser::GetPrio - Convert the priority from a string             /*{{{*/ 
 653 // --------------------------------------------------------------------- 
 655 unsigned char debListParser::GetPrio(string Str
) 
 658    if (GrabWord(Str
,PrioList
,Out
) == false) 
 659       Out 
= pkgCache::State::Extra
;