]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
b57eca813a03e1ecc2c0a00bfcaa21cafbfc565a
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::Version - Return the version string /*{{{*/
87 // ---------------------------------------------------------------------
88 /* This is to return the string describing the version in debian form,
89 epoch:upstream-release. If this returns the blank string then the
90 entry is assumed to only describe package properties */
91 string
debListParser::Version()
93 return Section
.FindS("Version");
96 // ListParser::NewVersion - Fill in the version structure /*{{{*/
97 // ---------------------------------------------------------------------
99 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
102 Ver
->Section
= UniqFindTagWrite("Section");
104 // Parse the architecture
105 Ver
->Arch
= WriteUniqString(Architecture());
108 Ver
->Size
= (unsigned)Section
.FindI("Size");
110 // Unpacked Size (in K)
111 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
112 Ver
->InstalledSize
*= 1024;
117 if (Section
.Find("Priority",Start
,Stop
) == true)
119 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
120 Ver
->Priority
= pkgCache::State::Extra
;
123 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
125 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
127 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
129 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
131 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
133 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
135 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
137 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
141 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
144 if (ParseProvides(Ver
) == false)
150 // ListParser::Description - Return the description string /*{{{*/
151 // ---------------------------------------------------------------------
152 /* This is to return the string describing the package in debian
153 form. If this returns the blank string then the entry is assumed to
154 only describe package properties */
155 string
debListParser::Description()
157 string
const lang
= DescriptionLanguage();
159 return Section
.FindS("Description");
161 return Section
.FindS(string("Description-").append(lang
).c_str());
164 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
165 // ---------------------------------------------------------------------
166 /* This is to return the string describing the language of
167 description. If this returns the blank string then the entry is
168 assumed to describe original description. */
169 string
debListParser::DescriptionLanguage()
171 if (Section
.FindS("Description").empty() == false)
174 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
175 for (std::vector
<string
>::const_iterator l
= lang
.begin();
176 l
!= lang
.end(); l
++)
177 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
183 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
184 // ---------------------------------------------------------------------
185 /* This is to return the md5 string to allow the check if it is the right
186 description. If no Description-md5 is found in the section it will be
189 MD5SumValue
debListParser::Description_md5()
191 string value
= Section
.FindS("Description-md5");
196 md5
.Add((Description() + "\n").c_str());
199 return MD5SumValue(value
);
202 // ListParser::UsePackage - Update a package structure /*{{{*/
203 // ---------------------------------------------------------------------
204 /* This is called to update the package with any new information
205 that might be found in the section */
206 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
207 pkgCache::VerIterator Ver
)
209 if (Pkg
->Section
== 0)
210 Pkg
->Section
= UniqFindTagWrite("Section");
212 // Packages which are not from "our" arch doesn't get the essential flag
213 string
const static myArch
= _config
->Find("APT::Architecture");
214 if (Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch())
215 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
217 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
220 if (strcmp(Pkg
.Name(),"apt") == 0)
221 Pkg
->Flags
|= pkgCache::Flag::Important
;
223 if (ParseStatus(Pkg
,Ver
) == false)
228 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
229 // ---------------------------------------------------------------------
231 unsigned short debListParser::VersionHash()
233 const char *Sections
[] ={"Installed-Size",
241 unsigned long Result
= INIT_FCS
;
243 for (const char **I
= Sections
; *I
!= 0; I
++)
247 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
250 /* Strip out any spaces from the text, this undoes dpkgs reformatting
251 of certain fields. dpkg also has the rather interesting notion of
252 reformatting depends operators < -> <= */
254 for (; Start
!= End
; Start
++)
256 if (isspace(*Start
) == 0)
257 *I
++ = tolower_ascii(*Start
);
258 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
260 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
264 Result
= AddCRC16(Result
,S
,I
- S
);
270 // ListParser::ParseStatus - Parse the status field /*{{{*/
271 // ---------------------------------------------------------------------
272 /* Status lines are of the form,
273 Status: want flag status
274 want = unknown, install, hold, deinstall, purge
275 flag = ok, reinstreq, hold, hold-reinstreq
276 status = not-installed, unpacked, half-configured,
277 half-installed, config-files, post-inst-failed,
278 removal-failed, installed
280 Some of the above are obsolete (I think?) flag = hold-* and
281 status = post-inst-failed, removal-failed at least.
283 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
284 pkgCache::VerIterator Ver
)
288 if (Section
.Find("Status",Start
,Stop
) == false)
291 // Isolate the first word
292 const char *I
= Start
;
293 for(; I
< Stop
&& *I
!= ' '; I
++);
294 if (I
>= Stop
|| *I
!= ' ')
295 return _error
->Error("Malformed Status line");
297 // Process the want field
298 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
299 {"install",pkgCache::State::Install
},
300 {"hold",pkgCache::State::Hold
},
301 {"deinstall",pkgCache::State::DeInstall
},
302 {"purge",pkgCache::State::Purge
},
304 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
305 return _error
->Error("Malformed 1st word in the Status line");
307 // Isloate the next word
310 for(; I
< Stop
&& *I
!= ' '; I
++);
311 if (I
>= Stop
|| *I
!= ' ')
312 return _error
->Error("Malformed status line, no 2nd word");
314 // Process the flag field
315 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
316 {"reinstreq",pkgCache::State::ReInstReq
},
317 {"hold",pkgCache::State::HoldInst
},
318 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
320 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
321 return _error
->Error("Malformed 2nd word in the Status line");
323 // Isloate the last word
326 for(; I
< Stop
&& *I
!= ' '; I
++);
328 return _error
->Error("Malformed Status line, no 3rd word");
330 // Process the flag field
331 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
332 {"unpacked",pkgCache::State::UnPacked
},
333 {"half-configured",pkgCache::State::HalfConfigured
},
334 {"installed",pkgCache::State::Installed
},
335 {"half-installed",pkgCache::State::HalfInstalled
},
336 {"config-files",pkgCache::State::ConfigFiles
},
337 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
338 {"triggers-pending",pkgCache::State::TriggersPending
},
339 {"post-inst-failed",pkgCache::State::HalfConfigured
},
340 {"removal-failed",pkgCache::State::HalfInstalled
},
342 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
343 return _error
->Error("Malformed 3rd word in the Status line");
345 /* A Status line marks the package as indicating the current
346 version as well. Only if it is actually installed.. Otherwise
347 the interesting dpkg handling of the status file creates bogus
349 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
350 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
352 if (Ver
.end() == true)
353 _error
->Warning("Encountered status field in a non-version description");
355 Pkg
->CurrentVer
= Ver
.Index();
361 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
363 // Determine the operator
371 Op
= pkgCache::Dep::LessEq
;
378 Op
= pkgCache::Dep::Less
;
382 // < is the same as <= and << is really Cs < for some reason
383 Op
= pkgCache::Dep::LessEq
;
391 Op
= pkgCache::Dep::GreaterEq
;
398 Op
= pkgCache::Dep::Greater
;
402 // > is the same as >= and >> is really Cs > for some reason
403 Op
= pkgCache::Dep::GreaterEq
;
407 Op
= pkgCache::Dep::Equals
;
411 // HACK around bad package definitions
413 Op
= pkgCache::Dep::Equals
;
420 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
421 // ---------------------------------------------------------------------
422 /* This parses the dependency elements out of a standard string in place,
424 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
425 string
&Package
,string
&Ver
,
426 unsigned int &Op
, bool const &ParseArchFlags
,
427 bool const &StripMultiArch
)
429 // Strip off leading space
430 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
432 // Parse off the package name
433 const char *I
= Start
;
434 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
435 *I
!= ',' && *I
!= '|'; I
++);
438 if (I
!= Stop
&& *I
== ')')
444 // Stash the package name
445 Package
.assign(Start
,I
- Start
);
447 // We don't want to confuse library users which can't handle MultiArch
448 if (StripMultiArch
== true) {
449 size_t const found
= Package
.rfind(':');
450 if (found
!= string::npos
)
451 Package
= Package
.substr(0,found
);
454 // Skip white space to the '('
455 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
458 if (I
!= Stop
&& *I
== '(')
461 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
464 I
= ConvertRelation(I
,Op
);
467 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
469 for (;I
!= Stop
&& *I
!= ')'; I
++);
470 if (I
== Stop
|| Start
== I
)
473 // Skip trailing whitespace
475 for (; End
> Start
&& isspace(End
[-1]); End
--);
477 Ver
.assign(Start
,End
-Start
);
483 Op
= pkgCache::Dep::NoOp
;
487 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
489 if (ParseArchFlags
== true)
491 string arch
= _config
->Find("APT::Architecture");
493 // Parse an architecture
494 if (I
!= Stop
&& *I
== '[')
503 bool NegArch
= false;
506 // look for whitespace or ending ']'
507 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
519 if (stringcmp(arch
,I
,End
) == 0)
528 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
535 Package
= ""; /* not for this arch */
539 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
542 if (I
!= Stop
&& *I
== '|')
543 Op
|= pkgCache::Dep::Or
;
545 if (I
== Stop
|| *I
== ',' || *I
== '|')
548 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
555 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
556 // ---------------------------------------------------------------------
557 /* This is the higher level depends parser. It takes a tag and generates
558 a complete depends tree for the given version. */
559 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
560 const char *Tag
,unsigned int Type
)
564 if (Section
.Find(Tag
,Start
,Stop
) == false)
568 string
const pkgArch
= Ver
.Arch();
574 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
576 return _error
->Error("Problem parsing dependency %s",Tag
);
578 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
586 // ListParser::ParseProvides - Parse the provides list /*{{{*/
587 // ---------------------------------------------------------------------
589 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
593 if (Section
.Find("Provides",Start
,Stop
) == false)
602 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
604 return _error
->Error("Problem parsing Provides line");
605 if (Op
!= pkgCache::Dep::NoOp
) {
606 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
608 if (NewProvides(Ver
,Package
,Version
) == false)
619 // ListParser::GrabWord - Matches a word and returns /*{{{*/
620 // ---------------------------------------------------------------------
621 /* Looks for a word in a list of words - for ParseStatus */
622 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
624 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
626 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
635 // ListParser::Step - Move to the next section in the file /*{{{*/
636 // ---------------------------------------------------------------------
637 /* This has to be carefull to only process the correct architecture */
638 bool debListParser::Step()
640 iOffset
= Tags
.Offset();
641 while (Tags
.Step(Section
) == true)
643 /* See if this is the correct Architecture, if it isn't then we
644 drop the whole section. A missing arch tag only happens (in theory)
645 inside the Status file, so that is a positive return */
646 string
const Architecture
= Section
.FindS("Architecture");
647 if (Architecture
.empty() == true)
650 if (Arch
.empty() == true)
652 if (APT::Configuration::checkArchitecture(Architecture
) == true)
657 if (Architecture
== Arch
)
660 if (Architecture
== "all")
664 iOffset
= Tags
.Offset();
669 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
670 // ---------------------------------------------------------------------
672 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
673 FileFd
&File
, string component
)
675 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
676 pkgTagSection Section
;
677 if (Tags
.Step(Section
) == false)
680 // FIXME: Do we need it now for multi-arch?
681 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
682 // FileI->Architecture = WriteUniqString(Arch);
684 // apt-secure does no longer download individual (per-section) Release
685 // file. to provide Component pinning we use the section name now
686 FileI
->Component
= WriteUniqString(component
);
690 if (Section
.Find("Suite",Start
,Stop
) == true)
691 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
692 if (Section
.Find("Component",Start
,Stop
) == true)
693 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
694 if (Section
.Find("Version",Start
,Stop
) == true)
695 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
696 if (Section
.Find("Origin",Start
,Stop
) == true)
697 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
698 if (Section
.Find("Codename",Start
,Stop
) == true)
699 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
700 if (Section
.Find("Label",Start
,Stop
) == true)
701 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
702 if (Section
.Find("Architecture",Start
,Stop
) == true)
703 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
705 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
706 pkgCache::Flag::NotAutomatic
) == false)
707 _error
->Warning("Bad NotAutomatic flag");
709 return !_error
->PendingError();
712 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
713 // ---------------------------------------------------------------------
715 unsigned char debListParser::GetPrio(string Str
)
718 if (GrabWord(Str
,PrioList
,Out
) == false)
719 Out
= pkgCache::State::Extra
;