]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.10 1998/08/09 00:51:35 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>
21 // ListParser::debListParser - Constructor /*{{{*/
22 // ---------------------------------------------------------------------
24 debListParser::debListParser(FileFd
&File
) : Tags(File
)
28 // ListParser::FindTag - Find the tag and return a string /*{{{*/
29 // ---------------------------------------------------------------------
31 string
debListParser::FindTag(const char *Tag
)
35 if (Section
.Find(Tag
,Start
,Stop
) == false)
37 return string(Start
,Stop
- Start
);
40 // ListParser::FindTagI - Find the tag and return an int /*{{{*/
41 // ---------------------------------------------------------------------
43 signed long debListParser::FindTagI(const char *Tag
,signed long Default
)
47 if (Section
.Find(Tag
,Start
,Stop
) == false)
50 // Copy it into a temp buffer so we can use strtol
52 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
54 strncpy(S
,Start
,Stop
-Start
);
58 signed long Result
= strtol(S
,&End
,10);
64 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
65 // ---------------------------------------------------------------------
67 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
71 if (Section
.Find(Tag
,Start
,Stop
) == false)
73 return WriteUniqString(Start
,Stop
- Start
);
76 // ListParser::HandleFlag - Sets a flag variable based on a tag /*{{{*/
77 // ---------------------------------------------------------------------
78 /* This checks the tag for true/false yes/no etc */
79 bool debListParser::HandleFlag(const char *Tag
,unsigned long &Flags
,
84 if (Section
.Find(Tag
,Start
,Stop
) == false)
88 if (stringcasecmp(Start
,Stop
,"yes") == 0)
90 if (stringcasecmp(Start
,Stop
,"true") == 0)
92 if (stringcasecmp(Start
,Stop
,"no") == 0)
94 if (stringcasecmp(Start
,Stop
,"false") == 0)
98 _error
->Warning("Unknown flag value");
109 // ListParser::Package - Return the package name /*{{{*/
110 // ---------------------------------------------------------------------
111 /* This is to return the name of the package this section describes */
112 string
debListParser::Package()
114 string Result
= FindTag("Package");
115 if (Result
.empty() == true)
116 _error
->Error("Encoutered a section with no Package: header");
120 // ListParser::Version - Return the version string /*{{{*/
121 // ---------------------------------------------------------------------
122 /* This is to return the string describing the version in debian form,
123 epoch:upstream-release. If this returns the blank string then the
124 entry is assumed to only describe package properties */
125 string
debListParser::Version()
127 return FindTag("Version");
130 // ListParser::NewVersion - Fill in the version structure /*{{{*/
131 // ---------------------------------------------------------------------
133 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
136 Ver
->Section
= UniqFindTagWrite("Section");
139 Ver
->Size
= (unsigned)FindTagI("Size");
141 // Unpacked Size (in K)
142 Ver
->InstalledSize
= (unsigned)FindTagI("Installed-Size");
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
,"Pre-Depends",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::Replaces
) == 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 Pkg
->Section
= UniqFindTagWrite("Section");
188 if (HandleFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
190 if (HandleFlag("Immediate-Configure",Pkg
->Flags
,pkgCache::Flag::ImmediateConf
) == false)
192 if (ParseStatus(Pkg
,Ver
) == false)
197 // ListParser::ParseStatus - Parse the status field /*{{{*/
198 // ---------------------------------------------------------------------
199 /* Status lines are of the form,
200 Status: want flag status
201 want = unknown, install, hold, deinstall, purge
202 flag = ok, reinstreq, hold, hold-reinstreq
203 status = not-installed, unpacked, half-configured, uninstalled,
204 half-installed, config-files, post-inst-failed,
205 removal-failed, installed
207 Some of the above are obsolete (I think?) flag = hold-* and
208 status = post-inst-failed, removal-failed at least.
210 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
211 pkgCache::VerIterator Ver
)
215 if (Section
.Find("Status",Start
,Stop
) == false)
218 // Isolate the first word
219 const char *I
= Start
;
220 for(; I
< Stop
&& *I
!= ' '; I
++);
221 if (I
>= Stop
|| *I
!= ' ')
222 return _error
->Error("Malformed Status line");
224 // Process the want field
225 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
226 {"install",pkgCache::State::Install
},
227 {"hold",pkgCache::State::Hold
},
228 {"deinstall",pkgCache::State::DeInstall
},
229 {"purge",pkgCache::State::Purge
}};
230 if (GrabWord(string(Start
,I
-Start
),WantList
,
231 _count(WantList
),Pkg
->SelectedState
) == false)
232 return _error
->Error("Malformed 1st word in the Status line");
234 // Isloate the next word
237 for(; I
< Stop
&& *I
!= ' '; I
++);
238 if (I
>= Stop
|| *I
!= ' ')
239 return _error
->Error("Malformed status line, no 2nd word");
241 // Process the flag field
242 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
243 {"reinstreq",pkgCache::State::ReInstReq
},
244 {"hold",pkgCache::State::HoldInst
},
245 {"hold-reinstreq",pkgCache::State::HoldReInstReq
}};
246 if (GrabWord(string(Start
,I
-Start
),FlagList
,
247 _count(FlagList
),Pkg
->InstState
) == false)
248 return _error
->Error("Malformed 2nd word in the Status line");
250 // Isloate the last word
253 for(; I
< Stop
&& *I
!= ' '; I
++);
255 return _error
->Error("Malformed Status line, no 3rd word");
257 // Process the flag field
258 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
259 {"unpacked",pkgCache::State::UnPacked
},
260 {"half-configured",pkgCache::State::HalfConfigured
},
261 {"installed",pkgCache::State::Installed
},
262 {"uninstalled",pkgCache::State::UnInstalled
},
263 {"half-installed",pkgCache::State::HalfInstalled
},
264 {"config-files",pkgCache::State::ConfigFiles
},
265 {"post-inst-failed",pkgCache::State::HalfConfigured
},
266 {"removal-failed",pkgCache::State::HalfInstalled
}};
267 if (GrabWord(string(Start
,I
-Start
),StatusList
,
268 _count(StatusList
),Pkg
->CurrentState
) == false)
269 return _error
->Error("Malformed 3rd word in the Status line");
271 /* A Status line marks the package as indicating the current
272 version as well. Only if it is actually installed.. Otherwise
273 the interesting dpkg handling of the status file creates bogus
275 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
276 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
278 if (Ver
.end() == true)
279 _error
->Warning("Encountered status field in a non-version description");
281 Pkg
->CurrentVer
= Ver
.Index();
287 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
288 // ---------------------------------------------------------------------
289 /* This parses the dependency elements out of a standard string in place,
291 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
292 string
&Package
,string
&Ver
,
295 // Strip off leading space
296 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
298 // Parse off the package name
299 const char *I
= Start
;
300 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
301 *I
!= ',' && *I
!= '|'; I
++);
304 if (I
!= Stop
&& *I
== ')')
310 // Stash the package name
311 Package
.assign(Start
,I
- Start
);
313 // Skip white space to the '('
314 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
317 if (I
!= Stop
&& *I
== '(')
320 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
324 // Determine the operator
332 Op
= pkgCache::Dep::LessEq
;
339 Op
= pkgCache::Dep::Less
;
343 // < is the same as <= and << is really Cs < for some reason
344 Op
= pkgCache::Dep::LessEq
;
352 Op
= pkgCache::Dep::GreaterEq
;
359 Op
= pkgCache::Dep::Greater
;
363 // > is the same as >= and >> is really Cs > for some reason
364 Op
= pkgCache::Dep::GreaterEq
;
368 Op
= pkgCache::Dep::Equals
;
372 // HACK around bad package definitions
374 Op
= pkgCache::Dep::Equals
;
379 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
381 for (;I
!= Stop
&& *I
!= ')'; I
++);
382 if (I
== Stop
|| Start
== I
)
385 Ver
= string(Start
,I
-Start
);
391 Op
= pkgCache::Dep::NoOp
;
395 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
396 if (I
!= Stop
&& *I
== '|')
397 Op
|= pkgCache::Dep::Or
;
399 if (I
== Stop
|| *I
== ',' || *I
== '|')
402 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
409 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
410 // ---------------------------------------------------------------------
411 /* This is the higher level depends parser. It takes a tag and generates
412 a complete depends tree for the given version. */
413 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
414 const char *Tag
,unsigned int Type
)
418 if (Section
.Find(Tag
,Start
,Stop
) == false)
427 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
429 return _error
->Error("Problem parsing dependency %s",Tag
);
431 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
439 // ListParser::ParseProvides - Parse the provides list /*{{{*/
440 // ---------------------------------------------------------------------
442 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
446 if (Section
.Find("Provides",Start
,Stop
) == false)
455 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
457 return _error
->Error("Problem parsing Provides line");
458 if (Op
!= pkgCache::Dep::NoOp
)
459 return _error
->Error("Malformed provides line");
461 if (NewProvides(Ver
,Package
,Version
) == false)
471 // ListParser::GrabWord - Matches a word and returns /*{{{*/
472 // ---------------------------------------------------------------------
473 /* Looks for a word in a list of words - for ParseStatus */
474 bool debListParser::GrabWord(string Word
,WordList
*List
,int Count
,
477 for (int C
= 0; C
!= Count
; C
++)
479 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
488 // ListParser::Step - Move to the next section in the file /*{{{*/
489 // ---------------------------------------------------------------------
490 /* This has to be carefull to only process the correct architecture */
491 bool debListParser::Step()
493 iOffset
= Tags
.Offset();
494 string Arch
= _config
->Find("APT::architecture");
495 while (Tags
.Step(Section
) == true)
497 /* See if this is the correct Architecture, if it isnt then we
498 drop the whole section */
501 if (Section
.Find("Architecture",Start
,Stop
) == false)
504 if (stringcmp(Start
,Stop
,Arch
.begin(),Arch
.end()) == 0)
507 if (stringcmp(Start
,Stop
,"all") == 0)
510 iOffset
= Tags
.Offset();