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