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(string(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 if (DescriptionLanguage().empty())
148 return Section.FindS("Description");
150 return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
153 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
154 // ---------------------------------------------------------------------
155 /* This is to return the string describing the language of
156 description. If this returns the blank string then the entry is
157 assumed to describe original description. */
158 string debListParser::DescriptionLanguage()
160 return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
163 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
164 // ---------------------------------------------------------------------
165 /* This is to return the md5 string to allow the check if it is the right
166 description. If no Description-md5 is found in the section it will be
169 MD5SumValue debListParser::Description_md5()
171 string value = Section.FindS("Description-md5");
176 md5.Add((Description() + "\n").c_str());
179 return MD5SumValue(value);
182 // ListParser::UsePackage - Update a package structure /*{{{*/
183 // ---------------------------------------------------------------------
184 /* This is called to update the package with any new information
185 that might be found in the section */
186 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
187 pkgCache::VerIterator Ver)
189 if (Pkg->Display == 0)
190 Pkg->Display = FindTagWrite("Name");
191 if (Pkg->Display == 0)
192 Pkg->Display = FindTagWrite("Maemo-Display-Name");
193 if (Pkg->Section == 0)
194 Pkg->Section = UniqFindTagWrite("Section");
195 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
197 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
200 if (strcmp(Pkg.Name(),"apt") == 0)
201 Pkg->Flags |= pkgCache::Flag::Important;
203 if (ParseStatus(Pkg,Ver) == false)
206 if (Pkg->TagList == 0)
207 if (ParseTag(Pkg) == false)
213 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
214 // ---------------------------------------------------------------------
216 unsigned short debListParser::VersionHash()
218 const char *Sections[] ={"Installed-Size",
226 unsigned long Result = INIT_FCS;
228 for (const char **I = Sections; *I != 0; I++)
232 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
235 /* Strip out any spaces from the text, this undoes dpkgs reformatting
236 of certain fields. dpkg also has the rather interesting notion of
237 reformatting depends operators < -> <= */
239 for (; Start != End; Start++)
241 if (isspace(*Start) == 0)
242 *I++ = tolower_ascii(*Start);
243 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
245 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
249 Result = AddCRC16(Result,S,I - S);
255 // ListParser::ParseStatus - Parse the status field /*{{{*/
256 // ---------------------------------------------------------------------
257 /* Status lines are of the form,
258 Status: want flag status
259 want = unknown, install, hold, deinstall, purge
260 flag = ok, reinstreq, hold, hold-reinstreq
261 status = not-installed, unpacked, half-configured,
262 half-installed, config-files, post-inst-failed,
263 removal-failed, installed
265 Some of the above are obsolete (I think?) flag = hold-* and
266 status = post-inst-failed, removal-failed at least.
268 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
269 pkgCache::VerIterator Ver)
273 if (Section.Find("Status",Start,Stop) == false)
276 // Isolate the first word
277 const char *I = Start;
278 for(; I < Stop && *I != ' '; I++);
279 if (I >= Stop || *I != ' ')
280 return _error->Error("Malformed Status line");
282 // Process the want field
283 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
284 {"install",pkgCache::State::Install},
285 {"hold",pkgCache::State::Hold},
286 {"deinstall",pkgCache::State::DeInstall},
287 {"purge",pkgCache::State::Purge},
289 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
290 return _error->Error("Malformed 1st word in the Status line");
292 // Isloate the next word
295 for(; I < Stop && *I != ' '; I++);
296 if (I >= Stop || *I != ' ')
297 return _error->Error("Malformed status line, no 2nd word");
299 // Process the flag field
300 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
301 {"reinstreq",pkgCache::State::ReInstReq},
302 {"hold",pkgCache::State::HoldInst},
303 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
305 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
306 return _error->Error("Malformed 2nd word in the Status line");
308 // Isloate the last word
311 for(; I < Stop && *I != ' '; I++);
313 return _error->Error("Malformed Status line, no 3rd word");
315 // Process the flag field
316 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
317 {"unpacked",pkgCache::State::UnPacked},
318 {"half-configured",pkgCache::State::HalfConfigured},
319 {"installed",pkgCache::State::Installed},
320 {"half-installed",pkgCache::State::HalfInstalled},
321 {"config-files",pkgCache::State::ConfigFiles},
322 {"triggers-awaited",pkgCache::State::TriggersAwaited},
323 {"triggers-pending",pkgCache::State::TriggersPending},
324 {"post-inst-failed",pkgCache::State::HalfConfigured},
325 {"removal-failed",pkgCache::State::HalfInstalled},
327 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
328 return _error->Error("Malformed 3rd word in the Status line");
330 /* A Status line marks the package as indicating the current
331 version as well. Only if it is actually installed.. Otherwise
332 the interesting dpkg handling of the status file creates bogus
334 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
335 Pkg->CurrentState == pkgCache::State::ConfigFiles))
337 if (Ver.end() == true)
338 _error->Warning("Encountered status field in a non-version description");
340 Pkg->CurrentVer = Ver.Index();
346 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
348 // Determine the operator
356 Op = pkgCache::Dep::LessEq;
363 Op = pkgCache::Dep::Less;
367 // < is the same as <= and << is really Cs < for some reason
368 Op = pkgCache::Dep::LessEq;
376 Op = pkgCache::Dep::GreaterEq;
383 Op = pkgCache::Dep::Greater;
387 // > is the same as >= and >> is really Cs > for some reason
388 Op = pkgCache::Dep::GreaterEq;
392 Op = pkgCache::Dep::Equals;
396 // HACK around bad package definitions
398 Op = pkgCache::Dep::Equals;
405 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
406 // ---------------------------------------------------------------------
407 /* This parses the dependency elements out of a standard string in place,
409 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
410 string &Package,string &Ver,
411 unsigned int &Op, bool ParseArchFlags)
413 // Strip off leading space
414 for (;Start != Stop && isspace(*Start) != 0; Start++);
416 // Parse off the package name
417 const char *I = Start;
418 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
419 *I != ',' && *I != '|'; I++);
422 if (I != Stop && *I == ')')
428 // Stash the package name
429 Package.assign(Start,I - Start);
431 // Skip white space to the '('
432 for (;I != Stop && isspace(*I) != 0 ; I++);
435 if (I != Stop && *I == '(')
438 for (I++; I != Stop && isspace(*I) != 0 ; I++);
441 I = ConvertRelation(I,Op);
444 for (;I != Stop && isspace(*I) != 0; I++);
446 for (;I != Stop && *I != ')'; I++);
447 if (I == Stop || Start == I)
450 // Skip trailing whitespace
452 for (; End > Start && isspace(End[-1]); End--);
454 Ver.assign(Start,End-Start);
460 Op = pkgCache::Dep::NoOp;
464 for (;I != Stop && isspace(*I) != 0; I++);
466 if (ParseArchFlags == true)
468 string arch = _config->Find("APT::Architecture");
470 // Parse an architecture
471 if (I != Stop && *I == '[')
480 bool NegArch = false;
483 // look for whitespace or ending ']'
484 while (End != Stop && !isspace(*End) && *End != ']')
496 if (stringcmp(arch,I,End) == 0)
505 for (;I != Stop && isspace(*I) != 0; I++);
512 Package = ""; /* not for this arch */
516 for (;I != Stop && isspace(*I) != 0; I++);
519 if (I != Stop && *I == '|')
520 Op |= pkgCache::Dep::Or;
522 if (I == Stop || *I == ',' || *I == '|')
525 for (I++; I != Stop && isspace(*I) != 0; I++);
532 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
533 // ---------------------------------------------------------------------
534 /* This is the higher level depends parser. It takes a tag and generates
535 a complete depends tree for the given version. */
536 bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
537 const char *Tag,unsigned int Type)
541 if (Section.Find(Tag,Start,Stop) == false)
550 Start = ParseDepends(Start,Stop,Package,Version,Op);
552 return _error->Error("Problem parsing dependency %s",Tag);
554 if (NewDepends(Ver,Package,Version,Op,Type) == false)
562 // ListParser::ParseProvides - Parse the provides list /*{{{*/
563 // ---------------------------------------------------------------------
565 bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
569 if (Section.Find("Provides",Start,Stop) == false)
578 Start = ParseDepends(Start,Stop,Package,Version,Op);
580 return _error->Error("Problem parsing Provides line");
581 if (Op != pkgCache::Dep::NoOp) {
582 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
584 if (NewProvides(Ver,Package,Version) == false)
595 // ListParser::ParseTag - Parse the tag list /*{{{*/
596 // ---------------------------------------------------------------------
598 bool debListParser::ParseTag(pkgCache::PkgIterator Pkg)
602 if (Section.Find("Tag",Start,Stop) == false)
609 if (Stop[-1] != ' ' && Stop[-1] != '\t')
614 const char *Begin = Stop - 1;
615 while (Begin != Start && Begin[-1] != ' ' && Begin[-1] != ',')
618 if (NewTag(Pkg, Begin, Stop - Begin) == false)
624 if (Begin[-1] == ',')
635 // ListParser::GrabWord - Matches a word and returns /*{{{*/
636 // ---------------------------------------------------------------------
637 /* Looks for a word in a list of words - for ParseStatus */
638 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
640 for (unsigned int C = 0; List[C].Str != 0; C++)
642 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
651 // ListParser::Step - Move to the next section in the file /*{{{*/
652 // ---------------------------------------------------------------------
653 /* This has to be carefull to only process the correct architecture */
654 bool debListParser::Step()
656 iOffset = Tags.Offset();
657 while (Tags.Step(Section) == true)
659 /* See if this is the correct Architecture, if it isn't then we
660 drop the whole section. A missing arch tag only happens (in theory)
661 inside the Status file, so that is a positive return */
664 if (Section.Find("Architecture",Start,Stop) == false)
667 if (stringcmp(Arch,Start,Stop) == 0)
670 if (stringcmp(Start,Stop,"all") == 0)
673 iOffset = Tags.Offset();
678 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
679 // ---------------------------------------------------------------------
681 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
682 FileFd &File, string component)
684 pkgTagFile Tags(&File, File.Size() + 256); // XXX
685 pkgTagSection Section;
686 if (Tags.Step(Section) == false)
689 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
690 //FileI->Architecture = WriteUniqString(Arch);
692 // apt-secure does no longer download individual (per-section) Release
693 // file. to provide Component pinning we use the section name now
694 FileI->Component = WriteUniqString(component);
698 if (Section.Find("Suite",Start,Stop) == true)
699 FileI->Archive = WriteUniqString(Start,Stop - Start);
700 if (Section.Find("Component",Start,Stop) == true)
701 FileI->Component = WriteUniqString(Start,Stop - Start);
702 if (Section.Find("Version",Start,Stop) == true)
703 FileI->Version = WriteUniqString(Start,Stop - Start);
704 if (Section.Find("Origin",Start,Stop) == true)
705 FileI->Origin = WriteUniqString(Start,Stop - Start);
706 if (Section.Find("Label",Start,Stop) == true)
707 FileI->Label = WriteUniqString(Start,Stop - Start);
708 if (Section.Find("Architecture",Start,Stop) == true)
709 FileI->Architecture = WriteUniqString(Start,Stop - Start);
711 if (Section.FindFlag("NotAutomatic",FileI->Flags,
712 pkgCache::Flag::NotAutomatic) == false)
713 _error->Warning("Bad NotAutomatic flag");
715 return !_error->PendingError();
718 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
719 // ---------------------------------------------------------------------
721 unsigned char debListParser::GetPrio(string Str)
724 if (GrabWord(Str,PrioList,Out) == false)
725 Out = pkgCache::State::Extra;