]>
git.saurik.com Git - apt-legacy.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>
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
)
78 Ver
->Section
= UniqFindTagWrite("Section");
79 Ver
->Arch
= UniqFindTagWrite("Architecture");
82 Ver
->Size
= (unsigned)Section
.FindI("Size");
84 // Unpacked Size (in K)
85 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
86 Ver
->InstalledSize
*= 1024;
91 if (Section
.Find("Priority",Start
,Stop
) == true)
93 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,Ver
->Priority
) == false)
94 Ver
->Priority
= pkgCache::State::Extra
;
97 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
99 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
101 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
103 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
105 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
107 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
111 if (ParseDepends(Ver
,"Optional",pkgCache::Dep::Suggests
) == false)
114 if (ParseProvides(Ver
) == false)
120 // ListParser::UsePackage - Update a package structure /*{{{*/
121 // ---------------------------------------------------------------------
122 /* This is called to update the package with any new information
123 that might be found in the section */
124 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
125 pkgCache::VerIterator Ver
)
127 if (Pkg
->Section
== 0)
128 Pkg
->Section
= UniqFindTagWrite("Section");
129 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
131 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
134 if (strcmp(Pkg
.Name(),"apt") == 0)
135 Pkg
->Flags
|= pkgCache::Flag::Important
;
137 if (ParseStatus(Pkg
,Ver
) == false)
142 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
143 // ---------------------------------------------------------------------
145 unsigned short debListParser::VersionHash()
147 const char *Sections
[] ={"Installed-Size",
154 unsigned long Result
= INIT_FCS
;
156 for (const char **I
= Sections
; *I
!= 0; I
++)
160 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
163 /* Strip out any spaces from the text, this undoes dpkgs reformatting
164 of certain fields. dpkg also has the rather interesting notion of
165 reformatting depends operators < -> <= */
167 for (; Start
!= End
; Start
++)
169 if (isspace(*Start
) == 0)
170 *I
++ = tolower(*Start
);
171 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
173 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
177 Result
= AddCRC16(Result
,S
,I
- S
);
183 // ListParser::ParseStatus - Parse the status field /*{{{*/
184 // ---------------------------------------------------------------------
185 /* Status lines are of the form,
186 Status: want flag status
187 want = unknown, install, hold, deinstall, purge
188 flag = ok, reinstreq, hold, hold-reinstreq
189 status = not-installed, unpacked, half-configured,
190 half-installed, config-files, post-inst-failed,
191 removal-failed, installed
193 Some of the above are obsolete (I think?) flag = hold-* and
194 status = post-inst-failed, removal-failed at least.
196 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
197 pkgCache::VerIterator Ver
)
201 if (Section
.Find("Status",Start
,Stop
) == false)
204 // Isolate the first word
205 const char *I
= Start
;
206 for(; I
< Stop
&& *I
!= ' '; I
++);
207 if (I
>= Stop
|| *I
!= ' ')
208 return _error
->Error("Malformed Status line");
210 // Process the want field
211 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
212 {"install",pkgCache::State::Install
},
213 {"hold",pkgCache::State::Hold
},
214 {"deinstall",pkgCache::State::DeInstall
},
215 {"purge",pkgCache::State::Purge
},
217 if (GrabWord(string(Start
,I
-Start
),WantList
,Pkg
->SelectedState
) == false)
218 return _error
->Error("Malformed 1st word in the Status line");
220 // Isloate the next word
223 for(; I
< Stop
&& *I
!= ' '; I
++);
224 if (I
>= Stop
|| *I
!= ' ')
225 return _error
->Error("Malformed status line, no 2nd word");
227 // Process the flag field
228 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
229 {"reinstreq",pkgCache::State::ReInstReq
},
230 {"hold",pkgCache::State::HoldInst
},
231 {"hold-reinstreq",pkgCache::State::HoldReInstReq
},
233 if (GrabWord(string(Start
,I
-Start
),FlagList
,Pkg
->InstState
) == false)
234 return _error
->Error("Malformed 2nd word in the Status line");
236 // Isloate the last word
239 for(; I
< Stop
&& *I
!= ' '; I
++);
241 return _error
->Error("Malformed Status line, no 3rd word");
243 // Process the flag field
244 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
245 {"unpacked",pkgCache::State::UnPacked
},
246 {"half-configured",pkgCache::State::HalfConfigured
},
247 {"installed",pkgCache::State::Installed
},
248 {"half-installed",pkgCache::State::HalfInstalled
},
249 {"config-files",pkgCache::State::ConfigFiles
},
250 {"post-inst-failed",pkgCache::State::HalfConfigured
},
251 {"removal-failed",pkgCache::State::HalfInstalled
},
253 if (GrabWord(string(Start
,I
-Start
),StatusList
,Pkg
->CurrentState
) == false)
254 return _error
->Error("Malformed 3rd word in the Status line");
256 /* A Status line marks the package as indicating the current
257 version as well. Only if it is actually installed.. Otherwise
258 the interesting dpkg handling of the status file creates bogus
260 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
261 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
263 if (Ver
.end() == true)
264 _error
->Warning("Encountered status field in a non-version description");
266 Pkg
->CurrentVer
= Ver
.Index();
272 const char *debListParser::ConvertRelation(const char *I
,unsigned int &Op
)
274 // Determine the operator
282 Op
= pkgCache::Dep::LessEq
;
289 Op
= pkgCache::Dep::Less
;
293 // < is the same as <= and << is really Cs < for some reason
294 Op
= pkgCache::Dep::LessEq
;
302 Op
= pkgCache::Dep::GreaterEq
;
309 Op
= pkgCache::Dep::Greater
;
313 // > is the same as >= and >> is really Cs > for some reason
314 Op
= pkgCache::Dep::GreaterEq
;
318 Op
= pkgCache::Dep::Equals
;
322 // HACK around bad package definitions
324 Op
= pkgCache::Dep::Equals
;
331 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
332 // ---------------------------------------------------------------------
333 /* This parses the dependency elements out of a standard string in place,
335 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
336 string
&Package
,string
&Ver
,
337 unsigned int &Op
, bool ParseArchFlags
)
339 // Strip off leading space
340 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
342 // Parse off the package name
343 const char *I
= Start
;
344 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
345 *I
!= ',' && *I
!= '|'; I
++);
348 if (I
!= Stop
&& *I
== ')')
354 // Stash the package name
355 Package
.assign(Start
,I
- Start
);
357 // Skip white space to the '('
358 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
361 if (I
!= Stop
&& *I
== '(')
364 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
367 I
= ConvertRelation(I
,Op
);
370 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
372 for (;I
!= Stop
&& *I
!= ')'; I
++);
373 if (I
== Stop
|| Start
== I
)
376 // Skip trailing whitespace
378 for (; End
> Start
&& isspace(End
[-1]); End
--);
380 Ver
.assign(Start
,End
-Start
);
386 Op
= pkgCache::Dep::NoOp
;
390 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
392 if (ParseArchFlags
== true)
394 string arch
= _config
->Find("APT::Architecture");
396 // Parse an architecture
397 if (I
!= Stop
&& *I
== '[')
406 bool NegArch
= false;
409 // look for whitespace or ending ']'
410 while (End
!= Stop
&& !isspace(*End
) && *End
!= ']')
422 if (stringcmp(arch
,I
,End
) == 0)
431 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
438 Package
= ""; /* not for this arch */
442 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
445 if (I
!= Stop
&& *I
== '|')
446 Op
|= pkgCache::Dep::Or
;
448 if (I
== Stop
|| *I
== ',' || *I
== '|')
451 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
458 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
459 // ---------------------------------------------------------------------
460 /* This is the higher level depends parser. It takes a tag and generates
461 a complete depends tree for the given version. */
462 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
463 const char *Tag
,unsigned int Type
)
467 if (Section
.Find(Tag
,Start
,Stop
) == false)
476 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
478 return _error
->Error("Problem parsing dependency %s",Tag
);
480 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
488 // ListParser::ParseProvides - Parse the provides list /*{{{*/
489 // ---------------------------------------------------------------------
491 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
495 if (Section
.Find("Provides",Start
,Stop
) == false)
504 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
506 return _error
->Error("Problem parsing Provides line");
507 if (Op
!= pkgCache::Dep::NoOp
) {
508 _error
->Warning("Ignoring Provides line with DepCompareOp for package %s", Package
.c_str());
510 if (NewProvides(Ver
,Package
,Version
) == false)
521 // ListParser::GrabWord - Matches a word and returns /*{{{*/
522 // ---------------------------------------------------------------------
523 /* Looks for a word in a list of words - for ParseStatus */
524 bool debListParser::GrabWord(string Word
,WordList
*List
,unsigned char &Out
)
526 for (unsigned int C
= 0; List
[C
].Str
!= 0; C
++)
528 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
537 // ListParser::Step - Move to the next section in the file /*{{{*/
538 // ---------------------------------------------------------------------
539 /* This has to be carefull to only process the correct architecture */
540 bool debListParser::Step()
542 iOffset
= Tags
.Offset();
543 while (Tags
.Step(Section
) == true)
545 /* See if this is the correct Architecture, if it isn't then we
546 drop the whole section. A missing arch tag only happens (in theory)
547 inside the Status file, so that is a positive return */
550 if (Section
.Find("Architecture",Start
,Stop
) == false)
553 if (stringcmp(Arch
,Start
,Stop
) == 0)
556 if (stringcmp(Start
,Stop
,"all") == 0)
559 iOffset
= Tags
.Offset();
564 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
565 // ---------------------------------------------------------------------
567 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
568 FileFd
&File
, string component
)
570 pkgTagFile
Tags(&File
, File
.Size() + 256); // XXX
571 pkgTagSection Section
;
572 if (Tags
.Step(Section
) == false)
575 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
576 //FileI->Architecture = WriteUniqString(Arch);
578 // apt-secure does no longer download individual (per-section) Release
579 // file. to provide Component pinning we use the section name now
580 FileI
->Component
= WriteUniqString(component
);
584 if (Section
.Find("Suite",Start
,Stop
) == true)
585 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
586 if (Section
.Find("Component",Start
,Stop
) == true)
587 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
588 if (Section
.Find("Version",Start
,Stop
) == true)
589 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
590 if (Section
.Find("Origin",Start
,Stop
) == true)
591 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
592 if (Section
.Find("Label",Start
,Stop
) == true)
593 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
594 if (Section
.Find("Architecture",Start
,Stop
) == true)
595 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
597 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
598 pkgCache::Flag::NotAutomatic
) == false)
599 _error
->Warning("Bad NotAutomatic flag");
601 return !_error
->PendingError();
604 // ListParser::GetPrio - Convert the priority from a string /*{{{*/
605 // ---------------------------------------------------------------------
607 unsigned char debListParser::GetPrio(string Str
)
610 if (GrabWord(Str
,PrioList
,Out
) == false)
611 Out
= pkgCache::State::Extra
;