]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/deb/deblistparser.cc
Allow the FileFd to use an external Compressor to uncompress a given file
[apt.git] / apt-pkg / deb / deblistparser.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz Exp $
4/* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
13#include <config.h>
14
15#include <apt-pkg/deblistparser.h>
16#include <apt-pkg/error.h>
17#include <apt-pkg/configuration.h>
18#include <apt-pkg/aptconfiguration.h>
19#include <apt-pkg/strutl.h>
20#include <apt-pkg/fileutl.h>
21#include <apt-pkg/crc-16.h>
22#include <apt-pkg/md5.h>
23#include <apt-pkg/macros.h>
24
25#include <fnmatch.h>
26#include <ctype.h>
27 /*}}}*/
28
29using std::string;
30
31static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Important},
32 {"required",pkgCache::State::Required},
33 {"standard",pkgCache::State::Standard},
34 {"optional",pkgCache::State::Optional},
35 {"extra",pkgCache::State::Extra},
36 {}};
37
38// ListParser::debListParser - Constructor /*{{{*/
39// ---------------------------------------------------------------------
40/* Provide an architecture and only this one and "all" will be accepted
41 in Step(), if no Architecture is given we will accept every arch
42 we would accept in general with checkArchitecture() */
43debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
44 Arch(Arch) {
45 if (Arch == "native")
46 this->Arch = _config->Find("APT::Architecture");
47 Architectures = APT::Configuration::getArchitectures();
48 MultiArchEnabled = Architectures.size() > 1;
49}
50 /*}}}*/
51// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
52// ---------------------------------------------------------------------
53/* */
54unsigned long debListParser::UniqFindTagWrite(const char *Tag)
55{
56 const char *Start;
57 const char *Stop;
58 if (Section.Find(Tag,Start,Stop) == false)
59 return 0;
60 return WriteUniqString(Start,Stop - Start);
61}
62 /*}}}*/
63// ListParser::Package - Return the package name /*{{{*/
64// ---------------------------------------------------------------------
65/* This is to return the name of the package this section describes */
66string debListParser::Package() {
67 string const Result = Section.FindS("Package");
68 if(unlikely(Result.empty() == true))
69 _error->Error("Encountered a section with no Package: header");
70 return Result;
71}
72 /*}}}*/
73// ListParser::Architecture - Return the package arch /*{{{*/
74// ---------------------------------------------------------------------
75/* This will return the Architecture of the package this section describes */
76string debListParser::Architecture() {
77 return Section.FindS("Architecture");
78}
79 /*}}}*/
80// ListParser::ArchitectureAll /*{{{*/
81// ---------------------------------------------------------------------
82/* */
83bool debListParser::ArchitectureAll() {
84 return Section.FindS("Architecture") == "all";
85}
86 /*}}}*/
87// ListParser::Version - Return the version string /*{{{*/
88// ---------------------------------------------------------------------
89/* This is to return the string describing the version in debian form,
90 epoch:upstream-release. If this returns the blank string then the
91 entry is assumed to only describe package properties */
92string debListParser::Version()
93{
94 return Section.FindS("Version");
95}
96 /*}}}*/
97// ListParser::NewVersion - Fill in the version structure /*{{{*/
98// ---------------------------------------------------------------------
99/* */
100bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
101{
102 // Parse the section
103 Ver->Section = UniqFindTagWrite("Section");
104
105 // Parse multi-arch
106 string const MultiArch = Section.FindS("Multi-Arch");
107 if (MultiArch.empty() == true)
108 Ver->MultiArch = pkgCache::Version::None;
109 else if (MultiArch == "same") {
110 // Parse multi-arch
111 if (ArchitectureAll() == true)
112 {
113 /* Arch all packages can't be Multi-Arch: same */
114 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
115 Section.FindS("Package").c_str());
116 Ver->MultiArch = pkgCache::Version::None;
117 }
118 else
119 Ver->MultiArch = pkgCache::Version::Same;
120 }
121 else if (MultiArch == "foreign")
122 Ver->MultiArch = pkgCache::Version::Foreign;
123 else if (MultiArch == "allowed")
124 Ver->MultiArch = pkgCache::Version::Allowed;
125 else
126 {
127 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
128 MultiArch.c_str(), Section.FindS("Package").c_str());
129 Ver->MultiArch = pkgCache::Version::None;
130 }
131
132 if (ArchitectureAll() == true)
133 Ver->MultiArch |= pkgCache::Version::All;
134
135 // Archive Size
136 Ver->Size = Section.FindULL("Size");
137 // Unpacked Size (in K)
138 Ver->InstalledSize = Section.FindULL("Installed-Size");
139 Ver->InstalledSize *= 1024;
140
141 // Priority
142 const char *Start;
143 const char *Stop;
144 if (Section.Find("Priority",Start,Stop) == true)
145 {
146 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
147 Ver->Priority = pkgCache::State::Extra;
148 }
149
150 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
151 return false;
152 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
153 return false;
154 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
155 return false;
156 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
157 return false;
158 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
159 return false;
160 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
161 return false;
162 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
163 return false;
164 if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
165 return false;
166
167 // Obsolete.
168 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
169 return false;
170
171 if (ParseProvides(Ver) == false)
172 return false;
173
174 return true;
175}
176 /*}}}*/
177// ListParser::Description - Return the description string /*{{{*/
178// ---------------------------------------------------------------------
179/* This is to return the string describing the package in debian
180 form. If this returns the blank string then the entry is assumed to
181 only describe package properties */
182string debListParser::Description()
183{
184 string const lang = DescriptionLanguage();
185 if (lang.empty())
186 return Section.FindS("Description");
187 else
188 return Section.FindS(string("Description-").append(lang).c_str());
189}
190 /*}}}*/
191// ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
192// ---------------------------------------------------------------------
193/* This is to return the string describing the language of
194 description. If this returns the blank string then the entry is
195 assumed to describe original description. */
196string debListParser::DescriptionLanguage()
197{
198 if (Section.FindS("Description").empty() == false)
199 return "";
200
201 std::vector<string> const lang = APT::Configuration::getLanguages(true);
202 for (std::vector<string>::const_iterator l = lang.begin();
203 l != lang.end(); ++l)
204 if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false)
205 return *l;
206
207 return "";
208}
209 /*}}}*/
210// ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
211// ---------------------------------------------------------------------
212/* This is to return the md5 string to allow the check if it is the right
213 description. If no Description-md5 is found in the section it will be
214 calculated.
215 */
216MD5SumValue debListParser::Description_md5()
217{
218 string value = Section.FindS("Description-md5");
219
220 if (value.empty())
221 {
222 MD5Summation md5;
223 md5.Add((Description() + "\n").c_str());
224 return md5.Result();
225 } else
226 return MD5SumValue(value);
227}
228 /*}}}*/
229// ListParser::UsePackage - Update a package structure /*{{{*/
230// ---------------------------------------------------------------------
231/* This is called to update the package with any new information
232 that might be found in the section */
233bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
234 pkgCache::VerIterator &Ver)
235{
236 if (Pkg->Section == 0)
237 Pkg->Section = UniqFindTagWrite("Section");
238
239 // Packages which are not from the "native" arch doesn't get the essential flag
240 // in the default "native" mode - it is also possible to mark "all" or "none".
241 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
242 string const static myArch = _config->Find("APT::Architecture");
243 string const static essential = _config->Find("pkgCacheGen::Essential", "native");
244 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
245 essential == "all")
246 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
247 return false;
248 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
249 return false;
250
251 if (strcmp(Pkg.Name(),"apt") == 0)
252 Pkg->Flags |= pkgCache::Flag::Important;
253
254 if (ParseStatus(Pkg,Ver) == false)
255 return false;
256 return true;
257}
258 /*}}}*/
259// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
260// ---------------------------------------------------------------------
261/* */
262unsigned short debListParser::VersionHash()
263{
264 const char *Sections[] ={"Installed-Size",
265 "Depends",
266 "Pre-Depends",
267// "Suggests",
268// "Recommends",
269 "Conflicts",
270 "Breaks",
271 "Replaces",0};
272 unsigned long Result = INIT_FCS;
273 char S[1024];
274 for (const char **I = Sections; *I != 0; I++)
275 {
276 const char *Start;
277 const char *End;
278 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
279 continue;
280
281 /* Strip out any spaces from the text, this undoes dpkgs reformatting
282 of certain fields. dpkg also has the rather interesting notion of
283 reformatting depends operators < -> <= */
284 char *J = S;
285 for (; Start != End; Start++)
286 {
287 if (isspace(*Start) == 0)
288 *J++ = tolower_ascii(*Start);
289 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
290 *J++ = '=';
291 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
292 *J++ = '=';
293 }
294
295 Result = AddCRC16(Result,S,J - S);
296 }
297
298 return Result;
299}
300 /*}}}*/
301// ListParser::ParseStatus - Parse the status field /*{{{*/
302// ---------------------------------------------------------------------
303/* Status lines are of the form,
304 Status: want flag status
305 want = unknown, install, hold, deinstall, purge
306 flag = ok, reinstreq, hold, hold-reinstreq
307 status = not-installed, unpacked, half-configured,
308 half-installed, config-files, post-inst-failed,
309 removal-failed, installed
310
311 Some of the above are obsolete (I think?) flag = hold-* and
312 status = post-inst-failed, removal-failed at least.
313 */
314bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
315 pkgCache::VerIterator &Ver)
316{
317 const char *Start;
318 const char *Stop;
319 if (Section.Find("Status",Start,Stop) == false)
320 return true;
321
322 // UsePackage() is responsible for setting the flag in the default case
323 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
324 if (essential == true &&
325 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
326 return false;
327
328 // Isolate the first word
329 const char *I = Start;
330 for(; I < Stop && *I != ' '; I++);
331 if (I >= Stop || *I != ' ')
332 return _error->Error("Malformed Status line");
333
334 // Process the want field
335 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
336 {"install",pkgCache::State::Install},
337 {"hold",pkgCache::State::Hold},
338 {"deinstall",pkgCache::State::DeInstall},
339 {"purge",pkgCache::State::Purge},
340 {}};
341 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
342 return _error->Error("Malformed 1st word in the Status line");
343
344 // Isloate the next word
345 I++;
346 Start = I;
347 for(; I < Stop && *I != ' '; I++);
348 if (I >= Stop || *I != ' ')
349 return _error->Error("Malformed status line, no 2nd word");
350
351 // Process the flag field
352 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
353 {"reinstreq",pkgCache::State::ReInstReq},
354 {"hold",pkgCache::State::HoldInst},
355 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
356 {}};
357 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
358 return _error->Error("Malformed 2nd word in the Status line");
359
360 // Isloate the last word
361 I++;
362 Start = I;
363 for(; I < Stop && *I != ' '; I++);
364 if (I != Stop)
365 return _error->Error("Malformed Status line, no 3rd word");
366
367 // Process the flag field
368 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
369 {"unpacked",pkgCache::State::UnPacked},
370 {"half-configured",pkgCache::State::HalfConfigured},
371 {"installed",pkgCache::State::Installed},
372 {"half-installed",pkgCache::State::HalfInstalled},
373 {"config-files",pkgCache::State::ConfigFiles},
374 {"triggers-awaited",pkgCache::State::TriggersAwaited},
375 {"triggers-pending",pkgCache::State::TriggersPending},
376 {"post-inst-failed",pkgCache::State::HalfConfigured},
377 {"removal-failed",pkgCache::State::HalfInstalled},
378 {}};
379 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
380 return _error->Error("Malformed 3rd word in the Status line");
381
382 /* A Status line marks the package as indicating the current
383 version as well. Only if it is actually installed.. Otherwise
384 the interesting dpkg handling of the status file creates bogus
385 entries. */
386 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
387 Pkg->CurrentState == pkgCache::State::ConfigFiles))
388 {
389 if (Ver.end() == true)
390 _error->Warning("Encountered status field in a non-version description");
391 else
392 Pkg->CurrentVer = Ver.Index();
393 }
394
395 return true;
396}
397
398const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
399{
400 // Determine the operator
401 switch (*I)
402 {
403 case '<':
404 I++;
405 if (*I == '=')
406 {
407 I++;
408 Op = pkgCache::Dep::LessEq;
409 break;
410 }
411
412 if (*I == '<')
413 {
414 I++;
415 Op = pkgCache::Dep::Less;
416 break;
417 }
418
419 // < is the same as <= and << is really Cs < for some reason
420 Op = pkgCache::Dep::LessEq;
421 break;
422
423 case '>':
424 I++;
425 if (*I == '=')
426 {
427 I++;
428 Op = pkgCache::Dep::GreaterEq;
429 break;
430 }
431
432 if (*I == '>')
433 {
434 I++;
435 Op = pkgCache::Dep::Greater;
436 break;
437 }
438
439 // > is the same as >= and >> is really Cs > for some reason
440 Op = pkgCache::Dep::GreaterEq;
441 break;
442
443 case '=':
444 Op = pkgCache::Dep::Equals;
445 I++;
446 break;
447
448 // HACK around bad package definitions
449 default:
450 Op = pkgCache::Dep::Equals;
451 break;
452 }
453 return I;
454}
455
456/*
457 * CompleteArch:
458 *
459 * The complete architecture, consisting of <kernel>-<cpu>.
460 */
461static string CompleteArch(std::string const &arch) {
462 if (arch == "armel") return "linux-arm";
463 if (arch == "armhf") return "linux-arm";
464 if (arch == "lpia") return "linux-i386";
465 if (arch == "powerpcspe") return "linux-powerpc";
466 if (arch == "uclibc-linux-armel") return "linux-arm";
467 if (arch == "uclinux-armel") return "uclinux-arm";
468
469 return (arch.find("-") != string::npos) ? arch : "linux-" + arch;
470}
471 /*}}}*/
472// ListParser::ParseDepends - Parse a dependency element /*{{{*/
473// ---------------------------------------------------------------------
474/* This parses the dependency elements out of a standard string in place,
475 bit by bit. */
476const char *debListParser::ParseDepends(const char *Start,const char *Stop,
477 string &Package,string &Ver,
478 unsigned int &Op, bool const &ParseArchFlags,
479 bool const &StripMultiArch)
480{
481 // Strip off leading space
482 for (;Start != Stop && isspace(*Start) != 0; Start++);
483
484 // Parse off the package name
485 const char *I = Start;
486 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
487 *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
488
489 // Malformed, no '('
490 if (I != Stop && *I == ')')
491 return 0;
492
493 if (I == Start)
494 return 0;
495
496 // Stash the package name
497 Package.assign(Start,I - Start);
498
499 // We don't want to confuse library users which can't handle MultiArch
500 string const arch = _config->Find("APT::Architecture");
501 if (StripMultiArch == true) {
502 size_t const found = Package.rfind(':');
503 if (found != string::npos &&
504 (strcmp(Package.c_str() + found, ":any") == 0 ||
505 strcmp(Package.c_str() + found, ":native") == 0 ||
506 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
507 Package = Package.substr(0,found);
508 }
509
510 // Skip white space to the '('
511 for (;I != Stop && isspace(*I) != 0 ; I++);
512
513 // Parse a version
514 if (I != Stop && *I == '(')
515 {
516 // Skip the '('
517 for (I++; I != Stop && isspace(*I) != 0 ; I++);
518 if (I + 3 >= Stop)
519 return 0;
520 I = ConvertRelation(I,Op);
521
522 // Skip whitespace
523 for (;I != Stop && isspace(*I) != 0; I++);
524 Start = I;
525 I = (const char*) memchr(I, ')', Stop - I);
526 if (I == NULL || Start == I)
527 return 0;
528
529 // Skip trailing whitespace
530 const char *End = I;
531 for (; End > Start && isspace(End[-1]); End--);
532
533 Ver.assign(Start,End-Start);
534 I++;
535 }
536 else
537 {
538 Ver.clear();
539 Op = pkgCache::Dep::NoOp;
540 }
541
542 // Skip whitespace
543 for (;I != Stop && isspace(*I) != 0; I++);
544
545 if (ParseArchFlags == true)
546 {
547 string completeArch = CompleteArch(arch);
548
549 // Parse an architecture
550 if (I != Stop && *I == '[')
551 {
552 // malformed
553 I++;
554 if (I == Stop)
555 return 0;
556
557 const char *End = I;
558 bool Found = false;
559 bool NegArch = false;
560 while (I != Stop)
561 {
562 // look for whitespace or ending ']'
563 while (End != Stop && !isspace(*End) && *End != ']')
564 End++;
565
566 if (End == Stop)
567 return 0;
568
569 if (*I == '!')
570 {
571 NegArch = true;
572 I++;
573 }
574
575 if (stringcmp(arch,I,End) == 0) {
576 Found = true;
577 } else {
578 std::string wildcard = SubstVar(string(I, End), "any", "*");
579 if (fnmatch(wildcard.c_str(), completeArch.c_str(), 0) == 0)
580 Found = true;
581 }
582
583 if (*End++ == ']') {
584 I = End;
585 break;
586 }
587
588 I = End;
589 for (;I != Stop && isspace(*I) != 0; I++);
590 }
591
592 if (NegArch)
593 Found = !Found;
594
595 if (Found == false)
596 Package = ""; /* not for this arch */
597 }
598
599 // Skip whitespace
600 for (;I != Stop && isspace(*I) != 0; I++);
601 }
602
603 if (I != Stop && *I == '|')
604 Op |= pkgCache::Dep::Or;
605
606 if (I == Stop || *I == ',' || *I == '|')
607 {
608 if (I != Stop)
609 for (I++; I != Stop && isspace(*I) != 0; I++);
610 return I;
611 }
612
613 return 0;
614}
615 /*}}}*/
616// ListParser::ParseDepends - Parse a dependency list /*{{{*/
617// ---------------------------------------------------------------------
618/* This is the higher level depends parser. It takes a tag and generates
619 a complete depends tree for the given version. */
620bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
621 const char *Tag,unsigned int Type)
622{
623 const char *Start;
624 const char *Stop;
625 if (Section.Find(Tag,Start,Stop) == false)
626 return true;
627
628 string Package;
629 string const pkgArch = Ver.Arch();
630 string Version;
631 unsigned int Op;
632
633 while (1)
634 {
635 Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled);
636 if (Start == 0)
637 return _error->Error("Problem parsing dependency %s",Tag);
638
639 if (MultiArchEnabled == true &&
640 (Type == pkgCache::Dep::Conflicts ||
641 Type == pkgCache::Dep::DpkgBreaks ||
642 Type == pkgCache::Dep::Replaces))
643 {
644 for (std::vector<std::string>::const_iterator a = Architectures.begin();
645 a != Architectures.end(); ++a)
646 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
647 return false;
648 }
649 else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
650 return false;
651 if (Start == Stop)
652 break;
653 }
654 return true;
655}
656 /*}}}*/
657// ListParser::ParseProvides - Parse the provides list /*{{{*/
658// ---------------------------------------------------------------------
659/* */
660bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
661{
662 const char *Start;
663 const char *Stop;
664 if (Section.Find("Provides",Start,Stop) == true)
665 {
666 string Package;
667 string Version;
668 string const Arch = Ver.Arch();
669 unsigned int Op;
670
671 while (1)
672 {
673 Start = ParseDepends(Start,Stop,Package,Version,Op);
674 if (Start == 0)
675 return _error->Error("Problem parsing Provides line");
676 if (Op != pkgCache::Dep::NoOp) {
677 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
678 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
679 if (NewProvidesAllArch(Ver, Package, Version) == false)
680 return false;
681 } else {
682 if (NewProvides(Ver, Package, Arch, Version) == false)
683 return false;
684 }
685
686 if (Start == Stop)
687 break;
688 }
689 }
690
691 if (MultiArchEnabled == false)
692 return true;
693 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
694 {
695 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
696 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
697 }
698 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
699 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
700
701 return true;
702}
703 /*}}}*/
704// ListParser::NewProvides - add provides for all architectures /*{{{*/
705bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
706 string const &Version) {
707 for (std::vector<string>::const_iterator a = Architectures.begin();
708 a != Architectures.end(); ++a)
709 {
710 if (NewProvides(Ver, Package, *a, Version) == false)
711 return false;
712 }
713 return true;
714}
715 /*}}}*/
716// ListParser::GrabWord - Matches a word and returns /*{{{*/
717// ---------------------------------------------------------------------
718/* Looks for a word in a list of words - for ParseStatus */
719bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
720{
721 for (unsigned int C = 0; List[C].Str != 0; C++)
722 {
723 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
724 {
725 Out = List[C].Val;
726 return true;
727 }
728 }
729 return false;
730}
731 /*}}}*/
732// ListParser::Step - Move to the next section in the file /*{{{*/
733// ---------------------------------------------------------------------
734/* This has to be carefull to only process the correct architecture */
735bool debListParser::Step()
736{
737 iOffset = Tags.Offset();
738 while (Tags.Step(Section) == true)
739 {
740 /* See if this is the correct Architecture, if it isn't then we
741 drop the whole section. A missing arch tag only happens (in theory)
742 inside the Status file, so that is a positive return */
743 string const Architecture = Section.FindS("Architecture");
744 if (Architecture.empty() == true)
745 return true;
746
747 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
748 {
749 if (APT::Configuration::checkArchitecture(Architecture) == true)
750 return true;
751 }
752 else
753 {
754 if (Architecture == Arch)
755 return true;
756
757 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
758 return true;
759 }
760
761 iOffset = Tags.Offset();
762 }
763 return false;
764}
765 /*}}}*/
766// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
767// ---------------------------------------------------------------------
768/* */
769bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
770 FileFd &File, string component)
771{
772 // apt-secure does no longer download individual (per-section) Release
773 // file. to provide Component pinning we use the section name now
774 FileI->Component = WriteUniqString(component);
775
776 // FIXME: Code depends on the fact that Release files aren't compressed
777 FILE* release = fdopen(dup(File.Fd()), "r");
778 if (release == NULL)
779 return false;
780
781 char buffer[101];
782 bool gpgClose = false;
783 while (fgets(buffer, sizeof(buffer), release) != NULL)
784 {
785 size_t len = 0;
786
787 // Skip empty lines
788 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
789 /* nothing */
790 ;
791 if (buffer[len] == '\0')
792 continue;
793
794 // only evalute the first GPG section
795 if (strncmp("-----", buffer, 5) == 0)
796 {
797 if (gpgClose == true)
798 break;
799 gpgClose = true;
800 continue;
801 }
802
803 // seperate the tag from the data
804 const char* dataStart = strchr(buffer + len, ':');
805 if (dataStart == NULL)
806 continue;
807 len = dataStart - buffer;
808 for (++dataStart; *dataStart == ' '; ++dataStart)
809 /* nothing */
810 ;
811 const char* dataEnd = (const char*)rawmemchr(dataStart, '\0');
812 // The last char should be a newline, but we can never be sure: #633350
813 const char* lineEnd = dataEnd;
814 for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
815 /* nothing */
816 ;
817 ++lineEnd;
818
819 // which datastorage need to be updated
820 enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None;
821 if (buffer[0] == ' ')
822 ;
823 #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X;
824 APT_PARSER_WRITETO(Suite)
825 APT_PARSER_WRITETO(Component)
826 APT_PARSER_WRITETO(Version)
827 APT_PARSER_WRITETO(Origin)
828 APT_PARSER_WRITETO(Codename)
829 APT_PARSER_WRITETO(Label)
830 #undef APT_PARSER_WRITETO
831 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
832 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
833 APT_PARSER_FLAGIT(NotAutomatic)
834 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
835 #undef APT_PARSER_FLAGIT
836
837 // load all data from the line and save it
838 string data;
839 if (writeTo != None)
840 data.append(dataStart, dataEnd);
841 if (sizeof(buffer) - 1 == (dataEnd - buffer))
842 {
843 while (fgets(buffer, sizeof(buffer), release) != NULL)
844 {
845 if (writeTo != None)
846 data.append(buffer);
847 if (strlen(buffer) != sizeof(buffer) - 1)
848 break;
849 }
850 }
851 if (writeTo != None)
852 {
853 // remove spaces and stuff from the end of the data line
854 for (std::string::reverse_iterator s = data.rbegin();
855 s != data.rend(); ++s)
856 {
857 if (*s != '\r' && *s != '\n' && *s != ' ')
858 break;
859 *s = '\0';
860 }
861 switch (writeTo) {
862 case Suite: FileI->Archive = WriteUniqString(data); break;
863 case Component: FileI->Component = WriteUniqString(data); break;
864 case Version: FileI->Version = WriteUniqString(data); break;
865 case Origin: FileI->Origin = WriteUniqString(data); break;
866 case Codename: FileI->Codename = WriteUniqString(data); break;
867 case Label: FileI->Label = WriteUniqString(data); break;
868 case None: break;
869 }
870 }
871 }
872 fclose(release);
873
874 return !_error->PendingError();
875}
876 /*}}}*/
877// ListParser::GetPrio - Convert the priority from a string /*{{{*/
878// ---------------------------------------------------------------------
879/* */
880unsigned char debListParser::GetPrio(string Str)
881{
882 unsigned char Out;
883 if (GrabWord(Str,PrioList,Out) == false)
884 Out = pkgCache::State::Extra;
885
886 return Out;
887}
888 /*}}}*/