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