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