]>
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>
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::UniqFindTagWrite(const char *Tag
)
46 if (Section
.Find(Tag
,Start
,Stop
) == false)
48 return WriteUniqString(Start
,Stop
- Start
);
51 // ListParser::Package - Return the package name /*{{{*/
52 // ---------------------------------------------------------------------
53 /* This is to return the name of the package this section describes */
54 string
debListParser::Package()
56 string Result
= Section
.FindS("Package");
57 if (Result
.empty() == true)
58 _error
->Error("Encountered a section with no Package: header");
62 // ListParser::Version - Return the version string /*{{{*/
63 // ---------------------------------------------------------------------
64 /* This is to return the string describing the version in debian form,
65 epoch:upstream-release. If this returns the blank string then the
66 entry is assumed to only describe package properties */
67 string
debListParser::Version()
69 return Section
.FindS("Version");
72 // ListParser::NewVersion - Fill in the version structure /*{{{*/
73 // ---------------------------------------------------------------------
75 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
78 Ver
->Section
= UniqFindTagWrite("Section");
79 Ver
->Arch
= UniqFindTagWrite("Architecture");
82 Ver
->Size
= (unsigned)Section
.FindI("Size");
84 // Unpacked Size (in K)
85 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
86 Ver
->InstalledSize
*= 1024;
91 if (Section
.Find("Priority",Start
,Stop
) == true)
93 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
94 Ver
->Priority
= pkgCache::State::Extra
;
97 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
99 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
101 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
103 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
105 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
107 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
109 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
111 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
115 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
118 if (ParseProvides(Ver
) == false)
124 // ListParser::Description - Return the description string /*{{{*/
125 // ---------------------------------------------------------------------
126 /* This is to return the string describing the package in debian
127 form. If this returns the blank string then the entry is assumed to
128 only describe package properties */
129 string
debListParser::Description()
131 if (DescriptionLanguage().empty())
132 return Section
.FindS("Description");
134 return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
137 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
138 // ---------------------------------------------------------------------
139 /* This is to return the string describing the language of
140 description. If this returns the blank string then the entry is
141 assumed to describe original description. */
142 string
debListParser::DescriptionLanguage()
144 return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
147 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
148 // ---------------------------------------------------------------------
149 /* This is to return the md5 string to allow the check if it is the right
150 description. If no Description-md5 is found in the section it will be
153 MD5SumValue
debListParser::Description_md5()
155 string value
= Section
.FindS("Description-md5");
160 md5
.Add((Description() + "\n").c_str());
163 return MD5SumValue(value
);
166 // ListParser::UsePackage - Update a package structure /*{{{*/
167 // ---------------------------------------------------------------------
168 /* This is called to update the package with any new information
169 that might be found in the section */
170 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
171 pkgCache::VerIterator Ver
)
173 if (Pkg
->Section
== 0)
174 Pkg
->Section
= UniqFindTagWrite("Section");
175 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
177 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
180 if (strcmp(Pkg
.Name(),"apt") == 0)
181 Pkg
->Flags
|= pkgCache::Flag::Important
;
183 if (ParseStatus(Pkg
,Ver
) == false)
188 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
189 // ---------------------------------------------------------------------
191 unsigned short debListParser::VersionHash()
193 const char *Sections
[] ={"Installed-Size",
201 unsigned long Result
= INIT_FCS
;
203 for (const char **I
= Sections
; *I
!= 0; I
++)
207 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
210 /* Strip out any spaces from the text, this undoes dpkgs reformatting
211 of certain fields. dpkg also has the rather interesting notion of
212 reformatting depends operators < -> <= */
214 for (; Start
!= End
; Start
++)
216 if (isspace(*Start
) == 0)
217 *I
++ = tolower_ascii(*Start
);
218 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
220 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
224 Result
= AddCRC16(Result
,S
,I
- S
);
230 // ListParser::ParseStatus - Parse the status field /*{{{*/
231 // ---------------------------------------------------------------------
232 /* Status lines are of the form,
233 Status: want flag status
234 want = unknown, install, hold, deinstall, purge
235 flag = ok, reinstreq, hold, hold-reinstreq
236 status = not-installed, unpacked, half-configured,
237 half-installed, config-files, post-inst-failed,
238 removal-failed, installed
240 Some of the above are obsolete (I think?) flag = hold-* and
241 status = post-inst-failed, removal-failed at least.
243 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
244 pkgCache::VerIterator Ver
)
248 if (Section
.Find("Status",Start
,Stop
) == false)
251 // Isolate the first word
252 const char *I
= Start
;
253 for(; I
< Stop
&& *I
!= ' '; I
++);
254 if (I
>= Stop
|| *I
!= ' ')
255 return _error
->Error("Malformed Status line");
257 // Process the want field
258 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
259 {"install",pkgCache::State::Install
},
260 {"hold",pkgCache::State::Hold
},
261 {"deinstall",pkgCache::State::DeInstall
},
262 {"purge",pkgCache::State::Purge
},
264 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
265 return _error
->Error("Malformed 1st word in the Status line");
267 // Isloate the next word
270 for(; I
< Stop
&& *I
!= ' '; I
++);
271 if (I
>= Stop
|| *I
!= ' ')
272 return _error
->Error("Malformed status line, no 2nd word");
274 // Process the flag field
275 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
276 {"reinstreq",pkgCache::State::ReInstReq
},
277 {"hold",pkgCache::State::HoldInst
},
278 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
280 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
281 return _error
->Error("Malformed 2nd word in the Status line");
283 // Isloate the last word
286 for(; I
< Stop
&& *I
!= ' '; I
++);
288 return _error
->Error("Malformed Status line, no 3rd word");
290 // Process the flag field
291 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
292 {"unpacked",pkgCache::State::UnPacked
},
293 {"half-configured",pkgCache::State::HalfConfigured
},
294 {"installed",pkgCache::State::Installed
},
295 {"half-installed",pkgCache::State::HalfInstalled
},
296 {"config-files",pkgCache::State::ConfigFiles
},
297 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
298 {"triggers-pending",pkgCache::State::TriggersPending
},
299 {"post-inst-failed",pkgCache::State::HalfConfigured
},
300 {"removal-failed",pkgCache::State::HalfInstalled
},
302 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
303 return _error
->Error("Malformed 3rd word in the Status line");
305 /* A Status line marks the package as indicating the current
306 version as well. Only if it is actually installed.. Otherwise
307 the interesting dpkg handling of the status file creates bogus
309 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
310 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
312 if (Ver
.end() == true)
313 _error
->Warning("Encountered status field in a non-version description");
315 Pkg
->CurrentVer
= Ver
.Index();
321 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
323 // Determine the operator
331 Op
= pkgCache::Dep::LessEq
;
338 Op
= pkgCache::Dep::Less
;
342 // < is the same as <= and << is really Cs < for some reason
343 Op
= pkgCache::Dep::LessEq
;
351 Op
= pkgCache::Dep::GreaterEq
;
358 Op
= pkgCache::Dep::Greater
;
362 // > is the same as >= and >> is really Cs > for some reason
363 Op
= pkgCache::Dep::GreaterEq
;
367 Op
= pkgCache::Dep::Equals
;
371 // HACK around bad package definitions
373 Op
= pkgCache::Dep::Equals
;
380 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
381 // ---------------------------------------------------------------------
382 /* This parses the dependency elements out of a standard string in place,
384 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
385 string
&Package
,string
&Ver
,
386 unsigned int &Op
, bool ParseArchFlags
)
388 // Strip off leading space
389 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
391 // Parse off the package name
392 const char *I
= Start
;
393 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
394 *I
!= ',' && *I
!= '|'; I
++);
397 if (I
!= Stop
&& *I
== ')')
403 // Stash the package name
404 Package
.assign(Start
,I
- Start
);
406 // Skip white space to the '('
407 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
410 if (I
!= Stop
&& *I
== '(')
413 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
416 I
= ConvertRelation(I
,Op
);
419 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
421 for (;I
!= Stop
&& *I
!= ')'; I
++);
422 if (I
== Stop
|| Start
== I
)
425 // Skip trailing whitespace
427 for (; End
> Start
&& isspace(End
[-1]); End
--);
429 Ver
.assign(Start
,End
-Start
);
435 Op
= pkgCache::Dep::NoOp
;
439 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
441 if (ParseArchFlags
== true)
443 string arch
= _config
->Find("APT::Architecture");
445 // Parse an architecture
446 if (I
!= Stop
&& *I
== '[')
455 bool NegArch
= false;
458 // look for whitespace or ending ']'
459 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
471 if (stringcmp(arch
,I
,End
) == 0)
480 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
487 Package
= ""; /* not for this arch */
491 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
494 if (I
!= Stop
&& *I
== '|')
495 Op
|= pkgCache::Dep::Or
;
497 if (I
== Stop
|| *I
== ',' || *I
== '|')
500 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
507 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
508 // ---------------------------------------------------------------------
509 /* This is the higher level depends parser. It takes a tag and generates
510 a complete depends tree for the given version. */
511 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
512 const char *Tag
,unsigned int Type
)
516 if (Section
.Find(Tag
,Start
,Stop
) == false)
525 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
527 return _error
->Error("Problem parsing dependency %s",Tag
);
529 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
537 // ListParser::ParseProvides - Parse the provides list /*{{{*/
538 // ---------------------------------------------------------------------
540 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
544 if (Section
.Find("Provides",Start
,Stop
) == false)
553 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
555 return _error
->Error("Problem parsing Provides line");
556 if (Op
!= pkgCache::Dep::NoOp
) {
557 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
559 if (NewProvides(Ver
,Package
,Version
) == false)
570 // ListParser::GrabWord - Matches a word and returns /*{{{*/
571 // ---------------------------------------------------------------------
572 /* Looks for a word in a list of words - for ParseStatus */
573 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
575 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
577 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
586 // ListParser::Step - Move to the next section in the file /*{{{*/
587 // ---------------------------------------------------------------------
588 /* This has to be carefull to only process the correct architecture */
589 bool debListParser::Step()
591 iOffset
= Tags
.Offset();
592 while (Tags
.Step(Section
) == true)
594 /* See if this is the correct Architecture, if it isn't then we
595 drop the whole section. A missing arch tag only happens (in theory)
596 inside the Status file, so that is a positive return */
599 if (Section
.Find("Architecture",Start
,Stop
) == false)
602 if (stringcmp(Arch
,Start
,Stop
) == 0)
605 if (stringcmp(Start
,Stop
,"all") == 0)
608 iOffset
= Tags
.Offset();
613 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
614 // ---------------------------------------------------------------------
616 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
617 FileFd
&File
, string component
)
619 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
620 pkgTagSection Section
;
621 if (Tags
.Step(Section
) == false)
624 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
625 //FileI->Architecture = WriteUniqString(Arch);
627 // apt-secure does no longer download individual (per-section) Release
628 // file. to provide Component pinning we use the section name now
629 FileI
->Component
= WriteUniqString(component
);
633 if (Section
.Find("Suite",Start
,Stop
) == true)
634 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
635 if (Section
.Find("Component",Start
,Stop
) == true)
636 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
637 if (Section
.Find("Version",Start
,Stop
) == true)
638 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
639 if (Section
.Find("Origin",Start
,Stop
) == true)
640 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
641 if (Section
.Find("Codename",Start
,Stop
) == true)
642 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
643 if (Section
.Find("Label",Start
,Stop
) == true)
644 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
645 if (Section
.Find("Architecture",Start
,Stop
) == true)
646 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
648 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
649 pkgCache::Flag::NotAutomatic
) == false)
650 _error
->Warning("Bad NotAutomatic flag");
652 return !_error
->PendingError();
655 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
656 // ---------------------------------------------------------------------
658 unsigned char debListParser::GetPrio(string Str
)
661 if (GrabWord(Str
,PrioList
,Out
) == false)
662 Out
= pkgCache::State::Extra
;