Replace bunch of rpm version checks with feature checks to get this to
[apt.git] / apt-pkg / rpm / rpmrecords.cc
1 // -*- mode: c++; mode: fold -*-
2 // Description                                                          /*{{{*/
3 /* ######################################################################
4    
5    RPM Package Records - Parser for RPM package records
6      
7    ##################################################################### 
8  */
9                                                                         /*}}}*/
10 // Include Files                                                        /*{{{*/
11 #ifdef __GNUG__
12 #pragma implementation "apt-pkg/rpmrecords.h"
13 #endif
14
15 #include <config.h>
16
17 #ifdef HAVE_RPM
18
19 #include <assert.h>
20
21 #include <apt-pkg/rpmrecords.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/rpmhandler.h>
24 #include <apt-pkg/rpmsystem.h>
25
26 #include <apti18n.h>
27
28 using namespace std;
29
30 // RecordParser::rpmRecordParser - Constructor                          /*{{{*/
31 // ---------------------------------------------------------------------
32 /* */
33 rpmRecordParser::rpmRecordParser(string File, pkgCache &Cache)
34    : Handler(0), Buffer(0), BufSize(0), BufUsed(0)
35 {
36    if (File == RPMDBHandler::DataPath(false)) {
37       IsDatabase = true;
38       Handler = rpmSys.GetDBHandler();
39    } else {
40       IsDatabase = false;
41       struct stat Buf;
42       if (stat(File.c_str(),&Buf) == 0 && S_ISDIR(Buf.st_mode))
43          Handler = new RPMDirHandler(File);
44       else if (flExtension(File) == "rpm")
45          Handler = new RPMSingleFileHandler(File);
46 #ifdef APT_WITH_REPOMD
47 #ifdef WITH_SQLITE3
48       else if (flExtension(File) == "sqlite")
49          Handler = new RPMSqliteHandler(File);
50 #endif
51       else if (flExtension(File) == "xml")
52          Handler = new RPMRepomdHandler(File);
53 #endif
54       else
55          Handler = new RPMFileHandler(File);
56    }
57 }
58                                                                         /*}}}*/
59 // RecordParser::~rpmRecordParser - Destructor                          /*{{{*/
60 // ---------------------------------------------------------------------
61 /* */
62 rpmRecordParser::~rpmRecordParser()
63 {
64    // Can't use Handler->IsDatabase here, since the RPMDBHandler
65    // could already have been destroyed.
66    if (IsDatabase == false)
67       delete Handler;
68    free(Buffer);
69 }
70                                                                         /*}}}*/
71 // RecordParser::Jump - Jump to a specific record                       /*{{{*/
72 // ---------------------------------------------------------------------
73 /* */
74 bool rpmRecordParser::Jump(pkgCache::VerFileIterator const &Ver)
75 {
76    return Handler->Jump(Ver->Offset);
77 }
78                                                                         /*}}}*/
79 // RecordParser::FileName - Return the archive filename on the site     /*{{{*/
80 // ---------------------------------------------------------------------
81 /* */
82 string rpmRecordParser::FileName()
83 {
84    string Dir = Handler->Directory();
85    if (Dir.empty() == true)
86       return Handler->FileName();
87    return flCombine(Dir, Handler->FileName());
88 }
89                                                                         /*}}}*/
90 // RecordParser::Name - Return the package name                         /*{{{*/
91 // ---------------------------------------------------------------------
92 /* */
93 string rpmRecordParser::Name()
94 {
95    return Handler->Name();
96 }
97                                                                         /*}}}*/
98 // RecordParser::MD5Hash - Return the archive hash                      /*{{{*/
99 // ---------------------------------------------------------------------
100 /* */
101 string rpmRecordParser::MD5Hash()
102 {
103    return Handler->MD5Sum();
104 }
105                                                                         /*}}}*/
106 string rpmRecordParser::SHA1Hash()
107 {
108    return Handler->SHA1Sum();
109 }
110
111 // RecordParser::Maintainer - Return the maintainer email               /*{{{*/
112 // ---------------------------------------------------------------------
113 /* */
114 string rpmRecordParser::Maintainer()
115 {
116    return Handler->Packager();
117 }
118                                                                         /*}}}*/
119 // RecordParser::ShortDesc - Return a 1 line description                /*{{{*/
120 // ---------------------------------------------------------------------
121 /* */
122 string rpmRecordParser::ShortDesc()
123 {
124    return Handler->Summary();
125 }
126                                                                         /*}}}*/
127 // RecordParser::LongDesc - Return a longer description                 /*{{{*/
128 // ---------------------------------------------------------------------
129 /* */
130 string rpmRecordParser::LongDesc()
131 {
132    return Handler->Description();
133 }
134                                                                         /*}}}*/
135 // RecordParser::SourcePkg - Return the source package name if any      /*{{{*/
136 // ---------------------------------------------------------------------
137 /* */
138 string rpmRecordParser::SourcePkg()
139 {
140    // This must be the *package* name, not the *file* name. We have no
141    // current way to extract it safely from the file name.
142
143 // A wild guess, hopefully covering most cases:
144 // Check for string "-$(version)-$(release)." in string srpm
145    string srpm = Handler->SourceRpm();
146    string versarch = "-" + Handler->Version() + "-" + Handler->Release() + ".";
147    string::size_type idx1 = srpm.find(versarch);
148
149 // not found
150    if ( idx1 == string::npos )
151      return "";
152
153 // check if the first dot in "srpm" is the dot at the end of versarch
154    string::size_type idx2 = srpm.find('.');
155
156    if ( idx2 < idx1 )
157 // no, the packager is playing dirty tricks with srpm names
158      return "";
159
160    return srpm.substr(0,idx1);
161 }
162                                                                         /*}}}*/
163
164 void rpmRecordParser::BufCat(const char *text)
165 {
166    if (text != NULL)
167       BufCat(text, text+strlen(text));
168 }
169
170 void rpmRecordParser::BufCat(const char *begin, const char *end)
171 {
172    unsigned len = end - begin;
173     
174    if (BufUsed+len+1 >= BufSize)
175    {
176       BufSize += 512;
177       char *tmp = (char*)realloc(Buffer, BufSize);
178       if (tmp == NULL)
179       {
180          _error->Errno("realloc", _("Could not allocate buffer for record text"));
181          return;
182       }
183       Buffer = tmp;
184    }
185
186    strncpy(Buffer+BufUsed, begin, len);
187    BufUsed += len;
188 }
189
190 void rpmRecordParser::BufCatTag(const char *tag, const char *value)
191 {
192    BufCat(tag);
193    BufCat(value);
194 }
195
196 void rpmRecordParser::BufCatDep(Dependency *Dep)
197 {
198    string buf;
199
200    BufCat(Dep->Name.c_str());
201    if (Dep->Version.empty() == false) 
202    {
203       BufCat(" ");
204       switch (Dep->Op) {
205          case pkgCache::Dep::Less:
206             buf += "<";
207             break;
208          case pkgCache::Dep::LessEq:
209             buf += "<=";
210             break;
211          case pkgCache::Dep::Equals: 
212             buf += "=";
213             break;
214          case pkgCache::Dep::Greater:
215             buf += ">";
216             break;
217          case pkgCache::Dep::GreaterEq:
218             buf += ">=";
219             break;
220       }
221
222       BufCat(buf.c_str());
223       BufCat(" ");
224       BufCat(Dep->Version.c_str());
225    }
226 }
227
228 void rpmRecordParser::BufCatDescr(const char *descr)
229 {
230    const char *begin = descr;
231
232    while (*descr) 
233    {
234       if (*descr=='\n') 
235       {
236          BufCat(" ");
237          BufCat(begin, descr+1);
238          begin = descr+1;
239       }
240       descr++;
241    }
242    BufCat(" ");
243    BufCat(begin, descr);
244    BufCat("\n");
245 }
246
247
248 // RecordParser::GetRec - The record in raw text, in std Debian format  /*{{{*/
249 // ---------------------------------------------------------------------
250 void rpmRecordParser::GetRec(const char *&Start,const char *&Stop) 
251 {
252    // FIXME: This method is leaking memory from headerGetEntry().
253    char buf[32];
254
255    BufUsed = 0;
256
257    BufCatTag("Package: ", Handler->Name().c_str());
258
259    BufCatTag("\nSection: ", Handler->Group().c_str());
260
261    snprintf(buf, sizeof(buf), "%lu", Handler->InstalledSize());
262    BufCatTag("\nInstalled Size: ", buf);
263
264    BufCatTag("\nPackager: ", Handler->Packager().c_str());
265    //BufCatTag("\nVendor: ", Handler->Vendor().c_str());
266    
267    BufCat("\nVersion: ");
268    
269    BufCat(Handler->EVR().c_str());
270
271
272    vector<Dependency*> Deps, Provides, Obsoletes, Conflicts;
273    vector<Dependency*>::iterator I;
274    bool start = true;
275
276    Handler->PRCO(pkgCache::Dep::Depends, Deps);
277    for (I = Deps.begin(); I != Deps.end(); I++) {
278       if ((*I)->Type != pkgCache::Dep::PreDepends)
279          continue;
280       if (start) {
281          BufCat("\nPre-Depends: ");
282          start = false;
283       } else {
284          BufCat(", ");
285       }
286       BufCatDep(*I);
287    }
288
289    start = true;
290    for (I = Deps.begin(); I != Deps.end(); I++) {
291       if ((*I)->Type != pkgCache::Dep::Depends)
292          continue;
293       if (start) {
294          BufCat("\nDepends: ");
295          start = false;
296       } else {
297          BufCat(", ");
298       }
299       BufCatDep(*I);
300    }
301       
302    Handler->PRCO(pkgCache::Dep::Conflicts, Conflicts);
303    start = true;
304    for (I = Conflicts.begin(); I != Conflicts.end(); I++) {
305       if (start) {
306          BufCat("\nConflicts: ");
307          start = false;
308       } else {
309          BufCat(", ");
310       }
311       BufCatDep(*I);
312    }
313
314    Handler->PRCO(pkgCache::Dep::Provides, Provides);
315    start = true;
316    for (I = Provides.begin(); I != Provides.end(); I++) {
317       if (start) {
318          BufCat("\nProvides: ");
319          start = false;
320       } else {
321          BufCat(", ");
322       }
323       BufCatDep(*I);
324    }
325
326    Handler->PRCO(pkgCache::Dep::Obsoletes, Obsoletes);
327    start = true;
328    for (I = Obsoletes.begin(); I != Obsoletes.end(); I++) {
329       if (start) {
330          BufCat("\nObsoletes: ");
331          start = false;
332       } else {
333          BufCat(", ");
334       }
335       BufCatDep(*I);
336    }
337
338    BufCatTag("\nArchitecture: ", Handler->Arch().c_str());
339    
340    snprintf(buf, sizeof(buf), "%lu", Handler->FileSize());
341    BufCatTag("\nSize: ", buf);
342
343    BufCatTag("\nMD5Sum: ", Handler->MD5Sum().c_str());
344
345    BufCatTag("\nFilename: ", Handler->FileName().c_str());
346
347    BufCatTag("\nSummary: ", Handler->Summary().c_str());
348    BufCat("\nDescription: ");
349    BufCat("\n");
350    BufCatDescr(Handler->Description().c_str());
351    BufCat("\n");
352    
353    Start = Buffer;
354    Stop = Buffer + BufUsed;
355 }
356                                                                         /*}}}*/
357 bool rpmRecordParser::FileList(vector<string> &Files)
358 {
359    return Handler->FileList(Files);
360 }
361
362 bool rpmRecordParser::ChangeLog(vector<ChangeLogEntry *> &ChangeLogs)
363 {
364    return Handler->ChangeLog(ChangeLogs);
365 }
366
367 bool rpmRecordParser::HasFile(const char *File)
368 {
369    return Handler->HasFile(File);
370 }
371
372 #endif /* HAVE_RPM */
373
374 // vim:sts=3:sw=3