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