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