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