]>
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
,"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_ascii(*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 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
297 {"triggers-pending",pkgCache::State::TriggersPending
},
298 {"post-inst-failed",pkgCache::State::HalfConfigured
},
299 {"removal-failed",pkgCache::State::HalfInstalled
},
301 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
302 return _error
->Error("Malformed 3rd word in the Status line");
304 /* A Status line marks the package as indicating the current
305 version as well. Only if it is actually installed.. Otherwise
306 the interesting dpkg handling of the status file creates bogus
308 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
309 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
311 if (Ver
.end() == true)
312 _error
->Warning("Encountered status field in a non-version description");
314 Pkg
->CurrentVer
= Ver
.Index();
320 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
322 // Determine the operator
330 Op
= pkgCache::Dep::LessEq
;
337 Op
= pkgCache::Dep::Less
;
341 // < is the same as <= and << is really Cs < for some reason
342 Op
= pkgCache::Dep::LessEq
;
350 Op
= pkgCache::Dep::GreaterEq
;
357 Op
= pkgCache::Dep::Greater
;
361 // > is the same as >= and >> is really Cs > for some reason
362 Op
= pkgCache::Dep::GreaterEq
;
366 Op
= pkgCache::Dep::Equals
;
370 // HACK around bad package definitions
372 Op
= pkgCache::Dep::Equals
;
379 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
380 // ---------------------------------------------------------------------
381 /* This parses the dependency elements out of a standard string in place,
383 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
384 string
&Package
,string
&Ver
,
385 unsigned int &Op
, bool ParseArchFlags
)
387 // Strip off leading space
388 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
390 // Parse off the package name
391 const char *I
= Start
;
392 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
393 *I
!= ',' && *I
!= '|'; I
++);
396 if (I
!= Stop
&& *I
== ')')
402 // Stash the package name
403 Package
.assign(Start
,I
- Start
);
405 // Skip white space to the '('
406 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
409 if (I
!= Stop
&& *I
== '(')
412 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
415 I
= ConvertRelation(I
,Op
);
418 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
420 for (;I
!= Stop
&& *I
!= ')'; I
++);
421 if (I
== Stop
|| Start
== I
)
424 // Skip trailing whitespace
426 for (; End
> Start
&& isspace(End
[-1]); End
--);
428 Ver
.assign(Start
,End
-Start
);
434 Op
= pkgCache::Dep::NoOp
;
438 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
440 if (ParseArchFlags
== true)
442 string arch
= _config
->Find("APT::Architecture");
444 // Parse an architecture
445 if (I
!= Stop
&& *I
== '[')
454 bool NegArch
= false;
457 // look for whitespace or ending ']'
458 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
470 if (stringcmp(arch
,I
,End
) == 0)
479 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
486 Package
= ""; /* not for this arch */
490 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
493 if (I
!= Stop
&& *I
== '|')
494 Op
|= pkgCache::Dep::Or
;
496 if (I
== Stop
|| *I
== ',' || *I
== '|')
499 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
506 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
507 // ---------------------------------------------------------------------
508 /* This is the higher level depends parser. It takes a tag and generates
509 a complete depends tree for the given version. */
510 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
511 const char *Tag
,unsigned int Type
)
515 if (Section
.Find(Tag
,Start
,Stop
) == false)
524 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
526 return _error
->Error("Problem parsing dependency %s",Tag
);
528 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
536 // ListParser::ParseProvides - Parse the provides list /*{{{*/
537 // ---------------------------------------------------------------------
539 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
543 if (Section
.Find("Provides",Start
,Stop
) == false)
552 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
554 return _error
->Error("Problem parsing Provides line");
555 if (Op
!= pkgCache::Dep::NoOp
) {
556 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
558 if (NewProvides(Ver
,Package
,Version
) == false)
569 // ListParser::GrabWord - Matches a word and returns /*{{{*/
570 // ---------------------------------------------------------------------
571 /* Looks for a word in a list of words - for ParseStatus */
572 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
574 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
576 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
585 // ListParser::Step - Move to the next section in the file /*{{{*/
586 // ---------------------------------------------------------------------
587 /* This has to be carefull to only process the correct architecture */
588 bool debListParser::Step()
590 iOffset
= Tags
.Offset();
591 while (Tags
.Step(Section
) == true)
593 /* See if this is the correct Architecture, if it isn't then we
594 drop the whole section. A missing arch tag only happens (in theory)
595 inside the Status file, so that is a positive return */
598 if (Section
.Find("Architecture",Start
,Stop
) == false)
601 if (stringcmp(Arch
,Start
,Stop
) == 0)
604 if (stringcmp(Start
,Stop
,"all") == 0)
607 iOffset
= Tags
.Offset();
612 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
613 // ---------------------------------------------------------------------
615 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
616 FileFd
&File
, string component
)
618 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
619 pkgTagSection Section
;
620 if (Tags
.Step(Section
) == false)
623 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
624 //FileI->Architecture = WriteUniqString(Arch);
626 // apt-secure does no longer download individual (per-section) Release
627 // file. to provide Component pinning we use the section name now
628 FileI
->Component
= WriteUniqString(component
);
632 if (Section
.Find("Suite",Start
,Stop
) == true)
633 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
634 if (Section
.Find("Component",Start
,Stop
) == true)
635 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
636 if (Section
.Find("Version",Start
,Stop
) == true)
637 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
638 if (Section
.Find("Origin",Start
,Stop
) == true)
639 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
640 if (Section
.Find("Label",Start
,Stop
) == true)
641 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
642 if (Section
.Find("Architecture",Start
,Stop
) == true)
643 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
645 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
646 pkgCache::Flag::NotAutomatic
) == false)
647 _error
->Warning("Bad NotAutomatic flag");
649 return !_error
->PendingError();
652 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
653 // ---------------------------------------------------------------------
655 unsigned char debListParser::GetPrio(string Str
)
658 if (GrabWord(Str
,PrioList
,Out
) == false)
659 Out
= pkgCache::State::Extra
;