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