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