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