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