convert a few for-loop char finds to proper strchr and memchr
[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
85c26e8c 204 std::vector<string> const lang = APT::Configuration::getLanguages(true);
45df0ad2 205 for (std::vector<string>::const_iterator l = lang.begin();
f7f0d6c7 206 l != lang.end(); ++l)
45df0ad2
DK
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 < -> <= */
470a5c38 287 char *J = S;
204fbdcc 288 for (; Start != End; Start++)
421c8d10 289 {
204fbdcc 290 if (isspace(*Start) == 0)
470a5c38 291 *J++ = tolower_ascii(*Start);
421c8d10 292 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
470a5c38 293 *J++ = '=';
421c8d10 294 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
470a5c38 295 *J++ = '=';
421c8d10 296 }
418a471f 297
470a5c38 298 Result = AddCRC16(Result,S,J - S);
204fbdcc
AL
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 */
550f6493 464static string CompleteArch(std::string const &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 != ')' &&
90cf90b2 490 *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
dcb79bae
AL
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
550f6493 503 string const arch = _config->Find("APT::Architecture");
41c81fd8
DK
504 if (StripMultiArch == true) {
505 size_t const found = Package.rfind(':');
550f6493
DK
506 if (found != string::npos &&
507 (strcmp(Package.c_str() + found, ":any") == 0 ||
508 strcmp(Package.c_str() + found, ":native") == 0 ||
509 strcmp(Package.c_str() + found + 1, arch.c_str()) == 0))
41c81fd8
DK
510 Package = Package.substr(0,found);
511 }
512
dcb79bae
AL
513 // Skip white space to the '('
514 for (;I != Stop && isspace(*I) != 0 ; I++);
515
516 // Parse a version
517 if (I != Stop && *I == '(')
518 {
519 // Skip the '('
520 for (I++; I != Stop && isspace(*I) != 0 ; I++);
521 if (I + 3 >= Stop)
522 return 0;
b2e465d6 523 I = ConvertRelation(I,Op);
dcb79bae
AL
524
525 // Skip whitespace
526 for (;I != Stop && isspace(*I) != 0; I++);
527 Start = I;
404528bd
DK
528 I = (const char*) memchr(I, ')', Stop - I);
529 if (I == NULL || Start == I)
530 return 0;
dcb79bae 531
02f000a9
AL
532 // Skip trailing whitespace
533 const char *End = I;
534 for (; End > Start && isspace(End[-1]); End--);
535
171c75f1 536 Ver.assign(Start,End-Start);
dcb79bae
AL
537 I++;
538 }
539 else
540 {
171c75f1 541 Ver.clear();
6c139d6e 542 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
543 }
544
545 // Skip whitespace
546 for (;I != Stop && isspace(*I) != 0; I++);
b2e465d6
AL
547
548 if (ParseArchFlags == true)
549 {
3b20aef1 550 string completeArch = CompleteArch(arch);
9e10ad8a 551
b2e465d6
AL
552 // Parse an architecture
553 if (I != Stop && *I == '[')
554 {
555 // malformed
556 I++;
557 if (I == Stop)
558 return 0;
559
560 const char *End = I;
561 bool Found = false;
9e10ad8a 562 bool NegArch = false;
b2e465d6
AL
563 while (I != Stop)
564 {
565 // look for whitespace or ending ']'
566 while (End != Stop && !isspace(*End) && *End != ']')
567 End++;
568
569 if (End == Stop)
570 return 0;
9e10ad8a
AL
571
572 if (*I == '!')
573 {
574 NegArch = true;
575 I++;
576 }
577
d4af23c2 578 if (stringcmp(arch,I,End) == 0) {
b2e465d6 579 Found = true;
d4af23c2
JAK
580 } else {
581 std::string wildcard = SubstVar(string(I, End), "any", "*");
3b20aef1 582 if (fnmatch(wildcard.c_str(), completeArch.c_str(), 0) == 0)
d4af23c2
JAK
583 Found = true;
584 }
b2e465d6
AL
585
586 if (*End++ == ']') {
587 I = End;
588 break;
589 }
590
591 I = End;
592 for (;I != Stop && isspace(*I) != 0; I++);
593 }
9e10ad8a
AL
594
595 if (NegArch)
596 Found = !Found;
b2e465d6 597
9e10ad8a 598 if (Found == false)
b2e465d6
AL
599 Package = ""; /* not for this arch */
600 }
601
602 // Skip whitespace
603 for (;I != Stop && isspace(*I) != 0; I++);
604 }
605
dcb79bae 606 if (I != Stop && *I == '|')
6c139d6e 607 Op |= pkgCache::Dep::Or;
dcb79bae
AL
608
609 if (I == Stop || *I == ',' || *I == '|')
610 {
611 if (I != Stop)
612 for (I++; I != Stop && isspace(*I) != 0; I++);
613 return I;
614 }
615
616 return 0;
617}
618 /*}}}*/
619// ListParser::ParseDepends - Parse a dependency list /*{{{*/
620// ---------------------------------------------------------------------
621/* This is the higher level depends parser. It takes a tag and generates
622 a complete depends tree for the given version. */
32b9a14c 623bool debListParser::ParseDepends(pkgCache::VerIterator &Ver,
dcb79bae
AL
624 const char *Tag,unsigned int Type)
625{
626 const char *Start;
627 const char *Stop;
628 if (Section.Find(Tag,Start,Stop) == false)
629 return true;
306eacf6 630
dcb79bae 631 string Package;
28166356 632 string const pkgArch = Ver.Arch();
dcb79bae
AL
633 string Version;
634 unsigned int Op;
635
8efa2a3b 636 while (1)
dcb79bae 637 {
60dcec6d 638 Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled);
dcb79bae
AL
639 if (Start == 0)
640 return _error->Error("Problem parsing dependency %s",Tag);
306eacf6 641
dcfa253f 642 if (MultiArchEnabled == true &&
306eacf6
DK
643 (Type == pkgCache::Dep::Conflicts ||
644 Type == pkgCache::Dep::DpkgBreaks ||
645 Type == pkgCache::Dep::Replaces))
646 {
dcfa253f
DK
647 for (std::vector<std::string>::const_iterator a = Architectures.begin();
648 a != Architectures.end(); ++a)
306eacf6
DK
649 if (NewDepends(Ver,Package,*a,Version,Op,Type) == false)
650 return false;
651 }
652 else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
dcb79bae 653 return false;
8efa2a3b
AL
654 if (Start == Stop)
655 break;
dcb79bae
AL
656 }
657 return true;
658}
659 /*}}}*/
660// ListParser::ParseProvides - Parse the provides list /*{{{*/
661// ---------------------------------------------------------------------
662/* */
32b9a14c 663bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
dcb79bae
AL
664{
665 const char *Start;
666 const char *Stop;
67e0766f 667 if (Section.Find("Provides",Start,Stop) == true)
dcb79bae 668 {
67e0766f
DK
669 string Package;
670 string Version;
28166356 671 string const Arch = Ver.Arch();
67e0766f
DK
672 unsigned int Op;
673
674 while (1)
675 {
676 Start = ParseDepends(Start,Stop,Package,Version,Op);
677 if (Start == 0)
678 return _error->Error("Problem parsing Provides line");
679 if (Op != pkgCache::Dep::NoOp) {
680 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
681 } else {
682 if (NewProvides(Ver, Package, Arch, Version) == false)
683 return false;
684 }
685
686 if (Start == Stop)
687 break;
b63380b0 688 }
67e0766f 689 }
dcb79bae 690
60dcec6d
DK
691 if (MultiArchEnabled == false)
692 return true;
693 else if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
4d174dc8
DK
694 {
695 string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
60dcec6d 696 return NewProvidesAllArch(Ver, Package, Ver.VerStr());
dcb79bae 697 }
60dcec6d
DK
698 else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
699 return NewProvidesAllArch(Ver, Ver.ParentPkg().Name(), Ver.VerStr());
dcb79bae 700
60dcec6d
DK
701 return true;
702}
703 /*}}}*/
704// ListParser::NewProvides - add provides for all architectures /*{{{*/
705bool debListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
706 string const &Version) {
dcfa253f
DK
707 for (std::vector<string>::const_iterator a = Architectures.begin();
708 a != Architectures.end(); ++a)
67e0766f
DK
709 {
710 if (NewProvides(Ver, Package, *a, Version) == false)
711 return false;
dcb79bae 712 }
f55a958f
AL
713 return true;
714}
715 /*}}}*/
716// ListParser::GrabWord - Matches a word and returns /*{{{*/
717// ---------------------------------------------------------------------
718/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 719bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 720{
b2e465d6 721 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
722 {
723 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
724 {
725 Out = List[C].Val;
726 return true;
727 }
728 }
729 return false;
730}
731 /*}}}*/
732// ListParser::Step - Move to the next section in the file /*{{{*/
733// ---------------------------------------------------------------------
0149949b 734/* This has to be carefull to only process the correct architecture */
f55a958f
AL
735bool debListParser::Step()
736{
dcb79bae 737 iOffset = Tags.Offset();
0149949b 738 while (Tags.Step(Section) == true)
ddc1d8d0
AL
739 {
740 /* See if this is the correct Architecture, if it isn't then we
741 drop the whole section. A missing arch tag only happens (in theory)
742 inside the Status file, so that is a positive return */
5dd4c8b8
DK
743 string const Architecture = Section.FindS("Architecture");
744 if (Architecture.empty() == true)
0149949b 745 return true;
9c14e3d6 746
dd13742e 747 if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false)
5dd4c8b8
DK
748 {
749 if (APT::Configuration::checkArchitecture(Architecture) == true)
750 return true;
751 }
752 else
753 {
754 if (Architecture == Arch)
755 return true;
0149949b 756
28166356 757 if (Architecture == "all" && Arch == _config->Find("APT::Architecture"))
5dd4c8b8
DK
758 return true;
759 }
dcb79bae
AL
760
761 iOffset = Tags.Offset();
0149949b
AL
762 }
763 return false;
f55a958f
AL
764}
765 /*}}}*/
b0b4efb9
AL
766// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
767// ---------------------------------------------------------------------
768/* */
32b9a14c 769bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI,
f2152f03 770 FileFd &File, string component)
b0b4efb9 771{
f2152f03
MV
772 // apt-secure does no longer download individual (per-section) Release
773 // file. to provide Component pinning we use the section name now
774 FileI->Component = WriteUniqString(component);
775
fe0f7911
DK
776 FILE* release = fdopen(dup(File.Fd()), "r");
777 if (release == NULL)
778 return false;
779
780 char buffer[101];
781 bool gpgClose = false;
782 while (fgets(buffer, sizeof(buffer), release) != NULL)
783 {
784 size_t len = 0;
785
786 // Skip empty lines
b433026f
MV
787 for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len)
788 /* nothing */
789 ;
fe0f7911
DK
790 if (buffer[len] == '\0')
791 continue;
792
793 // only evalute the first GPG section
794 if (strncmp("-----", buffer, 5) == 0)
795 {
796 if (gpgClose == true)
797 break;
798 gpgClose = true;
799 continue;
800 }
801
802 // seperate the tag from the data
404528bd
DK
803 const char* dataStart = strchr(buffer + len, ':');
804 if (dataStart == NULL)
fe0f7911 805 continue;
404528bd 806 len = dataStart - buffer;
b433026f
MV
807 for (++dataStart; *dataStart == ' '; ++dataStart)
808 /* nothing */
809 ;
404528bd 810 const char* dataEnd = (const char*)rawmemchr(dataStart, '\0');
ae6ea526 811 // The last char should be a newline, but we can never be sure: #633350
404528bd 812 const 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 /*}}}*/