]>
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")
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
= Section
.FindULL("Size");
137 // Unpacked Size (in K)
138 Ver
->InstalledSize
= Section
.FindULL("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 the "native" arch doesn't get the essential flag
259 // in the default "native" mode - it is also possible to mark "all" or "none".
260 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
261 string
const static myArch
= _config
->Find("APT::Architecture");
262 string
const static essential
= _config
->Find("pkgCacheGen::Essential", "native");
263 if ((essential
== "native" && Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch()) ||
265 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
267 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
270 if (strcmp(Pkg
.Name(),"apt") == 0)
271 Pkg
->Flags
|= pkgCache::Flag::Important
;
273 if (ParseStatus(Pkg
,Ver
) == false)
278 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
279 // ---------------------------------------------------------------------
281 unsigned short debListParser::VersionHash()
283 const char *Sections
[] ={"Installed-Size",
291 unsigned long Result
= INIT_FCS
;
293 for (const char **I
= Sections
; *I
!= 0; I
++)
297 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
300 /* Strip out any spaces from the text, this undoes dpkgs reformatting
301 of certain fields. dpkg also has the rather interesting notion of
302 reformatting depends operators < -> <= */
304 for (; Start
!= End
; Start
++)
306 if (isspace(*Start
) == 0)
307 *I
++ = tolower_ascii(*Start
);
308 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
310 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
314 Result
= AddCRC16(Result
,S
,I
- S
);
320 // ListParser::ParseStatus - Parse the status field /*{{{*/
321 // ---------------------------------------------------------------------
322 /* Status lines are of the form,
323 Status: want flag status
324 want = unknown, install, hold, deinstall, purge
325 flag = ok, reinstreq, hold, hold-reinstreq
326 status = not-installed, unpacked, half-configured,
327 half-installed, config-files, post-inst-failed,
328 removal-failed, installed
330 Some of the above are obsolete (I think?) flag = hold-* and
331 status = post-inst-failed, removal-failed at least.
333 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
334 pkgCache::VerIterator Ver
)
338 if (Section
.Find("Status",Start
,Stop
) == false)
341 // UsePackage() is responsible for setting the flag in the default case
342 bool const static essential
= _config
->Find("pkgCacheGen::Essential", "") == "installed";
343 if (essential
== true &&
344 Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
347 // Isolate the first word
348 const char *I
= Start
;
349 for(; I
< Stop
&& *I
!= ' '; I
++);
350 if (I
>= Stop
|| *I
!= ' ')
351 return _error
->Error("Malformed Status line");
353 // Process the want field
354 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
355 {"install",pkgCache::State::Install
},
356 {"hold",pkgCache::State::Hold
},
357 {"deinstall",pkgCache::State::DeInstall
},
358 {"purge",pkgCache::State::Purge
},
360 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
361 return _error
->Error("Malformed 1st word in the Status line");
363 // Isloate the next word
366 for(; I
< Stop
&& *I
!= ' '; I
++);
367 if (I
>= Stop
|| *I
!= ' ')
368 return _error
->Error("Malformed status line, no 2nd word");
370 // Process the flag field
371 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
372 {"reinstreq",pkgCache::State::ReInstReq
},
373 {"hold",pkgCache::State::HoldInst
},
374 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
376 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
377 return _error
->Error("Malformed 2nd word in the Status line");
379 // Isloate the last word
382 for(; I
< Stop
&& *I
!= ' '; I
++);
384 return _error
->Error("Malformed Status line, no 3rd word");
386 // Process the flag field
387 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
388 {"unpacked",pkgCache::State::UnPacked
},
389 {"half-configured",pkgCache::State::HalfConfigured
},
390 {"installed",pkgCache::State::Installed
},
391 {"half-installed",pkgCache::State::HalfInstalled
},
392 {"config-files",pkgCache::State::ConfigFiles
},
393 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
394 {"triggers-pending",pkgCache::State::TriggersPending
},
395 {"post-inst-failed",pkgCache::State::HalfConfigured
},
396 {"removal-failed",pkgCache::State::HalfInstalled
},
398 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
399 return _error
->Error("Malformed 3rd word in the Status line");
401 /* A Status line marks the package as indicating the current
402 version as well. Only if it is actually installed.. Otherwise
403 the interesting dpkg handling of the status file creates bogus
405 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
406 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
408 if (Ver
.end() == true)
409 _error
->Warning("Encountered status field in a non-version description");
411 Pkg
->CurrentVer
= Ver
.Index();
417 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
419 // Determine the operator
427 Op
= pkgCache::Dep::LessEq
;
434 Op
= pkgCache::Dep::Less
;
438 // < is the same as <= and << is really Cs < for some reason
439 Op
= pkgCache::Dep::LessEq
;
447 Op
= pkgCache::Dep::GreaterEq
;
454 Op
= pkgCache::Dep::Greater
;
458 // > is the same as >= and >> is really Cs > for some reason
459 Op
= pkgCache::Dep::GreaterEq
;
463 Op
= pkgCache::Dep::Equals
;
467 // HACK around bad package definitions
469 Op
= pkgCache::Dep::Equals
;
476 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
477 // ---------------------------------------------------------------------
478 /* This parses the dependency elements out of a standard string in place,
480 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
481 string
&Package
,string
&Ver
,
482 unsigned int &Op
, bool const &ParseArchFlags
,
483 bool const &StripMultiArch
)
485 // Strip off leading space
486 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
488 // Parse off the package name
489 const char *I
= Start
;
490 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
491 *I
!= ',' && *I
!= '|'; I
++);
494 if (I
!= Stop
&& *I
== ')')
500 // Stash the package name
501 Package
.assign(Start
,I
- Start
);
503 // We don't want to confuse library users which can't handle MultiArch
504 if (StripMultiArch
== true) {
505 size_t const found
= Package
.rfind(':');
506 if (found
!= string::npos
)
507 Package
= Package
.substr(0,found
);
510 // Skip white space to the '('
511 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
514 if (I
!= Stop
&& *I
== '(')
517 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
520 I
= ConvertRelation(I
,Op
);
523 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
525 for (;I
!= Stop
&& *I
!= ')'; I
++);
526 if (I
== Stop
|| Start
== I
)
529 // Skip trailing whitespace
531 for (; End
> Start
&& isspace(End
[-1]); End
--);
533 Ver
.assign(Start
,End
-Start
);
539 Op
= pkgCache::Dep::NoOp
;
543 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
545 if (ParseArchFlags
== true)
547 string arch
= _config
->Find("APT::Architecture");
549 // Parse an architecture
550 if (I
!= Stop
&& *I
== '[')
559 bool NegArch
= false;
562 // look for whitespace or ending ']'
563 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
575 if (stringcmp(arch
,I
,End
) == 0)
584 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
591 Package
= ""; /* not for this arch */
595 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
598 if (I
!= Stop
&& *I
== '|')
599 Op
|= pkgCache::Dep::Or
;
601 if (I
== Stop
|| *I
== ',' || *I
== '|')
604 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
611 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
612 // ---------------------------------------------------------------------
613 /* This is the higher level depends parser. It takes a tag and generates
614 a complete depends tree for the given version. */
615 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
616 const char *Tag
,unsigned int Type
)
620 if (Section
.Find(Tag
,Start
,Stop
) == false)
623 static std::vector
<std::string
> const archs
= APT::Configuration::getArchitectures();
624 static bool const multiArch
= archs
.size() <= 1;
627 string
const pkgArch
= Ver
.Arch(true);
633 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
635 return _error
->Error("Problem parsing dependency %s",Tag
);
637 if (multiArch
== true &&
638 (Type
== pkgCache::Dep::Conflicts
||
639 Type
== pkgCache::Dep::DpkgBreaks
||
640 Type
== pkgCache::Dep::Replaces
))
642 for (std::vector
<std::string
>::const_iterator a
= archs
.begin();
643 a
!= archs
.end(); ++a
)
644 if (NewDepends(Ver
,Package
,*a
,Version
,Op
,Type
) == false)
647 else if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
655 // ListParser::ParseProvides - Parse the provides list /*{{{*/
656 // ---------------------------------------------------------------------
658 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
662 if (Section
.Find("Provides",Start
,Stop
) == true)
666 string
const Arch
= Ver
.Arch(true);
671 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
673 return _error
->Error("Problem parsing Provides line");
674 if (Op
!= pkgCache::Dep::NoOp
) {
675 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
677 if (NewProvides(Ver
, Package
, Arch
, Version
) == false)
686 if (Ver
->MultiArch
== pkgCache::Version::Allowed
)
688 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
689 NewProvides(Ver
, Package
, "any", Ver
.VerStr());
692 if (Ver
->MultiArch
!= pkgCache::Version::Foreign
)
695 std::vector
<string
> const archs
= APT::Configuration::getArchitectures();
696 if (archs
.size() <= 1)
699 string
const Package
= Ver
.ParentPkg().Name();
700 string
const Version
= Ver
.VerStr();
701 for (std::vector
<string
>::const_iterator a
= archs
.begin();
702 a
!= archs
.end(); ++a
)
704 if (NewProvides(Ver
, Package
, *a
, Version
) == false)
711 // ListParser::GrabWord - Matches a word and returns /*{{{*/
712 // ---------------------------------------------------------------------
713 /* Looks for a word in a list of words - for ParseStatus */
714 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
716 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
718 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
727 // ListParser::Step - Move to the next section in the file /*{{{*/
728 // ---------------------------------------------------------------------
729 /* This has to be carefull to only process the correct architecture */
730 bool debListParser::Step()
732 iOffset
= Tags
.Offset();
733 while (Tags
.Step(Section
) == true)
735 /* See if this is the correct Architecture, if it isn't then we
736 drop the whole section. A missing arch tag only happens (in theory)
737 inside the Status file, so that is a positive return */
738 string
const Architecture
= Section
.FindS("Architecture");
739 if (Architecture
.empty() == true)
742 if (Arch
.empty() == true)
744 if (APT::Configuration::checkArchitecture(Architecture
) == true)
749 if (Architecture
== Arch
)
752 if (Architecture
== "all")
756 iOffset
= Tags
.Offset();
761 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
762 // ---------------------------------------------------------------------
764 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
765 FileFd
&File
, string component
)
767 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
768 pkgTagSection Section
;
769 if (Tags
.Step(Section
) == false)
772 // FIXME: Do we need it now for multi-arch?
773 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
774 // FileI->Architecture = WriteUniqString(Arch);
776 // apt-secure does no longer download individual (per-section) Release
777 // file. to provide Component pinning we use the section name now
778 FileI
->Component
= WriteUniqString(component
);
782 if (Section
.Find("Suite",Start
,Stop
) == true)
783 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
784 if (Section
.Find("Component",Start
,Stop
) == true)
785 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
786 if (Section
.Find("Version",Start
,Stop
) == true)
787 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
788 if (Section
.Find("Origin",Start
,Stop
) == true)
789 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
790 if (Section
.Find("Codename",Start
,Stop
) == true)
791 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
792 if (Section
.Find("Label",Start
,Stop
) == true)
793 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
794 if (Section
.Find("Architecture",Start
,Stop
) == true)
795 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
797 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
798 pkgCache::Flag::NotAutomatic
) == false)
799 _error
->Warning("Bad NotAutomatic flag");
801 return !_error
->PendingError();
804 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
805 // ---------------------------------------------------------------------
807 unsigned char debListParser::GetPrio(string Str
)
810 if (GrabWord(Str
,PrioList
,Out
) == false)
811 Out
= pkgCache::State::Extra
;