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