]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
cherry pick -r 2184.1.15..2184.1.18 from debian-experimental2
[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 return Section.FindS("Architecture");
73 }
74 /*}}}*/
75 // ListParser::ArchitectureAll /*{{{*/
76 // ---------------------------------------------------------------------
77 /* */
78 bool debListParser::ArchitectureAll() {
79 return Section.FindS("Architecture") == "all";
80 }
81 /*}}}*/
82 // ListParser::Version - Return the version string /*{{{*/
83 // ---------------------------------------------------------------------
84 /* This is to return the string describing the version in debian form,
85 epoch:upstream-release. If this returns the blank string then the
86 entry is assumed to only describe package properties */
87 string debListParser::Version()
88 {
89 return Section.FindS("Version");
90 }
91 /*}}}*/
92 // ListParser::NewVersion - Fill in the version structure /*{{{*/
93 // ---------------------------------------------------------------------
94 /* */
95 bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
96 {
97 // Parse the section
98 Ver->Section = UniqFindTagWrite("Section");
99
100 // Parse multi-arch
101 string const MultiArch = Section.FindS("Multi-Arch");
102 if (MultiArch.empty() == true)
103 Ver->MultiArch = pkgCache::Version::None;
104 else if (MultiArch == "same") {
105 // Parse multi-arch
106 if (ArchitectureAll() == true)
107 {
108 /* Arch all packages can't be Multi-Arch: same */
109 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
110 Section.FindS("Package").c_str());
111 Ver->MultiArch = pkgCache::Version::None;
112 }
113 else
114 Ver->MultiArch = pkgCache::Version::Same;
115 }
116 else if (MultiArch == "foreign")
117 Ver->MultiArch = pkgCache::Version::Foreign;
118 else if (MultiArch == "allowed")
119 Ver->MultiArch = pkgCache::Version::Allowed;
120 else
121 {
122 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
123 MultiArch.c_str(), Section.FindS("Package").c_str());
124 Ver->MultiArch = pkgCache::Version::None;
125 }
126
127 if (ArchitectureAll() == true)
128 Ver->MultiArch |= pkgCache::Version::All;
129
130 // Archive Size
131 Ver->Size = Section.FindULL("Size");
132 // Unpacked Size (in K)
133 Ver->InstalledSize = Section.FindULL("Installed-Size");
134 Ver->InstalledSize *= 1024;
135
136 // Priority
137 const char *Start;
138 const char *Stop;
139 if (Section.Find("Priority",Start,Stop) == true)
140 {
141 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
142 Ver->Priority = pkgCache::State::Extra;
143 }
144
145 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
146 return false;
147 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
148 return false;
149 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
150 return false;
151 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
152 return false;
153 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
154 return false;
155 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
156 return false;
157 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
158 return false;
159 if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
160 return false;
161
162 // Obsolete.
163 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
164 return false;
165
166 if (ParseProvides(Ver) == false)
167 return false;
168
169 return true;
170 }
171 /*}}}*/
172 // ListParser::Description - Return the description string /*{{{*/
173 // ---------------------------------------------------------------------
174 /* This is to return the string describing the package in debian
175 form. If this returns the blank string then the entry is assumed to
176 only describe package properties */
177 string debListParser::Description()
178 {
179 string const lang = DescriptionLanguage();
180 if (lang.empty())
181 return Section.FindS("Description");
182 else
183 return Section.FindS(string("Description-").append(lang).c_str());
184 }
185 /*}}}*/
186 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
187 // ---------------------------------------------------------------------
188 /* This is to return the string describing the language of
189 description. If this returns the blank string then the entry is
190 assumed to describe original description. */
191 string debListParser::DescriptionLanguage()
192 {
193 if (Section.FindS("Description").empty() == false)
194 return "";
195
196 std::vector<string> const lang = APT::Configuration::getLanguages(true);
197 for (std::vector<string>::const_iterator l = lang.begin();
198 l != lang.end(); ++l)
199 if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false)
200 return *l;
201
202 return "";
203 }
204 /*}}}*/
205 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
206 // ---------------------------------------------------------------------
207 /* This is to return the md5 string to allow the check if it is the right
208 description. If no Description-md5 is found in the section it will be
209 calculated.
210 */
211 MD5SumValue debListParser::Description_md5()
212 {
213 string value = Section.FindS("Description-md5");
214
215 if (value.empty())
216 {
217 MD5Summation md5;
218 md5.Add((Description() + "\n").c_str());
219 return md5.Result();
220 } else
221 return MD5SumValue(value);
222 }
223 /*}}}*/
224 // ListParser::UsePackage - Update a package structure /*{{{*/
225 // ---------------------------------------------------------------------
226 /* This is called to update the package with any new information
227 that might be found in the section */
228 bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
229 pkgCache::VerIterator &Ver)
230 {
231 if (Pkg->Section == 0)
232 Pkg->Section = UniqFindTagWrite("Section");
233
234 // Packages which are not from the "native" arch doesn't get the essential flag
235 // in the default "native" mode - it is also possible to mark "all" or "none".
236 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
237 string const static myArch = _config->Find("APT::Architecture");
238 string const static essential = _config->Find("pkgCacheGen::Essential", "native");
239 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
240 essential == "all")
241 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
242 return false;
243 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
244 return false;
245
246 if (strcmp(Pkg.Name(),"apt") == 0)
247 Pkg->Flags |= pkgCache::Flag::Important;
248
249 if (ParseStatus(Pkg,Ver) == false)
250 return false;
251 return true;
252 }
253 /*}}}*/
254 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
255 // ---------------------------------------------------------------------
256 /* */
257 unsigned short debListParser::VersionHash()
258 {
259 const char *Sections[] ={"Installed-Size",
260 "Depends",
261 "Pre-Depends",
262 // "Suggests",
263 // "Recommends",
264 "Conflicts",
265 "Breaks",
266 "Replaces",0};
267 unsigned long Result = INIT_FCS;
268 char S[1024];
269 for (const char **I = Sections; *I != 0; I++)
270 {
271 const char *Start;
272 const char *End;
273 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
274 continue;
275
276 /* Strip out any spaces from the text, this undoes dpkgs reformatting
277 of certain fields. dpkg also has the rather interesting notion of
278 reformatting depends operators < -> <= */
279 char *J = S;
280 for (; Start != End; Start++)
281 {
282 if (isspace(*Start) == 0)
283 *J++ = tolower_ascii(*Start);
284 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
285 *J++ = '=';
286 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
287 *J++ = '=';
288 }
289
290 Result = AddCRC16(Result,S,J - S);
291 }
292
293 return Result;
294 }
295 /*}}}*/
296 // ListParser::ParseStatus - Parse the status field /*{{{*/
297 // ---------------------------------------------------------------------
298 /* Status lines are of the form,
299 Status: want flag status
300 want = unknown, install, hold, deinstall, purge
301 flag = ok, reinstreq, hold, hold-reinstreq
302 status = not-installed, unpacked, half-configured,
303 half-installed, config-files, post-inst-failed,
304 removal-failed, installed
305
306 Some of the above are obsolete (I think?) flag = hold-* and
307 status = post-inst-failed, removal-failed at least.
308 */
309 bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
310 pkgCache::VerIterator &Ver)
311 {
312 const char *Start;
313 const char *Stop;
314 if (Section.Find("Status",Start,Stop) == false)
315 return true;
316
317 // UsePackage() is responsible for setting the flag in the default case
318 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
319 if (essential == true &&
320 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
321 return false;
322
323 // Isolate the first word
324 const char *I = Start;
325 for(; I < Stop && *I != ' '; I++);
326 if (I >= Stop || *I != ' ')
327 return _error->Error("Malformed Status line");
328
329 // Process the want field
330 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
331 {"install",pkgCache::State::Install},
332 {"hold",pkgCache::State::Hold},
333 {"deinstall",pkgCache::State::DeInstall},
334 {"purge",pkgCache::State::Purge},
335 {}};
336 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
337 return _error->Error("Malformed 1st word in the Status line");
338
339 // Isloate the next word
340 I++;
341 Start = I;
342 for(; I < Stop && *I != ' '; I++);
343 if (I >= Stop || *I != ' ')
344 return _error->Error("Malformed status line, no 2nd word");
345
346 // Process the flag field
347 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
348 {"reinstreq",pkgCache::State::ReInstReq},
349 {"hold",pkgCache::State::HoldInst},
350 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
351 {}};
352 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
353 return _error->Error("Malformed 2nd word in the Status line");
354
355 // Isloate the last word
356 I++;
357 Start = I;
358 for(; I < Stop && *I != ' '; I++);
359 if (I != Stop)
360 return _error->Error("Malformed Status line, no 3rd word");
361
362 // Process the flag field
363 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
364 {"unpacked",pkgCache::State::UnPacked},
365 {"half-configured",pkgCache::State::HalfConfigured},
366 {"installed",pkgCache::State::Installed},
367 {"half-installed",pkgCache::State::HalfInstalled},
368 {"config-files",pkgCache::State::ConfigFiles},
369 {"triggers-awaited",pkgCache::State::TriggersAwaited},
370 {"triggers-pending",pkgCache::State::TriggersPending},
371 {"post-inst-failed",pkgCache::State::HalfConfigured},
372 {"removal-failed",pkgCache::State::HalfInstalled},
373 {}};
374 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
375 return _error->Error("Malformed 3rd word in the Status line");
376
377 /* A Status line marks the package as indicating the current
378 version as well. Only if it is actually installed.. Otherwise
379 the interesting dpkg handling of the status file creates bogus
380 entries. */
381 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
382 Pkg->CurrentState == pkgCache::State::ConfigFiles))
383 {
384 if (Ver.end() == true)
385 _error->Warning("Encountered status field in a non-version description");
386 else
387 Pkg->CurrentVer = Ver.Index();
388 }
389
390 return true;
391 }
392
393 const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
394 {
395 // Determine the operator
396 switch (*I)
397 {
398 case '<':
399 I++;
400 if (*I == '=')
401 {
402 I++;
403 Op = pkgCache::Dep::LessEq;
404 break;
405 }
406
407 if (*I == '<')
408 {
409 I++;
410 Op = pkgCache::Dep::Less;
411 break;
412 }
413
414 // < is the same as <= and << is really Cs < for some reason
415 Op = pkgCache::Dep::LessEq;
416 break;
417
418 case '>':
419 I++;
420 if (*I == '=')
421 {
422 I++;
423 Op = pkgCache::Dep::GreaterEq;
424 break;
425 }
426
427 if (*I == '>')
428 {
429 I++;
430 Op = pkgCache::Dep::Greater;
431 break;
432 }
433
434 // > is the same as >= and >> is really Cs > for some reason
435 Op = pkgCache::Dep::GreaterEq;
436 break;
437
438 case '=':
439 Op = pkgCache::Dep::Equals;
440 I++;
441 break;
442
443 // HACK around bad package definitions
444 default:
445 Op = pkgCache::Dep::Equals;
446 break;
447 }
448 return I;
449 }
450
451 /*
452 * CompleteArch:
453 *
454 * The complete architecture, consisting of <kernel>-<cpu>.
455 */
456 static string CompleteArch(std::string const &arch) {
457 if (arch == "armel") return "linux-arm";
458 if (arch == "armhf") return "linux-arm";
459 if (arch == "lpia") return "linux-i386";
460 if (arch == "powerpcspe") return "linux-powerpc";
461 if (arch == "uclibc-linux-armel") return "linux-arm";
462 if (arch == "uclinux-armel") return "uclinux-arm";
463
464 return (arch.find("-") != string::npos) ? arch : "linux-" + arch;
465 }
466 /*}}}*/
467 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
468 // ---------------------------------------------------------------------
469 /* This parses the dependency elements out of a standard string in place,
470 bit by bit. */
471 const char *debListParser::ParseDepends(const char *Start,const char *Stop,
472 string &Package,string &Ver,
473 unsigned int &Op, bool const &ParseArchFlags,
474 bool const &StripMultiArch)
475 {
476 // Strip off leading space
477 for (;Start != Stop && isspace(*Start) != 0; Start++);
478
479 // Parse off the package name
480 const char *I = Start;
481 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
482 *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
483
484 // Malformed, no '('
485 if (I != Stop && *I == ')')
486 return 0;
487
488 if (I == Start)
489 return 0;
490
491 // Stash the package name
492 Package.assign(Start,I - Start);
493
494 // We don't want to confuse library users which can't handle MultiArch
495 string const arch = _config->Find("APT::Architecture");
496 if (StripMultiArch == true) {
497 size_t const found = Package.rfind(':');
498 if (found != string::npos &&
499 (strcmp(Package.c_str() + found, ":any") == 0 ||
500 strcmp(Package.c_str() + found, ":native") == 0 ||
501 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
502 Package = Package.substr(0,found);
503 }
504
505 // Skip white space to the '('
506 for (;I != Stop && isspace(*I) != 0 ; I++);
507
508 // Parse a version
509 if (I != Stop && *I == '(')
510 {
511 // Skip the '('
512 for (I++; I != Stop && isspace(*I) != 0 ; I++);
513 if (I + 3 >= Stop)
514 return 0;
515 I = ConvertRelation(I,Op);
516
517 // Skip whitespace
518 for (;I != Stop && isspace(*I) != 0; I++);
519 Start = I;
520 for (;I != Stop && *I != ')'; I++);
521 if (I == Stop || Start == I)
522 return 0;
523
524 // Skip trailing whitespace
525 const char *End = I;
526 for (; End > Start && isspace(End[-1]); End--);
527
528 Ver.assign(Start,End-Start);
529 I++;
530 }
531 else
532 {
533 Ver.clear();
534 Op = pkgCache::Dep::NoOp;
535 }
536
537 // Skip whitespace
538 for (;I != Stop && isspace(*I) != 0; I++);
539
540 if (ParseArchFlags == true)
541 {
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 /* nothing */
781 ;
782 if (buffer[len] == '\0')
783 continue;
784
785 // only evalute the first GPG section
786 if (strncmp("-----", buffer, 5) == 0)
787 {
788 if (gpgClose == true)
789 break;
790 gpgClose = true;
791 continue;
792 }
793
794 // seperate the tag from the data
795 for (; buffer[len] != ':' && buffer[len] != '\0'; ++len)
796 /* nothing */
797 ;
798 if (buffer[len] == '\0')
799 continue;
800 char* dataStart = buffer + len;
801 for (++dataStart; *dataStart == ' '; ++dataStart)
802 /* nothing */
803 ;
804 char* dataEnd = dataStart;
805 for (++dataEnd; *dataEnd != '\0'; ++dataEnd)
806 /* nothing */
807 ;
808 // The last char should be a newline, but we can never be sure: #633350
809 char* lineEnd = dataEnd;
810 for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
811 /* nothing */
812 ;
813 ++lineEnd;
814
815 // which datastorage need to be updated
816 enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None;
817 if (buffer[0] == ' ')
818 ;
819 #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X;
820 APT_PARSER_WRITETO(Suite)
821 APT_PARSER_WRITETO(Component)
822 APT_PARSER_WRITETO(Version)
823 APT_PARSER_WRITETO(Origin)
824 APT_PARSER_WRITETO(Codename)
825 APT_PARSER_WRITETO(Label)
826 #undef APT_PARSER_WRITETO
827 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
828 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
829 APT_PARSER_FLAGIT(NotAutomatic)
830 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
831 #undef APT_PARSER_FLAGIT
832
833 // load all data from the line and save it
834 string data;
835 if (writeTo != None)
836 data.append(dataStart, dataEnd);
837 if (sizeof(buffer) - 1 == (dataEnd - buffer))
838 {
839 while (fgets(buffer, sizeof(buffer), release) != NULL)
840 {
841 if (writeTo != None)
842 data.append(buffer);
843 if (strlen(buffer) != sizeof(buffer) - 1)
844 break;
845 }
846 }
847 if (writeTo != None)
848 {
849 // remove spaces and stuff from the end of the data line
850 for (std::string::reverse_iterator s = data.rbegin();
851 s != data.rend(); ++s)
852 {
853 if (*s != '\r' && *s != '\n' && *s != ' ')
854 break;
855 *s = '\0';
856 }
857 switch (writeTo) {
858 case Suite: FileI->Archive = WriteUniqString(data); break;
859 case Component: FileI->Component = WriteUniqString(data); break;
860 case Version: FileI->Version = WriteUniqString(data); break;
861 case Origin: FileI->Origin = WriteUniqString(data); break;
862 case Codename: FileI->Codename = WriteUniqString(data); break;
863 case Label: FileI->Label = WriteUniqString(data); break;
864 case None: break;
865 }
866 }
867 }
868 fclose(release);
869
870 return !_error->PendingError();
871 }
872 /*}}}*/
873 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
874 // ---------------------------------------------------------------------
875 /* */
876 unsigned char debListParser::GetPrio(string Str)
877 {
878 unsigned char Out;
879 if (GrabWord(Str,PrioList,Out) == false)
880 Out = pkgCache::State::Extra;
881
882 return Out;
883 }
884 /*}}}*/