- re-enable hashmap usage (Ralf)
[apt.git] / apt-pkg / rpm / rpmpackagedata.cc
1
2 #include <config.h>
3
4 #ifdef HAVE_RPM
5
6 #include <apt-pkg/error.h>
7 #include <apt-pkg/rpmpackagedata.h>
8 #include <apt-pkg/fileutl.h>
9 #include <apt-pkg/strutl.h>
10 #include <apt-pkg/configuration.h>
11 #include <apt-pkg/version.h>
12
13 #include <apti18n.h>
14
15 #include <rpm/rpmlib.h>
16
17 RPMPackageData::RPMPackageData()
18    :
19 #ifdef WITH_GNU_HASH_MAP
20   VerMap(517),
21 #endif
22   MinArchScore(-1)   
23 #ifdef WITH_GNU_HASH_MAP
24    , ArchScores(31)
25 #endif
26 {
27    BaseArch = _config->Find("APT::Architecture");
28    if (BaseArch == "x86_64" || BaseArch == "ia64" ||
29        BaseArch == "ppc64" || BaseArch == "sparc64")
30       MultilibSys = true;
31    else
32       MultilibSys = false;
33
34    if (MultilibSys) {
35       CompatArch["x86_64"].push_back("i386");
36       CompatArch["x86_64"].push_back("i486");
37       CompatArch["x86_64"].push_back("i586");
38       CompatArch["x86_64"].push_back("i686");
39       CompatArch["x86_64"].push_back("athlon");
40       CompatArch["ia64"] = CompatArch["x86_64"];
41       CompatArch["ppc64"].push_back("ppc");
42       CompatArch["sparc64"].push_back("sparc");
43    }
44
45    // Populate priorities
46    string FileName = _config->FindFile("Dir::Etc::rpmpriorities");
47    FileFd F(FileName, FileFd::ReadOnly);
48    if (_error->PendingError()) 
49    {
50       _error->Error(_("could not open package priority file %s"),
51                     FileName.c_str());
52       return;
53    }
54    pkgTagFile Tags(&F);
55    pkgTagSection Section;
56
57    if (!Tags.Step(Section)) 
58    {
59       _error->Error(_("no data in %s"), FileName.c_str());
60        return;
61    }
62    
63    for (int i = 0; i != 6; i++) 
64    {
65       const char *priorities[] = 
66       {
67          "Essential", "Important", "Required", "Standard", "Optional", "Extra"
68       };
69       pkgCache::State::VerPriority states[] = {
70              pkgCache::State::Important,
71              pkgCache::State::Important,
72              pkgCache::State::Required,
73              pkgCache::State::Standard,
74              pkgCache::State::Optional,
75              pkgCache::State::Extra
76       };
77       pkgCache::Flag::PkgFlags flags[] = {
78              pkgCache::Flag::Essential,
79              pkgCache::Flag::Important,
80              pkgCache::Flag::Important,
81              (pkgCache::Flag::PkgFlags)0,
82              (pkgCache::Flag::PkgFlags)0,
83              (pkgCache::Flag::PkgFlags)0
84       };
85
86       string Packages = Section.FindS(priorities[i]);
87       if (Packages.empty()) 
88          continue;
89
90       const char *C = Packages.c_str();
91       while (*C != 0)
92       {
93          string pkg;
94          if (ParseQuoteWord(C,pkg))
95          {
96             Priorities[pkg] = states[i];
97             Flags[pkg] = flags[i];
98          }
99       }
100    }
101
102    // Populate holding packages
103    const Configuration::Item *Top = _config->Tree("RPM::Hold");
104    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
105    {
106       regex_t *ptrn = new regex_t;
107       if (regcomp(ptrn,Top->Value.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
108       {
109          _error->Warning(_("Bad regular expression '%s' in option RPM::Hold."),
110                          Top->Value.c_str());
111          delete ptrn;
112       }
113       else
114           HoldPackages.push_back(ptrn);
115    }
116
117    // Populate ignored packages
118    Top = _config->Tree("RPM::Ignore");
119    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
120       IgnorePackages[Top->Value] = 1;
121 #if RPM_VERSION >= 0x040100
122    IgnorePackages["gpg-pubkey"] = 1;
123 #endif
124
125    // Populate Allow-Duplicated packages.
126    Top = _config->Tree("RPM::Allow-Duplicated");
127    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
128    {
129       regex_t *ptrn = new regex_t;
130       if (regcomp(ptrn,Top->Value.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
131       {
132          _error->Warning(_("Bad regular expression '%s' in option RPM::Allow-Duplicated."),
133                          Top->Value.c_str());
134          delete ptrn;
135       }
136       else
137           DuplicatedPatterns.push_back(ptrn);
138    }
139
140    // Populate fake provides
141    Top = _config->Tree("RPM::Fake-Provides");
142    for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
143    {
144       string Name = "";
145       string Version = "";
146       const char *C = Top->Value.c_str();
147       if (ParseQuoteWord(C,Name) == false)
148       {
149          _error->Warning(_("Bad entry '%s' in option RPM::FakeProvides."),
150                          Top->Value.c_str());
151          continue;
152       }
153       ParseQuoteWord(C,Version);
154
155       if (Version.empty() == true)
156       {
157          delete FakeProvides[Name];
158          FakeProvides[Name] = NULL;
159       }
160       else
161       {
162          if (FakeProvides.find(Name) != FakeProvides.end())
163          {
164             // If it's NULL, it was provided with an empty version
165             if (FakeProvides[Name] != NULL)
166                FakeProvides[Name]->push_back(Version);
167          }
168          else
169          {
170             vector<string> *VerList = new vector<string>;
171             VerList->push_back(Version);
172             FakeProvides[Name] = VerList;
173          }
174       }
175    }
176
177
178    // Populate translations
179    Configuration Cnf;
180    string CnfFile = _config->FindDir("Dir::Etc::translateparts");
181    if (FileExists(CnfFile) == true)
182       if (ReadConfigDir(Cnf,CnfFile,true) == false)
183          return;
184    CnfFile = _config->FindFile("Dir::Etc::translatelist");
185    if (FileExists(CnfFile) == true)
186       if (ReadConfigFile(Cnf,CnfFile,true) == false)
187          return;
188
189    const char *TString[] = {"translate-binary",
190                             "translate-source",
191                             "translate-index"};
192    vector<Translate*> *TList[] = {&BinaryTranslations,
193                                   &SourceTranslations,
194                                   &IndexTranslations};
195    for (int i = 0; i != 3; i++)
196    {
197       Top = Cnf.Tree(TString[i]);
198       for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
199       {
200          Translate *t = new Translate();
201          if (regcomp(&t->Pattern,Top->Tag.c_str(),REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0)
202          {
203             _error->Warning(_("Bad regular expression '%s' in URI translation"),
204                             Top->Tag.c_str());
205             delete t;
206          }
207          else
208          {
209             Configuration Block(Top);
210             t->Template = Block.Find("Template");
211             TList[i]->push_back(t);
212          }
213       }
214    }
215 }
216
217 bool RPMPackageData::HoldPackage(const char *name)
218 {
219    for (vector<regex_t*>::iterator I = HoldPackages.begin();
220         I != HoldPackages.end(); I++)
221       if (regexec(*I,name,0,0,0) == 0)
222          return true;
223    return false;
224 }
225
226 bool RPMPackageData::IgnoreDep(pkgVersioningSystem &VS,
227                                pkgCache::DepIterator &Dep)
228 {
229    const char *name = Dep.TargetPkg().Name();
230    if (FakeProvides.find(name) != FakeProvides.end()) {
231       vector<string> *VerList = FakeProvides[name];
232       if (VerList == NULL)
233          return true;
234       for (vector<string>::iterator I = VerList->begin();
235            I != VerList->end(); I++)
236       {
237          if (VS.CheckDep(I->c_str(),Dep->CompareOp,Dep.TargetVer()) == true)
238             return true;
239       }
240    }
241    return false;
242 }
243
244 static void ParseTemplate(string &Template, map<string,string> &Dict)
245 {
246    string::size_type start(string::npos);
247    string::size_type end(string::npos);
248    string::size_type last_start;
249    while (true)
250    {
251       last_start = start;
252       start = Template.rfind("%(", end);
253       if (start == string::npos)
254          break;
255       end = Template.find(")", start);
256       if (end < last_start)
257       {
258          string Key(Template,start+2,end-(start+2));
259          map<string,string>::const_iterator I = Dict.find(Key);
260          if (I != Dict.end())
261             Template.replace(start, end-start+1, I->second);
262       }
263       if (start == 0)
264          break;
265       end = start-1;
266    }
267 }
268
269 void RPMPackageData::GenericTranslate(vector<Translate*> &TList,
270                                       string &FullURI,
271                                       map<string,string> &Dict)
272 {
273    const char *fulluri = FullURI.c_str();
274    for (vector<Translate*>::iterator I = TList.begin(); I != TList.end(); I++)
275    {
276       if (regexec(&(*I)->Pattern,fulluri,0,0,0) == 0)
277       {
278          FullURI = (*I)->Template;
279          ParseTemplate(FullURI, Dict);
280          break;
281       }
282    }
283 }
284
285 void RPMPackageData::InitMinArchScore()
286 {
287    if (MinArchScore != -1)
288       return;
289    string Arch = _config->Find("RPM::Architecture", "");
290    if (Arch.empty() == false)
291       MinArchScore = rpmMachineScore(RPM_MACHTABLE_INSTARCH, Arch.c_str());
292    else
293       MinArchScore = 0;
294 }
295
296 int RPMPackageData::RpmArchScore(const char *Arch)
297 {
298    int Score = rpmMachineScore(RPM_MACHTABLE_INSTARCH, Arch);
299    if (Score >= MinArchScore)
300       return Score;
301    return 0;
302 }
303
304 bool RPMPackageData::IsCompatArch(string Arch)
305 {
306    for (vector<string>::iterator I = CompatArch[BaseArch].begin();
307         I != CompatArch[BaseArch].end(); I++) {
308       if (Arch == *I)
309          return true;
310    }
311    return false;
312 }
313
314
315 bool RPMPackageData::IsDupPackage(const string &Name)
316 {
317    if (DuplicatedPackages.find(Name) != DuplicatedPackages.end())
318       return true;
319    const char *name = Name.c_str();
320    for (vector<regex_t*>::iterator I = DuplicatedPatterns.begin();
321         I != DuplicatedPatterns.end(); I++) {
322       if (regexec(*I,name,0,0,0) == 0) {
323          SetDupPackage(Name);
324          return true;
325       }
326    }
327    return false;
328 }
329
330 RPMPackageData *RPMPackageData::Singleton()
331 {
332    static RPMPackageData *data = NULL;
333    if (!data)
334       data = new RPMPackageData();
335    return data;
336 }
337
338 #endif /* HAVE_RPM */
339 // vim:sw=3:sts=3