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