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