First draft of make system and name change to apt-pkg
[ntk/apt.git] / apt-pkg / tagfile.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: tagfile.cc,v 1.7 1998/07/12 23:58:39 jgg Exp $
4 /* ######################################################################
5
6 Fast scanner for RFC-822 type header information
7
8 This uses a rotating 64K 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 #include <apt-pkg/init.h>
21
22 #include <string>
23 #include <stdio.h>
24 /*}}}*/
25
26 // TagFile::pkgTagFile - Constructor /*{{{*/
27 // ---------------------------------------------------------------------
28 /* */
29 pkgTagFile::pkgTagFile(File &Fd) : Fd(Fd)
30 {
31 Buffer = new char[64*1024];
32 Start = End = Buffer + 64*1024;
33 Left = Fd.Size();
34 iOffset = 0;
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. */
41 bool 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)
49 return _error->Error("Unable to parse package file");
50 }
51 Start += Tag.size();
52 iOffset += Tag.size();
53
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 */
61 bool pkgTagFile::Fill()
62 {
63 unsigned long Size = End - Start;
64
65 if (Left == 0)
66 {
67 if (Size <= 1)
68 return false;
69 return true;
70 }
71
72 memmove(Buffer,Start,Size);
73 Start = Buffer;
74
75 // See if only a bit of the file is left or if
76 if (Left < End - Buffer - Size)
77 {
78 if (Fd.Read(Buffer + Size,Left) == false)
79 return false;
80 End = Buffer + Size + Left;
81 Left = 0;
82 }
83 else
84 {
85 if (Fd.Read(Buffer + Size, End - Buffer - Size) == false)
86 return false;
87 Left -= End - Buffer - Size;
88 }
89 return true;
90 }
91 /*}}}*/
92 // TagSection::Scan - Scan for the end of the header information /*{{{*/
93 // ---------------------------------------------------------------------
94 /* This looks for the first double new line in the data stream. It also
95 indexes the tags in the section. */
96 bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength)
97 {
98 const char *End = Start + MaxLength;
99 Stop = Section = Start;
100
101 TagCount = 0;
102 Indexes[TagCount++] = Stop - Section;
103 Stop++;
104 for (; Stop < End; Stop++)
105 {
106 if (Stop[-1] != '\n')
107 continue;
108 if (Stop[0] == '\n')
109 {
110 // Extra one at the end to simplify find
111 Indexes[TagCount] = Stop - Section;
112 for (; Stop[0] == '\n' && Stop < End; Stop++);
113 return true;
114 break;
115 }
116
117 if (isspace(Stop[0]) == 0)
118 Indexes[TagCount++] = Stop - Section;
119
120 // Just in case.
121 if (TagCount > sizeof(Indexes)/sizeof(Indexes[0]))
122 TagCount = sizeof(Indexes)/sizeof(Indexes[0]);
123 }
124 return false;
125 }
126 /*}}}*/
127 // TagSection::Find - Locate a tag /*{{{*/
128 // ---------------------------------------------------------------------
129 /* This searches the section for a tag that matches the given string. */
130 bool pkgTagSection::Find(const char *Tag,const char *&Start,
131 const char *&End)
132 {
133 unsigned int Length = strlen(Tag);
134 for (unsigned int I = 0; I != TagCount; I++)
135 {
136 if (strncasecmp(Tag,Section + Indexes[I],Length) != 0)
137 continue;
138
139 // Make sure the colon is in the right place
140 const char *C = Section + Length + Indexes[I];
141 for (; isspace(*C) != 0; C++);
142 if (*C != ':')
143 continue;
144
145 // Strip off the gunk from the start end
146 Start = C;
147 End = Section + Indexes[I+1];
148 for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++);
149 for (; isspace(End[-1]) != 0 && End > Start; End--);
150 return true;
151 }
152 Start = End = 0;
153 return false;
154 }
155 /*}}}*/