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