]>
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>
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 // ---------------------------------------------------------------------
34 /* Provide an architecture and only this one and "all" will be accepted
35 in Step(), if no Architecture is given we will accept every arch
36 we would accept in general with checkArchitecture() */
37 debListParser::debListParser(FileFd
*File
, string
const &Arch
) : Tags(File
),
40 this->Arch
= _config
->Find("APT::Architecture");
43 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
44 // ---------------------------------------------------------------------
46 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
50 if (Section
.Find(Tag
,Start
,Stop
) == false)
52 return WriteUniqString(Start
,Stop
- Start
);
55 // ListParser::Package - Return the package name /*{{{*/
56 // ---------------------------------------------------------------------
57 /* This is to return the name of the package this section describes */
58 string
debListParser::Package() {
59 string
const Result
= Section
.FindS("Package");
60 if(unlikely(Result
.empty() == true))
61 _error
->Error("Encountered a section with no Package: header");
65 // ListParser::Architecture - Return the package arch /*{{{*/
66 // ---------------------------------------------------------------------
67 /* This will return the Architecture of the package this section describes
68 Note that architecture "all" packages will get the architecture of the
69 Packages file parsed here. */
70 string
debListParser::Architecture() {
71 string
const Result
= Section
.FindS("Architecture");
72 if (Result
.empty() == true || Result
== "all") {
73 if (Arch
.empty() == true)
74 /* FIXME: this is a problem for installed arch all
75 packages as we don't know from which arch this
76 package was installed - and therefore which
77 dependency this package resolves. */
78 return _config
->Find("APT::Architecture");
85 // ListParser::ArchitectureAll /*{{{*/
86 // ---------------------------------------------------------------------
88 bool debListParser::ArchitectureAll() {
89 return Section
.FindS("Architecture") == "all";
92 // ListParser::Version - Return the version string /*{{{*/
93 // ---------------------------------------------------------------------
94 /* This is to return the string describing the version in debian form,
95 epoch:upstream-release. If this returns the blank string then the
96 entry is assumed to only describe package properties */
97 string
debListParser::Version()
99 return Section
.FindS("Version");
102 // ListParser::NewVersion - Fill in the version structure /*{{{*/
103 // ---------------------------------------------------------------------
105 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
108 Ver
->Section
= UniqFindTagWrite("Section");
111 if (Section
.FindS("Architecture") == "all")
112 /* Arch all packages can't have a Multi-Arch field,
113 but we need a special treatment for them nonetheless */
114 Ver
->MultiArch
= pkgCache::Version::All
;
117 string
const MultiArch
= Section
.FindS("Multi-Arch");
118 if (MultiArch
.empty() == true)
119 Ver
->MultiArch
= pkgCache::Version::None
;
120 else if (MultiArch
== "same")
121 Ver
->MultiArch
= pkgCache::Version::Same
;
122 else if (MultiArch
== "foreign")
123 Ver
->MultiArch
= pkgCache::Version::Foreign
;
124 else if (MultiArch
== "allowed")
125 Ver
->MultiArch
= pkgCache::Version::Allowed
;
128 _error
->Warning("Unknown Multi-Arch type »%s« for package »%s«",
129 MultiArch
.c_str(), Section
.FindS("Package").c_str());
130 Ver
->MultiArch
= pkgCache::Version::None
;
135 Ver
->Size
= (unsigned)Section
.FindI("Size");
137 // Unpacked Size (in K)
138 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
139 Ver
->InstalledSize
*= 1024;
144 if (Section
.Find("Priority",Start
,Stop
) == true)
146 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
147 Ver
->Priority
= pkgCache::State::Extra
;
150 if (Ver
->MultiArch
== pkgCache::Version::All
)
152 /* We maintain a "pseudo" arch=all package for architecture all versions
153 on which these versions can depend on. This pseudo package is many used
154 for downloading/installing: The other pseudo-packages will degenerate
155 to a NOP in the download/install step - this package will ensure that
156 it is downloaded only one time and installed only one time -- even if
157 the architecture bound versions coming in and out on regular basis. */
158 if (strcmp(Ver
.Arch(true),"all") == 0)
160 else if (Ver
.Pseudo() == true)
162 // our pseudo packages have no size to not confuse the fetcher
164 Ver
->InstalledSize
= 0;
168 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
170 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
172 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
174 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
176 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
178 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
180 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
182 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
186 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
189 if (ParseProvides(Ver
) == false)
195 // ListParser::Description - Return the description string /*{{{*/
196 // ---------------------------------------------------------------------
197 /* This is to return the string describing the package in debian
198 form. If this returns the blank string then the entry is assumed to
199 only describe package properties */
200 string
debListParser::Description()
202 string
const lang
= DescriptionLanguage();
204 return Section
.FindS("Description");
206 return Section
.FindS(string("Description-").append(lang
).c_str());
209 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
210 // ---------------------------------------------------------------------
211 /* This is to return the string describing the language of
212 description. If this returns the blank string then the entry is
213 assumed to describe original description. */
214 string
debListParser::DescriptionLanguage()
216 if (Section
.FindS("Description").empty() == false)
219 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
220 for (std::vector
<string
>::const_iterator l
= lang
.begin();
221 l
!= lang
.end(); l
++)
222 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
228 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
229 // ---------------------------------------------------------------------
230 /* This is to return the md5 string to allow the check if it is the right
231 description. If no Description-md5 is found in the section it will be
234 MD5SumValue
debListParser::Description_md5()
236 string value
= Section
.FindS("Description-md5");
241 md5
.Add((Description() + "\n").c_str());
244 return MD5SumValue(value
);
247 // ListParser::UsePackage - Update a package structure /*{{{*/
248 // ---------------------------------------------------------------------
249 /* This is called to update the package with any new information
250 that might be found in the section */
251 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
252 pkgCache::VerIterator Ver
)
254 if (Pkg
->Section
== 0)
255 Pkg
->Section
= UniqFindTagWrite("Section");
257 // Packages which are not from "our" arch doesn't get the essential flag
258 string
const static myArch
= _config
->Find("APT::Architecture");
259 if (Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch())
260 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
262 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
265 if (strcmp(Pkg
.Name(),"apt") == 0)
266 Pkg
->Flags
|= pkgCache::Flag::Important
;
268 if (ParseStatus(Pkg
,Ver
) == false)
273 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
274 // ---------------------------------------------------------------------
276 unsigned short debListParser::VersionHash()
278 const char *Sections
[] ={"Installed-Size",
286 unsigned long Result
= INIT_FCS
;
288 for (const char **I
= Sections
; *I
!= 0; I
++)
292 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
295 /* Strip out any spaces from the text, this undoes dpkgs reformatting
296 of certain fields. dpkg also has the rather interesting notion of
297 reformatting depends operators < -> <= */
299 for (; Start
!= End
; Start
++)
301 if (isspace(*Start
) == 0)
302 *I
++ = tolower_ascii(*Start
);
303 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
305 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
309 Result
= AddCRC16(Result
,S
,I
- S
);
315 // ListParser::ParseStatus - Parse the status field /*{{{*/
316 // ---------------------------------------------------------------------
317 /* Status lines are of the form,
318 Status: want flag status
319 want = unknown, install, hold, deinstall, purge
320 flag = ok, reinstreq, hold, hold-reinstreq
321 status = not-installed, unpacked, half-configured,
322 half-installed, config-files, post-inst-failed,
323 removal-failed, installed
325 Some of the above are obsolete (I think?) flag = hold-* and
326 status = post-inst-failed, removal-failed at least.
328 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
329 pkgCache::VerIterator Ver
)
333 if (Section
.Find("Status",Start
,Stop
) == false)
336 // Isolate the first word
337 const char *I
= Start
;
338 for(; I
< Stop
&& *I
!= ' '; I
++);
339 if (I
>= Stop
|| *I
!= ' ')
340 return _error
->Error("Malformed Status line");
342 // Process the want field
343 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
344 {"install",pkgCache::State::Install
},
345 {"hold",pkgCache::State::Hold
},
346 {"deinstall",pkgCache::State::DeInstall
},
347 {"purge",pkgCache::State::Purge
},
349 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
350 return _error
->Error("Malformed 1st word in the Status line");
352 // Isloate the next word
355 for(; I
< Stop
&& *I
!= ' '; I
++);
356 if (I
>= Stop
|| *I
!= ' ')
357 return _error
->Error("Malformed status line, no 2nd word");
359 // Process the flag field
360 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
361 {"reinstreq",pkgCache::State::ReInstReq
},
362 {"hold",pkgCache::State::HoldInst
},
363 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
365 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
366 return _error
->Error("Malformed 2nd word in the Status line");
368 // Isloate the last word
371 for(; I
< Stop
&& *I
!= ' '; I
++);
373 return _error
->Error("Malformed Status line, no 3rd word");
375 // Process the flag field
376 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
377 {"unpacked",pkgCache::State::UnPacked
},
378 {"half-configured",pkgCache::State::HalfConfigured
},
379 {"installed",pkgCache::State::Installed
},
380 {"half-installed",pkgCache::State::HalfInstalled
},
381 {"config-files",pkgCache::State::ConfigFiles
},
382 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
383 {"triggers-pending",pkgCache::State::TriggersPending
},
384 {"post-inst-failed",pkgCache::State::HalfConfigured
},
385 {"removal-failed",pkgCache::State::HalfInstalled
},
387 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
388 return _error
->Error("Malformed 3rd word in the Status line");
390 /* A Status line marks the package as indicating the current
391 version as well. Only if it is actually installed.. Otherwise
392 the interesting dpkg handling of the status file creates bogus
394 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
395 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
397 if (Ver
.end() == true)
398 _error
->Warning("Encountered status field in a non-version description");
400 Pkg
->CurrentVer
= Ver
.Index();
406 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
408 // Determine the operator
416 Op
= pkgCache::Dep::LessEq
;
423 Op
= pkgCache::Dep::Less
;
427 // < is the same as <= and << is really Cs < for some reason
428 Op
= pkgCache::Dep::LessEq
;
436 Op
= pkgCache::Dep::GreaterEq
;
443 Op
= pkgCache::Dep::Greater
;
447 // > is the same as >= and >> is really Cs > for some reason
448 Op
= pkgCache::Dep::GreaterEq
;
452 Op
= pkgCache::Dep::Equals
;
456 // HACK around bad package definitions
458 Op
= pkgCache::Dep::Equals
;
465 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
466 // ---------------------------------------------------------------------
467 /* This parses the dependency elements out of a standard string in place,
469 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
470 string
&Package
,string
&Ver
,
471 unsigned int &Op
, bool const &ParseArchFlags
,
472 bool const &StripMultiArch
)
474 // Strip off leading space
475 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
477 // Parse off the package name
478 const char *I
= Start
;
479 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
480 *I
!= ',' && *I
!= '|'; I
++);
483 if (I
!= Stop
&& *I
== ')')
489 // Stash the package name
490 Package
.assign(Start
,I
- Start
);
492 // We don't want to confuse library users which can't handle MultiArch
493 if (StripMultiArch
== true) {
494 size_t const found
= Package
.rfind(':');
495 if (found
!= string::npos
)
496 Package
= Package
.substr(0,found
);
499 // Skip white space to the '('
500 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
503 if (I
!= Stop
&& *I
== '(')
506 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
509 I
= ConvertRelation(I
,Op
);
512 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
514 for (;I
!= Stop
&& *I
!= ')'; I
++);
515 if (I
== Stop
|| Start
== I
)
518 // Skip trailing whitespace
520 for (; End
> Start
&& isspace(End
[-1]); End
--);
522 Ver
.assign(Start
,End
-Start
);
528 Op
= pkgCache::Dep::NoOp
;
532 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
534 if (ParseArchFlags
== true)
536 string arch
= _config
->Find("APT::Architecture");
538 // Parse an architecture
539 if (I
!= Stop
&& *I
== '[')
548 bool NegArch
= false;
551 // look for whitespace or ending ']'
552 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
564 if (stringcmp(arch
,I
,End
) == 0)
573 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
580 Package
= ""; /* not for this arch */
584 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
587 if (I
!= Stop
&& *I
== '|')
588 Op
|= pkgCache::Dep::Or
;
590 if (I
== Stop
|| *I
== ',' || *I
== '|')
593 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
600 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
601 // ---------------------------------------------------------------------
602 /* This is the higher level depends parser. It takes a tag and generates
603 a complete depends tree for the given version. */
604 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
605 const char *Tag
,unsigned int Type
)
609 if (Section
.Find(Tag
,Start
,Stop
) == false)
613 string
const pkgArch
= Ver
.Arch(true);
619 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
621 return _error
->Error("Problem parsing dependency %s",Tag
);
623 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
631 // ListParser::ParseProvides - Parse the provides list /*{{{*/
632 // ---------------------------------------------------------------------
634 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
638 if (Section
.Find("Provides",Start
,Stop
) == true)
642 string
const Arch
= Ver
.Arch(true);
647 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
649 return _error
->Error("Problem parsing Provides line");
650 if (Op
!= pkgCache::Dep::NoOp
) {
651 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
653 if (NewProvides(Ver
, Package
, Arch
, Version
) == false)
662 if (Ver
->MultiArch
== pkgCache::Version::Allowed
)
664 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
665 NewProvides(Ver
, Package
, "any", Ver
.VerStr());
668 if (Ver
->MultiArch
!= pkgCache::Version::Foreign
)
671 std::vector
<string
> const archs
= APT::Configuration::getArchitectures();
672 if (archs
.size() <= 1)
675 string
const Package
= Ver
.ParentPkg().Name();
676 string
const Version
= Ver
.VerStr();
677 for (std::vector
<string
>::const_iterator a
= archs
.begin();
678 a
!= archs
.end(); ++a
)
680 if (NewProvides(Ver
, Package
, *a
, Version
) == false)
687 // ListParser::GrabWord - Matches a word and returns /*{{{*/
688 // ---------------------------------------------------------------------
689 /* Looks for a word in a list of words - for ParseStatus */
690 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
692 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
694 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
703 // ListParser::Step - Move to the next section in the file /*{{{*/
704 // ---------------------------------------------------------------------
705 /* This has to be carefull to only process the correct architecture */
706 bool debListParser::Step()
708 iOffset
= Tags
.Offset();
709 while (Tags
.Step(Section
) == true)
711 /* See if this is the correct Architecture, if it isn't then we
712 drop the whole section. A missing arch tag only happens (in theory)
713 inside the Status file, so that is a positive return */
714 string
const Architecture
= Section
.FindS("Architecture");
715 if (Architecture
.empty() == true)
718 if (Arch
.empty() == true)
720 if (APT::Configuration::checkArchitecture(Architecture
) == true)
725 if (Architecture
== Arch
)
728 if (Architecture
== "all")
732 iOffset
= Tags
.Offset();
737 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
738 // ---------------------------------------------------------------------
740 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
741 FileFd
&File
, string component
)
743 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
744 pkgTagSection Section
;
745 if (Tags
.Step(Section
) == false)
748 // FIXME: Do we need it now for multi-arch?
749 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
750 // FileI->Architecture = WriteUniqString(Arch);
752 // apt-secure does no longer download individual (per-section) Release
753 // file. to provide Component pinning we use the section name now
754 FileI
->Component
= WriteUniqString(component
);
758 if (Section
.Find("Suite",Start
,Stop
) == true)
759 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
760 if (Section
.Find("Component",Start
,Stop
) == true)
761 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
762 if (Section
.Find("Version",Start
,Stop
) == true)
763 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
764 if (Section
.Find("Origin",Start
,Stop
) == true)
765 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
766 if (Section
.Find("Codename",Start
,Stop
) == true)
767 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
768 if (Section
.Find("Label",Start
,Stop
) == true)
769 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
770 if (Section
.Find("Architecture",Start
,Stop
) == true)
771 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
773 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
774 pkgCache::Flag::NotAutomatic
) == false)
775 _error
->Warning("Bad NotAutomatic flag");
777 return !_error
->PendingError();
780 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
781 // ---------------------------------------------------------------------
783 unsigned char debListParser::GetPrio(string Str
)
786 if (GrabWord(Str
,PrioList
,Out
) == false)
787 Out
= pkgCache::State::Extra
;