]>
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/strutl.h>
17 #include <apt-pkg/crc-16.h>
18 #include <apt-pkg/md5.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
,"Replaces",pkgCache::Dep::Replaces
) == false)
112 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
115 if (ParseProvides(Ver
) == false)
121 // ListParser::Description - Return the description string /*{{{*/
122 // ---------------------------------------------------------------------
123 /* This is to return the string describing the package in debian
124 form. If this returns the blank string then the entry is assumed to
125 only describe package properties */
126 string
debListParser::Description()
128 if (DescriptionLanguage().empty())
129 return Section
.FindS("Description");
131 return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
134 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
135 // ---------------------------------------------------------------------
136 /* This is to return the string describing the language of
137 description. If this returns the blank string then the entry is
138 assumed to describe original description. */
139 string
debListParser::DescriptionLanguage()
141 return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
144 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
145 // ---------------------------------------------------------------------
146 /* This is to return the md5 string to allow the check if is the right
147 description. If thisreturns a blank string then calculate the md5
149 MD5SumValue
debListParser::Description_md5()
151 string value
= Section
.FindS("Description-md5");
155 md5
.Add((Description() + "\n").c_str());
158 return MD5SumValue(value
);
161 // ListParser::UsePackage - Update a package structure /*{{{*/
162 // ---------------------------------------------------------------------
163 /* This is called to update the package with any new information
164 that might be found in the section */
165 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
166 pkgCache::VerIterator Ver
)
168 if (Pkg
->Section
== 0)
169 Pkg
->Section
= UniqFindTagWrite("Section");
170 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
172 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
175 if (strcmp(Pkg
.Name(),"apt") == 0)
176 Pkg
->Flags
|= pkgCache::Flag::Important
;
178 if (ParseStatus(Pkg
,Ver
) == false)
183 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
184 // ---------------------------------------------------------------------
186 unsigned short debListParser::VersionHash()
188 const char *Sections
[] ={"Installed-Size",
195 unsigned long Result
= INIT_FCS
;
197 for (const char **I
= Sections
; *I
!= 0; I
++)
201 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
204 /* Strip out any spaces from the text, this undoes dpkgs reformatting
205 of certain fields. dpkg also has the rather interesting notion of
206 reformatting depends operators < -> <= */
208 for (; Start
!= End
; Start
++)
210 if (isspace(*Start
) == 0)
211 *I
++ = tolower(*Start
);
212 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
214 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
218 Result
= AddCRC16(Result
,S
,I
- S
);
224 // ListParser::ParseStatus - Parse the status field /*{{{*/
225 // ---------------------------------------------------------------------
226 /* Status lines are of the form,
227 Status: want flag status
228 want = unknown, install, hold, deinstall, purge
229 flag = ok, reinstreq, hold, hold-reinstreq
230 status = not-installed, unpacked, half-configured,
231 half-installed, config-files, post-inst-failed,
232 removal-failed, installed
234 Some of the above are obsolete (I think?) flag = hold-* and
235 status = post-inst-failed, removal-failed at least.
237 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
238 pkgCache::VerIterator Ver
)
242 if (Section
.Find("Status",Start
,Stop
) == false)
245 // Isolate the first word
246 const char *I
= Start
;
247 for(; I
< Stop
&& *I
!= ' '; I
++);
248 if (I
>= Stop
|| *I
!= ' ')
249 return _error
->Error("Malformed Status line");
251 // Process the want field
252 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
253 {"install",pkgCache::State::Install
},
254 {"hold",pkgCache::State::Hold
},
255 {"deinstall",pkgCache::State::DeInstall
},
256 {"purge",pkgCache::State::Purge
},
258 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
259 return _error
->Error("Malformed 1st word in the Status line");
261 // Isloate the next word
264 for(; I
< Stop
&& *I
!= ' '; I
++);
265 if (I
>= Stop
|| *I
!= ' ')
266 return _error
->Error("Malformed status line, no 2nd word");
268 // Process the flag field
269 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
270 {"reinstreq",pkgCache::State::ReInstReq
},
271 {"hold",pkgCache::State::HoldInst
},
272 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
274 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
275 return _error
->Error("Malformed 2nd word in the Status line");
277 // Isloate the last word
280 for(; I
< Stop
&& *I
!= ' '; I
++);
282 return _error
->Error("Malformed Status line, no 3rd word");
284 // Process the flag field
285 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
286 {"unpacked",pkgCache::State::UnPacked
},
287 {"half-configured",pkgCache::State::HalfConfigured
},
288 {"installed",pkgCache::State::Installed
},
289 {"half-installed",pkgCache::State::HalfInstalled
},
290 {"config-files",pkgCache::State::ConfigFiles
},
291 {"post-inst-failed",pkgCache::State::HalfConfigured
},
292 {"removal-failed",pkgCache::State::HalfInstalled
},
294 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
295 return _error
->Error("Malformed 3rd word in the Status line");
297 /* A Status line marks the package as indicating the current
298 version as well. Only if it is actually installed.. Otherwise
299 the interesting dpkg handling of the status file creates bogus
301 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
302 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
304 if (Ver
.end() == true)
305 _error
->Warning("Encountered status field in a non-version description");
307 Pkg
->CurrentVer
= Ver
.Index();
313 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
315 // Determine the operator
323 Op
= pkgCache::Dep::LessEq
;
330 Op
= pkgCache::Dep::Less
;
334 // < is the same as <= and << is really Cs < for some reason
335 Op
= pkgCache::Dep::LessEq
;
343 Op
= pkgCache::Dep::GreaterEq
;
350 Op
= pkgCache::Dep::Greater
;
354 // > is the same as >= and >> is really Cs > for some reason
355 Op
= pkgCache::Dep::GreaterEq
;
359 Op
= pkgCache::Dep::Equals
;
363 // HACK around bad package definitions
365 Op
= pkgCache::Dep::Equals
;
372 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
373 // ---------------------------------------------------------------------
374 /* This parses the dependency elements out of a standard string in place,
376 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
377 string
&Package
,string
&Ver
,
378 unsigned int &Op
, bool ParseArchFlags
)
380 // Strip off leading space
381 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
383 // Parse off the package name
384 const char *I
= Start
;
385 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
386 *I
!= ',' && *I
!= '|'; I
++);
389 if (I
!= Stop
&& *I
== ')')
395 // Stash the package name
396 Package
.assign(Start
,I
- Start
);
398 // Skip white space to the '('
399 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
402 if (I
!= Stop
&& *I
== '(')
405 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
408 I
= ConvertRelation(I
,Op
);
411 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
413 for (;I
!= Stop
&& *I
!= ')'; I
++);
414 if (I
== Stop
|| Start
== I
)
417 // Skip trailing whitespace
419 for (; End
> Start
&& isspace(End
[-1]); End
--);
421 Ver
= string(Start
,End
-Start
);
427 Op
= pkgCache::Dep::NoOp
;
431 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
433 if (ParseArchFlags
== true)
435 string arch
= _config
->Find("APT::Architecture");
437 // Parse an architecture
438 if (I
!= Stop
&& *I
== '[')
447 bool NegArch
= false;
450 // look for whitespace or ending ']'
451 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
463 if (stringcmp(arch
,I
,End
) == 0)
472 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
479 Package
= ""; /* not for this arch */
483 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
486 if (I
!= Stop
&& *I
== '|')
487 Op
|= pkgCache::Dep::Or
;
489 if (I
== Stop
|| *I
== ',' || *I
== '|')
492 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
499 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
500 // ---------------------------------------------------------------------
501 /* This is the higher level depends parser. It takes a tag and generates
502 a complete depends tree for the given version. */
503 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
504 const char *Tag
,unsigned int Type
)
508 if (Section
.Find(Tag
,Start
,Stop
) == false)
517 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
519 return _error
->Error("Problem parsing dependency %s",Tag
);
521 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
529 // ListParser::ParseProvides - Parse the provides list /*{{{*/
530 // ---------------------------------------------------------------------
532 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
536 if (Section
.Find("Provides",Start
,Stop
) == false)
545 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
547 return _error
->Error("Problem parsing Provides line");
548 if (Op
!= pkgCache::Dep::NoOp
)
549 return _error
->Error("Malformed provides line");
551 if (NewProvides(Ver
,Package
,Version
) == false)
561 // ListParser::GrabWord - Matches a word and returns /*{{{*/
562 // ---------------------------------------------------------------------
563 /* Looks for a word in a list of words - for ParseStatus */
564 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
566 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
568 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
577 // ListParser::Step - Move to the next section in the file /*{{{*/
578 // ---------------------------------------------------------------------
579 /* This has to be carefull to only process the correct architecture */
580 bool debListParser::Step()
582 iOffset
= Tags
.Offset();
583 while (Tags
.Step(Section
) == true)
585 /* See if this is the correct Architecture, if it isn't then we
586 drop the whole section. A missing arch tag only happens (in theory)
587 inside the Status file, so that is a positive return */
590 if (Section
.Find("Architecture",Start
,Stop
) == false)
593 if (stringcmp(Arch
,Start
,Stop
) == 0)
596 if (stringcmp(Start
,Stop
,"all") == 0)
599 iOffset
= Tags
.Offset();
604 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
605 // ---------------------------------------------------------------------
607 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
610 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
611 pkgTagSection Section
;
612 if (Tags
.Step(Section
) == false)
617 if (Section
.Find("Suite",Start
,Stop
) == true)
618 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
619 if (Section
.Find("Component",Start
,Stop
) == true)
620 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
621 if (Section
.Find("Version",Start
,Stop
) == true)
622 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
623 if (Section
.Find("Origin",Start
,Stop
) == true)
624 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
625 if (Section
.Find("Label",Start
,Stop
) == true)
626 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
627 if (Section
.Find("Architecture",Start
,Stop
) == true)
628 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
630 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
631 pkgCache::Flag::NotAutomatic
) == false)
632 _error
->Warning("Bad NotAutomatic flag");
634 return !_error
->PendingError();
637 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
638 // ---------------------------------------------------------------------
640 unsigned char debListParser::GetPrio(string Str
)
643 if (GrabWord(Str
,PrioList
,Out
) == false)
644 Out
= pkgCache::State::Extra
;