]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.18 1999/04/12 19:16:11 jgg Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
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/strutl.h>
21 // ListParser::debListParser - Constructor /*{{{*/
22 // ---------------------------------------------------------------------
24 debListParser::debListParser(FileFd
&File
) : Tags(File
)
28 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
29 // ---------------------------------------------------------------------
31 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
35 if (Section
.Find(Tag
,Start
,Stop
) == false)
37 return WriteUniqString(Start
,Stop
- Start
);
40 // ListParser::Package - Return the package name /*{{{*/
41 // ---------------------------------------------------------------------
42 /* This is to return the name of the package this section describes */
43 string
debListParser::Package()
45 string Result
= Section
.FindS("Package");
46 if (Result
.empty() == true)
47 _error
->Error("Encountered a section with no Package: header");
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 */
56 string
debListParser::Version()
58 return Section
.FindS("Version");
61 // ListParser::NewVersion - Fill in the version structure /*{{{*/
62 // ---------------------------------------------------------------------
64 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
67 Ver
->Section
= UniqFindTagWrite("Section");
68 Ver
->Arch
= UniqFindTagWrite("Architecture");
71 Ver
->Size
= (unsigned)Section
.FindI("Size");
73 // Unpacked Size (in K)
74 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
75 Ver
->InstalledSize
*= 1024;
80 if (Section
.Find("Priority",Start
,Stop
) == true)
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
}};
87 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,
88 _count(PrioList
),Ver
->Priority
) == false)
89 return _error
->Error("Malformed Priority line");
92 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
94 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
96 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
98 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
100 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
102 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
105 if (ParseProvides(Ver
) == false)
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 */
115 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
116 pkgCache::VerIterator Ver
)
118 if (Pkg
->Section
== 0)
119 Pkg
->Section
= UniqFindTagWrite("Section");
120 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
122 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
125 if (strcmp(Pkg
.Name(),"apt") == 0)
126 Pkg
->Flags
|= pkgCache::Flag::Important
;
128 if (ParseStatus(Pkg
,Ver
) == false)
133 // ListParser::ParseStatus - Parse the status field /*{{{*/
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
143 Some of the above are obsolete (I think?) flag = hold-* and
144 status = post-inst-failed, removal-failed at least.
146 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
147 pkgCache::VerIterator Ver
)
151 if (Section
.Find("Status",Start
,Stop
) == false)
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");
160 // Process the want field
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
}};
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");
170 // Isloate the next word
173 for(; I
< Stop
&& *I
!= ' '; I
++);
174 if (I
>= Stop
|| *I
!= ' ')
175 return _error
->Error("Malformed status line, no 2nd word");
177 // Process the flag field
178 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
179 {"reinstreq",pkgCache::State::ReInstReq
},
180 {"hold",pkgCache::State::HoldInst
},
181 {"hold-reinstreq",pkgCache::State::HoldReInstReq
}};
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");
186 // Isloate the last word
189 for(; I
< Stop
&& *I
!= ' '; I
++);
191 return _error
->Error("Malformed Status line, no 3rd word");
193 // Process the flag field
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
}};
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");
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
211 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
212 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
214 if (Ver
.end() == true)
215 _error
->Warning("Encountered status field in a non-version description");
217 Pkg
->CurrentVer
= Ver
.Index();
223 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
224 // ---------------------------------------------------------------------
225 /* This parses the dependency elements out of a standard string in place,
227 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
228 string
&Package
,string
&Ver
,
231 // Strip off leading space
232 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
234 // Parse off the package name
235 const char *I
= Start
;
236 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
237 *I
!= ',' && *I
!= '|'; I
++);
240 if (I
!= Stop
&& *I
== ')')
246 // Stash the package name
247 Package
.assign(Start
,I
- Start
);
249 // Skip white space to the '('
250 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
253 if (I
!= Stop
&& *I
== '(')
256 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
260 // Determine the operator
268 Op
= pkgCache::Dep::LessEq
;
275 Op
= pkgCache::Dep::Less
;
279 // < is the same as <= and << is really Cs < for some reason
280 Op
= pkgCache::Dep::LessEq
;
288 Op
= pkgCache::Dep::GreaterEq
;
295 Op
= pkgCache::Dep::Greater
;
299 // > is the same as >= and >> is really Cs > for some reason
300 Op
= pkgCache::Dep::GreaterEq
;
304 Op
= pkgCache::Dep::Equals
;
308 // HACK around bad package definitions
310 Op
= pkgCache::Dep::Equals
;
315 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
317 for (;I
!= Stop
&& *I
!= ')'; I
++);
318 if (I
== Stop
|| Start
== I
)
321 // Skip trailing whitespace
323 for (; End
> Start
&& isspace(End
[-1]); End
--);
325 Ver
= string(Start
,End
-Start
);
331 Op
= pkgCache::Dep::NoOp
;
335 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
336 if (I
!= Stop
&& *I
== '|')
337 Op
|= pkgCache::Dep::Or
;
339 if (I
== Stop
|| *I
== ',' || *I
== '|')
342 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
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. */
353 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
354 const char *Tag
,unsigned int Type
)
358 if (Section
.Find(Tag
,Start
,Stop
) == false)
367 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
369 return _error
->Error("Problem parsing dependency %s",Tag
);
371 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
379 // ListParser::ParseProvides - Parse the provides list /*{{{*/
380 // ---------------------------------------------------------------------
382 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
386 if (Section
.Find("Provides",Start
,Stop
) == false)
395 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
397 return _error
->Error("Problem parsing Provides line");
398 if (Op
!= pkgCache::Dep::NoOp
)
399 return _error
->Error("Malformed provides line");
401 if (NewProvides(Ver
,Package
,Version
) == false)
411 // ListParser::GrabWord - Matches a word and returns /*{{{*/
412 // ---------------------------------------------------------------------
413 /* Looks for a word in a list of words - for ParseStatus */
414 bool debListParser::GrabWord(string Word
,WordList
*List
,int Count
,
417 for (int C
= 0; C
!= Count
; C
++)
419 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
428 // ListParser::Step - Move to the next section in the file /*{{{*/
429 // ---------------------------------------------------------------------
430 /* This has to be carefull to only process the correct architecture */
431 bool debListParser::Step()
433 iOffset
= Tags
.Offset();
434 string Arch
= _config
->Find("APT::architecture");
435 while (Tags
.Step(Section
) == true)
437 /* See if this is the correct Architecture, if it isnt then we
438 drop the whole section */
441 if (Section
.Find("Architecture",Start
,Stop
) == false)
444 if (stringcmp(Start
,Stop
,Arch
.begin(),Arch
.end()) == 0)
447 if (stringcmp(Start
,Stop
,"all") == 0)
450 iOffset
= Tags
.Offset();
455 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
456 // ---------------------------------------------------------------------
458 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
461 pkgTagFile
Tags(File
);
462 pkgTagSection Section
;
463 if (Tags
.Step(Section
) == false)
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
);
481 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
482 pkgCache::Flag::NotAutomatic
) == false)
483 _error
->Warning("Bad NotAutomatic flag");
485 return !_error
->PendingError();