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