]> git.saurik.com Git - apt-legacy.git/blame - apt-pkg/deb/deblistparser.cc.orig
I feel... vindicated?
[apt-legacy.git] / apt-pkg / deb / deblistparser.cc.orig
CommitLineData
acdafb44
JF
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz Exp $
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 /*{{{*/
13#include <apt-pkg/deblistparser.h>
14#include <apt-pkg/error.h>
15#include <apt-pkg/configuration.h>
16#include <apt-pkg/strutl.h>
17#include <apt-pkg/crc-16.h>
18#include <apt-pkg/md5.h>
19
20#include <ctype.h>
21
22#include <system.h>
23 /*}}}*/
24
25static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Important},
26 {"required",pkgCache::State::Required},
27 {"standard",pkgCache::State::Standard},
28 {"optional",pkgCache::State::Optional},
29 {"extra",pkgCache::State::Extra},
30 {}};
31
32// ListParser::debListParser - Constructor /*{{{*/
33// ---------------------------------------------------------------------
34/* */
35debListParser::debListParser(FileFd *File) : Tags(File)
36{
37 Arch = _config->Find("APT::architecture");
38}
39 /*}}}*/
40// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
41// ---------------------------------------------------------------------
42/* */
43unsigned long debListParser::UniqFindTagWrite(const char *Tag)
44{
45 const char *Start;
46 const char *Stop;
47 if (Section.Find(Tag,Start,Stop) == false)
48 return 0;
49 return WriteUniqString(Start,Stop - Start);
50}
51 /*}}}*/
52// ListParser::Package - Return the package name /*{{{*/
53// ---------------------------------------------------------------------
54/* This is to return the name of the package this section describes */
55string debListParser::Package()
56{
57 string Result = Section.FindS("Package");
58 if (Result.empty() == true)
59 _error->Error("Encountered a section with no Package: header");
60 return Result;
61}
62 /*}}}*/
63// ListParser::Version - Return the version string /*{{{*/
64// ---------------------------------------------------------------------
65/* This is to return the string describing the version in debian form,
66 epoch:upstream-release. If this returns the blank string then the
67 entry is assumed to only describe package properties */
68string debListParser::Version()
69{
70 return Section.FindS("Version");
71}
72 /*}}}*/
73// ListParser::NewVersion - Fill in the version structure /*{{{*/
74// ---------------------------------------------------------------------
75/* */
76bool debListParser::NewVersion(pkgCache::VerIterator Ver)
77{
78 Ver->Display = UniqFindTagWrite("Name");
79 if (Ver->Display == 0)
80 Ver->Display = UniqFindTagWrite("Maemo-Display-Name");
81
82 // Parse the section
83 Ver->Section = UniqFindTagWrite("Section");
84 Ver->Arch = UniqFindTagWrite("Architecture");
85
86 // Archive Size
87 Ver->Size = (unsigned)Section.FindI("Size");
88
89 // Unpacked Size (in K)
90 Ver->InstalledSize = (unsigned)Section.FindI("Installed-Size");
91 Ver->InstalledSize *= 1024;
92
93 // Priority
94 const char *Start;
95 const char *Stop;
96 if (Section.Find("Priority",Start,Stop) == true)
97 {
98 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
99 Ver->Priority = pkgCache::State::Extra;
100 }
101
102 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
103 return false;
104 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
105 return false;
106 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
107 return false;
108 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
109 return false;
110 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
111 return false;
112 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
113 return false;
114 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
115 return false;
116
117 // Obsolete.
118 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
119 return false;
120
121 if (ParseProvides(Ver) == false)
122 return false;
123
124 return true;
125}
126 /*}}}*/
127// ListParser::Description - Return the description string /*{{{*/
128// ---------------------------------------------------------------------
129/* This is to return the string describing the package in debian
130 form. If this returns the blank string then the entry is assumed to
131 only describe package properties */
132string debListParser::Description()
133{
134 if (DescriptionLanguage().empty())
135 return Section.FindS("Description");
136 else
137 return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
138}
139 /*}}}*/
140// ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
141// ---------------------------------------------------------------------
142/* This is to return the string describing the language of
143 description. If this returns the blank string then the entry is
144 assumed to describe original description. */
145string debListParser::DescriptionLanguage()
146{
147 return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
148}
149 /*}}}*/
150// ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
151// ---------------------------------------------------------------------
152/* This is to return the md5 string to allow the check if it is the right
153 description. If no Description-md5 is found in the section it will be
154 calculated.
155 */
156MD5SumValue debListParser::Description_md5()
157{
158 string value = Section.FindS("Description-md5");
159
160 if (value.empty())
161 {
162 MD5Summation md5;
163 md5.Add((Description() + "\n").c_str());
164 return md5.Result();
165 } else
166 return MD5SumValue(value);
167}
168 /*}}}*/
169// ListParser::UsePackage - Update a package structure /*{{{*/
170// ---------------------------------------------------------------------
171/* This is called to update the package with any new information
172 that might be found in the section */
173bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
174 pkgCache::VerIterator Ver)
175{
176 if (Pkg->Display == 0)
177 Pkg->Display = UniqFindTagWrite("Name");
178 if (Pkg->Display == 0)
179 Pkg->Display = UniqFindTagWrite("Maemo-Display-Name");
180 if (Pkg->Section == 0)
181 Pkg->Section = UniqFindTagWrite("Section");
182 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
183 return false;
184 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
185 return false;
186
187 if (strcmp(Pkg.Name(),"apt") == 0)
188 Pkg->Flags |= pkgCache::Flag::Important;
189
190 if (ParseStatus(Pkg,Ver) == false)
191 return false;
192 return true;
193}
194 /*}}}*/
195// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
196// ---------------------------------------------------------------------
197/* */
198unsigned short debListParser::VersionHash()
199{
200 const char *Sections[] ={"Installed-Size",
201 "Depends",
202 "Pre-Depends",
203// "Suggests",
204// "Recommends",
205 "Conflicts",
206 "Breaks",
207 "Replaces",0};
208 unsigned long Result = INIT_FCS;
209 char S[1024];
210 for (const char **I = Sections; *I != 0; I++)
211 {
212 const char *Start;
213 const char *End;
214 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
215 continue;
216
217 /* Strip out any spaces from the text, this undoes dpkgs reformatting
218 of certain fields. dpkg also has the rather interesting notion of
219 reformatting depends operators < -> <= */
220 char *I = S;
221 for (; Start != End; Start++)
222 {
223 if (isspace(*Start) == 0)
224 *I++ = tolower(*Start);
225 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
226 *I++ = '=';
227 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
228 *I++ = '=';
229 }
230
231 Result = AddCRC16(Result,S,I - S);
232 }
233
234 return Result;
235}
236 /*}}}*/
237// ListParser::ParseStatus - Parse the status field /*{{{*/
238// ---------------------------------------------------------------------
239/* Status lines are of the form,
240 Status: want flag status
241 want = unknown, install, hold, deinstall, purge
242 flag = ok, reinstreq, hold, hold-reinstreq
243 status = not-installed, unpacked, half-configured,
244 half-installed, config-files, post-inst-failed,
245 removal-failed, installed
246
247 Some of the above are obsolete (I think?) flag = hold-* and
248 status = post-inst-failed, removal-failed at least.
249 */
250bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
251 pkgCache::VerIterator Ver)
252{
253 const char *Start;
254 const char *Stop;
255 if (Section.Find("Status",Start,Stop) == false)
256 return true;
257
258 // Isolate the first word
259 const char *I = Start;
260 for(; I < Stop && *I != ' '; I++);
261 if (I >= Stop || *I != ' ')
262 return _error->Error("Malformed Status line");
263
264 // Process the want field
265 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
266 {"install",pkgCache::State::Install},
267 {"hold",pkgCache::State::Hold},
268 {"deinstall",pkgCache::State::DeInstall},
269 {"purge",pkgCache::State::Purge},
270 {}};
271 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
272 return _error->Error("Malformed 1st word in the Status line");
273
274 // Isloate the next word
275 I++;
276 Start = I;
277 for(; I < Stop && *I != ' '; I++);
278 if (I >= Stop || *I != ' ')
279 return _error->Error("Malformed status line, no 2nd word");
280
281 // Process the flag field
282 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
283 {"reinstreq",pkgCache::State::ReInstReq},
284 {"hold",pkgCache::State::HoldInst},
285 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
286 {}};
287 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
288 return _error->Error("Malformed 2nd word in the Status line");
289
290 // Isloate the last word
291 I++;
292 Start = I;
293 for(; I < Stop && *I != ' '; I++);
294 if (I != Stop)
295 return _error->Error("Malformed Status line, no 3rd word");
296
297 // Process the flag field
298 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
299 {"unpacked",pkgCache::State::UnPacked},
300 {"half-configured",pkgCache::State::HalfConfigured},
301 {"installed",pkgCache::State::Installed},
302 {"half-installed",pkgCache::State::HalfInstalled},
303 {"config-files",pkgCache::State::ConfigFiles},
304 {"triggers-awaited",pkgCache::State::TriggersAwaited},
305 {"triggers-pending",pkgCache::State::TriggersPending},
306 {"post-inst-failed",pkgCache::State::HalfConfigured},
307 {"removal-failed",pkgCache::State::HalfInstalled},
308 {}};
309 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
310 return _error->Error("Malformed 3rd word in the Status line");
311
312 /* A Status line marks the package as indicating the current
313 version as well. Only if it is actually installed.. Otherwise
314 the interesting dpkg handling of the status file creates bogus
315 entries. */
316 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
317 Pkg->CurrentState == pkgCache::State::ConfigFiles))
318 {
319 if (Ver.end() == true)
320 _error->Warning("Encountered status field in a non-version description");
321 else
322 Pkg->CurrentVer = Ver.Index();
323 }
324
325 return true;
326}
327
328const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
329{
330 // Determine the operator
331 switch (*I)
332 {
333 case '<':
334 I++;
335 if (*I == '=')
336 {
337 I++;
338 Op = pkgCache::Dep::LessEq;
339 break;
340 }
341
342 if (*I == '<')
343 {
344 I++;
345 Op = pkgCache::Dep::Less;
346 break;
347 }
348
349 // < is the same as <= and << is really Cs < for some reason
350 Op = pkgCache::Dep::LessEq;
351 break;
352
353 case '>':
354 I++;
355 if (*I == '=')
356 {
357 I++;
358 Op = pkgCache::Dep::GreaterEq;
359 break;
360 }
361
362 if (*I == '>')
363 {
364 I++;
365 Op = pkgCache::Dep::Greater;
366 break;
367 }
368
369 // > is the same as >= and >> is really Cs > for some reason
370 Op = pkgCache::Dep::GreaterEq;
371 break;
372
373 case '=':
374 Op = pkgCache::Dep::Equals;
375 I++;
376 break;
377
378 // HACK around bad package definitions
379 default:
380 Op = pkgCache::Dep::Equals;
381 break;
382 }
383 return I;
384}
385
386 /*}}}*/
387// ListParser::ParseDepends - Parse a dependency element /*{{{*/
388// ---------------------------------------------------------------------
389/* This parses the dependency elements out of a standard string in place,
390 bit by bit. */
391const char *debListParser::ParseDepends(const char *Start,const char *Stop,
392 string &Package,string &Ver,
393 unsigned int &Op, bool ParseArchFlags)
394{
395 // Strip off leading space
396 for (;Start != Stop && isspace(*Start) != 0; Start++);
397
398 // Parse off the package name
399 const char *I = Start;
400 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
401 *I != ',' && *I != '|'; I++);
402
403 // Malformed, no '('
404 if (I != Stop && *I == ')')
405 return 0;
406
407 if (I == Start)
408 return 0;
409
410 // Stash the package name
411 Package.assign(Start,I - Start);
412
413 // Skip white space to the '('
414 for (;I != Stop && isspace(*I) != 0 ; I++);
415
416 // Parse a version
417 if (I != Stop && *I == '(')
418 {
419 // Skip the '('
420 for (I++; I != Stop && isspace(*I) != 0 ; I++);
421 if (I + 3 >= Stop)
422 return 0;
423 I = ConvertRelation(I,Op);
424
425 // Skip whitespace
426 for (;I != Stop && isspace(*I) != 0; I++);
427 Start = I;
428 for (;I != Stop && *I != ')'; I++);
429 if (I == Stop || Start == I)
430 return 0;
431
432 // Skip trailing whitespace
433 const char *End = I;
434 for (; End > Start && isspace(End[-1]); End--);
435
436 Ver.assign(Start,End-Start);
437 I++;
438 }
439 else
440 {
441 Ver.clear();
442 Op = pkgCache::Dep::NoOp;
443 }
444
445 // Skip whitespace
446 for (;I != Stop && isspace(*I) != 0; I++);
447
448 if (ParseArchFlags == true)
449 {
450 string arch = _config->Find("APT::Architecture");
451
452 // Parse an architecture
453 if (I != Stop && *I == '[')
454 {
455 // malformed
456 I++;
457 if (I == Stop)
458 return 0;
459
460 const char *End = I;
461 bool Found = false;
462 bool NegArch = false;
463 while (I != Stop)
464 {
465 // look for whitespace or ending ']'
466 while (End != Stop && !isspace(*End) && *End != ']')
467 End++;
468
469 if (End == Stop)
470 return 0;
471
472 if (*I == '!')
473 {
474 NegArch = true;
475 I++;
476 }
477
478 if (stringcmp(arch,I,End) == 0)
479 Found = true;
480
481 if (*End++ == ']') {
482 I = End;
483 break;
484 }
485
486 I = End;
487 for (;I != Stop && isspace(*I) != 0; I++);
488 }
489
490 if (NegArch)
491 Found = !Found;
492
493 if (Found == false)
494 Package = ""; /* not for this arch */
495 }
496
497 // Skip whitespace
498 for (;I != Stop && isspace(*I) != 0; I++);
499 }
500
501 if (I != Stop && *I == '|')
502 Op |= pkgCache::Dep::Or;
503
504 if (I == Stop || *I == ',' || *I == '|')
505 {
506 if (I != Stop)
507 for (I++; I != Stop && isspace(*I) != 0; I++);
508 return I;
509 }
510
511 return 0;
512}
513 /*}}}*/
514// ListParser::ParseDepends - Parse a dependency list /*{{{*/
515// ---------------------------------------------------------------------
516/* This is the higher level depends parser. It takes a tag and generates
517 a complete depends tree for the given version. */
518bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
519 const char *Tag,unsigned int Type)
520{
521 const char *Start;
522 const char *Stop;
523 if (Section.Find(Tag,Start,Stop) == false)
524 return true;
525
526 string Package;
527 string Version;
528 unsigned int Op;
529
530 while (1)
531 {
532 Start = ParseDepends(Start,Stop,Package,Version,Op);
533 if (Start == 0)
534 return _error->Error("Problem parsing dependency %s",Tag);
535
536 if (NewDepends(Ver,Package,Version,Op,Type) == false)
537 return false;
538 if (Start == Stop)
539 break;
540 }
541 return true;
542}
543 /*}}}*/
544// ListParser::ParseProvides - Parse the provides list /*{{{*/
545// ---------------------------------------------------------------------
546/* */
547bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
548{
549 const char *Start;
550 const char *Stop;
551 if (Section.Find("Provides",Start,Stop) == false)
552 return true;
553
554 string Package;
555 string Version;
556 unsigned int Op;
557
558 while (1)
559 {
560 Start = ParseDepends(Start,Stop,Package,Version,Op);
561 if (Start == 0)
562 return _error->Error("Problem parsing Provides line");
563 if (Op != pkgCache::Dep::NoOp) {
564 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
565 } else {
566 if (NewProvides(Ver,Package,Version) == false)
567 return false;
568 }
569
570 if (Start == Stop)
571 break;
572 }
573
574 return true;
575}
576 /*}}}*/
577// ListParser::GrabWord - Matches a word and returns /*{{{*/
578// ---------------------------------------------------------------------
579/* Looks for a word in a list of words - for ParseStatus */
580bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
581{
582 for (unsigned int C = 0; List[C].Str != 0; C++)
583 {
584 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
585 {
586 Out = List[C].Val;
587 return true;
588 }
589 }
590 return false;
591}
592 /*}}}*/
593// ListParser::Step - Move to the next section in the file /*{{{*/
594// ---------------------------------------------------------------------
595/* This has to be carefull to only process the correct architecture */
596bool debListParser::Step()
597{
598 iOffset = Tags.Offset();
599 while (Tags.Step(Section) == true)
600 {
601 /* See if this is the correct Architecture, if it isn't then we
602 drop the whole section. A missing arch tag only happens (in theory)
603 inside the Status file, so that is a positive return */
604 const char *Start;
605 const char *Stop;
606 if (Section.Find("Architecture",Start,Stop) == false)
607 return true;
608
609 if (stringcmp(Arch,Start,Stop) == 0)
610 return true;
611
612 if (stringcmp(Start,Stop,"all") == 0)
613 return true;
614
615 iOffset = Tags.Offset();
616 }
617 return false;
618}
619 /*}}}*/
620// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
621// ---------------------------------------------------------------------
622/* */
623bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
624 FileFd &File, string component)
625{
626 pkgTagFile Tags(&File, File.Size() + 256); // XXX
627 pkgTagSection Section;
628 if (Tags.Step(Section) == false)
629 return false;
630
631 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
632 //FileI->Architecture = WriteUniqString(Arch);
633
634 // apt-secure does no longer download individual (per-section) Release
635 // file. to provide Component pinning we use the section name now
636 FileI->Component = WriteUniqString(component);
637
638 const char *Start;
639 const char *Stop;
640 if (Section.Find("Suite",Start,Stop) == true)
641 FileI->Archive = WriteUniqString(Start,Stop - Start);
642 if (Section.Find("Component",Start,Stop) == true)
643 FileI->Component = WriteUniqString(Start,Stop - Start);
644 if (Section.Find("Version",Start,Stop) == true)
645 FileI->Version = WriteUniqString(Start,Stop - Start);
646 if (Section.Find("Origin",Start,Stop) == true)
647 FileI->Origin = WriteUniqString(Start,Stop - Start);
648 if (Section.Find("Label",Start,Stop) == true)
649 FileI->Label = WriteUniqString(Start,Stop - Start);
650 if (Section.Find("Architecture",Start,Stop) == true)
651 FileI->Architecture = WriteUniqString(Start,Stop - Start);
652
653 if (Section.FindFlag("NotAutomatic",FileI->Flags,
654 pkgCache::Flag::NotAutomatic) == false)
655 _error->Warning("Bad NotAutomatic flag");
656
657 return !_error->PendingError();
658}
659 /*}}}*/
660// ListParser::GetPrio - Convert the priority from a string /*{{{*/
661// ---------------------------------------------------------------------
662/* */
663unsigned char debListParser::GetPrio(string Str)
664{
665 unsigned char Out;
666 if (GrabWord(Str,PrioList,Out) == false)
667 Out = pkgCache::State::Extra;
668
669 return Out;
670}
671 /*}}}*/