]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/deblistparser.cc
handle missing "Description" in apt-cache show
[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. */
dcb79bae
AL
477const char *debListParser::ParseDepends(const char *Start,const char *Stop,
478 string &Package,string &Ver,
41c81fd8
DK
479 unsigned int &Op, bool const &ParseArchFlags,
480 bool const &StripMultiArch)
dcb79bae
AL
481{
482 // Strip off leading space
483 for (;Start != Stop && isspace(*Start) != 0; Start++);
484
485 // Parse off the package name
486 const char *I = Start;
487 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
90cf90b2 488 *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
dcb79bae
AL
489
490 // Malformed, no '('
491 if (I != Stop && *I == ')')
492 return 0;
493
494 if (I == Start)
495 return 0;
496
497 // Stash the package name
498 Package.assign(Start,I - Start);
41c81fd8
DK
499
500 // We don't want to confuse library users which can't handle MultiArch
550f6493 501 string const arch = _config->Find("APT::Architecture");
41c81fd8
DK
502 if (StripMultiArch == true) {
503 size_t const found = Package.rfind(':');
550f6493
DK
504 if (found != string::npos &&
505 (strcmp(Package.c_str() + found, ":any") == 0 ||
506 strcmp(Package.c_str() + found, ":native") == 0 ||
507 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
41c81fd8
DK
508 Package = Package.substr(0,found);
509 }
510
dcb79bae
AL
511 // Skip white space to the '('
512 for (;I != Stop && isspace(*I) != 0 ; I++);
513
514 // Parse a version
515 if (I != Stop && *I == '(')
516 {
517 // Skip the '('
518 for (I++; I != Stop && isspace(*I) != 0 ; I++);
519 if (I + 3 >= Stop)
520 return 0;
b2e465d6 521 I = ConvertRelation(I,Op);
dcb79bae
AL
522
523 // Skip whitespace
524 for (;I != Stop && isspace(*I) != 0; I++);
525 Start = I;
404528bd
DK
526 I = (const char*) memchr(I, ')', Stop - I);
527 if (I == NULL || Start == I)
528 return 0;
dcb79bae 529
02f000a9
AL
530 // Skip trailing whitespace
531 const char *End = I;
532 for (; End > Start && isspace(End[-1]); End--);
533
171c75f1 534 Ver.assign(Start,End-Start);
dcb79bae
AL
535 I++;
536 }
537 else
538 {
171c75f1 539 Ver.clear();
6c139d6e 540 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
541 }
542
543 // Skip whitespace
544 for (;I != Stop && isspace(*I) != 0; I++);
b2e465d6
AL
545
546 if (ParseArchFlags == true)
547 {
424ff669 548 APT::CacheFilter::PackageArchitectureMatchesSpecification matchesArch(arch, false);
9e10ad8a 549
b2e465d6
AL
550 // Parse an architecture
551 if (I != Stop && *I == '[')
552 {
cd9694bf 553 ++I;
b2e465d6 554 // malformed
cd9694bf
DK
555 if (unlikely(I == Stop))
556 return 0;
557
558 const char *End = I;
559 bool Found = false;
560 bool NegArch = false;
561 while (I != Stop)
b2e465d6 562 {
cd9694bf
DK
563 // look for whitespace or ending ']'
564 for (;End != Stop && !isspace(*End) && *End != ']'; ++End);
565
566 if (unlikely(End == Stop))
b2e465d6 567 return 0;
9e10ad8a
AL
568
569 if (*I == '!')
cd9694bf 570 {
9e10ad8a 571 NegArch = true;
cd9694bf
DK
572 ++I;
573 }
9e10ad8a 574
424ff669
DK
575 std::string arch(I, End);
576 if (arch.empty() == false && matchesArch(arch.c_str()) == true)
cd9694bf 577 {
424ff669 578 Found = true;
cd9694bf
DK
579 if (I[-1] != '!')
580 NegArch = false;
581 // we found a match, so fast-forward to the end of the wildcards
582 for (; End != Stop && *End != ']'; ++End);
583 }
584
b2e465d6
AL
585 if (*End++ == ']') {
586 I = End;
587 break;
588 }
cd9694bf 589
b2e465d6
AL
590 I = End;
591 for (;I != Stop && isspace(*I) != 0; I++);
cd9694bf 592 }
9e10ad8a 593
cd9694bf 594 if (NegArch == true)
9e10ad8a 595 Found = !Found;
cd9694bf
DK
596
597 if (Found == false)
b2e465d6
AL
598 Package = ""; /* not for this arch */
599 }
cd9694bf 600
b2e465d6
AL
601 // Skip whitespace
602 for (;I != Stop && isspace(*I) != 0; I++);
603 }
604
dcb79bae 605 if (I != Stop && *I == '|')
6c139d6e 606 Op |= pkgCache::Dep::Or;
dcb79bae
AL
607
608 if (I == Stop || *I == ',' || *I == '|')
609 {
610 if (I != Stop)
611 for (I++; I != Stop && isspace(*I) != 0; I++);
612 return I;
613 }
614
615 return 0;
616}
617 /*}}}*/
618// ListParser::ParseDepends - Parse a dependency list /*{{{*/
619// ---------------------------------------------------------------------
620/* This is the higher level depends parser. It takes a tag and generates
621 a complete depends tree for the given version. */
32b9a14c 622bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
dcb79bae
AL
623 const char *Tag,unsigned int Type)
624{
625 const char *Start;
626 const char *Stop;
627 if (Section.Find(Tag,Start,Stop) == false)
628 return true;
306eacf6 629
28166356 630 string const pkgArch = Ver.Arch();
dcb79bae 631
8efa2a3b 632 while (1)
dcb79bae 633 {
0f485ee5
TG
634 string Package;
635 string Version;
636 unsigned int Op;
637
60dcec6d 638 Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled);
dcb79bae
AL
639 if (Start == 0)
640 return _error->Error("Problem parsing dependency %s",Tag);
0f485ee5 641 size_t const found = Package.rfind(':');
306eacf6 642
cef094c2
DK
643 // If negative is unspecific it needs to apply on all architectures
644 if (MultiArchEnabled == true && found == string::npos &&
306eacf6
DK
645 (Type == pkgCache::Dep::Conflicts ||
646 Type == pkgCache::Dep::DpkgBreaks ||
647 Type == pkgCache::Dep::Replaces))
648 {
dcfa253f
DK
649 for (std::vector<std::string>::const_iterator a = Architectures.begin();
650 a != Architectures.end(); ++a)
306eacf6
DK
651 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
652 return false;
c919ad6e
DK
653 if (NewDepends(Ver,Package,"none",Version,Op,Type) == false)
654 return false;
306eacf6 655 }
0f485ee5
TG
656 else if (MultiArchEnabled == true && found != string::npos &&
657 strcmp(Package.c_str() + found, ":any") != 0)
658 {
659 string Arch = Package.substr(found+1, string::npos);
660 Package = Package.substr(0, found);
661 // Such dependencies are not supposed to be accepted …
662 // … but this is probably the best thing to do.
663 if (Arch == "native")
664 Arch = _config->Find("APT::Architecture");
665 if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false)
666 return false;
667 }
c919ad6e
DK
668 else
669 {
670 if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
671 return false;
672 if ((Type == pkgCache::Dep::Conflicts ||
673 Type == pkgCache::Dep::DpkgBreaks ||
674 Type == pkgCache::Dep::Replaces) &&
675 NewDepends(Ver, Package,
676 (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"),
677 Version,Op,Type) == false)
678 return false;
679 }
8efa2a3b
AL
680 if (Start == Stop)
681 break;
dcb79bae
AL
682 }
683 return true;
684}
685 /*}}}*/
686// ListParser::ParseProvides - Parse the provides list /*{{{*/
687// ---------------------------------------------------------------------
688/* */
32b9a14c 689bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae
AL
690{
691 const char *Start;
692 const char *Stop;
67e0766f 693 if (Section.Find("Provides",Start,Stop) == true)
dcb79bae 694 {
67e0766f
DK
695 string Package;
696 string Version;
28166356 697 string const Arch = Ver.Arch();
67e0766f
DK
698 unsigned int Op;
699
700 while (1)
701 {
702 Start = ParseDepends(Start,Stop,Package,Version,Op);
703 if (Start == 0)
704 return _error->Error("Problem parsing Provides line");
705 if (Op != pkgCache::Dep::NoOp) {
706 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
04340db3
DK
707 } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
708 if (NewProvidesAllArch(Ver, Package, Version) == false)
709 return false;
67e0766f
DK
710 } else {
711 if (NewProvides(Ver, Package, Arch, Version) == false)
712 return false;
713 }
714
715 if (Start == Stop)
716 break;
b63380b0 717 }
67e0766f 718 }
dcb79bae 719
60dcec6d
DK
720 if (MultiArchEnabled == false)
721 return true;
894d672e 722 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
4d174dc8
DK
723 {
724 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
60dcec6d 725 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
dcb79bae 726 }
894d672e 727 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
60dcec6d 728 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
dcb79bae 729
60dcec6d
DK
730 return true;
731}
732 /*}}}*/
733// ListParser::NewProvides - add provides for all architectures /*{{{*/
734bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
735 string const &Version) {
dcfa253f
DK
736 for (std::vector<string>::const_iterator a = Architectures.begin();
737 a != Architectures.end(); ++a)
67e0766f
DK
738 {
739 if (NewProvides(Ver, Package, *a, Version) == false)
740 return false;
dcb79bae 741 }
f55a958f
AL
742 return true;
743}
744 /*}}}*/
745// ListParser::GrabWord - Matches a word and returns /*{{{*/
746// ---------------------------------------------------------------------
747/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 748bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 749{
b2e465d6 750 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
751 {
752 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
753 {
754 Out = List[C].Val;
755 return true;
756 }
757 }
758 return false;
759}
760 /*}}}*/
761// ListParser::Step - Move to the next section in the file /*{{{*/
762// ---------------------------------------------------------------------
0149949b 763/* This has to be carefull to only process the correct architecture */
f55a958f
AL
764bool debListParser::Step()
765{
dcb79bae 766 iOffset = Tags.Offset();
0149949b 767 while (Tags.Step(Section) == true)
ddc1d8d0
AL
768 {
769 /* See if this is the correct Architecture, if it isn't then we
770 drop the whole section. A missing arch tag only happens (in theory)
771 inside the Status file, so that is a positive return */
5dd4c8b8 772 string const Architecture = Section.FindS("Architecture");
9c14e3d6 773
dd13742e 774 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
5dd4c8b8
DK
775 {
776 if (APT::Configuration::checkArchitecture(Architecture) == true)
777 return true;
c919ad6e
DK
778 /* parse version stanzas without an architecture only in the status file
779 (and as misfortune bycatch flat-archives) */
780 if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true)
781 return true;
5dd4c8b8
DK
782 }
783 else
784 {
785 if (Architecture == Arch)
786 return true;
0149949b 787
28166356 788 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
5dd4c8b8
DK
789 return true;
790 }
dcb79bae
AL
791
792 iOffset = Tags.Offset();
0149949b
AL
793 }
794 return false;
f55a958f
AL
795}
796 /*}}}*/
b0b4efb9
AL
797// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
798// ---------------------------------------------------------------------
799/* */
32b9a14c 800bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
f2152f03 801 FileFd &File, string component)
b0b4efb9 802{
f2152f03
MV
803 // apt-secure does no longer download individual (per-section) Release
804 // file. to provide Component pinning we use the section name now
2b803d40
DK
805 map_ptrloc const storage = WriteUniqString(component);
806 FileI->Component = storage;
f2152f03 807
233b7808 808 // FIXME: should use FileFd and TagSection
fe0f7911
DK
809 FILE* release = fdopen(dup(File.Fd()), "r");
810 if (release == NULL)
811 return false;
812
813 char buffer[101];
fe0f7911
DK
814 while (fgets(buffer, sizeof(buffer), release) != NULL)
815 {
816 size_t len = 0;
817
818 // Skip empty lines
b433026f
MV
819 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
820 /* nothing */
821 ;
fe0f7911
DK
822 if (buffer[len] == '\0')
823 continue;
824
fe0f7911 825 // seperate the tag from the data
404528bd
DK
826 const char* dataStart = strchr(buffer + len, ':');
827 if (dataStart == NULL)
fe0f7911 828 continue;
404528bd 829 len = dataStart - buffer;
b433026f
MV
830 for (++dataStart; *dataStart == ' '; ++dataStart)
831 /* nothing */
832 ;
404528bd 833 const char* dataEnd = (const char*)rawmemchr(dataStart, '\0');
ae6ea526 834 // The last char should be a newline, but we can never be sure: #633350
404528bd 835 const char* lineEnd = dataEnd;
b433026f
MV
836 for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd)
837 /* nothing */
838 ;
ae6ea526 839 ++lineEnd;
fe0f7911
DK
840
841 // which datastorage need to be updated
a865ed25 842 enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None;
fe0f7911
DK
843 if (buffer[0] == ' ')
844 ;
a865ed25
MV
845 #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X;
846 APT_PARSER_WRITETO(Suite)
847 APT_PARSER_WRITETO(Component)
848 APT_PARSER_WRITETO(Version)
849 APT_PARSER_WRITETO(Origin)
850 APT_PARSER_WRITETO(Codename)
851 APT_PARSER_WRITETO(Label)
fe0f7911
DK
852 #undef APT_PARSER_WRITETO
853 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
ae6ea526 854 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd);
fe0f7911
DK
855 APT_PARSER_FLAGIT(NotAutomatic)
856 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
857 #undef APT_PARSER_FLAGIT
858
859 // load all data from the line and save it
860 string data;
a865ed25 861 if (writeTo != None)
fe0f7911
DK
862 data.append(dataStart, dataEnd);
863 if (sizeof(buffer) - 1 == (dataEnd - buffer))
864 {
865 while (fgets(buffer, sizeof(buffer), release) != NULL)
866 {
a865ed25 867 if (writeTo != None)
fe0f7911
DK
868 data.append(buffer);
869 if (strlen(buffer) != sizeof(buffer) - 1)
870 break;
871 }
872 }
a865ed25 873 if (writeTo != None)
fe0f7911
DK
874 {
875 // remove spaces and stuff from the end of the data line
876 for (std::string::reverse_iterator s = data.rbegin();
877 s != data.rend(); ++s)
878 {
879 if (*s != '\r' && *s != '\n' && *s != ' ')
880 break;
881 *s = '\0';
882 }
2b803d40 883 map_ptrloc const storage = WriteUniqString(data);
a865ed25 884 switch (writeTo) {
2b803d40
DK
885 case Suite: FileI->Archive = storage; break;
886 case Component: FileI->Component = storage; break;
887 case Version: FileI->Version = storage; break;
888 case Origin: FileI->Origin = storage; break;
889 case Codename: FileI->Codename = storage; break;
890 case Label: FileI->Label = storage; break;
a865ed25
MV
891 case None: break;
892 }
fe0f7911
DK
893 }
894 }
895 fclose(release);
f2152f03 896
b0b4efb9
AL
897 return !_error->PendingError();
898}
899 /*}}}*/
b2e465d6
AL
900// ListParser::GetPrio - Convert the priority from a string /*{{{*/
901// ---------------------------------------------------------------------
902/* */
903unsigned char debListParser::GetPrio(string Str)
904{
905 unsigned char Out;
906 if (GrabWord(Str,PrioList,Out) == false)
907 Out = pkgCache::State::Extra;
908
909 return Out;
910}
911 /*}}}*/