apt-pkg/contrib/configuration.cc: Fix a small memory leak in
[ntk/apt.git] / apt-pkg / deb / deblistparser.cc
CommitLineData
f55a958f
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: deblistparser.cc,v 1.29.2.5 2004/01/06 01:43:44 mdz 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>
a52f938b 18#include <apt-pkg/md5.h>
9c14e3d6 19
e7b470ee
AL
20#include <ctype.h>
21
f55a958f
AL
22#include <system.h>
23 /*}}}*/
24
b2e465d6
AL
25static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Important},
26 {"required",pkgCache::State::Required},
27 {"standard",pkgCache::State::Standard},
28 {"optional",pkgCache::State::Optional},
29 {"extra",pkgCache::State::Extra},
30 {}};
31
f55a958f
AL
32// ListParser::debListParser - Constructor /*{{{*/
33// ---------------------------------------------------------------------
34/* */
b2e465d6 35debListParser::debListParser(FileFd *File) : Tags(File)
f55a958f 36{
ddc1d8d0 37 Arch = _config->Find("APT::architecture");
0149949b
AL
38}
39 /*}}}*/
f55a958f
AL
40// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
41// ---------------------------------------------------------------------
42/* */
43unsigned long debListParser::UniqFindTagWrite(const char *Tag)
44{
45 const char *Start;
46 const char *Stop;
47 if (Section.Find(Tag,Start,Stop) == false)
48 return 0;
49 return WriteUniqString(Start,Stop - Start);
50}
51 /*}}}*/
f55a958f
AL
52// ListParser::Package - Return the package name /*{{{*/
53// ---------------------------------------------------------------------
54/* This is to return the name of the package this section describes */
55string debListParser::Package()
56{
b0b4efb9 57 string Result = Section.FindS("Package");
f55a958f 58 if (Result.empty() == true)
65a1e968 59 _error->Error("Encountered a section with no Package: header");
f55a958f
AL
60 return Result;
61}
62 /*}}}*/
63// ListParser::Version - Return the version string /*{{{*/
64// ---------------------------------------------------------------------
65/* This is to return the string describing the version in debian form,
66 epoch:upstream-release. If this returns the blank string then the
67 entry is assumed to only describe package properties */
68string debListParser::Version()
69{
b0b4efb9 70 return Section.FindS("Version");
f55a958f
AL
71}
72 /*}}}*/
f55a958f
AL
73// ListParser::NewVersion - Fill in the version structure /*{{{*/
74// ---------------------------------------------------------------------
75/* */
76bool debListParser::NewVersion(pkgCache::VerIterator Ver)
0149949b
AL
77{
78 // Parse the section
b35d2f5f 79 Ver->Section = UniqFindTagWrite("Section");
17caf1b1 80 Ver->Arch = UniqFindTagWrite("Architecture");
0149949b
AL
81
82 // Archive Size
b0b4efb9 83 Ver->Size = (unsigned)Section.FindI("Size");
0149949b
AL
84
85 // Unpacked Size (in K)
b0b4efb9 86 Ver->InstalledSize = (unsigned)Section.FindI("Installed-Size");
0149949b
AL
87 Ver->InstalledSize *= 1024;
88
89 // Priority
90 const char *Start;
91 const char *Stop;
92 if (Section.Find("Priority",Start,Stop) == true)
b2e465d6
AL
93 {
94 if (GrabWord(string(Start,Stop-Start),PrioList,Ver->Priority) == false)
421c8d10 95 Ver->Priority = pkgCache::State::Extra;
0149949b 96 }
dcb79bae 97
6c139d6e 98 if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
dcb79bae 99 return false;
8efa2a3b 100 if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
dcb79bae 101 return false;
6c139d6e 102 if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
dcb79bae 103 return false;
6c139d6e 104 if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
dcb79bae 105 return false;
6c139d6e 106 if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
dcb79bae 107 return false;
308c7d30
IJ
108 if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
109 return false;
f55ece0e 110 if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
dcb79bae
AL
111 return false;
112
b2e465d6
AL
113 // Obsolete.
114 if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
115 return false;
116
dcb79bae
AL
117 if (ParseProvides(Ver) == false)
118 return false;
0149949b 119
f55a958f
AL
120 return true;
121}
122 /*}}}*/
a52f938b
OS
123// ListParser::Description - Return the description string /*{{{*/
124// ---------------------------------------------------------------------
125/* This is to return the string describing the package in debian
126 form. If this returns the blank string then the entry is assumed to
127 only describe package properties */
128string debListParser::Description()
129{
130 if (DescriptionLanguage().empty())
131 return Section.FindS("Description");
132 else
133 return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
134}
135 /*}}}*/
136// ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
137// ---------------------------------------------------------------------
138/* This is to return the string describing the language of
139 description. If this returns the blank string then the entry is
140 assumed to describe original description. */
141string debListParser::DescriptionLanguage()
142{
143 return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
144}
145 /*}}}*/
146// ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
147// ---------------------------------------------------------------------
770c32ec
MV
148/* This is to return the md5 string to allow the check if it is the right
149 description. If no Description-md5 is found in the section it will be
150 calculated.
151 */
a52f938b
OS
152MD5SumValue debListParser::Description_md5()
153{
154 string value = Section.FindS("Description-md5");
155
770c32ec
MV
156 if (value.empty())
157 {
a52f938b
OS
158 MD5Summation md5;
159 md5.Add((Description() + "\n").c_str());
160 return md5.Result();
161 } else
162 return MD5SumValue(value);
163}
164 /*}}}*/
f55a958f
AL
165// ListParser::UsePackage - Update a package structure /*{{{*/
166// ---------------------------------------------------------------------
167/* This is called to update the package with any new information
168 that might be found in the section */
169bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
170 pkgCache::VerIterator Ver)
171{
172 if (Pkg->Section == 0)
b35d2f5f 173 Pkg->Section = UniqFindTagWrite("Section");
b0b4efb9 174 if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
f55a958f 175 return false;
138d4b3d 176 if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
f55a958f 177 return false;
138d4b3d
AL
178
179 if (strcmp(Pkg.Name(),"apt") == 0)
180 Pkg->Flags |= pkgCache::Flag::Important;
181
f55a958f
AL
182 if (ParseStatus(Pkg,Ver) == false)
183 return false;
184 return true;
185}
186 /*}}}*/
204fbdcc
AL
187// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
188// ---------------------------------------------------------------------
189/* */
190unsigned short debListParser::VersionHash()
191{
192 const char *Sections[] ={"Installed-Size",
193 "Depends",
194 "Pre-Depends",
f78439bf
AL
195// "Suggests",
196// "Recommends",
204fbdcc 197 "Conflicts",
308c7d30 198 "Breaks",
204fbdcc
AL
199 "Replaces",0};
200 unsigned long Result = INIT_FCS;
418a471f 201 char S[1024];
204fbdcc
AL
202 for (const char **I = Sections; *I != 0; I++)
203 {
204 const char *Start;
205 const char *End;
206 if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
207 continue;
208
209 /* Strip out any spaces from the text, this undoes dpkgs reformatting
421c8d10
AL
210 of certain fields. dpkg also has the rather interesting notion of
211 reformatting depends operators < -> <= */
204fbdcc
AL
212 char *I = S;
213 for (; Start != End; Start++)
421c8d10 214 {
204fbdcc 215 if (isspace(*Start) == 0)
ddc1d8d0 216 *I++ = tolower(*Start);
421c8d10
AL
217 if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
218 *I++ = '=';
219 if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
220 *I++ = '=';
221 }
418a471f 222
204fbdcc
AL
223 Result = AddCRC16(Result,S,I - S);
224 }
225
226 return Result;
227}
228 /*}}}*/
dcb79bae 229// ListParser::ParseStatus - Parse the status field /*{{{*/
f55a958f
AL
230// ---------------------------------------------------------------------
231/* Status lines are of the form,
232 Status: want flag status
233 want = unknown, install, hold, deinstall, purge
234 flag = ok, reinstreq, hold, hold-reinstreq
a005475e 235 status = not-installed, unpacked, half-configured,
f55a958f
AL
236 half-installed, config-files, post-inst-failed,
237 removal-failed, installed
238
239 Some of the above are obsolete (I think?) flag = hold-* and
240 status = post-inst-failed, removal-failed at least.
241 */
242bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
243 pkgCache::VerIterator Ver)
244{
245 const char *Start;
246 const char *Stop;
247 if (Section.Find("Status",Start,Stop) == false)
248 return true;
249
250 // Isolate the first word
251 const char *I = Start;
252 for(; I < Stop && *I != ' '; I++);
253 if (I >= Stop || *I != ' ')
254 return _error->Error("Malformed Status line");
255
256 // Process the want field
6c139d6e
AL
257 WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
258 {"install",pkgCache::State::Install},
259 {"hold",pkgCache::State::Hold},
260 {"deinstall",pkgCache::State::DeInstall},
b2e465d6
AL
261 {"purge",pkgCache::State::Purge},
262 {}};
263 if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false)
f55a958f
AL
264 return _error->Error("Malformed 1st word in the Status line");
265
266 // Isloate the next word
267 I++;
268 Start = I;
269 for(; I < Stop && *I != ' '; I++);
270 if (I >= Stop || *I != ' ')
271 return _error->Error("Malformed status line, no 2nd word");
272
273 // Process the flag field
6c139d6e
AL
274 WordList FlagList[] = {{"ok",pkgCache::State::Ok},
275 {"reinstreq",pkgCache::State::ReInstReq},
276 {"hold",pkgCache::State::HoldInst},
b2e465d6
AL
277 {"hold-reinstreq",pkgCache::State::HoldReInstReq},
278 {}};
279 if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false)
f55a958f
AL
280 return _error->Error("Malformed 2nd word in the Status line");
281
282 // Isloate the last word
283 I++;
284 Start = I;
285 for(; I < Stop && *I != ' '; I++);
286 if (I != Stop)
287 return _error->Error("Malformed Status line, no 3rd word");
288
289 // Process the flag field
6c139d6e
AL
290 WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
291 {"unpacked",pkgCache::State::UnPacked},
292 {"half-configured",pkgCache::State::HalfConfigured},
293 {"installed",pkgCache::State::Installed},
6c139d6e
AL
294 {"half-installed",pkgCache::State::HalfInstalled},
295 {"config-files",pkgCache::State::ConfigFiles},
9d06bc80
MV
296 {"triggers-awaited",pkgCache::State::TriggersAwaited},
297 {"triggers-pending",pkgCache::State::TriggersPending},
6c139d6e 298 {"post-inst-failed",pkgCache::State::HalfConfigured},
b2e465d6
AL
299 {"removal-failed",pkgCache::State::HalfInstalled},
300 {}};
301 if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false)
f55a958f
AL
302 return _error->Error("Malformed 3rd word in the Status line");
303
304 /* A Status line marks the package as indicating the current
305 version as well. Only if it is actually installed.. Otherwise
306 the interesting dpkg handling of the status file creates bogus
307 entries. */
6c139d6e
AL
308 if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
309 Pkg->CurrentState == pkgCache::State::ConfigFiles))
f55a958f
AL
310 {
311 if (Ver.end() == true)
312 _error->Warning("Encountered status field in a non-version description");
313 else
314 Pkg->CurrentVer = Ver.Index();
315 }
316
dcb79bae
AL
317 return true;
318}
a1826878 319
b2e465d6
AL
320const char *debListParser::ConvertRelation(const char *I,unsigned int &Op)
321{
322 // Determine the operator
323 switch (*I)
324 {
325 case '<':
326 I++;
327 if (*I == '=')
328 {
329 I++;
330 Op = pkgCache::Dep::LessEq;
331 break;
332 }
333
334 if (*I == '<')
335 {
336 I++;
337 Op = pkgCache::Dep::Less;
338 break;
339 }
340
341 // < is the same as <= and << is really Cs < for some reason
342 Op = pkgCache::Dep::LessEq;
343 break;
344
345 case '>':
346 I++;
347 if (*I == '=')
348 {
349 I++;
350 Op = pkgCache::Dep::GreaterEq;
351 break;
352 }
353
354 if (*I == '>')
355 {
356 I++;
357 Op = pkgCache::Dep::Greater;
358 break;
359 }
360
361 // > is the same as >= and >> is really Cs > for some reason
362 Op = pkgCache::Dep::GreaterEq;
363 break;
364
365 case '=':
366 Op = pkgCache::Dep::Equals;
367 I++;
368 break;
369
370 // HACK around bad package definitions
371 default:
372 Op = pkgCache::Dep::Equals;
373 break;
374 }
375 return I;
376}
377
a1826878
AL
378 /*}}}*/
379// ListParser::ParseDepends - Parse a dependency element /*{{{*/
380// ---------------------------------------------------------------------
381/* This parses the dependency elements out of a standard string in place,
382 bit by bit. */
dcb79bae
AL
383const char *debListParser::ParseDepends(const char *Start,const char *Stop,
384 string &Package,string &Ver,
b2e465d6 385 unsigned int &Op, bool ParseArchFlags)
dcb79bae
AL
386{
387 // Strip off leading space
388 for (;Start != Stop && isspace(*Start) != 0; Start++);
389
390 // Parse off the package name
391 const char *I = Start;
392 for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
393 *I != ',' && *I != '|'; I++);
394
395 // Malformed, no '('
396 if (I != Stop && *I == ')')
397 return 0;
398
399 if (I == Start)
400 return 0;
401
402 // Stash the package name
403 Package.assign(Start,I - Start);
404
405 // Skip white space to the '('
406 for (;I != Stop && isspace(*I) != 0 ; I++);
407
408 // Parse a version
409 if (I != Stop && *I == '(')
410 {
411 // Skip the '('
412 for (I++; I != Stop && isspace(*I) != 0 ; I++);
413 if (I + 3 >= Stop)
414 return 0;
b2e465d6 415 I = ConvertRelation(I,Op);
dcb79bae
AL
416
417 // Skip whitespace
418 for (;I != Stop && isspace(*I) != 0; I++);
419 Start = I;
420 for (;I != Stop && *I != ')'; I++);
421 if (I == Stop || Start == I)
422 return 0;
423
02f000a9
AL
424 // Skip trailing whitespace
425 const char *End = I;
426 for (; End > Start && isspace(End[-1]); End--);
427
171c75f1 428 Ver.assign(Start,End-Start);
dcb79bae
AL
429 I++;
430 }
431 else
432 {
171c75f1 433 Ver.clear();
6c139d6e 434 Op = pkgCache::Dep::NoOp;
dcb79bae
AL
435 }
436
437 // Skip whitespace
438 for (;I != Stop && isspace(*I) != 0; I++);
b2e465d6
AL
439
440 if (ParseArchFlags == true)
441 {
442 string arch = _config->Find("APT::Architecture");
9e10ad8a 443
b2e465d6
AL
444 // Parse an architecture
445 if (I != Stop && *I == '[')
446 {
447 // malformed
448 I++;
449 if (I == Stop)
450 return 0;
451
452 const char *End = I;
453 bool Found = false;
9e10ad8a 454 bool NegArch = false;
b2e465d6
AL
455 while (I != Stop)
456 {
457 // look for whitespace or ending ']'
458 while (End != Stop && !isspace(*End) && *End != ']')
459 End++;
460
461 if (End == Stop)
462 return 0;
9e10ad8a
AL
463
464 if (*I == '!')
465 {
466 NegArch = true;
467 I++;
468 }
469
3e18cc75 470 if (stringcmp(arch,I,End) == 0)
b2e465d6
AL
471 Found = true;
472
473 if (*End++ == ']') {
474 I = End;
475 break;
476 }
477
478 I = End;
479 for (;I != Stop && isspace(*I) != 0; I++);
480 }
9e10ad8a
AL
481
482 if (NegArch)
483 Found = !Found;
b2e465d6 484
9e10ad8a 485 if (Found == false)
b2e465d6
AL
486 Package = ""; /* not for this arch */
487 }
488
489 // Skip whitespace
490 for (;I != Stop && isspace(*I) != 0; I++);
491 }
492
dcb79bae 493 if (I != Stop && *I == '|')
6c139d6e 494 Op |= pkgCache::Dep::Or;
dcb79bae
AL
495
496 if (I == Stop || *I == ',' || *I == '|')
497 {
498 if (I != Stop)
499 for (I++; I != Stop && isspace(*I) != 0; I++);
500 return I;
501 }
502
503 return 0;
504}
505 /*}}}*/
506// ListParser::ParseDepends - Parse a dependency list /*{{{*/
507// ---------------------------------------------------------------------
508/* This is the higher level depends parser. It takes a tag and generates
509 a complete depends tree for the given version. */
510bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
511 const char *Tag,unsigned int Type)
512{
513 const char *Start;
514 const char *Stop;
515 if (Section.Find(Tag,Start,Stop) == false)
516 return true;
517
518 string Package;
519 string Version;
520 unsigned int Op;
521
8efa2a3b 522 while (1)
dcb79bae 523 {
8efa2a3b 524 Start = ParseDepends(Start,Stop,Package,Version,Op);
dcb79bae
AL
525 if (Start == 0)
526 return _error->Error("Problem parsing dependency %s",Tag);
8efa2a3b 527
dcb79bae
AL
528 if (NewDepends(Ver,Package,Version,Op,Type) == false)
529 return false;
8efa2a3b
AL
530 if (Start == Stop)
531 break;
dcb79bae
AL
532 }
533 return true;
534}
535 /*}}}*/
536// ListParser::ParseProvides - Parse the provides list /*{{{*/
537// ---------------------------------------------------------------------
538/* */
539bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
540{
541 const char *Start;
542 const char *Stop;
543 if (Section.Find("Provides",Start,Stop) == false)
544 return true;
545
546 string Package;
547 string Version;
548 unsigned int Op;
549
550 while (1)
551 {
552 Start = ParseDepends(Start,Stop,Package,Version,Op);
553 if (Start == 0)
554 return _error->Error("Problem parsing Provides line");
b63380b0
MV
555 if (Op != pkgCache::Dep::NoOp) {
556 _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
557 } else {
558 if (NewProvides(Ver,Package,Version) == false)
559 return false;
560 }
dcb79bae
AL
561
562 if (Start == Stop)
563 break;
564 }
565
f55a958f
AL
566 return true;
567}
568 /*}}}*/
569// ListParser::GrabWord - Matches a word and returns /*{{{*/
570// ---------------------------------------------------------------------
571/* Looks for a word in a list of words - for ParseStatus */
b2e465d6 572bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out)
f55a958f 573{
b2e465d6 574 for (unsigned int C = 0; List[C].Str != 0; C++)
f55a958f
AL
575 {
576 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
577 {
578 Out = List[C].Val;
579 return true;
580 }
581 }
582 return false;
583}
584 /*}}}*/
585// ListParser::Step - Move to the next section in the file /*{{{*/
586// ---------------------------------------------------------------------
0149949b 587/* This has to be carefull to only process the correct architecture */
f55a958f
AL
588bool debListParser::Step()
589{
dcb79bae 590 iOffset = Tags.Offset();
0149949b 591 while (Tags.Step(Section) == true)
ddc1d8d0
AL
592 {
593 /* See if this is the correct Architecture, if it isn't then we
594 drop the whole section. A missing arch tag only happens (in theory)
595 inside the Status file, so that is a positive return */
0149949b
AL
596 const char *Start;
597 const char *Stop;
598 if (Section.Find("Architecture",Start,Stop) == false)
599 return true;
9c14e3d6 600
3e18cc75 601 if (stringcmp(Arch,Start,Stop) == 0)
0149949b
AL
602 return true;
603
9c14e3d6 604 if (stringcmp(Start,Stop,"all") == 0)
0149949b 605 return true;
dcb79bae
AL
606
607 iOffset = Tags.Offset();
0149949b
AL
608 }
609 return false;
f55a958f
AL
610}
611 /*}}}*/
b0b4efb9
AL
612// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
613// ---------------------------------------------------------------------
614/* */
615bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
f2152f03 616 FileFd &File, string component)
b0b4efb9 617{
b3d44315 618 pkgTagFile Tags(&File, File.Size() + 256); // XXX
b0b4efb9
AL
619 pkgTagSection Section;
620 if (Tags.Step(Section) == false)
621 return false;
622
f2152f03
MV
623 //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
624 //FileI->Architecture = WriteUniqString(Arch);
625
626 // apt-secure does no longer download individual (per-section) Release
627 // file. to provide Component pinning we use the section name now
628 FileI->Component = WriteUniqString(component);
629
b0b4efb9
AL
630 const char *Start;
631 const char *Stop;
b3d44315 632 if (Section.Find("Suite",Start,Stop) == true)
b0b4efb9
AL
633 FileI->Archive = WriteUniqString(Start,Stop - Start);
634 if (Section.Find("Component",Start,Stop) == true)
635 FileI->Component = WriteUniqString(Start,Stop - Start);
636 if (Section.Find("Version",Start,Stop) == true)
637 FileI->Version = WriteUniqString(Start,Stop - Start);
638 if (Section.Find("Origin",Start,Stop) == true)
639 FileI->Origin = WriteUniqString(Start,Stop - Start);
640 if (Section.Find("Label",Start,Stop) == true)
641 FileI->Label = WriteUniqString(Start,Stop - Start);
642 if (Section.Find("Architecture",Start,Stop) == true)
643 FileI->Architecture = WriteUniqString(Start,Stop - Start);
0dbb95d8 644
3c124dde
AL
645 if (Section.FindFlag("NotAutomatic",FileI->Flags,
646 pkgCache::Flag::NotAutomatic) == false)
0dbb95d8 647 _error->Warning("Bad NotAutomatic flag");
f2152f03 648
b0b4efb9
AL
649 return !_error->PendingError();
650}
651 /*}}}*/
b2e465d6
AL
652// ListParser::GetPrio - Convert the priority from a string /*{{{*/
653// ---------------------------------------------------------------------
654/* */
655unsigned char debListParser::GetPrio(string Str)
656{
657 unsigned char Out;
658 if (GrabWord(Str,PrioList,Out) == false)
659 Out = pkgCache::State::Extra;
660
661 return Out;
662}
663 /*}}}*/