]> git.saurik.com Git - apt.git/blame - apt-pkg/tagfile.cc
Clean support
[apt.git] / apt-pkg / tagfile.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
f3bcc383 3// $Id: tagfile.cc,v 1.22 1999/01/31 21:52:27 jgg Exp $
578bfd0a
AL
4/* ######################################################################
5
6 Fast scanner for RFC-822 type header information
7
ad00ae81 8 This uses a rotating buffer to load the package information into.
578bfd0a
AL
9 The scanner runs over it and isolates and indexes a single section.
10
11 ##################################################################### */
12 /*}}}*/
13// Include Files /*{{{*/
6c139d6e 14#ifdef __GNUG__
094a497d 15#pragma implementation "apt-pkg/tagfile.h"
6c139d6e
AL
16#endif
17
094a497d
AL
18#include <apt-pkg/tagfile.h>
19#include <apt-pkg/error.h>
cdcc6d34 20#include <apt-pkg/strutl.h>
578bfd0a
AL
21
22#include <string>
23#include <stdio.h>
24 /*}}}*/
25
26// TagFile::pkgTagFile - Constructor /*{{{*/
27// ---------------------------------------------------------------------
28/* */
8e06abb2 29pkgTagFile::pkgTagFile(FileFd &Fd,unsigned long Size) : Fd(Fd), Size(Size)
578bfd0a 30{
ad00ae81
AL
31 Buffer = new char[Size];
32 Start = End = Buffer;
578bfd0a 33 Left = Fd.Size();
dcb79bae 34 iOffset = 0;
578bfd0a
AL
35 Fill();
36}
37 /*}}}*/
38// TagFile::Step - Advance to the next section /*{{{*/
39// ---------------------------------------------------------------------
40/* If the Section Scanner fails we refill the buffer and try again. */
41bool pkgTagFile::Step(pkgTagSection &Tag)
42{
43 if (Tag.Scan(Start,End - Start) == false)
44 {
45 if (Fill() == false)
46 return false;
47
48 if (Tag.Scan(Start,End - Start) == false)
c7b5ce1c 49 return _error->Error("Unable to parse package file %s",Fd.Name().c_str());
578bfd0a 50 }
dcb79bae
AL
51 Start += Tag.size();
52 iOffset += Tag.size();
53
578bfd0a
AL
54 return true;
55}
56 /*}}}*/
57// TagFile::Fill - Top up the buffer /*{{{*/
58// ---------------------------------------------------------------------
59/* This takes the bit at the end of the buffer and puts it at the start
60 then fills the rest from the file */
61bool pkgTagFile::Fill()
62{
ad00ae81 63 unsigned long EndSize = End - Start;
578bfd0a 64
c7b5ce1c
AL
65 memmove(Buffer,Start,EndSize);
66 Start = Buffer;
67 End = Buffer + EndSize;
68
578bfd0a
AL
69 if (Left == 0)
70 {
c7b5ce1c 71 if (EndSize <= 3)
578bfd0a 72 return false;
c7b5ce1c
AL
73 if (Size - (End - Buffer) < 4)
74 return true;
75
76 // Append a double new line if one does not exist
77 unsigned int LineCount = 0;
78 for (const char *E = End - 1; E - End < 6 && (*E == '\n' || *E == '\r'); E--)
79 if (*E == '\n')
80 LineCount++;
81 for (; LineCount < 2; LineCount++)
82 *End++ = '\n';
83
578bfd0a
AL
84 return true;
85 }
86
c88edf1d
AL
87 // See if only a bit of the file is left
88 if (Left < Size - (End - Buffer))
578bfd0a 89 {
ad00ae81 90 if (Fd.Read(End,Left) == false)
578bfd0a 91 return false;
c88edf1d 92
ad00ae81 93 End += Left;
578bfd0a
AL
94 Left = 0;
95 }
96 else
97 {
ad00ae81 98 if (Fd.Read(End,Size - (End - Buffer)) == false)
578bfd0a 99 return false;
c88edf1d 100
ad00ae81
AL
101 Left -= Size - (End - Buffer);
102 End = Buffer + Size;
578bfd0a
AL
103 }
104 return true;
105}
106 /*}}}*/
ad00ae81
AL
107// TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
108// ---------------------------------------------------------------------
03e39e59
AL
109/* This jumps to a pre-recorded file location and reads the record
110 that is there */
ad00ae81
AL
111bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
112{
113 iOffset = Offset;
114 Left = Fd.Size() - Offset;
115 if (Fd.Seek(Offset) == false)
116 return false;
117 End = Start = Buffer;
118
119 if (Fill() == false)
120 return false;
121
122 if (Tag.Scan(Start,End - Start) == false)
123 return _error->Error("Unable to parse package file");
124 return true;
125}
126 /*}}}*/
578bfd0a
AL
127// TagSection::Scan - Scan for the end of the header information /*{{{*/
128// ---------------------------------------------------------------------
129/* This looks for the first double new line in the data stream. It also
c1a22377
AL
130 indexes the tags in the section. This very simple hash function for the
131 first 3 letters gives very good performance on the debian package files */
578bfd0a
AL
132bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
133{
134 const char *End = Start + MaxLength;
135 Stop = Section = Start;
c1a22377 136 memset(AlphaIndexes,0,sizeof(AlphaIndexes));
c7b5ce1c
AL
137
138 if (Stop == 0)
139 return false;
578bfd0a
AL
140
141 TagCount = 0;
f3bcc383 142 while (TagCount < sizeof(Indexes)/sizeof(Indexes[0]) && Stop < End)
578bfd0a 143 {
90d64280 144 // Start a new index and add it to the hash
c1a22377
AL
145 if (isspace(Stop[0]) == 0)
146 {
147 Indexes[TagCount++] = Stop - Section;
148 unsigned char A = tolower(Stop[0]) - 'a';
149 unsigned char B = tolower(Stop[1]) - 'a';
150 unsigned char C = tolower(Stop[3]) - 'a';
151 AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)] = TagCount;
152 }
0a8e3465 153
c1a22377 154 Stop = (const char *)memchr(Stop,'\n',End - Stop);
0a8e3465 155
c1a22377
AL
156 if (Stop == 0)
157 return false;
90d64280 158 for (; Stop[1] == '\r' && Stop+1 < End; Stop++);
c1a22377 159
f3bcc383
AL
160 // Double newline marks the end of the record
161 if (Stop+1 < End && Stop[1] == '\n')
578bfd0a 162 {
578bfd0a 163 Indexes[TagCount] = Stop - Section;
0a8e3465 164 for (; (Stop[0] == '\n' || Stop[0] == '\r') && Stop < End; Stop++);
578bfd0a 165 return true;
578bfd0a
AL
166 }
167
c1a22377
AL
168 Stop++;
169 }
170
578bfd0a
AL
171 return false;
172}
173 /*}}}*/
174// TagSection::Find - Locate a tag /*{{{*/
175// ---------------------------------------------------------------------
176/* This searches the section for a tag that matches the given string. */
177bool pkgTagSection::Find(const char *Tag,const char *&Start,
178 const char *&End)
179{
180 unsigned int Length = strlen(Tag);
c1a22377
AL
181 unsigned char A = tolower(Tag[0]) - 'a';
182 unsigned char B = tolower(Tag[1]) - 'a';
183 unsigned char C = tolower(Tag[3]) - 'a';
184 unsigned int I = AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)];
185 if (I == 0)
186 return false;
187 I--;
188
189 for (unsigned int Counter = 0; Counter != TagCount; Counter++,
190 I = (I+1)%TagCount)
578bfd0a 191 {
c1a22377
AL
192 const char *St;
193 St = Section + Indexes[I];
194 if (strncasecmp(Tag,St,Length) != 0)
578bfd0a
AL
195 continue;
196
197 // Make sure the colon is in the right place
c1a22377 198 const char *C = St + Length;
578bfd0a
AL
199 for (; isspace(*C) != 0; C++);
200 if (*C != ':')
201 continue;
202
203 // Strip off the gunk from the start end
204 Start = C;
205 End = Section + Indexes[I+1];
206 for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
207 for (; isspace(End[-1]) != 0 && End > Start; End--);
c1a22377 208
578bfd0a
AL
209 return true;
210 }
c1a22377 211
578bfd0a
AL
212 Start = End = 0;
213 return false;
214}
215 /*}}}*/
0e66b144 216// TagSection::FindS - Find a string /*{{{*/
a05599f1
AL
217// ---------------------------------------------------------------------
218/* */
219string pkgTagSection::FindS(const char *Tag)
220{
221 const char *Start;
222 const char *End;
223 if (Find(Tag,Start,End) == false)
224 return string();
225 return string(Start,End);
226}
227 /*}}}*/
228// TagSection::FindI - Find an integer /*{{{*/
229// ---------------------------------------------------------------------
230/* */
b0b4efb9 231signed int pkgTagSection::FindI(const char *Tag,signed long Default)
a05599f1
AL
232{
233 const char *Start;
b0b4efb9
AL
234 const char *Stop;
235 if (Find(Tag,Start,Stop) == false)
236 return Default;
237
238 // Copy it into a temp buffer so we can use strtol
239 char S[300];
240 if ((unsigned)(Stop - Start) >= sizeof(S))
241 return Default;
242 strncpy(S,Start,Stop-Start);
243 S[Stop - Start] = 0;
244
245 char *End;
246 signed long Result = strtol(S,&End,10);
247 if (S == End)
248 return Default;
249 return Result;
250}
251 /*}}}*/
252// TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
253// ---------------------------------------------------------------------
254/* The bits marked in Flag are masked on/off in Flags */
255bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
256 unsigned long Flag)
257{
258 const char *Start;
259 const char *Stop;
260 if (Find(Tag,Start,Stop) == false)
261 return true;
a05599f1 262
b0b4efb9
AL
263 switch (StringToBool(string(Start,Stop)))
264 {
265 case 0:
266 Flags &= ~Flag;
267 return true;
268
269 case 1:
270 Flags |= Flag;
271 return true;
272
273 default:
274 _error->Warning("Unknown flag value");
275 return true;
276 }
277 return true;
a05599f1
AL
278}
279 /*}}}*/
b0b4efb9
AL
280
281