Ensure we have a Policy in CacheFile.BuildDepCache()
[ntk/apt.git] / ftparchive / override.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: override.cc,v 1.4 2003/02/10 07:34:41 doogie Exp $
4 /* ######################################################################
5
6 Override
7
8 Store the override file.
9
10 ##################################################################### */
11 /*}}}*/
12 // Include Files /*{{{*/
13 #include <config.h>
14
15 #include <apt-pkg/strutl.h>
16 #include <apt-pkg/error.h>
17
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <string.h>
21 #include <utility>
22
23 #include "override.h"
24
25 #include <apti18n.h>
26 /*}}}*/
27
28 // Override::ReadOverride - Read the override file /*{{{*/
29 // ---------------------------------------------------------------------
30 /* This parses the override file and reads it into the map */
31 bool Override::ReadOverride(string const &File,bool const &Source)
32 {
33 if (File.empty() == true)
34 return true;
35
36 FILE *F = fopen(File.c_str(),"r");
37 if (F == 0)
38 return _error->Errno("fopen",_("Unable to open %s"),File.c_str());
39
40 char Line[1000];
41 unsigned long long Counter = 0;
42 while (fgets(Line,sizeof(Line),F) != 0)
43 {
44 Counter++;
45 Item Itm;
46
47 // Silence
48 for (char *I = Line; *I != 0; I++)
49 if (*I == '#')
50 *I = 0;
51
52 // Strip space leading up to the package name, skip blank lines
53 char *Pkg = Line;
54 for (; isspace(*Pkg) && *Pkg != 0;Pkg++);
55 if (*Pkg == 0)
56 continue;
57
58 #define APT_FIND_NEXT_FIELD \
59 for (End++; isspace(*End) != 0 && *End != 0; ++End) \
60 /* skip spaces */ ; \
61 Start = End; \
62 for (; isspace(*End) == 0 && *End != 0; ++End) \
63 /* find end of word */ ;
64
65 #define APT_WARNING_MALFORMED_LINE(FIELD) \
66 if (*End == 0) \
67 { \
68 _error->Warning(_("Malformed override %s line %llu (%s)"),File.c_str(), \
69 Counter, FIELD ); \
70 continue; \
71 } \
72 *End = 0;
73
74 // Find the package and zero..
75 char *Start;
76 char *End = Pkg;
77 for (; isspace(*End) == 0 && *End != 0; End++);
78 APT_WARNING_MALFORMED_LINE("pkgname");
79
80 APT_FIND_NEXT_FIELD;
81
82 // Find the priority
83 if (Source == false)
84 {
85 APT_WARNING_MALFORMED_LINE("priority");
86 Itm.Priority = Start;
87
88 APT_FIND_NEXT_FIELD;
89 }
90
91 // Find the Section
92 APT_WARNING_MALFORMED_LINE("section");
93 Itm.FieldOverride["Section"] = Start;
94
95 // Source override files only have the two columns
96 if (Source == true)
97 {
98 Mapping[Pkg] = Itm;
99 continue;
100 }
101
102 // Find the =>
103 for (End++; isspace(*End) != 0 && *End != 0; End++);
104 if (*End != 0)
105 {
106 Start = End;
107 for (; *End != 0 && (End[0] != '=' || End[1] != '>'); End++);
108 if (*End == 0 || strlen(End) < 4)
109 {
110 Itm.OldMaint = "*";
111 Itm.NewMaint = _strstrip(Start);
112 }
113 else
114 {
115 *End = 0;
116 Itm.OldMaint = _strstrip(Start);
117
118 End += 3;
119 Itm.NewMaint = _strstrip(End);
120 }
121 }
122
123 Mapping[Pkg] = Itm;
124 }
125
126 if (ferror(F))
127 _error->Errno("fgets",_("Failed to read the override file %s"),File.c_str());
128 fclose(F);
129 return true;
130 }
131 /*}}}*/
132 // Override::ReadExtraOverride - Read the extra override file /*{{{*/
133 // ---------------------------------------------------------------------
134 /* This parses the extra override file and reads it into the map */
135 bool Override::ReadExtraOverride(string const &File,bool const &/*Source*/)
136 {
137 if (File.empty() == true)
138 return true;
139
140 FILE *F = fopen(File.c_str(),"r");
141 if (F == 0)
142 return _error->Errno("fopen",_("Unable to open %s"),File.c_str());
143
144 char Line[1000];
145 unsigned long long Counter = 0;
146 while (fgets(Line,sizeof(Line),F) != 0)
147 {
148 Counter++;
149
150 // Silence
151 for (char *I = Line; *I != 0; I++)
152 if (*I == '#')
153 *I = 0;
154
155 // Strip space leading up to the package name, skip blank lines
156 char *Pkg = Line;
157 for (; isspace(*Pkg) && *Pkg != 0;Pkg++);
158 if (Pkg == 0)
159 continue;
160
161 // Find the package and zero..
162 char *End = Pkg;
163 for (; isspace(*End) == 0 && *End != 0; End++);
164 if (*End == 0)
165 {
166 _error->Warning(_("Malformed override %s line %llu #1"),File.c_str(),
167 Counter);
168 continue;
169 }
170 *End = 0;
171
172 // Find the field
173 for (End++; isspace(*End) != 0 && *End != 0; End++);
174 char *Field = End;
175 for (; isspace(*End) == 0 && *End != 0; End++);
176 if (*End == 0)
177 {
178 _error->Warning(_("Malformed override %s line %llu #2"),File.c_str(),
179 Counter);
180 continue;
181 }
182 *End = 0;
183
184 // Find the field value
185 for (End++; isspace(*End) != 0 && *End != 0; End++);
186 char *Value = End;
187 for (; *End != 0; End++);
188 for (; isspace(*(End-1)) && End > Value; End--);
189 if (End == Value)
190 {
191 _error->Warning(_("Malformed override %s line %llu #3"),File.c_str(),
192 Counter);
193 continue;
194 }
195 *End = 0;
196
197 Mapping[Pkg].FieldOverride[Field] = Value;
198 }
199
200 if (ferror(F))
201 _error->Errno("fgets",_("Failed to read the override file %s"),File.c_str());
202 fclose(F);
203 return true;
204 }
205 /*}}}*/
206
207 // Override::GetItem - Get a architecture specific item /*{{{*/
208 // ---------------------------------------------------------------------
209 /* Returns a override item for the given package and the given architecture.
210 * Treats "all" special
211 */
212 Override::Item* Override::GetItem(string const &Package, string const &Architecture)
213 {
214 map<string,Item>::const_iterator I = Mapping.find(Package);
215 map<string,Item>::iterator J = Mapping.find(Package + "/" + Architecture);
216
217 if (I == Mapping.end() && J == Mapping.end())
218 {
219 return 0;
220 }
221
222 Item *result = new Item;
223 if (I == Mapping.end()) *result = J->second;
224 else
225 {
226 *result = I->second;
227 if (J != Mapping.end())
228 {
229 Item *R = &J->second;
230 if (R->Priority != "") result->Priority = R->Priority;
231 if (R->OldMaint != "") result->OldMaint = R->OldMaint;
232 if (R->NewMaint != "") result->NewMaint = R->NewMaint;
233 for (map<string,string>::const_iterator foI = R->FieldOverride.begin();
234 foI != R->FieldOverride.end(); ++foI)
235 {
236 result->FieldOverride[foI->first] = foI->second;
237 }
238 }
239 }
240 return result;
241 }
242
243
244 // Override::Item::SwapMaint - Swap the maintainer field if necessary /*{{{*/
245 // ---------------------------------------------------------------------
246 /* Returns the new maintainer string after evaluating the rewriting rule. If
247 there is a rule but it does not match then the empty string is returned,
248 also if there was no rewrite rule the empty string is returned. Failed
249 indicates if there was some kind of problem while rewriting. */
250 string Override::Item::SwapMaint(string const &Orig,bool &Failed)
251 {
252 Failed = false;
253
254 // Degenerate case..
255 if (NewMaint.empty() == true)
256 return OldMaint;
257
258 if (OldMaint == "*")
259 return NewMaint;
260
261 /* James: ancient, eliminate it, however it is still being used in the main
262 override file. Thus it persists.*/
263 #if 1
264 // Break OldMaint up into little bits on double slash boundaries.
265 string::const_iterator End = OldMaint.begin();
266 while (1)
267 {
268 string::const_iterator Start = End;
269 for (; End < OldMaint.end() &&
270 (End + 3 >= OldMaint.end() || End[0] != ' ' ||
271 End[1] != '/' || End[2] != '/'); ++End);
272 if (stringcasecmp(Start,End,Orig.begin(),Orig.end()) == 0)
273 return NewMaint;
274
275 if (End >= OldMaint.end())
276 break;
277
278 // Skip the divider and white space
279 for (; End < OldMaint.end() && (*End == '/' || *End == ' '); ++End);
280 }
281 #else
282 if (stringcasecmp(OldMaint.begin(),OldMaint.end(),Orig.begin(),Orig.end()) == 0)
283 return NewMaint;
284 #endif
285
286 Failed = true;
287 return string();
288 }
289 /*}}}*/