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