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)
78 Ver->Display = UniqFindTagWrite("Name");
79 if (Ver->Display == 0)
80 Ver->Display = UniqFindTagWrite("Maemo-Display-Name");
83 Ver->Section = UniqFindTagWrite("Section");
84 Ver->Arch = UniqFindTagWrite("Architecture");
87 Ver->Size = (unsigned)Section.FindI("Size");
89 // Unpacked Size (in K)
90 Ver->InstalledSize = (unsigned)Section.FindI("Installed-Size");
91 Ver->InstalledSize *= 1024;
96 if (Section.Find("Priority",Start,Stop) == true)
98 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
99 Ver->Priority = pkgCache::State::Extra;
102 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
104 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
106 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
108 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
110 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
112 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
114 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
118 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
121 if (ParseProvides(Ver) == false)
127 // ListParser::Description - Return the description string /*{{{*/
128 // ---------------------------------------------------------------------
129 /* This is to return the string describing the package in debian
130 form. If this returns the blank string then the entry is assumed to
131 only describe package properties */
132 string debListParser::Description()
134 if (DescriptionLanguage().empty())
135 return Section.FindS("Description");
137 return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
140 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
141 // ---------------------------------------------------------------------
142 /* This is to return the string describing the language of
143 description. If this returns the blank string then the entry is
144 assumed to describe original description. */
145 string debListParser::DescriptionLanguage()
147 return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
150 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
151 // ---------------------------------------------------------------------
152 /* This is to return the md5 string to allow the check if it is the right
153 description. If no Description-md5 is found in the section it will be
156 MD5SumValue debListParser::Description_md5()
158 string value = Section.FindS("Description-md5");
163 md5.Add((Description() + "\n").c_str());
166 return MD5SumValue(value);
169 // ListParser::UsePackage - Update a package structure /*{{{*/
170 // ---------------------------------------------------------------------
171 /* This is called to update the package with any new information
172 that might be found in the section */
173 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
174 pkgCache::VerIterator Ver)
176 if (Pkg->Display == 0)
177 Pkg->Display = UniqFindTagWrite("Name");
178 if (Pkg->Display == 0)
179 Pkg->Display = UniqFindTagWrite("Maemo-Display-Name");
180 if (Pkg->Section == 0)
181 Pkg->Section = UniqFindTagWrite("Section");
182 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
184 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
187 if (strcmp(Pkg.Name(),"apt") == 0)
188 Pkg->Flags |= pkgCache::Flag::Important;
190 if (ParseStatus(Pkg,Ver) == false)
195 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
196 // ---------------------------------------------------------------------
198 unsigned short debListParser::VersionHash()
200 const char *Sections[] ={"Installed-Size",
208 unsigned long Result = INIT_FCS;
210 for (const char **I = Sections; *I != 0; I++)
214 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
217 /* Strip out any spaces from the text, this undoes dpkgs reformatting
218 of certain fields. dpkg also has the rather interesting notion of
219 reformatting depends operators < -> <= */
221 for (; Start != End; Start++)
223 if (isspace(*Start) == 0)
224 *I++ = tolower(*Start);
225 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
227 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
231 Result = AddCRC16(Result,S,I - S);
237 // ListParser::ParseStatus - Parse the status field /*{{{*/
238 // ---------------------------------------------------------------------
239 /* Status lines are of the form,
240 Status: want flag status
241 want = unknown, install, hold, deinstall, purge
242 flag = ok, reinstreq, hold, hold-reinstreq
243 status = not-installed, unpacked, half-configured,
244 half-installed, config-files, post-inst-failed,
245 removal-failed, installed
247 Some of the above are obsolete (I think?) flag = hold-* and
248 status = post-inst-failed, removal-failed at least.
250 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
251 pkgCache::VerIterator Ver)
255 if (Section.Find("Status",Start,Stop) == false)
258 // Isolate the first word
259 const char *I = Start;
260 for(; I < Stop && *I != ' '; I++);
261 if (I >= Stop || *I != ' ')
262 return _error->Error("Malformed Status line");
264 // Process the want field
265 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
266 {"install",pkgCache::State::Install},
267 {"hold",pkgCache::State::Hold},
268 {"deinstall",pkgCache::State::DeInstall},
269 {"purge",pkgCache::State::Purge},
271 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
272 return _error->Error("Malformed 1st word in the Status line");
274 // Isloate the next word
277 for(; I < Stop && *I != ' '; I++);
278 if (I >= Stop || *I != ' ')
279 return _error->Error("Malformed status line, no 2nd word");
281 // Process the flag field
282 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
283 {"reinstreq",pkgCache::State::ReInstReq},
284 {"hold",pkgCache::State::HoldInst},
285 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
287 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
288 return _error->Error("Malformed 2nd word in the Status line");
290 // Isloate the last word
293 for(; I < Stop && *I != ' '; I++);
295 return _error->Error("Malformed Status line, no 3rd word");
297 // Process the flag field
298 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
299 {"unpacked",pkgCache::State::UnPacked},
300 {"half-configured",pkgCache::State::HalfConfigured},
301 {"installed",pkgCache::State::Installed},
302 {"half-installed",pkgCache::State::HalfInstalled},
303 {"config-files",pkgCache::State::ConfigFiles},
304 {"triggers-awaited",pkgCache::State::TriggersAwaited},
305 {"triggers-pending",pkgCache::State::TriggersPending},
306 {"post-inst-failed",pkgCache::State::HalfConfigured},
307 {"removal-failed",pkgCache::State::HalfInstalled},
309 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
310 return _error->Error("Malformed 3rd word in the Status line");
312 /* A Status line marks the package as indicating the current
313 version as well. Only if it is actually installed.. Otherwise
314 the interesting dpkg handling of the status file creates bogus
316 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
317 Pkg->CurrentState == pkgCache::State::ConfigFiles))
319 if (Ver.end() == true)
320 _error->Warning("Encountered status field in a non-version description");
322 Pkg->CurrentVer = Ver.Index();
328 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
330 // Determine the operator
338 Op = pkgCache::Dep::LessEq;
345 Op = pkgCache::Dep::Less;
349 // < is the same as <= and << is really Cs < for some reason
350 Op = pkgCache::Dep::LessEq;
358 Op = pkgCache::Dep::GreaterEq;
365 Op = pkgCache::Dep::Greater;
369 // > is the same as >= and >> is really Cs > for some reason
370 Op = pkgCache::Dep::GreaterEq;
374 Op = pkgCache::Dep::Equals;
378 // HACK around bad package definitions
380 Op = pkgCache::Dep::Equals;
387 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
388 // ---------------------------------------------------------------------
389 /* This parses the dependency elements out of a standard string in place,
391 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
392 string &Package,string &Ver,
393 unsigned int &Op, bool ParseArchFlags)
395 // Strip off leading space
396 for (;Start != Stop && isspace(*Start) != 0; Start++);
398 // Parse off the package name
399 const char *I = Start;
400 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
401 *I != ',' && *I != '|'; I++);
404 if (I != Stop && *I == ')')
410 // Stash the package name
411 Package.assign(Start,I - Start);
413 // Skip white space to the '('
414 for (;I != Stop && isspace(*I) != 0 ; I++);
417 if (I != Stop && *I == '(')
420 for (I++; I != Stop && isspace(*I) != 0 ; I++);
423 I = ConvertRelation(I,Op);
426 for (;I != Stop && isspace(*I) != 0; I++);
428 for (;I != Stop && *I != ')'; I++);
429 if (I == Stop || Start == I)
432 // Skip trailing whitespace
434 for (; End > Start && isspace(End[-1]); End--);
436 Ver.assign(Start,End-Start);
442 Op = pkgCache::Dep::NoOp;
446 for (;I != Stop && isspace(*I) != 0; I++);
448 if (ParseArchFlags == true)
450 string arch = _config->Find("APT::Architecture");
452 // Parse an architecture
453 if (I != Stop && *I == '[')
462 bool NegArch = false;
465 // look for whitespace or ending ']'
466 while (End != Stop && !isspace(*End) && *End != ']')
478 if (stringcmp(arch,I,End) == 0)
487 for (;I != Stop && isspace(*I) != 0; I++);
494 Package = ""; /* not for this arch */
498 for (;I != Stop && isspace(*I) != 0; I++);
501 if (I != Stop && *I == '|')
502 Op |= pkgCache::Dep::Or;
504 if (I == Stop || *I == ',' || *I == '|')
507 for (I++; I != Stop && isspace(*I) != 0; I++);
514 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
515 // ---------------------------------------------------------------------
516 /* This is the higher level depends parser. It takes a tag and generates
517 a complete depends tree for the given version. */
518 bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
519 const char *Tag,unsigned int Type)
523 if (Section.Find(Tag,Start,Stop) == false)
532 Start = ParseDepends(Start,Stop,Package,Version,Op);
534 return _error->Error("Problem parsing dependency %s",Tag);
536 if (NewDepends(Ver,Package,Version,Op,Type) == false)
544 // ListParser::ParseProvides - Parse the provides list /*{{{*/
545 // ---------------------------------------------------------------------
547 bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
551 if (Section.Find("Provides",Start,Stop) == false)
560 Start = ParseDepends(Start,Stop,Package,Version,Op);
562 return _error->Error("Problem parsing Provides line");
563 if (Op != pkgCache::Dep::NoOp) {
564 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
566 if (NewProvides(Ver,Package,Version) == false)
577 // ListParser::GrabWord - Matches a word and returns /*{{{*/
578 // ---------------------------------------------------------------------
579 /* Looks for a word in a list of words - for ParseStatus */
580 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
582 for (unsigned int C = 0; List[C].Str != 0; C++)
584 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
593 // ListParser::Step - Move to the next section in the file /*{{{*/
594 // ---------------------------------------------------------------------
595 /* This has to be carefull to only process the correct architecture */
596 bool debListParser::Step()
598 iOffset = Tags.Offset();
599 while (Tags.Step(Section) == true)
601 /* See if this is the correct Architecture, if it isn't then we
602 drop the whole section. A missing arch tag only happens (in theory)
603 inside the Status file, so that is a positive return */
606 if (Section.Find("Architecture",Start,Stop) == false)
609 if (stringcmp(Arch,Start,Stop) == 0)
612 if (stringcmp(Start,Stop,"all") == 0)
615 iOffset = Tags.Offset();
620 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
621 // ---------------------------------------------------------------------
623 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
624 FileFd &File, string component)
626 pkgTagFile Tags(&File, File.Size() + 256); // XXX
627 pkgTagSection Section;
628 if (Tags.Step(Section) == false)
631 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
632 //FileI->Architecture = WriteUniqString(Arch);
634 // apt-secure does no longer download individual (per-section) Release
635 // file. to provide Component pinning we use the section name now
636 FileI->Component = WriteUniqString(component);
640 if (Section.Find("Suite",Start,Stop) == true)
641 FileI->Archive = WriteUniqString(Start,Stop - Start);
642 if (Section.Find("Component",Start,Stop) == true)
643 FileI->Component = WriteUniqString(Start,Stop - Start);
644 if (Section.Find("Version",Start,Stop) == true)
645 FileI->Version = WriteUniqString(Start,Stop - Start);
646 if (Section.Find("Origin",Start,Stop) == true)
647 FileI->Origin = WriteUniqString(Start,Stop - Start);
648 if (Section.Find("Label",Start,Stop) == true)
649 FileI->Label = WriteUniqString(Start,Stop - Start);
650 if (Section.Find("Architecture",Start,Stop) == true)
651 FileI->Architecture = WriteUniqString(Start,Stop - Start);
653 if (Section.FindFlag("NotAutomatic",FileI->Flags,
654 pkgCache::Flag::NotAutomatic) == false)
655 _error->Warning("Bad NotAutomatic flag");
657 return !_error->PendingError();
660 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
661 // ---------------------------------------------------------------------
663 unsigned char debListParser::GetPrio(string Str)
666 if (GrabWord(Str,PrioList,Out) == false)
667 Out = pkgCache::State::Extra;