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