]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
* apt-pkg/deb/deblistparser.cc:
[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 *J = S;
288 for (; Start != End; Start++)
289 {
290 if (isspace(*Start) == 0)
291 *J++ = tolower_ascii(*Start);
292 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
293 *J++ = '=';
294 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
295 *J++ = '=';
296 }
297
298 Result = AddCRC16(Result,S,J - 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 const &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 string const arch = _config->Find("APT::Architecture");
504 if (StripMultiArch == true) {
505 size_t const found = Package.rfind(':');
506 if (found != string::npos &&
507 (strcmp(Package.c_str() + found, ":any") == 0 ||
508 strcmp(Package.c_str() + found, ":native") == 0 ||
509 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
510 Package = Package.substr(0,found);
511 }
512
513 // Skip white space to the '('
514 for (;I != Stop && isspace(*I) != 0 ; I++);
515
516 // Parse a version
517 if (I != Stop && *I == '(')
518 {
519 // Skip the '('
520 for (I++; I != Stop && isspace(*I) != 0 ; I++);
521 if (I + 3 >= Stop)
522 return 0;
523 I = ConvertRelation(I,Op);
524
525 // Skip whitespace
526 for (;I != Stop && isspace(*I) != 0; I++);
527 Start = I;
528 for (;I != Stop && *I != ')'; I++);
529 if (I == Stop || Start == I)
530 return 0;
531
532 // Skip trailing whitespace
533 const char *End = I;
534 for (; End > Start && isspace(End[-1]); End--);
535
536 Ver.assign(Start,End-Start);
537 I++;
538 }
539 else
540 {
541 Ver.clear();
542 Op = pkgCache::Dep::NoOp;
543 }
544
545 // Skip whitespace
546 for (;I != Stop && isspace(*I) != 0; I++);
547
548 if (ParseArchFlags == true)
549 {
550 string completeArch = CompleteArch(arch);
551
552 // Parse an architecture
553 if (I != Stop && *I == '[')
554 {
555 // malformed
556 I++;
557 if (I == Stop)
558 return 0;
559
560 const char *End = I;
561 bool Found = false;
562 bool NegArch = false;
563 while (I != Stop)
564 {
565 // look for whitespace or ending ']'
566 while (End != Stop && !isspace(*End) && *End != ']')
567 End++;
568
569 if (End == Stop)
570 return 0;
571
572 if (*I == '!')
573 {
574 NegArch = true;
575 I++;
576 }
577
578 if (stringcmp(arch,I,End) == 0) {
579 Found = true;
580 } else {
581 std::string wildcard = SubstVar(string(I, End), "any", "*");
582 if (fnmatch(wildcard.c_str(), completeArch.c_str(), 0) == 0)
583 Found = true;
584 }
585
586 if (*End++ == ']') {
587 I = End;
588 break;
589 }
590
591 I = End;
592 for (;I != Stop && isspace(*I) != 0; I++);
593 }
594
595 if (NegArch)
596 Found = !Found;
597
598 if (Found == false)
599 Package = ""; /* not for this arch */
600 }
601
602 // Skip whitespace
603 for (;I != Stop && isspace(*I) != 0; I++);
604 }
605
606 if (I != Stop && *I == '|')
607 Op |= pkgCache::Dep::Or;
608
609 if (I == Stop || *I == ',' || *I == '|')
610 {
611 if (I != Stop)
612 for (I++; I != Stop && isspace(*I) != 0; I++);
613 return I;
614 }
615
616 return 0;
617 }
618 /*}}}*/
619 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
620 // ---------------------------------------------------------------------
621 /* This is the higher level depends parser. It takes a tag and generates
622 a complete depends tree for the given version. */
623 bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
624 const char *Tag,unsigned int Type)
625 {
626 const char *Start;
627 const char *Stop;
628 if (Section.Find(Tag,Start,Stop) == false)
629 return true;
630
631 string Package;
632 string const pkgArch = Ver.Arch();
633 string Version;
634 unsigned int Op;
635
636 while (1)
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
642 if (MultiArchEnabled == true &&
643 (Type == pkgCache::Dep::Conflicts ||
644 Type == pkgCache::Dep::DpkgBreaks ||
645 Type == pkgCache::Dep::Replaces))
646 {
647 for (std::vector<std::string>::const_iterator a = Architectures.begin();
648 a != Architectures.end(); ++a)
649 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
650 return false;
651 }
652 else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
653 return false;
654 if (Start == Stop)
655 break;
656 }
657 return true;
658 }
659 /*}}}*/
660 // ListParser::ParseProvides - Parse the provides list /*{{{*/
661 // ---------------------------------------------------------------------
662 /* */
663 bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
664 {
665 const char *Start;
666 const char *Stop;
667 if (Section.Find("Provides",Start,Stop) == true)
668 {
669 string Package;
670 string Version;
671 string const Arch = Ver.Arch();
672 unsigned int Op;
673
674 while (1)
675 {
676 Start = ParseDepends(Start,Stop,Package,Version,Op);
677 if (Start == 0)
678 return _error->Error("Problem parsing Provides line");
679 if (Op != pkgCache::Dep::NoOp) {
680 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
681 } else {
682 if (NewProvides(Ver, Package, Arch, Version) == false)
683 return false;
684 }
685
686 if (Start == Stop)
687 break;
688 }
689 }
690
691 if (MultiArchEnabled == false)
692 return true;
693 else if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
694 {
695 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
696 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
697 }
698 else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
699 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
700
701 return true;
702 }
703 /*}}}*/
704 // ListParser::NewProvides - add provides for all architectures /*{{{*/
705 bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
706 string const &Version) {
707 for (std::vector<string>::const_iterator a = Architectures.begin();
708 a != Architectures.end(); ++a)
709 {
710 if (NewProvides(Ver, Package, *a, Version) == false)
711 return false;
712 }
713 return true;
714 }
715 /*}}}*/
716 // ListParser::GrabWord - Matches a word and returns /*{{{*/
717 // ---------------------------------------------------------------------
718 /* Looks for a word in a list of words - for ParseStatus */
719 bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
720 {
721 for (unsigned int C = 0; List[C].Str != 0; C++)
722 {
723 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
724 {
725 Out = List[C].Val;
726 return true;
727 }
728 }
729 return false;
730 }
731 /*}}}*/
732 // ListParser::Step - Move to the next section in the file /*{{{*/
733 // ---------------------------------------------------------------------
734 /* This has to be carefull to only process the correct architecture */
735 bool debListParser::Step()
736 {
737 iOffset = Tags.Offset();
738 while (Tags.Step(Section) == true)
739 {
740 /* See if this is the correct Architecture, if it isn't then we
741 drop the whole section. A missing arch tag only happens (in theory)
742 inside the Status file, so that is a positive return */
743 string const Architecture = Section.FindS("Architecture");
744 if (Architecture.empty() == true)
745 return true;
746
747 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
748 {
749 if (APT::Configuration::checkArchitecture(Architecture) == true)
750 return true;
751 }
752 else
753 {
754 if (Architecture == Arch)
755 return true;
756
757 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
758 return true;
759 }
760
761 iOffset = Tags.Offset();
762 }
763 return false;
764 }
765 /*}}}*/
766 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
767 // ---------------------------------------------------------------------
768 /* */
769 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
770 FileFd &File, string component)
771 {
772 // apt-secure does no longer download individual (per-section) Release
773 // file. to provide Component pinning we use the section name now
774 FileI->Component = WriteUniqString(component);
775
776 FILE* release = fdopen(dup(File.Fd()), "r");
777 if (release == NULL)
778 return false;
779
780 char buffer[101];
781 bool gpgClose = false;
782 while (fgets(buffer, sizeof(buffer), release) != NULL)
783 {
784 size_t len = 0;
785
786 // Skip empty lines
787 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len);
788 if (buffer[len] == '\0')
789 continue;
790
791 // only evalute the first GPG section
792 if (strncmp("-----", buffer, 5) == 0)
793 {
794 if (gpgClose == true)
795 break;
796 gpgClose = true;
797 continue;
798 }
799
800 // seperate the tag from the data
801 for (; buffer[len] != ':' && buffer[len] != '\0'; ++len);
802 if (buffer[len] == '\0')
803 continue;
804 char* dataStart = buffer + len;
805 for (++dataStart; *dataStart == ' '; ++dataStart);
806 char* dataEnd = dataStart;
807 for (++dataEnd; *dataEnd != '\0'; ++dataEnd);
808
809 // which datastorage need to be updated
810 map_ptrloc* writeTo = NULL;
811 if (buffer[0] == ' ')
812 ;
813 #define APT_PARSER_WRITETO(X, Y) else if (strncmp(Y, buffer, len) == 0) writeTo = &X;
814 APT_PARSER_WRITETO(FileI->Archive, "Suite")
815 APT_PARSER_WRITETO(FileI->Component, "Component")
816 APT_PARSER_WRITETO(FileI->Version, "Version")
817 APT_PARSER_WRITETO(FileI->Origin, "Origin")
818 APT_PARSER_WRITETO(FileI->Codename, "Codename")
819 APT_PARSER_WRITETO(FileI->Label, "Label")
820 #undef APT_PARSER_WRITETO
821 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
822 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, dataEnd-1);
823 APT_PARSER_FLAGIT(NotAutomatic)
824 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
825 #undef APT_PARSER_FLAGIT
826
827 // load all data from the line and save it
828 string data;
829 if (writeTo != NULL)
830 data.append(dataStart, dataEnd);
831 if (sizeof(buffer) - 1 == (dataEnd - buffer))
832 {
833 while (fgets(buffer, sizeof(buffer), release) != NULL)
834 {
835 if (writeTo != NULL)
836 data.append(buffer);
837 if (strlen(buffer) != sizeof(buffer) - 1)
838 break;
839 }
840 }
841 if (writeTo != NULL)
842 {
843 // remove spaces and stuff from the end of the data line
844 for (std::string::reverse_iterator s = data.rbegin();
845 s != data.rend(); ++s)
846 {
847 if (*s != '\r' && *s != '\n' && *s != ' ')
848 break;
849 *s = '\0';
850 }
851 *writeTo = WriteUniqString(data);
852 }
853 }
854 fclose(release);
855
856 return !_error->PendingError();
857 }
858 /*}}}*/
859 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
860 // ---------------------------------------------------------------------
861 /* */
862 unsigned char debListParser::GetPrio(string Str)
863 {
864 unsigned char Out;
865 if (GrabWord(Str,PrioList,Out) == false)
866 Out = pkgCache::State::Extra;
867
868 return Out;
869 }
870 /*}}}*/