]>
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)
613 static std::vector
<std::string
> const archs
= APT::Configuration::getArchitectures();
614 static bool const multiArch
= archs
.size() <= 1;
617 string
const pkgArch
= Ver
.Arch(true);
623 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
625 return _error
->Error("Problem parsing dependency %s",Tag
);
627 if (multiArch
== true &&
628 (Type
== pkgCache::Dep::Conflicts
||
629 Type
== pkgCache::Dep::DpkgBreaks
||
630 Type
== pkgCache::Dep::Replaces
))
632 for (std::vector
<std::string
>::const_iterator a
= archs
.begin();
633 a
!= archs
.end(); ++a
)
634 if (NewDepends(Ver
,Package
,*a
,Version
,Op
,Type
) == false)
637 else if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
645 // ListParser::ParseProvides - Parse the provides list /*{{{*/
646 // ---------------------------------------------------------------------
648 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
652 if (Section
.Find("Provides",Start
,Stop
) == true)
656 string
const Arch
= Ver
.Arch(true);
661 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
663 return _error
->Error("Problem parsing Provides line");
664 if (Op
!= pkgCache::Dep::NoOp
) {
665 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
667 if (NewProvides(Ver
, Package
, Arch
, Version
) == false)
676 if (Ver
->MultiArch
== pkgCache::Version::Allowed
)
678 string
const Package
= string(Ver
.ParentPkg().Name()).append(":").append("any");
679 NewProvides(Ver
, Package
, "any", Ver
.VerStr());
682 if (Ver
->MultiArch
!= pkgCache::Version::Foreign
)
685 std::vector
<string
> const archs
= APT::Configuration::getArchitectures();
686 if (archs
.size() <= 1)
689 string
const Package
= Ver
.ParentPkg().Name();
690 string
const Version
= Ver
.VerStr();
691 for (std::vector
<string
>::const_iterator a
= archs
.begin();
692 a
!= archs
.end(); ++a
)
694 if (NewProvides(Ver
, Package
, *a
, Version
) == false)
701 // ListParser::GrabWord - Matches a word and returns /*{{{*/
702 // ---------------------------------------------------------------------
703 /* Looks for a word in a list of words - for ParseStatus */
704 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
706 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
708 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
717 // ListParser::Step - Move to the next section in the file /*{{{*/
718 // ---------------------------------------------------------------------
719 /* This has to be carefull to only process the correct architecture */
720 bool debListParser::Step()
722 iOffset
= Tags
.Offset();
723 while (Tags
.Step(Section
) == true)
725 /* See if this is the correct Architecture, if it isn't then we
726 drop the whole section. A missing arch tag only happens (in theory)
727 inside the Status file, so that is a positive return */
728 string
const Architecture
= Section
.FindS("Architecture");
729 if (Architecture
.empty() == true)
732 if (Arch
.empty() == true)
734 if (APT::Configuration::checkArchitecture(Architecture
) == true)
739 if (Architecture
== Arch
)
742 if (Architecture
== "all")
746 iOffset
= Tags
.Offset();
751 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
752 // ---------------------------------------------------------------------
754 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
755 FileFd
&File
, string component
)
757 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
758 pkgTagSection Section
;
759 if (Tags
.Step(Section
) == false)
762 // FIXME: Do we need it now for multi-arch?
763 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
764 // FileI->Architecture = WriteUniqString(Arch);
766 // apt-secure does no longer download individual (per-section) Release
767 // file. to provide Component pinning we use the section name now
768 FileI
->Component
= WriteUniqString(component
);
772 if (Section
.Find("Suite",Start
,Stop
) == true)
773 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
774 if (Section
.Find("Component",Start
,Stop
) == true)
775 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
776 if (Section
.Find("Version",Start
,Stop
) == true)
777 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
778 if (Section
.Find("Origin",Start
,Stop
) == true)
779 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
780 if (Section
.Find("Codename",Start
,Stop
) == true)
781 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
782 if (Section
.Find("Label",Start
,Stop
) == true)
783 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
784 if (Section
.Find("Architecture",Start
,Stop
) == true)
785 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
787 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
788 pkgCache::Flag::NotAutomatic
) == false)
789 _error
->Warning("Bad NotAutomatic flag");
791 return !_error
->PendingError();
794 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
795 // ---------------------------------------------------------------------
797 unsigned char debListParser::GetPrio(string Str
)
800 if (GrabWord(Str
,PrioList
,Out
) == false)
801 Out
= pkgCache::State::Extra
;