]>
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
,"Replaces",pkgCache::Dep::Replaces
) == false)
112 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
115 if (ParseProvides(Ver
) == false)
121 // ListParser::Description - Return the description string /*{{{*/
122 // ---------------------------------------------------------------------
123 /* This is to return the string describing the package in debian
124 form. If this returns the blank string then the entry is assumed to
125 only describe package properties */
126 string
debListParser::Description()
128 if (DescriptionLanguage().empty())
129 return Section
.FindS("Description");
131 return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
134 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
135 // ---------------------------------------------------------------------
136 /* This is to return the string describing the language of
137 description. If this returns the blank string then the entry is
138 assumed to describe original description. */
139 string
debListParser::DescriptionLanguage()
141 return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
144 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
145 // ---------------------------------------------------------------------
146 /* This is to return the md5 string to allow the check if it is the right
147 description. If no Description-md5 is found in the section it will be
150 MD5SumValue
debListParser::Description_md5()
152 string value
= Section
.FindS("Description-md5");
157 md5
.Add((Description() + "\n").c_str());
160 return MD5SumValue(value
);
163 // ListParser::UsePackage - Update a package structure /*{{{*/
164 // ---------------------------------------------------------------------
165 /* This is called to update the package with any new information
166 that might be found in the section */
167 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
168 pkgCache::VerIterator Ver
)
170 if (Pkg
->Section
== 0)
171 Pkg
->Section
= UniqFindTagWrite("Section");
172 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
174 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
177 if (strcmp(Pkg
.Name(),"apt") == 0)
178 Pkg
->Flags
|= pkgCache::Flag::Important
;
180 if (ParseStatus(Pkg
,Ver
) == false)
185 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
186 // ---------------------------------------------------------------------
188 unsigned short debListParser::VersionHash()
190 const char *Sections
[] ={"Installed-Size",
197 unsigned long Result
= INIT_FCS
;
199 for (const char **I
= Sections
; *I
!= 0; I
++)
203 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
206 /* Strip out any spaces from the text, this undoes dpkgs reformatting
207 of certain fields. dpkg also has the rather interesting notion of
208 reformatting depends operators < -> <= */
210 for (; Start
!= End
; Start
++)
212 if (isspace(*Start
) == 0)
213 *I
++ = tolower(*Start
);
214 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
216 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
220 Result
= AddCRC16(Result
,S
,I
- S
);
226 // ListParser::ParseStatus - Parse the status field /*{{{*/
227 // ---------------------------------------------------------------------
228 /* Status lines are of the form,
229 Status: want flag status
230 want = unknown, install, hold, deinstall, purge
231 flag = ok, reinstreq, hold, hold-reinstreq
232 status = not-installed, unpacked, half-configured,
233 half-installed, config-files, post-inst-failed,
234 removal-failed, installed
236 Some of the above are obsolete (I think?) flag = hold-* and
237 status = post-inst-failed, removal-failed at least.
239 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
240 pkgCache::VerIterator Ver
)
244 if (Section
.Find("Status",Start
,Stop
) == false)
247 // Isolate the first word
248 const char *I
= Start
;
249 for(; I
< Stop
&& *I
!= ' '; I
++);
250 if (I
>= Stop
|| *I
!= ' ')
251 return _error
->Error("Malformed Status line");
253 // Process the want field
254 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
255 {"install",pkgCache::State::Install
},
256 {"hold",pkgCache::State::Hold
},
257 {"deinstall",pkgCache::State::DeInstall
},
258 {"purge",pkgCache::State::Purge
},
260 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
261 return _error
->Error("Malformed 1st word in the Status line");
263 // Isloate the next word
266 for(; I
< Stop
&& *I
!= ' '; I
++);
267 if (I
>= Stop
|| *I
!= ' ')
268 return _error
->Error("Malformed status line, no 2nd word");
270 // Process the flag field
271 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
272 {"reinstreq",pkgCache::State::ReInstReq
},
273 {"hold",pkgCache::State::HoldInst
},
274 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
276 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
277 return _error
->Error("Malformed 2nd word in the Status line");
279 // Isloate the last word
282 for(; I
< Stop
&& *I
!= ' '; I
++);
284 return _error
->Error("Malformed Status line, no 3rd word");
286 // Process the flag field
287 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
288 {"unpacked",pkgCache::State::UnPacked
},
289 {"half-configured",pkgCache::State::HalfConfigured
},
290 {"installed",pkgCache::State::Installed
},
291 {"half-installed",pkgCache::State::HalfInstalled
},
292 {"config-files",pkgCache::State::ConfigFiles
},
293 {"post-inst-failed",pkgCache::State::HalfConfigured
},
294 {"removal-failed",pkgCache::State::HalfInstalled
},
296 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
297 return _error
->Error("Malformed 3rd word in the Status line");
299 /* A Status line marks the package as indicating the current
300 version as well. Only if it is actually installed.. Otherwise
301 the interesting dpkg handling of the status file creates bogus
303 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
304 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
306 if (Ver
.end() == true)
307 _error
->Warning("Encountered status field in a non-version description");
309 Pkg
->CurrentVer
= Ver
.Index();
315 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
317 // Determine the operator
325 Op
= pkgCache::Dep::LessEq
;
332 Op
= pkgCache::Dep::Less
;
336 // < is the same as <= and << is really Cs < for some reason
337 Op
= pkgCache::Dep::LessEq
;
345 Op
= pkgCache::Dep::GreaterEq
;
352 Op
= pkgCache::Dep::Greater
;
356 // > is the same as >= and >> is really Cs > for some reason
357 Op
= pkgCache::Dep::GreaterEq
;
361 Op
= pkgCache::Dep::Equals
;
365 // HACK around bad package definitions
367 Op
= pkgCache::Dep::Equals
;
374 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
375 // ---------------------------------------------------------------------
376 /* This parses the dependency elements out of a standard string in place,
378 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
379 string
&Package
,string
&Ver
,
380 unsigned int &Op
, bool ParseArchFlags
)
382 // Strip off leading space
383 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
385 // Parse off the package name
386 const char *I
= Start
;
387 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
388 *I
!= ',' && *I
!= '|'; I
++);
391 if (I
!= Stop
&& *I
== ')')
397 // Stash the package name
398 Package
.assign(Start
,I
- Start
);
400 // Skip white space to the '('
401 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
404 if (I
!= Stop
&& *I
== '(')
407 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
410 I
= ConvertRelation(I
,Op
);
413 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
415 for (;I
!= Stop
&& *I
!= ')'; I
++);
416 if (I
== Stop
|| Start
== I
)
419 // Skip trailing whitespace
421 for (; End
> Start
&& isspace(End
[-1]); End
--);
423 Ver
.assign(Start
,End
-Start
);
429 Op
= pkgCache::Dep::NoOp
;
433 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
435 if (ParseArchFlags
== true)
437 string arch
= _config
->Find("APT::Architecture");
439 // Parse an architecture
440 if (I
!= Stop
&& *I
== '[')
449 bool NegArch
= false;
452 // look for whitespace or ending ']'
453 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
465 if (stringcmp(arch
,I
,End
) == 0)
474 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
481 Package
= ""; /* not for this arch */
485 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
488 if (I
!= Stop
&& *I
== '|')
489 Op
|= pkgCache::Dep::Or
;
491 if (I
== Stop
|| *I
== ',' || *I
== '|')
494 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
501 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
502 // ---------------------------------------------------------------------
503 /* This is the higher level depends parser. It takes a tag and generates
504 a complete depends tree for the given version. */
505 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
506 const char *Tag
,unsigned int Type
)
510 if (Section
.Find(Tag
,Start
,Stop
) == false)
519 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
521 return _error
->Error("Problem parsing dependency %s",Tag
);
523 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
531 // ListParser::ParseProvides - Parse the provides list /*{{{*/
532 // ---------------------------------------------------------------------
534 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
538 if (Section
.Find("Provides",Start
,Stop
) == false)
547 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
549 return _error
->Error("Problem parsing Provides line");
550 if (Op
!= pkgCache::Dep::NoOp
) {
551 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
553 if (NewProvides(Ver
,Package
,Version
) == false)
564 // ListParser::GrabWord - Matches a word and returns /*{{{*/
565 // ---------------------------------------------------------------------
566 /* Looks for a word in a list of words - for ParseStatus */
567 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
569 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
571 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
580 // ListParser::Step - Move to the next section in the file /*{{{*/
581 // ---------------------------------------------------------------------
582 /* This has to be carefull to only process the correct architecture */
583 bool debListParser::Step()
585 iOffset
= Tags
.Offset();
586 while (Tags
.Step(Section
) == true)
588 /* See if this is the correct Architecture, if it isn't then we
589 drop the whole section. A missing arch tag only happens (in theory)
590 inside the Status file, so that is a positive return */
593 if (Section
.Find("Architecture",Start
,Stop
) == false)
596 if (stringcmp(Arch
,Start
,Stop
) == 0)
599 if (stringcmp(Start
,Stop
,"all") == 0)
602 iOffset
= Tags
.Offset();
607 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
608 // ---------------------------------------------------------------------
610 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
611 FileFd
&File
, string component
)
613 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
614 pkgTagSection Section
;
615 if (Tags
.Step(Section
) == false)
618 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
619 //FileI->Architecture = WriteUniqString(Arch);
621 // apt-secure does no longer download individual (per-section) Release
622 // file. to provide Component pinning we use the section name now
623 FileI
->Component
= WriteUniqString(component
);
627 if (Section
.Find("Suite",Start
,Stop
) == true)
628 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
629 if (Section
.Find("Component",Start
,Stop
) == true)
630 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
631 if (Section
.Find("Version",Start
,Stop
) == true)
632 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
633 if (Section
.Find("Origin",Start
,Stop
) == true)
634 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
635 if (Section
.Find("Label",Start
,Stop
) == true)
636 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
637 if (Section
.Find("Architecture",Start
,Stop
) == true)
638 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
640 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
641 pkgCache::Flag::NotAutomatic
) == false)
642 _error
->Warning("Bad NotAutomatic flag");
644 return !_error
->PendingError();
647 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
648 // ---------------------------------------------------------------------
650 unsigned char debListParser::GetPrio(string Str
)
653 if (GrabWord(Str
,PrioList
,Out
) == false)
654 Out
= pkgCache::State::Extra
;