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