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