]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
c2ae6de9cb70e9314a5f6b65a25cef1aa59d22b1
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.8 1998/07/19 04:42:16 jgg 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>
21 // ListParser::debListParser - Constructor /*{{{*/
22 // ---------------------------------------------------------------------
24 debListParser::debListParser(FileFd
&File
) : Tags(File
)
28 // ListParser::FindTag - Find the tag and return a string /*{{{*/
29 // ---------------------------------------------------------------------
31 string
debListParser::FindTag(const char *Tag
)
35 if (Section
.Find(Tag
,Start
,Stop
) == false)
37 return string(Start
,Stop
- Start
);
40 // ListParser::FindTagI - Find the tag and return an int /*{{{*/
41 // ---------------------------------------------------------------------
43 signed long debListParser::FindTagI(const char *Tag
,signed long Default
)
47 if (Section
.Find(Tag
,Start
,Stop
) == false)
50 // Copy it into a temp buffer so we can use strtol
52 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
54 strncpy(S
,Start
,Stop
-Start
);
58 signed long Result
= strtol(S
,&End
,10);
64 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
65 // ---------------------------------------------------------------------
67 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
71 if (Section
.Find(Tag
,Start
,Stop
) == false)
73 return WriteUniqString(Start
,Stop
- Start
);
76 // ListParser::HandleFlag - Sets a flag variable based on a tag /*{{{*/
77 // ---------------------------------------------------------------------
78 /* This checks the tag for true/false yes/no etc */
79 bool debListParser::HandleFlag(const char *Tag
,unsigned long &Flags
,
84 if (Section
.Find(Tag
,Start
,Stop
) == false)
88 if (stringcasecmp(Start
,Stop
,"yes") == 0)
90 if (stringcasecmp(Start
,Stop
,"true") == 0)
92 if (stringcasecmp(Start
,Stop
,"no") == 0)
94 if (stringcasecmp(Start
,Stop
,"false") == 0)
98 _error
->Warning("Unknown flag value");
109 // ListParser::Package - Return the package name /*{{{*/
110 // ---------------------------------------------------------------------
111 /* This is to return the name of the package this section describes */
112 string
debListParser::Package()
114 string Result
= FindTag("Package");
115 if (Result
.empty() == true)
116 _error
->Error("Encoutered a section with no Package: header");
120 // ListParser::Version - Return the version string /*{{{*/
121 // ---------------------------------------------------------------------
122 /* This is to return the string describing the version in debian form,
123 epoch:upstream-release. If this returns the blank string then the
124 entry is assumed to only describe package properties */
125 string
debListParser::Version()
127 return FindTag("Version");
130 // ListParser::NewVersion - Fill in the version structure /*{{{*/
131 // ---------------------------------------------------------------------
133 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
136 if ((Ver
->Section
= UniqFindTagWrite("Section")) == 0)
137 return _error
->Warning("Missing Section tag");
140 if ((Ver
->Size
= (unsigned)FindTagI("Size")) == 0)
141 return _error
->Error("Unparsable Size field");
143 // Unpacked Size (in K)
144 if ((Ver
->InstalledSize
= (unsigned)FindTagI("Installed-Size")) == 0)
145 return _error
->Error("Unparsable Installed-Size field");
146 Ver
->InstalledSize
*= 1024;
151 if (Section
.Find("Priority",Start
,Stop
) == true)
153 WordList PrioList
[] = {{"important",pkgCache::State::Important
},
154 {"required",pkgCache::State::Required
},
155 {"standard",pkgCache::State::Standard
},
156 {"optional",pkgCache::State::Optional
},
157 {"extra",pkgCache::State::Extra
}};
158 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,
159 _count(PrioList
),Ver
->Priority
) == false)
160 return _error
->Error("Malformed Priority line");
163 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
165 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
167 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
169 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
171 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
173 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Depends
) == false)
176 if (ParseProvides(Ver
) == false)
182 // ListParser::UsePackage - Update a package structure /*{{{*/
183 // ---------------------------------------------------------------------
184 /* This is called to update the package with any new information
185 that might be found in the section */
186 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
187 pkgCache::VerIterator Ver
)
189 if (Pkg
->Section
== 0)
190 if ((Pkg
->Section
= UniqFindTagWrite("Section")) == 0)
192 if (HandleFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
194 if (HandleFlag("Immediate-Configure",Pkg
->Flags
,pkgCache::Flag::ImmediateConf
) == false)
196 if (ParseStatus(Pkg
,Ver
) == false)
201 // ListParser::ParseStatus - Parse the status field /*{{{*/
202 // ---------------------------------------------------------------------
203 /* Status lines are of the form,
204 Status: want flag status
205 want = unknown, install, hold, deinstall, purge
206 flag = ok, reinstreq, hold, hold-reinstreq
207 status = not-installed, unpacked, half-configured, uninstalled,
208 half-installed, config-files, post-inst-failed,
209 removal-failed, installed
211 Some of the above are obsolete (I think?) flag = hold-* and
212 status = post-inst-failed, removal-failed at least.
214 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
215 pkgCache::VerIterator Ver
)
219 if (Section
.Find("Status",Start
,Stop
) == false)
222 // Isolate the first word
223 const char *I
= Start
;
224 for(; I
< Stop
&& *I
!= ' '; I
++);
225 if (I
>= Stop
|| *I
!= ' ')
226 return _error
->Error("Malformed Status line");
228 // Process the want field
229 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
230 {"install",pkgCache::State::Install
},
231 {"hold",pkgCache::State::Hold
},
232 {"deinstall",pkgCache::State::DeInstall
},
233 {"purge",pkgCache::State::Purge
}};
234 if (GrabWord(string(Start
,I
-Start
),WantList
,
235 _count(WantList
),Pkg
->SelectedState
) == false)
236 return _error
->Error("Malformed 1st word in the Status line");
238 // Isloate the next word
241 for(; I
< Stop
&& *I
!= ' '; I
++);
242 if (I
>= Stop
|| *I
!= ' ')
243 return _error
->Error("Malformed status line, no 2nd word");
245 // Process the flag field
246 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
247 {"reinstreq",pkgCache::State::ReInstReq
},
248 {"hold",pkgCache::State::HoldInst
},
249 {"hold-reinstreq",pkgCache::State::HoldReInstReq
}};
250 if (GrabWord(string(Start
,I
-Start
),FlagList
,
251 _count(FlagList
),Pkg
->InstState
) == false)
252 return _error
->Error("Malformed 2nd word in the Status line");
254 // Isloate the last word
257 for(; I
< Stop
&& *I
!= ' '; I
++);
259 return _error
->Error("Malformed Status line, no 3rd word");
261 // Process the flag field
262 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
263 {"unpacked",pkgCache::State::UnPacked
},
264 {"half-configured",pkgCache::State::HalfConfigured
},
265 {"installed",pkgCache::State::Installed
},
266 {"uninstalled",pkgCache::State::UnInstalled
},
267 {"half-installed",pkgCache::State::HalfInstalled
},
268 {"config-files",pkgCache::State::ConfigFiles
},
269 {"post-inst-failed",pkgCache::State::HalfConfigured
},
270 {"removal-failed",pkgCache::State::HalfInstalled
}};
271 if (GrabWord(string(Start
,I
-Start
),StatusList
,
272 _count(StatusList
),Pkg
->CurrentState
) == false)
273 return _error
->Error("Malformed 3rd word in the Status line");
275 /* A Status line marks the package as indicating the current
276 version as well. Only if it is actually installed.. Otherwise
277 the interesting dpkg handling of the status file creates bogus
279 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
280 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
282 if (Ver
.end() == true)
283 _error
->Warning("Encountered status field in a non-version description");
285 Pkg
->CurrentVer
= Ver
.Index();
291 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
292 // ---------------------------------------------------------------------
293 /* This parses the dependency elements out of a standard string in place,
295 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
296 string
&Package
,string
&Ver
,
299 // Strip off leading space
300 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
302 // Parse off the package name
303 const char *I
= Start
;
304 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
305 *I
!= ',' && *I
!= '|'; I
++);
308 if (I
!= Stop
&& *I
== ')')
314 // Stash the package name
315 Package
.assign(Start
,I
- Start
);
317 // Skip white space to the '('
318 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
321 if (I
!= Stop
&& *I
== '(')
324 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
328 // Determine the operator
336 Op
= pkgCache::Dep::LessEq
;
343 Op
= pkgCache::Dep::Less
;
347 // < is the same as <= and << is really Cs < for some reason
348 Op
= pkgCache::Dep::LessEq
;
356 Op
= pkgCache::Dep::GreaterEq
;
363 Op
= pkgCache::Dep::Greater
;
367 // > is the same as >= and >> is really Cs > for some reason
368 Op
= pkgCache::Dep::GreaterEq
;
372 Op
= pkgCache::Dep::Equals
;
376 // HACK around bad package definitions
378 Op
= pkgCache::Dep::Equals
;
383 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
385 for (;I
!= Stop
&& *I
!= ')'; I
++);
386 if (I
== Stop
|| Start
== I
)
389 Ver
= string(Start
,I
-Start
);
395 Op
= pkgCache::Dep::NoOp
;
399 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
400 if (I
!= Stop
&& *I
== '|')
401 Op
|= pkgCache::Dep::Or
;
403 if (I
== Stop
|| *I
== ',' || *I
== '|')
406 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
413 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
414 // ---------------------------------------------------------------------
415 /* This is the higher level depends parser. It takes a tag and generates
416 a complete depends tree for the given version. */
417 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
418 const char *Tag
,unsigned int Type
)
422 if (Section
.Find(Tag
,Start
,Stop
) == false)
431 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
433 return _error
->Error("Problem parsing dependency %s",Tag
);
435 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
443 // ListParser::ParseProvides - Parse the provides list /*{{{*/
444 // ---------------------------------------------------------------------
446 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
450 if (Section
.Find("Provides",Start
,Stop
) == false)
459 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
461 return _error
->Error("Problem parsing Provides line");
462 if (Op
!= pkgCache::Dep::NoOp
)
463 return _error
->Error("Malformed provides line");
465 if (NewProvides(Ver
,Package
,Version
) == false)
475 // ListParser::GrabWord - Matches a word and returns /*{{{*/
476 // ---------------------------------------------------------------------
477 /* Looks for a word in a list of words - for ParseStatus */
478 bool debListParser::GrabWord(string Word
,WordList
*List
,int Count
,
481 for (int C
= 0; C
!= Count
; C
++)
483 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
492 // ListParser::Step - Move to the next section in the file /*{{{*/
493 // ---------------------------------------------------------------------
494 /* This has to be carefull to only process the correct architecture */
495 bool debListParser::Step()
497 iOffset
= Tags
.Offset();
498 string Arch
= _config
->Find("APT::architecture");
499 while (Tags
.Step(Section
) == true)
501 /* See if this is the correct Architecture, if it isnt then we
502 drop the whole section */
505 if (Section
.Find("Architecture",Start
,Stop
) == false)
508 if (stringcmp(Start
,Stop
,Arch
.begin(),Arch
.end()) == 0)
511 if (stringcmp(Start
,Stop
,"all") == 0)
514 iOffset
= Tags
.Offset();