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