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