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