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