]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/deblistparser.cc
Merge branch 'debian/sid' into debian/experimental
[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() */
53debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
54 Arch(Arch) {
33dd02e3
DK
55 if (Arch == "native")
56 this->Arch = _config->Find("APT::Architecture");
dcfa253f
DK
57 Architectures = APT::Configuration::getArchitectures();
58 MultiArchEnabled = Architectures.size() > 1;
0149949b
AL
59}
60 /*}}}*/
f55a958f
AL
61// ListParser::Package - Return the package name /*{{{*/
62// ---------------------------------------------------------------------
63/* This is to return the name of the package this section describes */
5bf15716 64string debListParser::Package() {
33dd02e3
DK
65 string const Result = Section.FindS("Package");
66 if(unlikely(Result.empty() == true))
67 _error->Error("Encountered a section with no Package: header");
68 return Result;
5bf15716
DK
69}
70 /*}}}*/
71// ListParser::Architecture - Return the package arch /*{{{*/
72// ---------------------------------------------------------------------
28166356 73/* This will return the Architecture of the package this section describes */
5bf15716 74string debListParser::Architecture() {
99a2ea5a 75 return Section.FindS("Architecture");
f55a958f
AL
76}
77 /*}}}*/
857e9c13
DK
78// ListParser::ArchitectureAll /*{{{*/
79// ---------------------------------------------------------------------
80/* */
81bool debListParser::ArchitectureAll() {
33dd02e3 82 return Section.FindS("Architecture") == "all";
f55a958f
AL
83}
84 /*}}}*/
85// ListParser::Version - Return the version string /*{{{*/
86// ---------------------------------------------------------------------
87/* This is to return the string describing the version in debian form,
88 epoch:upstream-release. If this returns the blank string then the
89 entry is assumed to only describe package properties */
90string debListParser::Version()
91{
b0b4efb9 92 return Section.FindS("Version");
f55a958f
AL
93}
94 /*}}}*/
e33dbfe5 95unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/
0149949b 96{
e33dbfe5 97 unsigned char MA;
28166356 98 string const MultiArch = Section.FindS("Multi-Arch");
19fb04e8 99 if (MultiArch.empty() == true || MultiArch == "no")
e33dbfe5 100 MA = pkgCache::Version::None;
28166356 101 else if (MultiArch == "same") {
ca238ede 102 if (ArchitectureAll() == true)
25396fb0 103 {
e33dbfe5
DK
104 if (showErrors == true)
105 _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same",
106 Section.FindS("Package").c_str());
107 MA = pkgCache::Version::None;
25396fb0 108 }
28166356 109 else
e33dbfe5 110 MA = pkgCache::Version::Same;
28166356
DK
111 }
112 else if (MultiArch == "foreign")
e33dbfe5 113 MA = pkgCache::Version::Foreign;
28166356 114 else if (MultiArch == "allowed")
e33dbfe5 115 MA = pkgCache::Version::Allowed;
28166356
DK
116 else
117 {
e33dbfe5
DK
118 if (showErrors == true)
119 _error->Warning("Unknown Multi-Arch type '%s' for package '%s'",
120 MultiArch.c_str(), Section.FindS("Package").c_str());
121 MA = pkgCache::Version::None;
25396fb0
DK
122 }
123
ca238ede 124 if (ArchitectureAll() == true)
e33dbfe5 125 MA |= pkgCache::Version::All;
ca238ede 126
e33dbfe5
DK
127 return MA;
128}
129 /*}}}*/
130// ListParser::NewVersion - Fill in the version structure /*{{{*/
131// ---------------------------------------------------------------------
132/* */
133bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
134{
78a5476f
DK
135 const char *Start;
136 const char *Stop;
137
e33dbfe5 138 // Parse the section
78a5476f
DK
139 if (Section.Find("Section",Start,Stop) == true)
140 {
141 map_stringitem_t const idx = StoreString(pkgCacheGenerator::SECTION, Start, Stop - Start);
142 Ver->Section = idx;
143 }
a221efc3
DK
144 // Parse the source package name
145 pkgCache::GrpIterator const G = Ver.ParentPkg().Group();
146 Ver->SourcePkgName = G->Name;
147 Ver->SourceVerStr = Ver->VerStr;
148 if (Section.Find("Source",Start,Stop) == true)
149 {
150 const char * const Space = (const char * const) memchr(Start, ' ', Stop - Start);
151 pkgCache::VerIterator V;
152
153 if (Space != NULL)
154 {
155 Stop = Space;
156 const char * const Open = (const char * const) memchr(Space, '(', Stop - Space);
157 if (likely(Open != NULL))
158 {
159 const char * const Close = (const char * const) memchr(Open, ')', Stop - Open);
160 if (likely(Close != NULL))
161 {
162 std::string const version(Open + 1, (Close - Open) - 1);
163 if (version != Ver.VerStr())
164 {
30b45652 165 map_stringitem_t const idx = StoreString(pkgCacheGenerator::VERSIONNUMBER, version);
a221efc3
DK
166 Ver->SourceVerStr = idx;
167 }
168 }
169 }
170 }
171
172 std::string const pkgname(Start, Stop - Start);
173 if (pkgname != G.Name())
174 {
175 for (pkgCache::PkgIterator P = G.PackageList(); P.end() == false; P = G.NextPkg(P))
176 {
177 for (V = P.VersionList(); V.end() == false; ++V)
178 {
179 if (pkgname == V.SourcePkgName())
180 {
181 Ver->SourcePkgName = V->SourcePkgName;
182 break;
183 }
184 }
185 if (V.end() == false)
186 break;
187 }
188 if (V.end() == true)
189 {
190 map_stringitem_t const idx = StoreString(pkgCacheGenerator::PKGNAME, pkgname);
191 Ver->SourcePkgName = idx;
192 }
193 }
194 }
78a5476f 195
e33dbfe5 196 Ver->MultiArch = ParseMultiArch(true);
0149949b 197 // Archive Size
e2c66de5 198 Ver->Size = Section.FindULL("Size");
0149949b 199 // Unpacked Size (in K)
e2c66de5 200 Ver->InstalledSize = Section.FindULL("Installed-Size");
0149949b
AL
201 Ver->InstalledSize *= 1024;
202
203 // Priority
0149949b 204 if (Section.Find("Priority",Start,Stop) == true)
78a5476f 205 {
b2e465d6 206 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
421c8d10 207 Ver->Priority = pkgCache::State::Extra;
0149949b 208 }
dcb79bae 209
6c139d6e 210 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
dcb79bae 211 return false;
8efa2a3b 212 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
dcb79bae 213 return false;
6c139d6e 214 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
dcb79bae 215 return false;
6c139d6e 216 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
dcb79bae 217 return false;
6c139d6e 218 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
dcb79bae 219 return false;
308c7d30
IJ
220 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
221 return false;
f55ece0e 222 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
dcb79bae 223 return false;
f8ae7e8b 224 if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
225 return false;
dcb79bae 226
b2e465d6
AL
227 // Obsolete.
228 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
229 return false;
230
dcb79bae
AL
231 if (ParseProvides(Ver) == false)
232 return false;
0149949b 233
f55a958f
AL
234 return true;
235}
236 /*}}}*/
a52f938b
OS
237// ListParser::Description - Return the description string /*{{{*/
238// ---------------------------------------------------------------------
239/* This is to return the string describing the package in debian
240 form. If this returns the blank string then the entry is assumed to
241 only describe package properties */
ffe3c68e 242string debListParser::Description(std::string const &lang)
a52f938b 243{
45df0ad2 244 if (lang.empty())
a52f938b
OS
245 return Section.FindS("Description");
246 else
45df0ad2 247 return Section.FindS(string("Description-").append(lang).c_str());
a52f938b 248}
ffe3c68e
DK
249 /*}}}*/
250// ListParser::AvailableDescriptionLanguages /*{{{*/
251std::vector<std::string> debListParser::AvailableDescriptionLanguages()
a52f938b 252{
ffe3c68e
DK
253 std::vector<std::string> const understood = APT::Configuration::getLanguages();
254 std::vector<std::string> avail;
255 if (Section.Exists("Description") == true)
256 avail.push_back("");
257 for (std::vector<std::string>::const_iterator lang = understood.begin(); lang != understood.end(); ++lang)
258 {
259 std::string const tagname = "Description-" + *lang;
260 if (Section.Exists(tagname.c_str()) == true)
261 avail.push_back(*lang);
262 }
263 return avail;
a52f938b 264}
ffe3c68e
DK
265 /*}}}*/
266// ListParser::Description_md5 - Return the description_md5 MD5SumValue /*{{{*/
a52f938b 267// ---------------------------------------------------------------------
770c32ec
MV
268/* This is to return the md5 string to allow the check if it is the right
269 description. If no Description-md5 is found in the section it will be
270 calculated.
271 */
a52f938b
OS
272MD5SumValue debListParser::Description_md5()
273{
fc691496
DK
274 string const value = Section.FindS("Description-md5");
275 if (value.empty() == true)
770c32ec 276 {
ffe3c68e 277 std::string const desc = Description("") + "\n";
99359751
DK
278 if (desc == "\n")
279 return MD5SumValue();
280
a52f938b 281 MD5Summation md5;
99359751 282 md5.Add(desc.c_str());
a52f938b 283 return md5.Result();
fc691496
DK
284 }
285 else if (likely(value.size() == 32))
286 {
287 if (likely(value.find_first_not_of("0123456789abcdefABCDEF") == string::npos))
288 return MD5SumValue(value);
289 _error->Error("Malformed Description-md5 line; includes invalid character '%s'", value.c_str());
290 return MD5SumValue();
291 }
292 _error->Error("Malformed Description-md5 line; doesn't have the required length (32 != %d) '%s'", (int)value.size(), value.c_str());
293 return MD5SumValue();
a52f938b
OS
294}
295 /*}}}*/
f55a958f
AL
296// ListParser::UsePackage - Update a package structure /*{{{*/
297// ---------------------------------------------------------------------
298/* This is called to update the package with any new information
299 that might be found in the section */
32b9a14c
DK
300bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
301 pkgCache::VerIterator &Ver)
f55a958f 302{
5dd4c8b8 303 string const static myArch = _config->Find("APT::Architecture");
e5a91f7e
DK
304 // Possible values are: "all", "native", "installed" and "none"
305 // The "installed" mode is handled by ParseStatus(), See #544481 and friends.
306 string const static essential = _config->Find("pkgCacheGen::Essential", "all");
307 if (essential == "all" ||
308 (essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()))
5dd4c8b8
DK
309 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
310 return false;
138d4b3d 311 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
f55a958f 312 return false;
138d4b3d
AL
313
314 if (strcmp(Pkg.Name(),"apt") == 0)
a552f37e
DK
315 {
316 if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) ||
317 essential == "all")
318 Pkg->Flags |= pkgCache::Flag::Essential | pkgCache::Flag::Important;
319 else
320 Pkg->Flags |= pkgCache::Flag::Important;
321 }
322
f55a958f
AL
323 if (ParseStatus(Pkg,Ver) == false)
324 return false;
325 return true;
326}
327 /*}}}*/
204fbdcc
AL
328// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
329// ---------------------------------------------------------------------
330/* */
331unsigned short debListParser::VersionHash()
332{
333 const char *Sections[] ={"Installed-Size",
334 "Depends",
335 "Pre-Depends",
f78439bf
AL
336// "Suggests",
337// "Recommends",
204fbdcc 338 "Conflicts",
308c7d30 339 "Breaks",
204fbdcc
AL
340 "Replaces",0};
341 unsigned long Result = INIT_FCS;
418a471f 342 char S[1024];
d9682cf8 343 for (const char * const *I = Sections; *I != 0; ++I)
204fbdcc
AL
344 {
345 const char *Start;
346 const char *End;
347 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
348 continue;
349
350 /* Strip out any spaces from the text, this undoes dpkgs reformatting
421c8d10
AL
351 of certain fields. dpkg also has the rather interesting notion of
352 reformatting depends operators < -> <= */
470a5c38 353 char *J = S;
d9682cf8 354 for (; Start != End; ++Start)
421c8d10 355 {
d9682cf8
DK
356 if (isspace(*Start) != 0)
357 continue;
358 *J++ = tolower_ascii(*Start);
359
360 if ((*Start == '<' || *Start == '>') && Start[1] != *Start && Start[1] != '=')
470a5c38 361 *J++ = '=';
421c8d10 362 }
418a471f 363
470a5c38 364 Result = AddCRC16(Result,S,J - S);
204fbdcc
AL
365 }
366
367 return Result;
368}
369 /*}}}*/
dcb79bae 370// ListParser::ParseStatus - Parse the status field /*{{{*/
f55a958f
AL
371// ---------------------------------------------------------------------
372/* Status lines are of the form,
373 Status: want flag status
374 want = unknown, install, hold, deinstall, purge
9227645d
GJ
375 flag = ok, reinstreq
376 status = not-installed, config-files, half-installed, unpacked,
377 half-configured, triggers-awaited, triggers-pending, installed
f55a958f 378 */
32b9a14c
DK
379bool debListParser::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
cef094c2
DK
794 // If negative is unspecific it needs to apply on all architectures
795 if (MultiArchEnabled == true && found == string::npos &&
306eacf6
DK
796 (Type == pkgCache::Dep::Conflicts ||
797 Type == pkgCache::Dep::DpkgBreaks ||
798 Type == pkgCache::Dep::Replaces))
799 {
dcfa253f
DK
800 for (std::vector<std::string>::const_iterator a = Architectures.begin();
801 a != Architectures.end(); ++a)
306eacf6
DK
802 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
803 return false;
c919ad6e
DK
804 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
805 return false;
306eacf6 806 }
0f485ee5
TG
807 else if (MultiArchEnabled == true && found != string::npos &&
808 strcmp(Package.c_str() + found, ":any") != 0)
809 {
810 string Arch = Package.substr(found+1, string::npos);
811 Package = Package.substr(0, found);
812 // Such dependencies are not supposed to be accepted …
813 // … but this is probably the best thing to do.
814 if (Arch == "native")
815 Arch = _config->Find("APT::Architecture");
816 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
817 return false;
818 }
c919ad6e
DK
819 else
820 {
821 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
822 return false;
823 if ((Type == pkgCache::Dep::Conflicts ||
824 Type == pkgCache::Dep::DpkgBreaks ||
825 Type == pkgCache::Dep::Replaces) &&
826 NewDepends(Ver, Package,
827 (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"),
828 Version,Op,Type) == false)
829 return false;
830 }
8efa2a3b
AL
831 if (Start == Stop)
832 break;
dcb79bae
AL
833 }
834 return true;
835}
836 /*}}}*/
837// ListParser::ParseProvides - Parse the provides list /*{{{*/
838// ---------------------------------------------------------------------
839/* */
32b9a14c 840bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae
AL
841{
842 const char *Start;
843 const char *Stop;
67e0766f 844 if (Section.Find("Provides",Start,Stop) == true)
dcb79bae 845 {
67e0766f
DK
846 string Package;
847 string Version;
28166356 848 string const Arch = Ver.Arch();
67e0766f
DK
849 unsigned int Op;
850
851 while (1)
852 {
853 Start = ParseDepends(Start,Stop,Package,Version,Op);
854 if (Start == 0)
855 return _error->Error("Problem parsing Provides line");
40faab46
DK
856 if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) {
857 _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str());
04340db3
DK
858 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
859 if (NewProvidesAllArch(Ver, Package, Version) == false)
860 return false;
67e0766f
DK
861 } else {
862 if (NewProvides(Ver, Package, Arch, Version) == false)
863 return false;
864 }
865
866 if (Start == Stop)
867 break;
b63380b0 868 }
67e0766f 869 }
dcb79bae 870
b4140ecf 871 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
4d174dc8
DK
872 {
873 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
60dcec6d 874 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
dcb79bae 875 }
894d672e 876 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
60dcec6d 877 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
dcb79bae 878
60dcec6d
DK
879 return true;
880}
881 /*}}}*/
882// ListParser::NewProvides - add provides for all architectures /*{{{*/
883bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
884 string const &Version) {
dcfa253f
DK
885 for (std::vector<string>::const_iterator a = Architectures.begin();
886 a != Architectures.end(); ++a)
67e0766f
DK
887 {
888 if (NewProvides(Ver, Package, *a, Version) == false)
889 return false;
dcb79bae 890 }
f55a958f
AL
891 return true;
892}
893 /*}}}*/
894// ListParser::GrabWord - Matches a word and returns /*{{{*/
895// ---------------------------------------------------------------------
896/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 897bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 898{
b2e465d6 899 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
900 {
901 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
902 {
903 Out = List[C].Val;
904 return true;
905 }
906 }
907 return false;
908}
909 /*}}}*/
910// ListParser::Step - Move to the next section in the file /*{{{*/
911// ---------------------------------------------------------------------
1e3f4083 912/* This has to be careful to only process the correct architecture */
f55a958f
AL
913bool debListParser::Step()
914{
dcb79bae 915 iOffset = Tags.Offset();
0149949b 916 while (Tags.Step(Section) == true)
ddc1d8d0
AL
917 {
918 /* See if this is the correct Architecture, if it isn't then we
919 drop the whole section. A missing arch tag only happens (in theory)
920 inside the Status file, so that is a positive return */
5dd4c8b8 921 string const Architecture = Section.FindS("Architecture");
9c14e3d6 922
dd13742e 923 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
5dd4c8b8
DK
924 {
925 if (APT::Configuration::checkArchitecture(Architecture) == true)
926 return true;
c919ad6e
DK
927 /* parse version stanzas without an architecture only in the status file
928 (and as misfortune bycatch flat-archives) */
929 if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true)
930 return true;
5dd4c8b8
DK
931 }
932 else
933 {
934 if (Architecture == Arch)
935 return true;
0149949b 936
28166356 937 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
5dd4c8b8
DK
938 return true;
939 }
dcb79bae
AL
940
941 iOffset = Tags.Offset();
0149949b
AL
942 }
943 return false;
f55a958f
AL
944}
945 /*}}}*/
b0b4efb9
AL
946// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
947// ---------------------------------------------------------------------
948/* */
32b9a14c 949bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
f2152f03 950 FileFd &File, string component)
b0b4efb9 951{
f2152f03
MV
952 // apt-secure does no longer download individual (per-section) Release
953 // file. to provide Component pinning we use the section name now
78a5476f 954 map_stringitem_t const storage = StoreString(pkgCacheGenerator::MIXED, component);
2b803d40 955 FileI->Component = storage;
f2152f03 956
233d79a5 957 pkgTagFile TagFile(&File, File.Size());
e9737c7f
DK
958 pkgTagSection Section;
959 if (_error->PendingError() == true || TagFile.Step(Section) == false)
fe0f7911
DK
960 return false;
961
e9737c7f 962 std::string data;
78a5476f 963 #define APT_INRELEASE(TYPE, TAG, STORE) \
e9737c7f
DK
964 data = Section.FindS(TAG); \
965 if (data.empty() == false) \
966 { \
78a5476f 967 map_stringitem_t const storage = StoreString(pkgCacheGenerator::TYPE, data); \
e9737c7f 968 STORE = storage; \
fe0f7911 969 }
78a5476f
DK
970 APT_INRELEASE(MIXED, "Suite", FileI->Archive)
971 APT_INRELEASE(MIXED, "Component", FileI->Component)
30b45652 972 APT_INRELEASE(VERSIONNUMBER, "Version", FileI->Version)
78a5476f
DK
973 APT_INRELEASE(MIXED, "Origin", FileI->Origin)
974 APT_INRELEASE(MIXED, "Codename", FileI->Codename)
975 APT_INRELEASE(MIXED, "Label", FileI->Label)
e9737c7f
DK
976 #undef APT_INRELEASE
977 Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic);
978 Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades);
f2152f03 979
b0b4efb9
AL
980 return !_error->PendingError();
981}
982 /*}}}*/
b2e465d6
AL
983// ListParser::GetPrio - Convert the priority from a string /*{{{*/
984// ---------------------------------------------------------------------
985/* */
986unsigned char debListParser::GetPrio(string Str)
987{
988 unsigned char Out;
989 if (GrabWord(Str,PrioList,Out) == false)
990 Out = pkgCache::State::Extra;
991
992 return Out;
993}
994 /*}}}*/
68134bda
DK
995#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
996bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/
997 pkgCache::VerIterator const &Ver)
998{
999 if (pkgCacheGenerator::ListParser::SameVersion(Hash, Ver) == false)
1000 return false;
1001 // status file has no (Download)Size, but all others are fair game
1002 // status file is parsed last, so the first version we encounter is
1003 // probably also the version we have downloaded
1004 unsigned long long const Size = Section.FindULL("Size");
1005 if (Size != 0 && Size != Ver->Size)
1006 return false;
1007 // available everywhere, but easier to check here than to include in VersionHash
1008 unsigned char MultiArch = ParseMultiArch(false);
1009 if (MultiArch != Ver->MultiArch)
1010 return false;
1011 // for all practical proposes (we can check): same version
1012 return true;
1013}
1014 /*}}}*/
1015#endif
0d29b9d4
MV
1016
1017
1018debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile)
1019 : debListParser(File, ""), DebFile(DebFile)
1020{
1021}
1022
1023bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg,
1024 pkgCache::VerIterator &Ver)
1025{
1026 bool res = debListParser::UsePackage(Pkg, Ver);
1027 // we use the full file path as a provides so that the file is found
1028 // by its name
1029 if(NewProvidesAllArch(Ver, DebFile, Ver.VerStr()) == false)
1030 return false;
1031 return res;
1032}
1033
862bafea 1034debListParser::~debListParser() {}