* apt-pkg/deb/deblistparser.cc:
[ntk/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)
a552f37e
DK
252 {
253 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
254 essential == "all")
255 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
256 else
257 Pkg->Flags |= pkgCache::Flag::Important;
258 }
259
f55a958f
AL
260 if (ParseStatus(Pkg,Ver) == false)
261 return false;
262 return true;
263}
264 /*}}}*/
204fbdcc
AL
265// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
266// ---------------------------------------------------------------------
267/* */
268unsigned short debListParser::VersionHash()
269{
270 const char *Sections[] ={"Installed-Size",
271 "Depends",
272 "Pre-Depends",
f78439bf
AL
273// "Suggests",
274// "Recommends",
204fbdcc 275 "Conflicts",
308c7d30 276 "Breaks",
204fbdcc
AL
277 "Replaces",0};
278 unsigned long Result = INIT_FCS;
418a471f 279 char S[1024];
204fbdcc
AL
280 for (const char **I = Sections; *I != 0; I++)
281 {
282 const char *Start;
283 const char *End;
284 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
285 continue;
286
287 /* Strip out any spaces from the text, this undoes dpkgs reformatting
421c8d10
AL
288 of certain fields. dpkg also has the rather interesting notion of
289 reformatting depends operators < -> <= */
470a5c38 290 char *J = S;
204fbdcc 291 for (; Start != End; Start++)
421c8d10 292 {
204fbdcc 293 if (isspace(*Start) == 0)
470a5c38 294 *J++ = tolower_ascii(*Start);
421c8d10 295 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
470a5c38 296 *J++ = '=';
421c8d10 297 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
470a5c38 298 *J++ = '=';
421c8d10 299 }
418a471f 300
470a5c38 301 Result = AddCRC16(Result,S,J - S);
204fbdcc
AL
302 }
303
304 return Result;
305}
306 /*}}}*/
dcb79bae 307// ListParser::ParseStatus - Parse the status field /*{{{*/
f55a958f
AL
308// ---------------------------------------------------------------------
309/* Status lines are of the form,
310 Status: want flag status
311 want = unknown, install, hold, deinstall, purge
312 flag = ok, reinstreq, hold, hold-reinstreq
a005475e 313 status = not-installed, unpacked, half-configured,
f55a958f
AL
314 half-installed, config-files, post-inst-failed,
315 removal-failed, installed
316
317 Some of the above are obsolete (I think?) flag = hold-* and
318 status = post-inst-failed, removal-failed at least.
319 */
32b9a14c
DK
320bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
321 pkgCache::VerIterator &Ver)
f55a958f
AL
322{
323 const char *Start;
324 const char *Stop;
325 if (Section.Find("Status",Start,Stop) == false)
326 return true;
6bc703c2
DK
327
328 // UsePackage() is responsible for setting the flag in the default case
329 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
330 if (essential == true &&
331 Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
332 return false;
333
f55a958f
AL
334 // Isolate the first word
335 const char *I = Start;
336 for(; I < Stop && *I != ' '; I++);
337 if (I >= Stop || *I != ' ')
338 return _error->Error("Malformed Status line");
339
340 // Process the want field
6c139d6e
AL
341 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
342 {"install",pkgCache::State::Install},
343 {"hold",pkgCache::State::Hold},
344 {"deinstall",pkgCache::State::DeInstall},
b2e465d6
AL
345 {"purge",pkgCache::State::Purge},
346 {}};
347 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
f55a958f
AL
348 return _error->Error("Malformed 1st word in the Status line");
349
350 // Isloate the next word
351 I++;
352 Start = I;
353 for(; I < Stop && *I != ' '; I++);
354 if (I >= Stop || *I != ' ')
355 return _error->Error("Malformed status line, no 2nd word");
356
357 // Process the flag field
6c139d6e
AL
358 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
359 {"reinstreq",pkgCache::State::ReInstReq},
360 {"hold",pkgCache::State::HoldInst},
b2e465d6
AL
361 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
362 {}};
363 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
f55a958f
AL
364 return _error->Error("Malformed 2nd word in the Status line");
365
366 // Isloate the last word
367 I++;
368 Start = I;
369 for(; I < Stop && *I != ' '; I++);
370 if (I != Stop)
371 return _error->Error("Malformed Status line, no 3rd word");
372
373 // Process the flag field
6c139d6e
AL
374 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
375 {"unpacked",pkgCache::State::UnPacked},
376 {"half-configured",pkgCache::State::HalfConfigured},
377 {"installed",pkgCache::State::Installed},
6c139d6e
AL
378 {"half-installed",pkgCache::State::HalfInstalled},
379 {"config-files",pkgCache::State::ConfigFiles},
9d06bc80
MV
380 {"triggers-awaited",pkgCache::State::TriggersAwaited},
381 {"triggers-pending",pkgCache::State::TriggersPending},
6c139d6e 382 {"post-inst-failed",pkgCache::State::HalfConfigured},
b2e465d6
AL
383 {"removal-failed",pkgCache::State::HalfInstalled},
384 {}};
385 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
f55a958f
AL
386 return _error->Error("Malformed 3rd word in the Status line");
387
388 /* A Status line marks the package as indicating the current
389 version as well. Only if it is actually installed.. Otherwise
390 the interesting dpkg handling of the status file creates bogus
391 entries. */
6c139d6e
AL
392 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
393 Pkg->CurrentState == pkgCache::State::ConfigFiles))
f55a958f
AL
394 {
395 if (Ver.end() == true)
396 _error->Warning("Encountered status field in a non-version description");
397 else
398 Pkg->CurrentVer = Ver.Index();
399 }
400
dcb79bae
AL
401 return true;
402}
a1826878 403
b2e465d6
AL
404const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
405{
406 // Determine the operator
407 switch (*I)
408 {
409 case '<':
410 I++;
411 if (*I == '=')
412 {
413 I++;
414 Op = pkgCache::Dep::LessEq;
415 break;
416 }
417
418 if (*I == '<')
419 {
420 I++;
421 Op = pkgCache::Dep::Less;
422 break;
423 }
424
425 // < is the same as <= and << is really Cs < for some reason
426 Op = pkgCache::Dep::LessEq;
427 break;
428
429 case '>':
430 I++;
431 if (*I == '=')
432 {
433 I++;
434 Op = pkgCache::Dep::GreaterEq;
435 break;
436 }
437
438 if (*I == '>')
439 {
440 I++;
441 Op = pkgCache::Dep::Greater;
442 break;
443 }
444
445 // > is the same as >= and >> is really Cs > for some reason
446 Op = pkgCache::Dep::GreaterEq;
447 break;
448
449 case '=':
450 Op = pkgCache::Dep::Equals;
451 I++;
452 break;
453
454 // HACK around bad package definitions
455 default:
456 Op = pkgCache::Dep::Equals;
457 break;
458 }
459 return I;
460}
461
3b20aef1
JAK
462/*
463 * CompleteArch:
464 *
465 * The complete architecture, consisting of <kernel>-<cpu>.
466 */
550f6493 467static string CompleteArch(std::string const &arch) {
5143f361 468 if (arch == "armel") return "linux-arm";
3b9c5cc2 469 if (arch == "armhf") return "linux-arm";
5143f361
JAK
470 if (arch == "lpia") return "linux-i386";
471 if (arch == "powerpcspe") return "linux-powerpc";
472 if (arch == "uclibc-linux-armel") return "linux-arm";
473 if (arch == "uclinux-armel") return "uclinux-arm";
474
3b20aef1
JAK
475 return (arch.find("-") != string::npos) ? arch : "linux-" + arch;
476}
a1826878
AL
477 /*}}}*/
478// ListParser::ParseDepends - Parse a dependency element /*{{{*/
479// ---------------------------------------------------------------------
480/* This parses the dependency elements out of a standard string in place,
481 bit by bit. */
dcb79bae
AL
482const char *debListParser::ParseDepends(const char *Start,const char *Stop,
483 string &Package,string &Ver,
41c81fd8
DK
484 unsigned int &Op, bool const &ParseArchFlags,
485 bool const &StripMultiArch)
dcb79bae
AL
486{
487 // Strip off leading space
488 for (;Start != Stop && isspace(*Start) != 0; Start++);
489
490 // Parse off the package name
491 const char *I = Start;
492 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
90cf90b2 493 *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
dcb79bae
AL
494
495 // Malformed, no '('
496 if (I != Stop && *I == ')')
497 return 0;
498
499 if (I == Start)
500 return 0;
501
502 // Stash the package name
503 Package.assign(Start,I - Start);
41c81fd8
DK
504
505 // We don't want to confuse library users which can't handle MultiArch
550f6493 506 string const arch = _config->Find("APT::Architecture");
41c81fd8
DK
507 if (StripMultiArch == true) {
508 size_t const found = Package.rfind(':');
550f6493
DK
509 if (found != string::npos &&
510 (strcmp(Package.c_str() + found, ":any") == 0 ||
511 strcmp(Package.c_str() + found, ":native") == 0 ||
512 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
41c81fd8
DK
513 Package = Package.substr(0,found);
514 }
515
dcb79bae
AL
516 // Skip white space to the '('
517 for (;I != Stop && isspace(*I) != 0 ; I++);
518
519 // Parse a version
520 if (I != Stop && *I == '(')
521 {
522 // Skip the '('
523 for (I++; I != Stop && isspace(*I) != 0 ; I++);
524 if (I + 3 >= Stop)
525 return 0;
b2e465d6 526 I = ConvertRelation(I,Op);
dcb79bae
AL
527
528 // Skip whitespace
529 for (;I != Stop && isspace(*I) != 0; I++);
530 Start = I;
404528bd
DK
531 I = (const char*) memchr(I, ')', Stop - I);
532 if (I == NULL || Start == I)
533 return 0;
dcb79bae 534
02f000a9
AL
535 // Skip trailing whitespace
536 const char *End = I;
537 for (; End > Start && isspace(End[-1]); End--);
538
171c75f1 539 Ver.assign(Start,End-Start);
dcb79bae
AL
540 I++;
541 }
542 else
543 {
171c75f1 544 Ver.clear();
6c139d6e 545 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
546 }
547
548 // Skip whitespace
549 for (;I != Stop && isspace(*I) != 0; I++);
b2e465d6
AL
550
551 if (ParseArchFlags == true)
552 {
3b20aef1 553 string completeArch = CompleteArch(arch);
9e10ad8a 554
b2e465d6
AL
555 // Parse an architecture
556 if (I != Stop && *I == '[')
557 {
558 // malformed
559 I++;
560 if (I == Stop)
561 return 0;
562
563 const char *End = I;
564 bool Found = false;
9e10ad8a 565 bool NegArch = false;
b2e465d6
AL
566 while (I != Stop)
567 {
568 // look for whitespace or ending ']'
569 while (End != Stop && !isspace(*End) && *End != ']')
570 End++;
571
572 if (End == Stop)
573 return 0;
9e10ad8a
AL
574
575 if (*I == '!')
576 {
577 NegArch = true;
578 I++;
579 }
580
d4af23c2 581 if (stringcmp(arch,I,End) == 0) {
b2e465d6 582 Found = true;
d4af23c2
JAK
583 } else {
584 std::string wildcard = SubstVar(string(I, End), "any", "*");
3b20aef1 585 if (fnmatch(wildcard.c_str(), completeArch.c_str(), 0) == 0)
d4af23c2
JAK
586 Found = true;
587 }
b2e465d6
AL
588
589 if (*End++ == ']') {
590 I = End;
591 break;
592 }
593
594 I = End;
595 for (;I != Stop && isspace(*I) != 0; I++);
596 }
9e10ad8a
AL
597
598 if (NegArch)
599 Found = !Found;
b2e465d6 600
9e10ad8a 601 if (Found == false)
b2e465d6
AL
602 Package = ""; /* not for this arch */
603 }
604
605 // Skip whitespace
606 for (;I != Stop && isspace(*I) != 0; I++);
607 }
608
dcb79bae 609 if (I != Stop && *I == '|')
6c139d6e 610 Op |= pkgCache::Dep::Or;
dcb79bae
AL
611
612 if (I == Stop || *I == ',' || *I == '|')
613 {
614 if (I != Stop)
615 for (I++; I != Stop && isspace(*I) != 0; I++);
616 return I;
617 }
618
619 return 0;
620}
621 /*}}}*/
622// ListParser::ParseDepends - Parse a dependency list /*{{{*/
623// ---------------------------------------------------------------------
624/* This is the higher level depends parser. It takes a tag and generates
625 a complete depends tree for the given version. */
32b9a14c 626bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
dcb79bae
AL
627 const char *Tag,unsigned int Type)
628{
629 const char *Start;
630 const char *Stop;
631 if (Section.Find(Tag,Start,Stop) == false)
632 return true;
306eacf6 633
dcb79bae 634 string Package;
28166356 635 string const pkgArch = Ver.Arch();
dcb79bae
AL
636 string Version;
637 unsigned int Op;
638
8efa2a3b 639 while (1)
dcb79bae 640 {
60dcec6d 641 Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled);
dcb79bae
AL
642 if (Start == 0)
643 return _error->Error("Problem parsing dependency %s",Tag);
306eacf6 644
dcfa253f 645 if (MultiArchEnabled == true &&
306eacf6
DK
646 (Type == pkgCache::Dep::Conflicts ||
647 Type == pkgCache::Dep::DpkgBreaks ||
648 Type == pkgCache::Dep::Replaces))
649 {
dcfa253f
DK
650 for (std::vector<std::string>::const_iterator a = Architectures.begin();
651 a != Architectures.end(); ++a)
306eacf6
DK
652 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
653 return false;
654 }
655 else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
dcb79bae 656 return false;
8efa2a3b
AL
657 if (Start == Stop)
658 break;
dcb79bae
AL
659 }
660 return true;
661}
662 /*}}}*/
663// ListParser::ParseProvides - Parse the provides list /*{{{*/
664// ---------------------------------------------------------------------
665/* */
32b9a14c 666bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae
AL
667{
668 const char *Start;
669 const char *Stop;
67e0766f 670 if (Section.Find("Provides",Start,Stop) == true)
dcb79bae 671 {
67e0766f
DK
672 string Package;
673 string Version;
28166356 674 string const Arch = Ver.Arch();
67e0766f
DK
675 unsigned int Op;
676
677 while (1)
678 {
679 Start = ParseDepends(Start,Stop,Package,Version,Op);
680 if (Start == 0)
681 return _error->Error("Problem parsing Provides line");
682 if (Op != pkgCache::Dep::NoOp) {
683 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
04340db3
DK
684 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
685 if (NewProvidesAllArch(Ver, Package, Version) == false)
686 return false;
67e0766f
DK
687 } else {
688 if (NewProvides(Ver, Package, Arch, Version) == false)
689 return false;
690 }
691
692 if (Start == Stop)
693 break;
b63380b0 694 }
67e0766f 695 }
dcb79bae 696
60dcec6d
DK
697 if (MultiArchEnabled == false)
698 return true;
894d672e 699 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
4d174dc8
DK
700 {
701 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
60dcec6d 702 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
dcb79bae 703 }
894d672e 704 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
60dcec6d 705 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
dcb79bae 706
60dcec6d
DK
707 return true;
708}
709 /*}}}*/
710// ListParser::NewProvides - add provides for all architectures /*{{{*/
711bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
712 string const &Version) {
dcfa253f
DK
713 for (std::vector<string>::const_iterator a = Architectures.begin();
714 a != Architectures.end(); ++a)
67e0766f
DK
715 {
716 if (NewProvides(Ver, Package, *a, Version) == false)
717 return false;
dcb79bae 718 }
f55a958f
AL
719 return true;
720}
721 /*}}}*/
722// ListParser::GrabWord - Matches a word and returns /*{{{*/
723// ---------------------------------------------------------------------
724/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 725bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 726{
b2e465d6 727 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
728 {
729 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
730 {
731 Out = List[C].Val;
732 return true;
733 }
734 }
735 return false;
736}
737 /*}}}*/
738// ListParser::Step - Move to the next section in the file /*{{{*/
739// ---------------------------------------------------------------------
0149949b 740/* This has to be carefull to only process the correct architecture */
f55a958f
AL
741bool debListParser::Step()
742{
dcb79bae 743 iOffset = Tags.Offset();
0149949b 744 while (Tags.Step(Section) == true)
ddc1d8d0
AL
745 {
746 /* See if this is the correct Architecture, if it isn't then we
747 drop the whole section. A missing arch tag only happens (in theory)
748 inside the Status file, so that is a positive return */
5dd4c8b8
DK
749 string const Architecture = Section.FindS("Architecture");
750 if (Architecture.empty() == true)
0149949b 751 return true;
9c14e3d6 752
dd13742e 753 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
5dd4c8b8
DK
754 {
755 if (APT::Configuration::checkArchitecture(Architecture) == true)
756 return true;
757 }
758 else
759 {
760 if (Architecture == Arch)
761 return true;
0149949b 762
28166356 763 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
5dd4c8b8
DK
764 return true;
765 }
dcb79bae
AL
766
767 iOffset = Tags.Offset();
0149949b
AL
768 }
769 return false;
f55a958f
AL
770}
771 /*}}}*/
b0b4efb9
AL
772// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
773// ---------------------------------------------------------------------
774/* */
32b9a14c 775bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
f2152f03 776 FileFd &File, string component)
b0b4efb9 777{
f2152f03
MV
778 // apt-secure does no longer download individual (per-section) Release
779 // file. to provide Component pinning we use the section name now
780 FileI->Component = WriteUniqString(component);
781
699b209e 782 // FIXME: Code depends on the fact that Release files aren't compressed
fe0f7911
DK
783 FILE* release = fdopen(dup(File.Fd()), "r");
784 if (release == NULL)
785 return false;
786
787 char buffer[101];
788 bool gpgClose = false;
789 while (fgets(buffer, sizeof(buffer), release) != NULL)
790 {
791 size_t len = 0;
792
793 // Skip empty lines
b433026f
MV
794 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
795 /* nothing */
796 ;
fe0f7911
DK
797 if (buffer[len] == '\0')
798 continue;
799
800 // only evalute the first GPG section
801 if (strncmp("-----", buffer, 5) == 0)
802 {
803 if (gpgClose == true)
804 break;
805 gpgClose = true;
806 continue;
807 }
808
809 // seperate the tag from the data
404528bd
DK
810 const char* dataStart = strchr(buffer + len, ':');
811 if (dataStart == NULL)
fe0f7911 812 continue;
404528bd 813 len = dataStart - buffer;
b433026f
MV
814 for (++dataStart; *dataStart == ' '; ++dataStart)
815 /* nothing */
816 ;
404528bd 817 const char* dataEnd = (const char*)rawmemchr(dataStart, '\0');
ae6ea526 818 // The last char should be a newline, but we can never be sure: #633350
404528bd 819 const char* lineEnd = dataEnd;
b433026f
MV
820 for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
821 /* nothing */
822 ;
ae6ea526 823 ++lineEnd;
fe0f7911
DK
824
825 // which datastorage need to be updated
a865ed25 826 enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None;
fe0f7911
DK
827 if (buffer[0] == ' ')
828 ;
a865ed25
MV
829 #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X;
830 APT_PARSER_WRITETO(Suite)
831 APT_PARSER_WRITETO(Component)
832 APT_PARSER_WRITETO(Version)
833 APT_PARSER_WRITETO(Origin)
834 APT_PARSER_WRITETO(Codename)
835 APT_PARSER_WRITETO(Label)
fe0f7911
DK
836 #undef APT_PARSER_WRITETO
837 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
ae6ea526 838 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
fe0f7911
DK
839 APT_PARSER_FLAGIT(NotAutomatic)
840 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
841 #undef APT_PARSER_FLAGIT
842
843 // load all data from the line and save it
844 string data;
a865ed25 845 if (writeTo != None)
fe0f7911
DK
846 data.append(dataStart, dataEnd);
847 if (sizeof(buffer) - 1 == (dataEnd - buffer))
848 {
849 while (fgets(buffer, sizeof(buffer), release) != NULL)
850 {
a865ed25 851 if (writeTo != None)
fe0f7911
DK
852 data.append(buffer);
853 if (strlen(buffer) != sizeof(buffer) - 1)
854 break;
855 }
856 }
a865ed25 857 if (writeTo != None)
fe0f7911
DK
858 {
859 // remove spaces and stuff from the end of the data line
860 for (std::string::reverse_iterator s = data.rbegin();
861 s != data.rend(); ++s)
862 {
863 if (*s != '\r' && *s != '\n' && *s != ' ')
864 break;
865 *s = '\0';
866 }
a865ed25
MV
867 switch (writeTo) {
868 case Suite: FileI->Archive = WriteUniqString(data); break;
869 case Component: FileI->Component = WriteUniqString(data); break;
870 case Version: FileI->Version = WriteUniqString(data); break;
871 case Origin: FileI->Origin = WriteUniqString(data); break;
872 case Codename: FileI->Codename = WriteUniqString(data); break;
873 case Label: FileI->Label = WriteUniqString(data); break;
874 case None: break;
875 }
fe0f7911
DK
876 }
877 }
878 fclose(release);
f2152f03 879
b0b4efb9
AL
880 return !_error->PendingError();
881}
882 /*}}}*/
b2e465d6
AL
883// ListParser::GetPrio - Convert the priority from a string /*{{{*/
884// ---------------------------------------------------------------------
885/* */
886unsigned char debListParser::GetPrio(string Str)
887{
888 unsigned char Out;
889 if (GrabWord(Str,PrioList,Out) == false)
890 Out = pkgCache::State::Extra;
891
892 return Out;
893}
894 /*}}}*/