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