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