]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.23 1999/09/30 06:30:34 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>
17 #include <apt-pkg/crc-16.h>
22 // ListParser::debListParser - Constructor /*{{{*/
23 // ---------------------------------------------------------------------
25 debListParser::debListParser(FileFd
&File
) : Tags(File
)
27 Arch
= _config
->Find("APT::architecture");
30 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
31 // ---------------------------------------------------------------------
33 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
37 if (Section
.Find(Tag
,Start
,Stop
) == false)
39 return WriteUniqString(Start
,Stop
- Start
);
42 // ListParser::Package - Return the package name /*{{{*/
43 // ---------------------------------------------------------------------
44 /* This is to return the name of the package this section describes */
45 string
debListParser::Package()
47 string Result
= Section
.FindS("Package");
48 if (Result
.empty() == true)
49 _error
->Error("Encountered a section with no Package: header");
53 // ListParser::Version - Return the version string /*{{{*/
54 // ---------------------------------------------------------------------
55 /* This is to return the string describing the version in debian form,
56 epoch:upstream-release. If this returns the blank string then the
57 entry is assumed to only describe package properties */
58 string
debListParser::Version()
60 return Section
.FindS("Version");
63 // ListParser::NewVersion - Fill in the version structure /*{{{*/
64 // ---------------------------------------------------------------------
66 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
69 Ver
->Section
= UniqFindTagWrite("Section");
70 Ver
->Arch
= UniqFindTagWrite("Architecture");
73 Ver
->Size
= (unsigned)Section
.FindI("Size");
75 // Unpacked Size (in K)
76 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
77 Ver
->InstalledSize
*= 1024;
82 if (Section
.Find("Priority",Start
,Stop
) == true)
84 WordList PrioList
[] = {{"important",pkgCache::State::Important
},
85 {"required",pkgCache::State::Required
},
86 {"standard",pkgCache::State::Standard
},
87 {"optional",pkgCache::State::Optional
},
88 {"extra",pkgCache::State::Extra
}};
89 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,
90 _count(PrioList
),Ver
->Priority
) == false)
91 Ver
->Priority
= pkgCache::State::Extra
;
94 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
96 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
98 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
100 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
102 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
104 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
107 if (ParseProvides(Ver
) == false)
113 // ListParser::UsePackage - Update a package structure /*{{{*/
114 // ---------------------------------------------------------------------
115 /* This is called to update the package with any new information
116 that might be found in the section */
117 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
118 pkgCache::VerIterator Ver
)
120 if (Pkg
->Section
== 0)
121 Pkg
->Section
= UniqFindTagWrite("Section");
122 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
124 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
127 if (strcmp(Pkg
.Name(),"apt") == 0)
128 Pkg
->Flags
|= pkgCache::Flag::Important
;
130 if (ParseStatus(Pkg
,Ver
) == false)
135 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
136 // ---------------------------------------------------------------------
138 unsigned short debListParser::VersionHash()
140 const char *Sections
[] ={"Installed-Size",
147 unsigned long Result
= INIT_FCS
;
149 for (const char **I
= Sections
; *I
!= 0; I
++)
153 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
156 /* Strip out any spaces from the text, this undoes dpkgs reformatting
157 of certain fields. dpkg also has the rather interesting notion of
158 reformatting depends operators < -> <= */
160 for (; Start
!= End
; Start
++)
162 if (isspace(*Start
) == 0)
163 *I
++ = tolower(*Start
);
164 if (*Start
== '<' && Start
[1] != '<' && Start
[1] != '=')
166 if (*Start
== '>' && Start
[1] != '>' && Start
[1] != '=')
170 Result
= AddCRC16(Result
,S
,I
- S
);
176 // ListParser::ParseStatus - Parse the status field /*{{{*/
177 // ---------------------------------------------------------------------
178 /* Status lines are of the form,
179 Status: want flag status
180 want = unknown, install, hold, deinstall, purge
181 flag = ok, reinstreq, hold, hold-reinstreq
182 status = not-installed, unpacked, half-configured,
183 half-installed, config-files, post-inst-failed,
184 removal-failed, installed
186 Some of the above are obsolete (I think?) flag = hold-* and
187 status = post-inst-failed, removal-failed at least.
189 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
190 pkgCache::VerIterator Ver
)
194 if (Section
.Find("Status",Start
,Stop
) == false)
197 // Isolate the first word
198 const char *I
= Start
;
199 for(; I
< Stop
&& *I
!= ' '; I
++);
200 if (I
>= Stop
|| *I
!= ' ')
201 return _error
->Error("Malformed Status line");
203 // Process the want field
204 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
205 {"install",pkgCache::State::Install
},
206 {"hold",pkgCache::State::Hold
},
207 {"deinstall",pkgCache::State::DeInstall
},
208 {"purge",pkgCache::State::Purge
}};
209 if (GrabWord(string(Start
,I
-Start
),WantList
,
210 _count(WantList
),Pkg
->SelectedState
) == false)
211 return _error
->Error("Malformed 1st word in the Status line");
213 // Isloate the next word
216 for(; I
< Stop
&& *I
!= ' '; I
++);
217 if (I
>= Stop
|| *I
!= ' ')
218 return _error
->Error("Malformed status line, no 2nd word");
220 // Process the flag field
221 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
222 {"reinstreq",pkgCache::State::ReInstReq
},
223 {"hold",pkgCache::State::HoldInst
},
224 {"hold-reinstreq",pkgCache::State::HoldReInstReq
}};
225 if (GrabWord(string(Start
,I
-Start
),FlagList
,
226 _count(FlagList
),Pkg
->InstState
) == false)
227 return _error
->Error("Malformed 2nd word in the Status line");
229 // Isloate the last word
232 for(; I
< Stop
&& *I
!= ' '; I
++);
234 return _error
->Error("Malformed Status line, no 3rd word");
236 // Process the flag field
237 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
238 {"unpacked",pkgCache::State::UnPacked
},
239 {"half-configured",pkgCache::State::HalfConfigured
},
240 {"installed",pkgCache::State::Installed
},
241 {"half-installed",pkgCache::State::HalfInstalled
},
242 {"config-files",pkgCache::State::ConfigFiles
},
243 {"post-inst-failed",pkgCache::State::HalfConfigured
},
244 {"removal-failed",pkgCache::State::HalfInstalled
}};
245 if (GrabWord(string(Start
,I
-Start
),StatusList
,
246 _count(StatusList
),Pkg
->CurrentState
) == false)
247 return _error
->Error("Malformed 3rd word in the Status line");
249 /* A Status line marks the package as indicating the current
250 version as well. Only if it is actually installed.. Otherwise
251 the interesting dpkg handling of the status file creates bogus
253 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
254 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
256 if (Ver
.end() == true)
257 _error
->Warning("Encountered status field in a non-version description");
259 Pkg
->CurrentVer
= Ver
.Index();
265 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
266 // ---------------------------------------------------------------------
267 /* This parses the dependency elements out of a standard string in place,
269 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
270 string
&Package
,string
&Ver
,
273 // Strip off leading space
274 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
276 // Parse off the package name
277 const char *I
= Start
;
278 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
279 *I
!= ',' && *I
!= '|'; I
++);
282 if (I
!= Stop
&& *I
== ')')
288 // Stash the package name
289 Package
.assign(Start
,I
- Start
);
291 // Skip white space to the '('
292 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
295 if (I
!= Stop
&& *I
== '(')
298 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
302 // Determine the operator
310 Op
= pkgCache::Dep::LessEq
;
317 Op
= pkgCache::Dep::Less
;
321 // < is the same as <= and << is really Cs < for some reason
322 Op
= pkgCache::Dep::LessEq
;
330 Op
= pkgCache::Dep::GreaterEq
;
337 Op
= pkgCache::Dep::Greater
;
341 // > is the same as >= and >> is really Cs > for some reason
342 Op
= pkgCache::Dep::GreaterEq
;
346 Op
= pkgCache::Dep::Equals
;
350 // HACK around bad package definitions
352 Op
= pkgCache::Dep::Equals
;
357 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
359 for (;I
!= Stop
&& *I
!= ')'; I
++);
360 if (I
== Stop
|| Start
== I
)
363 // Skip trailing whitespace
365 for (; End
> Start
&& isspace(End
[-1]); End
--);
367 Ver
= string(Start
,End
-Start
);
373 Op
= pkgCache::Dep::NoOp
;
377 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
378 if (I
!= Stop
&& *I
== '|')
379 Op
|= pkgCache::Dep::Or
;
381 if (I
== Stop
|| *I
== ',' || *I
== '|')
384 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
391 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
392 // ---------------------------------------------------------------------
393 /* This is the higher level depends parser. It takes a tag and generates
394 a complete depends tree for the given version. */
395 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
396 const char *Tag
,unsigned int Type
)
400 if (Section
.Find(Tag
,Start
,Stop
) == false)
409 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
411 return _error
->Error("Problem parsing dependency %s",Tag
);
413 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
421 // ListParser::ParseProvides - Parse the provides list /*{{{*/
422 // ---------------------------------------------------------------------
424 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
428 if (Section
.Find("Provides",Start
,Stop
) == false)
437 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
439 return _error
->Error("Problem parsing Provides line");
440 if (Op
!= pkgCache::Dep::NoOp
)
441 return _error
->Error("Malformed provides line");
443 if (NewProvides(Ver
,Package
,Version
) == false)
453 // ListParser::GrabWord - Matches a word and returns /*{{{*/
454 // ---------------------------------------------------------------------
455 /* Looks for a word in a list of words - for ParseStatus */
456 bool debListParser::GrabWord(string Word
,WordList
*List
,int Count
,
459 for (int C
= 0; C
!= Count
; C
++)
461 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
470 // ListParser::Step - Move to the next section in the file /*{{{*/
471 // ---------------------------------------------------------------------
472 /* This has to be carefull to only process the correct architecture */
473 bool debListParser::Step()
475 iOffset
= Tags
.Offset();
476 while (Tags
.Step(Section
) == true)
478 /* See if this is the correct Architecture, if it isn't then we
479 drop the whole section. A missing arch tag only happens (in theory)
480 inside the Status file, so that is a positive return */
483 if (Section
.Find("Architecture",Start
,Stop
) == false)
486 if (stringcmp(Start
,Stop
,Arch
.begin(),Arch
.end()) == 0)
489 if (stringcmp(Start
,Stop
,"all") == 0)
492 iOffset
= Tags
.Offset();
497 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
498 // ---------------------------------------------------------------------
500 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
503 pkgTagFile
Tags(File
);
504 pkgTagSection Section
;
505 if (Tags
.Step(Section
) == false)
510 if (Section
.Find("Archive",Start
,Stop
) == true)
511 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
512 if (Section
.Find("Component",Start
,Stop
) == true)
513 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
514 if (Section
.Find("Version",Start
,Stop
) == true)
515 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
516 if (Section
.Find("Origin",Start
,Stop
) == true)
517 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
518 if (Section
.Find("Label",Start
,Stop
) == true)
519 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
520 if (Section
.Find("Architecture",Start
,Stop
) == true)
521 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
523 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
524 pkgCache::Flag::NotAutomatic
) == false)
525 _error
->Warning("Bad NotAutomatic flag");
527 return !_error
->PendingError();