]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/deb/deblistparser.cc
merge patch from Daniel Hartwig to Show a error message if {,dist-}upgrade is used...
[apt.git] / apt-pkg / deb / deblistparser.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz Exp $
4/* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
13#include <config.h>
14
15#include <apt-pkg/deblistparser.h>
16#include <apt-pkg/error.h>
17#include <apt-pkg/configuration.h>
18#include <apt-pkg/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
29using std::string;
30
31static 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() */
44debListParser::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/* */
55unsigned 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 */
67string 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 */
77string debListParser::Architecture() {
78 return Section.FindS("Architecture");
79}
80 /*}}}*/
81// ListParser::ArchitectureAll /*{{{*/
82// ---------------------------------------------------------------------
83/* */
84bool 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 */
93string debListParser::Version()
94{
95 return Section.FindS("Version");
96}
97 /*}}}*/
98// ListParser::NewVersion - Fill in the version structure /*{{{*/
99// ---------------------------------------------------------------------
100/* */
101bool 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 */
183string 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. */
197string 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 */
217MD5SumValue 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 */
241bool 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/* */
275unsigned 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 */
327bool 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
411const 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. */
473const 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. */
618bool 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/* */
685bool 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 /*{{{*/
730bool 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 */
744bool 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 */
760bool 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/* */
796bool 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: should use FileFd and TagSection
805 FILE* release = fdopen(dup(File.Fd()), "r");
806 if (release == NULL)
807 return false;
808
809 char buffer[101];
810 while (fgets(buffer, sizeof(buffer), release) != NULL)
811 {
812 size_t len = 0;
813
814 // Skip empty lines
815 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
816 /* nothing */
817 ;
818 if (buffer[len] == '\0')
819 continue;
820
821 // seperate the tag from the data
822 const char* dataStart = strchr(buffer + len, ':');
823 if (dataStart == NULL)
824 continue;
825 len = dataStart - buffer;
826 for (++dataStart; *dataStart == ' '; ++dataStart)
827 /* nothing */
828 ;
829 const char* dataEnd = (const char*)rawmemchr(dataStart, '\0');
830 // The last char should be a newline, but we can never be sure: #633350
831 const char* lineEnd = dataEnd;
832 for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
833 /* nothing */
834 ;
835 ++lineEnd;
836
837 // which datastorage need to be updated
838 enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None;
839 if (buffer[0] == ' ')
840 ;
841 #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X;
842 APT_PARSER_WRITETO(Suite)
843 APT_PARSER_WRITETO(Component)
844 APT_PARSER_WRITETO(Version)
845 APT_PARSER_WRITETO(Origin)
846 APT_PARSER_WRITETO(Codename)
847 APT_PARSER_WRITETO(Label)
848 #undef APT_PARSER_WRITETO
849 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
850 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
851 APT_PARSER_FLAGIT(NotAutomatic)
852 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
853 #undef APT_PARSER_FLAGIT
854
855 // load all data from the line and save it
856 string data;
857 if (writeTo != None)
858 data.append(dataStart, dataEnd);
859 if (sizeof(buffer) - 1 == (dataEnd - buffer))
860 {
861 while (fgets(buffer, sizeof(buffer), release) != NULL)
862 {
863 if (writeTo != None)
864 data.append(buffer);
865 if (strlen(buffer) != sizeof(buffer) - 1)
866 break;
867 }
868 }
869 if (writeTo != None)
870 {
871 // remove spaces and stuff from the end of the data line
872 for (std::string::reverse_iterator s = data.rbegin();
873 s != data.rend(); ++s)
874 {
875 if (*s != '\r' && *s != '\n' && *s != ' ')
876 break;
877 *s = '\0';
878 }
879 map_ptrloc const storage = WriteUniqString(data);
880 switch (writeTo) {
881 case Suite: FileI->Archive = storage; break;
882 case Component: FileI->Component = storage; break;
883 case Version: FileI->Version = storage; break;
884 case Origin: FileI->Origin = storage; break;
885 case Codename: FileI->Codename = storage; break;
886 case Label: FileI->Label = storage; break;
887 case None: break;
888 }
889 }
890 }
891 fclose(release);
892
893 return !_error->PendingError();
894}
895 /*}}}*/
896// ListParser::GetPrio - Convert the priority from a string /*{{{*/
897// ---------------------------------------------------------------------
898/* */
899unsigned char debListParser::GetPrio(string Str)
900{
901 unsigned char Out;
902 if (GrabWord(Str,PrioList,Out) == false)
903 Out = pkgCache::State::Extra;
904
905 return Out;
906}
907 /*}}}*/