]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
97ee881830e1b6f70a2586c7ccdf79e3293aca09
[apt.git] / apt-pkg / deb / deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: deblistparser.cc,v 1.2 1998/07/04 22:32:17 jgg 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 <pkglib/deblistparser.h>
14 #include <pkglib/error.h>
15 #include <system.h>
16 /*}}}*/
17
18 // ListParser::debListParser - Constructor /*{{{*/
19 // ---------------------------------------------------------------------
20 /* */
21 debListParser::debListParser(File &File) : Tags(File)
22 {
23 }
24 /*}}}*/
25 // ListParser::FindTag - Find the tag and return a string /*{{{*/
26 // ---------------------------------------------------------------------
27 /* */
28 string debListParser::FindTag(const char *Tag)
29 {
30 const char *Start;
31 const char *Stop;
32 if (Section.Find(Tag,Start,Stop) == false)
33 return string();
34 return string(Start,Stop - Start);
35 }
36 /*}}}*/
37 // ListParser::FindTagI - Find the tag and return an int /*{{{*/
38 // ---------------------------------------------------------------------
39 /* */
40 signed long debListParser::FindTagI(const char *Tag,signed long Default)
41 {
42 const char *Start;
43 const char *Stop;
44 if (Section.Find(Tag,Start,Stop) == false)
45 return Default;
46
47 // Copy it into a temp buffer so we can use strtol
48 char S[300];
49 if ((unsigned)(Stop - Start) >= sizeof(S))
50 return Default;
51 strncpy(S,Start,Stop-Start);
52 S[Stop - Start] = 0;
53
54 char *End;
55 signed long Result = strtol(S,&End,10);
56 if (S == End)
57 return Default;
58 return Result;
59 }
60 /*}}}*/
61 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
62 // ---------------------------------------------------------------------
63 /* */
64 unsigned long debListParser::UniqFindTagWrite(const char *Tag)
65 {
66 const char *Start;
67 const char *Stop;
68 if (Section.Find(Tag,Start,Stop) == false)
69 return 0;
70 return WriteUniqString(Start,Stop - Start);
71 }
72 /*}}}*/
73 // ListParser::HandleFlag - Sets a flag variable based on a tag /*{{{*/
74 // ---------------------------------------------------------------------
75 /* This checks the tag for true/false yes/no etc */
76 bool debListParser::HandleFlag(const char *Tag,unsigned long &Flags,
77 unsigned long Flag)
78 {
79 const char *Start;
80 const char *Stop;
81 if (Section.Find(Tag,Start,Stop) == false)
82 return true;
83
84 int Set = 2;
85 if (strncasecmp(Start,"yes",Stop - Start) == 0)
86 Set = 1;
87 if (strncasecmp(Start,"true",Stop - Start) == 0)
88 Set = 1;
89 if (strncasecmp(Start,"no",Stop - Start) == 0)
90 Set = 0;
91 if (strncasecmp(Start,"false",Stop - Start) == 0)
92 Set = 0;
93 if (Set == 2)
94 {
95 _error->Warning("Unknown flag value");
96 return true;
97 }
98
99 if (Set == 0)
100 Flags &= ~Flag;
101 if (Set == 1)
102 Flags |= Flag;
103 return true;
104 }
105 /*}}}*/
106 // ListParser::Package - Return the package name /*{{{*/
107 // ---------------------------------------------------------------------
108 /* This is to return the name of the package this section describes */
109 string debListParser::Package()
110 {
111 string Result = FindTag("Package");
112 if (Result.empty() == true)
113 _error->Error("Encoutered a section with no Package: header");
114 return Result;
115 }
116 /*}}}*/
117 // ListParser::Version - Return the version string /*{{{*/
118 // ---------------------------------------------------------------------
119 /* This is to return the string describing the version in debian form,
120 epoch:upstream-release. If this returns the blank string then the
121 entry is assumed to only describe package properties */
122 string debListParser::Version()
123 {
124 return FindTag("Version");
125 }
126 /*}}}*/
127 // ListParser::NewPackage - Fill in the package structure /*{{{*/
128 // ---------------------------------------------------------------------
129 /* This is called when a new package structure is created. It must fill
130 in the static package information. */
131 bool debListParser::NewPackage(pkgCache::PkgIterator Pkg)
132 {
133 // Debian doesnt have anything, everything is condionally megered
134 return true;
135 }
136 /*}}}*/
137 // ListParser::NewVersion - Fill in the version structure /*{{{*/
138 // ---------------------------------------------------------------------
139 /* */
140 bool debListParser::NewVersion(pkgCache::VerIterator Ver)
141 {
142 // Parse the section
143 if ((Ver->Section = UniqFindTagWrite("Section")) == 0)
144 return _error->Warning("Missing Section tag");
145
146 // Archive Size
147 if ((Ver->Size = (unsigned)FindTagI("Size")) == 0)
148 return _error->Error("Unparsable Size field");
149
150 // Unpacked Size (in K)
151 if ((Ver->InstalledSize = (unsigned)FindTagI("Installed-Size")) == 0)
152 return _error->Error("Unparsable Installed-Size field");
153 Ver->InstalledSize *= 1024;
154
155 // Priority
156 const char *Start;
157 const char *Stop;
158 if (Section.Find("Priority",Start,Stop) == true)
159 {
160 WordList PrioList[] = {{"important",pkgCache::Important},
161 {"required",pkgCache::Required},
162 {"standard",pkgCache::Standard},
163 {"optional",pkgCache::Optional},
164 {"extra",pkgCache::Extra}};
165 if (GrabWord(string(Start,Stop-Start),PrioList,
166 _count(PrioList),Ver->Priority) == false)
167 return _error->Error("Malformed Priority line");
168 }
169
170 return true;
171 }
172 /*}}}*/
173 // ListParser::UsePackage - Update a package structure /*{{{*/
174 // ---------------------------------------------------------------------
175 /* This is called to update the package with any new information
176 that might be found in the section */
177 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
178 pkgCache::VerIterator Ver)
179 {
180 if (Pkg->Section == 0)
181 if ((Pkg->Section = UniqFindTagWrite("Section")) == 0)
182 return false;
183 if (HandleFlag("Essential",Pkg->Flags,pkgCache::Essential) == false)
184 return false;
185 if (HandleFlag("Immediate-Configure",Pkg->Flags,pkgCache::ImmediateConf) == false)
186 return false;
187 if (ParseStatus(Pkg,Ver) == false)
188 return false;
189 return true;
190 }
191 /*}}}*/
192 // ListParser::ParseStatus - Parse the status feild /*{{{*/
193 // ---------------------------------------------------------------------
194 /* Status lines are of the form,
195 Status: want flag status
196 want = unknown, install, hold, deinstall, purge
197 flag = ok, reinstreq, hold, hold-reinstreq
198 status = not-installed, unpacked, half-configured, uninstalled,
199 half-installed, config-files, post-inst-failed,
200 removal-failed, installed
201
202 Some of the above are obsolete (I think?) flag = hold-* and
203 status = post-inst-failed, removal-failed at least.
204 */
205 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
206 pkgCache::VerIterator Ver)
207 {
208 const char *Start;
209 const char *Stop;
210 if (Section.Find("Status",Start,Stop) == false)
211 return true;
212
213 // Isolate the first word
214 const char *I = Start;
215 for(; I < Stop && *I != ' '; I++);
216 if (I >= Stop || *I != ' ')
217 return _error->Error("Malformed Status line");
218
219 // Process the want field
220 WordList WantList[] = {{"unknown",pkgCache::Unknown},
221 {"install",pkgCache::Install},
222 {"hold",pkgCache::Hold},
223 {"deinstall",pkgCache::DeInstall},
224 {"purge",pkgCache::Purge}};
225 if (GrabWord(string(Start,I-Start),WantList,
226 _count(WantList),Pkg->SelectedState) == false)
227 return _error->Error("Malformed 1st word in the Status line");
228
229 // Isloate the next word
230 I++;
231 Start = I;
232 for(; I < Stop && *I != ' '; I++);
233 if (I >= Stop || *I != ' ')
234 return _error->Error("Malformed status line, no 2nd word");
235
236 // Process the flag field
237 WordList FlagList[] = {{"ok",pkgCache::Ok},
238 {"reinstreq",pkgCache::ReInstReq},
239 {"hold",pkgCache::HoldInst},
240 {"hold-reinstreq",pkgCache::HoldReInstReq}};
241 if (GrabWord(string(Start,I-Start),FlagList,
242 _count(FlagList),Pkg->InstState) == false)
243 return _error->Error("Malformed 2nd word in the Status line");
244
245 // Isloate the last word
246 I++;
247 Start = I;
248 for(; I < Stop && *I != ' '; I++);
249 if (I != Stop)
250 return _error->Error("Malformed Status line, no 3rd word");
251
252 // Process the flag field
253 WordList StatusList[] = {{"not-installed",pkgCache::NotInstalled},
254 {"unpacked",pkgCache::UnPacked},
255 {"half-configured",pkgCache::HalfConfigured},
256 {"installed",pkgCache::Installed},
257 {"uninstalled",pkgCache::UnInstalled},
258 {"half-installed",pkgCache::HalfInstalled},
259 {"config-files",pkgCache::ConfigFiles},
260 {"post-inst-failed",pkgCache::HalfConfigured},
261 {"removal-failed",pkgCache::HalfInstalled}};
262 if (GrabWord(string(Start,I-Start),StatusList,
263 _count(StatusList),Pkg->CurrentState) == false)
264 return _error->Error("Malformed 3rd word in the Status line");
265
266 /* A Status line marks the package as indicating the current
267 version as well. Only if it is actually installed.. Otherwise
268 the interesting dpkg handling of the status file creates bogus
269 entries. */
270 if (!(Pkg->CurrentState == pkgCache::NotInstalled ||
271 Pkg->CurrentState == pkgCache::ConfigFiles))
272 {
273 if (Ver.end() == true)
274 _error->Warning("Encountered status field in a non-version description");
275 else
276 Pkg->CurrentVer = Ver.Index();
277 }
278
279 return true;
280 }
281 /*}}}*/
282 // ListParser::GrabWord - Matches a word and returns /*{{{*/
283 // ---------------------------------------------------------------------
284 /* Looks for a word in a list of words - for ParseStatus */
285 bool debListParser::GrabWord(string Word,WordList *List,int Count,
286 unsigned char &Out)
287 {
288 for (int C = 0; C != Count; C++)
289 {
290 if (strcasecmp(Word.c_str(),List[C].Str) == 0)
291 {
292 Out = List[C].Val;
293 return true;
294 }
295 }
296 return false;
297 }
298 /*}}}*/
299 // ListParser::Step - Move to the next section in the file /*{{{*/
300 // ---------------------------------------------------------------------
301 /* This has to be carefull to only process the correct architecture */
302 bool debListParser::Step()
303 {
304 while (Tags.Step(Section) == true)
305 {
306 /* See if this is the correct Architecture, if it isnt then we
307 drop the whole section */
308 const char *Start;
309 const char *Stop;
310 if (Section.Find("Architecture",Start,Stop) == false)
311 return true;
312
313 if (strncmp(Start,"i386",Stop - Start) == 0 &&
314 strlen("i386") == (unsigned)(Stop - Start))
315 return true;
316
317 if (strncmp(Start,"all",Stop - Start) == 0 &&
318 3 == (unsigned)(Stop - Start))
319 return true;
320 }
321 return false;
322 }
323 /*}}}*/