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