* apt-pkg/pkgcache.h:
[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
199 std::vector<string> const lang = APT::Configuration::getLanguages();
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 */
459static string CompleteArch(std::string& 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
498 if (StripMultiArch == true) {
499 size_t const found = Package.rfind(':');
500 if (found != string::npos)
501 Package = Package.substr(0,found);
502 }
503
dcb79bae
AL
504 // Skip white space to the '('
505 for (;I != Stop && isspace(*I) != 0 ; I++);
506
507 // Parse a version
508 if (I != Stop && *I == '(')
509 {
510 // Skip the '('
511 for (I++; I != Stop && isspace(*I) != 0 ; I++);
512 if (I + 3 >= Stop)
513 return 0;
b2e465d6 514 I = ConvertRelation(I,Op);
dcb79bae
AL
515
516 // Skip whitespace
517 for (;I != Stop && isspace(*I) != 0; I++);
518 Start = I;
519 for (;I != Stop && *I != ')'; I++);
520 if (I == Stop || Start == I)
521 return 0;
522
02f000a9
AL
523 // Skip trailing whitespace
524 const char *End = I;
525 for (; End > Start && isspace(End[-1]); End--);
526
171c75f1 527 Ver.assign(Start,End-Start);
dcb79bae
AL
528 I++;
529 }
530 else
531 {
171c75f1 532 Ver.clear();
6c139d6e 533 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
534 }
535
536 // Skip whitespace
537 for (;I != Stop && isspace(*I) != 0; I++);
b2e465d6
AL
538
539 if (ParseArchFlags == true)
540 {
541 string arch = _config->Find("APT::Architecture");
3b20aef1 542 string completeArch = CompleteArch(arch);
9e10ad8a 543
b2e465d6
AL
544 // Parse an architecture
545 if (I != Stop && *I == '[')
546 {
547 // malformed
548 I++;
549 if (I == Stop)
550 return 0;
551
552 const char *End = I;
553 bool Found = false;
9e10ad8a 554 bool NegArch = false;
b2e465d6
AL
555 while (I != Stop)
556 {
557 // look for whitespace or ending ']'
558 while (End != Stop && !isspace(*End) && *End != ']')
559 End++;
560
561 if (End == Stop)
562 return 0;
9e10ad8a
AL
563
564 if (*I == '!')
565 {
566 NegArch = true;
567 I++;
568 }
569
d4af23c2 570 if (stringcmp(arch,I,End) == 0) {
b2e465d6 571 Found = true;
d4af23c2
JAK
572 } else {
573 std::string wildcard = SubstVar(string(I, End), "any", "*");
3b20aef1 574 if (fnmatch(wildcard.c_str(), completeArch.c_str(), 0) == 0)
d4af23c2
JAK
575 Found = true;
576 }
b2e465d6
AL
577
578 if (*End++ == ']') {
579 I = End;
580 break;
581 }
582
583 I = End;
584 for (;I != Stop && isspace(*I) != 0; I++);
585 }
9e10ad8a
AL
586
587 if (NegArch)
588 Found = !Found;
b2e465d6 589
9e10ad8a 590 if (Found == false)
b2e465d6
AL
591 Package = ""; /* not for this arch */
592 }
593
594 // Skip whitespace
595 for (;I != Stop && isspace(*I) != 0; I++);
596 }
597
dcb79bae 598 if (I != Stop && *I == '|')
6c139d6e 599 Op |= pkgCache::Dep::Or;
dcb79bae
AL
600
601 if (I == Stop || *I == ',' || *I == '|')
602 {
603 if (I != Stop)
604 for (I++; I != Stop && isspace(*I) != 0; I++);
605 return I;
606 }
607
608 return 0;
609}
610 /*}}}*/
611// ListParser::ParseDepends - Parse a dependency list /*{{{*/
612// ---------------------------------------------------------------------
613/* This is the higher level depends parser. It takes a tag and generates
614 a complete depends tree for the given version. */
32b9a14c 615bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
dcb79bae
AL
616 const char *Tag,unsigned int Type)
617{
618 const char *Start;
619 const char *Stop;
620 if (Section.Find(Tag,Start,Stop) == false)
621 return true;
306eacf6 622
dcb79bae 623 string Package;
28166356 624 string const pkgArch = Ver.Arch();
dcb79bae
AL
625 string Version;
626 unsigned int Op;
627
8efa2a3b 628 while (1)
dcb79bae 629 {
60dcec6d 630 Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled);
dcb79bae
AL
631 if (Start == 0)
632 return _error->Error("Problem parsing dependency %s",Tag);
306eacf6 633
dcfa253f 634 if (MultiArchEnabled == true &&
306eacf6
DK
635 (Type == pkgCache::Dep::Conflicts ||
636 Type == pkgCache::Dep::DpkgBreaks ||
637 Type == pkgCache::Dep::Replaces))
638 {
dcfa253f
DK
639 for (std::vector<std::string>::const_iterator a = Architectures.begin();
640 a != Architectures.end(); ++a)
306eacf6
DK
641 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
642 return false;
643 }
644 else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
dcb79bae 645 return false;
8efa2a3b
AL
646 if (Start == Stop)
647 break;
dcb79bae
AL
648 }
649 return true;
650}
651 /*}}}*/
652// ListParser::ParseProvides - Parse the provides list /*{{{*/
653// ---------------------------------------------------------------------
654/* */
32b9a14c 655bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae
AL
656{
657 const char *Start;
658 const char *Stop;
67e0766f 659 if (Section.Find("Provides",Start,Stop) == true)
dcb79bae 660 {
67e0766f
DK
661 string Package;
662 string Version;
28166356 663 string const Arch = Ver.Arch();
67e0766f
DK
664 unsigned int Op;
665
666 while (1)
667 {
668 Start = ParseDepends(Start,Stop,Package,Version,Op);
669 if (Start == 0)
670 return _error->Error("Problem parsing Provides line");
671 if (Op != pkgCache::Dep::NoOp) {
672 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
673 } else {
674 if (NewProvides(Ver, Package, Arch, Version) == false)
675 return false;
676 }
677
678 if (Start == Stop)
679 break;
b63380b0 680 }
67e0766f 681 }
dcb79bae 682
60dcec6d
DK
683 if (MultiArchEnabled == false)
684 return true;
894d672e 685 else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
4d174dc8
DK
686 {
687 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
60dcec6d 688 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
dcb79bae 689 }
894d672e 690 else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
60dcec6d 691 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
dcb79bae 692
60dcec6d
DK
693 return true;
694}
695 /*}}}*/
696// ListParser::NewProvides - add provides for all architectures /*{{{*/
697bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
698 string const &Version) {
dcfa253f
DK
699 for (std::vector<string>::const_iterator a = Architectures.begin();
700 a != Architectures.end(); ++a)
67e0766f
DK
701 {
702 if (NewProvides(Ver, Package, *a, Version) == false)
703 return false;
dcb79bae 704 }
f55a958f
AL
705 return true;
706}
707 /*}}}*/
708// ListParser::GrabWord - Matches a word and returns /*{{{*/
709// ---------------------------------------------------------------------
710/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 711bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 712{
b2e465d6 713 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
714 {
715 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
716 {
717 Out = List[C].Val;
718 return true;
719 }
720 }
721 return false;
722}
723 /*}}}*/
724// ListParser::Step - Move to the next section in the file /*{{{*/
725// ---------------------------------------------------------------------
0149949b 726/* This has to be carefull to only process the correct architecture */
f55a958f
AL
727bool debListParser::Step()
728{
dcb79bae 729 iOffset = Tags.Offset();
0149949b 730 while (Tags.Step(Section) == true)
ddc1d8d0
AL
731 {
732 /* See if this is the correct Architecture, if it isn't then we
733 drop the whole section. A missing arch tag only happens (in theory)
734 inside the Status file, so that is a positive return */
5dd4c8b8
DK
735 string const Architecture = Section.FindS("Architecture");
736 if (Architecture.empty() == true)
0149949b 737 return true;
9c14e3d6 738
dd13742e 739 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
5dd4c8b8
DK
740 {
741 if (APT::Configuration::checkArchitecture(Architecture) == true)
742 return true;
743 }
744 else
745 {
746 if (Architecture == Arch)
747 return true;
0149949b 748
28166356 749 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
5dd4c8b8
DK
750 return true;
751 }
dcb79bae
AL
752
753 iOffset = Tags.Offset();
0149949b
AL
754 }
755 return false;
f55a958f
AL
756}
757 /*}}}*/
b0b4efb9
AL
758// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
759// ---------------------------------------------------------------------
760/* */
32b9a14c 761bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
f2152f03 762 FileFd &File, string component)
b0b4efb9 763{
f2152f03
MV
764 // apt-secure does no longer download individual (per-section) Release
765 // file. to provide Component pinning we use the section name now
766 FileI->Component = WriteUniqString(component);
767
fe0f7911
DK
768 FILE* release = fdopen(dup(File.Fd()), "r");
769 if (release == NULL)
770 return false;
771
772 char buffer[101];
773 bool gpgClose = false;
774 while (fgets(buffer, sizeof(buffer), release) != NULL)
775 {
776 size_t len = 0;
777
778 // Skip empty lines
779 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len);
780 if (buffer[len] == '\0')
781 continue;
782
783 // only evalute the first GPG section
784 if (strncmp("-----", buffer, 5) == 0)
785 {
786 if (gpgClose == true)
787 break;
788 gpgClose = true;
789 continue;
790 }
791
792 // seperate the tag from the data
793 for (; buffer[len] != ':' && buffer[len] != '\0'; ++len);
794 if (buffer[len] == '\0')
795 continue;
796 char* dataStart = buffer + len;
797 for (++dataStart; *dataStart == ' '; ++dataStart);
798 char* dataEnd = dataStart;
799 for (++dataEnd; *dataEnd != '\0'; ++dataEnd);
800
801 // which datastorage need to be updated
802 map_ptrloc* writeTo = NULL;
803 if (buffer[0] == ' ')
804 ;
805 #define APT_PARSER_WRITETO(X, Y) else if (strncmp(Y, buffer, len) == 0) writeTo = &X;
806 APT_PARSER_WRITETO(FileI->Archive, "Suite")
807 APT_PARSER_WRITETO(FileI->Component, "Component")
808 APT_PARSER_WRITETO(FileI->Version, "Version")
809 APT_PARSER_WRITETO(FileI->Origin, "Origin")
810 APT_PARSER_WRITETO(FileI->Codename, "Codename")
811 APT_PARSER_WRITETO(FileI->Label, "Label")
812 #undef APT_PARSER_WRITETO
813 #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \
814 pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, dataEnd-1);
815 APT_PARSER_FLAGIT(NotAutomatic)
816 APT_PARSER_FLAGIT(ButAutomaticUpgrades)
817 #undef APT_PARSER_FLAGIT
818
819 // load all data from the line and save it
820 string data;
821 if (writeTo != NULL)
822 data.append(dataStart, dataEnd);
823 if (sizeof(buffer) - 1 == (dataEnd - buffer))
824 {
825 while (fgets(buffer, sizeof(buffer), release) != NULL)
826 {
827 if (writeTo != NULL)
828 data.append(buffer);
829 if (strlen(buffer) != sizeof(buffer) - 1)
830 break;
831 }
832 }
833 if (writeTo != NULL)
834 {
835 // remove spaces and stuff from the end of the data line
836 for (std::string::reverse_iterator s = data.rbegin();
837 s != data.rend(); ++s)
838 {
839 if (*s != '\r' && *s != '\n' && *s != ' ')
840 break;
841 *s = '\0';
842 }
843 *writeTo = WriteUniqString(data);
844 }
845 }
846 fclose(release);
f2152f03 847
b0b4efb9
AL
848 return !_error->PendingError();
849}
850 /*}}}*/
b2e465d6
AL
851// ListParser::GetPrio - Convert the priority from a string /*{{{*/
852// ---------------------------------------------------------------------
853/* */
854unsigned char debListParser::GetPrio(string Str)
855{
856 unsigned char Out;
857 if (GrabWord(Str,PrioList,Out) == false)
858 Out = pkgCache::State::Extra;
859
860 return Out;
861}
862 /*}}}*/