]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/deblistparser.cc
debListParser: Convert to use pkgTagSection::Key-based lookup
[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
JAK
256 static constexpr int prefixLen = 12;
257 static constexpr int avgLanguageLen = 5;
258 std::string tagname;
259
260 tagname.reserve(prefixLen + avgLanguageLen);
261 tagname.assign("Description-");
ffe3c68e
DK
262 if (Section.Exists("Description") == true)
263 avail.push_back("");
264 for (std::vector<std::string>::const_iterator lang = understood.begin(); lang != understood.end(); ++lang)
265 {
4a666d28
JAK
266 tagname.resize(prefixLen);
267 tagname.append(*lang);
268 if (Section.Exists(tagname) == true)
ffe3c68e
DK
269 avail.push_back(*lang);
270 }
271 return avail;
a52f938b 272}
ffe3c68e
DK
273 /*}}}*/
274// ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
a52f938b 275// ---------------------------------------------------------------------
770c32ec
MV
276/* This is to return the md5 string to allow the check if it is the right
277 description. If no Description-md5 is found in the section it will be
278 calculated.
279 */
a52f938b
OS
280MD5SumValue debListParser::Description_md5()
281{
5664bb20 282 StringView const value = Section.Find(pkgTagSection::Key::Description_md5);
fc691496 283 if (value.empty() == true)
770c32ec 284 {
5664bb20 285 StringView const desc = Section.Find(pkgTagSection::Key::Description);
99359751
DK
286 if (desc == "\n")
287 return MD5SumValue();
288
a52f938b 289 MD5Summation md5;
eff0c22e
JAK
290 md5.Add(desc.data(), desc.size());
291 md5.Add("\n");
a52f938b 292 return md5.Result();
fc691496
DK
293 }
294 else if (likely(value.size() == 32))
295 {
50b7dbc5
JAK
296 MD5SumValue sumvalue;
297 if (sumvalue.Set(value))
298 return sumvalue;
299
eff0c22e 300 _error->Error("Malformed Description-md5 line; includes invalid character '%.*s'", (int)value.length(), value.data());
fc691496
DK
301 return MD5SumValue();
302 }
eff0c22e 303 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%.*s'", (int)value.size(), (int)value.length(), value.data());
fc691496 304 return MD5SumValue();
a52f938b
OS
305}
306 /*}}}*/
f55a958f
AL
307// ListParser::UsePackage - Update a package structure /*{{{*/
308// ---------------------------------------------------------------------
309/* This is called to update the package with any new information
310 that might be found in the section */
32b9a14c
DK
311bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
312 pkgCache::VerIterator &Ver)
f55a958f 313{
5dd4c8b8 314 string const static myArch = _config->Find("APT::Architecture");
e5a91f7e
DK
315 // Possible values are: "all", "native", "installed" and "none"
316 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
317 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
318 if (essential == "all" ||
319 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
5664bb20 320 if (Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
5dd4c8b8 321 return false;
5664bb20 322 if (Section.FindFlag(pkgTagSection::Key::Important,Pkg->Flags,pkgCache::Flag::Important) == false)
f55a958f 323 return false;
138d4b3d 324
a9b724ee 325 if (std::find(forceEssential.begin(), forceEssential.end(), Pkg.Name()) != forceEssential.end())
a552f37e
DK
326 {
327 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
328 essential == "all")
329 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
330 else
331 Pkg->Flags |= pkgCache::Flag::Important;
332 }
a9b724ee
DK
333 else if (std::find(forceImportant.begin(), forceImportant.end(), Pkg.Name()) != forceImportant.end())
334 Pkg->Flags |= pkgCache::Flag::Important;
a552f37e 335
f55a958f
AL
336 if (ParseStatus(Pkg,Ver) == false)
337 return false;
338 return true;
339}
340 /*}}}*/
204fbdcc
AL
341// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
342// ---------------------------------------------------------------------
343/* */
344unsigned short debListParser::VersionHash()
345{
5664bb20
JAK
346 static constexpr pkgTagSection::Key Sections[] ={
347 pkgTagSection::Key::Installed_Size,
348 pkgTagSection::Key::Depends,
349 pkgTagSection::Key::Pre_Depends,
350// pkgTagSection::Key::Suggests,
351// pkgTagSection::Key::Recommends",
352 pkgTagSection::Key::Conflicts,
353 pkgTagSection::Key::Breaks,
354 pkgTagSection::Key::Replaces};
204fbdcc 355 unsigned long Result = INIT_FCS;
418a471f 356 char S[1024];
5664bb20 357 for (auto I : Sections)
204fbdcc
AL
358 {
359 const char *Start;
360 const char *End;
708e2f1f 361 if (Section.Find(I,Start,End) == false)
204fbdcc
AL
362 continue;
363
364 /* Strip out any spaces from the text, this undoes dpkgs reformatting
421c8d10
AL
365 of certain fields. dpkg also has the rather interesting notion of
366 reformatting depends operators < -> <= */
470a5c38 367 char *J = S;
708e2f1f 368 for (; Start != End && (J - S) < sizeof(S); ++Start)
421c8d10 369 {
74dedb4a 370 if (isspace_ascii(*Start) != 0)
d9682cf8
DK
371 continue;
372 *J++ = tolower_ascii(*Start);
373
b6e9756c
JAK
374 /* Normalize <= to < and >= to >. This is the wrong way around, but
375 * more efficient that the right way. And since we're only hashing
376 * it does not matter which way we normalize. */
377 if ((*Start == '<' || *Start == '>') && Start[1] == '=') {
378 Start++;
379 }
421c8d10 380 }
418a471f 381
470a5c38 382 Result = AddCRC16(Result,S,J - S);
204fbdcc
AL
383 }
384
385 return Result;
386}
387 /*}}}*/
1c73b0fc 388// StatusListParser::ParseStatus - Parse the status field /*{{{*/
f55a958f
AL
389// ---------------------------------------------------------------------
390/* Status lines are of the form,
391 Status: want flag status
392 want = unknown, install, hold, deinstall, purge
9227645d
GJ
393 flag = ok, reinstreq
394 status = not-installed, config-files, half-installed, unpacked,
395 half-configured, triggers-awaited, triggers-pending, installed
f55a958f 396 */
b830f576
DK
397bool debListParser::ParseStatus(pkgCache::PkgIterator &,
398 pkgCache::VerIterator &)
1c73b0fc
JAK
399{
400 return true;
401}
402bool debStatusListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
403 pkgCache::VerIterator &Ver)
f55a958f
AL
404{
405 const char *Start;
406 const char *Stop;
5664bb20 407 if (Section.Find(pkgTagSection::Key::Status,Start,Stop) == false)
f55a958f 408 return true;
6bc703c2
DK
409
410 // UsePackage() is responsible for setting the flag in the default case
411 bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed";
412 if (essential == true &&
5664bb20 413 Section.FindFlag(pkgTagSection::Key::Essential,Pkg->Flags,pkgCache::Flag::Essential) == false)
6bc703c2
DK
414 return false;
415
f55a958f
AL
416 // Isolate the first word
417 const char *I = Start;
418 for(; I < Stop && *I != ' '; I++);
419 if (I >= Stop || *I != ' ')
420 return _error->Error("Malformed Status line");
421
422 // Process the want field
6c139d6e
AL
423 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
424 {"install",pkgCache::State::Install},
425 {"hold",pkgCache::State::Hold},
426 {"deinstall",pkgCache::State::DeInstall},
b2e465d6 427 {"purge",pkgCache::State::Purge},
3b4045fc 428 {"", 0}};
eff0c22e 429 if (GrabWord(StringView(Start,I-Start),WantList,Pkg->SelectedState) == false)
f55a958f
AL
430 return _error->Error("Malformed 1st word in the Status line");
431
432 // Isloate the next word
433 I++;
434 Start = I;
435 for(; I < Stop && *I != ' '; I++);
436 if (I >= Stop || *I != ' ')
437 return _error->Error("Malformed status line, no 2nd word");
438
439 // Process the flag field
6c139d6e
AL
440 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
441 {"reinstreq",pkgCache::State::ReInstReq},
442 {"hold",pkgCache::State::HoldInst},
b2e465d6 443 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
3b4045fc 444 {"", 0}};
eff0c22e 445 if (GrabWord(StringView(Start,I-Start),FlagList,Pkg->InstState) == false)
f55a958f
AL
446 return _error->Error("Malformed 2nd word in the Status line");
447
448 // Isloate the last word
449 I++;
450 Start = I;
451 for(; I < Stop && *I != ' '; I++);
452 if (I != Stop)
453 return _error->Error("Malformed Status line, no 3rd word");
454
455 // Process the flag field
6c139d6e 456 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
9227645d
GJ
457 {"config-files",pkgCache::State::ConfigFiles},
458 {"half-installed",pkgCache::State::HalfInstalled},
6c139d6e
AL
459 {"unpacked",pkgCache::State::UnPacked},
460 {"half-configured",pkgCache::State::HalfConfigured},
9d06bc80
MV
461 {"triggers-awaited",pkgCache::State::TriggersAwaited},
462 {"triggers-pending",pkgCache::State::TriggersPending},
9227645d 463 {"installed",pkgCache::State::Installed},
3b4045fc 464 {"", 0}};
eff0c22e 465 if (GrabWord(StringView(Start,I-Start),StatusList,Pkg->CurrentState) == false)
f55a958f
AL
466 return _error->Error("Malformed 3rd word in the Status line");
467
468 /* A Status line marks the package as indicating the current
469 version as well. Only if it is actually installed.. Otherwise
470 the interesting dpkg handling of the status file creates bogus
471 entries. */
6c139d6e
AL
472 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
473 Pkg->CurrentState == pkgCache::State::ConfigFiles))
f55a958f
AL
474 {
475 if (Ver.end() == true)
476 _error->Warning("Encountered status field in a non-version description");
477 else
478 Pkg->CurrentVer = Ver.Index();
479 }
480
dcb79bae
AL
481 return true;
482}
a1826878 483
b2e465d6
AL
484const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
485{
486 // Determine the operator
487 switch (*I)
488 {
489 case '<':
490 I++;
491 if (*I == '=')
492 {
493 I++;
494 Op = pkgCache::Dep::LessEq;
495 break;
496 }
497
498 if (*I == '<')
499 {
500 I++;
501 Op = pkgCache::Dep::Less;
502 break;
503 }
504
505 // < is the same as <= and << is really Cs < for some reason
506 Op = pkgCache::Dep::LessEq;
507 break;
508
509 case '>':
510 I++;
511 if (*I == '=')
512 {
513 I++;
514 Op = pkgCache::Dep::GreaterEq;
515 break;
516 }
517
518 if (*I == '>')
519 {
520 I++;
521 Op = pkgCache::Dep::Greater;
522 break;
523 }
524
525 // > is the same as >= and >> is really Cs > for some reason
526 Op = pkgCache::Dep::GreaterEq;
527 break;
528
529 case '=':
530 Op = pkgCache::Dep::Equals;
531 I++;
532 break;
533
534 // HACK around bad package definitions
535 default:
536 Op = pkgCache::Dep::Equals;
537 break;
538 }
539 return I;
540}
a1826878
AL
541 /*}}}*/
542// ListParser::ParseDepends - Parse a dependency element /*{{{*/
543// ---------------------------------------------------------------------
544/* This parses the dependency elements out of a standard string in place,
545 bit by bit. */
565ded7b
JS
546const char *debListParser::ParseDepends(const char *Start,const char *Stop,
547 std::string &Package,std::string &Ver,unsigned int &Op)
548 { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); }
549const char *debListParser::ParseDepends(const char *Start,const char *Stop,
550 std::string &Package,std::string &Ver,unsigned int &Op,
551 bool const &ParseArchFlags)
552 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); }
553const char *debListParser::ParseDepends(const char *Start,const char *Stop,
554 std::string &Package,std::string &Ver,unsigned int &Op,
555 bool const &ParseArchFlags, bool const &StripMultiArch)
556 { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); }
dcb79bae
AL
557const char *debListParser::ParseDepends(const char *Start,const char *Stop,
558 string &Package,string &Ver,
41c81fd8 559 unsigned int &Op, bool const &ParseArchFlags,
565ded7b
JS
560 bool const &StripMultiArch,
561 bool const &ParseRestrictionsList)
eff0c22e
JAK
562{
563 StringView PackageView;
564 StringView VerView;
565
566 auto res = ParseDepends(Start, Stop, PackageView, VerView, Op, (bool)ParseArchFlags,
567 (bool) StripMultiArch, (bool) ParseRestrictionsList);
568 Package = PackageView.to_string();
569 Ver = VerView.to_string();
570
571 return res;
572}
573const char *debListParser::ParseDepends(const char *Start,const char *Stop,
574 StringView &Package,StringView &Ver,
575 unsigned int &Op, bool ParseArchFlags,
576 bool StripMultiArch,
577 bool ParseRestrictionsList)
dcb79bae
AL
578{
579 // Strip off leading space
74dedb4a 580 for (;Start != Stop && isspace_ascii(*Start) != 0; ++Start);
dcb79bae
AL
581
582 // Parse off the package name
583 const char *I = Start;
74dedb4a 584 for (;I != Stop && isspace_ascii(*I) == 0 && *I != '(' && *I != ')' &&
565ded7b
JS
585 *I != ',' && *I != '|' && *I != '[' && *I != ']' &&
586 *I != '<' && *I != '>'; ++I);
dcb79bae
AL
587
588 // Malformed, no '('
589 if (I != Stop && *I == ')')
590 return 0;
591
592 if (I == Start)
593 return 0;
594
595 // Stash the package name
eff0c22e 596 Package = StringView(Start, I - Start);
41c81fd8
DK
597
598 // We don't want to confuse library users which can't handle MultiArch
599 if (StripMultiArch == true) {
0e0bff78 600 string const arch = _config->Find("APT::Architecture");
41c81fd8 601 size_t const found = Package.rfind(':');
eff0c22e 602 if (found != StringView::npos &&
57590d3c
JAK
603 (Package.substr(found) == ":any" ||
604 Package.substr(found) == ":native" ||
605 Package.substr(found +1) == arch))
41c81fd8
DK
606 Package = Package.substr(0,found);
607 }
608
dcb79bae 609 // Skip white space to the '('
74dedb4a 610 for (;I != Stop && isspace_ascii(*I) != 0 ; I++);
dcb79bae
AL
611
612 // Parse a version
613 if (I != Stop && *I == '(')
614 {
615 // Skip the '('
74dedb4a 616 for (I++; I != Stop && isspace_ascii(*I) != 0 ; I++);
dcb79bae
AL
617 if (I + 3 >= Stop)
618 return 0;
b2e465d6 619 I = ConvertRelation(I,Op);
dcb79bae
AL
620
621 // Skip whitespace
74dedb4a 622 for (;I != Stop && isspace_ascii(*I) != 0; I++);
dcb79bae 623 Start = I;
404528bd
DK
624 I = (const char*) memchr(I, ')', Stop - I);
625 if (I == NULL || Start == I)
626 return 0;
dcb79bae 627
02f000a9
AL
628 // Skip trailing whitespace
629 const char *End = I;
74dedb4a 630 for (; End > Start && isspace_ascii(End[-1]); End--);
02f000a9 631
eff0c22e 632 Ver = StringView(Start,End-Start);
dcb79bae
AL
633 I++;
634 }
635 else
636 {
eff0c22e 637 Ver = StringView();
6c139d6e 638 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
639 }
640
641 // Skip whitespace
74dedb4a 642 for (;I != Stop && isspace_ascii(*I) != 0; I++);
b2e465d6 643
14704162 644 if (unlikely(ParseArchFlags == true))
b2e465d6 645 {
0e0bff78 646 string const arch = _config->Find("APT::Architecture");
424ff669 647 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
9e10ad8a 648
b2e465d6
AL
649 // Parse an architecture
650 if (I != Stop && *I == '[')
651 {
cd9694bf 652 ++I;
b2e465d6 653 // malformed
cd9694bf
DK
654 if (unlikely(I == Stop))
655 return 0;
656
657 const char *End = I;
658 bool Found = false;
659 bool NegArch = false;
660 while (I != Stop)
b2e465d6 661 {
cd9694bf 662 // look for whitespace or ending ']'
74dedb4a 663 for (;End != Stop && !isspace_ascii(*End) && *End != ']'; ++End);
cd9694bf
DK
664
665 if (unlikely(End == Stop))
b2e465d6 666 return 0;
9e10ad8a
AL
667
668 if (*I == '!')
cd9694bf 669 {
9e10ad8a 670 NegArch = true;
cd9694bf
DK
671 ++I;
672 }
9e10ad8a 673
8efd5947 674 std::string const arch(I, End);
424ff669 675 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
cd9694bf 676 {
424ff669 677 Found = true;
cd9694bf
DK
678 if (I[-1] != '!')
679 NegArch = false;
680 // we found a match, so fast-forward to the end of the wildcards
681 for (; End != Stop && *End != ']'; ++End);
682 }
683
b2e465d6
AL
684 if (*End++ == ']') {
685 I = End;
686 break;
687 }
cd9694bf 688
b2e465d6 689 I = End;
74dedb4a 690 for (;I != Stop && isspace_ascii(*I) != 0; I++);
cd9694bf 691 }
9e10ad8a 692
cd9694bf 693 if (NegArch == true)
9e10ad8a 694 Found = !Found;
cd9694bf
DK
695
696 if (Found == false)
b2e465d6
AL
697 Package = ""; /* not for this arch */
698 }
cd9694bf 699
b2e465d6 700 // Skip whitespace
74dedb4a 701 for (;I != Stop && isspace_ascii(*I) != 0; I++);
b2e465d6
AL
702 }
703
14704162 704 if (unlikely(ParseRestrictionsList == true))
565ded7b 705 {
ac81c0f9 706 // Parse a restrictions formula which is in disjunctive normal form:
707 // (foo AND bar) OR (blub AND bla)
708
709 std::vector<string> const profiles = APT::Configuration::getBuildProfiles();
710
711 // if the next character is a restriction list, then by default the
712 // dependency does not apply and the conditions have to be checked
713 // if the next character is not a restriction list, then by default the
714 // dependency applies
715 bool applies1 = (*I != '<');
716 while (I != Stop)
565ded7b 717 {
ac81c0f9 718 if (*I != '<')
719 break;
720
565ded7b
JS
721 ++I;
722 // malformed
723 if (unlikely(I == Stop))
724 return 0;
725
565ded7b 726 const char *End = I;
565ded7b 727
ac81c0f9 728 // if of the prior restriction list is already fulfilled, then
729 // we can just skip to the end of the current list
730 if (applies1) {
731 for (;End != Stop && *End != '>'; ++End);
732 I = ++End;
733 // skip whitespace
74dedb4a 734 for (;I != Stop && isspace_ascii(*I) != 0; I++);
ac81c0f9 735 } else {
736 bool applies2 = true;
737 // all the conditions inside a restriction list have to be
738 // met so once we find one that is not met, we can skip to
739 // the end of this list
740 while (I != Stop)
565ded7b 741 {
ac81c0f9 742 // look for whitespace or ending '>'
743 // End now points to the character after the current term
74dedb4a 744 for (;End != Stop && !isspace_ascii(*End) && *End != '>'; ++End);
565ded7b 745
ac81c0f9 746 if (unlikely(End == Stop))
747 return 0;
565ded7b 748
ac81c0f9 749 bool NegRestriction = false;
750 if (*I == '!')
751 {
752 NegRestriction = true;
753 ++I;
754 }
755
8efd5947 756 std::string const restriction(I, End);
565ded7b 757 if (restriction.empty() == false && profiles.empty() == false &&
ac81c0f9 758 std::find(profiles.begin(), profiles.end(), restriction) != profiles.end())
565ded7b 759 {
ac81c0f9 760 if (NegRestriction) {
761 applies2 = false;
762 // since one of the terms does not apply we don't have to check the others
763 for (; End != Stop && *End != '>'; ++End);
764 }
765 } else {
766 if (!NegRestriction) {
767 applies2 = false;
768 // since one of the terms does not apply we don't have to check the others
769 for (; End != Stop && *End != '>'; ++End);
770 }
771 }
772
773 if (*End++ == '>') {
774 I = End;
775 // skip whitespace
74dedb4a 776 for (;I != Stop && isspace_ascii(*I) != 0; I++);
ac81c0f9 777 break;
565ded7b 778 }
565ded7b 779
565ded7b 780 I = End;
ac81c0f9 781 // skip whitespace
74dedb4a 782 for (;I != Stop && isspace_ascii(*I) != 0; I++);
ac81c0f9 783 }
784 if (applies2) {
785 applies1 = true;
565ded7b 786 }
565ded7b 787 }
565ded7b
JS
788 }
789
ac81c0f9 790 if (applies1 == false) {
791 Package = ""; //not for this restriction
792 }
565ded7b
JS
793 }
794
dcb79bae 795 if (I != Stop && *I == '|')
6c139d6e 796 Op |= pkgCache::Dep::Or;
dcb79bae
AL
797
798 if (I == Stop || *I == ',' || *I == '|')
799 {
800 if (I != Stop)
74dedb4a 801 for (I++; I != Stop && isspace_ascii(*I) != 0; I++);
dcb79bae
AL
802 return I;
803 }
804
805 return 0;
806}
807 /*}}}*/
808// ListParser::ParseDepends - Parse a dependency list /*{{{*/
809// ---------------------------------------------------------------------
810/* This is the higher level depends parser. It takes a tag and generates
811 a complete depends tree for the given version. */
32b9a14c 812bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
5664bb20 813 pkgTagSection::Key Key,unsigned int Type)
dcb79bae
AL
814{
815 const char *Start;
816 const char *Stop;
5664bb20 817 if (Section.Find(Key,Start,Stop) == false || Start == Stop)
dcb79bae 818 return true;
306eacf6 819
28166356 820 string const pkgArch = Ver.Arch();
dcb79bae 821
8efa2a3b 822 while (1)
dcb79bae 823 {
eff0c22e
JAK
824 StringView Package;
825 StringView Version;
0f485ee5
TG
826 unsigned int Op;
827
565ded7b 828 Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false);
dcb79bae 829 if (Start == 0)
5664bb20 830 return _error->Error("Problem parsing dependency %zu",static_cast<size_t>(Key)); // TODO
0f485ee5 831 size_t const found = Package.rfind(':');
306eacf6 832
f6ce7ffc 833 if (found == string::npos)
306eacf6 834 {
bb0f6a34 835 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
c919ad6e 836 return false;
306eacf6 837 }
57590d3c 838 else if (Package.substr(found) == ":any")
f6ce7ffc
DK
839 {
840 if (NewDepends(Ver,Package,"any",Version,Op,Type) == false)
841 return false;
842 }
bb0f6a34 843 else
0f485ee5 844 {
0f485ee5 845 // Such dependencies are not supposed to be accepted …
bb0f6a34 846 // … but this is probably the best thing to do anyway
3addaba1 847 if (Package.substr(found + 1) == "native")
8efd5947
DK
848 {
849 std::string const Pkg = Package.substr(0, found).to_string() + ':' + Ver.Cache()->NativeArch();
850 if (NewDepends(Ver, Pkg, "any", Version, Op | pkgCache::Dep::ArchSpecific, Type) == false)
851 return false;
852 }
853 else if (NewDepends(Ver, Package, "any", Version, Op | pkgCache::Dep::ArchSpecific, Type) == false)
0f485ee5
TG
854 return false;
855 }
bb0f6a34 856
8efa2a3b
AL
857 if (Start == Stop)
858 break;
dcb79bae
AL
859 }
860 return true;
861}
862 /*}}}*/
863// ListParser::ParseProvides - Parse the provides list /*{{{*/
864// ---------------------------------------------------------------------
865/* */
32b9a14c 866bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae 867{
3addaba1
DK
868 /* it is unlikely, but while parsing dependencies, we might have already
869 picked up multi-arch implicit provides which we do not want to duplicate here */
870 bool hasProvidesAlready = false;
871 std::string const spzName = Ver.ParentPkg().FullName(false);
872 {
873 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
874 {
875 if (Prv.IsMultiArchImplicit() == false || (Prv->Flags & pkgCache::Flag::ArchSpecific) == 0)
876 continue;
877 if (spzName != Prv.OwnerPkg().FullName(false))
878 continue;
879 hasProvidesAlready = true;
880 break;
881 }
882 }
883
384f17b4 884 string const Arch = Ver.Arch();
dcb79bae
AL
885 const char *Start;
886 const char *Stop;
5664bb20 887 if (Section.Find(pkgTagSection::Key::Provides,Start,Stop) == true)
dcb79bae 888 {
eff0c22e
JAK
889 StringView Package;
890 StringView Version;
67e0766f
DK
891 unsigned int Op;
892
3addaba1 893 do
67e0766f 894 {
3addaba1 895 Start = ParseDepends(Start,Stop,Package,Version,Op, false, false, false);
b209edfa 896 const size_t archfound = Package.rfind(':');
67e0766f
DK
897 if (Start == 0)
898 return _error->Error("Problem parsing Provides line");
eff0c22e
JAK
899 if (unlikely(Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals)) {
900 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.to_string().c_str());
b209edfa 901 } else if (archfound != string::npos) {
eff0c22e 902 StringView spzArch = Package.substr(archfound + 1);
3addaba1
DK
903 if (spzArch != "any")
904 {
905 if (NewProvides(Ver, Package.substr(0, archfound), spzArch, Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
906 return false;
907 }
908 if (NewProvides(Ver, Package, "any", Version, pkgCache::Flag::ArchSpecific) == false)
b209edfa 909 return false;
04340db3 910 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
384f17b4 911 if (APT::Configuration::checkArchitecture(Arch))
62428dbc 912 {
384f17b4
DK
913 if (NewProvidesAllArch(Ver, Package, Version, 0) == false)
914 return false;
62428dbc
DK
915 }
916 else if (NewProvides(Ver, Package, Arch, Version, 0) == false)
917 return false;
67e0766f 918 } else {
3addaba1
DK
919 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
920 {
eff0c22e 921 if (NewProvides(Ver, Package.to_string().append(":any"), "any", Version, pkgCache::Flag::MultiArchImplicit) == false)
3addaba1
DK
922 return false;
923 }
8c7af4d4 924 if (NewProvides(Ver, Package, Arch, Version, 0) == false)
67e0766f
DK
925 return false;
926 }
3addaba1
DK
927 if (archfound == std::string::npos)
928 {
eff0c22e
JAK
929 string spzName = Package.to_string();
930 spzName.push_back(':');
931 spzName.append(Ver.ParentPkg().Arch());
3addaba1
DK
932 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
933 if (spzPkg.end() == false)
934 {
935 if (NewProvides(Ver, spzName, "any", Version, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
936 return false;
937 }
938 }
939 } while (Start != Stop);
67e0766f 940 }
dcb79bae 941
384f17b4 942 if (APT::Configuration::checkArchitecture(Arch))
4d174dc8 943 {
384f17b4
DK
944 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
945 {
946 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
3addaba1
DK
947 if (NewProvides(Ver, Package, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
948 return false;
384f17b4
DK
949 }
950 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
3addaba1
DK
951 {
952 if (NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr(), pkgCache::Flag::MultiArchImplicit) == false)
953 return false;
954 }
dcb79bae 955 }
dcb79bae 956
3addaba1
DK
957 if (hasProvidesAlready == false)
958 {
959 pkgCache::PkgIterator const spzPkg = Ver.Cache()->FindPkg(spzName, "any");
960 if (spzPkg.end() == false)
961 {
962 if (NewProvides(Ver, spzName, "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
963 return false;
964 }
965 }
60dcec6d
DK
966 return true;
967}
968 /*}}}*/
f55a958f
AL
969// ListParser::GrabWord - Matches a word and returns /*{{{*/
970// ---------------------------------------------------------------------
971/* Looks for a word in a list of words - for ParseStatus */
3b4045fc 972bool debListParser::GrabWord(StringView Word, WordList const *List, unsigned char &Out)
f55a958f 973{
3b4045fc 974 for (unsigned int C = 0; List[C].Str.empty() == false; C++)
f55a958f 975 {
3b4045fc
DK
976 if (Word.length() == List[C].Str.length() &&
977 strncasecmp(Word.data(), List[C].Str.data(), Word.length()) == 0)
f55a958f
AL
978 {
979 Out = List[C].Val;
980 return true;
981 }
982 }
983 return false;
984}
985 /*}}}*/
986// ListParser::Step - Move to the next section in the file /*{{{*/
987// ---------------------------------------------------------------------
1e3f4083 988/* This has to be careful to only process the correct architecture */
f55a958f
AL
989bool debListParser::Step()
990{
dcb79bae 991 iOffset = Tags.Offset();
7f8c0eed 992 return Tags.Step(Section);
f55a958f
AL
993}
994 /*}}}*/
b2e465d6
AL
995// ListParser::GetPrio - Convert the priority from a string /*{{{*/
996// ---------------------------------------------------------------------
997/* */
998unsigned char debListParser::GetPrio(string Str)
999{
1000 unsigned char Out;
1001 if (GrabWord(Str,PrioList,Out) == false)
1002 Out = pkgCache::State::Extra;
1003
1004 return Out;
1005}
1006 /*}}}*/
68134bda
DK
1007bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
1008 pkgCache::VerIterator const &Ver)
1009{
c9443c01 1010 if (pkgCacheListParser::SameVersion(Hash, Ver) == false)
68134bda
DK
1011 return false;
1012 // status file has no (Download)Size, but all others are fair game
1013 // status file is parsed last, so the first version we encounter is
1014 // probably also the version we have downloaded
5664bb20 1015 unsigned long long const Size = Section.FindULL(pkgTagSection::Key::Size);
e7edb2fe 1016 if (Size != 0 && Ver->Size != 0 && Size != Ver->Size)
68134bda
DK
1017 return false;
1018 // available everywhere, but easier to check here than to include in VersionHash
1019 unsigned char MultiArch = ParseMultiArch(false);
1020 if (MultiArch != Ver->MultiArch)
1021 return false;
1022 // for all practical proposes (we can check): same version
1023 return true;
1024}
1025 /*}}}*/
0d29b9d4
MV
1026
1027debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile)
7f8c0eed 1028 : debListParser(File), DebFile(DebFile)
0d29b9d4
MV
1029{
1030}
1031
1032bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
1033 pkgCache::VerIterator &Ver)
1034{
1035 bool res = debListParser::UsePackage(Pkg, Ver);
1036 // we use the full file path as a provides so that the file is found
1037 // by its name
5465192b 1038 if(NewProvides(Ver, DebFile, Pkg.Cache()->NativeArch(), Ver.VerStr(), 0) == false)
0d29b9d4
MV
1039 return false;
1040 return res;
1041}
1042
862bafea 1043debListParser::~debListParser() {}