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