]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
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/aptconfiguration.h>
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/crc-16.h>
19 #include <apt-pkg/md5.h>
20 #include <apt-pkg/macros.h>
25 static 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
},
32 // ListParser::debListParser - Constructor /*{{{*/
33 // ---------------------------------------------------------------------
35 debListParser::debListParser(FileFd
*File
) : Tags(File
)
37 Arch
= _config
->Find("APT::architecture");
40 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
41 // ---------------------------------------------------------------------
43 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
47 if (Section
.Find(Tag
,Start
,Stop
) == false)
49 return WriteUniqString(Start
,Stop
- Start
);
52 // ListParser::Package - Return the package name /*{{{*/
53 // ---------------------------------------------------------------------
54 /* This is to return the name of the package this section describes */
55 string
debListParser::Package()
57 string Result
= Section
.FindS("Package");
58 if (Result
.empty() == true)
59 _error
->Error("Encountered a section with no Package: header");
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 */
68 string
debListParser::Version()
70 return Section
.FindS("Version");
73 // ListParser::NewVersion - Fill in the version structure /*{{{*/
74 // ---------------------------------------------------------------------
76 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
79 Ver
->Section
= UniqFindTagWrite("Section");
80 Ver
->Arch
= UniqFindTagWrite("Architecture");
83 Ver
->Size
= (unsigned)Section
.FindI("Size");
85 // Unpacked Size (in K)
86 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
87 Ver
->InstalledSize
*= 1024;
92 if (Section
.Find("Priority",Start
,Stop
) == true)
94 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
95 Ver
->Priority
= pkgCache::State::Extra
;
98 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
100 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
102 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
104 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
106 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
108 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
110 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
112 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
116 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
119 if (ParseProvides(Ver
) == false)
125 // ListParser::Description - Return the description string /*{{{*/
126 // ---------------------------------------------------------------------
127 /* This is to return the string describing the package in debian
128 form. If this returns the blank string then the entry is assumed to
129 only describe package properties */
130 string
debListParser::Description()
132 string
const lang
= DescriptionLanguage();
134 return Section
.FindS("Description");
136 return Section
.FindS(string("Description-").append(lang
).c_str());
139 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
140 // ---------------------------------------------------------------------
141 /* This is to return the string describing the language of
142 description. If this returns the blank string then the entry is
143 assumed to describe original description. */
144 string
debListParser::DescriptionLanguage()
146 if (Section
.FindS("Description").empty() == false)
149 std::vector
<string
> const lang
= APT::Configuration::getLanguages();
150 for (std::vector
<string
>::const_iterator l
= lang
.begin();
151 l
!= lang
.end(); l
++)
152 if (Section
.FindS(string("Description-").append(*l
).c_str()).empty() == false)
158 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
159 // ---------------------------------------------------------------------
160 /* This is to return the md5 string to allow the check if it is the right
161 description. If no Description-md5 is found in the section it will be
164 MD5SumValue
debListParser::Description_md5()
166 string value
= Section
.FindS("Description-md5");
171 md5
.Add((Description() + "\n").c_str());
174 return MD5SumValue(value
);
177 // ListParser::UsePackage - Update a package structure /*{{{*/
178 // ---------------------------------------------------------------------
179 /* This is called to update the package with any new information
180 that might be found in the section */
181 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
182 pkgCache::VerIterator Ver
)
184 if (Pkg
->Section
== 0)
185 Pkg
->Section
= UniqFindTagWrite("Section");
186 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
188 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
191 if (strcmp(Pkg
.Name(),"apt") == 0)
192 Pkg
->Flags
|= pkgCache::Flag::Important
;
194 if (ParseStatus(Pkg
,Ver
) == false)
199 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
200 // ---------------------------------------------------------------------
202 unsigned short debListParser::VersionHash()
204 const char *Sections
[] ={"Installed-Size",
212 unsigned long Result
= INIT_FCS
;
214 for (const char **I
= Sections
; *I
!= 0; I
++)
218 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
221 /* Strip out any spaces from the text, this undoes dpkgs reformatting
222 of certain fields. dpkg also has the rather interesting notion of
223 reformatting depends operators < -> <= */
225 for (; Start
!= End
; Start
++)
227 if (isspace(*Start
) == 0)
228 *I
++ = tolower_ascii(*Start
);
229 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
231 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
235 Result
= AddCRC16(Result
,S
,I
- S
);
241 // ListParser::ParseStatus - Parse the status field /*{{{*/
242 // ---------------------------------------------------------------------
243 /* Status lines are of the form,
244 Status: want flag status
245 want = unknown, install, hold, deinstall, purge
246 flag = ok, reinstreq, hold, hold-reinstreq
247 status = not-installed, unpacked, half-configured,
248 half-installed, config-files, post-inst-failed,
249 removal-failed, installed
251 Some of the above are obsolete (I think?) flag = hold-* and
252 status = post-inst-failed, removal-failed at least.
254 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
255 pkgCache::VerIterator Ver
)
259 if (Section
.Find("Status",Start
,Stop
) == false)
262 // Isolate the first word
263 const char *I
= Start
;
264 for(; I
< Stop
&& *I
!= ' '; I
++);
265 if (I
>= Stop
|| *I
!= ' ')
266 return _error
->Error("Malformed Status line");
268 // Process the want field
269 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
270 {"install",pkgCache::State::Install
},
271 {"hold",pkgCache::State::Hold
},
272 {"deinstall",pkgCache::State::DeInstall
},
273 {"purge",pkgCache::State::Purge
},
275 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
276 return _error
->Error("Malformed 1st word in the Status line");
278 // Isloate the next word
281 for(; I
< Stop
&& *I
!= ' '; I
++);
282 if (I
>= Stop
|| *I
!= ' ')
283 return _error
->Error("Malformed status line, no 2nd word");
285 // Process the flag field
286 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
287 {"reinstreq",pkgCache::State::ReInstReq
},
288 {"hold",pkgCache::State::HoldInst
},
289 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
291 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
292 return _error
->Error("Malformed 2nd word in the Status line");
294 // Isloate the last word
297 for(; I
< Stop
&& *I
!= ' '; I
++);
299 return _error
->Error("Malformed Status line, no 3rd word");
301 // Process the flag field
302 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
303 {"unpacked",pkgCache::State::UnPacked
},
304 {"half-configured",pkgCache::State::HalfConfigured
},
305 {"installed",pkgCache::State::Installed
},
306 {"half-installed",pkgCache::State::HalfInstalled
},
307 {"config-files",pkgCache::State::ConfigFiles
},
308 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
309 {"triggers-pending",pkgCache::State::TriggersPending
},
310 {"post-inst-failed",pkgCache::State::HalfConfigured
},
311 {"removal-failed",pkgCache::State::HalfInstalled
},
313 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
314 return _error
->Error("Malformed 3rd word in the Status line");
316 /* A Status line marks the package as indicating the current
317 version as well. Only if it is actually installed.. Otherwise
318 the interesting dpkg handling of the status file creates bogus
320 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
321 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
323 if (Ver
.end() == true)
324 _error
->Warning("Encountered status field in a non-version description");
326 Pkg
->CurrentVer
= Ver
.Index();
332 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
334 // Determine the operator
342 Op
= pkgCache::Dep::LessEq
;
349 Op
= pkgCache::Dep::Less
;
353 // < is the same as <= and << is really Cs < for some reason
354 Op
= pkgCache::Dep::LessEq
;
362 Op
= pkgCache::Dep::GreaterEq
;
369 Op
= pkgCache::Dep::Greater
;
373 // > is the same as >= and >> is really Cs > for some reason
374 Op
= pkgCache::Dep::GreaterEq
;
378 Op
= pkgCache::Dep::Equals
;
382 // HACK around bad package definitions
384 Op
= pkgCache::Dep::Equals
;
391 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
392 // ---------------------------------------------------------------------
393 /* This parses the dependency elements out of a standard string in place,
395 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
396 string
&Package
,string
&Ver
,
397 unsigned int &Op
, bool const &ParseArchFlags
,
398 bool const &StripMultiArch
)
400 // Strip off leading space
401 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
403 // Parse off the package name
404 const char *I
= Start
;
405 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
406 *I
!= ',' && *I
!= '|'; I
++);
409 if (I
!= Stop
&& *I
== ')')
415 // Stash the package name
416 Package
.assign(Start
,I
- Start
);
418 // We don't want to confuse library users which can't handle MultiArch
419 if (StripMultiArch
== true) {
420 size_t const found
= Package
.rfind(':');
421 if (found
!= string::npos
)
422 Package
= Package
.substr(0,found
);
425 // Skip white space to the '('
426 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
429 if (I
!= Stop
&& *I
== '(')
432 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
435 I
= ConvertRelation(I
,Op
);
438 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
440 for (;I
!= Stop
&& *I
!= ')'; I
++);
441 if (I
== Stop
|| Start
== I
)
444 // Skip trailing whitespace
446 for (; End
> Start
&& isspace(End
[-1]); End
--);
448 Ver
.assign(Start
,End
-Start
);
454 Op
= pkgCache::Dep::NoOp
;
458 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
460 if (ParseArchFlags
== true)
462 string arch
= _config
->Find("APT::Architecture");
464 // Parse an architecture
465 if (I
!= Stop
&& *I
== '[')
474 bool NegArch
= false;
477 // look for whitespace or ending ']'
478 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
490 if (stringcmp(arch
,I
,End
) == 0)
499 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
506 Package
= ""; /* not for this arch */
510 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
513 if (I
!= Stop
&& *I
== '|')
514 Op
|= pkgCache::Dep::Or
;
516 if (I
== Stop
|| *I
== ',' || *I
== '|')
519 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
526 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
527 // ---------------------------------------------------------------------
528 /* This is the higher level depends parser. It takes a tag and generates
529 a complete depends tree for the given version. */
530 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
531 const char *Tag
,unsigned int Type
)
535 if (Section
.Find(Tag
,Start
,Stop
) == false)
544 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
546 return _error
->Error("Problem parsing dependency %s",Tag
);
548 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
556 // ListParser::ParseProvides - Parse the provides list /*{{{*/
557 // ---------------------------------------------------------------------
559 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
563 if (Section
.Find("Provides",Start
,Stop
) == false)
572 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
574 return _error
->Error("Problem parsing Provides line");
575 if (Op
!= pkgCache::Dep::NoOp
) {
576 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
578 if (NewProvides(Ver
,Package
,Version
) == false)
589 // ListParser::GrabWord - Matches a word and returns /*{{{*/
590 // ---------------------------------------------------------------------
591 /* Looks for a word in a list of words - for ParseStatus */
592 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
594 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
596 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
605 // ListParser::Step - Move to the next section in the file /*{{{*/
606 // ---------------------------------------------------------------------
607 /* This has to be carefull to only process the correct architecture */
608 bool debListParser::Step()
610 iOffset
= Tags
.Offset();
611 while (Tags
.Step(Section
) == true)
613 /* See if this is the correct Architecture, if it isn't then we
614 drop the whole section. A missing arch tag only happens (in theory)
615 inside the Status file, so that is a positive return */
618 if (Section
.Find("Architecture",Start
,Stop
) == false)
621 if (stringcmp(Arch
,Start
,Stop
) == 0)
624 if (stringcmp(Start
,Stop
,"all") == 0)
627 iOffset
= Tags
.Offset();
632 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
633 // ---------------------------------------------------------------------
635 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
636 FileFd
&File
, string component
)
638 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
639 pkgTagSection Section
;
640 if (Tags
.Step(Section
) == false)
643 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
644 //FileI->Architecture = WriteUniqString(Arch);
646 // apt-secure does no longer download individual (per-section) Release
647 // file. to provide Component pinning we use the section name now
648 FileI
->Component
= WriteUniqString(component
);
652 if (Section
.Find("Suite",Start
,Stop
) == true)
653 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
654 if (Section
.Find("Component",Start
,Stop
) == true)
655 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
656 if (Section
.Find("Version",Start
,Stop
) == true)
657 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
658 if (Section
.Find("Origin",Start
,Stop
) == true)
659 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
660 if (Section
.Find("Codename",Start
,Stop
) == true)
661 FileI
->Codename
= WriteUniqString(Start
,Stop
- Start
);
662 if (Section
.Find("Label",Start
,Stop
) == true)
663 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
664 if (Section
.Find("Architecture",Start
,Stop
) == true)
665 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
667 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
668 pkgCache::Flag::NotAutomatic
) == false)
669 _error
->Warning("Bad NotAutomatic flag");
671 return !_error
->PendingError();
674 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
675 // ---------------------------------------------------------------------
677 unsigned char debListParser::GetPrio(string Str
)
680 if (GrabWord(Str
,PrioList
,Out
) == false)
681 Out
= pkgCache::State::Extra
;