]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
5fbb43a9f357e06c6e2ba2d91b7a368d34438882
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.4 1998/07/07 04:17:16 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 <pkglib/deblistparser.h>
14 #include <pkglib/error.h>
18 // ListParser::debListParser - Constructor /*{{{*/
19 // ---------------------------------------------------------------------
21 debListParser::debListParser(File
&File
) : Tags(File
)
25 // ListParser::FindTag - Find the tag and return a string /*{{{*/
26 // ---------------------------------------------------------------------
28 string
debListParser::FindTag(const char *Tag
)
32 if (Section
.Find(Tag
,Start
,Stop
) == false)
34 return string(Start
,Stop
- Start
);
37 // ListParser::FindTagI - Find the tag and return an int /*{{{*/
38 // ---------------------------------------------------------------------
40 signed long debListParser::FindTagI(const char *Tag
,signed long Default
)
44 if (Section
.Find(Tag
,Start
,Stop
) == false)
47 // Copy it into a temp buffer so we can use strtol
49 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
51 strncpy(S
,Start
,Stop
-Start
);
55 signed long Result
= strtol(S
,&End
,10);
61 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
62 // ---------------------------------------------------------------------
64 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
68 if (Section
.Find(Tag
,Start
,Stop
) == false)
70 return WriteUniqString(Start
,Stop
- Start
);
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
,
81 if (Section
.Find(Tag
,Start
,Stop
) == false)
85 if (strncasecmp(Start
,"yes",Stop
- Start
) == 0)
87 if (strncasecmp(Start
,"true",Stop
- Start
) == 0)
89 if (strncasecmp(Start
,"no",Stop
- Start
) == 0)
91 if (strncasecmp(Start
,"false",Stop
- Start
) == 0)
95 _error
->Warning("Unknown flag value");
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()
111 string Result
= FindTag("Package");
112 if (Result
.empty() == true)
113 _error
->Error("Encoutered a section with no Package: header");
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()
124 return FindTag("Version");
127 // ListParser::NewVersion - Fill in the version structure /*{{{*/
128 // ---------------------------------------------------------------------
130 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
133 if ((Ver
->Section
= UniqFindTagWrite("Section")) == 0)
134 return _error
->Warning("Missing Section tag");
137 if ((Ver
->Size
= (unsigned)FindTagI("Size")) == 0)
138 return _error
->Error("Unparsable Size field");
140 // Unpacked Size (in K)
141 if ((Ver
->InstalledSize
= (unsigned)FindTagI("Installed-Size")) == 0)
142 return _error
->Error("Unparsable Installed-Size field");
143 Ver
->InstalledSize
*= 1024;
148 if (Section
.Find("Priority",Start
,Stop
) == true)
150 WordList PrioList
[] = {{"important",pkgCache::State::Important
},
151 {"required",pkgCache::State::Required
},
152 {"standard",pkgCache::State::Standard
},
153 {"optional",pkgCache::State::Optional
},
154 {"extra",pkgCache::State::Extra
}};
155 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,
156 _count(PrioList
),Ver
->Priority
) == false)
157 return _error
->Error("Malformed Priority line");
160 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
162 if (ParseDepends(Ver
,"PreDepends",pkgCache::Dep::PreDepends
) == false)
164 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
166 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
168 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
170 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Depends
) == false)
173 if (ParseProvides(Ver
) == false)
179 // ListParser::UsePackage - Update a package structure /*{{{*/
180 // ---------------------------------------------------------------------
181 /* This is called to update the package with any new information
182 that might be found in the section */
183 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
184 pkgCache::VerIterator Ver
)
186 if (Pkg
->Section
== 0)
187 if ((Pkg
->Section
= UniqFindTagWrite("Section")) == 0)
189 if (HandleFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
191 if (HandleFlag("Immediate-Configure",Pkg
->Flags
,pkgCache::Flag::ImmediateConf
) == false)
193 if (ParseStatus(Pkg
,Ver
) == false)
198 // ListParser::ParseStatus - Parse the status field /*{{{*/
199 // ---------------------------------------------------------------------
200 /* Status lines are of the form,
201 Status: want flag status
202 want = unknown, install, hold, deinstall, purge
203 flag = ok, reinstreq, hold, hold-reinstreq
204 status = not-installed, unpacked, half-configured, uninstalled,
205 half-installed, config-files, post-inst-failed,
206 removal-failed, installed
208 Some of the above are obsolete (I think?) flag = hold-* and
209 status = post-inst-failed, removal-failed at least.
211 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
212 pkgCache::VerIterator Ver
)
216 if (Section
.Find("Status",Start
,Stop
) == false)
219 // Isolate the first word
220 const char *I
= Start
;
221 for(; I
< Stop
&& *I
!= ' '; I
++);
222 if (I
>= Stop
|| *I
!= ' ')
223 return _error
->Error("Malformed Status line");
225 // Process the want field
226 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
227 {"install",pkgCache::State::Install
},
228 {"hold",pkgCache::State::Hold
},
229 {"deinstall",pkgCache::State::DeInstall
},
230 {"purge",pkgCache::State::Purge
}};
231 if (GrabWord(string(Start
,I
-Start
),WantList
,
232 _count(WantList
),Pkg
->SelectedState
) == false)
233 return _error
->Error("Malformed 1st word in the Status line");
235 // Isloate the next word
238 for(; I
< Stop
&& *I
!= ' '; I
++);
239 if (I
>= Stop
|| *I
!= ' ')
240 return _error
->Error("Malformed status line, no 2nd word");
242 // Process the flag field
243 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
244 {"reinstreq",pkgCache::State::ReInstReq
},
245 {"hold",pkgCache::State::HoldInst
},
246 {"hold-reinstreq",pkgCache::State::HoldReInstReq
}};
247 if (GrabWord(string(Start
,I
-Start
),FlagList
,
248 _count(FlagList
),Pkg
->InstState
) == false)
249 return _error
->Error("Malformed 2nd word in the Status line");
251 // Isloate the last word
254 for(; I
< Stop
&& *I
!= ' '; I
++);
256 return _error
->Error("Malformed Status line, no 3rd word");
258 // Process the flag field
259 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
260 {"unpacked",pkgCache::State::UnPacked
},
261 {"half-configured",pkgCache::State::HalfConfigured
},
262 {"installed",pkgCache::State::Installed
},
263 {"uninstalled",pkgCache::State::UnInstalled
},
264 {"half-installed",pkgCache::State::HalfInstalled
},
265 {"config-files",pkgCache::State::ConfigFiles
},
266 {"post-inst-failed",pkgCache::State::HalfConfigured
},
267 {"removal-failed",pkgCache::State::HalfInstalled
}};
268 if (GrabWord(string(Start
,I
-Start
),StatusList
,
269 _count(StatusList
),Pkg
->CurrentState
) == false)
270 return _error
->Error("Malformed 3rd word in the Status line");
272 /* A Status line marks the package as indicating the current
273 version as well. Only if it is actually installed.. Otherwise
274 the interesting dpkg handling of the status file creates bogus
276 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
277 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
279 if (Ver
.end() == true)
280 _error
->Warning("Encountered status field in a non-version description");
282 Pkg
->CurrentVer
= Ver
.Index();
288 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
289 // ---------------------------------------------------------------------
290 /* This parses the dependency elements out of a standard string in place,
292 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
293 string
&Package
,string
&Ver
,
296 // Strip off leading space
297 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
299 // Parse off the package name
300 const char *I
= Start
;
301 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
302 *I
!= ',' && *I
!= '|'; I
++);
305 if (I
!= Stop
&& *I
== ')')
311 // Stash the package name
312 Package
.assign(Start
,I
- Start
);
314 // Skip white space to the '('
315 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
318 if (I
!= Stop
&& *I
== '(')
321 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
325 // Determine the operator
333 Op
= pkgCache::Dep::LessEq
;
340 Op
= pkgCache::Dep::Less
;
344 // < is the same as <= and << is really Cs < for some reason
345 Op
= pkgCache::Dep::LessEq
;
353 Op
= pkgCache::Dep::GreaterEq
;
360 Op
= pkgCache::Dep::Greater
;
364 // > is the same as >= and >> is really Cs > for some reason
365 Op
= pkgCache::Dep::GreaterEq
;
369 Op
= pkgCache::Dep::Equals
;
373 // HACK around bad package definitions
375 Op
= pkgCache::Dep::Equals
;
380 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
382 for (;I
!= Stop
&& *I
!= ')'; I
++);
383 if (I
== Stop
|| Start
== I
)
386 Ver
= string(Start
,I
-Start
);
392 Op
= pkgCache::Dep::NoOp
;
396 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
397 if (I
!= Stop
&& *I
== '|')
398 Op
|= pkgCache::Dep::Or
;
400 if (I
== Stop
|| *I
== ',' || *I
== '|')
403 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
410 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
411 // ---------------------------------------------------------------------
412 /* This is the higher level depends parser. It takes a tag and generates
413 a complete depends tree for the given version. */
414 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
415 const char *Tag
,unsigned int Type
)
419 if (Section
.Find(Tag
,Start
,Stop
) == false)
426 while ((Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
)) != Stop
)
429 return _error
->Error("Problem parsing dependency %s",Tag
);
431 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
437 // ListParser::ParseProvides - Parse the provides list /*{{{*/
438 // ---------------------------------------------------------------------
440 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
444 if (Section
.Find("Provides",Start
,Stop
) == false)
453 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
455 return _error
->Error("Problem parsing Provides line");
456 if (Op
!= pkgCache::Dep::NoOp
)
457 return _error
->Error("Malformed provides line");
459 if (NewProvides(Ver
,Package
,Version
) == false)
469 // ListParser::GrabWord - Matches a word and returns /*{{{*/
470 // ---------------------------------------------------------------------
471 /* Looks for a word in a list of words - for ParseStatus */
472 bool debListParser::GrabWord(string Word
,WordList
*List
,int Count
,
475 for (int C
= 0; C
!= Count
; C
++)
477 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
486 // ListParser::Step - Move to the next section in the file /*{{{*/
487 // ---------------------------------------------------------------------
488 /* This has to be carefull to only process the correct architecture */
489 bool debListParser::Step()
491 iOffset
= Tags
.Offset();
492 while (Tags
.Step(Section
) == true)
494 /* See if this is the correct Architecture, if it isnt then we
495 drop the whole section */
498 if (Section
.Find("Architecture",Start
,Stop
) == false)
501 if (strncmp(Start
,"i386",Stop
- Start
) == 0 &&
502 strlen("i386") == (unsigned)(Stop
- Start
))
505 if (strncmp(Start
,"all",Stop
- Start
) == 0 &&
506 3 == (unsigned)(Stop
- Start
))
509 iOffset
= Tags
.Offset();