]>
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/strutl.h>
17 #include <apt-pkg/crc-16.h>
18 #include <apt-pkg/md5.h>
25 static debListParser::WordList PrioList
[] = {{"important",pkgCache::State::Important
},
26 {"required",pkgCache::State::Required
},
27 {"standard",pkgCache::State::Standard
},
28 {"optional",pkgCache::State::Optional
},
29 {"extra",pkgCache::State::Extra
},
32 // ListParser::debListParser - Constructor /*{{{*/
33 // ---------------------------------------------------------------------
35 debListParser::debListParser(FileFd
*File
) : Tags(File
)
37 Arch
= _config
->Find("APT::architecture");
40 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
41 // ---------------------------------------------------------------------
43 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
47 if (Section
.Find(Tag
,Start
,Stop
) == false)
49 return WriteUniqString(Start
,Stop
- Start
);
52 // ListParser::Package - Return the package name /*{{{*/
53 // ---------------------------------------------------------------------
54 /* This is to return the name of the package this section describes */
55 string
debListParser::Package()
57 string Result
= Section
.FindS("Package");
58 if (Result
.empty() == true)
59 _error
->Error("Encountered a section with no Package: header");
63 // ListParser::Version - Return the version string /*{{{*/
64 // ---------------------------------------------------------------------
65 /* This is to return the string describing the version in debian form,
66 epoch:upstream-release. If this returns the blank string then the
67 entry is assumed to only describe package properties */
68 string
debListParser::Version()
70 return Section
.FindS("Version");
73 // ListParser::NewVersion - Fill in the version structure /*{{{*/
74 // ---------------------------------------------------------------------
76 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
79 Ver
->Section
= UniqFindTagWrite("Section");
80 Ver
->Arch
= UniqFindTagWrite("Architecture");
83 Ver
->Size
= (unsigned)Section
.FindI("Size");
85 // Unpacked Size (in K)
86 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
87 Ver
->InstalledSize
*= 1024;
92 if (Section
.Find("Priority",Start
,Stop
) == true)
94 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
95 Ver
->Priority
= pkgCache::State::Extra
;
98 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
100 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
102 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
104 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
106 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
108 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
110 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
112 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
116 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
119 if (ParseProvides(Ver
) == false)
125 // ListParser::Description - Return the description string /*{{{*/
126 // ---------------------------------------------------------------------
127 /* This is to return the string describing the package in debian
128 form. If this returns the blank string then the entry is assumed to
129 only describe package properties */
130 string
debListParser::Description()
132 if (DescriptionLanguage().empty())
133 return Section
.FindS("Description");
135 return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
138 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
139 // ---------------------------------------------------------------------
140 /* This is to return the string describing the language of
141 description. If this returns the blank string then the entry is
142 assumed to describe original description. */
143 string
debListParser::DescriptionLanguage()
145 return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
148 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
149 // ---------------------------------------------------------------------
150 /* This is to return the md5 string to allow the check if it is the right
151 description. If no Description-md5 is found in the section it will be
154 MD5SumValue
debListParser::Description_md5()
156 string value
= Section
.FindS("Description-md5");
161 md5
.Add((Description() + "\n").c_str());
164 return MD5SumValue(value
);
167 // ListParser::UsePackage - Update a package structure /*{{{*/
168 // ---------------------------------------------------------------------
169 /* This is called to update the package with any new information
170 that might be found in the section */
171 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
172 pkgCache::VerIterator Ver
)
174 if (Pkg
->Section
== 0)
175 Pkg
->Section
= UniqFindTagWrite("Section");
176 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
178 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
181 if (strcmp(Pkg
.Name(),"apt") == 0)
182 Pkg
->Flags
|= pkgCache::Flag::Important
;
184 if (ParseStatus(Pkg
,Ver
) == false)
189 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
190 // ---------------------------------------------------------------------
192 unsigned short debListParser::VersionHash()
194 const char *Sections
[] ={"Installed-Size",
202 unsigned long Result
= INIT_FCS
;
204 for (const char **I
= Sections
; *I
!= 0; I
++)
208 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
211 /* Strip out any spaces from the text, this undoes dpkgs reformatting
212 of certain fields. dpkg also has the rather interesting notion of
213 reformatting depends operators < -> <= */
215 for (; Start
!= End
; Start
++)
217 if (isspace(*Start
) == 0)
218 *I
++ = tolower_ascii(*Start
);
219 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
221 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
225 Result
= AddCRC16(Result
,S
,I
- S
);
231 // ListParser::ParseStatus - Parse the status field /*{{{*/
232 // ---------------------------------------------------------------------
233 /* Status lines are of the form,
234 Status: want flag status
235 want = unknown, install, hold, deinstall, purge
236 flag = ok, reinstreq, hold, hold-reinstreq
237 status = not-installed, unpacked, half-configured,
238 half-installed, config-files, post-inst-failed,
239 removal-failed, installed
241 Some of the above are obsolete (I think?) flag = hold-* and
242 status = post-inst-failed, removal-failed at least.
244 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
245 pkgCache::VerIterator Ver
)
249 if (Section
.Find("Status",Start
,Stop
) == false)
252 // Isolate the first word
253 const char *I
= Start
;
254 for(; I
< Stop
&& *I
!= ' '; I
++);
255 if (I
>= Stop
|| *I
!= ' ')
256 return _error
->Error("Malformed Status line");
258 // Process the want field
259 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
260 {"install",pkgCache::State::Install
},
261 {"hold",pkgCache::State::Hold
},
262 {"deinstall",pkgCache::State::DeInstall
},
263 {"purge",pkgCache::State::Purge
},
265 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
266 return _error
->Error("Malformed 1st word in the Status line");
268 // Isloate the next word
271 for(; I
< Stop
&& *I
!= ' '; I
++);
272 if (I
>= Stop
|| *I
!= ' ')
273 return _error
->Error("Malformed status line, no 2nd word");
275 // Process the flag field
276 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
277 {"reinstreq",pkgCache::State::ReInstReq
},
278 {"hold",pkgCache::State::HoldInst
},
279 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
281 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
282 return _error
->Error("Malformed 2nd word in the Status line");
284 // Isloate the last word
287 for(; I
< Stop
&& *I
!= ' '; I
++);
289 return _error
->Error("Malformed Status line, no 3rd word");
291 // Process the flag field
292 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
293 {"unpacked",pkgCache::State::UnPacked
},
294 {"half-configured",pkgCache::State::HalfConfigured
},
295 {"installed",pkgCache::State::Installed
},
296 {"half-installed",pkgCache::State::HalfInstalled
},
297 {"config-files",pkgCache::State::ConfigFiles
},
298 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
299 {"triggers-pending",pkgCache::State::TriggersPending
},
300 {"post-inst-failed",pkgCache::State::HalfConfigured
},
301 {"removal-failed",pkgCache::State::HalfInstalled
},
303 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
304 return _error
->Error("Malformed 3rd word in the Status line");
306 /* A Status line marks the package as indicating the current
307 version as well. Only if it is actually installed.. Otherwise
308 the interesting dpkg handling of the status file creates bogus
310 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
311 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
313 if (Ver
.end() == true)
314 _error
->Warning("Encountered status field in a non-version description");
316 Pkg
->CurrentVer
= Ver
.Index();
322 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
324 // Determine the operator
332 Op
= pkgCache::Dep::LessEq
;
339 Op
= pkgCache::Dep::Less
;
343 // < is the same as <= and << is really Cs < for some reason
344 Op
= pkgCache::Dep::LessEq
;
352 Op
= pkgCache::Dep::GreaterEq
;
359 Op
= pkgCache::Dep::Greater
;
363 // > is the same as >= and >> is really Cs > for some reason
364 Op
= pkgCache::Dep::GreaterEq
;
368 Op
= pkgCache::Dep::Equals
;
372 // HACK around bad package definitions
374 Op
= pkgCache::Dep::Equals
;
381 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
382 // ---------------------------------------------------------------------
383 /* This parses the dependency elements out of a standard string in place,
385 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
386 string
&Package
,string
&Ver
,
387 unsigned int &Op
, bool ParseArchFlags
)
389 // Strip off leading space
390 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
392 // Parse off the package name
393 const char *I
= Start
;
394 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
395 *I
!= ',' && *I
!= '|'; I
++);
398 if (I
!= Stop
&& *I
== ')')
404 // Stash the package name
405 Package
.assign(Start
,I
- Start
);
407 // Skip white space to the '('
408 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
411 if (I
!= Stop
&& *I
== '(')
414 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
417 I
= ConvertRelation(I
,Op
);
420 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
422 for (;I
!= Stop
&& *I
!= ')'; I
++);
423 if (I
== Stop
|| Start
== I
)
426 // Skip trailing whitespace
428 for (; End
> Start
&& isspace(End
[-1]); End
--);
430 Ver
.assign(Start
,End
-Start
);
436 Op
= pkgCache::Dep::NoOp
;
440 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
442 if (ParseArchFlags
== true)
444 string arch
= _config
->Find("APT::Architecture");
446 // Parse an architecture
447 if (I
!= Stop
&& *I
== '[')
456 bool NegArch
= false;
459 // look for whitespace or ending ']'
460 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
472 if (stringcmp(arch
,I
,End
) == 0)
481 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
488 Package
= ""; /* not for this arch */
492 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
495 if (I
!= Stop
&& *I
== '|')
496 Op
|= pkgCache::Dep::Or
;
498 if (I
== Stop
|| *I
== ',' || *I
== '|')
501 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
508 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
509 // ---------------------------------------------------------------------
510 /* This is the higher level depends parser. It takes a tag and generates
511 a complete depends tree for the given version. */
512 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
513 const char *Tag
,unsigned int Type
)
517 if (Section
.Find(Tag
,Start
,Stop
) == false)
526 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
528 return _error
->Error("Problem parsing dependency %s",Tag
);
530 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
538 // ListParser::ParseProvides - Parse the provides list /*{{{*/
539 // ---------------------------------------------------------------------
541 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
545 if (Section
.Find("Provides",Start
,Stop
) == false)
554 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
556 return _error
->Error("Problem parsing Provides line");
557 if (Op
!= pkgCache::Dep::NoOp
) {
558 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
560 if (NewProvides(Ver
,Package
,Version
) == false)
571 // ListParser::GrabWord - Matches a word and returns /*{{{*/
572 // ---------------------------------------------------------------------
573 /* Looks for a word in a list of words - for ParseStatus */
574 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
576 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
578 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
587 // ListParser::Step - Move to the next section in the file /*{{{*/
588 // ---------------------------------------------------------------------
589 /* This has to be carefull to only process the correct architecture */
590 bool debListParser::Step()
592 iOffset
= Tags
.Offset();
593 while (Tags
.Step(Section
) == true)
595 /* See if this is the correct Architecture, if it isn't then we
596 drop the whole section. A missing arch tag only happens (in theory)
597 inside the Status file, so that is a positive return */
600 if (Section
.Find("Architecture",Start
,Stop
) == false)
603 if (stringcmp(Arch
,Start
,Stop
) == 0)
606 if (stringcmp(Start
,Stop
,"all") == 0)
609 iOffset
= Tags
.Offset();
614 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
615 // ---------------------------------------------------------------------
617 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
618 FileFd
&File
, string component
)
620 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
621 pkgTagSection Section
;
622 if (Tags
.Step(Section
) == false)
625 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
626 //FileI->Architecture = WriteUniqString(Arch);
628 // apt-secure does no longer download individual (per-section) Release
629 // file. to provide Component pinning we use the section name now
630 FileI
->Component
= WriteUniqString(component
);
634 if (Section
.Find("Suite",Start
,Stop
) == true)
635 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
636 if (Section
.Find("Component",Start
,Stop
) == true)
637 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
638 if (Section
.Find("Version",Start
,Stop
) == true)
639 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
640 if (Section
.Find("Origin",Start
,Stop
) == true)
641 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
642 if (Section
.Find("Codename",Start
,Stop
) == true)
643 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
644 if (Section
.Find("Label",Start
,Stop
) == true)
645 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
646 if (Section
.Find("Architecture",Start
,Stop
) == true)
647 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
649 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
650 pkgCache::Flag::NotAutomatic
) == false)
651 _error
->Warning("Bad NotAutomatic flag");
653 return !_error
->PendingError();
656 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
657 // ---------------------------------------------------------------------
659 unsigned char debListParser::GetPrio(string Str
)
662 if (GrabWord(Str
,PrioList
,Out
) == false)
663 Out
= pkgCache::State::Extra
;