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