enable APT in unpack/configure ordering to handle loops as well
[ntk/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 <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/crc-16.h>
21 #include <apt-pkg/md5.h>
22 #include <apt-pkg/macros.h>
23
24 #include <fnmatch.h>
25 #include <ctype.h>
26 /*}}}*/
27
28 static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Important},
29 {"required",pkgCache::State::Required},
30 {"standard",pkgCache::State::Standard},
31 {"optional",pkgCache::State::Optional},
32 {"extra",pkgCache::State::Extra},
33 {}};
34
35 // ListParser::debListParser - Constructor /*{{{*/
36 // ---------------------------------------------------------------------
37 /* Provide an architecture and only this one and "all" will be accepted
38 in Step(), if no Architecture is given we will accept every arch
39 we would accept in general with checkArchitecture() */
40 debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
41 Arch(Arch) {
42 if (Arch == "native")
43 this->Arch = _config->Find("APT::Architecture");
44 Architectures = APT::Configuration::getArchitectures();
45 MultiArchEnabled = Architectures.size() > 1;
46 }
47 /*}}}*/
48 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
49 // ---------------------------------------------------------------------
50 /* */
51 unsigned long debListParser::UniqFindTagWrite(const char *Tag)
52 {
53 const char *Start;
54 const char *Stop;
55 if (Section.Find(Tag,Start,Stop) == false)
56 return 0;
57 return WriteUniqString(Start,Stop - Start);
58 }
59 /*}}}*/
60 // ListParser::Package - Return the package name /*{{{*/
61 // ---------------------------------------------------------------------
62 /* This is to return the name of the package this section describes */
63 string debListParser::Package() {
64 string const Result = Section.FindS("Package");
65 if(unlikely(Result.empty() == true))
66 _error->Error("Encountered a section with no Package: header");
67 return Result;
68 }
69 /*}}}*/
70 // ListParser::Architecture - Return the package arch /*{{{*/
71 // ---------------------------------------------------------------------
72 /* This will return the Architecture of the package this section describes */
73 string debListParser::Architecture() {
74 std::string const Arch = Section.FindS("Architecture");
75 if (Arch.empty() == true)
76 return _config->Find("APT::Architecture");
77 return Arch;
78 }
79 /*}}}*/
80 // ListParser::ArchitectureAll /*{{{*/
81 // ---------------------------------------------------------------------
82 /* */
83 bool 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 */
92 string debListParser::Version()
93 {
94 return Section.FindS("Version");
95 }
96 /*}}}*/
97 // ListParser::NewVersion - Fill in the version structure /*{{{*/
98 // ---------------------------------------------------------------------
99 /* */
100 bool 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 */
182 string 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. */
196 string 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 */
216 MD5SumValue 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 */
233 bool 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 /* */
262 unsigned 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 */
314 bool 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
398 const 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 */
461 static 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. */
476 const 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 for (;I != Stop && *I != ')'; I++);
526 if (I == Stop || 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. */
620 bool 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 /* */
660 bool 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 {
679 if (NewProvides(Ver, Package, Arch, Version) == false)
680 return false;
681 }
682
683 if (Start == Stop)
684 break;
685 }
686 }
687
688 if (MultiArchEnabled == false)
689 return true;
690 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
691 {
692 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
693 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
694 }
695 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
696 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
697
698 return true;
699 }
700 /*}}}*/
701 // ListParser::NewProvides - add provides for all architectures /*{{{*/
702 bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
703 string const &Version) {
704 for (std::vector<string>::const_iterator a = Architectures.begin();
705 a != Architectures.end(); ++a)
706 {
707 if (NewProvides(Ver, Package, *a, Version) == false)
708 return false;
709 }
710 return true;
711 }
712 /*}}}*/
713 // ListParser::GrabWord - Matches a word and returns /*{{{*/
714 // ---------------------------------------------------------------------
715 /* Looks for a word in a list of words - for ParseStatus */
716 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
717 {
718 for (unsigned int C = 0; List[C].Str != 0; C++)
719 {
720 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
721 {
722 Out = List[C].Val;
723 return true;
724 }
725 }
726 return false;
727 }
728 /*}}}*/
729 // ListParser::Step - Move to the next section in the file /*{{{*/
730 // ---------------------------------------------------------------------
731 /* This has to be carefull to only process the correct architecture */
732 bool debListParser::Step()
733 {
734 iOffset = Tags.Offset();
735 while (Tags.Step(Section) == true)
736 {
737 /* See if this is the correct Architecture, if it isn't then we
738 drop the whole section. A missing arch tag only happens (in theory)
739 inside the Status file, so that is a positive return */
740 string const Architecture = Section.FindS("Architecture");
741 if (Architecture.empty() == true)
742 return true;
743
744 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
745 {
746 if (APT::Configuration::checkArchitecture(Architecture) == true)
747 return true;
748 }
749 else
750 {
751 if (Architecture == Arch)
752 return true;
753
754 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
755 return true;
756 }
757
758 iOffset = Tags.Offset();
759 }
760 return false;
761 }
762 /*}}}*/
763 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
764 // ---------------------------------------------------------------------
765 /* */
766 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
767 FileFd &File, string component)
768 {
769 // apt-secure does no longer download individual (per-section) Release
770 // file. to provide Component pinning we use the section name now
771 FileI->Component = WriteUniqString(component);
772
773 FILE* release = fdopen(dup(File.Fd()), "r");
774 if (release == NULL)
775 return false;
776
777 char buffer[101];
778 bool gpgClose = false;
779 while (fgets(buffer, sizeof(buffer), release) != NULL)
780 {
781 size_t len = 0;
782
783 // Skip empty lines
784 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
785 /* nothing */
786 ;
787 if (buffer[len] == '\0')
788 continue;
789
790 // only evalute the first GPG section
791 if (strncmp("-----", buffer, 5) == 0)
792 {
793 if (gpgClose == true)
794 break;
795 gpgClose = true;
796 continue;
797 }
798
799 // seperate the tag from the data
800 for (; buffer[len] != ':' && buffer[len] != '\0'; ++len)
801 /* nothing */
802 ;
803 if (buffer[len] == '\0')
804 continue;
805 char* dataStart = buffer + len;
806 for (++dataStart; *dataStart == ' '; ++dataStart)
807 /* nothing */
808 ;
809 char* dataEnd = dataStart;
810 for (++dataEnd; *dataEnd != '\0'; ++dataEnd)
811 /* nothing */
812 ;
813 // The last char should be a newline, but we can never be sure: #633350
814 char* lineEnd = dataEnd;
815 for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
816 /* nothing */
817 ;
818 ++lineEnd;
819
820 // which datastorage need to be updated
821 map_ptrloc* writeTo = NULL;
822 if (buffer[0] == ' ')
823 ;
824 #define APT_PARSER_WRITETO(X, Y) else if (strncmp(Y, buffer, len) == 0) writeTo = &X;
825 APT_PARSER_WRITETO(FileI->Archive, "Suite")
826 APT_PARSER_WRITETO(FileI->Component, "Component")
827 APT_PARSER_WRITETO(FileI->Version, "Version")
828 APT_PARSER_WRITETO(FileI->Origin, "Origin")
829 APT_PARSER_WRITETO(FileI->Codename, "Codename")
830 APT_PARSER_WRITETO(FileI->Label, "Label")
831 #undef APT_PARSER_WRITETO
832 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
833 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
834 APT_PARSER_FLAGIT(NotAutomatic)
835 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
836 #undef APT_PARSER_FLAGIT
837
838 // load all data from the line and save it
839 string data;
840 if (writeTo != NULL)
841 data.append(dataStart, dataEnd);
842 if (sizeof(buffer) - 1 == (dataEnd - buffer))
843 {
844 while (fgets(buffer, sizeof(buffer), release) != NULL)
845 {
846 if (writeTo != NULL)
847 data.append(buffer);
848 if (strlen(buffer) != sizeof(buffer) - 1)
849 break;
850 }
851 }
852 if (writeTo != NULL)
853 {
854 // remove spaces and stuff from the end of the data line
855 for (std::string::reverse_iterator s = data.rbegin();
856 s != data.rend(); ++s)
857 {
858 if (*s != '\r' && *s != '\n' && *s != ' ')
859 break;
860 *s = '\0';
861 }
862 *writeTo = WriteUniqString(data);
863 }
864 }
865 fclose(release);
866
867 return !_error->PendingError();
868 }
869 /*}}}*/
870 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
871 // ---------------------------------------------------------------------
872 /* */
873 unsigned char debListParser::GetPrio(string Str)
874 {
875 unsigned char Out;
876 if (GrabWord(Str,PrioList,Out) == false)
877 Out = pkgCache::State::Extra;
878
879 return Out;
880 }
881 /*}}}*/