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