]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/deb/deblistparser.cc
5b44800c4d66a853088fad5bf7c3cdf74bec70d7
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/strutl.h>
17 #include <apt-pkg/crc-16.h>
18 #include <apt-pkg/md5.h>
19 #include <apt-pkg/macros.h>
24 static debListParser::WordList PrioList
[] = {{"important",pkgCache::State::Important
},
25 {"required",pkgCache::State::Required
},
26 {"standard",pkgCache::State::Standard
},
27 {"optional",pkgCache::State::Optional
},
28 {"extra",pkgCache::State::Extra
},
31 // ListParser::debListParser - Constructor /*{{{*/
32 // ---------------------------------------------------------------------
34 debListParser::debListParser(FileFd
*File
) : Tags(File
)
36 Arch
= _config
->Find("APT::architecture");
39 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
40 // ---------------------------------------------------------------------
42 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
46 if (Section
.Find(Tag
,Start
,Stop
) == false)
48 return WriteUniqString(Start
,Stop
- Start
);
51 // ListParser::Package - Return the package name /*{{{*/
52 // ---------------------------------------------------------------------
53 /* This is to return the name of the package this section describes */
54 string
debListParser::Package()
56 string Result
= Section
.FindS("Package");
57 if (Result
.empty() == true)
58 _error
->Error("Encountered a section with no Package: header");
62 // ListParser::Version - Return the version string /*{{{*/
63 // ---------------------------------------------------------------------
64 /* This is to return the string describing the version in debian form,
65 epoch:upstream-release. If this returns the blank string then the
66 entry is assumed to only describe package properties */
67 string
debListParser::Version()
69 return Section
.FindS("Version");
72 // ListParser::NewVersion - Fill in the version structure /*{{{*/
73 // ---------------------------------------------------------------------
75 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
77 Ver
->Display
= UniqFindTagWrite("Name");
78 if (Ver
->Display
== 0)
79 Ver
->Display
= UniqFindTagWrite("Maemo-Display-Name");
82 Ver
->Section
= UniqFindTagWrite("Section");
83 Ver
->Arch
= UniqFindTagWrite("Architecture");
86 Ver
->Size
= (unsigned)Section
.FindI("Size");
88 // Unpacked Size (in K)
89 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
90 Ver
->InstalledSize
*= 1024;
95 if (Section
.Find("Priority",Start
,Stop
) == true)
97 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
98 Ver
->Priority
= pkgCache::State::Extra
;
101 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
103 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
105 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
107 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
109 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
111 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
113 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
115 if (ParseDepends(Ver
,"Enhances",pkgCache::Dep::Enhances
) == false)
119 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
122 if (ParseProvides(Ver
) == false)
128 // ListParser::Description - Return the description string /*{{{*/
129 // ---------------------------------------------------------------------
130 /* This is to return the string describing the package in debian
131 form. If this returns the blank string then the entry is assumed to
132 only describe package properties */
133 string
debListParser::Description()
135 if (DescriptionLanguage().empty())
136 return Section
.FindS("Description");
138 return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
141 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
142 // ---------------------------------------------------------------------
143 /* This is to return the string describing the language of
144 description. If this returns the blank string then the entry is
145 assumed to describe original description. */
146 string
debListParser::DescriptionLanguage()
148 return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
151 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
152 // ---------------------------------------------------------------------
153 /* This is to return the md5 string to allow the check if it is the right
154 description. If no Description-md5 is found in the section it will be
157 MD5SumValue
debListParser::Description_md5()
159 string value
= Section
.FindS("Description-md5");
164 md5
.Add((Description() + "\n").c_str());
167 return MD5SumValue(value
);
170 // ListParser::UsePackage - Update a package structure /*{{{*/
171 // ---------------------------------------------------------------------
172 /* This is called to update the package with any new information
173 that might be found in the section */
174 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
175 pkgCache::VerIterator Ver
)
177 if (Pkg
->Display
== 0)
178 Pkg
->Display
= UniqFindTagWrite("Name");
179 if (Pkg
->Display
== 0)
180 Pkg
->Display
= UniqFindTagWrite("Maemo-Display-Name");
181 if (Pkg
->Section
== 0)
182 Pkg
->Section
= UniqFindTagWrite("Section");
183 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
185 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
188 if (strcmp(Pkg
.Name(),"apt") == 0)
189 Pkg
->Flags
|= pkgCache::Flag::Important
;
191 if (ParseStatus(Pkg
,Ver
) == false)
194 if (Pkg
->TagList
== 0)
195 if (ParseTag(Pkg
) == false)
201 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
202 // ---------------------------------------------------------------------
204 unsigned short debListParser::VersionHash()
206 const char *Sections
[] ={"Installed-Size",
214 unsigned long Result
= INIT_FCS
;
216 for (const char **I
= Sections
; *I
!= 0; I
++)
220 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
223 /* Strip out any spaces from the text, this undoes dpkgs reformatting
224 of certain fields. dpkg also has the rather interesting notion of
225 reformatting depends operators < -> <= */
227 for (; Start
!= End
; Start
++)
229 if (isspace(*Start
) == 0)
230 *I
++ = tolower_ascii(*Start
);
231 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
233 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
237 Result
= AddCRC16(Result
,S
,I
- S
);
243 // ListParser::ParseStatus - Parse the status field /*{{{*/
244 // ---------------------------------------------------------------------
245 /* Status lines are of the form,
246 Status: want flag status
247 want = unknown, install, hold, deinstall, purge
248 flag = ok, reinstreq, hold, hold-reinstreq
249 status = not-installed, unpacked, half-configured,
250 half-installed, config-files, post-inst-failed,
251 removal-failed, installed
253 Some of the above are obsolete (I think?) flag = hold-* and
254 status = post-inst-failed, removal-failed at least.
256 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
257 pkgCache::VerIterator Ver
)
261 if (Section
.Find("Status",Start
,Stop
) == false)
264 // Isolate the first word
265 const char *I
= Start
;
266 for(; I
< Stop
&& *I
!= ' '; I
++);
267 if (I
>= Stop
|| *I
!= ' ')
268 return _error
->Error("Malformed Status line");
270 // Process the want field
271 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
272 {"install",pkgCache::State::Install
},
273 {"hold",pkgCache::State::Hold
},
274 {"deinstall",pkgCache::State::DeInstall
},
275 {"purge",pkgCache::State::Purge
},
277 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
278 return _error
->Error("Malformed 1st word in the Status line");
280 // Isloate the next word
283 for(; I
< Stop
&& *I
!= ' '; I
++);
284 if (I
>= Stop
|| *I
!= ' ')
285 return _error
->Error("Malformed status line, no 2nd word");
287 // Process the flag field
288 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
289 {"reinstreq",pkgCache::State::ReInstReq
},
290 {"hold",pkgCache::State::HoldInst
},
291 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
293 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
294 return _error
->Error("Malformed 2nd word in the Status line");
296 // Isloate the last word
299 for(; I
< Stop
&& *I
!= ' '; I
++);
301 return _error
->Error("Malformed Status line, no 3rd word");
303 // Process the flag field
304 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
305 {"unpacked",pkgCache::State::UnPacked
},
306 {"half-configured",pkgCache::State::HalfConfigured
},
307 {"installed",pkgCache::State::Installed
},
308 {"half-installed",pkgCache::State::HalfInstalled
},
309 {"config-files",pkgCache::State::ConfigFiles
},
310 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
311 {"triggers-pending",pkgCache::State::TriggersPending
},
312 {"post-inst-failed",pkgCache::State::HalfConfigured
},
313 {"removal-failed",pkgCache::State::HalfInstalled
},
315 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
316 return _error
->Error("Malformed 3rd word in the Status line");
318 /* A Status line marks the package as indicating the current
319 version as well. Only if it is actually installed.. Otherwise
320 the interesting dpkg handling of the status file creates bogus
322 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
323 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
325 if (Ver
.end() == true)
326 _error
->Warning("Encountered status field in a non-version description");
328 Pkg
->CurrentVer
= Ver
.Index();
334 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
336 // Determine the operator
344 Op
= pkgCache::Dep::LessEq
;
351 Op
= pkgCache::Dep::Less
;
355 // < is the same as <= and << is really Cs < for some reason
356 Op
= pkgCache::Dep::LessEq
;
364 Op
= pkgCache::Dep::GreaterEq
;
371 Op
= pkgCache::Dep::Greater
;
375 // > is the same as >= and >> is really Cs > for some reason
376 Op
= pkgCache::Dep::GreaterEq
;
380 Op
= pkgCache::Dep::Equals
;
384 // HACK around bad package definitions
386 Op
= pkgCache::Dep::Equals
;
393 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
394 // ---------------------------------------------------------------------
395 /* This parses the dependency elements out of a standard string in place,
397 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
398 string
&Package
,string
&Ver
,
399 unsigned int &Op
, bool ParseArchFlags
)
401 // Strip off leading space
402 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
404 // Parse off the package name
405 const char *I
= Start
;
406 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
407 *I
!= ',' && *I
!= '|'; I
++);
410 if (I
!= Stop
&& *I
== ')')
416 // Stash the package name
417 Package
.assign(Start
,I
- Start
);
419 // Skip white space to the '('
420 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
423 if (I
!= Stop
&& *I
== '(')
426 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
429 I
= ConvertRelation(I
,Op
);
432 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
434 for (;I
!= Stop
&& *I
!= ')'; I
++);
435 if (I
== Stop
|| Start
== I
)
438 // Skip trailing whitespace
440 for (; End
> Start
&& isspace(End
[-1]); End
--);
442 Ver
.assign(Start
,End
-Start
);
448 Op
= pkgCache::Dep::NoOp
;
452 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
454 if (ParseArchFlags
== true)
456 string arch
= _config
->Find("APT::Architecture");
458 // Parse an architecture
459 if (I
!= Stop
&& *I
== '[')
468 bool NegArch
= false;
471 // look for whitespace or ending ']'
472 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
484 if (stringcmp(arch
,I
,End
) == 0)
493 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
500 Package
= ""; /* not for this arch */
504 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
507 if (I
!= Stop
&& *I
== '|')
508 Op
|= pkgCache::Dep::Or
;
510 if (I
== Stop
|| *I
== ',' || *I
== '|')
513 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
520 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
521 // ---------------------------------------------------------------------
522 /* This is the higher level depends parser. It takes a tag and generates
523 a complete depends tree for the given version. */
524 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
525 const char *Tag
,unsigned int Type
)
529 if (Section
.Find(Tag
,Start
,Stop
) == false)
538 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
540 return _error
->Error("Problem parsing dependency %s",Tag
);
542 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
550 // ListParser::ParseProvides - Parse the provides list /*{{{*/
551 // ---------------------------------------------------------------------
553 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
557 if (Section
.Find("Provides",Start
,Stop
) == false)
566 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
568 return _error
->Error("Problem parsing Provides line");
569 if (Op
!= pkgCache::Dep::NoOp
) {
570 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
572 if (NewProvides(Ver
,Package
,Version
) == false)
583 // ListParser::ParseTag - Parse the tag list /*{{{*/
584 // ---------------------------------------------------------------------
586 bool debListParser::ParseTag(pkgCache::PkgIterator Pkg
)
590 if (Section
.Find("Tag",Start
,Stop
) == false)
597 if (Stop
[-1] != ' ' && Stop
[-1] != '\t')
602 const char *Begin
= Stop
- 1;
603 while (Begin
!= Start
&& Begin
[-1] != ' ' && Begin
[-1] != ',')
606 if (NewTag(Pkg
, Begin
, Stop
- Begin
) == false)
612 if (Begin
[-1] == ',')
623 // ListParser::GrabWord - Matches a word and returns /*{{{*/
624 // ---------------------------------------------------------------------
625 /* Looks for a word in a list of words - for ParseStatus */
626 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
628 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
630 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
639 // ListParser::Step - Move to the next section in the file /*{{{*/
640 // ---------------------------------------------------------------------
641 /* This has to be carefull to only process the correct architecture */
642 bool debListParser::Step()
644 iOffset
= Tags
.Offset();
645 while (Tags
.Step(Section
) == true)
650 if (Section
.Find("Package",Start
,Stop
) == false) {
651 _error
->Warning("Encountered a section with no Package: header");
655 /* See if this is the correct Architecture, if it isn't then we
656 drop the whole section. A missing arch tag only happens (in theory)
657 inside the Status file, so that is a positive return */
659 if (Section
.Find("Architecture",Start
,Stop
) == false)
662 if (stringcmp(Arch
,Start
,Stop
) == 0)
665 if (stringcmp(Start
,Stop
,"all") == 0)
668 iOffset
= Tags
.Offset();
673 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
674 // ---------------------------------------------------------------------
676 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
677 FileFd
&File
, string component
)
679 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
680 pkgTagSection Section
;
681 if (Tags
.Step(Section
) == false)
684 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
685 //FileI->Architecture = WriteUniqString(Arch);
687 // apt-secure does no longer download individual (per-section) Release
688 // file. to provide Component pinning we use the section name now
689 FileI
->Component
= WriteUniqString(component
);
693 if (Section
.Find("Suite",Start
,Stop
) == true)
694 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
695 if (Section
.Find("Component",Start
,Stop
) == true)
696 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
697 if (Section
.Find("Version",Start
,Stop
) == true)
698 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
699 if (Section
.Find("Origin",Start
,Stop
) == true)
700 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
701 if (Section
.Find("Label",Start
,Stop
) == true)
702 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
703 if (Section
.Find("Architecture",Start
,Stop
) == true)
704 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
706 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
707 pkgCache::Flag::NotAutomatic
) == false)
708 _error
->Warning("Bad NotAutomatic flag");
710 return !_error
->PendingError();
713 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
714 // ---------------------------------------------------------------------
716 unsigned char debListParser::GetPrio(string Str
)
719 if (GrabWord(Str
,PrioList
,Out
) == false)
720 Out
= pkgCache::State::Extra
;