]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/deblistparser.cc
Fixed size mismatch
[apt.git] / apt-pkg / deb / deblistparser.cc
CommitLineData
f55a958f
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
138d4b3d 3// $Id: deblistparser.cc,v 1.17 1999/02/21 08:38:53 jgg Exp $
f55a958f
AL
4/* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
094a497d
AL
13#include <apt-pkg/deblistparser.h>
14#include <apt-pkg/error.h>
15#include <apt-pkg/configuration.h>
cdcc6d34 16#include <apt-pkg/strutl.h>
9c14e3d6 17
f55a958f
AL
18#include <system.h>
19 /*}}}*/
20
21// ListParser::debListParser - Constructor /*{{{*/
22// ---------------------------------------------------------------------
23/* */
8e06abb2 24debListParser::debListParser(FileFd &File) : Tags(File)
f55a958f 25{
0149949b
AL
26}
27 /*}}}*/
f55a958f
AL
28// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
29// ---------------------------------------------------------------------
30/* */
31unsigned long debListParser::UniqFindTagWrite(const char *Tag)
32{
33 const char *Start;
34 const char *Stop;
35 if (Section.Find(Tag,Start,Stop) == false)
36 return 0;
37 return WriteUniqString(Start,Stop - Start);
38}
39 /*}}}*/
f55a958f
AL
40// ListParser::Package - Return the package name /*{{{*/
41// ---------------------------------------------------------------------
42/* This is to return the name of the package this section describes */
43string debListParser::Package()
44{
b0b4efb9 45 string Result = Section.FindS("Package");
f55a958f 46 if (Result.empty() == true)
65a1e968 47 _error->Error("Encountered a section with no Package: header");
f55a958f
AL
48 return Result;
49}
50 /*}}}*/
51// ListParser::Version - Return the version string /*{{{*/
52// ---------------------------------------------------------------------
53/* This is to return the string describing the version in debian form,
54 epoch:upstream-release. If this returns the blank string then the
55 entry is assumed to only describe package properties */
56string debListParser::Version()
57{
b0b4efb9 58 return Section.FindS("Version");
f55a958f
AL
59}
60 /*}}}*/
f55a958f
AL
61// ListParser::NewVersion - Fill in the version structure /*{{{*/
62// ---------------------------------------------------------------------
63/* */
64bool debListParser::NewVersion(pkgCache::VerIterator Ver)
0149949b
AL
65{
66 // Parse the section
b35d2f5f 67 Ver->Section = UniqFindTagWrite("Section");
17caf1b1 68 Ver->Arch = UniqFindTagWrite("Architecture");
0149949b
AL
69
70 // Archive Size
b0b4efb9 71 Ver->Size = (unsigned)Section.FindI("Size");
0149949b
AL
72
73 // Unpacked Size (in K)
b0b4efb9 74 Ver->InstalledSize = (unsigned)Section.FindI("Installed-Size");
0149949b
AL
75 Ver->InstalledSize *= 1024;
76
77 // Priority
78 const char *Start;
79 const char *Stop;
80 if (Section.Find("Priority",Start,Stop) == true)
81 {
6c139d6e
AL
82 WordList PrioList[] = {{"important",pkgCache::State::Important},
83 {"required",pkgCache::State::Required},
84 {"standard",pkgCache::State::Standard},
85 {"optional",pkgCache::State::Optional},
86 {"extra",pkgCache::State::Extra}};
0149949b
AL
87 if (GrabWord(string(Start,Stop-Start),PrioList,
88 _count(PrioList),Ver->Priority) == false)
89 return _error->Error("Malformed Priority line");
90 }
dcb79bae 91
6c139d6e 92 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
dcb79bae 93 return false;
8efa2a3b 94 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
dcb79bae 95 return false;
6c139d6e 96 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
dcb79bae 97 return false;
6c139d6e 98 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
dcb79bae 99 return false;
6c139d6e 100 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
dcb79bae 101 return false;
f55ece0e 102 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
dcb79bae
AL
103 return false;
104
105 if (ParseProvides(Ver) == false)
106 return false;
0149949b 107
f55a958f
AL
108 return true;
109}
110 /*}}}*/
111// ListParser::UsePackage - Update a package structure /*{{{*/
112// ---------------------------------------------------------------------
113/* This is called to update the package with any new information
114 that might be found in the section */
115bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
116 pkgCache::VerIterator Ver)
117{
118 if (Pkg->Section == 0)
b35d2f5f 119 Pkg->Section = UniqFindTagWrite("Section");
b0b4efb9 120 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
f55a958f 121 return false;
138d4b3d 122 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
f55a958f 123 return false;
138d4b3d
AL
124
125 if (strcmp(Pkg.Name(),"apt") == 0)
126 Pkg->Flags |= pkgCache::Flag::Important;
127
f55a958f
AL
128 if (ParseStatus(Pkg,Ver) == false)
129 return false;
130 return true;
131}
132 /*}}}*/
dcb79bae 133// ListParser::ParseStatus - Parse the status field /*{{{*/
f55a958f
AL
134// ---------------------------------------------------------------------
135/* Status lines are of the form,
136 Status: want flag status
137 want = unknown, install, hold, deinstall, purge
138 flag = ok, reinstreq, hold, hold-reinstreq
139 status = not-installed, unpacked, half-configured, uninstalled,
140 half-installed, config-files, post-inst-failed,
141 removal-failed, installed
142
143 Some of the above are obsolete (I think?) flag = hold-* and
144 status = post-inst-failed, removal-failed at least.
145 */
146bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
147 pkgCache::VerIterator Ver)
148{
149 const char *Start;
150 const char *Stop;
151 if (Section.Find("Status",Start,Stop) == false)
152 return true;
153
154 // Isolate the first word
155 const char *I = Start;
156 for(; I < Stop && *I != ' '; I++);
157 if (I >= Stop || *I != ' ')
158 return _error->Error("Malformed Status line");
159
160 // Process the want field
6c139d6e
AL
161 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
162 {"install",pkgCache::State::Install},
163 {"hold",pkgCache::State::Hold},
164 {"deinstall",pkgCache::State::DeInstall},
165 {"purge",pkgCache::State::Purge}};
f55a958f
AL
166 if (GrabWord(string(Start,I-Start),WantList,
167 _count(WantList),Pkg->SelectedState) == false)
168 return _error->Error("Malformed 1st word in the Status line");
169
170 // Isloate the next word
171 I++;
172 Start = I;
173 for(; I < Stop && *I != ' '; I++);
174 if (I >= Stop || *I != ' ')
175 return _error->Error("Malformed status line, no 2nd word");
176
177 // Process the flag field
6c139d6e
AL
178 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
179 {"reinstreq",pkgCache::State::ReInstReq},
180 {"hold",pkgCache::State::HoldInst},
181 {"hold-reinstreq",pkgCache::State::HoldReInstReq}};
f55a958f
AL
182 if (GrabWord(string(Start,I-Start),FlagList,
183 _count(FlagList),Pkg->InstState) == false)
184 return _error->Error("Malformed 2nd word in the Status line");
185
186 // Isloate the last word
187 I++;
188 Start = I;
189 for(; I < Stop && *I != ' '; I++);
190 if (I != Stop)
191 return _error->Error("Malformed Status line, no 3rd word");
192
193 // Process the flag field
6c139d6e
AL
194 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
195 {"unpacked",pkgCache::State::UnPacked},
196 {"half-configured",pkgCache::State::HalfConfigured},
197 {"installed",pkgCache::State::Installed},
198 {"uninstalled",pkgCache::State::UnInstalled},
199 {"half-installed",pkgCache::State::HalfInstalled},
200 {"config-files",pkgCache::State::ConfigFiles},
201 {"post-inst-failed",pkgCache::State::HalfConfigured},
202 {"removal-failed",pkgCache::State::HalfInstalled}};
f55a958f
AL
203 if (GrabWord(string(Start,I-Start),StatusList,
204 _count(StatusList),Pkg->CurrentState) == false)
205 return _error->Error("Malformed 3rd word in the Status line");
206
207 /* A Status line marks the package as indicating the current
208 version as well. Only if it is actually installed.. Otherwise
209 the interesting dpkg handling of the status file creates bogus
210 entries. */
6c139d6e
AL
211 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
212 Pkg->CurrentState == pkgCache::State::ConfigFiles))
f55a958f
AL
213 {
214 if (Ver.end() == true)
215 _error->Warning("Encountered status field in a non-version description");
216 else
217 Pkg->CurrentVer = Ver.Index();
218 }
219
dcb79bae
AL
220 return true;
221}
222 /*}}}*/
223// ListParser::ParseDepends - Parse a dependency element /*{{{*/
224// ---------------------------------------------------------------------
225/* This parses the dependency elements out of a standard string in place,
226 bit by bit. */
227const char *debListParser::ParseDepends(const char *Start,const char *Stop,
228 string &Package,string &Ver,
229 unsigned int &Op)
230{
231 // Strip off leading space
232 for (;Start != Stop && isspace(*Start) != 0; Start++);
233
234 // Parse off the package name
235 const char *I = Start;
236 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
237 *I != ',' && *I != '|'; I++);
238
239 // Malformed, no '('
240 if (I != Stop && *I == ')')
241 return 0;
242
243 if (I == Start)
244 return 0;
245
246 // Stash the package name
247 Package.assign(Start,I - Start);
248
249 // Skip white space to the '('
250 for (;I != Stop && isspace(*I) != 0 ; I++);
251
252 // Parse a version
253 if (I != Stop && *I == '(')
254 {
255 // Skip the '('
256 for (I++; I != Stop && isspace(*I) != 0 ; I++);
257 if (I + 3 >= Stop)
258 return 0;
259
260 // Determine the operator
261 switch (*I)
262 {
263 case '<':
264 I++;
265 if (*I == '=')
266 {
267 I++;
6c139d6e 268 Op = pkgCache::Dep::LessEq;
dcb79bae
AL
269 break;
270 }
271
272 if (*I == '<')
273 {
274 I++;
6c139d6e 275 Op = pkgCache::Dep::Less;
dcb79bae
AL
276 break;
277 }
278
279 // < is the same as <= and << is really Cs < for some reason
6c139d6e 280 Op = pkgCache::Dep::LessEq;
dcb79bae
AL
281 break;
282
283 case '>':
284 I++;
285 if (*I == '=')
286 {
287 I++;
6c139d6e 288 Op = pkgCache::Dep::GreaterEq;
dcb79bae
AL
289 break;
290 }
291
292 if (*I == '>')
293 {
294 I++;
6c139d6e 295 Op = pkgCache::Dep::Greater;
dcb79bae
AL
296 break;
297 }
298
299 // > is the same as >= and >> is really Cs > for some reason
6c139d6e 300 Op = pkgCache::Dep::GreaterEq;
dcb79bae
AL
301 break;
302
303 case '=':
6c139d6e 304 Op = pkgCache::Dep::Equals;
dcb79bae
AL
305 I++;
306 break;
307
308 // HACK around bad package definitions
309 default:
6c139d6e 310 Op = pkgCache::Dep::Equals;
dcb79bae
AL
311 break;
312 }
313
314 // Skip whitespace
315 for (;I != Stop && isspace(*I) != 0; I++);
316 Start = I;
317 for (;I != Stop && *I != ')'; I++);
318 if (I == Stop || Start == I)
319 return 0;
320
321 Ver = string(Start,I-Start);
322 I++;
323 }
324 else
325 {
326 Ver = string();
6c139d6e 327 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
328 }
329
330 // Skip whitespace
331 for (;I != Stop && isspace(*I) != 0; I++);
332 if (I != Stop && *I == '|')
6c139d6e 333 Op |= pkgCache::Dep::Or;
dcb79bae
AL
334
335 if (I == Stop || *I == ',' || *I == '|')
336 {
337 if (I != Stop)
338 for (I++; I != Stop && isspace(*I) != 0; I++);
339 return I;
340 }
341
342 return 0;
343}
344 /*}}}*/
345// ListParser::ParseDepends - Parse a dependency list /*{{{*/
346// ---------------------------------------------------------------------
347/* This is the higher level depends parser. It takes a tag and generates
348 a complete depends tree for the given version. */
349bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
350 const char *Tag,unsigned int Type)
351{
352 const char *Start;
353 const char *Stop;
354 if (Section.Find(Tag,Start,Stop) == false)
355 return true;
356
357 string Package;
358 string Version;
359 unsigned int Op;
360
8efa2a3b 361 while (1)
dcb79bae 362 {
8efa2a3b 363 Start = ParseDepends(Start,Stop,Package,Version,Op);
dcb79bae
AL
364 if (Start == 0)
365 return _error->Error("Problem parsing dependency %s",Tag);
8efa2a3b 366
dcb79bae
AL
367 if (NewDepends(Ver,Package,Version,Op,Type) == false)
368 return false;
8efa2a3b
AL
369 if (Start == Stop)
370 break;
dcb79bae
AL
371 }
372 return true;
373}
374 /*}}}*/
375// ListParser::ParseProvides - Parse the provides list /*{{{*/
376// ---------------------------------------------------------------------
377/* */
378bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
379{
380 const char *Start;
381 const char *Stop;
382 if (Section.Find("Provides",Start,Stop) == false)
383 return true;
384
385 string Package;
386 string Version;
387 unsigned int Op;
388
389 while (1)
390 {
391 Start = ParseDepends(Start,Stop,Package,Version,Op);
392 if (Start == 0)
393 return _error->Error("Problem parsing Provides line");
6c139d6e 394 if (Op != pkgCache::Dep::NoOp)
dcb79bae
AL
395 return _error->Error("Malformed provides line");
396
397 if (NewProvides(Ver,Package,Version) == false)
398 return false;
399
400 if (Start == Stop)
401 break;
402 }
403
f55a958f
AL
404 return true;
405}
406 /*}}}*/
407// ListParser::GrabWord - Matches a word and returns /*{{{*/
408// ---------------------------------------------------------------------
409/* Looks for a word in a list of words - for ParseStatus */
410bool debListParser::GrabWord(string Word,WordList *List,int Count,
411 unsigned char &Out)
412{
413 for (int C = 0; C != Count; C++)
414 {
415 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
416 {
417 Out = List[C].Val;
418 return true;
419 }
420 }
421 return false;
422}
423 /*}}}*/
424// ListParser::Step - Move to the next section in the file /*{{{*/
425// ---------------------------------------------------------------------
0149949b 426/* This has to be carefull to only process the correct architecture */
f55a958f
AL
427bool debListParser::Step()
428{
dcb79bae 429 iOffset = Tags.Offset();
9c14e3d6 430 string Arch = _config->Find("APT::architecture");
0149949b
AL
431 while (Tags.Step(Section) == true)
432 {
433 /* See if this is the correct Architecture, if it isnt then we
434 drop the whole section */
435 const char *Start;
436 const char *Stop;
437 if (Section.Find("Architecture",Start,Stop) == false)
438 return true;
9c14e3d6
AL
439
440 if (stringcmp(Start,Stop,Arch.begin(),Arch.end()) == 0)
0149949b
AL
441 return true;
442
9c14e3d6 443 if (stringcmp(Start,Stop,"all") == 0)
0149949b 444 return true;
dcb79bae
AL
445
446 iOffset = Tags.Offset();
0149949b
AL
447 }
448 return false;
f55a958f
AL
449}
450 /*}}}*/
b0b4efb9
AL
451// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
452// ---------------------------------------------------------------------
453/* */
454bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
455 FileFd &File)
456{
457 pkgTagFile Tags(File);
458 pkgTagSection Section;
459 if (Tags.Step(Section) == false)
460 return false;
461
462 const char *Start;
463 const char *Stop;
464 if (Section.Find("Archive",Start,Stop) == true)
465 FileI->Archive = WriteUniqString(Start,Stop - Start);
466 if (Section.Find("Component",Start,Stop) == true)
467 FileI->Component = WriteUniqString(Start,Stop - Start);
468 if (Section.Find("Version",Start,Stop) == true)
469 FileI->Version = WriteUniqString(Start,Stop - Start);
470 if (Section.Find("Origin",Start,Stop) == true)
471 FileI->Origin = WriteUniqString(Start,Stop - Start);
472 if (Section.Find("Label",Start,Stop) == true)
473 FileI->Label = WriteUniqString(Start,Stop - Start);
474 if (Section.Find("Architecture",Start,Stop) == true)
475 FileI->Architecture = WriteUniqString(Start,Stop - Start);
0dbb95d8 476
3c124dde
AL
477 if (Section.FindFlag("NotAutomatic",FileI->Flags,
478 pkgCache::Flag::NotAutomatic) == false)
0dbb95d8 479 _error->Warning("Bad NotAutomatic flag");
0dbb95d8 480
b0b4efb9
AL
481 return !_error->PendingError();
482}
483 /*}}}*/