Sanitize python object -> tag number exception handling
[platform/upstream/rpm.git] / lib / tagexts.c
1 /** \ingroup header
2  * \file lib/formats.c
3  */
4
5 #include "system.h"
6
7 #include <rpm/rpmtypes.h>
8 #include <rpm/rpmlib.h>         /* rpmGetFilesystem*() */
9 #include <rpm/rpmmacro.h>       /* XXX for %_i18ndomains */
10 #include <rpm/rpmfi.h>
11 #include <rpm/rpmstring.h>
12
13 #include "debug.h"
14
15 struct headerTagFunc_s {
16     rpmTag tag;         /*!< Tag of extension. */
17     void *func;         /*!< Pointer to formatter function. */  
18 };
19
20 /* forward declarations */
21 static const struct headerTagFunc_s rpmHeaderTagExtensions[];
22
23 void *rpmHeaderTagFunc(rpmTag tag);
24
25 /** \ingroup rpmfi
26  * Retrieve file names from header.
27  *
28  * The representation of file names in package headers changed in rpm-4.0.
29  * Originally, file names were stored as an array of absolute paths.
30  * In rpm-4.0, file names are stored as separate arrays of dirname's and
31  * basename's, * with a dirname index to associate the correct dirname
32  * with each basname.
33  *
34  * This function is used to retrieve file names independent of how the
35  * file names are represented in the package header.
36  * 
37  * @param h             header
38  * @param tagN          RPMTAG_BASENAMES | PMTAG_ORIGBASENAMES
39  * @retval *fnp         array of file names
40  * @retval *fcp         number of files
41  */
42 static void rpmfiBuildFNames(Header h, rpmTag tagN,
43         const char *** fnp, rpm_count_t * fcp)
44 {
45     const char **baseNames, **dirNames, **fileNames;
46     uint32_t *dirIndexes;
47     rpm_count_t count;
48     size_t size;
49     rpmTag dirNameTag = 0;
50     rpmTag dirIndexesTag = 0;
51     char * t;
52     int i;
53     struct rpmtd_s bnames, dnames, dixs;
54
55     if (tagN == RPMTAG_BASENAMES) {
56         dirNameTag = RPMTAG_DIRNAMES;
57         dirIndexesTag = RPMTAG_DIRINDEXES;
58     } else if (tagN == RPMTAG_ORIGBASENAMES) {
59         dirNameTag = RPMTAG_ORIGDIRNAMES;
60         dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
61     }
62
63     if (!headerGet(h, tagN, &bnames, HEADERGET_MINMEM)) {
64         *fnp = NULL;
65         *fcp = 0;
66         return;         /* no file list */
67     }
68     (void) headerGet(h, dirNameTag, &dnames, HEADERGET_MINMEM);
69     (void) headerGet(h, dirIndexesTag, &dixs, HEADERGET_MINMEM);
70
71     count = rpmtdCount(&bnames);
72     baseNames = bnames.data;
73     dirNames = dnames.data;
74     dirIndexes = dixs.data;
75
76     /*
77      * fsm, psm and rpmfi assume the data is stored in a single allocation
78      * block, until those assumptions are removed we need to jump through
79      * a few hoops here and precalculate sizes etc
80      */
81     size = sizeof(*fileNames) * count;
82     for (i = 0; i < count; i++)
83         size += strlen(baseNames[i]) + strlen(dirNames[dirIndexes[i]]) + 1;
84
85     fileNames = xmalloc(size);
86     t = ((char *) fileNames) + (sizeof(*fileNames) * count);
87     for (i = 0; i < count; i++) {
88         fileNames[i] = t;
89         t = stpcpy( stpcpy(t, dirNames[dirIndexes[i]]), baseNames[i]);
90         *t++ = '\0';
91     }
92     rpmtdFreeData(&bnames);
93     rpmtdFreeData(&dnames);
94     rpmtdFreeData(&dixs);
95
96     *fnp = fileNames;
97     *fcp = count;
98 }
99
100 static int filedepTag(Header h, rpmTag tagN, rpmtd td, headerGetFlags hgflags)
101 {
102     rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
103     rpmds ds = NULL;
104     char **fdeps = NULL;
105     int numfiles;
106     char deptype = 'R';
107     int fileix;
108     int rc = 0;
109
110     numfiles = rpmfiFC(fi);
111     if (numfiles <= 0) {
112         goto exit;
113     }
114
115     if (tagN == RPMTAG_PROVIDENAME)
116         deptype = 'P';
117     else if (tagN == RPMTAG_REQUIRENAME)
118         deptype = 'R';
119
120     ds = rpmdsNew(h, tagN, 0);
121     fdeps = xmalloc(numfiles * sizeof(*fdeps));
122
123     while ((fileix = rpmfiNext(fi)) >= 0) {
124         ARGV_t deps = NULL;
125         const uint32_t * ddict = NULL;
126         int ndx = rpmfiFDepends(fi, &ddict);
127         if (ddict != NULL) {
128             while (ndx-- > 0) {
129                 const char * DNEVR;
130                 unsigned dix = *ddict++;
131                 char mydt = ((dix >> 24) & 0xff);
132                 if (mydt != deptype)
133                     continue;
134                 dix &= 0x00ffffff;
135                 (void) rpmdsSetIx(ds, dix-1);
136                 if (rpmdsNext(ds) < 0)
137                     continue;
138                 DNEVR = rpmdsDNEVR(ds);
139                 if (DNEVR != NULL) {
140                     argvAdd(&deps, DNEVR + 2);
141                 }
142             }
143         }
144         fdeps[fileix] = deps ? argvJoin(deps, " ") : xstrdup("");
145         argvFree(deps);
146     }
147     td->data = fdeps;
148     td->count = numfiles;
149     td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
150     td->type = RPM_STRING_ARRAY_TYPE;
151     rc = 1;
152
153 exit:
154     fi = rpmfiFree(fi);
155     ds = rpmdsFree(ds);
156     return rc;
157 }
158
159 /**
160  * Retrieve mounted file system paths.
161  * @param h             header
162  * @retval td           tag data container
163  * @return              1 on success
164  */
165 static int fsnamesTag(Header h, rpmtd td, headerGetFlags hgflags)
166 {
167     const char ** list;
168
169     if (rpmGetFilesystemList(&list, &(td->count)))
170         return 0;
171
172     td->type = RPM_STRING_ARRAY_TYPE;
173     td->data = list;
174
175     return 1; 
176 }
177
178 /**
179  * Retrieve install prefixes.
180  * @param h             header
181  * @retval td           tag data container
182  * @return              1 on success
183  */
184 static int instprefixTag(Header h, rpmtd td, headerGetFlags hgflags)
185 {
186     struct rpmtd_s prefixes;
187     int flags = HEADERGET_MINMEM;
188
189     if (headerGet(h, RPMTAG_INSTALLPREFIX, td, flags)) {
190         return 1;
191     } else if (headerGet(h, RPMTAG_INSTPREFIXES, &prefixes, flags)) {
192         /* only return the first prefix of the array */
193         td->type = RPM_STRING_TYPE;
194         td->data = xstrdup(rpmtdGetString(&prefixes));
195         td->flags = RPMTD_ALLOCED;
196         rpmtdFreeData(&prefixes);
197         return 1;
198     }
199
200     return 0;
201 }
202
203 /**
204  * Retrieve mounted file system space.
205  * @param h             header
206  * @retval td           tag data container
207  * @return              1 on success
208  */
209 static int fssizesTag(Header h, rpmtd td, headerGetFlags hgflags)
210 {
211     struct rpmtd_s fsizes, fnames;
212     const char ** filenames = NULL;
213     rpm_loff_t * filesizes = NULL;
214     rpm_loff_t * usages = NULL;
215     rpm_count_t numFiles = 0;
216
217     if (headerGet(h, RPMTAG_LONGFILESIZES, &fsizes, HEADERGET_EXT)) {
218         filesizes = fsizes.data;
219         headerGet(h, RPMTAG_FILENAMES, &fnames, HEADERGET_EXT);
220         filenames = fnames.data;
221         numFiles = rpmtdCount(&fnames);
222     }
223         
224     if (rpmGetFilesystemList(NULL, &(td->count)))
225         return 0;
226
227     td->type = RPM_INT64_TYPE;
228     td->flags = RPMTD_ALLOCED;
229
230     if (filenames == NULL) {
231         usages = xcalloc((td->count), sizeof(usages));
232         td->data = usages;
233
234         return 1;
235     }
236
237     if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))      
238         return 0;
239
240     td->data = usages;
241
242     rpmtdFreeData(&fnames);
243     rpmtdFreeData(&fsizes);
244
245     return 1;
246 }
247
248 /**
249  * Retrieve trigger info.
250  * @param h             header
251  * @retval td           tag data container
252  * @return              1 on success
253  */
254 static int triggercondsTag(Header h, rpmtd td, headerGetFlags hgflags)
255 {
256     uint32_t * indices;
257     int i, j;
258     char ** conds;
259     struct rpmtd_s nametd, indextd, flagtd, versiontd, scripttd;
260     int hgeflags = HEADERGET_MINMEM;
261
262     if (!headerGet(h, RPMTAG_TRIGGERNAME, &nametd, hgeflags)) {
263         return 0;
264     }
265
266     headerGet(h, RPMTAG_TRIGGERINDEX, &indextd, hgeflags);
267     headerGet(h, RPMTAG_TRIGGERFLAGS, &flagtd, hgeflags);
268     headerGet(h, RPMTAG_TRIGGERVERSION, &versiontd, hgeflags);
269     headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripttd, hgeflags);
270
271     td->type = RPM_STRING_ARRAY_TYPE;
272     td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
273     td->data = conds = xmalloc(sizeof(*conds) * rpmtdCount(&scripttd));
274     td->count = rpmtdCount(&scripttd);
275
276     indices = indextd.data;
277
278     while ((i = rpmtdNext(&scripttd)) >= 0) {
279         rpm_flag_t *flag;
280         char *flagStr, *item;
281         ARGV_t items = NULL;
282
283         rpmtdInit(&nametd); rpmtdInit(&flagtd); rpmtdInit(&versiontd);
284         while ((j = rpmtdNext(&nametd)) >= 0) {
285             /* flag and version arrays match name array size always */
286             rpmtdNext(&flagtd); rpmtdNext(&versiontd);
287
288             if (indices[j] != i)
289                 continue;
290
291             flag = rpmtdGetUint32(&flagtd);
292             if (flag && *flag & RPMSENSE_SENSEMASK) {
293                 flagStr = rpmtdFormat(&flagtd, RPMTD_FORMAT_DEPFLAGS, NULL);
294                 rasprintf(&item, "%s %s %s", rpmtdGetString(&nametd),
295                                              flagStr,
296                                              rpmtdGetString(&versiontd));
297                 free(flagStr);
298             } else {
299                 item = xstrdup(rpmtdGetString(&nametd));
300             }
301
302             argvAdd(&items, item);
303             free(item);
304         }
305
306         conds[i] = argvJoin(items, ", ");
307         argvFree(items);
308     }
309
310     rpmtdFreeData(&nametd);
311     rpmtdFreeData(&versiontd);
312     rpmtdFreeData(&flagtd);
313     rpmtdFreeData(&indextd);
314     rpmtdFreeData(&scripttd);
315     return 1;
316 }
317
318 /**
319  * Retrieve trigger type info.
320  * @param h             header
321  * @retval td           tag data container
322  * @return              1 on success
323  */
324 static int triggertypeTag(Header h, rpmtd td, headerGetFlags hgflags)
325 {
326     int i;
327     char ** conds;
328     struct rpmtd_s indices, flags, scripts;
329
330     if (!headerGet(h, RPMTAG_TRIGGERINDEX, &indices, HEADERGET_MINMEM)) {
331         return 0;
332     }
333
334     headerGet(h, RPMTAG_TRIGGERFLAGS, &flags, HEADERGET_MINMEM);
335     headerGet(h, RPMTAG_TRIGGERSCRIPTS, &scripts, HEADERGET_MINMEM);
336
337     td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
338     td->count = rpmtdCount(&scripts);
339     td->data = conds = xmalloc(sizeof(*conds) * td->count);
340     td->type = RPM_STRING_ARRAY_TYPE;
341
342     while ((i = rpmtdNext(&scripts)) >= 0) {
343         rpm_flag_t *flag;
344         rpmtdInit(&indices); rpmtdInit(&flags);
345
346         while (rpmtdNext(&indices) >= 0 && rpmtdNext(&flags) >= 0) {
347             if (*rpmtdGetUint32(&indices) != i) 
348                 continue;
349
350             flag = rpmtdGetUint32(&flags);
351             if (*flag & RPMSENSE_TRIGGERPREIN)
352                 conds[i] = xstrdup("prein");
353             else if (*flag & RPMSENSE_TRIGGERIN)
354                 conds[i] = xstrdup("in");
355             else if (*flag & RPMSENSE_TRIGGERUN)
356                 conds[i] = xstrdup("un");
357             else if (*flag & RPMSENSE_TRIGGERPOSTUN)
358                 conds[i] = xstrdup("postun");
359             else
360                 conds[i] = xstrdup("");
361             break;
362         }
363     }
364     rpmtdFreeData(&indices);
365     rpmtdFreeData(&flags);
366     rpmtdFreeData(&scripts);
367
368     return 1;
369 }
370
371 /**
372  * Retrieve file paths.
373  * @param h             header
374  * @retval td           tag data container
375  * @return              1 on success
376  */
377 static int filenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
378 {
379     rpmfiBuildFNames(h, RPMTAG_BASENAMES, 
380                      (const char ***) &(td->data), &(td->count));
381     if (td->data) {
382         td->type = RPM_STRING_ARRAY_TYPE;
383         td->flags = RPMTD_ALLOCED;
384     }
385     return (td->data != NULL); 
386 }
387
388 /**
389  * Retrieve original file paths (wrt relocation).
390  * @param h             header
391  * @retval td           tag data container
392  * @return              1 on success
393  */
394 static int origfilenamesTag(Header h, rpmtd td, headerGetFlags hgflags)
395 {
396     rpmfiBuildFNames(h, RPMTAG_ORIGBASENAMES, 
397                      (const char ***) &(td->data), &(td->count));
398     if (td->data) {
399         td->type = RPM_STRING_ARRAY_TYPE;
400         td->flags = RPMTD_ALLOCED;
401     }
402     return (td->data != NULL); 
403 }
404 /**
405  * Retrieve file classes.
406  * @param h             header
407  * @retval td           tag data container
408  * @return              1 on success
409  */
410 static int fileclassTag(Header h, rpmtd td, headerGetFlags hgflags)
411 {
412     rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
413     char **fclasses;
414     int ix, numfiles;
415     int rc = 0;
416
417     numfiles = rpmfiFC(fi);
418     if (numfiles <= 0) {
419         goto exit;
420     }
421
422     fclasses = xmalloc(numfiles * sizeof(*fclasses));
423     rpmfiInit(fi, 0);
424     while ((ix = rpmfiNext(fi)) >= 0) {
425         const char *fclass = rpmfiFClass(fi);
426         fclasses[ix] = xstrdup(fclass ? fclass : "");
427     }
428
429     td->data = fclasses;
430     td->count = numfiles;
431     td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
432     td->type = RPM_STRING_ARRAY_TYPE;
433     rc = 1;
434
435 exit:
436     fi = rpmfiFree(fi);
437     return rc; 
438 }
439
440 /**
441  * Retrieve file provides.
442  * @param h             header
443  * @retval td           tag data container
444  * @return              1 on success
445  */
446 static int fileprovideTag(Header h, rpmtd td, headerGetFlags hgflags)
447 {
448     return filedepTag(h, RPMTAG_PROVIDENAME, td, hgflags);
449 }
450
451 /**
452  * Retrieve file requires.
453  * @param h             header
454  * @retval td           tag data container
455  * @return              1 on success
456  */
457 static int filerequireTag(Header h, rpmtd td, headerGetFlags hgflags)
458 {
459     return filedepTag(h, RPMTAG_REQUIRENAME, td, hgflags);
460 }
461
462 /* I18N look aside diversions */
463
464 #if defined(ENABLE_NLS)
465 extern int _nl_msg_cat_cntr;    /* XXX GNU gettext voodoo */
466 #endif
467 static const char * const language = "LANGUAGE";
468
469 static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
470
471 /**
472  * Retrieve i18n text.
473  * @param h             header
474  * @param tag           tag
475  * @retval td           tag data container
476  * @return              1 on success
477  */
478 static int i18nTag(Header h, rpmTag tag, rpmtd td, headerGetFlags hgflags)
479 {
480     char * dstring = rpmExpand(_macro_i18ndomains, NULL);
481     int rc;
482
483     td->type = RPM_STRING_TYPE;
484     td->data = NULL;
485     td->count = 0;
486
487     if (dstring && *dstring) {
488         char *domain, *de;
489         const char * langval;
490         char * msgkey;
491         const char * msgid;
492
493         rasprintf(&msgkey, "%s(%s)", headerGetString(h, RPMTAG_NAME), 
494                   rpmTagGetName(tag));
495
496         /* change to en_US for msgkey -> msgid resolution */
497         langval = getenv(language);
498         (void) setenv(language, "en_US", 1);
499 #if defined(ENABLE_NLS)
500         ++_nl_msg_cat_cntr;
501 #endif
502
503         msgid = NULL;
504         for (domain = dstring; domain != NULL; domain = de) {
505             de = strchr(domain, ':');
506             if (de) *de++ = '\0';
507             msgid = dgettext(domain, msgkey);
508             if (msgid != msgkey) break;
509         }
510
511         /* restore previous environment for msgid -> msgstr resolution */
512         if (langval)
513             (void) setenv(language, langval, 1);
514         else
515             unsetenv(language);
516 #if defined(ENABLE_NLS)
517         ++_nl_msg_cat_cntr;
518 #endif
519
520         if (domain && msgid) {
521             td->data = dgettext(domain, msgid);
522             td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */
523             td->count = 1;
524             td->flags = RPMTD_ALLOCED;
525         }
526         dstring = _free(dstring);
527         free(msgkey);
528         if (td->data)
529             return 1;
530     }
531
532     dstring = _free(dstring);
533
534     rc = headerGet(h, tag, td, HEADERGET_DEFAULT);
535     return rc;
536 }
537
538 /**
539  * Retrieve summary text.
540  * @param h             header
541  * @retval td           tag data container
542  * @return              1 on success
543  */
544 static int summaryTag(Header h, rpmtd td, headerGetFlags hgflags)
545 {
546     return i18nTag(h, RPMTAG_SUMMARY, td, hgflags);
547 }
548
549 /**
550  * Retrieve description text.
551  * @param h             header
552  * @retval td           tag data container
553  * @return              1 on success
554  */
555 static int descriptionTag(Header h, rpmtd td, headerGetFlags hgflags)
556 {
557     return i18nTag(h, RPMTAG_DESCRIPTION, td, hgflags);
558 }
559
560 /**
561  * Retrieve group text.
562  * @param h             header
563  * @retval td           tag data container
564  * @return              1 on success
565  */
566 static int groupTag(Header h, rpmtd td, headerGetFlags hgflags)
567 {
568     return i18nTag(h, RPMTAG_GROUP, td, hgflags);
569 }
570
571 /*
572  * Helper to convert 32bit tag to 64bit version.
573  * If header has new 64bit tag then just return the data,
574  * otherwise convert 32bit old tag data to 64bit values.
575  * For consistency, always return malloced data.
576  */
577 static int get64(Header h, rpmtd td, rpmTag newtag, rpmTag oldtag)
578 {
579     int rc;
580
581     if (headerIsEntry(h, newtag)) {
582         rc = headerGet(h, newtag, td, HEADERGET_ALLOC);
583     } else {
584         struct rpmtd_s olddata;
585         uint32_t *d32 = NULL;
586         uint64_t *d64 = NULL;
587
588         headerGet(h, oldtag, &olddata, HEADERGET_MINMEM);
589         if (rpmtdType(&olddata) == RPM_INT32_TYPE) {
590             td->type = RPM_INT64_TYPE;
591             td->count = olddata.count;
592             td->flags = RPMTD_ALLOCED;
593             td->data = xmalloc(sizeof(*d64) * td->count);
594             d64 = td->data;
595             while ((d32 = rpmtdNextUint32(&olddata))) {
596                 *d64++ = *d32;
597             }
598         } 
599         rpmtdFreeData(&olddata);
600         rc = d64 ? 1 : 0;
601     }
602
603     return rc;
604 }
605
606 /**
607  * Retrieve file sizes as 64bit regardless of how they're stored.
608  * @param h             header
609  * @retval td           tag data container
610  * @return              1 on success
611  */
612 static int longfilesizesTag(Header h, rpmtd td, headerGetFlags hgflags)
613 {
614     return get64(h, td, RPMTAG_LONGFILESIZES, RPMTAG_FILESIZES);
615 }
616
617 static int longarchivesizeTag(Header h, rpmtd td, headerGetFlags hgflags)
618 {
619     return get64(h, td, RPMTAG_LONGARCHIVESIZE, RPMTAG_ARCHIVESIZE);
620 }
621
622 static int longsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
623 {
624     return get64(h, td, RPMTAG_LONGSIZE, RPMTAG_SIZE);
625 }
626
627 static int longsigsizeTag(Header h, rpmtd td, headerGetFlags hgflags)
628 {
629     return get64(h, td, RPMTAG_LONGSIGSIZE, RPMTAG_SIGSIZE);
630 }
631
632 static int numberTag(rpmtd td, uint32_t val)
633 {
634     uint32_t *tval = xmalloc(sizeof(*tval));
635
636     tval[0] = val;
637     td->type = RPM_INT32_TYPE;
638     td->count = 1;
639     td->data = tval;
640     td->flags = RPMTD_ALLOCED;
641     return 1; /* this cannot fail */
642 }
643
644 static int dbinstanceTag(Header h, rpmtd td, headerGetFlags hgflags)
645 {
646     return numberTag(td, headerGetInstance(h));
647 }
648
649 static int headercolorTag(Header h, rpmtd td, headerGetFlags hgflags)
650 {
651     rpm_color_t *fcolor, hcolor = 0;
652     struct rpmtd_s fcolors;
653
654     headerGet(h, RPMTAG_FILECOLORS, &fcolors, HEADERGET_MINMEM);
655     while ((fcolor = rpmtdNextUint32(&fcolors)) != NULL) {
656         hcolor |= *fcolor;
657     }
658     rpmtdFreeData(&fcolors);
659     hcolor &= 0x0f;
660
661     return numberTag(td, hcolor);
662 }
663
664 typedef enum nevraFlags_e {
665     NEVRA_NAME          = (1 << 0),
666     NEVRA_EPOCH         = (1 << 1),
667     NEVRA_VERSION       = (1 << 2),
668     NEVRA_RELEASE       = (1 << 3),
669     NEVRA_ARCH          = (1 << 4)
670 } nevraFlags;
671
672 static int getNEVRA(Header h, rpmtd td, nevraFlags flags)
673 {
674     const char *val = NULL;
675     char *res = NULL;
676
677     if ((flags & NEVRA_NAME)) {
678         val = headerGetString(h, RPMTAG_NAME);
679         if (val) rstrscat(&res, val, "-", NULL);
680     }
681     if ((flags & NEVRA_EPOCH)) {
682         char *e = headerGetAsString(h, RPMTAG_EPOCH);
683         if (e) rstrscat(&res, e, ":", NULL);
684         free(e);
685     }
686     if ((flags & NEVRA_VERSION)) {
687         val = headerGetString(h, RPMTAG_VERSION);
688         if (val) rstrscat(&res, val, "-", NULL);
689     }
690     if ((flags & NEVRA_RELEASE)) {
691         val = headerGetString(h, RPMTAG_RELEASE);
692         if (val) rstrscat(&res, val, NULL);
693     }
694     if ((flags & NEVRA_ARCH)) {
695         val = headerGetString(h, RPMTAG_ARCH);
696         if (headerIsSource(h) && val == NULL) val = "src";
697         if (val) rstrscat(&res, ".", val, NULL);
698     }
699
700     td->type = RPM_STRING_TYPE;
701     td->data = res;
702     td->count = 1;
703     td->flags = RPMTD_ALLOCED;
704
705     return 1;
706 }
707
708 static int evrTag(Header h, rpmtd td, headerGetFlags hgflags)
709 {
710     return getNEVRA(h, td, NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
711 }
712
713 static int nvrTag(Header h, rpmtd td, headerGetFlags hgflags)
714 {
715     return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE);
716 }
717
718 static int nvraTag(Header h, rpmtd td, headerGetFlags hgflags)
719 {
720     return getNEVRA(h, td, NEVRA_NAME|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
721 }
722
723 static int nevrTag(Header h, rpmtd td, headerGetFlags hgflags)
724 {
725     return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE);
726 }
727
728 static int nevraTag(Header h, rpmtd td, headerGetFlags hgflags)
729 {
730     return getNEVRA(h, td, NEVRA_NAME|NEVRA_EPOCH|NEVRA_VERSION|NEVRA_RELEASE|NEVRA_ARCH);
731 }
732
733 void *rpmHeaderTagFunc(rpmTag tag)
734 {
735     const struct headerTagFunc_s * ext;
736     void *func = NULL;
737
738     for (ext = rpmHeaderTagExtensions; ext->func != NULL; ext++) {
739         if (ext->tag == tag) {
740             func = ext->func;
741             break;
742         }
743     }
744     return func;
745 }
746
747 static const struct headerTagFunc_s rpmHeaderTagExtensions[] = {
748     { RPMTAG_GROUP,             groupTag },
749     { RPMTAG_DESCRIPTION,       descriptionTag },
750     { RPMTAG_SUMMARY,           summaryTag },
751     { RPMTAG_FILECLASS,         fileclassTag },
752     { RPMTAG_FILENAMES,         filenamesTag },
753     { RPMTAG_ORIGFILENAMES,     origfilenamesTag },
754     { RPMTAG_FILEPROVIDE,       fileprovideTag },
755     { RPMTAG_FILEREQUIRE,       filerequireTag },
756     { RPMTAG_FSNAMES,           fsnamesTag },
757     { RPMTAG_FSSIZES,           fssizesTag },
758     { RPMTAG_INSTALLPREFIX,     instprefixTag },
759     { RPMTAG_TRIGGERCONDS,      triggercondsTag },
760     { RPMTAG_TRIGGERTYPE,       triggertypeTag },
761     { RPMTAG_LONGFILESIZES,     longfilesizesTag },
762     { RPMTAG_LONGARCHIVESIZE,   longarchivesizeTag },
763     { RPMTAG_LONGSIZE,          longsizeTag },
764     { RPMTAG_LONGSIGSIZE,       longsigsizeTag },
765     { RPMTAG_DBINSTANCE,        dbinstanceTag },
766     { RPMTAG_EVR,               evrTag },
767     { RPMTAG_NVR,               nvrTag },
768     { RPMTAG_NEVR,              nevrTag },
769     { RPMTAG_NVRA,              nvraTag },
770     { RPMTAG_NEVRA,             nevraTag },
771     { RPMTAG_HEADERCOLOR,       headercolorTag },
772     { 0,                        NULL }
773 };
774