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