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