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