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