]>
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/aptconfiguration.h>
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/crc-16.h>
19 #include <apt-pkg/md5.h>
20 #include <apt-pkg/macros.h>
26 static debListParser::WordList PrioList
[] = {{"important",pkgCache::State::Important
},
27 {"required",pkgCache::State::Required
},
28 {"standard",pkgCache::State::Standard
},
29 {"optional",pkgCache::State::Optional
},
30 {"extra",pkgCache::State::Extra
},
33 // ListParser::debListParser - Constructor /*{{{*/
34 // ---------------------------------------------------------------------
35 /* Provide an architecture and only this one and "all" will be accepted
36 in Step(), if no Architecture is given we will accept every arch
37 we would accept in general with checkArchitecture() */
38 debListParser::debListParser(FileFd
*File
, string
const &Arch
) : Tags(File
),
41 this->Arch
= _config
->Find("APT::Architecture");
44 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
45 // ---------------------------------------------------------------------
47 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
51 if (Section
.Find(Tag
,Start
,Stop
) == false)
53 return WriteUniqString(Start
,Stop
- Start
);
56 // ListParser::Package - Return the package name /*{{{*/
57 // ---------------------------------------------------------------------
58 /* This is to return the name of the package this section describes */
59 string
debListParser::Package() {
60 string
const Result
= Section
.FindS("Package");
61 if(unlikely(Result
.empty() == true))
62 _error
->Error("Encountered a section with no Package: header");
66 // ListParser::Architecture - Return the package arch /*{{{*/
67 // ---------------------------------------------------------------------
68 /* This will return the Architecture of the package this section describes
69 Note that architecture "all" packages will get the architecture of the
70 Packages file parsed here. */
71 string
debListParser::Architecture() {
72 string
const Result
= Section
.FindS("Architecture");
73 if (Result
.empty() == true || Result
== "all")
75 if (Arch
.empty() == true)
76 /* FIXME: this is a problem for installed arch all
77 packages as we don't know from which arch this
78 package was installed - and therefore which
79 dependency this package resolves. */
80 return _config
->Find("APT::Architecture");
87 // ListParser::ArchitectureAll /*{{{*/
88 // ---------------------------------------------------------------------
90 bool debListParser::ArchitectureAll() {
91 return Section
.FindS("Architecture") == "all";
94 // ListParser::Version - Return the version string /*{{{*/
95 // ---------------------------------------------------------------------
96 /* This is to return the string describing the version in debian form,
97 epoch:upstream-release. If this returns the blank string then the
98 entry is assumed to only describe package properties */
99 string
debListParser::Version()
101 return Section
.FindS("Version");
104 // ListParser::NewVersion - Fill in the version structure /*{{{*/
105 // ---------------------------------------------------------------------
107 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
110 Ver
->Section
= UniqFindTagWrite("Section");
113 if (Section
.FindS("Architecture") == "all")
114 /* Arch all packages can't have a Multi-Arch field,
115 but we need a special treatment for them nonetheless */
116 Ver
->MultiArch
= pkgCache::Version::All
;
119 string
const MultiArch
= Section
.FindS("Multi-Arch");
120 if (MultiArch
.empty() == true)
121 Ver
->MultiArch
= pkgCache::Version::None
;
122 else if (MultiArch
== "same")
123 Ver
->MultiArch
= pkgCache::Version::Same
;
124 else if (MultiArch
== "foreign")
125 Ver
->MultiArch
= pkgCache::Version::Foreign
;
126 else if (MultiArch
== "allowed")
127 Ver
->MultiArch
= pkgCache::Version::Allowed
;
130 _error
->Warning("Unknown Multi-Arch type »%s« for package »%s«",
131 MultiArch
.c_str(), Section
.FindS("Package").c_str());
132 Ver
->MultiArch
= pkgCache::Version::None
;
137 Ver
->Size
= Section
.FindULL("Size");
138 // Unpacked Size (in K)
139 Ver
->InstalledSize
= Section
.FindULL("Installed-Size");
140 Ver
->InstalledSize
*= 1024;
145 if (Section
.Find("Priority",Start
,Stop
) == true)
147 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
148 Ver
->Priority
= pkgCache::State::Extra
;
151 if (Ver
->MultiArch
== pkgCache::Version::All
)
153 /* We maintain a "pseudo" arch=all package for architecture all versions
154 on which these versions can depend on. This pseudo package is many used
155 for downloading/installing: The other pseudo-packages will degenerate
156 to a NOP in the download/install step - this package will ensure that
157 it is downloaded only one time and installed only one time -- even if
158 the architecture bound versions coming in and out on regular basis. */
159 bool const static multiArch
= APT::Configuration::getArchitectures().size() > 1;
160 if (strcmp(Ver
.Arch(true),"all") == 0)
162 else if (multiArch
== true)
164 // our pseudo packages have no size to not confuse the fetcher
166 Ver
->InstalledSize
= 0;
170 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
172 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
174 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
176 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
178 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
180 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
182 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
184 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
188 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
191 if (ParseProvides(Ver
) == false)
197 // ListParser::Description - Return the description string /*{{{*/
198 // ---------------------------------------------------------------------
199 /* This is to return the string describing the package in debian
200 form. If this returns the blank string then the entry is assumed to
201 only describe package properties */
202 string
debListParser::Description()
204 string
const lang
= DescriptionLanguage();
206 return Section
.FindS("Description");
208 return Section
.FindS(string("Description-").append(lang
).c_str());
211 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
212 // ---------------------------------------------------------------------
213 /* This is to return the string describing the language of
214 description. If this returns the blank string then the entry is
215 assumed to describe original description. */
216 string
debListParser::DescriptionLanguage()
218 if (Section
.FindS("Description").empty() == false)
221 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
222 for (std::vector
<string
>::const_iterator l
= lang
.begin();
223 l
!= lang
.end(); l
++)
224 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
230 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
231 // ---------------------------------------------------------------------
232 /* This is to return the md5 string to allow the check if it is the right
233 description. If no Description-md5 is found in the section it will be
236 MD5SumValue
debListParser::Description_md5()
238 string value
= Section
.FindS("Description-md5");
243 md5
.Add((Description() + "\n").c_str());
246 return MD5SumValue(value
);
249 // ListParser::UsePackage - Update a package structure /*{{{*/
250 // ---------------------------------------------------------------------
251 /* This is called to update the package with any new information
252 that might be found in the section */
253 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
254 pkgCache::VerIterator Ver
)
256 if (Pkg
->Section
== 0)
257 Pkg
->Section
= UniqFindTagWrite("Section");
259 // Packages which are not from the "native" arch doesn't get the essential flag
260 // in the default "native" mode - it is also possible to mark "all" or "none".
261 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
262 string
const static myArch
= _config
->Find("APT::Architecture");
263 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "native");
264 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
266 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
268 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
271 if (strcmp(Pkg
.Name(),"apt") == 0)
272 Pkg
->Flags
|= pkgCache::Flag::Important
;
274 if (ParseStatus(Pkg
,Ver
) == false)
279 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
280 // ---------------------------------------------------------------------
282 unsigned short debListParser::VersionHash()
284 const char *Sections
[] ={"Installed-Size",
292 unsigned long Result
= INIT_FCS
;
294 for (const char **I
= Sections
; *I
!= 0; I
++)
298 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
301 /* Strip out any spaces from the text, this undoes dpkgs reformatting
302 of certain fields. dpkg also has the rather interesting notion of
303 reformatting depends operators < -> <= */
305 for (; Start
!= End
; Start
++)
307 if (isspace(*Start
) == 0)
308 *I
++ = tolower_ascii(*Start
);
309 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
311 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
315 Result
= AddCRC16(Result
,S
,I
- S
);
321 // ListParser::ParseStatus - Parse the status field /*{{{*/
322 // ---------------------------------------------------------------------
323 /* Status lines are of the form,
324 Status: want flag status
325 want = unknown, install, hold, deinstall, purge
326 flag = ok, reinstreq, hold, hold-reinstreq
327 status = not-installed, unpacked, half-configured,
328 half-installed, config-files, post-inst-failed,
329 removal-failed, installed
331 Some of the above are obsolete (I think?) flag = hold-* and
332 status = post-inst-failed, removal-failed at least.
334 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
335 pkgCache::VerIterator Ver
)
339 if (Section
.Find("Status",Start
,Stop
) == false)
342 // UsePackage() is responsible for setting the flag in the default case
343 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
344 if (essential
== true &&
345 Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
348 // Isolate the first word
349 const char *I
= Start
;
350 for(; I
< Stop
&& *I
!= ' '; I
++);
351 if (I
>= Stop
|| *I
!= ' ')
352 return _error
->Error("Malformed Status line");
354 // Process the want field
355 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
356 {"install",pkgCache::State::Install
},
357 {"hold",pkgCache::State::Hold
},
358 {"deinstall",pkgCache::State::DeInstall
},
359 {"purge",pkgCache::State::Purge
},
361 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
362 return _error
->Error("Malformed 1st word in the Status line");
364 // Isloate the next word
367 for(; I
< Stop
&& *I
!= ' '; I
++);
368 if (I
>= Stop
|| *I
!= ' ')
369 return _error
->Error("Malformed status line, no 2nd word");
371 // Process the flag field
372 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
373 {"reinstreq",pkgCache::State::ReInstReq
},
374 {"hold",pkgCache::State::HoldInst
},
375 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
377 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
378 return _error
->Error("Malformed 2nd word in the Status line");
380 // Isloate the last word
383 for(; I
< Stop
&& *I
!= ' '; I
++);
385 return _error
->Error("Malformed Status line, no 3rd word");
387 // Process the flag field
388 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
389 {"unpacked",pkgCache::State::UnPacked
},
390 {"half-configured",pkgCache::State::HalfConfigured
},
391 {"installed",pkgCache::State::Installed
},
392 {"half-installed",pkgCache::State::HalfInstalled
},
393 {"config-files",pkgCache::State::ConfigFiles
},
394 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
395 {"triggers-pending",pkgCache::State::TriggersPending
},
396 {"post-inst-failed",pkgCache::State::HalfConfigured
},
397 {"removal-failed",pkgCache::State::HalfInstalled
},
399 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
400 return _error
->Error("Malformed 3rd word in the Status line");
402 /* A Status line marks the package as indicating the current
403 version as well. Only if it is actually installed.. Otherwise
404 the interesting dpkg handling of the status file creates bogus
406 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
407 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
409 if (Ver
.end() == true)
410 _error
->Warning("Encountered status field in a non-version description");
412 Pkg
->CurrentVer
= Ver
.Index();
418 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
420 // Determine the operator
428 Op
= pkgCache::Dep::LessEq
;
435 Op
= pkgCache::Dep::Less
;
439 // < is the same as <= and << is really Cs < for some reason
440 Op
= pkgCache::Dep::LessEq
;
448 Op
= pkgCache::Dep::GreaterEq
;
455 Op
= pkgCache::Dep::Greater
;
459 // > is the same as >= and >> is really Cs > for some reason
460 Op
= pkgCache::Dep::GreaterEq
;
464 Op
= pkgCache::Dep::Equals
;
468 // HACK around bad package definitions
470 Op
= pkgCache::Dep::Equals
;
479 * The complete architecture, consisting of <kernel>-<cpu>.
481 static string
CompleteArch(std::string
& arch
) {
482 return (arch
.find("-") != string::npos
) ? arch
: "linux-" + arch
;
485 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
486 // ---------------------------------------------------------------------
487 /* This parses the dependency elements out of a standard string in place,
489 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
490 string
&Package
,string
&Ver
,
491 unsigned int &Op
, bool const &ParseArchFlags
,
492 bool const &StripMultiArch
)
494 // Strip off leading space
495 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
497 // Parse off the package name
498 const char *I
= Start
;
499 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
500 *I
!= ',' && *I
!= '|'; I
++);
503 if (I
!= Stop
&& *I
== ')')
509 // Stash the package name
510 Package
.assign(Start
,I
- Start
);
512 // We don't want to confuse library users which can't handle MultiArch
513 if (StripMultiArch
== true) {
514 size_t const found
= Package
.rfind(':');
515 if (found
!= string::npos
)
516 Package
= Package
.substr(0,found
);
519 // Skip white space to the '('
520 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
523 if (I
!= Stop
&& *I
== '(')
526 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
529 I
= ConvertRelation(I
,Op
);
532 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
534 for (;I
!= Stop
&& *I
!= ')'; I
++);
535 if (I
== Stop
|| Start
== I
)
538 // Skip trailing whitespace
540 for (; End
> Start
&& isspace(End
[-1]); End
--);
542 Ver
.assign(Start
,End
-Start
);
548 Op
= pkgCache::Dep::NoOp
;
552 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
554 if (ParseArchFlags
== true)
556 string arch
= _config
->Find("APT::Architecture");
557 string completeArch
= CompleteArch(arch
);
559 // Parse an architecture
560 if (I
!= Stop
&& *I
== '[')
569 bool NegArch
= false;
572 // look for whitespace or ending ']'
573 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
585 if (stringcmp(arch
,I
,End
) == 0) {
588 std::string wildcard
= SubstVar(string(I
, End
), "any", "*");
589 if (fnmatch(wildcard
.c_str(), completeArch
.c_str(), 0) == 0)
599 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
606 Package
= ""; /* not for this arch */
610 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
613 if (I
!= Stop
&& *I
== '|')
614 Op
|= pkgCache::Dep::Or
;
616 if (I
== Stop
|| *I
== ',' || *I
== '|')
619 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
626 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
627 // ---------------------------------------------------------------------
628 /* This is the higher level depends parser. It takes a tag and generates
629 a complete depends tree for the given version. */
630 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
631 const char *Tag
,unsigned int Type
)
635 if (Section
.Find(Tag
,Start
,Stop
) == false)
638 static std::vector
<std::string
> const archs
= APT::Configuration::getArchitectures();
639 static bool const multiArch
= archs
.size() <= 1;
642 string
const pkgArch
= Ver
.Arch(true);
648 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
650 return _error
->Error("Problem parsing dependency %s",Tag
);
652 if (multiArch
== true &&
653 (Type
== pkgCache::Dep::Conflicts
||
654 Type
== pkgCache::Dep::DpkgBreaks
||
655 Type
== pkgCache::Dep::Replaces
))
657 for (std::vector
<std::string
>::const_iterator a
= archs
.begin();
658 a
!= archs
.end(); ++a
)
659 if (NewDepends(Ver
,Package
,*a
,Version
,Op
,Type
) == false)
662 else if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
670 // ListParser::ParseProvides - Parse the provides list /*{{{*/
671 // ---------------------------------------------------------------------
673 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
677 if (Section
.Find("Provides",Start
,Stop
) == true)
681 string
const Arch
= Ver
.Arch(true);
686 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
688 return _error
->Error("Problem parsing Provides line");
689 if (Op
!= pkgCache::Dep::NoOp
) {
690 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
692 if (NewProvides(Ver
, Package
, Arch
, Version
) == false)
701 if (Ver
->MultiArch
== pkgCache::Version::Allowed
)
703 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
704 NewProvides(Ver
, Package
, "any", Ver
.VerStr());
707 if (Ver
->MultiArch
!= pkgCache::Version::Foreign
)
710 std::vector
<string
> const archs
= APT::Configuration::getArchitectures();
711 if (archs
.size() <= 1)
714 string
const Package
= Ver
.ParentPkg().Name();
715 string
const Version
= Ver
.VerStr();
716 for (std::vector
<string
>::const_iterator a
= archs
.begin();
717 a
!= archs
.end(); ++a
)
719 if (NewProvides(Ver
, Package
, *a
, Version
) == false)
726 // ListParser::GrabWord - Matches a word and returns /*{{{*/
727 // ---------------------------------------------------------------------
728 /* Looks for a word in a list of words - for ParseStatus */
729 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
731 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
733 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
742 // ListParser::Step - Move to the next section in the file /*{{{*/
743 // ---------------------------------------------------------------------
744 /* This has to be carefull to only process the correct architecture */
745 bool debListParser::Step()
747 iOffset
= Tags
.Offset();
748 while (Tags
.Step(Section
) == true)
750 /* See if this is the correct Architecture, if it isn't then we
751 drop the whole section. A missing arch tag only happens (in theory)
752 inside the Status file, so that is a positive return */
753 string
const Architecture
= Section
.FindS("Architecture");
754 if (Architecture
.empty() == true)
757 if (Arch
.empty() == true)
759 if (APT::Configuration::checkArchitecture(Architecture
) == true)
764 if (Architecture
== Arch
)
767 if (Architecture
== "all")
771 iOffset
= Tags
.Offset();
776 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
777 // ---------------------------------------------------------------------
779 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
780 FileFd
&File
, string component
)
782 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
783 pkgTagSection Section
;
784 if (Tags
.Step(Section
) == false)
787 // FIXME: Do we need it now for multi-arch?
788 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
789 // FileI->Architecture = WriteUniqString(Arch);
791 // apt-secure does no longer download individual (per-section) Release
792 // file. to provide Component pinning we use the section name now
793 FileI
->Component
= WriteUniqString(component
);
797 if (Section
.Find("Suite",Start
,Stop
) == true)
798 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
799 if (Section
.Find("Component",Start
,Stop
) == true)
800 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
801 if (Section
.Find("Version",Start
,Stop
) == true)
802 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
803 if (Section
.Find("Origin",Start
,Stop
) == true)
804 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
805 if (Section
.Find("Codename",Start
,Stop
) == true)
806 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
807 if (Section
.Find("Label",Start
,Stop
) == true)
808 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
809 if (Section
.Find("Architecture",Start
,Stop
) == true)
810 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
812 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
813 pkgCache::Flag::NotAutomatic
) == false)
814 _error
->Warning("Bad NotAutomatic flag");
816 return !_error
->PendingError();
819 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
820 // ---------------------------------------------------------------------
822 unsigned char debListParser::GetPrio(string Str
)
825 if (GrabWord(Str
,PrioList
,Out
) == false)
826 Out
= pkgCache::State::Extra
;