]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
implement BuildProfileSpec support as dpkg has in 1.17.2
[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 std::string const desc = Description() + "\n";
223 if (desc == "\n")
224 return MD5SumValue();
225
226 MD5Summation md5;
227 md5.Add(desc.c_str());
228 return md5.Result();
229 }
230 else if (likely(value.size() == 32))
231 {
232 if (likely(value.find_first_not_of("0123456789abcdefABCDEF") == string::npos))
233 return MD5SumValue(value);
234 _error->Error("Malformed Description-md5 line; includes invalid character '%s'", value.c_str());
235 return MD5SumValue();
236 }
237 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%s'", (int)value.size(), value.c_str());
238 return MD5SumValue();
239 }
240 /*}}}*/
241 // ListParser::UsePackage - Update a package structure /*{{{*/
242 // ---------------------------------------------------------------------
243 /* This is called to update the package with any new information
244 that might be found in the section */
245 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
246 pkgCache::VerIterator &Ver)
247 {
248 if (Pkg->Section == 0)
249 Pkg->Section = UniqFindTagWrite("Section");
250
251 string const static myArch = _config->Find("APT::Architecture");
252 // Possible values are: "all", "native", "installed" and "none"
253 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
254 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
255 if (essential == "all" ||
256 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
257 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
258 return false;
259 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
260 return false;
261
262 if (strcmp(Pkg.Name(),"apt") == 0)
263 {
264 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
265 essential == "all")
266 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
267 else
268 Pkg->Flags |= pkgCache::Flag::Important;
269 }
270
271 if (ParseStatus(Pkg,Ver) == false)
272 return false;
273 return true;
274 }
275 /*}}}*/
276 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
277 // ---------------------------------------------------------------------
278 /* */
279 unsigned short debListParser::VersionHash()
280 {
281 const char *Sections[] ={"Installed-Size",
282 "Depends",
283 "Pre-Depends",
284 // "Suggests",
285 // "Recommends",
286 "Conflicts",
287 "Breaks",
288 "Replaces",0};
289 unsigned long Result = INIT_FCS;
290 char S[1024];
291 for (const char * const *I = Sections; *I != 0; ++I)
292 {
293 const char *Start;
294 const char *End;
295 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
296 continue;
297
298 /* Strip out any spaces from the text, this undoes dpkgs reformatting
299 of certain fields. dpkg also has the rather interesting notion of
300 reformatting depends operators < -> <= */
301 char *J = S;
302 for (; Start != End; ++Start)
303 {
304 if (isspace(*Start) != 0)
305 continue;
306 *J++ = tolower_ascii(*Start);
307
308 if ((*Start == '<' || *Start == '>') && Start[1] != *Start && Start[1] != '=')
309 *J++ = '=';
310 }
311
312 Result = AddCRC16(Result,S,J - S);
313 }
314
315 return Result;
316 }
317 /*}}}*/
318 // ListParser::ParseStatus - Parse the status field /*{{{*/
319 // ---------------------------------------------------------------------
320 /* Status lines are of the form,
321 Status: want flag status
322 want = unknown, install, hold, deinstall, purge
323 flag = ok, reinstreq, hold, hold-reinstreq
324 status = not-installed, unpacked, half-configured,
325 half-installed, config-files, post-inst-failed,
326 removal-failed, installed
327
328 Some of the above are obsolete (I think?) flag = hold-* and
329 status = post-inst-failed, removal-failed at least.
330 */
331 bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
332 pkgCache::VerIterator &Ver)
333 {
334 const char *Start;
335 const char *Stop;
336 if (Section.Find("Status",Start,Stop) == false)
337 return true;
338
339 // UsePackage() is responsible for setting the flag in the default case
340 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
341 if (essential == true &&
342 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
343 return false;
344
345 // Isolate the first word
346 const char *I = Start;
347 for(; I < Stop && *I != ' '; I++);
348 if (I >= Stop || *I != ' ')
349 return _error->Error("Malformed Status line");
350
351 // Process the want field
352 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
353 {"install",pkgCache::State::Install},
354 {"hold",pkgCache::State::Hold},
355 {"deinstall",pkgCache::State::DeInstall},
356 {"purge",pkgCache::State::Purge},
357 {}};
358 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
359 return _error->Error("Malformed 1st word in the Status line");
360
361 // Isloate the next word
362 I++;
363 Start = I;
364 for(; I < Stop && *I != ' '; I++);
365 if (I >= Stop || *I != ' ')
366 return _error->Error("Malformed status line, no 2nd word");
367
368 // Process the flag field
369 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
370 {"reinstreq",pkgCache::State::ReInstReq},
371 {"hold",pkgCache::State::HoldInst},
372 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
373 {}};
374 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
375 return _error->Error("Malformed 2nd word in the Status line");
376
377 // Isloate the last word
378 I++;
379 Start = I;
380 for(; I < Stop && *I != ' '; I++);
381 if (I != Stop)
382 return _error->Error("Malformed Status line, no 3rd word");
383
384 // Process the flag field
385 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
386 {"unpacked",pkgCache::State::UnPacked},
387 {"half-configured",pkgCache::State::HalfConfigured},
388 {"installed",pkgCache::State::Installed},
389 {"half-installed",pkgCache::State::HalfInstalled},
390 {"config-files",pkgCache::State::ConfigFiles},
391 {"triggers-awaited",pkgCache::State::TriggersAwaited},
392 {"triggers-pending",pkgCache::State::TriggersPending},
393 {"post-inst-failed",pkgCache::State::HalfConfigured},
394 {"removal-failed",pkgCache::State::HalfInstalled},
395 {}};
396 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
397 return _error->Error("Malformed 3rd word in the Status line");
398
399 /* A Status line marks the package as indicating the current
400 version as well. Only if it is actually installed.. Otherwise
401 the interesting dpkg handling of the status file creates bogus
402 entries. */
403 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
404 Pkg->CurrentState == pkgCache::State::ConfigFiles))
405 {
406 if (Ver.end() == true)
407 _error->Warning("Encountered status field in a non-version description");
408 else
409 Pkg->CurrentVer = Ver.Index();
410 }
411
412 return true;
413 }
414
415 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
416 {
417 // Determine the operator
418 switch (*I)
419 {
420 case '<':
421 I++;
422 if (*I == '=')
423 {
424 I++;
425 Op = pkgCache::Dep::LessEq;
426 break;
427 }
428
429 if (*I == '<')
430 {
431 I++;
432 Op = pkgCache::Dep::Less;
433 break;
434 }
435
436 // < is the same as <= and << is really Cs < for some reason
437 Op = pkgCache::Dep::LessEq;
438 break;
439
440 case '>':
441 I++;
442 if (*I == '=')
443 {
444 I++;
445 Op = pkgCache::Dep::GreaterEq;
446 break;
447 }
448
449 if (*I == '>')
450 {
451 I++;
452 Op = pkgCache::Dep::Greater;
453 break;
454 }
455
456 // > is the same as >= and >> is really Cs > for some reason
457 Op = pkgCache::Dep::GreaterEq;
458 break;
459
460 case '=':
461 Op = pkgCache::Dep::Equals;
462 I++;
463 break;
464
465 // HACK around bad package definitions
466 default:
467 Op = pkgCache::Dep::Equals;
468 break;
469 }
470 return I;
471 }
472 /*}}}*/
473 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
474 // ---------------------------------------------------------------------
475 /* This parses the dependency elements out of a standard string in place,
476 bit by bit. */
477 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
478 std::string &Package,std::string &Ver,unsigned int &Op)
479 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
480 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
481 std::string &Package,std::string &Ver,unsigned int &Op,
482 bool const &ParseArchFlags)
483 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
484 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
485 std::string &Package,std::string &Ver,unsigned int &Op,
486 bool const &ParseArchFlags, bool const &StripMultiArch)
487 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
488 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
489 string &Package,string &Ver,
490 unsigned int &Op, bool const &ParseArchFlags,
491 bool const &StripMultiArch,
492 bool const &ParseRestrictionsList)
493 {
494 // Strip off leading space
495 for (;Start != Stop && isspace(*Start) != 0; ++Start);
496
497 // Parse off the package name
498 const char *I = Start;
499 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
500 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
501 *I != '<' && *I != '>'; ++I);
502
503 // Malformed, no '('
504 if (I != Stop && *I == ')')
505 return 0;
506
507 if (I == Start)
508 return 0;
509
510 // Stash the package name
511 Package.assign(Start,I - Start);
512
513 // We don't want to confuse library users which can't handle MultiArch
514 string const arch = _config->Find("APT::Architecture");
515 if (StripMultiArch == true) {
516 size_t const found = Package.rfind(':');
517 if (found != string::npos &&
518 (strcmp(Package.c_str() + found, ":any") == 0 ||
519 strcmp(Package.c_str() + found, ":native") == 0 ||
520 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
521 Package = Package.substr(0,found);
522 }
523
524 // Skip white space to the '('
525 for (;I != Stop && isspace(*I) != 0 ; I++);
526
527 // Parse a version
528 if (I != Stop && *I == '(')
529 {
530 // Skip the '('
531 for (I++; I != Stop && isspace(*I) != 0 ; I++);
532 if (I + 3 >= Stop)
533 return 0;
534 I = ConvertRelation(I,Op);
535
536 // Skip whitespace
537 for (;I != Stop && isspace(*I) != 0; I++);
538 Start = I;
539 I = (const char*) memchr(I, ')', Stop - I);
540 if (I == NULL || Start == I)
541 return 0;
542
543 // Skip trailing whitespace
544 const char *End = I;
545 for (; End > Start && isspace(End[-1]); End--);
546
547 Ver.assign(Start,End-Start);
548 I++;
549 }
550 else
551 {
552 Ver.clear();
553 Op = pkgCache::Dep::NoOp;
554 }
555
556 // Skip whitespace
557 for (;I != Stop && isspace(*I) != 0; I++);
558
559 if (ParseArchFlags == true)
560 {
561 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
562
563 // Parse an architecture
564 if (I != Stop && *I == '[')
565 {
566 ++I;
567 // malformed
568 if (unlikely(I == Stop))
569 return 0;
570
571 const char *End = I;
572 bool Found = false;
573 bool NegArch = false;
574 while (I != Stop)
575 {
576 // look for whitespace or ending ']'
577 for (;End != Stop && !isspace(*End) && *End != ']'; ++End);
578
579 if (unlikely(End == Stop))
580 return 0;
581
582 if (*I == '!')
583 {
584 NegArch = true;
585 ++I;
586 }
587
588 std::string arch(I, End);
589 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
590 {
591 Found = true;
592 if (I[-1] != '!')
593 NegArch = false;
594 // we found a match, so fast-forward to the end of the wildcards
595 for (; End != Stop && *End != ']'; ++End);
596 }
597
598 if (*End++ == ']') {
599 I = End;
600 break;
601 }
602
603 I = End;
604 for (;I != Stop && isspace(*I) != 0; I++);
605 }
606
607 if (NegArch == true)
608 Found = !Found;
609
610 if (Found == false)
611 Package = ""; /* not for this arch */
612 }
613
614 // Skip whitespace
615 for (;I != Stop && isspace(*I) != 0; I++);
616 }
617
618 if (ParseRestrictionsList == true)
619 {
620 // Parse a restrictions list
621 if (I != Stop && *I == '<')
622 {
623 ++I;
624 // malformed
625 if (unlikely(I == Stop))
626 return 0;
627
628 std::vector<string> const profiles = _config->FindVector("APT::Build-Profiles");
629
630 const char *End = I;
631 bool Found = false;
632 bool NegRestriction = false;
633 while (I != Stop)
634 {
635 // look for whitespace or ending '>'
636 for (;End != Stop && !isspace(*End) && *End != '>'; ++End);
637
638 if (unlikely(End == Stop))
639 return 0;
640
641 if (*I == '!')
642 {
643 NegRestriction = true;
644 ++I;
645 }
646
647 std::string restriction(I, End);
648
649 std::string prefix = "profile.";
650 // only support for "profile" prefix, ignore others
651 if (restriction.size() > prefix.size() &&
652 restriction.substr(0, prefix.size()) == prefix)
653 {
654 // get the name of the profile
655 restriction = restriction.substr(prefix.size());
656
657 if (restriction.empty() == false && profiles.empty() == false &&
658 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
659 {
660 Found = true;
661 if (I[-1] != '!')
662 NegRestriction = false;
663 // we found a match, so fast-forward to the end of the wildcards
664 for (; End != Stop && *End != '>'; ++End);
665 }
666 }
667
668 if (*End++ == '>') {
669 I = End;
670 break;
671 }
672
673 I = End;
674 for (;I != Stop && isspace(*I) != 0; I++);
675 }
676
677 if (NegRestriction == true)
678 Found = !Found;
679
680 if (Found == false)
681 Package = ""; /* not for this restriction */
682 }
683
684 // Skip whitespace
685 for (;I != Stop && isspace(*I) != 0; I++);
686 }
687
688 if (I != Stop && *I == '|')
689 Op |= pkgCache::Dep::Or;
690
691 if (I == Stop || *I == ',' || *I == '|')
692 {
693 if (I != Stop)
694 for (I++; I != Stop && isspace(*I) != 0; I++);
695 return I;
696 }
697
698 return 0;
699 }
700 /*}}}*/
701 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
702 // ---------------------------------------------------------------------
703 /* This is the higher level depends parser. It takes a tag and generates
704 a complete depends tree for the given version. */
705 bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
706 const char *Tag,unsigned int Type)
707 {
708 const char *Start;
709 const char *Stop;
710 if (Section.Find(Tag,Start,Stop) == false)
711 return true;
712
713 string const pkgArch = Ver.Arch();
714
715 while (1)
716 {
717 string Package;
718 string Version;
719 unsigned int Op;
720
721 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
722 if (Start == 0)
723 return _error->Error("Problem parsing dependency %s",Tag);
724 size_t const found = Package.rfind(':');
725
726 // If negative is unspecific it needs to apply on all architectures
727 if (MultiArchEnabled == true && found == string::npos &&
728 (Type == pkgCache::Dep::Conflicts ||
729 Type == pkgCache::Dep::DpkgBreaks ||
730 Type == pkgCache::Dep::Replaces))
731 {
732 for (std::vector<std::string>::const_iterator a = Architectures.begin();
733 a != Architectures.end(); ++a)
734 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
735 return false;
736 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
737 return false;
738 }
739 else if (MultiArchEnabled == true && found != string::npos &&
740 strcmp(Package.c_str() + found, ":any") != 0)
741 {
742 string Arch = Package.substr(found+1, string::npos);
743 Package = Package.substr(0, found);
744 // Such dependencies are not supposed to be accepted …
745 // … but this is probably the best thing to do.
746 if (Arch == "native")
747 Arch = _config->Find("APT::Architecture");
748 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
749 return false;
750 }
751 else
752 {
753 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
754 return false;
755 if ((Type == pkgCache::Dep::Conflicts ||
756 Type == pkgCache::Dep::DpkgBreaks ||
757 Type == pkgCache::Dep::Replaces) &&
758 NewDepends(Ver, Package,
759 (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"),
760 Version,Op,Type) == false)
761 return false;
762 }
763 if (Start == Stop)
764 break;
765 }
766 return true;
767 }
768 /*}}}*/
769 // ListParser::ParseProvides - Parse the provides list /*{{{*/
770 // ---------------------------------------------------------------------
771 /* */
772 bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
773 {
774 const char *Start;
775 const char *Stop;
776 if (Section.Find("Provides",Start,Stop) == true)
777 {
778 string Package;
779 string Version;
780 string const Arch = Ver.Arch();
781 unsigned int Op;
782
783 while (1)
784 {
785 Start = ParseDepends(Start,Stop,Package,Version,Op);
786 if (Start == 0)
787 return _error->Error("Problem parsing Provides line");
788 if (Op != pkgCache::Dep::NoOp) {
789 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
790 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
791 if (NewProvidesAllArch(Ver, Package, Version) == false)
792 return false;
793 } else {
794 if (NewProvides(Ver, Package, Arch, Version) == false)
795 return false;
796 }
797
798 if (Start == Stop)
799 break;
800 }
801 }
802
803 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
804 {
805 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
806 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
807 }
808 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
809 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
810
811 return true;
812 }
813 /*}}}*/
814 // ListParser::NewProvides - add provides for all architectures /*{{{*/
815 bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
816 string const &Version) {
817 for (std::vector<string>::const_iterator a = Architectures.begin();
818 a != Architectures.end(); ++a)
819 {
820 if (NewProvides(Ver, Package, *a, Version) == false)
821 return false;
822 }
823 return true;
824 }
825 /*}}}*/
826 // ListParser::GrabWord - Matches a word and returns /*{{{*/
827 // ---------------------------------------------------------------------
828 /* Looks for a word in a list of words - for ParseStatus */
829 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
830 {
831 for (unsigned int C = 0; List[C].Str != 0; C++)
832 {
833 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
834 {
835 Out = List[C].Val;
836 return true;
837 }
838 }
839 return false;
840 }
841 /*}}}*/
842 // ListParser::Step - Move to the next section in the file /*{{{*/
843 // ---------------------------------------------------------------------
844 /* This has to be careful to only process the correct architecture */
845 bool debListParser::Step()
846 {
847 iOffset = Tags.Offset();
848 while (Tags.Step(Section) == true)
849 {
850 /* See if this is the correct Architecture, if it isn't then we
851 drop the whole section. A missing arch tag only happens (in theory)
852 inside the Status file, so that is a positive return */
853 string const Architecture = Section.FindS("Architecture");
854
855 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
856 {
857 if (APT::Configuration::checkArchitecture(Architecture) == true)
858 return true;
859 /* parse version stanzas without an architecture only in the status file
860 (and as misfortune bycatch flat-archives) */
861 if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true)
862 return true;
863 }
864 else
865 {
866 if (Architecture == Arch)
867 return true;
868
869 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
870 return true;
871 }
872
873 iOffset = Tags.Offset();
874 }
875 return false;
876 }
877 /*}}}*/
878 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
879 // ---------------------------------------------------------------------
880 /* */
881 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
882 FileFd &File, string component)
883 {
884 // apt-secure does no longer download individual (per-section) Release
885 // file. to provide Component pinning we use the section name now
886 map_ptrloc const storage = WriteUniqString(component);
887 FileI->Component = storage;
888
889 pkgTagFile TagFile(&File, File.Size());
890 pkgTagSection Section;
891 if (_error->PendingError() == true || TagFile.Step(Section) == false)
892 return false;
893
894 std::string data;
895 #define APT_INRELEASE(TAG, STORE) \
896 data = Section.FindS(TAG); \
897 if (data.empty() == false) \
898 { \
899 map_ptrloc const storage = WriteUniqString(data); \
900 STORE = storage; \
901 }
902 APT_INRELEASE("Suite", FileI->Archive)
903 APT_INRELEASE("Component", FileI->Component)
904 APT_INRELEASE("Version", FileI->Version)
905 APT_INRELEASE("Origin", FileI->Origin)
906 APT_INRELEASE("Codename", FileI->Codename)
907 APT_INRELEASE("Label", FileI->Label)
908 #undef APT_INRELEASE
909 Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic);
910 Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades);
911
912 return !_error->PendingError();
913 }
914 /*}}}*/
915 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
916 // ---------------------------------------------------------------------
917 /* */
918 unsigned char debListParser::GetPrio(string Str)
919 {
920 unsigned char Out;
921 if (GrabWord(Str,PrioList,Out) == false)
922 Out = pkgCache::State::Extra;
923
924 return Out;
925 }
926 /*}}}*/