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