]>
git.saurik.com Git - apt.git/blob - apt-pkg/tagfile.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: tagfile.cc,v 1.25 1999/07/03 06:45:40 jgg Exp $
4 /* ######################################################################
6 Fast scanner for RFC-822 type header information
8 This uses a rotating buffer to load the package information into.
9 The scanner runs over it and isolates and indexes a single section.
11 ##################################################################### */
13 // Include Files /*{{{*/
15 #pragma implementation "apt-pkg/tagfile.h"
18 #include <apt-pkg/tagfile.h>
19 #include <apt-pkg/error.h>
20 #include <apt-pkg/strutl.h>
26 // TagFile::pkgTagFile - Constructor /*{{{*/
27 // ---------------------------------------------------------------------
29 pkgTagFile::pkgTagFile(FileFd
&Fd
,unsigned long Size
) : Fd(Fd
), Size(Size
)
31 Buffer
= new char[Size
];
38 // pkgTagFile::~pkgTagFile - Destructor /*{{{*/
39 // ---------------------------------------------------------------------
41 pkgTagFile::~pkgTagFile()
46 // TagFile::Step - Advance to the next section /*{{{*/
47 // ---------------------------------------------------------------------
48 /* If the Section Scanner fails we refill the buffer and try again. */
49 bool pkgTagFile::Step(pkgTagSection
&Tag
)
51 if (Tag
.Scan(Start
,End
- Start
) == false)
56 if (Tag
.Scan(Start
,End
- Start
) == false)
57 return _error
->Error("Unable to parse package file %s (1)",Fd
.Name().c_str());
60 iOffset
+= Tag
.size();
65 // TagFile::Fill - Top up the buffer /*{{{*/
66 // ---------------------------------------------------------------------
67 /* This takes the bit at the end of the buffer and puts it at the start
68 then fills the rest from the file */
69 bool pkgTagFile::Fill()
71 unsigned long EndSize
= End
- Start
;
73 memmove(Buffer
,Start
,EndSize
);
75 End
= Buffer
+ EndSize
;
81 if (Size
- (End
- Buffer
) < 4)
84 // Append a double new line if one does not exist
85 unsigned int LineCount
= 0;
86 for (const char *E
= End
- 1; E
- End
< 6 && (*E
== '\n' || *E
== '\r'); E
--)
89 for (; LineCount
< 2; LineCount
++)
95 // See if only a bit of the file is left
96 if (Left
< Size
- (End
- Buffer
))
98 if (Fd
.Read(End
,Left
) == false)
106 if (Fd
.Read(End
,Size
- (End
- Buffer
)) == false)
109 Left
-= Size
- (End
- Buffer
);
115 // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
116 // ---------------------------------------------------------------------
117 /* This jumps to a pre-recorded file location and reads the record
119 bool pkgTagFile::Jump(pkgTagSection
&Tag
,unsigned long Offset
)
122 Left
= Fd
.Size() - Offset
;
123 if (Fd
.Seek(Offset
) == false)
125 End
= Start
= Buffer
;
130 if (Tag
.Scan(Start
,End
- Start
) == true)
133 // This appends a double new line (for the real eof handling)
137 if (Tag
.Scan(Start
,End
- Start
) == false)
139 cout
<< string(Start
,End
) << endl
;
140 return _error
->Error("Unable to parse package file %s (2)",Fd
.Name().c_str());
146 // TagSection::Scan - Scan for the end of the header information /*{{{*/
147 // ---------------------------------------------------------------------
148 /* This looks for the first double new line in the data stream. It also
149 indexes the tags in the section. This very simple hash function for the
150 first 3 letters gives very good performance on the debian package files */
151 bool pkgTagSection::Scan(const char *Start
,unsigned long MaxLength
)
153 const char *End
= Start
+ MaxLength
;
154 Stop
= Section
= Start
;
155 memset(AlphaIndexes
,0,sizeof(AlphaIndexes
));
161 while (TagCount
< sizeof(Indexes
)/sizeof(Indexes
[0]) && Stop
< End
)
163 // Start a new index and add it to the hash
164 if (isspace(Stop
[0]) == 0)
166 Indexes
[TagCount
++] = Stop
- Section
;
167 unsigned char A
= tolower(Stop
[0]) - 'a';
168 unsigned char B
= tolower(Stop
[1]) - 'a';
169 unsigned char C
= tolower(Stop
[3]) - 'a';
170 AlphaIndexes
[((A
+ C
/3)%26
) + 26*((B
+ C
/2)%26
)] = TagCount
;
173 Stop
= (const char *)memchr(Stop
,'\n',End
- Stop
);
178 for (; Stop
[1] == '\r' && Stop
+1 < End
; Stop
++);
180 // Double newline marks the end of the record
181 if (Stop
+1 < End
&& Stop
[1] == '\n')
183 Indexes
[TagCount
] = Stop
- Section
;
184 for (; (Stop
[0] == '\n' || Stop
[0] == '\r') && Stop
< End
; Stop
++);
194 // TagSection::Find - Locate a tag /*{{{*/
195 // ---------------------------------------------------------------------
196 /* This searches the section for a tag that matches the given string. */
197 bool pkgTagSection::Find(const char *Tag
,const char *&Start
,
200 unsigned int Length
= strlen(Tag
);
201 unsigned char A
= tolower(Tag
[0]) - 'a';
202 unsigned char B
= tolower(Tag
[1]) - 'a';
203 unsigned char C
= tolower(Tag
[3]) - 'a';
204 unsigned int I
= AlphaIndexes
[((A
+ C
/3)%26
) + 26*((B
+ C
/2)%26
)];
209 for (unsigned int Counter
= 0; Counter
!= TagCount
; Counter
++,
213 St
= Section
+ Indexes
[I
];
214 if (strncasecmp(Tag
,St
,Length
) != 0)
217 // Make sure the colon is in the right place
218 const char *C
= St
+ Length
;
219 for (; isspace(*C
) != 0; C
++);
223 // Strip off the gunk from the start end
225 End
= Section
+ Indexes
[I
+1];
227 return _error
->Error("Internal parsing error");
229 for (; (isspace(*Start
) != 0 || *Start
== ':') && Start
< End
; Start
++);
230 for (; isspace(End
[-1]) != 0 && End
> Start
; End
--);
239 // TagSection::FindS - Find a string /*{{{*/
240 // ---------------------------------------------------------------------
242 string
pkgTagSection::FindS(const char *Tag
)
246 if (Find(Tag
,Start
,End
) == false)
248 return string(Start
,End
);
251 // TagSection::FindI - Find an integer /*{{{*/
252 // ---------------------------------------------------------------------
254 signed int pkgTagSection::FindI(const char *Tag
,signed long Default
)
258 if (Find(Tag
,Start
,Stop
) == false)
261 // Copy it into a temp buffer so we can use strtol
263 if ((unsigned)(Stop
- Start
) >= sizeof(S
))
265 strncpy(S
,Start
,Stop
-Start
);
269 signed long Result
= strtol(S
,&End
,10);
275 // TagSection::FindFlag - Locate a yes/no type flag /*{{{*/
276 // ---------------------------------------------------------------------
277 /* The bits marked in Flag are masked on/off in Flags */
278 bool pkgTagSection::FindFlag(const char *Tag
,unsigned long &Flags
,
283 if (Find(Tag
,Start
,Stop
) == false)
286 switch (StringToBool(string(Start
,Stop
)))
297 _error
->Warning("Unknown flag value");