]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
Revert "Fix select timeout to be 50msec instead of 0.5msec" for acquire
[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/crc-16.h>
22 #include <apt-pkg/md5.h>
23 #include <apt-pkg/pkgcache.h>
24 #include <apt-pkg/cacheiterators.h>
25 #include <apt-pkg/tagfile.h>
26 #include <apt-pkg/macros.h>
27
28 #include <stddef.h>
29 #include <string.h>
30 #include <algorithm>
31 #include <string>
32 #include <vector>
33 #include <ctype.h>
34 /*}}}*/
35
36 using std::string;
37
38 static debListParser::WordList PrioList[] = {
39 {"required",pkgCache::State::Required},
40 {"important",pkgCache::State::Important},
41 {"standard",pkgCache::State::Standard},
42 {"optional",pkgCache::State::Optional},
43 {"extra",pkgCache::State::Extra},
44 {NULL, 0}};
45
46 // ListParser::debListParser - Constructor /*{{{*/
47 // ---------------------------------------------------------------------
48 /* Provide an architecture and only this one and "all" will be accepted
49 in Step(), if no Architecture is given we will accept every arch
50 we would accept in general with checkArchitecture() */
51 debListParser::debListParser(FileFd *File) :
52 pkgCacheListParser(), d(NULL), Tags(File)
53 {
54 }
55 /*}}}*/
56 // ListParser::Package - Return the package name /*{{{*/
57 // ---------------------------------------------------------------------
58 /* This is to return the name of the package this section describes */
59 string debListParser::Package() {
60 string const Result = Section.FindS("Package");
61 if(unlikely(Result.empty() == true))
62 _error->Error("Encountered a section with no Package: header");
63 return Result;
64 }
65 /*}}}*/
66 // ListParser::Architecture - Return the package arch /*{{{*/
67 // ---------------------------------------------------------------------
68 /* This will return the Architecture of the package this section describes */
69 string debListParser::Architecture() {
70 std::string const Arch = Section.FindS("Architecture");
71 return Arch.empty() ? "none" : Arch;
72 }
73 /*}}}*/
74 // ListParser::ArchitectureAll /*{{{*/
75 // ---------------------------------------------------------------------
76 /* */
77 bool debListParser::ArchitectureAll() {
78 return Section.FindS("Architecture") == "all";
79 }
80 /*}}}*/
81 // ListParser::Version - Return the version string /*{{{*/
82 // ---------------------------------------------------------------------
83 /* This is to return the string describing the version in debian form,
84 epoch:upstream-release. If this returns the blank string then the
85 entry is assumed to only describe package properties */
86 string debListParser::Version()
87 {
88 return Section.FindS("Version");
89 }
90 /*}}}*/
91 unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/
92 {
93 unsigned char MA;
94 string const MultiArch = Section.FindS("Multi-Arch");
95 if (MultiArch.empty() == true || MultiArch == "no")
96 MA = pkgCache::Version::No;
97 else if (MultiArch == "same") {
98 if (ArchitectureAll() == true)
99 {
100 if (showErrors == true)
101 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
102 Section.FindS("Package").c_str());
103 MA = pkgCache::Version::No;
104 }
105 else
106 MA = pkgCache::Version::Same;
107 }
108 else if (MultiArch == "foreign")
109 MA = pkgCache::Version::Foreign;
110 else if (MultiArch == "allowed")
111 MA = pkgCache::Version::Allowed;
112 else
113 {
114 if (showErrors == true)
115 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
116 MultiArch.c_str(), Section.FindS("Package").c_str());
117 MA = pkgCache::Version::No;
118 }
119
120 if (ArchitectureAll() == true)
121 MA |= pkgCache::Version::All;
122
123 return MA;
124 }
125 /*}}}*/
126 // ListParser::NewVersion - Fill in the version structure /*{{{*/
127 // ---------------------------------------------------------------------
128 /* */
129 bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
130 {
131 const char *Start;
132 const char *Stop;
133
134 // Parse the section
135 if (Section.Find("Section",Start,Stop) == true)
136 {
137 map_stringitem_t const idx = StoreString(pkgCacheGenerator::SECTION, Start, Stop - Start);
138 Ver->Section = idx;
139 }
140 // Parse the source package name
141 pkgCache::GrpIterator const G = Ver.ParentPkg().Group();
142 Ver->SourcePkgName = G->Name;
143 Ver->SourceVerStr = Ver->VerStr;
144 if (Section.Find("Source",Start,Stop) == true)
145 {
146 const char * const Space = (const char * const) memchr(Start, ' ', Stop - Start);
147 pkgCache::VerIterator V;
148
149 if (Space != NULL)
150 {
151 Stop = Space;
152 const char * const Open = (const char * const) memchr(Space, '(', Stop - Space);
153 if (likely(Open != NULL))
154 {
155 const char * const Close = (const char * const) memchr(Open, ')', Stop - Open);
156 if (likely(Close != NULL))
157 {
158 std::string const version(Open + 1, (Close - Open) - 1);
159 if (version != Ver.VerStr())
160 {
161 map_stringitem_t const idx = StoreString(pkgCacheGenerator::VERSIONNUMBER, version);
162 Ver->SourceVerStr = idx;
163 }
164 }
165 }
166 }
167
168 std::string const pkgname(Start, Stop - Start);
169 if (pkgname != G.Name())
170 {
171 for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
172 {
173 for (V = P.VersionList(); V.end() == false; ++V)
174 {
175 if (pkgname == V.SourcePkgName())
176 {
177 Ver->SourcePkgName = V->SourcePkgName;
178 break;
179 }
180 }
181 if (V.end() == false)
182 break;
183 }
184 if (V.end() == true)
185 {
186 map_stringitem_t const idx = StoreString(pkgCacheGenerator::PKGNAME, pkgname);
187 Ver->SourcePkgName = idx;
188 }
189 }
190 }
191
192 Ver->MultiArch = ParseMultiArch(true);
193 // Archive Size
194 Ver->Size = Section.FindULL("Size");
195 // Unpacked Size (in K)
196 Ver->InstalledSize = Section.FindULL("Installed-Size");
197 Ver->InstalledSize *= 1024;
198
199 // Priority
200 if (Section.Find("Priority",Start,Stop) == true)
201 {
202 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
203 Ver->Priority = pkgCache::State::Extra;
204 }
205
206 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
207 return false;
208 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
209 return false;
210 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
211 return false;
212 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
213 return false;
214 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
215 return false;
216 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
217 return false;
218 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
219 return false;
220 if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
221 return false;
222 // Obsolete.
223 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
224 return false;
225
226 if (ParseProvides(Ver) == false)
227 return false;
228
229 return true;
230 }
231 /*}}}*/
232 // ListParser::Description - Return the description string /*{{{*/
233 // ---------------------------------------------------------------------
234 /* This is to return the string describing the package in debian
235 form. If this returns the blank string then the entry is assumed to
236 only describe package properties */
237 string debListParser::Description(std::string const &lang)
238 {
239 if (lang.empty())
240 return Section.FindS("Description");
241 else
242 return Section.FindS(string("Description-").append(lang).c_str());
243 }
244 /*}}}*/
245 // ListParser::AvailableDescriptionLanguages /*{{{*/
246 std::vector<std::string> debListParser::AvailableDescriptionLanguages()
247 {
248 std::vector<std::string> const understood = APT::Configuration::getLanguages();
249 std::vector<std::string> avail;
250 if (Section.Exists("Description") == true)
251 avail.push_back("");
252 for (std::vector<std::string>::const_iterator lang = understood.begin(); lang != understood.end(); ++lang)
253 {
254 std::string const tagname = "Description-" + *lang;
255 if (Section.Exists(tagname.c_str()) == true)
256 avail.push_back(*lang);
257 }
258 return avail;
259 }
260 /*}}}*/
261 // ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
262 // ---------------------------------------------------------------------
263 /* This is to return the md5 string to allow the check if it is the right
264 description. If no Description-md5 is found in the section it will be
265 calculated.
266 */
267 MD5SumValue debListParser::Description_md5()
268 {
269 string const value = Section.FindS("Description-md5");
270 if (value.empty() == true)
271 {
272 std::string const desc = Description("") + "\n";
273 if (desc == "\n")
274 return MD5SumValue();
275
276 MD5Summation md5;
277 md5.Add(desc.c_str());
278 return md5.Result();
279 }
280 else if (likely(value.size() == 32))
281 {
282 if (likely(value.find_first_not_of("0123456789abcdefABCDEF") == string::npos))
283 return MD5SumValue(value);
284 _error->Error("Malformed Description-md5 line; includes invalid character '%s'", value.c_str());
285 return MD5SumValue();
286 }
287 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%s'", (int)value.size(), value.c_str());
288 return MD5SumValue();
289 }
290 /*}}}*/
291 // ListParser::UsePackage - Update a package structure /*{{{*/
292 // ---------------------------------------------------------------------
293 /* This is called to update the package with any new information
294 that might be found in the section */
295 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
296 pkgCache::VerIterator &Ver)
297 {
298 string const static myArch = _config->Find("APT::Architecture");
299 // Possible values are: "all", "native", "installed" and "none"
300 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
301 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
302 if (essential == "all" ||
303 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
304 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
305 return false;
306 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
307 return false;
308
309 if (strcmp(Pkg.Name(),"apt") == 0)
310 {
311 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
312 essential == "all")
313 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
314 else
315 Pkg->Flags |= pkgCache::Flag::Important;
316 }
317
318 if (ParseStatus(Pkg,Ver) == false)
319 return false;
320 return true;
321 }
322 /*}}}*/
323 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
324 // ---------------------------------------------------------------------
325 /* */
326 unsigned short debListParser::VersionHash()
327 {
328 const char *Sections[] ={"Installed-Size",
329 "Depends",
330 "Pre-Depends",
331 // "Suggests",
332 // "Recommends",
333 "Conflicts",
334 "Breaks",
335 "Replaces",0};
336 unsigned long Result = INIT_FCS;
337 char S[1024];
338 for (const char * const *I = Sections; *I != 0; ++I)
339 {
340 const char *Start;
341 const char *End;
342 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
343 continue;
344
345 /* Strip out any spaces from the text, this undoes dpkgs reformatting
346 of certain fields. dpkg also has the rather interesting notion of
347 reformatting depends operators < -> <= */
348 char *J = S;
349 for (; Start != End; ++Start)
350 {
351 if (isspace(*Start) != 0)
352 continue;
353 *J++ = tolower_ascii(*Start);
354
355 if ((*Start == '<' || *Start == '>') && Start[1] != *Start && Start[1] != '=')
356 *J++ = '=';
357 }
358
359 Result = AddCRC16(Result,S,J - S);
360 }
361
362 return Result;
363 }
364 /*}}}*/
365 // StatusListParser::ParseStatus - Parse the status field /*{{{*/
366 // ---------------------------------------------------------------------
367 /* Status lines are of the form,
368 Status: want flag status
369 want = unknown, install, hold, deinstall, purge
370 flag = ok, reinstreq
371 status = not-installed, config-files, half-installed, unpacked,
372 half-configured, triggers-awaited, triggers-pending, installed
373 */
374 bool debListParser::ParseStatus(pkgCache::PkgIterator &,
375 pkgCache::VerIterator &)
376 {
377 return true;
378 }
379 bool debStatusListParser::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)
795 {
796 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
797 return false;
798 }
799 else if (strcmp(Package.c_str() + found, ":any") == 0)
800 {
801 if (NewDepends(Ver,Package,"any",Version,Op,Type) == false)
802 return false;
803 }
804 else
805 {
806 // Such dependencies are not supposed to be accepted …
807 // … but this is probably the best thing to do anyway
808 if (Package.substr(found + 1) == "native")
809 Package = Package.substr(0, found) + ':' + Ver.Cache()->NativeArch();
810
811 if (NewDepends(Ver, Package, "any", Version, Op | pkgCache::Dep::ArchSpecific, Type) == false)
812 return false;
813 }
814
815 if (Start == Stop)
816 break;
817 }
818 return true;
819 }
820 /*}}}*/
821 // ListParser::ParseProvides - Parse the provides list /*{{{*/
822 // ---------------------------------------------------------------------
823 /* */
824 bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
825 {
826 /* it is unlikely, but while parsing dependencies, we might have already
827 picked up multi-arch implicit provides which we do not want to duplicate here */
828 bool hasProvidesAlready = false;
829 std::string const spzName = Ver.ParentPkg().FullName(false);
830 {
831 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
832 {
833 if (Prv.IsMultiArchImplicit() == false || (Prv->Flags & pkgCache::Flag::ArchSpecific) == 0)
834 continue;
835 if (spzName != Prv.OwnerPkg().FullName(false))
836 continue;
837 hasProvidesAlready = true;
838 break;
839 }
840 }
841
842 string const Arch = Ver.Arch();
843 const char *Start;
844 const char *Stop;
845 if (Section.Find("Provides",Start,Stop) == true)
846 {
847 string Package;
848 string Version;
849 unsigned int Op;
850
851 do
852 {
853 Start = ParseDepends(Start,Stop,Package,Version,Op, false, false, false);
854 const size_t archfound = Package.rfind(':');
855 if (Start == 0)
856 return _error->Error("Problem parsing Provides line");
857 if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) {
858 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str());
859 } else if (archfound != string::npos) {
860 std::string spzArch = Package.substr(archfound + 1);
861 if (spzArch != "any")
862 {
863 if (NewProvides(Ver, Package.substr(0, archfound), spzArch, Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
864 return false;
865 }
866 if (NewProvides(Ver, Package, "any", Version, pkgCache::Flag::ArchSpecific) == false)
867 return false;
868 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
869 if (APT::Configuration::checkArchitecture(Arch))
870 if (NewProvidesAllArch(Ver, Package, Version, 0) == false)
871 return false;
872 } else {
873 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
874 {
875 if (NewProvides(Ver, Package + ":any", "any", Version, pkgCache::Flag::MultiArchImplicit) == false)
876 return false;
877 }
878 if (NewProvides(Ver, Package, Arch, Version, 0) == false)
879 return false;
880 }
881 if (archfound == std::string::npos)
882 {
883 std::string const spzName = Package + ':' + Ver.ParentPkg().Arch();
884 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
885 if (spzPkg.end() == false)
886 {
887 if (NewProvides(Ver, spzName, "any", Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
888 return false;
889 }
890 }
891 } while (Start != Stop);
892 }
893
894 if (APT::Configuration::checkArchitecture(Arch))
895 {
896 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
897 {
898 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
899 if (NewProvides(Ver, Package, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
900 return false;
901 }
902 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
903 {
904 if (NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
905 return false;
906 }
907 }
908
909 if (hasProvidesAlready == false)
910 {
911 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
912 if (spzPkg.end() == false)
913 {
914 if (NewProvides(Ver, spzName, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
915 return false;
916 }
917 }
918 return true;
919 }
920 /*}}}*/
921 // ListParser::GrabWord - Matches a word and returns /*{{{*/
922 // ---------------------------------------------------------------------
923 /* Looks for a word in a list of words - for ParseStatus */
924 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
925 {
926 for (unsigned int C = 0; List[C].Str != 0; C++)
927 {
928 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
929 {
930 Out = List[C].Val;
931 return true;
932 }
933 }
934 return false;
935 }
936 /*}}}*/
937 // ListParser::Step - Move to the next section in the file /*{{{*/
938 // ---------------------------------------------------------------------
939 /* This has to be careful to only process the correct architecture */
940 bool debListParser::Step()
941 {
942 iOffset = Tags.Offset();
943 return Tags.Step(Section);
944 }
945 /*}}}*/
946 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
947 // ---------------------------------------------------------------------
948 /* */
949 unsigned char debListParser::GetPrio(string Str)
950 {
951 unsigned char Out;
952 if (GrabWord(Str,PrioList,Out) == false)
953 Out = pkgCache::State::Extra;
954
955 return Out;
956 }
957 /*}}}*/
958 bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
959 pkgCache::VerIterator const &Ver)
960 {
961 if (pkgCacheListParser::SameVersion(Hash, Ver) == false)
962 return false;
963 // status file has no (Download)Size, but all others are fair game
964 // status file is parsed last, so the first version we encounter is
965 // probably also the version we have downloaded
966 unsigned long long const Size = Section.FindULL("Size");
967 if (Size != 0 && Size != Ver->Size)
968 return false;
969 // available everywhere, but easier to check here than to include in VersionHash
970 unsigned char MultiArch = ParseMultiArch(false);
971 if (MultiArch != Ver->MultiArch)
972 return false;
973 // for all practical proposes (we can check): same version
974 return true;
975 }
976 /*}}}*/
977
978 debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile)
979 : debListParser(File), DebFile(DebFile)
980 {
981 }
982
983 bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
984 pkgCache::VerIterator &Ver)
985 {
986 bool res = debListParser::UsePackage(Pkg, Ver);
987 // we use the full file path as a provides so that the file is found
988 // by its name
989 if(NewProvides(Ver, DebFile, Pkg.Cache()->NativeArch(), Ver.VerStr(), 0) == false)
990 return false;
991 return res;
992 }
993
994 debListParser::~debListParser() {}