]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/deb/deblistparser.cc
20739e0dfa9c679ff4a5c7491f38b630bfcea323
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
))
248 /* Strip out any spaces from the text, this undoes dpkgs reformatting
249 of certain fields. dpkg also has the rather interesting notion of
250 reformatting depends operators < -> <= */
252 for (; Start
!= End
; Start
++)
254 if (isspace(*Start
) == 0)
255 *I
++ = tolower_ascii(*Start
);
256 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
258 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
262 Result
= AddCRC16(Result
,S
,I
- S
);
268 // ListParser::ParseStatus - Parse the status field /*{{{*/
269 // ---------------------------------------------------------------------
270 /* Status lines are of the form,
271 Status: want flag status
272 want = unknown, install, hold, deinstall, purge
273 flag = ok, reinstreq, hold, hold-reinstreq
274 status = not-installed, unpacked, half-configured,
275 half-installed, config-files, post-inst-failed,
276 removal-failed, installed
278 Some of the above are obsolete (I think?) flag = hold-* and
279 status = post-inst-failed, removal-failed at least.
281 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
282 pkgCache::VerIterator Ver
)
286 if (Section
.Find("Status",Start
,Stop
) == false)
289 // Isolate the first word
290 const char *I
= Start
;
291 for(; I
< Stop
&& *I
!= ' '; I
++);
292 if (I
>= Stop
|| *I
!= ' ')
293 return _error
->Error("Malformed Status line");
295 // Process the want field
296 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
297 {"install",pkgCache::State::Install
},
298 {"hold",pkgCache::State::Hold
},
299 {"deinstall",pkgCache::State::DeInstall
},
300 {"purge",pkgCache::State::Purge
},
302 if (GrabWord(srkString(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
303 return _error
->Error("Malformed 1st word in the Status line");
305 // Isloate the next word
308 for(; I
< Stop
&& *I
!= ' '; I
++);
309 if (I
>= Stop
|| *I
!= ' ')
310 return _error
->Error("Malformed status line, no 2nd word");
312 // Process the flag field
313 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
314 {"reinstreq",pkgCache::State::ReInstReq
},
315 {"hold",pkgCache::State::HoldInst
},
316 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
318 if (GrabWord(srkString(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
319 return _error
->Error("Malformed 2nd word in the Status line");
321 // Isloate the last word
324 for(; I
< Stop
&& *I
!= ' '; I
++);
326 return _error
->Error("Malformed Status line, no 3rd word");
328 // Process the flag field
329 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
330 {"unpacked",pkgCache::State::UnPacked
},
331 {"half-configured",pkgCache::State::HalfConfigured
},
332 {"installed",pkgCache::State::Installed
},
333 {"half-installed",pkgCache::State::HalfInstalled
},
334 {"config-files",pkgCache::State::ConfigFiles
},
335 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
336 {"triggers-pending",pkgCache::State::TriggersPending
},
337 {"post-inst-failed",pkgCache::State::HalfConfigured
},
338 {"removal-failed",pkgCache::State::HalfInstalled
},
340 if (GrabWord(srkString(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
341 return _error
->Error("Malformed 3rd word in the Status line");
343 /* A Status line marks the package as indicating the current
344 version as well. Only if it is actually installed.. Otherwise
345 the interesting dpkg handling of the status file creates bogus
347 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
348 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
350 if (Ver
.end() == true)
351 _error
->Warning("Encountered status field in a non-version description");
353 Pkg
->CurrentVer
= Ver
.Index();
359 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
361 // Determine the operator
369 Op
= pkgCache::Dep::LessEq
;
376 Op
= pkgCache::Dep::Less
;
380 // < is the same as <= and << is really Cs < for some reason
381 Op
= pkgCache::Dep::LessEq
;
389 Op
= pkgCache::Dep::GreaterEq
;
396 Op
= pkgCache::Dep::Greater
;
400 // > is the same as >= and >> is really Cs > for some reason
401 Op
= pkgCache::Dep::GreaterEq
;
405 Op
= pkgCache::Dep::Equals
;
409 // HACK around bad package definitions
411 Op
= pkgCache::Dep::Equals
;
418 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
419 // ---------------------------------------------------------------------
420 /* This parses the dependency elements out of a standard string in place,
422 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
423 string
&Package
,string
&Ver
,
424 unsigned int &Op
, bool ParseArchFlags
)
426 srkString cPackage
, cVer
;
427 const char *Value
= ParseDepends(Start
, Stop
, cPackage
, cVer
, Op
, ParseArchFlags
);
433 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
434 srkString
&Package
,srkString
&Ver
,
435 unsigned int &Op
, bool ParseArchFlags
)
437 // Strip off leading space
438 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
440 // Parse off the package name
441 const char *I
= Start
;
442 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
443 *I
!= ',' && *I
!= '|'; I
++);
446 if (I
!= Stop
&& *I
== ')')
452 // Stash the package name
453 Package
.assign(Start
,I
- Start
);
455 // Skip white space to the '('
456 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
459 if (I
!= Stop
&& *I
== '(')
462 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
465 I
= ConvertRelation(I
,Op
);
468 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
470 for (;I
!= Stop
&& *I
!= ')'; I
++);
471 if (I
== Stop
|| Start
== I
)
474 // Skip trailing whitespace
476 for (; End
> Start
&& isspace(End
[-1]); End
--);
478 Ver
.assign(Start
,End
-Start
);
484 Op
= pkgCache::Dep::NoOp
;
488 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
490 if (ParseArchFlags
== true)
492 string arch
= _config
->Find("APT::Architecture");
494 // Parse an architecture
495 if (I
!= Stop
&& *I
== '[')
504 bool NegArch
= false;
507 // look for whitespace or ending ']'
508 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
520 if (stringcmp(arch
,I
,End
) == 0)
529 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
536 Package
.clear(); /* not for this arch */
540 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
543 if (I
!= Stop
&& *I
== '|')
544 Op
|= pkgCache::Dep::Or
;
546 if (I
== Stop
|| *I
== ',' || *I
== '|')
549 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
556 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
557 // ---------------------------------------------------------------------
558 /* This is the higher level depends parser. It takes a tag and generates
559 a complete depends tree for the given version. */
560 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
561 const char *Tag
,unsigned int Type
)
565 if (Section
.Find(Tag
,Start
,Stop
) == false)
574 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
576 _error
->Warning("Problem parsing dependency %s",Tag
);
580 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
588 // ListParser::ParseProvides - Parse the provides list /*{{{*/
589 // ---------------------------------------------------------------------
591 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
595 if (Section
.Find("Provides",Start
,Stop
) == false)
604 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
606 _error
->Warning("Problem parsing Provides line");
610 if (Op
!= pkgCache::Dep::NoOp
) {
611 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", std::string(Package
).c_str());
613 if (NewProvides(Ver
,Package
,Version
) == false)
624 // ListParser::ParseTag - Parse the tag list /*{{{*/
625 // ---------------------------------------------------------------------
627 bool debListParser::ParseTag(pkgCache::PkgIterator Pkg
)
631 if (Section
.Find("Tag",Start
,Stop
) == false)
638 if (Stop
[-1] != ' ' && Stop
[-1] != '\t')
643 const char *Begin
= Stop
- 1;
644 while (Begin
!= Start
&& Begin
[-1] != ' ' && Begin
[-1] != ',')
647 if (NewTag(Pkg
, Begin
, Stop
- Begin
) == false)
653 if (Begin
[-1] == ',')
664 // ListParser::GrabWord - Matches a word and returns /*{{{*/
665 // ---------------------------------------------------------------------
666 /* Looks for a word in a list of words - for ParseStatus */
667 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
669 return GrabWord(srkString(Word
), List
, Out
);
672 bool debListParser::GrabWord(const srkString
&Word
,WordList
*List
,unsigned char &Out
)
674 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
676 if (strncasecmp(Word
.Start
,List
[C
].Str
,Word
.Size
) == 0)
685 // ListParser::Step - Move to the next section in the file /*{{{*/
686 // ---------------------------------------------------------------------
687 /* This has to be carefull to only process the correct architecture */
688 bool debListParser::Step()
690 iOffset
= Tags
.Offset();
691 while (Tags
.Step(Section
) == true)
696 if (Section
.Find("Package",Start
,Stop
) == false) {
697 _error
->Warning("Encountered a section with no Package: header");
701 /* See if this is the correct Architecture, if it isn't then we
702 drop the whole section. A missing arch tag only happens (in theory)
703 inside the Status file, so that is a positive return */
705 if (Section
.Find("Architecture",Start
,Stop
) == false)
708 if (stringcmp(Arch
,Start
,Stop
) == 0)
711 if (stringcmp(Start
,Stop
,"all") == 0)
714 if (stringcmp(Start
,Stop
,"cydia") == 0)
717 iOffset
= Tags
.Offset();
722 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
723 // ---------------------------------------------------------------------
725 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
726 FileFd
&File
, string component
)
728 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
729 pkgTagSection Section
;
730 if (Tags
.Step(Section
) == false)
733 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
734 //FileI->Architecture = WriteUniqString(Arch);
736 // apt-secure does no longer download individual (per-section) Release
737 // file. to provide Component pinning we use the section name now
738 FileI
->Component
= WriteUniqString(component
);
742 if (Section
.Find("Suite",Start
,Stop
) == true)
743 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
744 if (Section
.Find("Component",Start
,Stop
) == true)
745 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
746 if (Section
.Find("Version",Start
,Stop
) == true)
747 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
748 if (Section
.Find("Origin",Start
,Stop
) == true)
749 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
750 if (Section
.Find("Label",Start
,Stop
) == true)
751 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
752 if (Section
.Find("Architecture",Start
,Stop
) == true)
753 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
755 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
756 pkgCache::Flag::NotAutomatic
) == false)
757 _error
->Warning("Bad NotAutomatic flag");
759 return !_error
->PendingError();
762 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
763 // ---------------------------------------------------------------------
765 unsigned char debListParser::GetPrio(string Str
)
768 if (GrabWord(Str
,PrioList
,Out
) == false)
769 Out
= pkgCache::State::Extra
;