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