Don't die if lines in sources.list are too long. Closes...
[ntk/apt.git] / apt-pkg / sourcelist.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: sourcelist.cc,v 1.24 2002/07/08 04:18:07 jgg Exp $
4 /* ######################################################################
5
6 List of Sources
7
8 ##################################################################### */
9 /*}}}*/
10 // Include Files /*{{{*/
11 #ifdef __GNUG__
12 #pragma implementation "apt-pkg/sourcelist.h"
13 #endif
14
15 #include <apt-pkg/sourcelist.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/fileutl.h>
18 #include <apt-pkg/configuration.h>
19 #include <apt-pkg/strutl.h>
20
21 #include <apti18n.h>
22
23 #include <fstream>
24 /*}}}*/
25
26 using namespace std;
27
28 // Global list of Items supported
29 static pkgSourceList::Type *ItmList[10];
30 pkgSourceList::Type **pkgSourceList::Type::GlobalList = ItmList;
31 unsigned long pkgSourceList::Type::GlobalListLen = 0;
32
33 // Type::Type - Constructor /*{{{*/
34 // ---------------------------------------------------------------------
35 /* Link this to the global list of items*/
36 pkgSourceList::Type::Type()
37 {
38 ItmList[GlobalListLen] = this;
39 GlobalListLen++;
40 }
41 /*}}}*/
42 // Type::GetType - Get a specific meta for a given type /*{{{*/
43 // ---------------------------------------------------------------------
44 /* */
45 pkgSourceList::Type *pkgSourceList::Type::GetType(const char *Type)
46 {
47 for (unsigned I = 0; I != GlobalListLen; I++)
48 if (strcmp(GlobalList[I]->Name,Type) == 0)
49 return GlobalList[I];
50 return 0;
51 }
52 /*}}}*/
53 // Type::FixupURI - Normalize the URI and check it.. /*{{{*/
54 // ---------------------------------------------------------------------
55 /* */
56 bool pkgSourceList::Type::FixupURI(string &URI) const
57 {
58 if (URI.empty() == true)
59 return false;
60
61 if (URI.find(':') == string::npos)
62 return false;
63
64 URI = SubstVar(URI,"$(ARCH)",_config->Find("APT::Architecture"));
65
66 // Make sure that the URI is / postfixed
67 if (URI[URI.size() - 1] != '/')
68 URI += '/';
69
70 return true;
71 }
72 /*}}}*/
73 // Type::ParseLine - Parse a single line /*{{{*/
74 // ---------------------------------------------------------------------
75 /* This is a generic one that is the 'usual' format for sources.list
76 Weird types may override this. */
77 bool pkgSourceList::Type::ParseLine(vector<pkgIndexFile *> &List,
78 Vendor const *Vendor,
79 const char *Buffer,
80 unsigned long CurLine,
81 string File) const
82 {
83 string URI;
84 string Dist;
85 string Section;
86
87 if (ParseQuoteWord(Buffer,URI) == false)
88 return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str());
89 if (ParseQuoteWord(Buffer,Dist) == false)
90 return _error->Error(_("Malformed line %lu in source list %s (dist)"),CurLine,File.c_str());
91
92 if (FixupURI(URI) == false)
93 return _error->Error(_("Malformed line %lu in source list %s (URI parse)"),CurLine,File.c_str());
94
95 // Check for an absolute dists specification.
96 if (Dist.empty() == false && Dist[Dist.size() - 1] == '/')
97 {
98 if (ParseQuoteWord(Buffer,Section) == true)
99 return _error->Error(_("Malformed line %lu in source list %s (Absolute dist)"),CurLine,File.c_str());
100 Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture"));
101 return CreateItem(List,URI,Dist,Section,Vendor);
102 }
103
104 // Grab the rest of the dists
105 if (ParseQuoteWord(Buffer,Section) == false)
106 return _error->Error(_("Malformed line %lu in source list %s (dist parse)"),CurLine,File.c_str());
107
108 do
109 {
110 if (CreateItem(List,URI,Dist,Section,Vendor) == false)
111 return false;
112 }
113 while (ParseQuoteWord(Buffer,Section) == true);
114
115 return true;
116 }
117 /*}}}*/
118
119 // SourceList::pkgSourceList - Constructors /*{{{*/
120 // ---------------------------------------------------------------------
121 /* */
122 pkgSourceList::pkgSourceList()
123 {
124 }
125
126 pkgSourceList::pkgSourceList(string File)
127 {
128 Read(File);
129 }
130 /*}}}*/
131 // SourceList::~pkgSourceList - Destructor /*{{{*/
132 // ---------------------------------------------------------------------
133 /* */
134 pkgSourceList::~pkgSourceList()
135 {
136 for (const_iterator I = SrcList.begin(); I != SrcList.end(); I++)
137 delete *I;
138 for (vector<Vendor const *>::const_iterator I = VendorList.begin();
139 I != VendorList.end(); I++)
140 delete *I;
141 }
142 /*}}}*/
143 // SourceList::ReadVendors - Read list of known package vendors /*{{{*/
144 // ---------------------------------------------------------------------
145 /* This also scans a directory of vendor files similar to apt.conf.d
146 which can contain the usual suspects of distribution provided data.
147 The APT config mechanism allows the user to override these in their
148 configuration file. */
149 bool pkgSourceList::ReadVendors()
150 {
151 Configuration Cnf;
152
153 string CnfFile = _config->FindDir("Dir::Etc::vendorparts");
154 if (FileExists(CnfFile) == true)
155 if (ReadConfigDir(Cnf,CnfFile,true) == false)
156 return false;
157 CnfFile = _config->FindFile("Dir::Etc::vendorlist");
158 if (FileExists(CnfFile) == true)
159 if (ReadConfigFile(Cnf,CnfFile,true) == false)
160 return false;
161
162 for (vector<Vendor const *>::const_iterator I = VendorList.begin();
163 I != VendorList.end(); I++)
164 delete *I;
165 VendorList.erase(VendorList.begin(),VendorList.end());
166
167 // Process 'simple-key' type sections
168 const Configuration::Item *Top = Cnf.Tree("simple-key");
169 for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
170 {
171 Configuration Block(Top);
172 Vendor *Vendor;
173
174 Vendor = new pkgSourceList::Vendor;
175
176 Vendor->VendorID = Top->Tag;
177 Vendor->FingerPrint = Block.Find("Fingerprint");
178 Vendor->Description = Block.Find("Name");
179
180 if (Vendor->FingerPrint.empty() == true ||
181 Vendor->Description.empty() == true)
182 {
183 _error->Error(_("Vendor block %s is invalid"), Vendor->VendorID.c_str());
184 delete Vendor;
185 continue;
186 }
187
188 VendorList.push_back(Vendor);
189 }
190
191 /* XXX Process 'group-key' type sections
192 This is currently faked out so that the vendors file format is
193 parsed but nothing is done with it except check for validity */
194 Top = Cnf.Tree("group-key");
195 for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
196 {
197 Configuration Block(Top);
198 Vendor *Vendor;
199
200 Vendor = new pkgSourceList::Vendor;
201
202 Vendor->VendorID = Top->Tag;
203 Vendor->Description = Block.Find("Name");
204
205 if (Vendor->Description.empty() == true)
206 {
207 _error->Error(_("Vendor block %s is invalid"),
208 Vendor->VendorID.c_str());
209 delete Vendor;
210 continue;
211 }
212
213 VendorList.push_back(Vendor);
214 }
215
216 return !_error->PendingError();
217 }
218 /*}}}*/
219 // SourceList::ReadMainList - Read the main source list from etc /*{{{*/
220 // ---------------------------------------------------------------------
221 /* */
222 bool pkgSourceList::ReadMainList()
223 {
224 return ReadVendors() && Read(_config->FindFile("Dir::Etc::sourcelist"));
225 }
226 /*}}}*/
227 // SourceList::Read - Parse the sourcelist file /*{{{*/
228 // ---------------------------------------------------------------------
229 /* */
230 bool pkgSourceList::Read(string File)
231 {
232 // Open the stream for reading
233 ifstream F(File.c_str(),ios::in /*| ios::nocreate*/);
234 if (!F != 0)
235 return _error->Errno("ifstream::ifstream",_("Opening %s"),File.c_str());
236
237 for (const_iterator I = SrcList.begin(); I != SrcList.end(); I++)
238 delete *I;
239 SrcList.erase(SrcList.begin(),SrcList.end());
240 char Buffer[300];
241
242 int CurLine = 0;
243 while (F.eof() == false)
244 {
245 F.getline(Buffer,sizeof(Buffer));
246 CurLine++;
247 _strtabexpand(Buffer,sizeof(Buffer));
248 if (F.fail() && !F.eof())
249 return _error->Error(_("Line %u too long in source list %s."),
250 CurLine,File.c_str());
251
252
253 char *I;
254 for (I = Buffer; *I != 0 && *I != '#'; I++);
255 *I = 0;
256
257 const char *C = _strstrip(Buffer);
258
259 // Comment or blank
260 if (C[0] == '#' || C[0] == 0)
261 continue;
262
263 // Grok it
264 string LineType;
265 if (ParseQuoteWord(C,LineType) == false)
266 return _error->Error(_("Malformed line %u in source list %s (type)"),CurLine,File.c_str());
267
268 Type *Parse = Type::GetType(LineType.c_str());
269 if (Parse == 0)
270 return _error->Error(_("Type '%s' is not known in on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str());
271
272 // Authenticated repository
273 Vendor const *Vndr = 0;
274 if (C[0] == '[')
275 {
276 string VendorID;
277
278 if (ParseQuoteWord(C,VendorID) == false)
279 return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
280
281 if (VendorID.length() < 2 || VendorID.end()[-1] != ']')
282 return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str());
283 VendorID = string(VendorID,1,VendorID.size()-2);
284
285 for (vector<Vendor const *>::const_iterator iter = VendorList.begin();
286 iter != VendorList.end(); iter++)
287 {
288 if ((*iter)->VendorID == VendorID)
289 {
290 Vndr = *iter;
291 break;
292 }
293 }
294
295 if (Vndr == 0)
296 return _error->Error(_("Unknown vendor ID '%s' in line %u of source list %s"),
297 VendorID.c_str(),CurLine,File.c_str());
298 }
299
300 if (Parse->ParseLine(SrcList,Vndr,C,CurLine,File) == false)
301 return false;
302 }
303 return true;
304 }
305 /*}}}*/
306 // SourceList::FindIndex - Get the index associated with a file /*{{{*/
307 // ---------------------------------------------------------------------
308 /* */
309 bool pkgSourceList::FindIndex(pkgCache::PkgFileIterator File,
310 pkgIndexFile *&Found) const
311 {
312 for (const_iterator I = SrcList.begin(); I != SrcList.end(); I++)
313 {
314 if ((*I)->FindInCache(*File.Cache()) == File)
315 {
316 Found = *I;
317 return true;
318 }
319 }
320
321 return false;
322 }
323 /*}}}*/
324 // SourceList::GetIndexes - Load the index files into the downloader /*{{{*/
325 // ---------------------------------------------------------------------
326 /* */
327 bool pkgSourceList::GetIndexes(pkgAcquire *Owner) const
328 {
329 for (const_iterator I = SrcList.begin(); I != SrcList.end(); I++)
330 if ((*I)->GetIndexes(Owner) == false)
331 return false;
332 return true;
333 }
334 /*}}}*/