Fixed for new egcs
[ntk/apt.git] / apt-pkg / tagfile.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: tagfile.cc,v 1.11 1998/10/02 04:39:48 jgg Exp $
4 /* ######################################################################
5
6 Fast scanner for RFC-822 type header information
7
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.
10
11 ##################################################################### */
12 /*}}}*/
13 // Include Files /*{{{*/
14 #ifdef __GNUG__
15 #pragma implementation "apt-pkg/tagfile.h"
16 #endif
17
18 #include <apt-pkg/tagfile.h>
19 #include <apt-pkg/error.h>
20
21 #include <string>
22 #include <stdio.h>
23 /*}}}*/
24
25 // TagFile::pkgTagFile - Constructor /*{{{*/
26 // ---------------------------------------------------------------------
27 /* */
28 pkgTagFile::pkgTagFile(FileFd &Fd,unsigned long Size) : Fd(Fd), Size(Size)
29 {
30 Buffer = new char[Size];
31 Start = End = Buffer;
32 Left = Fd.Size();
33 iOffset = 0;
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. */
40 bool 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)
48 {
49 cout << string(Start,End-Start) << endl;
50 return _error->Error("Unable to parse package file");
51 }
52 }
53 Start += Tag.size();
54 iOffset += Tag.size();
55
56 return true;
57 }
58 /*}}}*/
59 // TagFile::Fill - Top up the buffer /*{{{*/
60 // ---------------------------------------------------------------------
61 /* This takes the bit at the end of the buffer and puts it at the start
62 then fills the rest from the file */
63 bool pkgTagFile::Fill()
64 {
65 unsigned long EndSize = End - Start;
66
67 if (Left == 0)
68 {
69 if (EndSize <= 1)
70 return false;
71 return true;
72 }
73
74 memmove(Buffer,Start,EndSize);
75 Start = Buffer;
76 End = Buffer + EndSize;
77
78 // See if only a bit of the file is left
79 if (Left < Size)
80 {
81 if (Fd.Read(End,Left) == false)
82 return false;
83 End += Left;
84 Left = 0;
85 }
86 else
87 {
88 if (Fd.Read(End,Size - (End - Buffer)) == false)
89 return false;
90 Left -= Size - (End - Buffer);
91 End = Buffer + Size;
92 }
93 return true;
94 }
95 /*}}}*/
96 // TagFile::Jump - Jump to a pre-recorded location in the file /*{{{*/
97 // ---------------------------------------------------------------------
98 /* This jumps to a pre-recorded file location and */
99 bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset)
100 {
101 iOffset = Offset;
102 Left = Fd.Size() - Offset;
103 if (Fd.Seek(Offset) == false)
104 return false;
105 End = Start = Buffer;
106
107 if (Fill() == false)
108 return false;
109
110 if (Tag.Scan(Start,End - Start) == false)
111 return _error->Error("Unable to parse package file");
112 return true;
113 }
114 /*}}}*/
115 // TagSection::Scan - Scan for the end of the header information /*{{{*/
116 // ---------------------------------------------------------------------
117 /* This looks for the first double new line in the data stream. It also
118 indexes the tags in the section. */
119 bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
120 {
121 const char *End = Start + MaxLength;
122 Stop = Section = Start;
123
124 TagCount = 0;
125 Indexes[TagCount++] = Stop - Section;
126 Stop++;
127 for (; Stop < End; Stop++)
128 {
129 if (Stop[-1] != '\n')
130 continue;
131
132 // Skip line feeds
133 for (; Stop[0] == '\r' && Stop < End; Stop++);
134
135 if (Stop[0] == '\n')
136 {
137 // Extra one at the end to simplify find
138 Indexes[TagCount] = Stop - Section;
139 for (; (Stop[0] == '\n' || Stop[0] == '\r') && Stop < End; Stop++);
140 return true;
141 }
142
143 if (isspace(Stop[0]) == 0)
144 Indexes[TagCount++] = Stop - Section;
145
146 // Just in case.
147 if (TagCount > sizeof(Indexes)/sizeof(Indexes[0]))
148 TagCount = sizeof(Indexes)/sizeof(Indexes[0]);
149 }
150 return false;
151 }
152 /*}}}*/
153 // TagSection::Find - Locate a tag /*{{{*/
154 // ---------------------------------------------------------------------
155 /* This searches the section for a tag that matches the given string. */
156 bool pkgTagSection::Find(const char *Tag,const char *&Start,
157 const char *&End)
158 {
159 unsigned int Length = strlen(Tag);
160 for (unsigned int I = 0; I != TagCount; I++)
161 {
162 if (strncasecmp(Tag,Section + Indexes[I],Length) != 0)
163 continue;
164
165 // Make sure the colon is in the right place
166 const char *C = Section + Length + Indexes[I];
167 for (; isspace(*C) != 0; C++);
168 if (*C != ':')
169 continue;
170
171 // Strip off the gunk from the start end
172 Start = C;
173 End = Section + Indexes[I+1];
174 for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
175 for (; isspace(End[-1]) != 0 && End > Start; End--);
176
177 return true;
178 }
179 Start = End = 0;
180 return false;
181 }
182 /*}}}*/