]> git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
Fixed some display glitches
[apt.git] / apt-pkg / pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: pkgcachegen.cc,v 1.12 1998/07/21 05:33:19 jgg Exp $
4 /* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12 // Include Files /*{{{*/
13 #ifdef __GNUG__
14 #pragma implementation "apt-pkg/pkgcachegen.h"
15 #endif
16
17 #include <apt-pkg/pkgcachegen.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/version.h>
20 #include <strutl.h>
21
22 #include <sys/stat.h>
23 #include <unistd.h>
24 /*}}}*/
25
26 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
27 // ---------------------------------------------------------------------
28 /* We set the diry flag and make sure that is written to the disk */
29 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map,OpProgress &Prog) :
30 Map(Map), Cache(Map), Progress(Prog)
31 {
32 if (_error->PendingError() == true)
33 return;
34
35 if (Map.Size() == 0)
36 {
37 Map.RawAllocate(sizeof(pkgCache::Header));
38 *Cache.HeaderP = pkgCache::Header();
39 }
40 Cache.HeaderP->Dirty = true;
41 Map.Sync(0,sizeof(pkgCache::Header));
42 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
43 }
44 /*}}}*/
45 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
46 // ---------------------------------------------------------------------
47 /* We sync the data then unset the dirty flag in two steps so as to
48 advoid a problem during a crash */
49 pkgCacheGenerator::~pkgCacheGenerator()
50 {
51 if (_error->PendingError() == true)
52 return;
53 if (Map.Sync() == false)
54 return;
55
56 Cache.HeaderP->Dirty = false;
57 Map.Sync(0,sizeof(pkgCache::Header));
58 }
59 /*}}}*/
60 // CacheGenerator::MergeList - Merge the package list /*{{{*/
61 // ---------------------------------------------------------------------
62 /* This provides the generation of the entries in the cache. Each loop
63 goes through a single package record from the underlying parse engine. */
64 bool pkgCacheGenerator::MergeList(ListParser &List)
65 {
66 List.Owner = this;
67
68 while (List.Step() == true)
69 {
70 // Get a pointer to the package structure
71 string PackageName = List.Package();
72 pkgCache::PkgIterator Pkg;
73 if (NewPackage(Pkg,PackageName) == false)
74 return false;
75 Progress.Progress(List.Offset());
76
77 /* Get a pointer to the version structure. We know the list is sorted
78 so we use that fact in the search. Insertion of new versions is
79 done with correct sorting */
80 string Version = List.Version();
81 if (Version.empty() == true)
82 {
83 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
84 return false;
85 continue;
86 }
87
88 pkgCache::VerIterator Ver = Pkg.VersionList();
89 unsigned long *Last = &Pkg->VersionList;
90 int Res = 1;
91 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
92 {
93 Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
94 Ver.VerStr() + strlen(Ver.VerStr()));
95 if (Res >= 0)
96 break;
97 }
98
99 /* We already have a version for this item, record that we
100 saw it */
101 if (Res == 0)
102 {
103 if (List.UsePackage(Pkg,Ver) == false)
104 return false;
105
106 if (NewFileVer(Ver,List) == false)
107 return false;
108
109 continue;
110 }
111
112 // Add a new version
113 *Last = NewVersion(Ver,Version,*Last);
114 Ver->ParentPkg = Pkg.Index();
115 if (List.NewVersion(Ver) == false)
116 return false;
117
118 if (List.UsePackage(Pkg,Ver) == false)
119 return false;
120
121 if (NewFileVer(Ver,List) == false)
122 return false;
123 }
124
125 return true;
126 }
127 /*}}}*/
128 // CacheGenerator::NewPackage - Add a new package /*{{{*/
129 // ---------------------------------------------------------------------
130 /* This creates a new package structure and adds it to the hash table */
131 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
132 {
133 Pkg = Cache.FindPkg(Name);
134 if (Pkg.end() == false)
135 return true;
136
137 // Get a structure
138 unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
139 if (Package == 0)
140 return false;
141
142 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
143
144 // Insert it into the hash table
145 unsigned long Hash = Cache.Hash(Name);
146 Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
147 Cache.HeaderP->HashTable[Hash] = Package;
148
149 // Set the name and the ID
150 Pkg->Name = Map.WriteString(Name);
151 if (Pkg->Name == 0)
152 return false;
153 Pkg->ID = Cache.HeaderP->PackageCount++;
154
155 return true;
156 }
157 /*}}}*/
158 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
159 // ---------------------------------------------------------------------
160 /* */
161 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
162 ListParser &List)
163 {
164 // Get a structure
165 unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
166 if (VerFile == 0)
167 return 0;
168
169 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
170 VF->File = CurrentFile - Cache.PkgFileP;
171 VF->NextFile = Ver->FileList;
172 Ver->FileList = VF.Index();
173 VF->Offset = List.Offset();
174 VF->Size = List.Size();
175 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
176 Cache.HeaderP->MaxVerFileSize = VF->Size;
177 return true;
178 }
179 /*}}}*/
180 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
181 // ---------------------------------------------------------------------
182 /* This puts a version structure in the linked list */
183 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
184 string VerStr,
185 unsigned long Next)
186 {
187 // Get a structure
188 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
189 if (Version == 0)
190 return 0;
191
192 // Fill it in
193 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
194 Ver->NextVer = Next;
195 Ver->ID = Cache.HeaderP->VersionCount++;
196 Ver->VerStr = Map.WriteString(VerStr);
197 if (Ver->VerStr == 0)
198 return 0;
199
200 return Version;
201 }
202 /*}}}*/
203 // ListParser::NewDepends - Create a dependency element /*{{{*/
204 // ---------------------------------------------------------------------
205 /* This creates a dependency element in the tree. It is linked to the
206 version and to the package that it is pointing to. */
207 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
208 string PackageName,
209 string Version,
210 unsigned int Op,
211 unsigned int Type)
212 {
213 pkgCache &Cache = Owner->Cache;
214
215 // Get a structure
216 unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
217 if (Dependency == 0)
218 return false;
219
220 // Fill it in
221 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
222 Dep->ParentVer = Ver.Index();
223 Dep->Type = Type;
224 Dep->CompareOp = Op;
225 Dep->ID = Cache.HeaderP->DependsCount++;
226
227 // Locate the target package
228 pkgCache::PkgIterator Pkg;
229 if (Owner->NewPackage(Pkg,PackageName) == false)
230 return false;
231
232 // Probe the reverse dependency list for a version string that matches
233 if (Version.empty() == false)
234 {
235 for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
236 if (I->Version != 0 && I.TargetVer() == Version)
237 Dep->Version = I->Version;
238 if (Dep->Version == 0)
239 if ((Dep->Version = WriteString(Version)) == 0)
240 return false;
241 }
242
243 // Link it to the package
244 Dep->Package = Pkg.Index();
245 Dep->NextRevDepends = Pkg->RevDepends;
246 Pkg->RevDepends = Dep.Index();
247
248 // Link it to the version (at the end of the list)
249 unsigned long *Last = &Ver->DependsList;
250 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
251 Last = &D->NextDepends;
252 Dep->NextDepends = *Last;
253 *Last = Dep.Index();
254
255 return true;
256 }
257 /*}}}*/
258 // ListParser::NewProvides - Create a Provides element /*{{{*/
259 // ---------------------------------------------------------------------
260 /* */
261 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
262 string PackageName,
263 string Version)
264 {
265 pkgCache &Cache = Owner->Cache;
266
267 // We do not add self referencing provides
268 if (Ver.ParentPkg().Name() == PackageName)
269 return true;
270
271 // Get a structure
272 unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
273 if (Provides == 0)
274 return false;
275
276 // Fill it in
277 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
278 Prv->Version = Ver.Index();
279 Prv->NextPkgProv = Ver->ProvidesList;
280 Ver->ProvidesList = Prv.Index();
281 if (Version.empty() == false && (Prv->Version = WriteString(Version)) == 0)
282 return false;
283
284 // Locate the target package
285 pkgCache::PkgIterator Pkg;
286 if (Owner->NewPackage(Pkg,PackageName) == false)
287 return false;
288
289 // Link it to the package
290 Prv->ParentPkg = Pkg.Index();
291 Prv->NextProvides = Pkg->ProvidesList;
292 Pkg->ProvidesList = Prv.Index();
293
294 return true;
295 }
296 /*}}}*/
297 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
298 // ---------------------------------------------------------------------
299 /* This is used to select which file is to be associated with all newly
300 added versions. */
301 bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
302 {
303 struct stat Buf;
304 if (stat(File.c_str(),&Buf) == -1)
305 return _error->Errno("stat","Couldn't stat ",File.c_str());
306
307 // Get some space for the structure
308 CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
309 if (CurrentFile == Cache.PkgFileP)
310 return false;
311
312 // Fill it in
313 CurrentFile->FileName = Map.WriteString(File);
314 CurrentFile->Size = Buf.st_size;
315 CurrentFile->mtime = Buf.st_mtime;
316 CurrentFile->NextFile = Cache.HeaderP->FileList;
317 CurrentFile->Flags = Flags;
318 PkgFileName = File;
319 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
320
321 if (CurrentFile->FileName == 0)
322 return false;
323
324 Progress.SubProgress(Buf.st_size,File);
325 return true;
326 }
327 /*}}}*/
328 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
329 // ---------------------------------------------------------------------
330 /* This is used to create handles to strings. Given the same text it
331 always returns the same number */
332 unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
333 unsigned int Size)
334 {
335 // Search for an insertion point
336 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
337 int Res = 1;
338 unsigned long *Last = &Cache.HeaderP->StringList;
339 for (; I != Cache.StringItemP; Last = &I->NextItem,
340 I = Cache.StringItemP + I->NextItem)
341 {
342 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
343 if (Res >= 0)
344 break;
345 }
346
347 // Match
348 if (Res == 0)
349 return I->String;
350
351 // Get a structure
352 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
353 if (Item == 0)
354 return 0;
355
356 // Fill in the structure
357 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
358 ItemP->NextItem = I - Cache.StringItemP;
359 *Last = Item;
360 ItemP->String = Map.WriteString(S,Size);
361 if (ItemP->String == 0)
362 return 0;
363
364 return ItemP->String;
365 }
366 /*}}}*/