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