]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.22 1999/07/30 02:54:25 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 return _error
->Error("Malformed Priority line");
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
159 for (; Start
!= End
; Start
++)
160 if (isspace(*Start
) == 0)
161 *I
++ = tolower(*Start
);
163 Result
= AddCRC16(Result
,S
,I
- S
);
169 // ListParser::ParseStatus - Parse the status field /*{{{*/
170 // ---------------------------------------------------------------------
171 /* Status lines are of the form,
172 Status: want flag status
173 want = unknown, install, hold, deinstall, purge
174 flag = ok, reinstreq, hold, hold-reinstreq
175 status = not-installed, unpacked, half-configured,
176 half-installed, config-files, post-inst-failed,
177 removal-failed, installed
179 Some of the above are obsolete (I think?) flag = hold-* and
180 status = post-inst-failed, removal-failed at least.
182 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
183 pkgCache::VerIterator Ver
)
187 if (Section
.Find("Status",Start
,Stop
) == false)
190 // Isolate the first word
191 const char *I
= Start
;
192 for(; I
< Stop
&& *I
!= ' '; I
++);
193 if (I
>= Stop
|| *I
!= ' ')
194 return _error
->Error("Malformed Status line");
196 // Process the want field
197 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
198 {"install",pkgCache::State::Install
},
199 {"hold",pkgCache::State::Hold
},
200 {"deinstall",pkgCache::State::DeInstall
},
201 {"purge",pkgCache::State::Purge
}};
202 if (GrabWord(string(Start
,I
-Start
),WantList
,
203 _count(WantList
),Pkg
->SelectedState
) == false)
204 return _error
->Error("Malformed 1st word in the Status line");
206 // Isloate the next word
209 for(; I
< Stop
&& *I
!= ' '; I
++);
210 if (I
>= Stop
|| *I
!= ' ')
211 return _error
->Error("Malformed status line, no 2nd word");
213 // Process the flag field
214 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
215 {"reinstreq",pkgCache::State::ReInstReq
},
216 {"hold",pkgCache::State::HoldInst
},
217 {"hold-reinstreq",pkgCache::State::HoldReInstReq
}};
218 if (GrabWord(string(Start
,I
-Start
),FlagList
,
219 _count(FlagList
),Pkg
->InstState
) == false)
220 return _error
->Error("Malformed 2nd word in the Status line");
222 // Isloate the last word
225 for(; I
< Stop
&& *I
!= ' '; I
++);
227 return _error
->Error("Malformed Status line, no 3rd word");
229 // Process the flag field
230 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
231 {"unpacked",pkgCache::State::UnPacked
},
232 {"half-configured",pkgCache::State::HalfConfigured
},
233 {"installed",pkgCache::State::Installed
},
234 {"half-installed",pkgCache::State::HalfInstalled
},
235 {"config-files",pkgCache::State::ConfigFiles
},
236 {"post-inst-failed",pkgCache::State::HalfConfigured
},
237 {"removal-failed",pkgCache::State::HalfInstalled
}};
238 if (GrabWord(string(Start
,I
-Start
),StatusList
,
239 _count(StatusList
),Pkg
->CurrentState
) == false)
240 return _error
->Error("Malformed 3rd word in the Status line");
242 /* A Status line marks the package as indicating the current
243 version as well. Only if it is actually installed.. Otherwise
244 the interesting dpkg handling of the status file creates bogus
246 if (!(Pkg
->CurrentState
== pkgCache::State::NotInstalled
||
247 Pkg
->CurrentState
== pkgCache::State::ConfigFiles
))
249 if (Ver
.end() == true)
250 _error
->Warning("Encountered status field in a non-version description");
252 Pkg
->CurrentVer
= Ver
.Index();
258 // ListParser::ParseDepends - Parse a dependency element /*{{{*/
259 // ---------------------------------------------------------------------
260 /* This parses the dependency elements out of a standard string in place,
262 const char *debListParser::ParseDepends(const char *Start
,const char *Stop
,
263 string
&Package
,string
&Ver
,
266 // Strip off leading space
267 for (;Start
!= Stop
&& isspace(*Start
) != 0; Start
++);
269 // Parse off the package name
270 const char *I
= Start
;
271 for (;I
!= Stop
&& isspace(*I
) == 0 && *I
!= '(' && *I
!= ')' &&
272 *I
!= ',' && *I
!= '|'; I
++);
275 if (I
!= Stop
&& *I
== ')')
281 // Stash the package name
282 Package
.assign(Start
,I
- Start
);
284 // Skip white space to the '('
285 for (;I
!= Stop
&& isspace(*I
) != 0 ; I
++);
288 if (I
!= Stop
&& *I
== '(')
291 for (I
++; I
!= Stop
&& isspace(*I
) != 0 ; I
++);
295 // Determine the operator
303 Op
= pkgCache::Dep::LessEq
;
310 Op
= pkgCache::Dep::Less
;
314 // < is the same as <= and << is really Cs < for some reason
315 Op
= pkgCache::Dep::LessEq
;
323 Op
= pkgCache::Dep::GreaterEq
;
330 Op
= pkgCache::Dep::Greater
;
334 // > is the same as >= and >> is really Cs > for some reason
335 Op
= pkgCache::Dep::GreaterEq
;
339 Op
= pkgCache::Dep::Equals
;
343 // HACK around bad package definitions
345 Op
= pkgCache::Dep::Equals
;
350 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
352 for (;I
!= Stop
&& *I
!= ')'; I
++);
353 if (I
== Stop
|| Start
== I
)
356 // Skip trailing whitespace
358 for (; End
> Start
&& isspace(End
[-1]); End
--);
360 Ver
= string(Start
,End
-Start
);
366 Op
= pkgCache::Dep::NoOp
;
370 for (;I
!= Stop
&& isspace(*I
) != 0; I
++);
371 if (I
!= Stop
&& *I
== '|')
372 Op
|= pkgCache::Dep::Or
;
374 if (I
== Stop
|| *I
== ',' || *I
== '|')
377 for (I
++; I
!= Stop
&& isspace(*I
) != 0; I
++);
384 // ListParser::ParseDepends - Parse a dependency list /*{{{*/
385 // ---------------------------------------------------------------------
386 /* This is the higher level depends parser. It takes a tag and generates
387 a complete depends tree for the given version. */
388 bool debListParser::ParseDepends(pkgCache::VerIterator Ver
,
389 const char *Tag
,unsigned int Type
)
393 if (Section
.Find(Tag
,Start
,Stop
) == false)
402 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
404 return _error
->Error("Problem parsing dependency %s",Tag
);
406 if (NewDepends(Ver
,Package
,Version
,Op
,Type
) == false)
414 // ListParser::ParseProvides - Parse the provides list /*{{{*/
415 // ---------------------------------------------------------------------
417 bool debListParser::ParseProvides(pkgCache::VerIterator Ver
)
421 if (Section
.Find("Provides",Start
,Stop
) == false)
430 Start
= ParseDepends(Start
,Stop
,Package
,Version
,Op
);
432 return _error
->Error("Problem parsing Provides line");
433 if (Op
!= pkgCache::Dep::NoOp
)
434 return _error
->Error("Malformed provides line");
436 if (NewProvides(Ver
,Package
,Version
) == false)
446 // ListParser::GrabWord - Matches a word and returns /*{{{*/
447 // ---------------------------------------------------------------------
448 /* Looks for a word in a list of words - for ParseStatus */
449 bool debListParser::GrabWord(string Word
,WordList
*List
,int Count
,
452 for (int C
= 0; C
!= Count
; C
++)
454 if (strcasecmp(Word
.c_str(),List
[C
].Str
) == 0)
463 // ListParser::Step - Move to the next section in the file /*{{{*/
464 // ---------------------------------------------------------------------
465 /* This has to be carefull to only process the correct architecture */
466 bool debListParser::Step()
468 iOffset
= Tags
.Offset();
469 while (Tags
.Step(Section
) == true)
471 /* See if this is the correct Architecture, if it isn't then we
472 drop the whole section. A missing arch tag only happens (in theory)
473 inside the Status file, so that is a positive return */
476 if (Section
.Find("Architecture",Start
,Stop
) == false)
479 if (stringcmp(Start
,Stop
,Arch
.begin(),Arch
.end()) == 0)
482 if (stringcmp(Start
,Stop
,"all") == 0)
485 iOffset
= Tags
.Offset();
490 // ListParser::LoadReleaseInfo - Load the release information /*{{{*/
491 // ---------------------------------------------------------------------
493 bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI
,
496 pkgTagFile
Tags(File
);
497 pkgTagSection Section
;
498 if (Tags
.Step(Section
) == false)
503 if (Section
.Find("Archive",Start
,Stop
) == true)
504 FileI
->Archive
= WriteUniqString(Start
,Stop
- Start
);
505 if (Section
.Find("Component",Start
,Stop
) == true)
506 FileI
->Component
= WriteUniqString(Start
,Stop
- Start
);
507 if (Section
.Find("Version",Start
,Stop
) == true)
508 FileI
->Version
= WriteUniqString(Start
,Stop
- Start
);
509 if (Section
.Find("Origin",Start
,Stop
) == true)
510 FileI
->Origin
= WriteUniqString(Start
,Stop
- Start
);
511 if (Section
.Find("Label",Start
,Stop
) == true)
512 FileI
->Label
= WriteUniqString(Start
,Stop
- Start
);
513 if (Section
.Find("Architecture",Start
,Stop
) == true)
514 FileI
->Architecture
= WriteUniqString(Start
,Stop
- Start
);
516 if (Section
.FindFlag("NotAutomatic",FileI
->Flags
,
517 pkgCache::Flag::NotAutomatic
) == false)
518 _error
->Warning("Bad NotAutomatic flag");
520 return !_error
->PendingError();