]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/deb/deblistparser.cc
afc91633555ba2a23440566e82603447e8d414b6
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
)
78 Ver
->Display
= UniqFindTagWrite("Name");
79 if (Ver
->Display
== 0)
80 Ver
->Display
= UniqFindTagWrite("Maemo-Display-Name");
83 Ver
->Section
= UniqFindTagWrite("Section");
84 Ver
->Arch
= UniqFindTagWrite("Architecture");
87 Ver
->Size
= (unsigned)Section
.FindI("Size");
89 // Unpacked Size (in K)
90 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
91 Ver
->InstalledSize
*= 1024;
96 if (Section
.Find("Priority",Start
,Stop
) == true)
98 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
99 Ver
->Priority
= pkgCache::State::Extra
;
102 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
104 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
106 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
108 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
110 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
112 if (ParseDepends(Ver
,"Breaks",pkgCache::Dep::DpkgBreaks
) == false)
114 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
118 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
121 if (ParseProvides(Ver
) == false)
127 // ListParser::Description - Return the description string /*{{{*/
128 // ---------------------------------------------------------------------
129 /* This is to return the string describing the package in debian
130 form. If this returns the blank string then the entry is assumed to
131 only describe package properties */
132 string
debListParser::Description()
134 if (DescriptionLanguage().empty())
135 return Section
.FindS("Description");
137 return Section
.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
140 // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
141 // ---------------------------------------------------------------------
142 /* This is to return the string describing the language of
143 description. If this returns the blank string then the entry is
144 assumed to describe original description. */
145 string
debListParser::DescriptionLanguage()
147 return Section
.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
150 // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
151 // ---------------------------------------------------------------------
152 /* This is to return the md5 string to allow the check if it is the right
153 description. If no Description-md5 is found in the section it will be
156 MD5SumValue
debListParser::Description_md5()
158 string value
= Section
.FindS("Description-md5");
163 md5
.Add((Description() + "\n").c_str());
166 return MD5SumValue(value
);
169 // ListParser::UsePackage - Update a package structure /*{{{*/
170 // ---------------------------------------------------------------------
171 /* This is called to update the package with any new information
172 that might be found in the section */
173 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
174 pkgCache::VerIterator Ver
)
176 if (Pkg
->Display
== 0)
177 Pkg
->Display
= UniqFindTagWrite("Name");
178 if (Pkg
->Display
== 0)
179 Pkg
->Display
= UniqFindTagWrite("Maemo-Display-Name");
180 if (Pkg
->Section
== 0)
181 Pkg
->Section
= UniqFindTagWrite("Section");
182 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
184 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
187 if (strcmp(Pkg
.Name(),"apt") == 0)
188 Pkg
->Flags
|= pkgCache::Flag::Important
;
190 if (ParseStatus(Pkg
,Ver
) == false)
193 if (Pkg
->TagList
== 0)
194 if (ParseTag(Pkg
) == false)
200 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
201 // ---------------------------------------------------------------------
203 unsigned short debListParser::VersionHash()
205 const char *Sections
[] ={"Installed-Size",
213 unsigned long Result
= INIT_FCS
;
215 for (const char **I
= Sections
; *I
!= 0; I
++)
219 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
222 /* Strip out any spaces from the text, this undoes dpkgs reformatting
223 of certain fields. dpkg also has the rather interesting notion of
224 reformatting depends operators < -> <= */
226 for (; Start
!= End
; Start
++)
228 if (isspace(*Start
) == 0)
229 *I
++ = tolower(*Start
);
230 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
232 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
236 Result
= AddCRC16(Result
,S
,I
- S
);
242 // ListParser::ParseStatus - Parse the status field /*{{{*/
243 // ---------------------------------------------------------------------
244 /* Status lines are of the form,
245 Status: want flag status
246 want = unknown, install, hold, deinstall, purge
247 flag = ok, reinstreq, hold, hold-reinstreq
248 status = not-installed, unpacked, half-configured,
249 half-installed, config-files, post-inst-failed,
250 removal-failed, installed
252 Some of the above are obsolete (I think?) flag = hold-* and
253 status = post-inst-failed, removal-failed at least.
255 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
256 pkgCache::VerIterator Ver
)
260 if (Section
.Find("Status",Start
,Stop
) == false)
263 // Isolate the first word
264 const char *I
= Start
;
265 for(; I
< Stop
&& *I
!= ' '; I
++);
266 if (I
>= Stop
|| *I
!= ' ')
267 return _error
->Error("Malformed Status line");
269 // Process the want field
270 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
271 {"install",pkgCache::State::Install
},
272 {"hold",pkgCache::State::Hold
},
273 {"deinstall",pkgCache::State::DeInstall
},
274 {"purge",pkgCache::State::Purge
},
276 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
277 return _error
->Error("Malformed 1st word in the Status line");
279 // Isloate the next word
282 for(; I
< Stop
&& *I
!= ' '; I
++);
283 if (I
>= Stop
|| *I
!= ' ')
284 return _error
->Error("Malformed status line, no 2nd word");
286 // Process the flag field
287 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
288 {"reinstreq",pkgCache::State::ReInstReq
},
289 {"hold",pkgCache::State::HoldInst
},
290 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
292 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
293 return _error
->Error("Malformed 2nd word in the Status line");
295 // Isloate the last word
298 for(; I
< Stop
&& *I
!= ' '; I
++);
300 return _error
->Error("Malformed Status line, no 3rd word");
302 // Process the flag field
303 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
304 {"unpacked",pkgCache::State::UnPacked
},
305 {"half-configured",pkgCache::State::HalfConfigured
},
306 {"installed",pkgCache::State::Installed
},
307 {"half-installed",pkgCache::State::HalfInstalled
},
308 {"config-files",pkgCache::State::ConfigFiles
},
309 {"triggers-awaited",pkgCache::State::TriggersAwaited
},
310 {"triggers-pending",pkgCache::State::TriggersPending
},
311 {"post-inst-failed",pkgCache::State::HalfConfigured
},
312 {"removal-failed",pkgCache::State::HalfInstalled
},
314 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
315 return _error
->Error("Malformed 3rd word in the Status line");
317 /* A Status line marks the package as indicating the current
318 version as well. Only if it is actually installed.. Otherwise
319 the interesting dpkg handling of the status file creates bogus
321 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
322 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
324 if (Ver
.end() == true)
325 _error
->Warning("Encountered status field in a non-version description");
327 Pkg
->CurrentVer
= Ver
.Index();
333 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
335 // Determine the operator
343 Op
= pkgCache::Dep::LessEq
;
350 Op
= pkgCache::Dep::Less
;
354 // < is the same as <= and << is really Cs < for some reason
355 Op
= pkgCache::Dep::LessEq
;
363 Op
= pkgCache::Dep::GreaterEq
;
370 Op
= pkgCache::Dep::Greater
;
374 // > is the same as >= and >> is really Cs > for some reason
375 Op
= pkgCache::Dep::GreaterEq
;
379 Op
= pkgCache::Dep::Equals
;
383 // HACK around bad package definitions
385 Op
= pkgCache::Dep::Equals
;
392 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
393 // ---------------------------------------------------------------------
394 /* This parses the dependency elements out of a standard string in place,
396 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
397 string
&Package
,string
&Ver
,
398 unsigned int &Op
, bool ParseArchFlags
)
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 // Skip white space to the '('
419 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
422 if (I
!= Stop
&& *I
== '(')
425 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
428 I
= ConvertRelation(I
,Op
);
431 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
433 for (;I
!= Stop
&& *I
!= ')'; I
++);
434 if (I
== Stop
|| Start
== I
)
437 // Skip trailing whitespace
439 for (; End
> Start
&& isspace(End
[-1]); End
--);
441 Ver
.assign(Start
,End
-Start
);
447 Op
= pkgCache::Dep::NoOp
;
451 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
453 if (ParseArchFlags
== true)
455 string arch
= _config
->Find("APT::Architecture");
457 // Parse an architecture
458 if (I
!= Stop
&& *I
== '[')
467 bool NegArch
= false;
470 // look for whitespace or ending ']'
471 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
483 if (stringcmp(arch
,I
,End
) == 0)
492 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
499 Package
= ""; /* not for this arch */
503 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
506 if (I
!= Stop
&& *I
== '|')
507 Op
|= pkgCache::Dep::Or
;
509 if (I
== Stop
|| *I
== ',' || *I
== '|')
512 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
519 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
520 // ---------------------------------------------------------------------
521 /* This is the higher level depends parser. It takes a tag and generates
522 a complete depends tree for the given version. */
523 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
524 const char *Tag
,unsigned int Type
)
528 if (Section
.Find(Tag
,Start
,Stop
) == false)
537 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
539 return _error
->Error("Problem parsing dependency %s",Tag
);
541 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
549 // ListParser::ParseProvides - Parse the provides list /*{{{*/
550 // ---------------------------------------------------------------------
552 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
556 if (Section
.Find("Provides",Start
,Stop
) == false)
565 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
567 return _error
->Error("Problem parsing Provides line");
568 if (Op
!= pkgCache::Dep::NoOp
) {
569 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
571 if (NewProvides(Ver
,Package
,Version
) == false)
582 // ListParser::ParseTag - Parse the tag list /*{{{*/
583 // ---------------------------------------------------------------------
585 bool debListParser::ParseTag(pkgCache::PkgIterator Pkg
)
589 if (Section
.Find("Tag",Start
,Stop
) == false)
596 if (Stop
[-1] != ' ' && Stop
[-1] != '\t')
601 const char *Begin
= Stop
- 1;
602 while (Begin
!= Start
&& Begin
[-1] != ' ' && Begin
[-1] != ',')
605 if (NewTag(Pkg
, Begin
, Stop
- Begin
) == false)
611 if (Begin
[-1] == ',')
622 // ListParser::GrabWord - Matches a word and returns /*{{{*/
623 // ---------------------------------------------------------------------
624 /* Looks for a word in a list of words - for ParseStatus */
625 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
627 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
629 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
638 // ListParser::Step - Move to the next section in the file /*{{{*/
639 // ---------------------------------------------------------------------
640 /* This has to be carefull to only process the correct architecture */
641 bool debListParser::Step()
643 iOffset
= Tags
.Offset();
644 while (Tags
.Step(Section
) == true)
649 if (Section
.Find("Package",Start
,Stop
) == false) {
650 _error
->Warning("Encountered a section with no Package: header");
654 /* See if this is the correct Architecture, if it isn't then we
655 drop the whole section. A missing arch tag only happens (in theory)
656 inside the Status file, so that is a positive return */
658 if (Section
.Find("Architecture",Start
,Stop
) == false)
661 if (stringcmp(Arch
,Start
,Stop
) == 0)
664 if (stringcmp(Start
,Stop
,"all") == 0)
667 iOffset
= Tags
.Offset();
672 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
673 // ---------------------------------------------------------------------
675 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
676 FileFd
&File
, string component
)
678 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
679 pkgTagSection Section
;
680 if (Tags
.Step(Section
) == false)
683 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
684 //FileI->Architecture = WriteUniqString(Arch);
686 // apt-secure does no longer download individual (per-section) Release
687 // file. to provide Component pinning we use the section name now
688 FileI
->Component
= WriteUniqString(component
);
692 if (Section
.Find("Suite",Start
,Stop
) == true)
693 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
694 if (Section
.Find("Component",Start
,Stop
) == true)
695 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
696 if (Section
.Find("Version",Start
,Stop
) == true)
697 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
698 if (Section
.Find("Origin",Start
,Stop
) == true)
699 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
700 if (Section
.Find("Label",Start
,Stop
) == true)
701 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
702 if (Section
.Find("Architecture",Start
,Stop
) == true)
703 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
705 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
706 pkgCache::Flag::NotAutomatic
) == false)
707 _error
->Warning("Bad NotAutomatic flag");
709 return !_error
->PendingError();
712 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
713 // ---------------------------------------------------------------------
715 unsigned char debListParser::GetPrio(string Str
)
718 if (GrabWord(Str
,PrioList
,Out
) == false)
719 Out
= pkgCache::State::Extra
;