]>
git.saurik.com Git - apt-legacy.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/strutl.h>
17 #include <apt-pkg/crc-16.h>
18 #include <apt-pkg/md5.h>
19 #include <apt-pkg/macros.h>
24 static debListParser::WordList PrioList
[] = {{"important",pkgCache::State::Important
},
25 {"required",pkgCache::State::Required
},
26 {"standard",pkgCache::State::Standard
},
27 {"optional",pkgCache::State::Optional
},
28 {"extra",pkgCache::State::Extra
},
31 // ListParser::debListParser - Constructor /*{{{*/
32 // ---------------------------------------------------------------------
34 debListParser::debListParser(FileFd
*File
) : Tags(File
)
36 Arch
= _config
->Find("APT::architecture");
39 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
40 // ---------------------------------------------------------------------
42 unsigned long debListParser::FindTagWrite(const char *Tag
)
46 if (Section
.Find(Tag
,Start
,Stop
) == false)
48 return WriteString(Start
,Stop
- Start
);
51 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
52 // ---------------------------------------------------------------------
54 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
58 if (Section
.Find(Tag
,Start
,Stop
) == false)
60 return WriteUniqString(Start
,Stop
- Start
);
63 // ListParser::Package - Return the package name /*{{{*/
64 // ---------------------------------------------------------------------
65 /* This is to return the name of the package this section describes */
66 string
debListParser::Package()
68 string Result
= Section
.FindS("Package");
69 if (Result
.empty() == true)
70 _error
->Error("Encountered a section with no Package: header");
74 // ListParser::Version - Return the version string /*{{{*/
75 // ---------------------------------------------------------------------
76 /* This is to return the string describing the version in debian form,
77 epoch:upstream-release. If this returns the blank string then the
78 entry is assumed to only describe package properties */
79 string
debListParser::Version()
81 return Section
.FindS("Version");
84 // ListParser::NewVersion - Fill in the version structure /*{{{*/
85 // ---------------------------------------------------------------------
87 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
89 Ver
->Display
= FindTagWrite("Name");
90 if (Ver
->Display
== 0)
91 Ver
->Display
= FindTagWrite("Maemo-Display-Name");
94 Ver
->Section
= UniqFindTagWrite("Section");
95 Ver
->Arch
= UniqFindTagWrite("Architecture");
98 Ver
->Size
= (unsigned)Section
.FindI("Size");
100 // Unpacked Size (in K)
101 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
102 Ver
->InstalledSize
*= 1024;
107 if (Section
.Find("Priority",Start
,Stop
) == true)
109 if (GrabWord(srkString(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
110 Ver
->Priority
= pkgCache::State::Extra
;
113 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
115 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
117 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
119 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
121 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
123 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
125 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
127 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
131 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
134 if (ParseProvides(Ver
) == false)
140 // ListParser::Description - Return the description string /*{{{*/
141 // ---------------------------------------------------------------------
142 /* This is to return the string describing the package in debian
143 form. If this returns the blank string then the entry is assumed to
144 only describe package properties */
145 string
debListParser::Description()
147 srkString description
;
148 Description(description
);
152 void debListParser::Description(srkString
&Str
) {
153 const char *Start
, *Stop
;
154 if (!Section
.Find("Description", Start
, Stop
))
155 if (!Section
.Find(("Description-" + pkgIndexFile::LanguageCode()).c_str(), Start
, Stop
)) {
159 Str
.assign(Start
, Stop
);
162 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
163 // ---------------------------------------------------------------------
164 /* This is to return the string describing the language of
165 description. If this returns the blank string then the entry is
166 assumed to describe original description. */
167 string
debListParser::DescriptionLanguage()
169 const char *Start
, *Stop
;
170 return Section
.Find("Description", Start
, Stop
) ? std::string() : pkgIndexFile::LanguageCode();
173 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
174 // ---------------------------------------------------------------------
175 /* This is to return the md5 string to allow the check if it is the right
176 description. If no Description-md5 is found in the section it will be
179 MD5SumValue
debListParser::Description_md5()
183 if (!Section
.Find("Description-md5", Start
, Stop
))
186 srkString description
;
187 Description(description
);
188 md5
.Add((const unsigned char *) description
.Start
, description
.Size
);
192 return MD5SumValue(srkString(Start
, Stop
));
195 // ListParser::UsePackage - Update a package structure /*{{{*/
196 // ---------------------------------------------------------------------
197 /* This is called to update the package with any new information
198 that might be found in the section */
199 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
200 pkgCache::VerIterator Ver
)
202 if (Pkg
->Display
== 0)
203 Pkg
->Display
= FindTagWrite("Name");
204 if (Pkg
->Display
== 0)
205 Pkg
->Display
= FindTagWrite("Maemo-Display-Name");
206 if (Pkg
->Section
== 0)
207 Pkg
->Section
= UniqFindTagWrite("Section");
208 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
210 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
213 if (strcmp(Pkg
.Name(),"apt") == 0)
214 Pkg
->Flags
|= pkgCache::Flag::Important
;
216 if (ParseStatus(Pkg
,Ver
) == false)
219 if (Pkg
->TagList
== 0)
220 if (ParseTag(Pkg
) == false)
226 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
227 // ---------------------------------------------------------------------
229 unsigned short debListParser::VersionHash()
231 const char *Sections
[] ={"Installed-Size",
239 unsigned long Result
= INIT_FCS
;
241 for (const char **I
= Sections
; *I
!= 0; I
++)
245 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
249 /* Strip out any spaces from the text, this undoes dpkgs reformatting
250 of certain fields. dpkg also has the rather interesting notion of
251 reformatting depends operators < -> <= */
253 for (; Start
!= End
; Start
++)
255 if (isspace(*Start
) == 0)
256 *I
++ = tolower_ascii(*Start
);
257 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
259 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
263 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(srkString(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(srkString(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(srkString(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 ParseArchFlags
)
428 srkString cPackage
, cVer
;
429 const char *Value
= ParseDepends(Start
, Stop
, cPackage
, cVer
, Op
, ParseArchFlags
);
435 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
436 srkString
&Package
,srkString
&Ver
,
437 unsigned int &Op
, bool ParseArchFlags
)
439 // Strip off leading space
440 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
442 // Parse off the package name
443 const char *I
= Start
;
444 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
445 *I
!= ',' && *I
!= '|'; I
++);
448 if (I
!= Stop
&& *I
== ')')
454 // Stash the package name
455 Package
.assign(Start
,I
- Start
);
457 // Skip white space to the '('
458 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
461 if (I
!= Stop
&& *I
== '(')
464 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
467 I
= ConvertRelation(I
,Op
);
470 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
472 for (;I
!= Stop
&& *I
!= ')'; I
++);
473 if (I
== Stop
|| Start
== I
)
476 // Skip trailing whitespace
478 for (; End
> Start
&& isspace(End
[-1]); End
--);
480 Ver
.assign(Start
,End
-Start
);
486 Op
= pkgCache::Dep::NoOp
;
490 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
492 if (ParseArchFlags
== true)
494 string arch
= _config
->Find("APT::Architecture");
496 // Parse an architecture
497 if (I
!= Stop
&& *I
== '[')
506 bool NegArch
= false;
509 // look for whitespace or ending ']'
510 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
522 if (stringcmp(arch
,I
,End
) == 0)
531 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
538 Package
.clear(); /* not for this arch */
542 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
545 if (I
!= Stop
&& *I
== '|')
546 Op
|= pkgCache::Dep::Or
;
548 if (I
== Stop
|| *I
== ',' || *I
== '|')
551 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
558 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
559 // ---------------------------------------------------------------------
560 /* This is the higher level depends parser. It takes a tag and generates
561 a complete depends tree for the given version. */
562 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
563 const char *Tag
,unsigned int Type
)
567 if (Section
.Find(Tag
,Start
,Stop
) == false)
576 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
578 _error
->Warning("Problem parsing dependency %s",Tag
);
582 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
590 // ListParser::ParseProvides - Parse the provides list /*{{{*/
591 // ---------------------------------------------------------------------
593 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
597 if (Section
.Find("Provides",Start
,Stop
) == false)
606 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
608 _error
->Warning("Problem parsing Provides line");
612 if (Op
!= pkgCache::Dep::NoOp
) {
613 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", std::string(Package
).c_str());
615 if (NewProvides(Ver
,Package
,Version
) == false)
626 // ListParser::ParseTag - Parse the tag list /*{{{*/
627 // ---------------------------------------------------------------------
629 bool debListParser::ParseTag(pkgCache::PkgIterator Pkg
)
633 if (Section
.Find("Tag",Start
,Stop
) == false)
640 if (Stop
[-1] != ' ' && Stop
[-1] != '\t')
645 const char *Begin
= Stop
- 1;
646 while (Begin
!= Start
&& Begin
[-1] != ' ' && Begin
[-1] != ',')
649 if (NewTag(Pkg
, Begin
, Stop
- Begin
) == false)
655 if (Begin
[-1] == ',')
666 // ListParser::GrabWord - Matches a word and returns /*{{{*/
667 // ---------------------------------------------------------------------
668 /* Looks for a word in a list of words - for ParseStatus */
669 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
671 return GrabWord(srkString(Word
), List
, Out
);
674 bool debListParser::GrabWord(const srkString
&Word
,WordList
*List
,unsigned char &Out
)
676 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
678 if (strncasecmp(Word
.Start
,List
[C
].Str
,Word
.Size
) == 0)
687 // ListParser::Step - Move to the next section in the file /*{{{*/
688 // ---------------------------------------------------------------------
689 /* This has to be carefull to only process the correct architecture */
690 bool debListParser::Step()
692 iOffset
= Tags
.Offset();
693 while (Tags
.Step(Section
) == true)
698 if (Section
.Find("Package",Start
,Stop
) == false) {
699 _error
->Warning("Encountered a section with no Package: header");
703 /* See if this is the correct Architecture, if it isn't then we
704 drop the whole section. A missing arch tag only happens (in theory)
705 inside the Status file, so that is a positive return */
707 if (Section
.Find("Architecture",Start
,Stop
) == false)
710 if (stringcmp(Arch
,Start
,Stop
) == 0)
713 if (stringcmp(Start
,Stop
,"all") == 0)
716 if (stringcmp(Start
,Stop
,"cydia") == 0)
719 iOffset
= Tags
.Offset();
724 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
725 // ---------------------------------------------------------------------
727 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
728 FileFd
&File
, string component
)
730 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
731 pkgTagSection Section
;
732 if (Tags
.Step(Section
) == false)
735 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
736 //FileI->Architecture = WriteUniqString(Arch);
738 // apt-secure does no longer download individual (per-section) Release
739 // file. to provide Component pinning we use the section name now
740 FileI
->Component
= WriteUniqString(component
);
744 if (Section
.Find("Suite",Start
,Stop
) == true)
745 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
746 if (Section
.Find("Component",Start
,Stop
) == true)
747 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
748 if (Section
.Find("Version",Start
,Stop
) == true)
749 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
750 if (Section
.Find("Origin",Start
,Stop
) == true)
751 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
752 if (Section
.Find("Label",Start
,Stop
) == true)
753 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
754 if (Section
.Find("Architecture",Start
,Stop
) == true)
755 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
757 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
758 pkgCache::Flag::NotAutomatic
) == false)
759 _error
->Warning("Bad NotAutomatic flag");
761 return !_error
->PendingError();
764 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
765 // ---------------------------------------------------------------------
767 unsigned char debListParser::GetPrio(string Str
)
770 if (GrabWord(Str
,PrioList
,Out
) == false)
771 Out
= pkgCache::State::Extra
;