]>
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 bool const static multiArch
= APT::Configuration::getArchitectures().size() > 1;
159 if (strcmp(Ver
.Arch(true),"all") == 0)
161 else if (multiArch
== true)
163 // our pseudo packages have no size to not confuse the fetcher
165 Ver
->InstalledSize
= 0;
169 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
171 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
173 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
175 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
177 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
179 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
181 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
183 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
187 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
190 if (ParseProvides(Ver
) == false)
196 // ListParser::Description - Return the description string /*{{{*/
197 // ---------------------------------------------------------------------
198 /* This is to return the string describing the package in debian
199 form. If this returns the blank string then the entry is assumed to
200 only describe package properties */
201 string
debListParser::Description()
203 string
const lang
= DescriptionLanguage();
205 return Section
.FindS("Description");
207 return Section
.FindS(string("Description-").append(lang
).c_str());
210 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
211 // ---------------------------------------------------------------------
212 /* This is to return the string describing the language of
213 description. If this returns the blank string then the entry is
214 assumed to describe original description. */
215 string
debListParser::DescriptionLanguage()
217 if (Section
.FindS("Description").empty() == false)
220 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
221 for (std::vector
<string
>::const_iterator l
= lang
.begin();
222 l
!= lang
.end(); l
++)
223 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
229 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
230 // ---------------------------------------------------------------------
231 /* This is to return the md5 string to allow the check if it is the right
232 description. If no Description-md5 is found in the section it will be
235 MD5SumValue
debListParser::Description_md5()
237 string value
= Section
.FindS("Description-md5");
242 md5
.Add((Description() + "\n").c_str());
245 return MD5SumValue(value
);
248 // ListParser::UsePackage - Update a package structure /*{{{*/
249 // ---------------------------------------------------------------------
250 /* This is called to update the package with any new information
251 that might be found in the section */
252 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
253 pkgCache::VerIterator Ver
)
255 if (Pkg
->Section
== 0)
256 Pkg
->Section
= UniqFindTagWrite("Section");
258 // Packages which are not from "our" arch doesn't get the essential flag
259 string
const static myArch
= _config
->Find("APT::Architecture");
260 if (Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch())
261 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
263 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
266 if (strcmp(Pkg
.Name(),"apt") == 0)
267 Pkg
->Flags
|= pkgCache::Flag::Important
;
269 if (ParseStatus(Pkg
,Ver
) == false)
274 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
275 // ---------------------------------------------------------------------
277 unsigned short debListParser::VersionHash()
279 const char *Sections
[] ={"Installed-Size",
287 unsigned long Result
= INIT_FCS
;
289 for (const char **I
= Sections
; *I
!= 0; I
++)
293 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
296 /* Strip out any spaces from the text, this undoes dpkgs reformatting
297 of certain fields. dpkg also has the rather interesting notion of
298 reformatting depends operators < -> <= */
300 for (; Start
!= End
; Start
++)
302 if (isspace(*Start
) == 0)
303 *I
++ = tolower_ascii(*Start
);
304 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
306 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
310 Result
= AddCRC16(Result
,S
,I
- S
);
316 // ListParser::ParseStatus - Parse the status field /*{{{*/
317 // ---------------------------------------------------------------------
318 /* Status lines are of the form,
319 Status: want flag status
320 want = unknown, install, hold, deinstall, purge
321 flag = ok, reinstreq, hold, hold-reinstreq
322 status = not-installed, unpacked, half-configured,
323 half-installed, config-files, post-inst-failed,
324 removal-failed, installed
326 Some of the above are obsolete (I think?) flag = hold-* and
327 status = post-inst-failed, removal-failed at least.
329 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
330 pkgCache::VerIterator Ver
)
334 if (Section
.Find("Status",Start
,Stop
) == false)
337 // Isolate the first word
338 const char *I
= Start
;
339 for(; I
< Stop
&& *I
!= ' '; I
++);
340 if (I
>= Stop
|| *I
!= ' ')
341 return _error
->Error("Malformed Status line");
343 // Process the want field
344 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
345 {"install",pkgCache::State::Install
},
346 {"hold",pkgCache::State::Hold
},
347 {"deinstall",pkgCache::State::DeInstall
},
348 {"purge",pkgCache::State::Purge
},
350 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
351 return _error
->Error("Malformed 1st word in the Status line");
353 // Isloate the next word
356 for(; I
< Stop
&& *I
!= ' '; I
++);
357 if (I
>= Stop
|| *I
!= ' ')
358 return _error
->Error("Malformed status line, no 2nd word");
360 // Process the flag field
361 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
362 {"reinstreq",pkgCache::State::ReInstReq
},
363 {"hold",pkgCache::State::HoldInst
},
364 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
366 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
367 return _error
->Error("Malformed 2nd word in the Status line");
369 // Isloate the last word
372 for(; I
< Stop
&& *I
!= ' '; I
++);
374 return _error
->Error("Malformed Status line, no 3rd word");
376 // Process the flag field
377 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
378 {"unpacked",pkgCache::State::UnPacked
},
379 {"half-configured",pkgCache::State::HalfConfigured
},
380 {"installed",pkgCache::State::Installed
},
381 {"half-installed",pkgCache::State::HalfInstalled
},
382 {"config-files",pkgCache::State::ConfigFiles
},
383 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
384 {"triggers-pending",pkgCache::State::TriggersPending
},
385 {"post-inst-failed",pkgCache::State::HalfConfigured
},
386 {"removal-failed",pkgCache::State::HalfInstalled
},
388 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
389 return _error
->Error("Malformed 3rd word in the Status line");
391 /* A Status line marks the package as indicating the current
392 version as well. Only if it is actually installed.. Otherwise
393 the interesting dpkg handling of the status file creates bogus
395 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
396 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
398 if (Ver
.end() == true)
399 _error
->Warning("Encountered status field in a non-version description");
401 Pkg
->CurrentVer
= Ver
.Index();
407 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
409 // Determine the operator
417 Op
= pkgCache::Dep::LessEq
;
424 Op
= pkgCache::Dep::Less
;
428 // < is the same as <= and << is really Cs < for some reason
429 Op
= pkgCache::Dep::LessEq
;
437 Op
= pkgCache::Dep::GreaterEq
;
444 Op
= pkgCache::Dep::Greater
;
448 // > is the same as >= and >> is really Cs > for some reason
449 Op
= pkgCache::Dep::GreaterEq
;
453 Op
= pkgCache::Dep::Equals
;
457 // HACK around bad package definitions
459 Op
= pkgCache::Dep::Equals
;
466 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
467 // ---------------------------------------------------------------------
468 /* This parses the dependency elements out of a standard string in place,
470 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
471 string
&Package
,string
&Ver
,
472 unsigned int &Op
, bool const &ParseArchFlags
,
473 bool const &StripMultiArch
)
475 // Strip off leading space
476 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
478 // Parse off the package name
479 const char *I
= Start
;
480 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
481 *I
!= ',' && *I
!= '|'; I
++);
484 if (I
!= Stop
&& *I
== ')')
490 // Stash the package name
491 Package
.assign(Start
,I
- Start
);
493 // We don't want to confuse library users which can't handle MultiArch
494 if (StripMultiArch
== true) {
495 size_t const found
= Package
.rfind(':');
496 if (found
!= string::npos
)
497 Package
= Package
.substr(0,found
);
500 // Skip white space to the '('
501 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
504 if (I
!= Stop
&& *I
== '(')
507 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
510 I
= ConvertRelation(I
,Op
);
513 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
515 for (;I
!= Stop
&& *I
!= ')'; I
++);
516 if (I
== Stop
|| Start
== I
)
519 // Skip trailing whitespace
521 for (; End
> Start
&& isspace(End
[-1]); End
--);
523 Ver
.assign(Start
,End
-Start
);
529 Op
= pkgCache::Dep::NoOp
;
533 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
535 if (ParseArchFlags
== true)
537 string arch
= _config
->Find("APT::Architecture");
539 // Parse an architecture
540 if (I
!= Stop
&& *I
== '[')
549 bool NegArch
= false;
552 // look for whitespace or ending ']'
553 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
565 if (stringcmp(arch
,I
,End
) == 0)
574 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
581 Package
= ""; /* not for this arch */
585 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
588 if (I
!= Stop
&& *I
== '|')
589 Op
|= pkgCache::Dep::Or
;
591 if (I
== Stop
|| *I
== ',' || *I
== '|')
594 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
601 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
602 // ---------------------------------------------------------------------
603 /* This is the higher level depends parser. It takes a tag and generates
604 a complete depends tree for the given version. */
605 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
606 const char *Tag
,unsigned int Type
)
610 if (Section
.Find(Tag
,Start
,Stop
) == false)
614 string
const pkgArch
= Ver
.Arch(true);
620 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
622 return _error
->Error("Problem parsing dependency %s",Tag
);
624 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
632 // ListParser::ParseProvides - Parse the provides list /*{{{*/
633 // ---------------------------------------------------------------------
635 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
639 if (Section
.Find("Provides",Start
,Stop
) == true)
643 string
const Arch
= Ver
.Arch(true);
648 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
650 return _error
->Error("Problem parsing Provides line");
651 if (Op
!= pkgCache::Dep::NoOp
) {
652 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
654 if (NewProvides(Ver
, Package
, Arch
, Version
) == false)
663 if (Ver
->MultiArch
== pkgCache::Version::Allowed
)
665 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
666 NewProvides(Ver
, Package
, "any", Ver
.VerStr());
669 if (Ver
->MultiArch
!= pkgCache::Version::Foreign
)
672 std::vector
<string
> const archs
= APT::Configuration::getArchitectures();
673 if (archs
.size() <= 1)
676 string
const Package
= Ver
.ParentPkg().Name();
677 string
const Version
= Ver
.VerStr();
678 for (std::vector
<string
>::const_iterator a
= archs
.begin();
679 a
!= archs
.end(); ++a
)
681 if (NewProvides(Ver
, Package
, *a
, Version
) == false)
688 // ListParser::GrabWord - Matches a word and returns /*{{{*/
689 // ---------------------------------------------------------------------
690 /* Looks for a word in a list of words - for ParseStatus */
691 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
693 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
695 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
704 // ListParser::Step - Move to the next section in the file /*{{{*/
705 // ---------------------------------------------------------------------
706 /* This has to be carefull to only process the correct architecture */
707 bool debListParser::Step()
709 iOffset
= Tags
.Offset();
710 while (Tags
.Step(Section
) == true)
712 /* See if this is the correct Architecture, if it isn't then we
713 drop the whole section. A missing arch tag only happens (in theory)
714 inside the Status file, so that is a positive return */
715 string
const Architecture
= Section
.FindS("Architecture");
716 if (Architecture
.empty() == true)
719 if (Arch
.empty() == true)
721 if (APT::Configuration::checkArchitecture(Architecture
) == true)
726 if (Architecture
== Arch
)
729 if (Architecture
== "all")
733 iOffset
= Tags
.Offset();
738 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
739 // ---------------------------------------------------------------------
741 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
742 FileFd
&File
, string component
)
744 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
745 pkgTagSection Section
;
746 if (Tags
.Step(Section
) == false)
749 // FIXME: Do we need it now for multi-arch?
750 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
751 // FileI->Architecture = WriteUniqString(Arch);
753 // apt-secure does no longer download individual (per-section) Release
754 // file. to provide Component pinning we use the section name now
755 FileI
->Component
= WriteUniqString(component
);
759 if (Section
.Find("Suite",Start
,Stop
) == true)
760 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
761 if (Section
.Find("Component",Start
,Stop
) == true)
762 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
763 if (Section
.Find("Version",Start
,Stop
) == true)
764 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
765 if (Section
.Find("Origin",Start
,Stop
) == true)
766 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
767 if (Section
.Find("Codename",Start
,Stop
) == true)
768 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
769 if (Section
.Find("Label",Start
,Stop
) == true)
770 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
771 if (Section
.Find("Architecture",Start
,Stop
) == true)
772 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
774 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
775 pkgCache::Flag::NotAutomatic
) == false)
776 _error
->Warning("Bad NotAutomatic flag");
778 return !_error
->PendingError();
781 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
782 // ---------------------------------------------------------------------
784 unsigned char debListParser::GetPrio(string Str
)
787 if (GrabWord(Str
,PrioList
,Out
) == false)
788 Out
= pkgCache::State::Extra
;