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