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