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