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