]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
f683de423f74417fdd098cce9d2f7295699d7f1c
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 if (Section
.FindS("Architecture") == "all")
109 /* Arch all packages can't have a Multi-Arch field,
110 but we need a special treatment for them nonetheless */
111 Ver
->MultiArch
= pkgCache::Version::All
;
114 string
const MultiArch
= Section
.FindS("Multi-Arch");
115 if (MultiArch
.empty() == true)
116 Ver
->MultiArch
= pkgCache::Version::None
;
117 else if (MultiArch
== "same")
118 Ver
->MultiArch
= pkgCache::Version::Same
;
119 else if (MultiArch
== "foreign")
120 Ver
->MultiArch
= pkgCache::Version::Foreign
;
121 else if (MultiArch
== "allowed")
122 Ver
->MultiArch
= pkgCache::Version::Allowed
;
125 _error
->Warning("Unknown Multi-Arch type »%s« for package »%s«",
126 MultiArch
.c_str(), Section
.FindS("Package").c_str());
127 Ver
->MultiArch
= pkgCache::Version::None
;
132 Ver
->Size
= (unsigned)Section
.FindI("Size");
134 // Unpacked Size (in K)
135 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
136 Ver
->InstalledSize
*= 1024;
141 if (Section
.Find("Priority",Start
,Stop
) == true)
143 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
144 Ver
->Priority
= pkgCache::State::Extra
;
147 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
149 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
151 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
153 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
155 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
157 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
159 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
161 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
165 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
168 if (ParseProvides(Ver
) == false)
174 // ListParser::Description - Return the description string /*{{{*/
175 // ---------------------------------------------------------------------
176 /* This is to return the string describing the package in debian
177 form. If this returns the blank string then the entry is assumed to
178 only describe package properties */
179 string
debListParser::Description()
181 string
const lang
= DescriptionLanguage();
183 return Section
.FindS("Description");
185 return Section
.FindS(string("Description-").append(lang
).c_str());
188 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
189 // ---------------------------------------------------------------------
190 /* This is to return the string describing the language of
191 description. If this returns the blank string then the entry is
192 assumed to describe original description. */
193 string
debListParser::DescriptionLanguage()
195 if (Section
.FindS("Description").empty() == false)
198 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
199 for (std::vector
<string
>::const_iterator l
= lang
.begin();
200 l
!= lang
.end(); l
++)
201 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
207 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
208 // ---------------------------------------------------------------------
209 /* This is to return the md5 string to allow the check if it is the right
210 description. If no Description-md5 is found in the section it will be
213 MD5SumValue
debListParser::Description_md5()
215 string value
= Section
.FindS("Description-md5");
220 md5
.Add((Description() + "\n").c_str());
223 return MD5SumValue(value
);
226 // ListParser::UsePackage - Update a package structure /*{{{*/
227 // ---------------------------------------------------------------------
228 /* This is called to update the package with any new information
229 that might be found in the section */
230 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
231 pkgCache::VerIterator Ver
)
233 if (Pkg
->Section
== 0)
234 Pkg
->Section
= UniqFindTagWrite("Section");
236 // Packages which are not from "our" arch doesn't get the essential flag
237 string
const static myArch
= _config
->Find("APT::Architecture");
238 if (Pkg
->Arch
!= 0 && myArch
== Pkg
.Arch())
239 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
241 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
244 if (strcmp(Pkg
.Name(),"apt") == 0)
245 Pkg
->Flags
|= pkgCache::Flag::Important
;
247 if (ParseStatus(Pkg
,Ver
) == false)
252 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
253 // ---------------------------------------------------------------------
255 unsigned short debListParser::VersionHash()
257 const char *Sections
[] ={"Installed-Size",
265 unsigned long Result
= INIT_FCS
;
267 for (const char **I
= Sections
; *I
!= 0; I
++)
271 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
274 /* Strip out any spaces from the text, this undoes dpkgs reformatting
275 of certain fields. dpkg also has the rather interesting notion of
276 reformatting depends operators < -> <= */
278 for (; Start
!= End
; Start
++)
280 if (isspace(*Start
) == 0)
281 *I
++ = tolower_ascii(*Start
);
282 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
284 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
288 Result
= AddCRC16(Result
,S
,I
- S
);
294 // ListParser::ParseStatus - Parse the status field /*{{{*/
295 // ---------------------------------------------------------------------
296 /* Status lines are of the form,
297 Status: want flag status
298 want = unknown, install, hold, deinstall, purge
299 flag = ok, reinstreq, hold, hold-reinstreq
300 status = not-installed, unpacked, half-configured,
301 half-installed, config-files, post-inst-failed,
302 removal-failed, installed
304 Some of the above are obsolete (I think?) flag = hold-* and
305 status = post-inst-failed, removal-failed at least.
307 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
308 pkgCache::VerIterator Ver
)
312 if (Section
.Find("Status",Start
,Stop
) == false)
315 // Isolate the first word
316 const char *I
= Start
;
317 for(; I
< Stop
&& *I
!= ' '; I
++);
318 if (I
>= Stop
|| *I
!= ' ')
319 return _error
->Error("Malformed Status line");
321 // Process the want field
322 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
323 {"install",pkgCache::State::Install
},
324 {"hold",pkgCache::State::Hold
},
325 {"deinstall",pkgCache::State::DeInstall
},
326 {"purge",pkgCache::State::Purge
},
328 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
329 return _error
->Error("Malformed 1st word in the Status line");
331 // Isloate the next word
334 for(; I
< Stop
&& *I
!= ' '; I
++);
335 if (I
>= Stop
|| *I
!= ' ')
336 return _error
->Error("Malformed status line, no 2nd word");
338 // Process the flag field
339 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
340 {"reinstreq",pkgCache::State::ReInstReq
},
341 {"hold",pkgCache::State::HoldInst
},
342 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
344 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
345 return _error
->Error("Malformed 2nd word in the Status line");
347 // Isloate the last word
350 for(; I
< Stop
&& *I
!= ' '; I
++);
352 return _error
->Error("Malformed Status line, no 3rd word");
354 // Process the flag field
355 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
356 {"unpacked",pkgCache::State::UnPacked
},
357 {"half-configured",pkgCache::State::HalfConfigured
},
358 {"installed",pkgCache::State::Installed
},
359 {"half-installed",pkgCache::State::HalfInstalled
},
360 {"config-files",pkgCache::State::ConfigFiles
},
361 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
362 {"triggers-pending",pkgCache::State::TriggersPending
},
363 {"post-inst-failed",pkgCache::State::HalfConfigured
},
364 {"removal-failed",pkgCache::State::HalfInstalled
},
366 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
367 return _error
->Error("Malformed 3rd word in the Status line");
369 /* A Status line marks the package as indicating the current
370 version as well. Only if it is actually installed.. Otherwise
371 the interesting dpkg handling of the status file creates bogus
373 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
374 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
376 if (Ver
.end() == true)
377 _error
->Warning("Encountered status field in a non-version description");
379 Pkg
->CurrentVer
= Ver
.Index();
385 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
387 // Determine the operator
395 Op
= pkgCache::Dep::LessEq
;
402 Op
= pkgCache::Dep::Less
;
406 // < is the same as <= and << is really Cs < for some reason
407 Op
= pkgCache::Dep::LessEq
;
415 Op
= pkgCache::Dep::GreaterEq
;
422 Op
= pkgCache::Dep::Greater
;
426 // > is the same as >= and >> is really Cs > for some reason
427 Op
= pkgCache::Dep::GreaterEq
;
431 Op
= pkgCache::Dep::Equals
;
435 // HACK around bad package definitions
437 Op
= pkgCache::Dep::Equals
;
444 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
445 // ---------------------------------------------------------------------
446 /* This parses the dependency elements out of a standard string in place,
448 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
449 string
&Package
,string
&Ver
,
450 unsigned int &Op
, bool const &ParseArchFlags
,
451 bool const &StripMultiArch
)
453 // Strip off leading space
454 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
456 // Parse off the package name
457 const char *I
= Start
;
458 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
459 *I
!= ',' && *I
!= '|'; I
++);
462 if (I
!= Stop
&& *I
== ')')
468 // Stash the package name
469 Package
.assign(Start
,I
- Start
);
471 // We don't want to confuse library users which can't handle MultiArch
472 if (StripMultiArch
== true) {
473 size_t const found
= Package
.rfind(':');
474 if (found
!= string::npos
)
475 Package
= Package
.substr(0,found
);
478 // Skip white space to the '('
479 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
482 if (I
!= Stop
&& *I
== '(')
485 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
488 I
= ConvertRelation(I
,Op
);
491 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
493 for (;I
!= Stop
&& *I
!= ')'; I
++);
494 if (I
== Stop
|| Start
== I
)
497 // Skip trailing whitespace
499 for (; End
> Start
&& isspace(End
[-1]); End
--);
501 Ver
.assign(Start
,End
-Start
);
507 Op
= pkgCache::Dep::NoOp
;
511 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
513 if (ParseArchFlags
== true)
515 string arch
= _config
->Find("APT::Architecture");
517 // Parse an architecture
518 if (I
!= Stop
&& *I
== '[')
527 bool NegArch
= false;
530 // look for whitespace or ending ']'
531 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
543 if (stringcmp(arch
,I
,End
) == 0)
552 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
559 Package
= ""; /* not for this arch */
563 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
566 if (I
!= Stop
&& *I
== '|')
567 Op
|= pkgCache::Dep::Or
;
569 if (I
== Stop
|| *I
== ',' || *I
== '|')
572 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
579 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
580 // ---------------------------------------------------------------------
581 /* This is the higher level depends parser. It takes a tag and generates
582 a complete depends tree for the given version. */
583 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
584 const char *Tag
,unsigned int Type
)
588 if (Section
.Find(Tag
,Start
,Stop
) == false)
592 string
const pkgArch
= Ver
.Arch();
598 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
600 return _error
->Error("Problem parsing dependency %s",Tag
);
602 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
610 // ListParser::ParseProvides - Parse the provides list /*{{{*/
611 // ---------------------------------------------------------------------
613 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
617 if (Section
.Find("Provides",Start
,Stop
) == false)
626 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
628 return _error
->Error("Problem parsing Provides line");
629 if (Op
!= pkgCache::Dep::NoOp
) {
630 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
632 if (NewProvides(Ver
,Package
,Version
) == false)
643 // ListParser::GrabWord - Matches a word and returns /*{{{*/
644 // ---------------------------------------------------------------------
645 /* Looks for a word in a list of words - for ParseStatus */
646 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
648 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
650 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
659 // ListParser::Step - Move to the next section in the file /*{{{*/
660 // ---------------------------------------------------------------------
661 /* This has to be carefull to only process the correct architecture */
662 bool debListParser::Step()
664 iOffset
= Tags
.Offset();
665 while (Tags
.Step(Section
) == true)
667 /* See if this is the correct Architecture, if it isn't then we
668 drop the whole section. A missing arch tag only happens (in theory)
669 inside the Status file, so that is a positive return */
670 string
const Architecture
= Section
.FindS("Architecture");
671 if (Architecture
.empty() == true)
674 if (Arch
.empty() == true)
676 if (APT::Configuration::checkArchitecture(Architecture
) == true)
681 if (Architecture
== Arch
)
684 if (Architecture
== "all")
688 iOffset
= Tags
.Offset();
693 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
694 // ---------------------------------------------------------------------
696 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
697 FileFd
&File
, string component
)
699 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
700 pkgTagSection Section
;
701 if (Tags
.Step(Section
) == false)
704 // FIXME: Do we need it now for multi-arch?
705 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
706 // FileI->Architecture = WriteUniqString(Arch);
708 // apt-secure does no longer download individual (per-section) Release
709 // file. to provide Component pinning we use the section name now
710 FileI
->Component
= WriteUniqString(component
);
714 if (Section
.Find("Suite",Start
,Stop
) == true)
715 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
716 if (Section
.Find("Component",Start
,Stop
) == true)
717 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
718 if (Section
.Find("Version",Start
,Stop
) == true)
719 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
720 if (Section
.Find("Origin",Start
,Stop
) == true)
721 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
722 if (Section
.Find("Codename",Start
,Stop
) == true)
723 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
724 if (Section
.Find("Label",Start
,Stop
) == true)
725 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
726 if (Section
.Find("Architecture",Start
,Stop
) == true)
727 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
729 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
730 pkgCache::Flag::NotAutomatic
) == false)
731 _error
->Warning("Bad NotAutomatic flag");
733 return !_error
->PendingError();
736 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
737 // ---------------------------------------------------------------------
739 unsigned char debListParser::GetPrio(string Str
)
742 if (GrabWord(Str
,PrioList
,Out
) == false)
743 Out
= pkgCache::State::Extra
;