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