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