]>
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>
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 // ---------------------------------------------------------------------
36 debListParser::debListParser(FileFd
*File
) : Tags(File
)
38 Arch
= _config
->Find("APT::architecture");
41 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
42 // ---------------------------------------------------------------------
44 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
48 if (Section
.Find(Tag
,Start
,Stop
) == false)
50 return WriteUniqString(Start
,Stop
- Start
);
53 // ListParser::Package - Return the package name /*{{{*/
54 // ---------------------------------------------------------------------
55 /* This is to return the name of the package this section describes */
56 string
debListParser::Package() {
57 string
const Result
= Section
.FindS("Package");
58 if(unlikely(Result
.empty() == true))
59 _error
->Error("Encountered a section with no Package: header");
63 // ListParser::Architecture - Return the package arch /*{{{*/
64 // ---------------------------------------------------------------------
65 /* This will return the Architecture of the package this section describes
66 Note that architecture "all" packages will get the architecture of the
67 Packages file parsed here */
68 string
debListParser::Architecture() {
69 string
const Result
= Section
.FindS("Architecture");
70 if (Result
.empty() == true)
77 // ListParser::Version - Return the version string /*{{{*/
78 // ---------------------------------------------------------------------
79 /* This is to return the string describing the version in debian form,
80 epoch:upstream-release. If this returns the blank string then the
81 entry is assumed to only describe package properties */
82 string
debListParser::Version()
84 return Section
.FindS("Version");
87 // ListParser::NewVersion - Fill in the version structure /*{{{*/
88 // ---------------------------------------------------------------------
90 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
93 Ver
->Section
= UniqFindTagWrite("Section");
95 // Parse the architecture
96 Ver
->Arch
= WriteUniqString(Architecture());
99 Ver
->Size
= (unsigned)Section
.FindI("Size");
101 // Unpacked Size (in K)
102 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
103 Ver
->InstalledSize
*= 1024;
108 if (Section
.Find("Priority",Start
,Stop
) == true)
110 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
111 Ver
->Priority
= pkgCache::State::Extra
;
114 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
116 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
118 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
120 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
122 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
124 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
126 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
128 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
132 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
135 if (ParseProvides(Ver
) == false)
141 // ListParser::Description - Return the description string /*{{{*/
142 // ---------------------------------------------------------------------
143 /* This is to return the string describing the package in debian
144 form. If this returns the blank string then the entry is assumed to
145 only describe package properties */
146 string
debListParser::Description()
148 string
const lang
= DescriptionLanguage();
150 return Section
.FindS("Description");
152 return Section
.FindS(string("Description-").append(lang
).c_str());
155 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
156 // ---------------------------------------------------------------------
157 /* This is to return the string describing the language of
158 description. If this returns the blank string then the entry is
159 assumed to describe original description. */
160 string
debListParser::DescriptionLanguage()
162 if (Section
.FindS("Description").empty() == false)
165 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
166 for (std::vector
<string
>::const_iterator l
= lang
.begin();
167 l
!= lang
.end(); l
++)
168 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
174 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
175 // ---------------------------------------------------------------------
176 /* This is to return the md5 string to allow the check if it is the right
177 description. If no Description-md5 is found in the section it will be
180 MD5SumValue
debListParser::Description_md5()
182 string value
= Section
.FindS("Description-md5");
187 md5
.Add((Description() + "\n").c_str());
190 return MD5SumValue(value
);
193 // ListParser::UsePackage - Update a package structure /*{{{*/
194 // ---------------------------------------------------------------------
195 /* This is called to update the package with any new information
196 that might be found in the section */
197 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
198 pkgCache::VerIterator Ver
)
200 if (Pkg
->Section
== 0)
201 Pkg
->Section
= UniqFindTagWrite("Section");
202 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
204 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
207 if (strcmp(Pkg
.Name(),"apt") == 0)
208 Pkg
->Flags
|= pkgCache::Flag::Important
;
210 if (ParseStatus(Pkg
,Ver
) == false)
215 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
216 // ---------------------------------------------------------------------
218 unsigned short debListParser::VersionHash()
220 const char *Sections
[] ={"Installed-Size",
228 unsigned long Result
= INIT_FCS
;
230 for (const char **I
= Sections
; *I
!= 0; I
++)
234 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
237 /* Strip out any spaces from the text, this undoes dpkgs reformatting
238 of certain fields. dpkg also has the rather interesting notion of
239 reformatting depends operators < -> <= */
241 for (; Start
!= End
; Start
++)
243 if (isspace(*Start
) == 0)
244 *I
++ = tolower_ascii(*Start
);
245 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
247 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
251 Result
= AddCRC16(Result
,S
,I
- S
);
257 // ListParser::ParseStatus - Parse the status field /*{{{*/
258 // ---------------------------------------------------------------------
259 /* Status lines are of the form,
260 Status: want flag status
261 want = unknown, install, hold, deinstall, purge
262 flag = ok, reinstreq, hold, hold-reinstreq
263 status = not-installed, unpacked, half-configured,
264 half-installed, config-files, post-inst-failed,
265 removal-failed, installed
267 Some of the above are obsolete (I think?) flag = hold-* and
268 status = post-inst-failed, removal-failed at least.
270 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
271 pkgCache::VerIterator Ver
)
275 if (Section
.Find("Status",Start
,Stop
) == false)
278 // Isolate the first word
279 const char *I
= Start
;
280 for(; I
< Stop
&& *I
!= ' '; I
++);
281 if (I
>= Stop
|| *I
!= ' ')
282 return _error
->Error("Malformed Status line");
284 // Process the want field
285 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
286 {"install",pkgCache::State::Install
},
287 {"hold",pkgCache::State::Hold
},
288 {"deinstall",pkgCache::State::DeInstall
},
289 {"purge",pkgCache::State::Purge
},
291 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
292 return _error
->Error("Malformed 1st word in the Status line");
294 // Isloate the next word
297 for(; I
< Stop
&& *I
!= ' '; I
++);
298 if (I
>= Stop
|| *I
!= ' ')
299 return _error
->Error("Malformed status line, no 2nd word");
301 // Process the flag field
302 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
303 {"reinstreq",pkgCache::State::ReInstReq
},
304 {"hold",pkgCache::State::HoldInst
},
305 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
307 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
308 return _error
->Error("Malformed 2nd word in the Status line");
310 // Isloate the last word
313 for(; I
< Stop
&& *I
!= ' '; I
++);
315 return _error
->Error("Malformed Status line, no 3rd word");
317 // Process the flag field
318 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
319 {"unpacked",pkgCache::State::UnPacked
},
320 {"half-configured",pkgCache::State::HalfConfigured
},
321 {"installed",pkgCache::State::Installed
},
322 {"half-installed",pkgCache::State::HalfInstalled
},
323 {"config-files",pkgCache::State::ConfigFiles
},
324 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
325 {"triggers-pending",pkgCache::State::TriggersPending
},
326 {"post-inst-failed",pkgCache::State::HalfConfigured
},
327 {"removal-failed",pkgCache::State::HalfInstalled
},
329 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
330 return _error
->Error("Malformed 3rd word in the Status line");
332 /* A Status line marks the package as indicating the current
333 version as well. Only if it is actually installed.. Otherwise
334 the interesting dpkg handling of the status file creates bogus
336 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
337 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
339 if (Ver
.end() == true)
340 _error
->Warning("Encountered status field in a non-version description");
342 Pkg
->CurrentVer
= Ver
.Index();
348 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
350 // Determine the operator
358 Op
= pkgCache::Dep::LessEq
;
365 Op
= pkgCache::Dep::Less
;
369 // < is the same as <= and << is really Cs < for some reason
370 Op
= pkgCache::Dep::LessEq
;
378 Op
= pkgCache::Dep::GreaterEq
;
385 Op
= pkgCache::Dep::Greater
;
389 // > is the same as >= and >> is really Cs > for some reason
390 Op
= pkgCache::Dep::GreaterEq
;
394 Op
= pkgCache::Dep::Equals
;
398 // HACK around bad package definitions
400 Op
= pkgCache::Dep::Equals
;
407 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
408 // ---------------------------------------------------------------------
409 /* This parses the dependency elements out of a standard string in place,
411 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
412 string
&Package
,string
&Ver
,
413 unsigned int &Op
, bool const &ParseArchFlags
,
414 bool const &StripMultiArch
)
416 // Strip off leading space
417 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
419 // Parse off the package name
420 const char *I
= Start
;
421 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
422 *I
!= ',' && *I
!= '|'; I
++);
425 if (I
!= Stop
&& *I
== ')')
431 // Stash the package name
432 Package
.assign(Start
,I
- Start
);
434 // We don't want to confuse library users which can't handle MultiArch
435 if (StripMultiArch
== true) {
436 size_t const found
= Package
.rfind(':');
437 if (found
!= string::npos
)
438 Package
= Package
.substr(0,found
);
441 // Skip white space to the '('
442 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
445 if (I
!= Stop
&& *I
== '(')
448 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
451 I
= ConvertRelation(I
,Op
);
454 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
456 for (;I
!= Stop
&& *I
!= ')'; I
++);
457 if (I
== Stop
|| Start
== I
)
460 // Skip trailing whitespace
462 for (; End
> Start
&& isspace(End
[-1]); End
--);
464 Ver
.assign(Start
,End
-Start
);
470 Op
= pkgCache::Dep::NoOp
;
474 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
476 if (ParseArchFlags
== true)
478 string arch
= _config
->Find("APT::Architecture");
480 // Parse an architecture
481 if (I
!= Stop
&& *I
== '[')
490 bool NegArch
= false;
493 // look for whitespace or ending ']'
494 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
506 if (stringcmp(arch
,I
,End
) == 0)
515 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
522 Package
= ""; /* not for this arch */
526 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
529 if (I
!= Stop
&& *I
== '|')
530 Op
|= pkgCache::Dep::Or
;
532 if (I
== Stop
|| *I
== ',' || *I
== '|')
535 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
542 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
543 // ---------------------------------------------------------------------
544 /* This is the higher level depends parser. It takes a tag and generates
545 a complete depends tree for the given version. */
546 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
547 const char *Tag
,unsigned int Type
)
551 if (Section
.Find(Tag
,Start
,Stop
) == false)
555 string
const pkgArch
= Ver
.Arch();
561 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
563 return _error
->Error("Problem parsing dependency %s",Tag
);
565 if (NewDepends(Ver
,Package
,pkgArch
,Version
,Op
,Type
) == false)
573 // ListParser::ParseProvides - Parse the provides list /*{{{*/
574 // ---------------------------------------------------------------------
576 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
580 if (Section
.Find("Provides",Start
,Stop
) == false)
589 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
591 return _error
->Error("Problem parsing Provides line");
592 if (Op
!= pkgCache::Dep::NoOp
) {
593 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
595 if (NewProvides(Ver
,Package
,Version
) == false)
606 // ListParser::GrabWord - Matches a word and returns /*{{{*/
607 // ---------------------------------------------------------------------
608 /* Looks for a word in a list of words - for ParseStatus */
609 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
611 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
613 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
622 // ListParser::Step - Move to the next section in the file /*{{{*/
623 // ---------------------------------------------------------------------
624 /* This has to be carefull to only process the correct architecture */
625 bool debListParser::Step()
627 iOffset
= Tags
.Offset();
628 while (Tags
.Step(Section
) == true)
630 /* See if this is the correct Architecture, if it isn't then we
631 drop the whole section. A missing arch tag only happens (in theory)
632 inside the Status file, so that is a positive return */
635 if (Section
.Find("Architecture",Start
,Stop
) == false)
638 //FIXME: Accept different Architectures here
639 if (stringcmp(Arch
,Start
,Stop
) == 0)
642 if (stringcmp(Start
,Stop
,"all") == 0)
645 iOffset
= Tags
.Offset();
650 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
651 // ---------------------------------------------------------------------
653 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
654 FileFd
&File
, string component
)
656 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
657 pkgTagSection Section
;
658 if (Tags
.Step(Section
) == false)
661 // FIXME: Do we need it now for multi-arch?
662 // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
663 // FileI->Architecture = WriteUniqString(Arch);
665 // apt-secure does no longer download individual (per-section) Release
666 // file. to provide Component pinning we use the section name now
667 FileI
->Component
= WriteUniqString(component
);
671 if (Section
.Find("Suite",Start
,Stop
) == true)
672 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
673 if (Section
.Find("Component",Start
,Stop
) == true)
674 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
675 if (Section
.Find("Version",Start
,Stop
) == true)
676 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
677 if (Section
.Find("Origin",Start
,Stop
) == true)
678 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
679 if (Section
.Find("Codename",Start
,Stop
) == true)
680 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
681 if (Section
.Find("Label",Start
,Stop
) == true)
682 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
683 if (Section
.Find("Architecture",Start
,Stop
) == true)
684 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
686 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
687 pkgCache::Flag::NotAutomatic
) == false)
688 _error
->Warning("Bad NotAutomatic flag");
690 return !_error
->PendingError();
693 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
694 // ---------------------------------------------------------------------
696 unsigned char debListParser::GetPrio(string Str
)
699 if (GrabWord(Str
,PrioList
,Out
) == false)
700 Out
= pkgCache::State::Extra
;