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