]> git.saurik.com Git - apt.git/blame - apt-pkg/tagfile.cc
Moved strutl.h
[apt.git] / apt-pkg / tagfile.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
cdcc6d34 3// $Id: tagfile.cc,v 1.20 1999/01/27 02:48:52 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;
c1a22377 142 while (TagCount < sizeof(Indexes)/sizeof(Indexes[0]))
578bfd0a 143 {
c1a22377
AL
144 if (isspace(Stop[0]) == 0)
145 {
146 Indexes[TagCount++] = Stop - Section;
147 unsigned char A = tolower(Stop[0]) - 'a';
148 unsigned char B = tolower(Stop[1]) - 'a';
149 unsigned char C = tolower(Stop[3]) - 'a';
150 AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)] = TagCount;
151 }
0a8e3465 152
c1a22377 153 Stop = (const char *)memchr(Stop,'\n',End - Stop);
0a8e3465 154
c1a22377
AL
155 if (Stop == 0)
156 return false;
157 for (; Stop[1] == '\r' && Stop < End; Stop++);
158
159 if (Stop[1] == '\n')
578bfd0a 160 {
578bfd0a 161 Indexes[TagCount] = Stop - Section;
0a8e3465 162 for (; (Stop[0] == '\n' || Stop[0] == '\r') && Stop < End; Stop++);
578bfd0a 163 return true;
578bfd0a
AL
164 }
165
c1a22377
AL
166 Stop++;
167 }
168
578bfd0a
AL
169 return false;
170}
171 /*}}}*/
172// TagSection::Find - Locate a tag /*{{{*/
173// ---------------------------------------------------------------------
174/* This searches the section for a tag that matches the given string. */
175bool pkgTagSection::Find(const char *Tag,const char *&Start,
176 const char *&End)
177{
178 unsigned int Length = strlen(Tag);
c1a22377
AL
179 unsigned char A = tolower(Tag[0]) - 'a';
180 unsigned char B = tolower(Tag[1]) - 'a';
181 unsigned char C = tolower(Tag[3]) - 'a';
182 unsigned int I = AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)];
183 if (I == 0)
184 return false;
185 I--;
186
187 for (unsigned int Counter = 0; Counter != TagCount; Counter++,
188 I = (I+1)%TagCount)
578bfd0a 189 {
c1a22377
AL
190 const char *St;
191 St = Section + Indexes[I];
192 if (strncasecmp(Tag,St,Length) != 0)
578bfd0a
AL
193 continue;
194
195 // Make sure the colon is in the right place
c1a22377 196 const char *C = St + Length;
578bfd0a
AL
197 for (; isspace(*C) != 0; C++);
198 if (*C != ':')
199 continue;
200
201 // Strip off the gunk from the start end
202 Start = C;
203 End = Section + Indexes[I+1];
204 for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
205 for (; isspace(End[-1]) != 0 && End > Start; End--);
c1a22377 206
578bfd0a
AL
207 return true;
208 }
c1a22377 209
578bfd0a
AL
210 Start = End = 0;
211 return false;
212}
213 /*}}}*/
0e66b144 214// TagSection::FindS - Find a string /*{{{*/
a05599f1
AL
215// ---------------------------------------------------------------------
216/* */
217string pkgTagSection::FindS(const char *Tag)
218{
219 const char *Start;
220 const char *End;
221 if (Find(Tag,Start,End) == false)
222 return string();
223 return string(Start,End);
224}
225 /*}}}*/
226// TagSection::FindI - Find an integer /*{{{*/
227// ---------------------------------------------------------------------
228/* */
b0b4efb9 229signed int pkgTagSection::FindI(const char *Tag,signed long Default)
a05599f1
AL
230{
231 const char *Start;
b0b4efb9
AL
232 const char *Stop;
233 if (Find(Tag,Start,Stop) == false)
234 return Default;
235
236 // Copy it into a temp buffer so we can use strtol
237 char S[300];
238 if ((unsigned)(Stop - Start) >= sizeof(S))
239 return Default;
240 strncpy(S,Start,Stop-Start);
241 S[Stop - Start] = 0;
242
243 char *End;
244 signed long Result = strtol(S,&End,10);
245 if (S == End)
246 return Default;
247 return Result;
248}
249 /*}}}*/
250// TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
251// ---------------------------------------------------------------------
252/* The bits marked in Flag are masked on/off in Flags */
253bool pkgTagSection::FindFlag(const char *Tag,unsigned long &Flags,
254 unsigned long Flag)
255{
256 const char *Start;
257 const char *Stop;
258 if (Find(Tag,Start,Stop) == false)
259 return true;
a05599f1 260
b0b4efb9
AL
261 switch (StringToBool(string(Start,Stop)))
262 {
263 case 0:
264 Flags &= ~Flag;
265 return true;
266
267 case 1:
268 Flags |= Flag;
269 return true;
270
271 default:
272 _error->Warning("Unknown flag value");
273 return true;
274 }
275 return true;
a05599f1
AL
276}
277 /*}}}*/
b0b4efb9
AL
278
279