]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
074abea6d0ae76f5ccc4ff37ae0ede852cad91ba
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
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
110 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
114 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
117 if (ParseProvides(Ver
) == false)
123 // ListParser::Description - Return the description string /*{{{*/
124 // ---------------------------------------------------------------------
125 /* This is to return the string describing the package in debian
126 form. If this returns the blank string then the entry is assumed to
127 only describe package properties */
128 string
debListParser::Description()
130 if (DescriptionLanguage().empty())
131 return Section
.FindS("Description");
133 return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
136 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
137 // ---------------------------------------------------------------------
138 /* This is to return the string describing the language of
139 description. If this returns the blank string then the entry is
140 assumed to describe original description. */
141 string
debListParser::DescriptionLanguage()
143 return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
146 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
147 // ---------------------------------------------------------------------
148 /* This is to return the md5 string to allow the check if it is the right
149 description. If no Description-md5 is found in the section it will be
152 MD5SumValue
debListParser::Description_md5()
154 string value
= Section
.FindS("Description-md5");
159 md5
.Add((Description() + "\n").c_str());
162 return MD5SumValue(value
);
165 // ListParser::UsePackage - Update a package structure /*{{{*/
166 // ---------------------------------------------------------------------
167 /* This is called to update the package with any new information
168 that might be found in the section */
169 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
170 pkgCache::VerIterator Ver
)
172 if (Pkg
->Section
== 0)
173 Pkg
->Section
= UniqFindTagWrite("Section");
174 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
176 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
179 if (strcmp(Pkg
.Name(),"apt") == 0)
180 Pkg
->Flags
|= pkgCache::Flag::Important
;
182 if (ParseStatus(Pkg
,Ver
) == false)
187 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
188 // ---------------------------------------------------------------------
190 unsigned short debListParser::VersionHash()
192 const char *Sections
[] ={"Installed-Size",
200 unsigned long Result
= INIT_FCS
;
202 for (const char **I
= Sections
; *I
!= 0; I
++)
206 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
209 /* Strip out any spaces from the text, this undoes dpkgs reformatting
210 of certain fields. dpkg also has the rather interesting notion of
211 reformatting depends operators < -> <= */
213 for (; Start
!= End
; Start
++)
215 if (isspace(*Start
) == 0)
216 *I
++ = tolower(*Start
);
217 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
219 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
223 Result
= AddCRC16(Result
,S
,I
- S
);
229 // ListParser::ParseStatus - Parse the status field /*{{{*/
230 // ---------------------------------------------------------------------
231 /* Status lines are of the form,
232 Status: want flag status
233 want = unknown, install, hold, deinstall, purge
234 flag = ok, reinstreq, hold, hold-reinstreq
235 status = not-installed, unpacked, half-configured,
236 half-installed, config-files, post-inst-failed,
237 removal-failed, installed
239 Some of the above are obsolete (I think?) flag = hold-* and
240 status = post-inst-failed, removal-failed at least.
242 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
243 pkgCache::VerIterator Ver
)
247 if (Section
.Find("Status",Start
,Stop
) == false)
250 // Isolate the first word
251 const char *I
= Start
;
252 for(; I
< Stop
&& *I
!= ' '; I
++);
253 if (I
>= Stop
|| *I
!= ' ')
254 return _error
->Error("Malformed Status line");
256 // Process the want field
257 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
258 {"install",pkgCache::State::Install
},
259 {"hold",pkgCache::State::Hold
},
260 {"deinstall",pkgCache::State::DeInstall
},
261 {"purge",pkgCache::State::Purge
},
263 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
264 return _error
->Error("Malformed 1st word in the Status line");
266 // Isloate the next word
269 for(; I
< Stop
&& *I
!= ' '; I
++);
270 if (I
>= Stop
|| *I
!= ' ')
271 return _error
->Error("Malformed status line, no 2nd word");
273 // Process the flag field
274 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
275 {"reinstreq",pkgCache::State::ReInstReq
},
276 {"hold",pkgCache::State::HoldInst
},
277 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
279 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
280 return _error
->Error("Malformed 2nd word in the Status line");
282 // Isloate the last word
285 for(; I
< Stop
&& *I
!= ' '; I
++);
287 return _error
->Error("Malformed Status line, no 3rd word");
289 // Process the flag field
290 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
291 {"unpacked",pkgCache::State::UnPacked
},
292 {"half-configured",pkgCache::State::HalfConfigured
},
293 {"installed",pkgCache::State::Installed
},
294 {"half-installed",pkgCache::State::HalfInstalled
},
295 {"config-files",pkgCache::State::ConfigFiles
},
296 {"post-inst-failed",pkgCache::State::HalfConfigured
},
297 {"removal-failed",pkgCache::State::HalfInstalled
},
299 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
300 return _error
->Error("Malformed 3rd word in the Status line");
302 /* A Status line marks the package as indicating the current
303 version as well. Only if it is actually installed.. Otherwise
304 the interesting dpkg handling of the status file creates bogus
306 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
307 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
309 if (Ver
.end() == true)
310 _error
->Warning("Encountered status field in a non-version description");
312 Pkg
->CurrentVer
= Ver
.Index();
318 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
320 // Determine the operator
328 Op
= pkgCache::Dep::LessEq
;
335 Op
= pkgCache::Dep::Less
;
339 // < is the same as <= and << is really Cs < for some reason
340 Op
= pkgCache::Dep::LessEq
;
348 Op
= pkgCache::Dep::GreaterEq
;
355 Op
= pkgCache::Dep::Greater
;
359 // > is the same as >= and >> is really Cs > for some reason
360 Op
= pkgCache::Dep::GreaterEq
;
364 Op
= pkgCache::Dep::Equals
;
368 // HACK around bad package definitions
370 Op
= pkgCache::Dep::Equals
;
377 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
378 // ---------------------------------------------------------------------
379 /* This parses the dependency elements out of a standard string in place,
381 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
382 string
&Package
,string
&Ver
,
383 unsigned int &Op
, bool ParseArchFlags
)
385 // Strip off leading space
386 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
388 // Parse off the package name
389 const char *I
= Start
;
390 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
391 *I
!= ',' && *I
!= '|'; I
++);
394 if (I
!= Stop
&& *I
== ')')
400 // Stash the package name
401 Package
.assign(Start
,I
- Start
);
403 // Skip white space to the '('
404 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
407 if (I
!= Stop
&& *I
== '(')
410 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
413 I
= ConvertRelation(I
,Op
);
416 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
418 for (;I
!= Stop
&& *I
!= ')'; I
++);
419 if (I
== Stop
|| Start
== I
)
422 // Skip trailing whitespace
424 for (; End
> Start
&& isspace(End
[-1]); End
--);
426 Ver
.assign(Start
,End
-Start
);
432 Op
= pkgCache::Dep::NoOp
;
436 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
438 if (ParseArchFlags
== true)
440 string arch
= _config
->Find("APT::Architecture");
442 // Parse an architecture
443 if (I
!= Stop
&& *I
== '[')
452 bool NegArch
= false;
455 // look for whitespace or ending ']'
456 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
468 if (stringcmp(arch
,I
,End
) == 0)
477 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
484 Package
= ""; /* not for this arch */
488 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
491 if (I
!= Stop
&& *I
== '|')
492 Op
|= pkgCache::Dep::Or
;
494 if (I
== Stop
|| *I
== ',' || *I
== '|')
497 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
504 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
505 // ---------------------------------------------------------------------
506 /* This is the higher level depends parser. It takes a tag and generates
507 a complete depends tree for the given version. */
508 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
509 const char *Tag
,unsigned int Type
)
513 if (Section
.Find(Tag
,Start
,Stop
) == false)
522 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
524 return _error
->Error("Problem parsing dependency %s",Tag
);
526 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
534 // ListParser::ParseProvides - Parse the provides list /*{{{*/
535 // ---------------------------------------------------------------------
537 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
541 if (Section
.Find("Provides",Start
,Stop
) == false)
550 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
552 return _error
->Error("Problem parsing Provides line");
553 if (Op
!= pkgCache::Dep::NoOp
) {
554 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
556 if (NewProvides(Ver
,Package
,Version
) == false)
567 // ListParser::GrabWord - Matches a word and returns /*{{{*/
568 // ---------------------------------------------------------------------
569 /* Looks for a word in a list of words - for ParseStatus */
570 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
572 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
574 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
583 // ListParser::Step - Move to the next section in the file /*{{{*/
584 // ---------------------------------------------------------------------
585 /* This has to be carefull to only process the correct architecture */
586 bool debListParser::Step()
588 iOffset
= Tags
.Offset();
589 while (Tags
.Step(Section
) == true)
591 /* See if this is the correct Architecture, if it isn't then we
592 drop the whole section. A missing arch tag only happens (in theory)
593 inside the Status file, so that is a positive return */
596 if (Section
.Find("Architecture",Start
,Stop
) == false)
599 if (stringcmp(Arch
,Start
,Stop
) == 0)
602 if (stringcmp(Start
,Stop
,"all") == 0)
605 iOffset
= Tags
.Offset();
610 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
611 // ---------------------------------------------------------------------
613 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
614 FileFd
&File
, string component
)
616 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
617 pkgTagSection Section
;
618 if (Tags
.Step(Section
) == false)
621 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
622 //FileI->Architecture = WriteUniqString(Arch);
624 // apt-secure does no longer download individual (per-section) Release
625 // file. to provide Component pinning we use the section name now
626 FileI
->Component
= WriteUniqString(component
);
630 if (Section
.Find("Suite",Start
,Stop
) == true)
631 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
632 if (Section
.Find("Component",Start
,Stop
) == true)
633 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
634 if (Section
.Find("Version",Start
,Stop
) == true)
635 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
636 if (Section
.Find("Origin",Start
,Stop
) == true)
637 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
638 if (Section
.Find("Label",Start
,Stop
) == true)
639 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
640 if (Section
.Find("Architecture",Start
,Stop
) == true)
641 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
643 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
644 pkgCache::Flag::NotAutomatic
) == false)
645 _error
->Warning("Bad NotAutomatic flag");
647 return !_error
->PendingError();
650 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
651 // ---------------------------------------------------------------------
653 unsigned char debListParser::GetPrio(string Str
)
656 if (GrabWord(Str
,PrioList
,Out
) == false)
657 Out
= pkgCache::State::Extra
;