Fixed the cps resume problem
[ntk/apt.git] / apt-pkg / deb / deblistparser.cc
CommitLineData
f55a958f
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
02f000a9 3// $Id: deblistparser.cc,v 1.18 1999/04/12 19:16:11 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
02f000a9
AL
321 // Skip trailing whitespace
322 const char *End = I;
323 for (; End > Start && isspace(End[-1]); End--);
324
325 Ver = string(Start,End-Start);
dcb79bae
AL
326 I++;
327 }
328 else
329 {
330 Ver = string();
6c139d6e 331 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
332 }
333
334 // Skip whitespace
335 for (;I != Stop && isspace(*I) != 0; I++);
336 if (I != Stop && *I == '|')
6c139d6e 337 Op |= pkgCache::Dep::Or;
dcb79bae
AL
338
339 if (I == Stop || *I == ',' || *I == '|')
340 {
341 if (I != Stop)
342 for (I++; I != Stop && isspace(*I) != 0; I++);
343 return I;
344 }
345
346 return 0;
347}
348 /*}}}*/
349// ListParser::ParseDepends - Parse a dependency list /*{{{*/
350// ---------------------------------------------------------------------
351/* This is the higher level depends parser. It takes a tag and generates
352 a complete depends tree for the given version. */
353bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
354 const char *Tag,unsigned int Type)
355{
356 const char *Start;
357 const char *Stop;
358 if (Section.Find(Tag,Start,Stop) == false)
359 return true;
360
361 string Package;
362 string Version;
363 unsigned int Op;
364
8efa2a3b 365 while (1)
dcb79bae 366 {
8efa2a3b 367 Start = ParseDepends(Start,Stop,Package,Version,Op);
dcb79bae
AL
368 if (Start == 0)
369 return _error->Error("Problem parsing dependency %s",Tag);
8efa2a3b 370
dcb79bae
AL
371 if (NewDepends(Ver,Package,Version,Op,Type) == false)
372 return false;
8efa2a3b
AL
373 if (Start == Stop)
374 break;
dcb79bae
AL
375 }
376 return true;
377}
378 /*}}}*/
379// ListParser::ParseProvides - Parse the provides list /*{{{*/
380// ---------------------------------------------------------------------
381/* */
382bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
383{
384 const char *Start;
385 const char *Stop;
386 if (Section.Find("Provides",Start,Stop) == false)
387 return true;
388
389 string Package;
390 string Version;
391 unsigned int Op;
392
393 while (1)
394 {
395 Start = ParseDepends(Start,Stop,Package,Version,Op);
396 if (Start == 0)
397 return _error->Error("Problem parsing Provides line");
6c139d6e 398 if (Op != pkgCache::Dep::NoOp)
dcb79bae
AL
399 return _error->Error("Malformed provides line");
400
401 if (NewProvides(Ver,Package,Version) == false)
402 return false;
403
404 if (Start == Stop)
405 break;
406 }
407
f55a958f
AL
408 return true;
409}
410 /*}}}*/
411// ListParser::GrabWord - Matches a word and returns /*{{{*/
412// ---------------------------------------------------------------------
413/* Looks for a word in a list of words - for ParseStatus */
414bool debListParser::GrabWord(string Word,WordList *List,int Count,
415 unsigned char &Out)
416{
417 for (int C = 0; C != Count; C++)
418 {
419 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
420 {
421 Out = List[C].Val;
422 return true;
423 }
424 }
425 return false;
426}
427 /*}}}*/
428// ListParser::Step - Move to the next section in the file /*{{{*/
429// ---------------------------------------------------------------------
0149949b 430/* This has to be carefull to only process the correct architecture */
f55a958f
AL
431bool debListParser::Step()
432{
dcb79bae 433 iOffset = Tags.Offset();
9c14e3d6 434 string Arch = _config->Find("APT::architecture");
0149949b
AL
435 while (Tags.Step(Section) == true)
436 {
437 /* See if this is the correct Architecture, if it isnt then we
438 drop the whole section */
439 const char *Start;
440 const char *Stop;
441 if (Section.Find("Architecture",Start,Stop) == false)
442 return true;
9c14e3d6
AL
443
444 if (stringcmp(Start,Stop,Arch.begin(),Arch.end()) == 0)
0149949b
AL
445 return true;
446
9c14e3d6 447 if (stringcmp(Start,Stop,"all") == 0)
0149949b 448 return true;
dcb79bae
AL
449
450 iOffset = Tags.Offset();
0149949b
AL
451 }
452 return false;
f55a958f
AL
453}
454 /*}}}*/
b0b4efb9
AL
455// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
456// ---------------------------------------------------------------------
457/* */
458bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
459 FileFd &File)
460{
461 pkgTagFile Tags(File);
462 pkgTagSection Section;
463 if (Tags.Step(Section) == false)
464 return false;
465
466 const char *Start;
467 const char *Stop;
468 if (Section.Find("Archive",Start,Stop) == true)
469 FileI->Archive = WriteUniqString(Start,Stop - Start);
470 if (Section.Find("Component",Start,Stop) == true)
471 FileI->Component = WriteUniqString(Start,Stop - Start);
472 if (Section.Find("Version",Start,Stop) == true)
473 FileI->Version = WriteUniqString(Start,Stop - Start);
474 if (Section.Find("Origin",Start,Stop) == true)
475 FileI->Origin = WriteUniqString(Start,Stop - Start);
476 if (Section.Find("Label",Start,Stop) == true)
477 FileI->Label = WriteUniqString(Start,Stop - Start);
478 if (Section.Find("Architecture",Start,Stop) == true)
479 FileI->Architecture = WriteUniqString(Start,Stop - Start);
0dbb95d8 480
3c124dde
AL
481 if (Section.FindFlag("NotAutomatic",FileI->Flags,
482 pkgCache::Flag::NotAutomatic) == false)
0dbb95d8 483 _error->Warning("Bad NotAutomatic flag");
0dbb95d8 484
b0b4efb9
AL
485 return !_error->PendingError();
486}
487 /*}}}*/