Add rpm_off_t type for file size types, use where spotted
[platform/upstream/rpm.git] / lib / formats.c
1 /** \ingroup header
2  * \file lib/formats.c
3  */
4
5 #include "system.h"
6
7 #include <rpm/rpmtag.h>
8 #include <rpm/rpmlib.h>         /* rpmGetFilesystem*() */
9 #include <rpm/rpmds.h>
10 #include <rpm/rpmmacro.h>       /* XXX for %_i18ndomains */
11 #include <rpm/rpmfi.h>
12
13 #include "rpmio/digest.h"
14 #include "lib/manifest.h"
15
16 #include "debug.h"
17
18
19 /**
20  * Identify type of trigger.
21  * @param type          tag type
22  * @param data          tag value
23  * @param formatPrefix  (unused)
24  * @param padding       (unused)
25  * @param element       (unused)
26  * @return              formatted string
27  */
28 static char * triggertypeFormat(rpm_tagtype_t type, rpm_constdata_t data, 
29                 char * formatPrefix, size_t padding,
30                 int element)
31 {
32     const int32_t * item = data;
33     char * val;
34
35     if (type != RPM_INT32_TYPE)
36         val = xstrdup(_("(not a number)"));
37     else if (*item & RPMSENSE_TRIGGERPREIN)
38         val = xstrdup("prein");
39     else if (*item & RPMSENSE_TRIGGERIN)
40         val = xstrdup("in");
41     else if (*item & RPMSENSE_TRIGGERUN)
42         val = xstrdup("un");
43     else if (*item & RPMSENSE_TRIGGERPOSTUN)
44         val = xstrdup("postun");
45     else
46         val = xstrdup("");
47     return val;
48 }
49
50 /**
51  * Format file permissions for display.
52  * @param type          tag type
53  * @param data          tag value
54  * @param formatPrefix
55  * @param padding
56  * @param element       (unused)
57  * @return              formatted string
58  */
59 static char * permsFormat(rpm_tagtype_t type, rpm_constdata_t data,
60                 char * formatPrefix, size_t padding, int element)
61 {
62     char * val;
63     char * buf;
64
65     if (type != RPM_INT32_TYPE) {
66         val = xstrdup(_("(not a number)"));
67     } else {
68         val = xmalloc(15 + padding);
69         strcat(formatPrefix, "s");
70         buf = rpmPermsString(*((const int32_t *) data));
71         sprintf(val, formatPrefix, buf);
72         buf = _free(buf);
73     }
74
75     return val;
76 }
77
78 /**
79  * Format file flags for display.
80  * @param type          tag type
81  * @param data          tag value
82  * @param formatPrefix
83  * @param padding
84  * @param element       (unused)
85  * @return              formatted string
86  */
87 static char * fflagsFormat(rpm_tagtype_t type, rpm_constdata_t data, 
88                 char * formatPrefix, size_t padding, int element)
89 {
90     char * val;
91     char buf[15];
92     int anint = *((const int32_t *) data);
93
94     if (type != RPM_INT32_TYPE) {
95         val = xstrdup(_("(not a number)"));
96     } else {
97         buf[0] = '\0';
98         if (anint & RPMFILE_DOC)
99             strcat(buf, "d");
100         if (anint & RPMFILE_CONFIG)
101             strcat(buf, "c");
102         if (anint & RPMFILE_SPECFILE)
103             strcat(buf, "s");
104         if (anint & RPMFILE_MISSINGOK)
105             strcat(buf, "m");
106         if (anint & RPMFILE_NOREPLACE)
107             strcat(buf, "n");
108         if (anint & RPMFILE_GHOST)
109             strcat(buf, "g");
110         if (anint & RPMFILE_LICENSE)
111             strcat(buf, "l");
112         if (anint & RPMFILE_README)
113             strcat(buf, "r");
114
115         val = xmalloc(5 + padding);
116         strcat(formatPrefix, "s");
117         sprintf(val, formatPrefix, buf);
118     }
119
120     return val;
121 }
122
123 /**
124  * Wrap a pubkey in ascii armor for display.
125  * @todo Permit selectable display formats (i.e. binary).
126  * @param type          tag type
127  * @param data          tag value
128  * @param formatPrefix  (unused)
129  * @param padding       (unused)
130  * @param element       no. bytes of binary data
131  * @return              formatted string
132  */
133 static char * armorFormat(rpm_tagtype_t type, rpm_constdata_t data, 
134                 char * formatPrefix, size_t padding,
135                 int element)
136 {
137     const char * enc;
138     const unsigned char * s;
139     unsigned char * bs;
140     size_t ns;
141     int atype;
142
143     switch (type) {
144     case RPM_BIN_TYPE:
145         s = data;
146         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
147         ns = element;
148         atype = PGPARMOR_SIGNATURE;     /* XXX check pkt for signature */
149         break;
150     case RPM_STRING_TYPE:
151     case RPM_STRING_ARRAY_TYPE:
152         enc = data;
153         if (b64decode(enc, (void **)&bs, &ns))
154             return xstrdup(_("(not base64)"));
155         s = bs;
156         atype = PGPARMOR_PUBKEY;        /* XXX check pkt for pubkey */
157         break;
158     case RPM_NULL_TYPE:
159     case RPM_CHAR_TYPE:
160     case RPM_INT8_TYPE:
161     case RPM_INT16_TYPE:
162     case RPM_INT32_TYPE:
163     case RPM_I18NSTRING_TYPE:
164     default:
165         return xstrdup(_("(invalid type)"));
166         break;
167     }
168
169     /* XXX this doesn't use padding directly, assumes enough slop in retval. */
170     return pgpArmorWrap(atype, s, ns);
171 }
172
173 /**
174  * Encode binary data in base64 for display.
175  * @todo Permit selectable display formats (i.e. binary).
176  * @param type          tag type
177  * @param data          tag value
178  * @param formatPrefix  (unused)
179  * @param padding
180  * @param element
181  * @return              formatted string
182  */
183 static char * base64Format(rpm_tagtype_t type, rpm_constdata_t data, 
184                 char * formatPrefix, size_t padding, int element)
185 {
186     char * val;
187
188     if (type != RPM_BIN_TYPE) {
189         val = xstrdup(_("(not a blob)"));
190     } else {
191         char * enc;
192         char * t;
193         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
194         size_t ns = element;
195         size_t nt = 0;
196
197         if ((enc = b64encode(data, ns, -1)) != NULL) {
198                 nt = strlen(enc);
199         }
200
201         val = t = xmalloc(nt + padding + 1);
202
203         *t = '\0';
204         if (enc != NULL) {
205             t = stpcpy(t, enc);
206             enc = _free(enc);
207         }
208     }
209
210     return val;
211 }
212
213 /**
214  */
215 static size_t xmlstrlen(const char * s)
216 {
217     size_t len = 0;
218     int c;
219
220     while ((c = *s++) != '\0')
221     {
222         switch (c) {
223         case '<': case '>':     len += 4;       break;
224         case '&':               len += 5;       break;
225         default:                len += 1;       break;
226         }
227     }
228     return len;
229 }
230
231 /**
232  */
233 static char * xmlstrcpy(char * t, const char * s)
234 {
235     char * te = t;
236     int c;
237
238     while ((c = *s++) != '\0') {
239         switch (c) {
240         case '<':       te = stpcpy(te, "&lt;");        break;
241         case '>':       te = stpcpy(te, "&gt;");        break;
242         case '&':       te = stpcpy(te, "&amp;");       break;
243         default:        *te++ = c;                      break;
244         }
245     }
246     *te = '\0';
247     return t;
248 }
249
250 /**
251  * Wrap tag data in simple header xml markup.
252  * @param type          tag type
253  * @param data          tag value
254  * @param formatPrefix
255  * @param padding
256  * @param element       (unused)
257  * @return              formatted string
258  */
259 static char * xmlFormat(rpm_tagtype_t type, rpm_constdata_t data, 
260                 char * formatPrefix, size_t padding,
261                 int element)
262 {
263     const char * xtag = NULL;
264     size_t nb;
265     char * val, * bs = NULL;
266     const char * s = NULL;
267     char * t, * te;
268     unsigned long anint = 0;
269     int xx;
270
271     switch (type) {
272     case RPM_I18NSTRING_TYPE:
273     case RPM_STRING_TYPE:
274         s = data;
275         xtag = "string";
276         break;
277     case RPM_BIN_TYPE:
278     {   
279         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
280         size_t ns = element;
281         if ((bs = b64encode(data, ns, 0)) == NULL) {
282                 /* XXX proper error handling would be better. */
283                 bs = xcalloc(1, padding + (ns / 3) * 4 + 1);
284         }
285         s = bs;
286         xtag = "base64";
287     }   break;
288     case RPM_CHAR_TYPE:
289     case RPM_INT8_TYPE:
290         anint = *((const uint8_t *) data);
291         break;
292     case RPM_INT16_TYPE:
293         anint = *((const uint16_t *) data);
294         break;
295     case RPM_INT32_TYPE:
296         anint = *((const uint32_t *) data);
297         break;
298     case RPM_NULL_TYPE:
299     case RPM_STRING_ARRAY_TYPE:
300     default:
301         return xstrdup(_("(invalid xml type)"));
302         break;
303     }
304
305     if (s == NULL) {
306         size_t tlen = 32;
307         t = memset(alloca(tlen+1), 0, tlen+1);
308         if (anint != 0)
309             xx = snprintf(t, tlen, "%lu", anint);
310         s = t;
311         xtag = "integer";
312     }
313
314     nb = xmlstrlen(s);
315     if (nb == 0) {
316         nb += strlen(xtag) + sizeof("\t</>");
317         te = t = alloca(nb);
318         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
319     } else {
320         nb += 2 * strlen(xtag) + sizeof("\t<></>");
321         te = t = alloca(nb);
322         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
323         te = xmlstrcpy(te, s);
324         te += strlen(te);
325         te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
326     }
327
328     /* XXX s was malloc'd */
329     if (!strcmp(xtag, "base64"))
330         free(bs);
331
332     nb += padding;
333     val = xmalloc(nb+1);
334     strcat(formatPrefix, "s");
335     xx = snprintf(val, nb, formatPrefix, t);
336     val[nb] = '\0';
337
338     return val;
339 }
340
341 /**
342  * Display signature fingerprint and time.
343  * @param type          tag type
344  * @param data          tag value
345  * @param formatPrefix  (unused)
346  * @param padding
347  * @param element       (unused)
348  * @return              formatted string
349  */
350 static char * pgpsigFormat(rpm_tagtype_t type, rpm_constdata_t data, 
351                 char * formatPrefix, size_t padding,
352                 int element)
353 {
354     char * val, * t;
355
356     if (type != RPM_BIN_TYPE) {
357         val = xstrdup(_("(not a blob)"));
358     } else {
359         const uint8_t * pkt = (const uint8_t *) data;
360         size_t pktlen = 0;
361         unsigned int v = *pkt;
362         pgpTag tag = 0;
363         size_t plen;
364         size_t hlen = 0;
365
366         if (v & 0x80) {
367             if (v & 0x40) {
368                 tag = (v & 0x3f);
369                 plen = pgpLen(pkt+1, &hlen);
370             } else {
371                 tag = (v >> 2) & 0xf;
372                 plen = (1 << (v & 0x3));
373                 hlen = pgpGrab(pkt+1, plen);
374             }
375         
376             pktlen = 1 + plen + hlen;
377         }
378
379         if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
380             val = xstrdup(_("(not an OpenPGP signature)"));
381         } else {
382             pgpDig dig = pgpNewDig();
383             pgpDigParams sigp = &dig->signature;
384             size_t nb = 0;
385             const char *tempstr;
386
387             (void) pgpPrtPkts(pkt, pktlen, dig, 0);
388
389             val = NULL;
390         again:
391             nb += 100;
392             val = t = xrealloc(val, nb + 1);
393
394             switch (sigp->pubkey_algo) {
395             case PGPPUBKEYALGO_DSA:
396                 t = stpcpy(t, "DSA");
397                 break;
398             case PGPPUBKEYALGO_RSA:
399                 t = stpcpy(t, "RSA");
400                 break;
401             default:
402                 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
403                 t += strlen(t);
404                 break;
405             }
406             if (t + 5 >= val + nb)
407                 goto again;
408             *t++ = '/';
409             switch (sigp->hash_algo) {
410             case PGPHASHALGO_MD5:
411                 t = stpcpy(t, "MD5");
412                 break;
413             case PGPHASHALGO_SHA1:
414                 t = stpcpy(t, "SHA1");
415                 break;
416             default:
417                 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
418                 t += strlen(t);
419                 break;
420             }
421             if (t + strlen (", ") + 1 >= val + nb)
422                 goto again;
423
424             t = stpcpy(t, ", ");
425
426             /* this is important if sizeof(int32_t) ! sizeof(time_t) */
427             {   time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
428                 struct tm * tstruct = localtime(&dateint);
429                 if (tstruct)
430                     (void) strftime(t, (nb - (t - val)), "%c", tstruct);
431             }
432             t += strlen(t);
433             if (t + strlen (", Key ID ") + 1 >= val + nb)
434                 goto again;
435             t = stpcpy(t, ", Key ID ");
436             tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
437             if (t + strlen (tempstr) > val + nb)
438                 goto again;
439             t = stpcpy(t, tempstr);
440
441             dig = pgpFreeDig(dig);
442         }
443     }
444
445     return val;
446 }
447
448 /**
449  * Format dependency flags for display.
450  * @param type          tag type
451  * @param data          tag value
452  * @param formatPrefix
453  * @param padding
454  * @param element       (unused)
455  * @return              formatted string
456  */
457 static char * depflagsFormat(rpm_tagtype_t type, rpm_constdata_t data, 
458                 char * formatPrefix, size_t padding, int element)
459 {
460     char * val;
461     char buf[10];
462     int anint;
463
464     if (type != RPM_INT32_TYPE) {
465         val = xstrdup(_("(not a number)"));
466     } else {
467         anint = *((const int32_t *) data);
468         buf[0] = '\0';
469
470         if (anint & RPMSENSE_LESS) 
471             strcat(buf, "<");
472         if (anint & RPMSENSE_GREATER)
473             strcat(buf, ">");
474         if (anint & RPMSENSE_EQUAL)
475             strcat(buf, "=");
476
477         val = xmalloc(5 + padding);
478         strcat(formatPrefix, "s");
479         sprintf(val, formatPrefix, buf);
480     }
481
482     return val;
483 }
484
485 /**
486  * Retrieve mounted file system paths.
487  * @param h             header
488  * @retval *type        tag type
489  * @retval *data        tag value
490  * @retval *count       no. of data items
491  * @retval *freeData    data-was-malloc'ed indicator
492  * @return              0 on success
493  */
494 static int fsnamesTag( Header h, int32_t * type,
495                 rpm_data_t * data, rpm_count_t * count,
496                 int * freeData)
497 {
498     const char ** list;
499
500     if (rpmGetFilesystemList(&list, count))
501         return 1;
502
503     if (type) *type = RPM_STRING_ARRAY_TYPE;
504     if (data) *((const char ***) data) = list;
505     if (freeData) *freeData = 0;
506
507     return 0; 
508 }
509
510 /**
511  * Retrieve install prefixes.
512  * @param h             header
513  * @retval *type        tag type
514  * @retval *data        tag value
515  * @retval *count       no. of data items
516  * @retval *freeData    data-was-malloc'ed indicator
517  * @return              0 on success
518  */
519 static int instprefixTag(Header h, rpm_tagtype_t* type,
520                 rpm_data_t * data,
521                 rpm_count_t * count,
522                 int * freeData)
523 {
524     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
525     HFD_t hfd = headerFreeData;
526     rpm_tagtype_t ipt;
527     char ** array;
528
529     if (hge(h, RPMTAG_INSTALLPREFIX, type, (rpm_data_t *)data, count)) {
530         if (freeData) *freeData = 0;
531         return 0;
532     } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (rpm_data_t *) &array, count)) {
533         if (type) *type = RPM_STRING_TYPE;
534         if (data) *data = xstrdup(array[0]);
535         if (freeData) *freeData = 1;
536         array = hfd(array, ipt);
537         return 0;
538     }
539
540     return 1;
541 }
542
543 /**
544  * Retrieve mounted file system space.
545  * @param h             header
546  * @retval *type        tag type
547  * @retval *data        tag value
548  * @retval *count       no. of data items
549  * @retval *freeData    data-was-malloc'ed indicator
550  * @return              0 on success
551  */
552 static int fssizesTag(Header h, rpm_tagtype_t* type,
553                 rpm_data_t * data, rpm_count_t * count,
554                 int * freeData)
555 {
556     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
557     const char ** filenames;
558     rpm_off_t * filesizes;
559     rpm_off_t * usages;
560     rpm_count_t numFiles;
561
562     if (!hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &filesizes, &numFiles)) {
563         filesizes = NULL;
564         numFiles = 0;
565         filenames = NULL;
566     } else {
567         rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
568     }
569
570     if (rpmGetFilesystemList(NULL, count))
571         return 1;
572
573     *type = RPM_INT32_TYPE;
574     *freeData = 1;
575
576     if (filenames == NULL) {
577         usages = xcalloc((*count), sizeof(usages));
578         *data = usages;
579
580         return 0;
581     }
582
583     if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))      
584         return 1;
585
586     *data = usages;
587
588     filenames = _free(filenames);
589
590     return 0;
591 }
592
593 /**
594  * Retrieve trigger info.
595  * @param h             header
596  * @retval *type        tag type
597  * @retval *data        tag value
598  * @retval *count       no. of data items
599  * @retval *freeData    data-was-malloc'ed indicator
600  * @return              0 on success
601  */
602 static int triggercondsTag(Header h, rpm_tagtype_t* type,
603                 rpm_data_t * data, rpm_count_t * count,
604                 int * freeData)
605 {
606     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
607     HFD_t hfd = headerFreeData;
608     rpm_tagtype_t tnt, tvt, tst;
609     int32_t * indices, * flags;
610     char ** names, ** versions;
611     rpm_count_t numNames, numScripts;
612     rpm_count_t i, j;
613     char ** conds, ** s;
614     char * item, * flagsStr;
615     char * chptr;
616     int xx;
617     char buf[5];
618
619     if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (rpm_data_t *) &names, &numNames)) {
620         *freeData = 0;
621         return 0;
622     }
623
624     xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, NULL);
625     xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
626     xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (rpm_data_t *) &versions, NULL);
627     xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
628     s = hfd(s, tst);
629
630     *freeData = 1;
631     *data = conds = xmalloc(sizeof(*conds) * numScripts);
632     *count = numScripts;
633     *type = RPM_STRING_ARRAY_TYPE;
634     for (i = 0; i < numScripts; i++) {
635         chptr = xstrdup("");
636
637         for (j = 0; j < numNames; j++) {
638             if (indices[j] != i)
639                 continue;
640
641             item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
642             if (flags[j] & RPMSENSE_SENSEMASK) {
643                 buf[0] = '%', buf[1] = '\0';
644                 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, 0);
645                 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
646                 flagsStr = _free(flagsStr);
647             } else {
648                 strcpy(item, names[j]);
649             }
650
651             chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
652             if (*chptr != '\0') strcat(chptr, ", ");
653             strcat(chptr, item);
654             item = _free(item);
655         }
656
657         conds[i] = chptr;
658     }
659
660     names = hfd(names, tnt);
661     versions = hfd(versions, tvt);
662
663     return 0;
664 }
665
666 /**
667  * Retrieve trigger type info.
668  * @param h             header
669  * @retval *type        tag type
670  * @retval *data        tag value
671  * @retval *count       no. of data items
672  * @retval *freeData    data-was-malloc'ed indicator
673  * @return              0 on success
674  */
675 static int triggertypeTag(Header h, rpm_tagtype_t* type,
676                 rpm_data_t * data, rpm_count_t * count,
677                 int * freeData)
678 {
679     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
680     HFD_t hfd = headerFreeData;
681     rpm_tagtype_t tst;
682     int32_t * indices, * flags;
683     const char ** conds;
684     const char ** s;
685     int xx;
686     rpm_count_t numScripts, numNames;
687     rpm_count_t i, j;
688
689     if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, &numNames)) {
690         *freeData = 0;
691         return 1;
692     }
693
694     xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
695     xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
696     s = hfd(s, tst);
697
698     *freeData = 1;
699     *data = conds = xmalloc(sizeof(*conds) * numScripts);
700     *count = numScripts;
701     *type = RPM_STRING_ARRAY_TYPE;
702     for (i = 0; i < numScripts; i++) {
703         for (j = 0; j < numNames; j++) {
704             if (indices[j] != i)
705                 continue;
706
707             if (flags[j] & RPMSENSE_TRIGGERPREIN)
708                 conds[i] = xstrdup("prein");
709             else if (flags[j] & RPMSENSE_TRIGGERIN)
710                 conds[i] = xstrdup("in");
711             else if (flags[j] & RPMSENSE_TRIGGERUN)
712                 conds[i] = xstrdup("un");
713             else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
714                 conds[i] = xstrdup("postun");
715             else
716                 conds[i] = xstrdup("");
717             break;
718         }
719     }
720
721     return 0;
722 }
723
724 /**
725  * Retrieve file paths.
726  * @param h             header
727  * @retval *type        tag type
728  * @retval *data        tag value
729  * @retval *count       no. of data items
730  * @retval *freeData    data-was-malloc'ed indicator
731  * @return              0 on success
732  */
733 static int filenamesTag(Header h, rpm_tagtype_t* type,
734                 rpm_data_t * data, rpm_count_t * count,
735                 int * freeData)
736 {
737     *type = RPM_STRING_ARRAY_TYPE;
738     rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
739     *freeData = 1;
740     return 0; 
741 }
742
743 /**
744  * Retrieve file classes.
745  * @param h             header
746  * @retval *type        tag type
747  * @retval *data        tag value
748  * @retval *count       no. of data items
749  * @retval *freeData    data-was-malloc'ed indicator
750  * @return              0 on success
751  */
752 static int fileclassTag(Header h, rpm_tagtype_t* type,
753                 rpm_data_t * data, rpm_count_t * count,
754                 int * freeData)
755 {
756     *type = RPM_STRING_ARRAY_TYPE;
757     rpmfiBuildFClasses(h, (const char ***) data, count);
758     *freeData = 1;
759     return 0; 
760 }
761
762 /**
763  * Retrieve file provides.
764  * @param h             header
765  * @retval *type        tag type
766  * @retval *data        tag value
767  * @retval *count       no. of data items
768  * @retval *freeData    data-was-malloc'ed indicator
769  * @return              0 on success
770  */
771 static int fileprovideTag(Header h, rpm_tagtype_t* type,
772                 rpm_data_t * data, rpm_count_t * count,
773                 int * freeData)
774 {
775     *type = RPM_STRING_ARRAY_TYPE;
776     rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
777     *freeData = 1;
778     return 0; 
779 }
780
781 /**
782  * Retrieve file requires.
783  * @param h             header
784  * @retval *type        tag type
785  * @retval *data        tag value
786  * @retval *count       no. of data items
787  * @retval *freeData    data-was-malloc'ed indicator
788  * @return              0 on success
789  */
790 static int filerequireTag(Header h, rpm_tagtype_t* type,
791                 rpm_data_t * data, rpm_count_t * count,
792                 int * freeData)
793 {
794     *type = RPM_STRING_ARRAY_TYPE;
795     rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
796     *freeData = 1;
797     return 0; 
798 }
799
800 /* I18N look aside diversions */
801
802 #if defined(ENABLE_NLS)
803 extern int _nl_msg_cat_cntr;    /* XXX GNU gettext voodoo */
804 #endif
805 static const char * language = "LANGUAGE";
806
807 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
808
809 /**
810  * Retrieve i18n text.
811  * @param h             header
812  * @param tag           tag
813  * @retval *type        tag type
814  * @retval *data        tag value
815  * @retval *count       no. of data items
816  * @retval *freeData    data-was-malloc'ed indicator
817  * @return              0 on success
818  */
819 static int i18nTag(Header h, rpm_tag_t tag, rpm_tagtype_t* type,
820                 rpm_data_t * data, rpm_count_t * count,
821                 int * freeData)
822 {
823     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
824     char * dstring = rpmExpand(_macro_i18ndomains, NULL);
825     int rc;
826
827     *type = RPM_STRING_TYPE;
828     *data = NULL;
829     *count = 0;
830     *freeData = 0;
831
832     if (dstring && *dstring) {
833         char *domain, *de;
834         const char * langval;
835         const char * msgkey;
836         const char * msgid;
837
838         {   const char * tn = rpmTagGetName(tag);
839             const char * n;
840             char * mk;
841             size_t nb = sizeof("()");
842             int xx;
843             xx = headerNVR(h, &n, NULL, NULL);
844             if (tn)     nb += strlen(tn);
845             if (n)      nb += strlen(n);
846             mk = alloca(nb);
847             sprintf(mk, "%s(%s)", n, tn);
848             msgkey = mk;
849         }
850
851         /* change to en_US for msgkey -> msgid resolution */
852         langval = getenv(language);
853         (void) setenv(language, "en_US", 1);
854 #if defined(ENABLE_NLS)
855         ++_nl_msg_cat_cntr;
856 #endif
857
858         msgid = NULL;
859         for (domain = dstring; domain != NULL; domain = de) {
860             de = strchr(domain, ':');
861             if (de) *de++ = '\0';
862             msgid = dgettext(domain, msgkey);
863             if (msgid != msgkey) break;
864         }
865
866         /* restore previous environment for msgid -> msgstr resolution */
867         if (langval)
868             (void) setenv(language, langval, 1);
869         else
870             unsetenv(language);
871 #if defined(ENABLE_NLS)
872         ++_nl_msg_cat_cntr;
873 #endif
874
875         if (domain && msgid) {
876             *data = dgettext(domain, msgid);
877             *data = xstrdup(*data);     /* XXX xstrdup has side effects. */
878             *count = 1;
879             *freeData = 1;
880         }
881         dstring = _free(dstring);
882         if (*data)
883             return 0;
884     }
885
886     dstring = _free(dstring);
887
888     rc = hge(h, tag, type, data, count);
889
890     if (rc && (*data) != NULL) {
891         *data = xstrdup(*data);
892         *freeData = 1;
893         return 0;
894     }
895
896     *freeData = 0;
897     *data = NULL;
898     *count = 0;
899     return 1;
900 }
901
902 /**
903  * Retrieve summary text.
904  * @param h             header
905  * @retval *type        tag type
906  * @retval *data        tag value
907  * @retval *count       no. of data items
908  * @retval *freeData    data-was-malloc'ed indicator
909  * @return              0 on success
910  */
911 static int summaryTag(Header h, rpm_tagtype_t* type,
912                 rpm_data_t * data, rpm_count_t * count,
913                 int * freeData)
914 {
915     return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
916 }
917
918 /**
919  * Retrieve description text.
920  * @param h             header
921  * @retval *type        tag type
922  * @retval *data        tag value
923  * @retval *count       no. of data items
924  * @retval *freeData    data-was-malloc'ed indicator
925  * @return              0 on success
926  */
927 static int descriptionTag(Header h, rpm_tagtype_t* type,
928                 rpm_data_t * data, rpm_count_t * count,
929                 int * freeData)
930 {
931     return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
932 }
933
934 /**
935  * Retrieve group text.
936  * @param h             header
937  * @retval *type        tag type
938  * @retval *data        tag value
939  * @retval *count       no. of data items
940  * @retval *freeData    data-was-malloc'ed indicator
941  * @return              0 on success
942  */
943 static int groupTag(Header h, rpm_tagtype_t* type,
944                 rpm_data_t * data, rpm_count_t * count,
945                 int * freeData)
946 {
947     return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
948 }
949
950 /* FIX: cast? */
951 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
952     { HEADER_EXT_TAG, "RPMTAG_GROUP",           { groupTag } },
953     { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",     { descriptionTag } },
954     { HEADER_EXT_TAG, "RPMTAG_SUMMARY",         { summaryTag } },
955     { HEADER_EXT_TAG, "RPMTAG_FILECLASS",       { fileclassTag } },
956     { HEADER_EXT_TAG, "RPMTAG_FILENAMES",       { filenamesTag } },
957     { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE",     { fileprovideTag } },
958     { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE",     { filerequireTag } },
959     { HEADER_EXT_TAG, "RPMTAG_FSNAMES",         { fsnamesTag } },
960     { HEADER_EXT_TAG, "RPMTAG_FSSIZES",         { fssizesTag } },
961     { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",   { instprefixTag } },
962     { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",    { triggercondsTag } },
963     { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",     { triggertypeTag } },
964     { HEADER_EXT_FORMAT, "armor",               { armorFormat } },
965     { HEADER_EXT_FORMAT, "base64",              { base64Format } },
966     { HEADER_EXT_FORMAT, "pgpsig",              { pgpsigFormat } },
967     { HEADER_EXT_FORMAT, "depflags",            { depflagsFormat } },
968     { HEADER_EXT_FORMAT, "fflags",              { fflagsFormat } },
969     { HEADER_EXT_FORMAT, "perms",               { permsFormat } },
970     { HEADER_EXT_FORMAT, "permissions",         { permsFormat } },
971     { HEADER_EXT_FORMAT, "triggertype",         { triggertypeFormat } },
972     { HEADER_EXT_FORMAT, "xml",                 { xmlFormat } },
973     { HEADER_EXT_MORE, NULL,            { (void *) headerDefaultFormats } }
974 } ;