]>
git.saurik.com Git - apt.git/blob - apt-pkg/deb/deblistparser.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: deblistparser.cc,v 1.19 1999/05/23 22:55:54 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
)
29 // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
30 // ---------------------------------------------------------------------
32 unsigned long debListParser::UniqFindTagWrite(const char *Tag
)
36 if (Section
.Find(Tag
,Start
,Stop
) == false)
38 return WriteUniqString(Start
,Stop
- Start
);
41 // ListParser::Package - Return the package name /*{{{*/
42 // ---------------------------------------------------------------------
43 /* This is to return the name of the package this section describes */
44 string
debListParser::Package()
46 string Result
= Section
.FindS("Package");
47 if (Result
.empty() == true)
48 _error
->Error("Encountered a section with no Package: header");
52 // ListParser::Version - Return the version string /*{{{*/
53 // ---------------------------------------------------------------------
54 /* This is to return the string describing the version in debian form,
55 epoch:upstream-release. If this returns the blank string then the
56 entry is assumed to only describe package properties */
57 string
debListParser::Version()
59 return Section
.FindS("Version");
62 // ListParser::NewVersion - Fill in the version structure /*{{{*/
63 // ---------------------------------------------------------------------
65 bool debListParser::NewVersion(pkgCache::VerIterator Ver
)
68 Ver
->Section
= UniqFindTagWrite("Section");
69 Ver
->Arch
= UniqFindTagWrite("Architecture");
72 Ver
->Size
= (unsigned)Section
.FindI("Size");
74 // Unpacked Size (in K)
75 Ver
->InstalledSize
= (unsigned)Section
.FindI("Installed-Size");
76 Ver
->InstalledSize
*= 1024;
81 if (Section
.Find("Priority",Start
,Stop
) == true)
83 WordList PrioList
[] = {{"important",pkgCache::State::Important
},
84 {"required",pkgCache::State::Required
},
85 {"standard",pkgCache::State::Standard
},
86 {"optional",pkgCache::State::Optional
},
87 {"extra",pkgCache::State::Extra
}};
88 if (GrabWord(string(Start
,Stop
-Start
),PrioList
,
89 _count(PrioList
),Ver
->Priority
) == false)
90 return _error
->Error("Malformed Priority line");
93 if (ParseDepends(Ver
,"Depends",pkgCache::Dep::Depends
) == false)
95 if (ParseDepends(Ver
,"Pre-Depends",pkgCache::Dep::PreDepends
) == false)
97 if (ParseDepends(Ver
,"Suggests",pkgCache::Dep::Suggests
) == false)
99 if (ParseDepends(Ver
,"Recommends",pkgCache::Dep::Recommends
) == false)
101 if (ParseDepends(Ver
,"Conflicts",pkgCache::Dep::Conflicts
) == false)
103 if (ParseDepends(Ver
,"Replaces",pkgCache::Dep::Replaces
) == false)
106 if (ParseProvides(Ver
) == false)
112 // ListParser::UsePackage - Update a package structure /*{{{*/
113 // ---------------------------------------------------------------------
114 /* This is called to update the package with any new information
115 that might be found in the section */
116 bool debListParser::UsePackage(pkgCache::PkgIterator Pkg
,
117 pkgCache::VerIterator Ver
)
119 if (Pkg
->Section
== 0)
120 Pkg
->Section
= UniqFindTagWrite("Section");
121 if (Section
.FindFlag("Essential",Pkg
->Flags
,pkgCache::Flag::Essential
) == false)
123 if (Section
.FindFlag("Important",Pkg
->Flags
,pkgCache::Flag::Important
) == false)
126 if (strcmp(Pkg
.Name(),"apt") == 0)
127 Pkg
->Flags
|= pkgCache::Flag::Important
;
129 if (ParseStatus(Pkg
,Ver
) == false)
134 // ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
135 // ---------------------------------------------------------------------
137 unsigned short debListParser::VersionHash()
139 const char *Sections
[] ={"Installed-Size",
146 unsigned long Result
= INIT_FCS
;
148 for (const char **I
= Sections
; *I
!= 0; I
++)
152 if (Section
.Find(*I
,Start
,End
) == false || End
- Start
>= (signed)sizeof(S
))
155 /* Strip out any spaces from the text, this undoes dpkgs reformatting
158 for (; Start
!= End
; Start
++)
159 if (isspace(*Start
) == 0)
162 Result
= AddCRC16(Result
,S
,I
- S
);
168 // ListParser::ParseStatus - Parse the status field /*{{{*/
169 // ---------------------------------------------------------------------
170 /* Status lines are of the form,
171 Status: want flag status
172 want = unknown, install, hold, deinstall, purge
173 flag = ok, reinstreq, hold, hold-reinstreq
174 status = not-installed, unpacked, half-configured, uninstalled,
175 half-installed, config-files, post-inst-failed,
176 removal-failed, installed
178 Some of the above are obsolete (I think?) flag = hold-* and
179 status = post-inst-failed, removal-failed at least.
181 bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg
,
182 pkgCache::VerIterator Ver
)
186 if (Section
.Find("Status",Start
,Stop
) == false)
189 // Isolate the first word
190 const char *I
= Start
;
191 for(; I
< Stop
&& *I
!= ' '; I
++);
192 if (I
>= Stop
|| *I
!= ' ')
193 return _error
->Error("Malformed Status line");
195 // Process the want field
196 WordList WantList
[] = {{"unknown",pkgCache::State::Unknown
},
197 {"install",pkgCache::State::Install
},
198 {"hold",pkgCache::State::Hold
},
199 {"deinstall",pkgCache::State::DeInstall
},
200 {"purge",pkgCache::State::Purge
}};
201 if (GrabWord(string(Start
,I
-Start
),WantList
,
202 _count(WantList
),Pkg
->SelectedState
) == false)
203 return _error
->Error("Malformed 1st word in the Status line");
205 // Isloate the next word
208 for(; I
< Stop
&& *I
!= ' '; I
++);
209 if (I
>= Stop
|| *I
!= ' ')
210 return _error
->Error("Malformed status line, no 2nd word");
212 // Process the flag field
213 WordList FlagList
[] = {{"ok",pkgCache::State::Ok
},
214 {"reinstreq",pkgCache::State::ReInstReq
},
215 {"hold",pkgCache::State::HoldInst
},
216 {"hold-reinstreq",pkgCache::State::HoldReInstReq
}};
217 if (GrabWord(string(Start
,I
-Start
),FlagList
,
218 _count(FlagList
),Pkg
->InstState
) == false)
219 return _error
->Error("Malformed 2nd word in the Status line");
221 // Isloate the last word
224 for(; I
< Stop
&& *I
!= ' '; I
++);
226 return _error
->Error("Malformed Status line, no 3rd word");
228 // Process the flag field
229 WordList StatusList
[] = {{"not-installed",pkgCache::State::NotInstalled
},
230 {"unpacked",pkgCache::State::UnPacked
},
231 {"half-configured",pkgCache::State::HalfConfigured
},
232 {"installed",pkgCache::State::Installed
},
233 {"uninstalled",pkgCache::State::UnInstalled
},
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 string Arch
= _config
->Find("APT::architecture");
470 while (Tags
.Step(Section
) == true)
472 /* See if this is the correct Architecture, if it isnt then we
473 drop the whole section */
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();