Configuration fixes
[ntk/apt.git] / apt-pkg / tagfile.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
c7b5ce1c 3// $Id: tagfile.cc,v 1.18 1998/12/08 05:24:41 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>
578bfd0a
AL
20
21#include <string>
22#include <stdio.h>
23 /*}}}*/
24
25// TagFile::pkgTagFile - Constructor /*{{{*/
26// ---------------------------------------------------------------------
27/* */
8e06abb2 28pkgTagFile::pkgTagFile(FileFd &Fd,unsigned long Size) : Fd(Fd), Size(Size)
578bfd0a 29{
ad00ae81
AL
30 Buffer = new char[Size];
31 Start = End = Buffer;
578bfd0a 32 Left = Fd.Size();
dcb79bae 33 iOffset = 0;
578bfd0a
AL
34 Fill();
35}
36 /*}}}*/
37// TagFile::Step - Advance to the next section /*{{{*/
38// ---------------------------------------------------------------------
39/* If the Section Scanner fails we refill the buffer and try again. */
40bool pkgTagFile::Step(pkgTagSection &Tag)
41{
42 if (Tag.Scan(Start,End - Start) == false)
43 {
44 if (Fill() == false)
45 return false;
46
47 if (Tag.Scan(Start,End - Start) == false)
c7b5ce1c 48 return _error->Error("Unable to parse package file %s",Fd.Name().c_str());
578bfd0a 49 }
dcb79bae
AL
50 Start += Tag.size();
51 iOffset += Tag.size();
52
578bfd0a
AL
53 return true;
54}
55 /*}}}*/
56// TagFile::Fill - Top up the buffer /*{{{*/
57// ---------------------------------------------------------------------
58/* This takes the bit at the end of the buffer and puts it at the start
59 then fills the rest from the file */
60bool pkgTagFile::Fill()
61{
ad00ae81 62 unsigned long EndSize = End - Start;
578bfd0a 63
c7b5ce1c
AL
64 memmove(Buffer,Start,EndSize);
65 Start = Buffer;
66 End = Buffer + EndSize;
67
578bfd0a
AL
68 if (Left == 0)
69 {
c7b5ce1c 70 if (EndSize <= 3)
578bfd0a 71 return false;
c7b5ce1c
AL
72 if (Size - (End - Buffer) < 4)
73 return true;
74
75 // Append a double new line if one does not exist
76 unsigned int LineCount = 0;
77 for (const char *E = End - 1; E - End < 6 && (*E == '\n' || *E == '\r'); E--)
78 if (*E == '\n')
79 LineCount++;
80 for (; LineCount < 2; LineCount++)
81 *End++ = '\n';
82
578bfd0a
AL
83 return true;
84 }
85
c88edf1d
AL
86 // See if only a bit of the file is left
87 if (Left < Size - (End - Buffer))
578bfd0a 88 {
ad00ae81 89 if (Fd.Read(End,Left) == false)
578bfd0a 90 return false;
c88edf1d 91
ad00ae81 92 End += Left;
578bfd0a
AL
93 Left = 0;
94 }
95 else
96 {
ad00ae81 97 if (Fd.Read(End,Size - (End - Buffer)) == false)
578bfd0a 98 return false;
c88edf1d 99
ad00ae81
AL
100 Left -= Size - (End - Buffer);
101 End = Buffer + Size;
578bfd0a
AL
102 }
103 return true;
104}
105 /*}}}*/
ad00ae81
AL
106// TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
107// ---------------------------------------------------------------------
03e39e59
AL
108/* This jumps to a pre-recorded file location and reads the record
109 that is there */
ad00ae81
AL
110bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
111{
112 iOffset = Offset;
113 Left = Fd.Size() - Offset;
114 if (Fd.Seek(Offset) == false)
115 return false;
116 End = Start = Buffer;
117
118 if (Fill() == false)
119 return false;
120
121 if (Tag.Scan(Start,End - Start) == false)
122 return _error->Error("Unable to parse package file");
123 return true;
124}
125 /*}}}*/
578bfd0a
AL
126// TagSection::Scan - Scan for the end of the header information /*{{{*/
127// ---------------------------------------------------------------------
128/* This looks for the first double new line in the data stream. It also
c1a22377
AL
129 indexes the tags in the section. This very simple hash function for the
130 first 3 letters gives very good performance on the debian package files */
578bfd0a
AL
131bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
132{
133 const char *End = Start + MaxLength;
134 Stop = Section = Start;
c1a22377 135 memset(AlphaIndexes,0,sizeof(AlphaIndexes));
c7b5ce1c
AL
136
137 if (Stop == 0)
138 return false;
578bfd0a
AL
139
140 TagCount = 0;
c1a22377 141 while (TagCount < sizeof(Indexes)/sizeof(Indexes[0]))
578bfd0a 142 {
c1a22377
AL
143 if (isspace(Stop[0]) == 0)
144 {
145 Indexes[TagCount++] = Stop - Section;
146 unsigned char A = tolower(Stop[0]) - 'a';
147 unsigned char B = tolower(Stop[1]) - 'a';
148 unsigned char C = tolower(Stop[3]) - 'a';
149 AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)] = TagCount;
150 }
0a8e3465 151
c1a22377 152 Stop = (const char *)memchr(Stop,'\n',End - Stop);
0a8e3465 153
c1a22377
AL
154 if (Stop == 0)
155 return false;
156 for (; Stop[1] == '\r' && Stop < End; Stop++);
157
158 if (Stop[1] == '\n')
578bfd0a 159 {
578bfd0a 160 Indexes[TagCount] = Stop - Section;
0a8e3465 161 for (; (Stop[0] == '\n' || Stop[0] == '\r') && Stop < End; Stop++);
578bfd0a 162 return true;
578bfd0a
AL
163 }
164
c1a22377
AL
165 Stop++;
166 }
167
578bfd0a
AL
168 return false;
169}
170 /*}}}*/
171// TagSection::Find - Locate a tag /*{{{*/
172// ---------------------------------------------------------------------
173/* This searches the section for a tag that matches the given string. */
174bool pkgTagSection::Find(const char *Tag,const char *&Start,
175 const char *&End)
176{
177 unsigned int Length = strlen(Tag);
c1a22377
AL
178 unsigned char A = tolower(Tag[0]) - 'a';
179 unsigned char B = tolower(Tag[1]) - 'a';
180 unsigned char C = tolower(Tag[3]) - 'a';
181 unsigned int I = AlphaIndexes[((A + C/3)%26) + 26*((B + C/2)%26)];
182 if (I == 0)
183 return false;
184 I--;
185
186 for (unsigned int Counter = 0; Counter != TagCount; Counter++,
187 I = (I+1)%TagCount)
578bfd0a 188 {
c1a22377
AL
189 const char *St;
190 St = Section + Indexes[I];
191 if (strncasecmp(Tag,St,Length) != 0)
578bfd0a
AL
192 continue;
193
194 // Make sure the colon is in the right place
c1a22377 195 const char *C = St + Length;
578bfd0a
AL
196 for (; isspace(*C) != 0; C++);
197 if (*C != ':')
198 continue;
199
200 // Strip off the gunk from the start end
201 Start = C;
202 End = Section + Indexes[I+1];
203 for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
204 for (; isspace(End[-1]) != 0 && End > Start; End--);
c1a22377 205
578bfd0a
AL
206 return true;
207 }
c1a22377 208
578bfd0a
AL
209 Start = End = 0;
210 return false;
211}
212 /*}}}*/
0e66b144 213// TagSection::FindS - Find a string /*{{{*/
a05599f1
AL
214// ---------------------------------------------------------------------
215/* */
216string pkgTagSection::FindS(const char *Tag)
217{
218 const char *Start;
219 const char *End;
220 if (Find(Tag,Start,End) == false)
221 return string();
222 return string(Start,End);
223}
224 /*}}}*/
225// TagSection::FindI - Find an integer /*{{{*/
226// ---------------------------------------------------------------------
227/* */
228unsigned int pkgTagSection::FindI(const char *Tag)
229{
230 const char *Start;
231 const char *End;
232 if (Find(Tag,Start,End) == false)
233 return 0;
234
235 return atoi(string(Start,End).c_str());
236}
237 /*}}}*/
0e66b144 238