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>
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") {
74 if (Arch
.empty() == true)
75 /* FIXME: this is a problem for installed arch all
76 packages as we don't know from which arch this
77 package was installed - and therefore which
78 dependency this package resolves. */
79 return _config
->Find("APT::Architecture");
86 // ListParser::ArchitectureAll /*{{{*/
87 // ---------------------------------------------------------------------
89 bool debListParser::ArchitectureAll() {
90 return Section
.FindS("Architecture") == "all";
93 // ListParser::Version - Return the version string /*{{{*/
94 // ---------------------------------------------------------------------
95 /* This is to return the string describing the version in debian form,
96 epoch:upstream-release. If this returns the blank string then the
97 entry is assumed to only describe package properties */
98 string
debListParser::Version()
100 return Section
.FindS("Version");
103 // ListParser::NewVersion - Fill in the version structure /*{{{*/
104 // ---------------------------------------------------------------------
106 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
109 Ver
->Section
= UniqFindTagWrite("Section");
112 if (Section
.FindS("Architecture") == "all")
113 /* Arch all packages can't have a Multi-Arch field,
114 but we need a special treatment for them nonetheless */
115 Ver
->MultiArch
= pkgCache::Version::All
;
118 string
const MultiArch
= Section
.FindS("Multi-Arch");
119 if (MultiArch
.empty() == true)
120 Ver
->MultiArch
= pkgCache::Version::None
;
121 else if (MultiArch
== "same")
122 Ver
->MultiArch
= pkgCache::Version::Same
;
123 else if (MultiArch
== "foreign")
124 Ver
->MultiArch
= pkgCache::Version::Foreign
;
125 else if (MultiArch
== "allowed")
126 Ver
->MultiArch
= pkgCache::Version::Allowed
;
129 _error
->Warning("Unknown Multi-Arch type »%s« for package »%s«",
130 MultiArch
.c_str(), Section
.FindS("Package").c_str());
131 Ver
->MultiArch
= pkgCache::Version::None
;
136 Ver
->Size
= (unsigned)Section
.FindI("Size");
138 // Unpacked Size (in K)
139 Ver
->InstalledSize
= (unsigned)Section
.FindI("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 (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
153 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
155 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
157 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
159 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
161 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
163 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
165 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
169 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
172 if (ParseProvides(Ver
) == false)
178 // ListParser::Description - Return the description string /*{{{*/
179 // ---------------------------------------------------------------------
180 /* This is to return the string describing the package in debian
181 form. If this returns the blank string then the entry is assumed to
182 only describe package properties */
183 string
debListParser::Description()
185 string
const lang
= DescriptionLanguage();
187 return Section
.FindS("Description");
189 return Section
.FindS(string("Description-").append(lang
).c_str());
192 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
193 // ---------------------------------------------------------------------
194 /* This is to return the string describing the language of
195 description. If this returns the blank string then the entry is
196 assumed to describe original description. */
197 string
debListParser::DescriptionLanguage()
199 if (Section
.FindS("Description").empty() == false)
202 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
203 for (std::vector
<string
>::const_iterator l
= lang
.begin();
204 l
!= lang
.end(); l
++)
205 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
211 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
212 // ---------------------------------------------------------------------
213 /* This is to return the md5 string to allow the check if it is the right
214 description. If no Description-md5 is found in the section it will be
217 MD5SumValue
debListParser::Description_md5()
219 string value
= Section
.FindS("Description-md5");
224 md5
.Add((Description() + "\n").c_str());
227 return MD5SumValue(value
);
230 // ListParser::UsePackage - Update a package structure /*{{{*/
231 // ---------------------------------------------------------------------
232 /* This is called to update the package with any new information
233 that might be found in the section */
234 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
235 pkgCache::VerIterator Ver
)
237 if (Pkg
->Section
== 0)
238 Pkg
->Section
= UniqFindTagWrite("Section");
240 // Packages which are not from "our" arch doesn't get the essential flag
241 string
const static myArch
= _config
->Find("APT::Architecture");
242 if (Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch())
243 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
245 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
248 if (strcmp(Pkg
.Name(),"apt") == 0)
249 Pkg
->Flags
|= pkgCache::Flag::Important
;
251 if (ParseStatus(Pkg
,Ver
) == false)
256 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
257 // ---------------------------------------------------------------------
259 unsigned short debListParser::VersionHash()
261 const char *Sections
[] ={"Installed-Size",
269 unsigned long Result
= INIT_FCS
;
271 for (const char **I
= Sections
; *I
!= 0; I
++)
275 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
278 /* Strip out any spaces from the text, this undoes dpkgs reformatting
279 of certain fields. dpkg also has the rather interesting notion of
280 reformatting depends operators < -> <= */
282 for (; Start
!= End
; Start
++)
284 if (isspace(*Start
) == 0)
285 *I
++ = tolower_ascii(*Start
);
286 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
288 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
292 Result
= AddCRC16(Result
,S
,I
- S
);
298 // ListParser::ParseStatus - Parse the status field /*{{{*/
299 // ---------------------------------------------------------------------
300 /* Status lines are of the form,
301 Status: want flag status
302 want = unknown, install, hold, deinstall, purge
303 flag = ok, reinstreq, hold, hold-reinstreq
304 status = not-installed, unpacked, half-configured,
305 half-installed, config-files, post-inst-failed,
306 removal-failed, installed
308 Some of the above are obsolete (I think?) flag = hold-* and
309 status = post-inst-failed, removal-failed at least.
311 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
312 pkgCache::VerIterator Ver
)
316 if (Section
.Find("Status",Start
,Stop
) == false)
319 // Isolate the first word
320 const char *I
= Start
;
321 for(; I
< Stop
&& *I
!= ' '; I
++);
322 if (I
>= Stop
|| *I
!= ' ')
323 return _error
->Error("Malformed Status line");
325 // Process the want field
326 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
327 {"install",pkgCache::State::Install
},
328 {"hold",pkgCache::State::Hold
},
329 {"deinstall",pkgCache::State::DeInstall
},
330 {"purge",pkgCache::State::Purge
},
332 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
333 return _error
->Error("Malformed 1st word in the Status line");
335 // Isloate the next word
338 for(; I
< Stop
&& *I
!= ' '; I
++);
339 if (I
>= Stop
|| *I
!= ' ')
340 return _error
->Error("Malformed status line, no 2nd word");
342 // Process the flag field
343 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
344 {"reinstreq",pkgCache::State::ReInstReq
},
345 {"hold",pkgCache::State::HoldInst
},
346 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
348 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
349 return _error
->Error("Malformed 2nd word in the Status line");
351 // Isloate the last word
354 for(; I
< Stop
&& *I
!= ' '; I
++);
356 return _error
->Error("Malformed Status line, no 3rd word");
358 // Process the flag field
359 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
360 {"unpacked",pkgCache::State::UnPacked
},
361 {"half-configured",pkgCache::State::HalfConfigured
},
362 {"installed",pkgCache::State::Installed
},
363 {"half-installed",pkgCache::State::HalfInstalled
},
364 {"config-files",pkgCache::State::ConfigFiles
},
365 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
366 {"triggers-pending",pkgCache::State::TriggersPending
},
367 {"post-inst-failed",pkgCache::State::HalfConfigured
},
368 {"removal-failed",pkgCache::State::HalfInstalled
},
370 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
371 return _error
->Error("Malformed 3rd word in the Status line");
373 /* A Status line marks the package as indicating the current
374 version as well. Only if it is actually installed.. Otherwise
375 the interesting dpkg handling of the status file creates bogus
377 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
378 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
380 if (Ver
.end() == true)
381 _error
->Warning("Encountered status field in a non-version description");
383 Pkg
->CurrentVer
= Ver
.Index();
389 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
391 // Determine the operator
399 Op
= pkgCache::Dep::LessEq
;
406 Op
= pkgCache::Dep::Less
;
410 // < is the same as <= and << is really Cs < for some reason
411 Op
= pkgCache::Dep::LessEq
;
419 Op
= pkgCache::Dep::GreaterEq
;
426 Op
= pkgCache::Dep::Greater
;
430 // > is the same as >= and >> is really Cs > for some reason
431 Op
= pkgCache::Dep::GreaterEq
;
435 Op
= pkgCache::Dep::Equals
;
439 // HACK around bad package definitions
441 Op
= pkgCache::Dep::Equals
;
448 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
449 // ---------------------------------------------------------------------
450 /* This parses the dependency elements out of a standard string in place,
452 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
453 string
&Package
,string
&Ver
,
454 unsigned int &Op
, bool const &ParseArchFlags
,
455 bool const &StripMultiArch
)
457 // Strip off leading space
458 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
460 // Parse off the package name
461 const char *I
= Start
;
462 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
463 *I
!= ',' && *I
!= '|'; I
++);
466 if (I
!= Stop
&& *I
== ')')
472 // Stash the package name
473 Package
.assign(Start
,I
- Start
);
475 // We don't want to confuse library users which can't handle MultiArch
476 if (StripMultiArch
== true) {
477 size_t const found
= Package
.rfind(':');
478 if (found
!= string::npos
)
479 Package
= Package
.substr(0,found
);
482 // Skip white space to the '('
483 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
486 if (I
!= Stop
&& *I
== '(')
489 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
492 I
= ConvertRelation(I
,Op
);
495 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
497 for (;I
!= Stop
&& *I
!= ')'; I
++);
498 if (I
== Stop
|| Start
== I
)
501 // Skip trailing whitespace
503 for (; End
> Start
&& isspace(End
[-1]); End
--);
505 Ver
.assign(Start
,End
-Start
);
511 Op
= pkgCache::Dep::NoOp
;
515 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
517 if (ParseArchFlags
== true)
519 string arch
= _config
->Find("APT::Architecture");
521 // Parse an architecture
522 if (I
!= Stop
&& *I
== '[')
531 bool NegArch
= false;
534 // look for whitespace or ending ']'
535 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
547 if (stringcmp(arch
,I
,End
) == 0)
556 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
563 Package
= ""; /* not for this arch */
567 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
570 if (I
!= Stop
&& *I
== '|')
571 Op
|= pkgCache::Dep::Or
;
573 if (I
== Stop
|| *I
== ',' || *I
== '|')
576 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
583 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
584 // ---------------------------------------------------------------------
585 /* This is the higher level depends parser. It takes a tag and generates
586 a complete depends tree for the given version. */
587 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
588 const char *Tag
,unsigned int Type
)
592 if (Section
.Find(Tag
,Start
,Stop
) == false)
596 string
const pkgArch
= Ver
.Arch();
602 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
604 return _error
->Error("Problem parsing dependency %s",Tag
);
606 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
614 // ListParser::ParseProvides - Parse the provides list /*{{{*/
615 // ---------------------------------------------------------------------
617 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
621 if (Section
.Find("Provides",Start
,Stop
) == true)
625 string
const Arch
= Ver
.Arch();
630 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
632 return _error
->Error("Problem parsing Provides line");
633 if (Op
!= pkgCache::Dep::NoOp
) {
634 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
636 if (NewProvides(Ver
, Package
, Arch
, Version
) == false)
645 if (Ver
->MultiArch
== pkgCache::Version::Allowed
)
647 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
648 NewProvides(Ver
, Package
, "any", Ver
.VerStr());
651 if (Ver
->MultiArch
!= pkgCache::Version::Foreign
)
654 std::vector
<string
> const archs
= APT::Configuration::getArchitectures();
655 if (archs
.size() <= 1)
658 string
const Package
= Ver
.ParentPkg().Name();
659 string
const Version
= Ver
.VerStr();
660 for (std::vector
<string
>::const_iterator a
= archs
.begin();
661 a
!= archs
.end(); ++a
)
663 if (NewProvides(Ver
, Package
, *a
, Version
) == false)
670 // ListParser::GrabWord - Matches a word and returns /*{{{*/
671 // ---------------------------------------------------------------------
672 /* Looks for a word in a list of words - for ParseStatus */
673 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
675 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
677 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
686 // ListParser::Step - Move to the next section in the file /*{{{*/
687 // ---------------------------------------------------------------------
688 /* This has to be carefull to only process the correct architecture */
689 bool debListParser::Step()
691 iOffset
= Tags
.Offset();
692 while (Tags
.Step(Section
) == true)
694 /* See if this is the correct Architecture, if it isn't then we
695 drop the whole section. A missing arch tag only happens (in theory)
696 inside the Status file, so that is a positive return */
697 string
const Architecture
= Section
.FindS("Architecture");
698 if (Architecture
.empty() == true)
701 if (Arch
.empty() == true)
703 if (APT::Configuration::checkArchitecture(Architecture
) == true)
708 if (Architecture
== Arch
)
711 if (Architecture
== "all")
715 iOffset
= Tags
.Offset();
720 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
721 // ---------------------------------------------------------------------
723 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
724 FileFd
&File
, string component
)
726 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
727 pkgTagSection Section
;
728 if (Tags
.Step(Section
) == false)
731 // FIXME: Do we need it now for multi-arch?
732 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
733 // FileI->Architecture = WriteUniqString(Arch);
735 // apt-secure does no longer download individual (per-section) Release
736 // file. to provide Component pinning we use the section name now
737 FileI
->Component
= WriteUniqString(component
);
741 if (Section
.Find("Suite",Start
,Stop
) == true)
742 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
743 if (Section
.Find("Component",Start
,Stop
) == true)
744 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
745 if (Section
.Find("Version",Start
,Stop
) == true)
746 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
747 if (Section
.Find("Origin",Start
,Stop
) == true)
748 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
749 if (Section
.Find("Codename",Start
,Stop
) == true)
750 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
751 if (Section
.Find("Label",Start
,Stop
) == true)
752 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
753 if (Section
.Find("Architecture",Start
,Stop
) == true)
754 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
756 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
757 pkgCache::Flag::NotAutomatic
) == false)
758 _error
->Warning("Bad NotAutomatic flag");
760 return !_error
->PendingError();
763 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
764 // ---------------------------------------------------------------------
766 unsigned char debListParser::GetPrio(string Str
)
769 if (GrabWord(Str
,PrioList
,Out
) == false)
770 Out
= pkgCache::State::Extra
;