rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmdb/hdrfmt.c
Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 /* XXX todo: these should likely be in "system.h" */
    00008 #if defined(HAVE_ICONV)
    00009 #include <iconv.h>
    00010 #if defined(__LCLINT__)
    00011 /*@-declundef -exportheader -incondefs @*/
    00012 extern /*@only@*/ iconv_t iconv_open(const char *__tocode, const char *__fromcode)
    00013         /*@*/;
    00014
    00015 extern size_t iconv(iconv_t __cd, /*@null@*/ char ** __inbuf,
    00016                     /*@out@*/ size_t * __inbytesleft,
    00017                     /*@out@*/ char ** __outbuf,
    00018                     /*@out@*/ size_t * __outbytesleft)
    00019         /*@modifies __cd,
    00020                 *__inbuf, *__inbytesleft, *__outbuf, *__outbytesleft @*/;
    00021
    00022 extern int iconv_close(/*@only@*/ iconv_t __cd)
    00023         /*@modifies __cd @*/;
    00024 /*@=declundef =exportheader =incondefs @*/
    00025 #endif
    00026 #endif
    00027
    00028 #if defined(HAVE_LANGINFO_H)
    00029 #include <langinfo.h>
    00030 #if defined(__LCLINT__)
    00031 /*@-declundef -exportheader -incondefs @*/
    00032 extern char *nl_langinfo (nl_item __item)
    00033         /*@*/;
    00034 /*@=declundef =exportheader =incondefs @*/
    00035 #endif
    00036 #endif
    00037
    00038 #define _MIRE_INTERNAL
    00039 #include "rpmio_internal.h"
    00040 #include <rpmbc.h>      /* XXX beecrypt base64 */
    00041 #include <rpmcb.h>      /* XXX rpmIsVerbose */
    00042 #include <rpmmacro.h>   /* XXX for %_i18ndomains */
    00043 #include <rpmuuid.h>
    00044 #include <argv.h>
    00045 #include <ugid.h>
    00046
    00047 #define _RPMTAG_INTERNAL
    00048 #include <rpmtag.h>
    00049 #define _RPMEVR_INTERNAL
    00050 #include <rpmevr.h>     /* XXX RPMSENSE_FOO */
    00051 #include <rpmns.h>
    00052 #include <rpmdb.h>
    00053
    00054 #include <rpmtypes.h>   /* XXX rpmfi */
    00055 #include "misc.h"       /* XXX rpmMkdirPath */
    00056 #include <rpmfi.h>      /* XXX RPMFILE_FOO */
    00057
    00058 #include "legacy.h"
    00059 #include "misc.h"
    00060
    00061 #include "debug.h"
    00062
    00063 /*@unchecked@*/
    00064 int _hdrqf_debug;
    00065
    00066 /*@access pgpDig @*/
    00067 /*@access pgpDigParams @*/
    00068 /*@access headerSprintfExtension @*/
    00069 /*@access headerTagTableEntry @*/
    00070 /*@access Header @*/    /* XXX debugging msgs */
    00071 /*@access EVR_t @*/
    00072 /*@access rpmdb @*/     /* XXX for casts */
    00073 /*@access miRE @*/
    00074
    00082 static char * intFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
    00083                 /*@null@*/ const char *fmt)
    00084         /*@*/
    00085 {
    00086     rpmuint32_t ix = (he->ix > 0 ? he->ix : 0);
    00087     rpmuint64_t ival = 0;
    00088     const char * istr = NULL;
    00089     char * b;
    00090     size_t nb = 0;
    00091     int xx;
    00092
    00093     if (fmt == NULL || *fmt == '\0')
    00094         fmt = "d";
    00095
    00096     switch (he->t) {
    00097     default:
    00098         return xstrdup(_("(not a number)"));
    00099         /*@notreached@*/ break;
    00100     case RPM_UINT8_TYPE:
    00101         ival = (rpmuint64_t) he->p.ui8p[ix];
    00102         break;
    00103     case RPM_UINT16_TYPE:
    00104         ival = (rpmuint64_t) he->p.ui16p[ix];
    00105         break;
    00106     case RPM_UINT32_TYPE:
    00107         ival = (rpmuint64_t) he->p.ui32p[ix];
    00108         break;
    00109     case RPM_UINT64_TYPE:
    00110         ival = he->p.ui64p[ix];
    00111         break;
    00112     case RPM_STRING_TYPE:
    00113         istr = he->p.str;
    00114         break;
    00115     case RPM_STRING_ARRAY_TYPE:
    00116         istr = he->p.argv[ix];
    00117         break;
    00118     case RPM_BIN_TYPE:
    00119         {   static char hex[] = "0123456789abcdef";
    00120             const char * s = he->p.str;
    00121             rpmTagCount c = he->c;
    00122             char * t;
    00123
    00124             nb = 2 * c + 1;
    00125             t = b = alloca(nb+1);
    00126             while (c-- > 0) {
    00127                 unsigned i;
    00128                 i = (unsigned) *s++;
    00129                 *t++ = hex[ (i >> 4) & 0xf ];
    00130                 *t++ = hex[ (i     ) & 0xf ];
    00131             }
    00132             *t = '\0';
    00133         }   break;
    00134     }
    00135
    00136     if (istr) {         /* string */
    00137         b = (char *)istr;       /* NOCAST */
    00138     } else
    00139     if (nb == 0) {      /* number */
    00140         char myfmt[] = "%llX";
    00141         myfmt[3] = ((fmt != NULL && *fmt != '\0') ? *fmt : 'd');
    00142         nb = 64;
    00143         b = alloca(nb);
    00144 /*@-formatconst@*/
    00145         xx = snprintf(b, nb, myfmt, ival);
    00146 /*@=formatconst@*/
    00147         b[nb-1] = '\0';
    00148     }
    00149
    00150     return xstrdup(b);
    00151 }
    00152
    00159 static char * octFormat(HE_t he, /*@null@*/ const char ** av)
    00160         /*@*/
    00161 {
    00162     return intFormat(he, av, "o");
    00163 }
    00164
    00171 static char * hexFormat(HE_t he, /*@null@*/ const char ** av)
    00172         /*@*/
    00173 {
    00174     return intFormat(he, av, "x");
    00175 }
    00176
    00183 static char * decFormat(HE_t he, /*@null@*/ const char ** av)
    00184         /*@*/
    00185 {
    00186     return intFormat(he, av, "d");
    00187 }
    00188
    00196 static char * realDateFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
    00197                 const char * strftimeFormat)
    00198         /*@*/
    00199 {
    00200     char * val;
    00201
    00202     if (he->t != RPM_UINT64_TYPE) {
    00203         val = xstrdup(_("(not a number)"));
    00204     } else {
    00205         struct tm * tstruct;
    00206         char buf[50];
    00207
    00208         /* this is important if sizeof(rpmuint64_t) ! sizeof(time_t) */
    00209         {   time_t dateint = he->p.ui64p[0];
    00210             tstruct = localtime(&dateint);
    00211         }
    00212         buf[0] = '\0';
    00213         if (tstruct)
    00214             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
    00215         buf[sizeof(buf) - 1] = '\0';
    00216         val = xstrdup(buf);
    00217     }
    00218
    00219     return val;
    00220 }
    00221
    00228 static char * dateFormat(HE_t he, /*@null@*/ const char ** av)
    00229         /*@*/
    00230 {
    00231     return realDateFormat(he, av, _("%c"));
    00232 }
    00233
    00240 static char * dayFormat(HE_t he, /*@null@*/ const char ** av)
    00241         /*@*/
    00242 {
    00243     return realDateFormat(he, av, _("%a %b %d %Y"));
    00244 }
    00245
    00252 static char * shescapeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00253         /*@*/
    00254 {
    00255     char * val;
    00256     size_t nb;
    00257     int xx;
    00258
    00259     /* XXX one of these integer types is unnecessary. */
    00260     if (he->t == RPM_UINT32_TYPE) {
    00261         nb = 20;
    00262         val = xmalloc(nb);
    00263         xx = snprintf(val, nb, "%u", (unsigned) he->p.ui32p[0]);
    00264         val[nb-1] = '\0';
    00265     } else if (he->t == RPM_UINT64_TYPE) {
    00266         nb = 40;
    00267         val = xmalloc(40);
    00268 /*@-duplicatequals@*/
    00269         xx = snprintf(val, nb, "%llu", (unsigned long long)he->p.ui64p[0]);
    00270 /*@=duplicatequals@*/
    00271         val[nb-1] = '\0';
    00272     } else if (he->t == RPM_STRING_TYPE) {
    00273         const char * s = he->p.str;
    00274         char * t;
    00275         int c;
    00276
    00277         nb = 0;
    00278         for (s = he->p.str; (c = (int)*s) != 0; s++)  {
    00279             nb++;
    00280             if (c == (int)'\'')
    00281                 nb += 3;
    00282         }
    00283         nb += 3;
    00284         t = val = xmalloc(nb);
    00285         *t++ = '\'';
    00286         for (s = he->p.str; (c = (int)*s) != 0; s++)  {
    00287             if (c == (int)'\'') {
    00288                 *t++ = '\'';
    00289                 *t++ = '\\';
    00290                 *t++ = '\'';
    00291             }
    00292             *t++ = (char) c;
    00293         }
    00294         *t++ = '\'';
    00295         *t = '\0';
    00296     } else
    00297         val = xstrdup(_("invalid type"));
    00298
    00299     return val;
    00300 }
    00301
    00302 static struct headerSprintfExtension_s _headerDefaultFormats[] = {
    00303     { HEADER_EXT_FORMAT, "octal",
    00304         { .fmtFunction = octFormat } },
    00305     { HEADER_EXT_FORMAT, "oct",
    00306         { .fmtFunction = octFormat } },
    00307     { HEADER_EXT_FORMAT, "hex",
    00308         { .fmtFunction = hexFormat } },
    00309     { HEADER_EXT_FORMAT, "decimal",
    00310         { .fmtFunction = decFormat } },
    00311     { HEADER_EXT_FORMAT, "dec",
    00312         { .fmtFunction = decFormat } },
    00313     { HEADER_EXT_FORMAT, "date",
    00314         { .fmtFunction = dateFormat } },
    00315     { HEADER_EXT_FORMAT, "day",
    00316         { .fmtFunction = dayFormat } },
    00317     { HEADER_EXT_FORMAT, "shescape",
    00318         { .fmtFunction = shescapeFormat } },
    00319     { HEADER_EXT_LAST, NULL, { NULL } }
    00320 };
    00321
    00322 headerSprintfExtension headerDefaultFormats = &_headerDefaultFormats[0];
    00323
    00324 /* XXX FIXME: static for now, refactor from manifest.c later. */
    00325 static char * rpmPermsString(int mode)
    00326         /*@*/
    00327 {
    00328     char *perms = xstrdup("----------");
    00329
    00330     if (S_ISREG(mode))
    00331         perms[0] = '-';
    00332     else if (S_ISDIR(mode))
    00333         perms[0] = 'd';
    00334     else if (S_ISLNK(mode))
    00335         perms[0] = 'l';
    00336     else if (S_ISFIFO(mode))
    00337         perms[0] = 'p';
    00338 /*@-unrecog@*/
    00339     else if (S_ISSOCK(mode))
    00340         perms[0] = 's';
    00341 /*@=unrecog@*/
    00342     else if (S_ISCHR(mode))
    00343         perms[0] = 'c';
    00344     else if (S_ISBLK(mode))
    00345         perms[0] = 'b';
    00346     else
    00347         perms[0] = '?';
    00348
    00349     if (mode & S_IRUSR) perms[1] = 'r';
    00350     if (mode & S_IWUSR) perms[2] = 'w';
    00351     if (mode & S_IXUSR) perms[3] = 'x';
    00352
    00353     if (mode & S_IRGRP) perms[4] = 'r';
    00354     if (mode & S_IWGRP) perms[5] = 'w';
    00355     if (mode & S_IXGRP) perms[6] = 'x';
    00356
    00357     if (mode & S_IROTH) perms[7] = 'r';
    00358     if (mode & S_IWOTH) perms[8] = 'w';
    00359     if (mode & S_IXOTH) perms[9] = 'x';
    00360
    00361     if (mode & S_ISUID)
    00362         perms[3] = ((mode & S_IXUSR) ? 's' : 'S');
    00363
    00364     if (mode & S_ISGID)
    00365         perms[6] = ((mode & S_IXGRP) ? 's' : 'S');
    00366
    00367     if (mode & S_ISVTX)
    00368         perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
    00369
    00370     return perms;
    00371 }
    00372
    00379 static /*@only@*/ char * triggertypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00380         /*@*/
    00381 {
    00382     int ix = (he->ix > 0 ? he->ix : 0);
    00383     char * val;
    00384
    00385 assert(ix == 0);
    00386     if (he->t != RPM_UINT64_TYPE)
    00387         val = xstrdup(_("(invalid type)"));
    00388     else {
    00389         rpmuint64_t anint = he->p.ui64p[ix];
    00390         if (anint & RPMSENSE_TRIGGERPREIN)
    00391             val = xstrdup("prein");
    00392         else if (anint & RPMSENSE_TRIGGERIN)
    00393             val = xstrdup("in");
    00394         else if (anint & RPMSENSE_TRIGGERUN)
    00395             val = xstrdup("un");
    00396         else if (anint & RPMSENSE_TRIGGERPOSTUN)
    00397             val = xstrdup("postun");
    00398         else
    00399             val = xstrdup("");
    00400     }
    00401     return val;
    00402 }
    00403
    00410 static /*@only@*/ char * permsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00411         /*@*/
    00412 {
    00413     int ix = (he->ix > 0 ? he->ix : 0);
    00414     char * val;
    00415
    00416 assert(ix == 0);
    00417     if (he->t != RPM_UINT64_TYPE) {
    00418         val = xstrdup(_("(invalid type)"));
    00419     } else {
    00420         rpmuint64_t anint = he->p.ui64p[0];
    00421         val = rpmPermsString((int)anint);
    00422     }
    00423
    00424     return val;
    00425 }
    00426
    00433 static /*@only@*/ char * fflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00434         /*@*/
    00435 {
    00436     int ix = (he->ix >= 0 ? he->ix : 0);
    00437     char * val;
    00438
    00439 assert(ix == 0);
    00440     if (he->t != RPM_UINT64_TYPE) {
    00441         val = xstrdup(_("(invalid type)"));
    00442     } else {
    00443         char buf[15];
    00444         rpmuint64_t anint = he->p.ui64p[ix];
    00445         buf[0] = '\0';
    00446         if (anint & RPMFILE_DOC)
    00447             strcat(buf, "d");
    00448         if (anint & RPMFILE_CONFIG)
    00449             strcat(buf, "c");
    00450         if (anint & RPMFILE_SPECFILE)
    00451             strcat(buf, "s");
    00452         if (anint & RPMFILE_MISSINGOK)
    00453             strcat(buf, "m");
    00454         if (anint & RPMFILE_NOREPLACE)
    00455             strcat(buf, "n");
    00456         if (anint & RPMFILE_GHOST)
    00457             strcat(buf, "g");
    00458         if (anint & RPMFILE_LICENSE)
    00459             strcat(buf, "l");
    00460         if (anint & RPMFILE_README)
    00461             strcat(buf, "r");
    00462         val = xstrdup(buf);
    00463     }
    00464
    00465     return val;
    00466 }
    00467
    00475 static /*@only@*/ char * armorFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00476         /*@*/
    00477 {
    00478     int ix = (he->ix > 0 ? he->ix : 0);
    00479     const char * enc;
    00480     const unsigned char * s;
    00481     size_t ns;
    00482     rpmuint8_t atype;
    00483     char * val;
    00484
    00485 assert(ix == 0);
    00486     switch (he->t) {
    00487     case RPM_BIN_TYPE:
    00488         s = (unsigned char *) he->p.ui8p;
    00489         ns = he->c;
    00490         atype = (rpmuint8_t)PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
    00491         break;
    00492     case RPM_STRING_TYPE:
    00493     case RPM_STRING_ARRAY_TYPE:
    00494         enc = he->p.str;
    00495         s = NULL;
    00496         ns = 0;
    00497 /*@-moduncon@*/
    00498         if (b64decode(enc, (void **)&s, &ns))
    00499             return xstrdup(_("(not base64)"));
    00500 /*@=moduncon@*/
    00501         atype = (rpmuint8_t)PGPARMOR_PUBKEY;    /* XXX check pkt for pubkey */
    00502         break;
    00503     case RPM_UINT8_TYPE:
    00504     case RPM_UINT16_TYPE:
    00505     case RPM_UINT32_TYPE:
    00506     case RPM_UINT64_TYPE:
    00507     case RPM_I18NSTRING_TYPE:
    00508     default:
    00509         return xstrdup(_("(invalid type)"));
    00510         /*@notreached@*/ break;
    00511     }
    00512
    00513     val = pgpArmorWrap(atype, s, ns);
    00514     if (atype == (rpmuint8_t)PGPARMOR_PUBKEY)
    00515         s = _free(s);
    00516     return val;
    00517 }
    00518
    00526 static /*@only@*/ char * base64Format(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00527         /*@*/
    00528 {
    00529     int ix = (he->ix > 0 ? he->ix : 0);
    00530     char * val;
    00531     const char * enc;
    00532     char * t;
    00533     int lc;
    00534     size_t ns;
    00535     size_t nt;
    00536
    00537 assert(ix == 0);
    00538     switch(he->t) {
    00539     default:
    00540         val = xstrdup(_("(invalid type :base64)"));
    00541         goto exit;
    00542         /*@notreached@*/ break;
    00543     case RPM_UINT64_TYPE:
    00544         ns = sizeof(he->p.ui64p[0]);
    00545         break;
    00546     case RPM_STRING_TYPE:
    00547         ns = strlen(he->p.str);
    00548         break;
    00549     case RPM_BIN_TYPE:
    00550         ns = he->c;
    00551         break;
    00552     }
    00553
    00554     nt = ((ns + 2) / 3) * 4;
    00555
    00556 /*@-globs@*/
    00557     /* Add additional bytes necessary for eol string(s). */
    00558     if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
    00559         lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
    00560         if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
    00561             ++lc;
    00562         nt += lc * strlen(b64encode_eolstr);
    00563     }
    00564 /*@=globs@*/
    00565
    00566     val = t = xcalloc(1, nt + 1);
    00567     *t = '\0';
    00568
    00569     /* XXX b64encode accesses uninitialized memory. */
    00570     {   unsigned char * _data = xcalloc(1, ns+1);
    00571 assert(he->p.ptr != NULL);
    00572         memcpy(_data, he->p.ptr, ns);
    00573 /*@-moduncon@*/
    00574         if ((enc = b64encode(_data, ns)) != NULL) {
    00575             t = stpcpy(t, enc);
    00576             enc = _free(enc);
    00577         }
    00578 /*@=moduncon@*/
    00579         _data = _free(_data);
    00580     }
    00581
    00582 exit:
    00583 /*@-globstate@*/        /* b64encode_eolstr annotation */
    00584     return val;
    00585 /*@=globstate@*/
    00586 }
    00587
    00593 static size_t xmlstrlen(const char * s)
    00594         /*@*/
    00595 {
    00596     size_t len = 0;
    00597     int c;
    00598
    00599     while ((c = (int) *s++) != (int) '\0') {
    00600         switch (c) {
    00601         case '<':
    00602         case '>':       len += sizeof("&lt;") - 1;      /*@switchbreak@*/ break;
    00603         case '&':       len += sizeof("&amp;") - 1;     /*@switchbreak@*/ break;
    00604         default:        len += 1;                       /*@switchbreak@*/ break;
    00605         }
    00606     }
    00607     return len;
    00608 }
    00609
    00616 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s)
    00617         /*@modifies t @*/
    00618 {
    00619     char * te = t;
    00620     int c;
    00621
    00622     while ((c = (int) *s++) != (int) '\0') {
    00623         switch (c) {
    00624         case '<':       te = stpcpy(te, "&lt;");        /*@switchbreak@*/ break;
    00625         case '>':       te = stpcpy(te, "&gt;");        /*@switchbreak@*/ break;
    00626         case '&':       te = stpcpy(te, "&amp;");       /*@switchbreak@*/ break;
    00627         default:        *te++ = (char) c;               /*@switchbreak@*/ break;
    00628         }
    00629     }
    00630     *te = '\0';
    00631     return t;
    00632 }
    00633
    00634 static /*@only@*/ /*@null@*/ char *
    00635 strdup_locale_convert (/*@null@*/ const char * buffer,
    00636                 /*@null@*/ const char * tocode)
    00637         /*@*/
    00638 {
    00639     char *dest_str;
    00640 #if defined(HAVE_ICONV)
    00641     char *fromcode = NULL;
    00642     iconv_t fd;
    00643
    00644     if (buffer == NULL)
    00645         return NULL;
    00646
    00647     if (tocode == NULL)
    00648         tocode = "UTF-8";
    00649
    00650 #ifdef HAVE_LANGINFO_H
    00651     fromcode = nl_langinfo (CODESET);
    00652 #endif
    00653
    00654     if (fromcode != NULL && strcmp(tocode, fromcode) != 0
    00655      && (fd = iconv_open(tocode, fromcode)) != (iconv_t)-1)
    00656     {
    00657         const char *pin = buffer;
    00658         char *pout = NULL;
    00659         size_t ib, ob, dest_size;
    00660         int done;
    00661         int is_error;
    00662         size_t err;
    00663         const char *shift_pin = NULL;
    00664         int xx;
    00665
    00666         err = iconv(fd, NULL, &ib, &pout, &ob);
    00667         dest_size = ob = ib = strlen(buffer);
    00668         dest_str = pout = malloc((dest_size + 1) * sizeof(*dest_str));
    00669         if (dest_str)
    00670             *dest_str = '\0';
    00671         done = is_error = 0;
    00672         if (pout != NULL)
    00673         while (done == 0 && is_error == 0) {
    00674             err = iconv(fd, (char **)&pin, &ib, &pout, &ob);
    00675
    00676             if (err == (size_t)-1) {
    00677                 switch (errno) {
    00678                 case EINVAL:
    00679                     done = 1;
    00680                     /*@switchbreak@*/ break;
    00681                 case E2BIG:
    00682                 {   size_t used = (size_t)(pout - dest_str);
    00683                     dest_size *= 2;
    00684                     dest_str = realloc(dest_str, (dest_size + 1) * sizeof(*dest_str));
    00685                     if (dest_str == NULL) {
    00686                         is_error = 1;
    00687                         continue;
    00688                     }
    00689                     pout = dest_str + used;
    00690                     ob = dest_size - used;
    00691                 }   /*@switchbreak@*/ break;
    00692                 case EILSEQ:
    00693                     is_error = 1;
    00694                     /*@switchbreak@*/ break;
    00695                 default:
    00696                     is_error = 1;
    00697                     /*@switchbreak@*/ break;
    00698                 }
    00699             } else {
    00700                 if (shift_pin == NULL) {
    00701                     shift_pin = pin;
    00702                     pin = NULL;
    00703                     ib = 0;
    00704                 } else {
    00705                     done = 1;
    00706                 }
    00707             }
    00708         }
    00709         xx = iconv_close(fd);
    00710         if (pout)
    00711             *pout = '\0';
    00712         if (dest_str != NULL)
    00713             dest_str = xstrdup(dest_str);
    00714     } else
    00715 #endif
    00716     {
    00717         dest_str = xstrdup((buffer ? buffer : ""));
    00718     }
    00719
    00720     return dest_str;
    00721 }
    00722
    00729 static /*@only@*/ char * cdataFormat(HE_t he, /*@null@*/ const char ** av)
    00730         /*@*/
    00731 {
    00732     int ix = (he->ix > 0 ? he->ix : 0);
    00733     char * val;
    00734
    00735 assert(ix == 0);
    00736     if (he->t != RPM_STRING_TYPE) {
    00737         val = xstrdup(_("(not a string)"));
    00738     } else {
    00739         const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
    00740         size_t nb;
    00741         char * t;
    00742
    00743         if (s == NULL) {
    00744             /* XXX better error msg? */
    00745             val = xstrdup(_("(not a string)"));
    00746             goto exit;
    00747         }
    00748         nb = xmlstrlen(s);
    00749         val = t = xcalloc(1, nb + 1);
    00750         t = xmlstrcpy(t, s);    t += strlen(t);
    00751         *t = '\0';
    00752         s = _free(s);
    00753     }
    00754
    00755 exit:
    00756     return val;
    00757 }
    00758
    00765 static /*@only@*/ char * iconvFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00766         /*@*/
    00767 {
    00768     int ix = (he->ix > 0 ? he->ix : 0);
    00769     char * val = NULL;
    00770
    00771 assert(ix == 0);
    00772     if (he->t == RPM_STRING_TYPE)
    00773         val = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
    00774     if (val == NULL)
    00775         val = xstrdup(_("(not a string)"));
    00776
    00777     return val;
    00778 }
    00779
    00786 static /*@only@*/ char * xmlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00787         /*@*/
    00788 {
    00789     int ix = (he->ix > 0 ? he->ix : 0);
    00790     const char * xtag = NULL;
    00791     size_t nb;
    00792     char * val;
    00793     const char * s = NULL;
    00794     char * t, * te;
    00795     rpmuint64_t anint = 0;
    00796     int freeit = 0;
    00797     int xx;
    00798
    00799 assert(ix == 0);
    00800 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
    00801     switch (he->t) {
    00802     case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
    00803         s = he->p.argv[ix];
    00804         xtag = "string";
    00805         /* XXX Force utf8 strings. */
    00806         s = xstrdup(s);
    00807         s = xstrtolocale(s);
    00808         freeit = 1;
    00809         break;
    00810     case RPM_I18NSTRING_TYPE:   /* XXX currently never happens */
    00811     case RPM_STRING_TYPE:
    00812         s = he->p.str;
    00813         xtag = "string";
    00814         /* XXX Force utf8 strings. */
    00815         s = xstrdup(s);
    00816         s = xstrtolocale(s);
    00817         freeit = 1;
    00818         break;
    00819     case RPM_BIN_TYPE:
    00820 /*@-globs -mods@*/      /* Don't bother annotating beecrypt global mods */
    00821     {   int cpl = b64encode_chars_per_line;
    00822         b64encode_chars_per_line = 0;
    00823 /*@-formatconst@*/
    00824         s = base64Format(he, NULL);
    00825 /*@=formatconst@*/
    00826         b64encode_chars_per_line = cpl;
    00827         xtag = "base64";
    00828         freeit = 1;
    00829     }   break;
    00830 /*@=globs =mods@*/
    00831     case RPM_UINT8_TYPE:
    00832         anint = (rpmuint64_t)he->p.ui8p[ix];
    00833         break;
    00834     case RPM_UINT16_TYPE:
    00835         anint = (rpmuint64_t)he->p.ui16p[ix];
    00836         break;
    00837     case RPM_UINT32_TYPE:
    00838         anint = (rpmuint64_t)he->p.ui32p[ix];
    00839         break;
    00840     case RPM_UINT64_TYPE:
    00841         anint = he->p.ui64p[ix];
    00842         break;
    00843     default:
    00844         return xstrdup(_("(invalid xml type)"));
    00845         /*@notreached@*/ break;
    00846     }
    00847
    00848     if (s == NULL) {
    00849         int tlen = 64;
    00850         t = memset(alloca(tlen+1), 0, tlen+1);
    00851 /*@-duplicatequals@*/
    00852         if (anint != 0)
    00853             xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
    00854 /*@=duplicatequals@*/
    00855         s = t;
    00856         xtag = "integer";
    00857     }
    00858
    00859     nb = xmlstrlen(s);
    00860     if (nb == 0) {
    00861         nb += strlen(xtag) + sizeof("\t</>");
    00862         te = t = alloca(nb);
    00863         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
    00864     } else {
    00865         nb += 2 * strlen(xtag) + sizeof("\t<></>");
    00866         te = t = alloca(nb);
    00867         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
    00868         te = xmlstrcpy(te, s);
    00869         te += strlen(te);
    00870         te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
    00871     }
    00872
    00873     if (freeit)
    00874         s = _free(s);
    00875
    00876     val = xstrdup(t);
    00877
    00878     return val;
    00879 }
    00880
    00887 static size_t yamlstrlen(const char * s, int lvl)
    00888         /*@*/
    00889 {
    00890     size_t len = 0;
    00891     int indent = (lvl > 0);
    00892     int c;
    00893
    00894     while ((c = (int) *s++) != (int) '\0')
    00895     {
    00896         if (indent) {
    00897             len += 2 * lvl;
    00898             indent = 0;
    00899         }
    00900         if (c == (int) '\n')
    00901             indent = (lvl > 0);
    00902         len++;
    00903     }
    00904     return len;
    00905 }
    00906
    00914 static char * yamlstrcpy(/*@out@*/ /*@returned@*/ char * t, const char * s, int lvl)
    00915         /*@modifies t @*/
    00916 {
    00917     char * te = t;
    00918     int indent = (lvl > 0);
    00919     int c;
    00920
    00921     while ((c = (int) *s++) != (int) '\0') {
    00922         if (indent) {
    00923             int i;
    00924             for (i = 0; i < lvl; i++) {
    00925                 *te++ = ' ';
    00926                 *te++ = ' ';
    00927             }
    00928             indent = 0;
    00929         }
    00930         if (c == (int) '\n')
    00931             indent = (lvl > 0);
    00932         *te++ = (char) c;
    00933     }
    00934     *te = '\0';
    00935     return t;
    00936 }
    00937
    00944 static /*@only@*/ char * yamlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    00945         /*@*/
    00946 {
    00947     int element = he->ix;
    00948     int ix = (he->ix > 0 ? he->ix : 0);
    00949     const char * xtag = NULL;
    00950     int freetag = 0;
    00951     size_t nb;
    00952     char * val;
    00953     const char * s = NULL;
    00954     char * t, * te;
    00955     rpmuint64_t anint = 0;
    00956     int freeit = 0;
    00957     int lvl = 0;
    00958     int xx;
    00959     int ls;
    00960     int c;
    00961
    00962 assert(ix == 0);
    00963 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
    00964     xx = 0;
    00965     ls = 0;
    00966     switch (he->t) {
    00967     case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
    00968     case RPM_I18NSTRING_TYPE:   /* XXX currently never happens */
    00969     case RPM_STRING_TYPE:
    00970         s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str);
    00971         if (strchr("[", s[0]))  /* leading [ */
    00972             xx = 1;
    00973         if (xx == 0)
    00974         while ((c = (int) *s++) != (int) '\0') {
    00975             switch (c) {
    00976             default:
    00977                 continue;
    00978             case '\n':  /* multiline */
    00979                 xx = 1;
    00980                 if (s[0] == ' ' || s[0] == '\t') /* leading space */
    00981                     ls = 1;
    00982                 continue;
    00983             case '-':   /* leading "- \"" */
    00984             case ':':   /* embedded ": " or ":" at EOL */
    00985                 if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
    00986                     continue;
    00987                 xx = 1;
    00988                 /*@switchbreak@*/ break;
    00989             }
    00990             /*@loopbreak@*/ break;
    00991         }
    00992         if (xx) {
    00993             if (ls) { /* leading spaces means we need to specify the indent */
    00994                 xtag = xmalloc(strlen("- |##-\n") + 1);
    00995                 freetag = 1;
    00996                 if (element >= 0) {
    00997                     lvl = 3;
    00998                     sprintf((char *)xtag, "- |%d-\n", lvl);
    00999                 } else {
    01000                     lvl = 2;
    01001                     if (he->ix < 0) lvl++;  /* XXX extra indent for array[1] */
    01002                     sprintf((char *)xtag, "|%d-\n", lvl);
    01003                 }
    01004             } else {
    01005                 if (element >= 0) {
    01006                     xtag = "- |-\n";
    01007                     lvl = 3;
    01008                 } else {
    01009                     xtag = "|-\n";
    01010                     lvl = 2;
    01011                     if (he->ix < 0) lvl++;  /* XXX extra indent for array[1] */
    01012                 }
    01013             }
    01014         } else {
    01015             xtag = (element >= 0 ? "- " : NULL);
    01016         }
    01017
    01018         /* XXX Force utf8 strings. */
    01019         s = xstrdup(he->p.str);
    01020         s = xstrtolocale(s);
    01021         freeit = 1;
    01022         break;
    01023     case RPM_BIN_TYPE:
    01024 /*@-globs -mods@*/      /* Don't bother annotating beecrypt global mods */
    01025     {   int cpl = b64encode_chars_per_line;
    01026         b64encode_chars_per_line = 0;
    01027 /*@-formatconst@*/
    01028         s = base64Format(he, NULL);
    01029         element = -element;     /* XXX skip "    " indent. */
    01030 /*@=formatconst@*/
    01031         b64encode_chars_per_line = cpl;
    01032         xtag = "!!binary ";
    01033         freeit = 1;
    01034     }   break;
    01035 /*@=globs =mods@*/
    01036     case RPM_UINT8_TYPE:
    01037         anint = (rpmuint64_t)he->p.ui8p[ix];
    01038         break;
    01039     case RPM_UINT16_TYPE:
    01040         anint = (rpmuint64_t)he->p.ui16p[ix];
    01041         break;
    01042     case RPM_UINT32_TYPE:
    01043         anint = (rpmuint64_t)he->p.ui32p[ix];
    01044         break;
    01045     case RPM_UINT64_TYPE:
    01046         anint = he->p.ui64p[ix];
    01047         break;
    01048     default:
    01049         return xstrdup(_("(invalid yaml type)"));
    01050         /*@notreached@*/ break;
    01051     }
    01052
    01053     if (s == NULL) {
    01054         int tlen = 64;
    01055         t = memset(alloca(tlen+1), 0, tlen+1);
    01056 /*@-duplicatequals@*/
    01057         xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
    01058 /*@=duplicatequals@*/
    01059         s = t;
    01060         xtag = (element >= 0 ? "- " : NULL);
    01061     }
    01062
    01063     nb = yamlstrlen(s, lvl);
    01064     if (nb == 0) {
    01065         if (element >= 0)
    01066             nb += sizeof("    ") - 1;
    01067         nb += sizeof("- ~") - 1;
    01068         nb++;
    01069         te = t = alloca(nb);
    01070         if (element >= 0)
    01071             te = stpcpy(te, "    ");
    01072         te = stpcpy(te, "- ~");
    01073     } else {
    01074         if (element >= 0)
    01075             nb += sizeof("    ") - 1;
    01076         if (xtag)
    01077             nb += strlen(xtag);
    01078         nb++;
    01079         te = t = alloca(nb);
    01080         if (element >= 0)
    01081             te = stpcpy(te, "    ");
    01082         if (xtag)
    01083             te = stpcpy(te, xtag);
    01084 /*@-modobserver -observertrans -statictrans @*/ /* XXX LCL: can't see freetag flow */
    01085             if (freetag)
    01086                 xtag = _free(xtag);
    01087 /*@=modobserver =observertrans =statictrans @*/
    01088         te = yamlstrcpy(te, s, lvl);
    01089         te += strlen(te);
    01090     }
    01091
    01092     /* XXX s was malloc'd */
    01093     if (freeit)
    01094         s = _free(s);
    01095
    01096     val = xstrdup(t);
    01097
    01098     return val;
    01099 }
    01100
    01107 static /*@only@*/ char * pgpsigFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    01108         /*@globals fileSystem, internalState @*/
    01109         /*@modifies fileSystem, internalState @*/
    01110 {
    01111     int ix = (he->ix > 0 ? he->ix : 0);
    01112     char * val, * t;
    01113
    01114 assert(ix == 0);
    01115     if (!(he->t == RPM_BIN_TYPE)) {
    01116         val = xstrdup(_("(not a blob)"));
    01117     } else {
    01118         rpmuint8_t * pkt = he->p.ui8p;
    01119         unsigned int pktlen = 0;
    01120         unsigned int v = (unsigned int) *pkt;
    01121         pgpTag tag = 0;
    01122         unsigned int plen;
    01123         unsigned int hlen = 0;
    01124
    01125         if (v & 0x80) {
    01126             if (v & 0x40) {
    01127                 tag = (v & 0x3f);
    01128                 plen = pgpLen(pkt+1, &hlen);
    01129             } else {
    01130                 tag = (v >> 2) & 0xf;
    01131                 plen = (1 << (v & 0x3));
    01132                 hlen = pgpGrab(pkt+1, plen);
    01133             }
    01134
    01135             pktlen = 1 + plen + hlen;
    01136         }
    01137
    01138         if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
    01139             val = xstrdup(_("(not an OpenPGP signature)"));
    01140         } else {
    01141             pgpDig dig = pgpDigNew(0);
    01142             pgpDigParams sigp = pgpGetSignature(dig);
    01143             size_t nb = 0;
    01144             const char *tempstr;
    01145
    01146             (void) pgpPrtPkts(pkt, pktlen, dig, 0);
    01147
    01148             val = NULL;
    01149         again:
    01150             nb += 100;
    01151             val = t = xrealloc(val, nb + 1);
    01152
    01153             switch (sigp->pubkey_algo) {
    01154             case PGPPUBKEYALGO_DSA:
    01155                 t = stpcpy(t, "DSA");
    01156                 break;
    01157             case PGPPUBKEYALGO_RSA:
    01158                 t = stpcpy(t, "RSA");
    01159                 break;
    01160             default:
    01161                 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->pubkey_algo);
    01162                 t += strlen(t);
    01163                 break;
    01164             }
    01165             if (t + 5 >= val + nb)
    01166                 goto again;
    01167             *t++ = '/';
    01168             switch (sigp->hash_algo) {
    01169             case PGPHASHALGO_MD5:
    01170                 t = stpcpy(t, "MD5");
    01171                 break;
    01172             case PGPHASHALGO_SHA1:
    01173                 t = stpcpy(t, "SHA1");
    01174                 break;
    01175             default:
    01176                 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->hash_algo);
    01177                 t += strlen(t);
    01178                 break;
    01179             }
    01180             if (t + strlen (", ") + 1 >= val + nb)
    01181                 goto again;
    01182
    01183             t = stpcpy(t, ", ");
    01184
    01185             /* this is important if sizeof(rpmuint32_t) ! sizeof(time_t) */
    01186             {   time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
    01187                 struct tm * tstruct = localtime(&dateint);
    01188                 if (tstruct)
    01189                     (void) strftime(t, (nb - (t - val)), "%c", tstruct);
    01190             }
    01191             t += strlen(t);
    01192             if (t + strlen (", Key ID ") + 1 >= val + nb)
    01193                 goto again;
    01194             t = stpcpy(t, ", Key ID ");
    01195             tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
    01196             if (t + strlen (tempstr) > val + nb)
    01197                 goto again;
    01198             t = stpcpy(t, tempstr);
    01199
    01200             dig = pgpDigFree(dig, "pgpsigFormat");
    01201         }
    01202     }
    01203
    01204     return val;
    01205 }
    01206
    01213 static /*@only@*/
    01214 char * depflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    01215         /*@*/
    01216 {
    01217     int ix = (he->ix > 0 ? he->ix : 0);
    01218     char * val;
    01219
    01220 assert(ix == 0);
    01221     if (he->t != RPM_UINT64_TYPE) {
    01222         val = xstrdup(_("(invalid type)"));
    01223     } else {
    01224         rpmuint64_t anint = he->p.ui64p[ix];
    01225         char *t, *buf;
    01226
    01227         t = buf = alloca(32);
    01228         *t = '\0';
    01229
    01230 #ifdef  NOTYET  /* XXX appending markers breaks :depflags format. */
    01231         if (anint & RPMSENSE_SCRIPT_PRE)
    01232             t = stpcpy(t, "(pre)");
    01233         else if (anint & RPMSENSE_SCRIPT_POST)
    01234             t = stpcpy(t, "(post)");
    01235         else if (anint & RPMSENSE_SCRIPT_PREUN)
    01236             t = stpcpy(t, "(preun)");
    01237         else if (anint & RPMSENSE_SCRIPT_POSTUN)
    01238             t = stpcpy(t, "(postun)");
    01239 #endif
    01240         if (anint & RPMSENSE_SENSEMASK)
    01241             *t++ = ' ';
    01242         if (anint & RPMSENSE_LESS)
    01243             *t++ = '<';
    01244         if (anint & RPMSENSE_GREATER)
    01245             *t++ = '>';
    01246         if (anint & RPMSENSE_EQUAL)
    01247             *t++ = '=';
    01248         if (anint & RPMSENSE_SENSEMASK)
    01249             *t++ = ' ';
    01250         *t = '\0';
    01251
    01252         val = xstrdup(buf);
    01253     }
    01254
    01255     return val;
    01256 }
    01257
    01265 static /*@only@*/
    01266 char * deptypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
    01267         /*@*/
    01268 {
    01269     int ix = (he->ix > 0 ? he->ix : 0);
    01270     char * val;
    01271
    01272 assert(ix == 0);
    01273     if (he->t != RPM_UINT64_TYPE) {
    01274         val = xstrdup(_("(invalid type)"));
    01275     } else {
    01276         rpmuint64_t anint = he->p.ui64p[ix];
    01277         char *t, *buf;
    01278
    01279         t = buf = alloca(32);
    01280         *t = '\0';
    01281
    01282         if (anint & RPMSENSE_SCRIPT_PRE)
    01283             t = stpcpy(t, "pre");
    01284         else if (anint & RPMSENSE_SCRIPT_POST)
    01285             t = stpcpy(t, "post");
    01286         else if (anint & RPMSENSE_SCRIPT_PREUN)
    01287             t = stpcpy(t, "preun");
    01288         else if (anint & RPMSENSE_SCRIPT_POSTUN)
    01289             t = stpcpy(t, "postun");
    01290         else if (anint & RPMSENSE_SCRIPT_VERIFY)
    01291             t = stpcpy(t, "verify");
    01292         else if (anint & RPMSENSE_RPMLIB)
    01293             t = stpcpy(t, "rpmlib");
    01294         else if (anint & RPMSENSE_INTERP)
    01295             t = stpcpy(t, "interp");
    01296         else if (anint & (RPMSENSE_FIND_PROVIDES | RPMSENSE_FIND_REQUIRES))
    01297             t = stpcpy(t, "auto");
    01298         else
    01299             t = stpcpy(t, "manual");
    01300         *t = '\0';
    01301
    01302         val = xstrdup(buf);
    01303     }
    01304
    01305     return val;
    01306 }
    01307
    01314 static int instprefixTag(Header h, HE_t he)
    01315         /*@globals internalState @*/
    01316         /*@modifies he, internalState @*/
    01317 {
    01318     he->tag = RPMTAG_INSTALLPREFIX;
    01319     if (headerGet(h, he, 0))
    01320         return 0;
    01321
    01322     he->tag = RPMTAG_INSTPREFIXES;
    01323     if (headerGet(h, he, 0)) {
    01324         rpmTagData array = { .argv = he->p.argv };
    01325         he->t = RPM_STRING_TYPE;
    01326         he->c = 1;
    01327         he->p.str = xstrdup(array.argv[0]);
    01328         he->freeData = 1;
    01329         array.ptr = _free(array.ptr);
    01330         return 0;
    01331     }
    01332     return 1;
    01333 }
    01334
    01342 static int tv2uuidv1(/*@unused@*/ Header h, HE_t he, struct timeval *tv)
    01343         /*@modifies he @*/
    01344 {
    01345     rpmuint64_t uuid_time = ((rpmuint64_t)tv->tv_sec * 10000000) +
    01346                         (tv->tv_usec * 10) + 0x01B21DD213814000ULL;
    01347
    01348     he->t = RPM_BIN_TYPE;
    01349     he->c = 128/8;
    01350     he->p.ptr = xcalloc(1, he->c);
    01351     he->freeData = 1;
    01352     if (rpmuuidMake(1, NULL, NULL, NULL, (unsigned char *)he->p.ui8p)) {
    01353         he->p.ptr = _free(he->p.ptr);
    01354         he->freeData = 0;
    01355         return 1;
    01356     }
    01357
    01358     he->p.ui8p[6] &= 0xf0;      /* preserve version, clear time_hi nibble */
    01359     he->p.ui8p[8] &= 0x3f;      /* preserve reserved, clear clock */
    01360     he->p.ui8p[9] &= 0x00;
    01361
    01362     he->p.ui8p[3] = (rpmuint8_t)(uuid_time >>  0);
    01363     he->p.ui8p[2] = (rpmuint8_t)(uuid_time >>  8);
    01364     he->p.ui8p[1] = (rpmuint8_t)(uuid_time >> 16);
    01365     he->p.ui8p[0] = (rpmuint8_t)(uuid_time >> 24);
    01366     he->p.ui8p[5] = (rpmuint8_t)(uuid_time >> 32);
    01367     he->p.ui8p[4] = (rpmuint8_t)(uuid_time >> 40);
    01368     he->p.ui8p[6] |= (rpmuint8_t)(uuid_time >> 56) & 0x0f;
    01369
    01370 #ifdef  NOTYET
    01371     /* XXX Jigger up a non-zero (but constant) clock value. Is this needed? */
    01372     he->p.ui8p[8] |= (he->p.ui8p[2] & 0x3f);
    01373     he->p.ui8p[9] |= he->p.ui8p[3]
    01374 #endif
    01375
    01376     return 0;
    01377 }
    01378
    01385 static int tag2uuidv1(Header h, HE_t he)
    01386         /*@globals internalState @*/
    01387         /*@modifies he, internalState @*/
    01388 {
    01389     struct timeval tv;
    01390
    01391     if (!headerGet(h, he, 0))
    01392         return 1;
    01393     tv.tv_sec = (long) he->p.ui32p[0];
    01394     tv.tv_usec = (long) (he->c > 1 ? he->p.ui32p[1] : 0);
    01395     he->p.ptr = _free(he->p.ptr);
    01396     return tv2uuidv1(h, he, &tv);
    01397 }
    01398
    01405 static int installtime_uuidTag(Header h, HE_t he)
    01406         /*@globals internalState @*/
    01407         /*@modifies he, internalState @*/
    01408 {
    01409     he->tag = RPMTAG_INSTALLTIME;
    01410     return tag2uuidv1(h, he);
    01411 }
    01412
    01419 static int buildtime_uuidTag(Header h, HE_t he)
    01420         /*@globals internalState @*/
    01421         /*@modifies he, internalState @*/
    01422 {
    01423     he->tag = RPMTAG_BUILDTIME;
    01424     return tag2uuidv1(h, he);
    01425 }
    01426
    01433 static int origintime_uuidTag(Header h, HE_t he)
    01434         /*@globals internalState @*/
    01435         /*@modifies he, internalState @*/
    01436 {
    01437     he->tag = RPMTAG_ORIGINTIME;
    01438     return tag2uuidv1(h, he);
    01439 }
    01440
    01447 static int installtid_uuidTag(Header h, HE_t he)
    01448         /*@globals internalState @*/
    01449         /*@modifies he, internalState @*/
    01450 {
    01451     he->tag = RPMTAG_INSTALLTID;
    01452     return tag2uuidv1(h, he);
    01453 }
    01454
    01461 static int removetid_uuidTag(Header h, HE_t he)
    01462         /*@globals internalState @*/
    01463         /*@modifies he, internalState @*/
    01464 {
    01465     he->tag = RPMTAG_REMOVETID;
    01466     return tag2uuidv1(h, he);
    01467 }
    01468
    01475 static int origintid_uuidTag(Header h, HE_t he)
    01476         /*@globals internalState @*/
    01477         /*@modifies he, internalState @*/
    01478 {
    01479     he->tag = RPMTAG_ORIGINTID;
    01480     return tag2uuidv1(h, he);
    01481 }
    01482
    01483 /*@unchecked@*/ /*@observer@*/
    01484 static const char uuid_ns[] = "ns:URL";
    01485 /*@unchecked@*/ /*@observer@*/
    01486 static const char uuid_auth[] = "%{?_uuid_auth}%{!?_uuid_auth:http://rpm5.org}";
    01487 /*@unchecked@*/ /*@observer@*/
    01488 static const char uuid_path[] = "%{?_uuid_path}%{!?_uuid_path:/package}";
    01489 /*@unchecked@*/
    01490 static rpmuint32_t uuid_version = 5;
    01491
    01500 static int str2uuid(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
    01501                 rpmuint32_t version, char * val)
    01502         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01503         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01504 {
    01505     const char * ns = NULL;
    01506     const char * tagn = tagName(he->tag);
    01507     const char * s = NULL;
    01508     int rc;
    01509
    01510     /* XXX Substitute Pkgid & Hdrid strings for aliases. */
    01511     if (!strcmp("Sigmd5", tagn))
    01512         tagn = "Pkgid";
    01513     else if (!strcmp("Sha1header", tagn))
    01514         tagn = "Hdrid";
    01515
    01516     switch (version) {
    01517     default:
    01518         version = uuid_version;
    01519         /*@fallthrough@*/
    01520     case 3:
    01521     case 5:
    01522 assert(he->t == RPM_STRING_TYPE);
    01523         ns = uuid_ns;
    01524         s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/",
    01525                         he->p.str, NULL);
    01526         /*@fallthrough@*/
    01527     case 4:
    01528         break;
    01529     }
    01530     he->p.ptr = _free(he->p.ptr);
    01531     he->t = RPM_BIN_TYPE;
    01532     he->c = 128/8;
    01533     he->p.ptr = xcalloc(1, he->c);
    01534     he->freeData = 1;
    01535     rc = rpmuuidMake((int)version, ns, s, val, (unsigned char *)he->p.ui8p);
    01536     if (rc) {
    01537         he->p.ptr = _free(he->p.ptr);
    01538         he->freeData = 0;
    01539     }
    01540     s = _free(s);
    01541     return rc;
    01542 }
    01543
    01550 static int tag2uuidv5(Header h, HE_t he)
    01551         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01552         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01553 {
    01554     if (!headerGet(h, he, 0))
    01555         return 1;
    01556     switch (he->t) {
    01557     default:
    01558 assert(0);
    01559         /*@notreached@*/ break;
    01560     case RPM_BIN_TYPE:  {       /* Convert RPMTAG_PKGID from binary => hex. */
    01561         static const char hex[] = "0123456789abcdef";
    01562         char * t;
    01563         char * te;
    01564         rpmuint32_t i;
    01565
    01566         t = te = xmalloc (2*he->c + 1);
    01567         for (i = 0; i < he->c; i++) {
    01568             *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ];
    01569             *te++ = hex[ (int)((he->p.ui8p[i]     ) & 0x0f) ];
    01570         }
    01571         *te = '\0';
    01572         he->p.ptr = _free(he->p.ptr);
    01573         he->t = RPM_STRING_TYPE;
    01574         he->p.ptr = t;
    01575         he->c = 1;
    01576         he->freeData = 1;
    01577     }   break;
    01578     case RPM_STRING_TYPE:
    01579         break;
    01580     }
    01581     return str2uuid(he, NULL, 0, NULL);
    01582 }
    01583
    01590 static int pkguuidTag(Header h, HE_t he)
    01591         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01592         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01593 {
    01594     he->tag = RPMTAG_PKGID;
    01595     return tag2uuidv5(h, he);
    01596 }
    01597
    01604 static int sourcepkguuidTag(Header h, HE_t he)
    01605         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01606         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01607 {
    01608     he->tag = RPMTAG_SOURCEPKGID;
    01609     return tag2uuidv5(h, he);
    01610 }
    01611
    01618 static int hdruuidTag(Header h, HE_t he)
    01619         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01620         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01621 {
    01622     he->tag = RPMTAG_HDRID;
    01623     return tag2uuidv5(h, he);
    01624 }
    01625
    01632 static int triggercondsTag(Header h, HE_t he)
    01633         /*@globals internalState @*/
    01634         /*@modifies he, internalState @*/
    01635 {
    01636     HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
    01637     HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
    01638     HE_t Ihe = memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
    01639     HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
    01640     HE_t Vhe = memset(alloca(sizeof(*Vhe)), 0, sizeof(*Vhe));
    01641     HE_t She = memset(alloca(sizeof(*She)), 0, sizeof(*She));
    01642     rpmuint64_t anint;
    01643     unsigned i, j;
    01644     int rc = 1;         /* assume failure */
    01645     int xx;
    01646
    01647     he->freeData = 0;
    01648
    01649     Nhe->tag = RPMTAG_TRIGGERNAME;
    01650     xx = headerGet(h, Nhe, 0);
    01651     if (!xx) {          /* no triggers, succeed anyways */
    01652         rc = 0;
    01653         goto exit;
    01654     }
    01655
    01656     Ihe->tag = RPMTAG_TRIGGERINDEX;
    01657     xx = headerGet(h, Ihe, 0);
    01658     if (!xx) goto exit;
    01659
    01660     Fhe->tag = RPMTAG_TRIGGERFLAGS;
    01661     xx = headerGet(h, Fhe, 0);
    01662     if (!xx) goto exit;
    01663
    01664     Vhe->tag = RPMTAG_TRIGGERVERSION;
    01665     xx = headerGet(h, Vhe, 0);
    01666     if (!xx) goto exit;
    01667
    01668     She->tag = RPMTAG_TRIGGERSCRIPTS;
    01669     xx = headerGet(h, She, 0);
    01670     if (!xx) goto exit;
    01671
    01672     _he->tag = he->tag;
    01673     _he->t = RPM_UINT64_TYPE;
    01674     _he->p.ui64p = &anint;
    01675     _he->c = 1;
    01676     _he->freeData = 0;
    01677
    01678     he->t = RPM_STRING_ARRAY_TYPE;
    01679     he->c = She->c;
    01680
    01681     he->freeData = 1;
    01682     he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
    01683     for (i = 0; i < (unsigned) he->c; i++) {
    01684         char * item, * flagsStr;
    01685         char * chptr;
    01686
    01687         chptr = xstrdup("");
    01688
    01689         for (j = 0; j < Nhe->c; j++) {
    01690             if (Ihe->p.ui32p[j] != i)
    01691                 /*@innercontinue@*/ continue;
    01692
    01693             item = xmalloc(strlen(Nhe->p.argv[j]) + strlen(Vhe->p.argv[j]) + 20);
    01694 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    01695             if (Fhe->p.ui32p[j] & RPMSENSE_SENSEMASK) {
    01696                 anint = Fhe->p.ui32p[j];
    01697                 flagsStr = depflagsFormat(_he, NULL);
    01698                 sprintf(item, "%s%s%s", Nhe->p.argv[j], flagsStr, Vhe->p.argv[j]);
    01699                 flagsStr = _free(flagsStr);
    01700             } else
    01701                 strcpy(item, Nhe->p.argv[j]);
    01702 /*@=compmempass@*/
    01703
    01704             chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
    01705             if (*chptr != '\0') strcat(chptr, ", ");
    01706             strcat(chptr, item);
    01707             item = _free(item);
    01708         }
    01709
    01710         he->p.argv[i] = chptr;
    01711     }
    01712     rc = 0;
    01713
    01714 exit:
    01715     Ihe->p.ptr = _free(Ihe->p.ptr);
    01716     Fhe->p.ptr = _free(Fhe->p.ptr);
    01717     Nhe->p.ptr = _free(Nhe->p.ptr);
    01718     Vhe->p.ptr = _free(Vhe->p.ptr);
    01719     She->p.ptr = _free(She->p.ptr);
    01720
    01721     return rc;
    01722 }
    01723
    01730 static int triggertypeTag(Header h, HE_t he)
    01731         /*@globals internalState @*/
    01732         /*@modifies he, internalState @*/
    01733 {
    01734     HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
    01735     rpmTagData indices = { .ptr = NULL };
    01736     rpmTagData flags = { .ptr = NULL };
    01737     rpmTagData s = { .ptr = NULL };
    01738     rpmTagCount numNames;
    01739     rpmTagCount numScripts;
    01740     unsigned i, j;
    01741     int rc = 1;         /* assume failure */
    01742     int xx;
    01743
    01744     he->freeData = 0;
    01745
    01746 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    01747     _he->tag = RPMTAG_TRIGGERINDEX;
    01748     xx = headerGet(h, _he, 0);
    01749     if (!xx) goto exit;
    01750     indices.ui32p = _he->p.ui32p;
    01751     numNames = _he->c;
    01752
    01753     _he->tag = RPMTAG_TRIGGERFLAGS;
    01754     xx = headerGet(h, _he, 0);
    01755     if (!xx) goto exit;
    01756     flags.ui32p = _he->p.ui32p;
    01757
    01758     _he->tag = RPMTAG_TRIGGERSCRIPTS;
    01759     xx = headerGet(h, _he, 0);
    01760     if (!xx) goto exit;
    01761     s.argv = _he->p.argv;
    01762     numScripts = _he->c;
    01763 /*@=compmempass@*/
    01764
    01765     he->t = RPM_STRING_ARRAY_TYPE;
    01766     he->c = numScripts;
    01767
    01768     he->freeData = 1;
    01769     he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
    01770     for (i = 0; i < (unsigned) he->c; i++) {
    01771         for (j = 0; j < (unsigned) numNames; j++) {
    01772             if (indices.ui32p[j] != i)
    01773                 /*@innercontinue@*/ continue;
    01774
    01775             /* XXX FIXME: there's memory leaks here. */
    01776             if (flags.ui32p[j] & RPMSENSE_TRIGGERPREIN)
    01777                 he->p.argv[i] = xstrdup("prein");
    01778             else if (flags.ui32p[j] & RPMSENSE_TRIGGERIN)
    01779                 he->p.argv[i] = xstrdup("in");
    01780             else if (flags.ui32p[j] & RPMSENSE_TRIGGERUN)
    01781                 he->p.argv[i] = xstrdup("un");
    01782             else if (flags.ui32p[j] & RPMSENSE_TRIGGERPOSTUN)
    01783                 he->p.argv[i] = xstrdup("postun");
    01784             else
    01785                 he->p.argv[i] = xstrdup("");
    01786             /*@innerbreak@*/ break;
    01787         }
    01788     }
    01789     rc = 0;
    01790
    01791 exit:
    01792     indices.ptr = _free(indices.ptr);
    01793     flags.ptr = _free(flags.ptr);
    01794     s.ptr = _free(s.ptr);
    01795     return 0;
    01796 }
    01797
    01798 /* I18N look aside diversions */
    01799
    01800 #if defined(ENABLE_NLS)
    01801 /*@-exportlocal -exportheadervar@*/
    01802 /*@unchecked@*/
    01803 extern int _nl_msg_cat_cntr;    /* XXX GNU gettext voodoo */
    01804 /*@=exportlocal =exportheadervar@*/
    01805 #endif
    01806 /*@observer@*/ /*@unchecked@*/
    01807 static const char * language = "LANGUAGE";
    01808
    01809 /*@observer@*/ /*@unchecked@*/
    01810 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
    01811
    01818 static int i18nTag(Header h, HE_t he)
    01819         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01820         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01821 {
    01822     char * dstring = rpmExpand(_macro_i18ndomains, NULL);
    01823     int rc = 1;         /* assume failure */
    01824
    01825     he->t = RPM_STRING_TYPE;
    01826     he->p.str = NULL;
    01827     he->c = 0;
    01828     he->freeData = 0;
    01829
    01830     if (dstring && *dstring) {
    01831         char *domain, *de;
    01832         const char * langval;
    01833         const char * msgkey;
    01834         const char * msgid;
    01835
    01836         {   HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
    01837             const char * tn;
    01838             char * mk;
    01839             size_t nb = sizeof("()");
    01840             int xx;
    01841
    01842             nhe->tag = RPMTAG_NAME;
    01843             xx = headerGet(h, nhe, 0);
    01844             /*
    01845              * XXX Ick, tagName() is called by headerGet(), and the tagName()
    01846              * buffer is valid only until next tagName() call.
    01847              * For now, do the tagName() lookup after headerGet().
    01848              */
    01849             tn = tagName(he->tag);
    01850             if (tn)     nb += strlen(tn);
    01851             if (nhe->p.str)     nb += strlen(nhe->p.str);
    01852             mk = alloca(nb);
    01853             (void) snprintf(mk, nb, "%s(%s)",
    01854                         (nhe->p.str ? nhe->p.str : ""), (tn ? tn : ""));
    01855             mk[nb-1] = '\0';
    01856             nhe->p.ptr = _free(nhe->p.ptr);
    01857             msgkey = mk;
    01858         }
    01859
    01860         /* change to en_US for msgkey -> msgid resolution */
    01861         langval = getenv(language);
    01862         (void) setenv(language, "en_US", 1);
    01863 #if defined(ENABLE_NLS)
    01864 /*@i@*/ ++_nl_msg_cat_cntr;
    01865 #endif
    01866
    01867         msgid = NULL;
    01868         for (domain = dstring; domain != NULL; domain = de) {
    01869             de = strchr(domain, ':');
    01870             if (de) *de++ = '\0';
    01871 /*@-unrecog@*/
    01872             msgid = dgettext(domain, msgkey);
    01873 /*@=unrecog@*/
    01874             if (msgid != msgkey) break;
    01875         }
    01876
    01877         /* restore previous environment for msgid -> msgstr resolution */
    01878         if (langval)
    01879             (void) setenv(language, langval, 1);
    01880         else
    01881             unsetenv(language);
    01882 #if defined(ENABLE_NLS)
    01883 /*@i@*/ ++_nl_msg_cat_cntr;
    01884 #endif
    01885
    01886         if (domain && msgid) {
    01887 /*@-unrecog@*/
    01888             const char * s = dgettext(domain, msgid);
    01889 /*@=unrecog@*/
    01890             if (s) {
    01891                 rc = 0;
    01892                 he->p.str = xstrdup(s);
    01893                 he->c = 1;
    01894                 he->freeData = 1;
    01895             }
    01896         }
    01897     }
    01898
    01899 /*@-dependenttrans@*/
    01900     dstring = _free(dstring);
    01901 /*@=dependenttrans@*/
    01902     if (!rc)
    01903         return rc;
    01904
    01905     rc = headerGet(h, he, HEADERGET_NOEXTENSION);
    01906     if (rc) {
    01907         rc = 0;
    01908         he->p.str = xstrtolocale(he->p.str);
    01909         he->freeData = 1;
    01910         return rc;
    01911     }
    01912
    01913     he->t = RPM_STRING_TYPE;
    01914     he->p.str = NULL;
    01915     he->c = 0;
    01916     he->freeData = 0;
    01917
    01918     return 1;
    01919 }
    01920
    01924 static int localeTag(Header h, HE_t he)
    01925         /*@globals internalState @*/
    01926         /*@modifies he, internalState @*/
    01927 {
    01928     int rc;
    01929
    01930     rc = headerGet(h, he, HEADERGET_NOEXTENSION);
    01931     if (!rc || he->p.str == NULL || he->c == 0) {
    01932         he->t = RPM_STRING_TYPE;
    01933         he->freeData = 0;
    01934         return 1;
    01935     }
    01936
    01937     switch (he->t) {
    01938     default:
    01939         he->freeData = 0;
    01940         break;
    01941     case RPM_STRING_TYPE:
    01942         he->p.str = xstrtolocale(he->p.str);
    01943         he->freeData = 1;
    01944         break;
    01945     case RPM_STRING_ARRAY_TYPE:
    01946     {   const char ** argv;
    01947         char * te;
    01948         size_t l = 0;
    01949         unsigned i;
    01950         for (i = 0; i < (unsigned) he->c; i++) {
    01951             he->p.argv[i] = xstrdup(he->p.argv[i]);
    01952             he->p.argv[i] = xstrtolocale(he->p.argv[i]);
    01953 assert(he->p.argv[i] != NULL);
    01954             l += strlen(he->p.argv[i]) + 1;
    01955         }
    01956         argv = xmalloc(he->c * sizeof(*argv) + l);
    01957         te = (char *)&argv[he->c];
    01958         for (i = 0; i < (unsigned) he->c; i++) {
    01959             argv[i] = te;
    01960             te = stpcpy(te, he->p.argv[i]);
    01961             te++;
    01962             he->p.argv[i] = _free(he->p.argv[i]);
    01963         }
    01964         he->p.ptr = _free(he->p.ptr);
    01965         he->p.argv = argv;
    01966         he->freeData = 1;
    01967     }   break;
    01968     }
    01969
    01970     return 0;
    01971 }
    01972
    01979 static int summaryTag(Header h, HE_t he)
    01980         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01981         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01982 {
    01983     he->tag = RPMTAG_SUMMARY;
    01984     return i18nTag(h, he);
    01985 }
    01986
    01993 static int descriptionTag(Header h, HE_t he)
    01994         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    01995         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    01996 {
    01997     he->tag = RPMTAG_DESCRIPTION;
    01998     return i18nTag(h, he);
    01999 }
    02000
    02001 static int changelognameTag(Header h, HE_t he)
    02002         /*@globals internalState @*/
    02003         /*@modifies he, internalState @*/
    02004 {
    02005     he->tag = RPMTAG_CHANGELOGNAME;
    02006     return localeTag(h, he);
    02007 }
    02008
    02009 static int changelogtextTag(Header h, HE_t he)
    02010         /*@globals internalState @*/
    02011         /*@modifies he, internalState @*/
    02012 {
    02013     he->tag = RPMTAG_CHANGELOGTEXT;
    02014     return localeTag(h, he);
    02015 }
    02016
    02023 static int groupTag(Header h, HE_t he)
    02024         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02025         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    02026 {
    02027     he->tag = RPMTAG_GROUP;
    02028     return i18nTag(h, he);
    02029 }
    02030
    02037 static int dbinstanceTag(Header h, HE_t he)
    02038         /*@modifies he @*/
    02039 {
    02040     he->tag = RPMTAG_DBINSTANCE;
    02041     he->t = RPM_UINT32_TYPE;
    02042     he->p.ui32p = xmalloc(sizeof(*he->p.ui32p));
    02043     he->p.ui32p[0] = headerGetInstance(h);
    02044     he->freeData = 1;
    02045     he->c = 1;
    02046     return 0;
    02047 }
    02048
    02055 static int headerstartoffTag(Header h, HE_t he)
    02056         /*@modifies he @*/
    02057 {
    02058     he->tag = RPMTAG_HEADERSTARTOFF;
    02059     he->t = RPM_UINT64_TYPE;
    02060     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
    02061     he->p.ui64p[0] = headerGetStartOff(h);
    02062     he->freeData = 1;
    02063     he->c = 1;
    02064     return 0;
    02065 }
    02066
    02073 static int headerendoffTag(Header h, HE_t he)
    02074         /*@modifies he @*/
    02075 {
    02076     he->tag = RPMTAG_HEADERENDOFF;
    02077     he->t = RPM_UINT64_TYPE;
    02078     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
    02079     he->p.ui64p[0] = headerGetEndOff(h);
    02080     he->freeData = 1;
    02081     he->c = 1;
    02082     return 0;
    02083 }
    02084
    02091 static int pkgoriginTag(Header h, HE_t he)
    02092         /*@globals internalState @*/
    02093         /*@modifies he, internalState @*/
    02094 {
    02095     const char * origin;
    02096     int rc = 1;
    02097
    02098     he->tag = RPMTAG_PACKAGEORIGIN;
    02099     if (!headerGet(h, he, HEADERGET_NOEXTENSION)
    02100      && (origin = headerGetOrigin(h)) != NULL)
    02101     {
    02102         he->t = RPM_STRING_TYPE;
    02103         he->p.str = xstrdup(origin);
    02104         he->c = 1;
    02105         he->freeData = 1;
    02106         rc = 0;
    02107     }
    02108     return rc;
    02109 }
    02110
    02117 static int pkgbaseurlTag(Header h, HE_t he)
    02118         /*@globals internalState @*/
    02119         /*@modifies he, internalState @*/
    02120 {
    02121     const char * baseurl;
    02122     int rc = 1;
    02123
    02124     he->tag = RPMTAG_PACKAGEBASEURL;
    02125     if (!headerGet(h, he, HEADERGET_NOEXTENSION)
    02126      && (baseurl = headerGetBaseURL(h)) != NULL)
    02127     {
    02128         he->t = RPM_STRING_TYPE;
    02129         he->p.str = xstrdup(baseurl);
    02130         he->c = 1;
    02131         he->freeData = 1;
    02132         rc = 0;
    02133     }
    02134     return rc;
    02135 }
    02136
    02143 static int pkgdigestTag(Header h, HE_t he)
    02144         /*@modifies he @*/
    02145 {
    02146     const char * digest;
    02147     int rc = 1;
    02148
    02149     he->tag = RPMTAG_PACKAGEDIGEST;
    02150     if ((digest = headerGetDigest(h)) != NULL)
    02151     {
    02152         he->t = RPM_STRING_TYPE;
    02153         he->p.str = xstrdup(digest);
    02154         he->c = 1;
    02155         he->freeData = 1;
    02156         rc = 0;
    02157     }
    02158     return rc;
    02159 }
    02160
    02167 static int pkgmtimeTag(Header h, HE_t he)
    02168         /*@modifies he @*/
    02169 {
    02170     struct stat * st = headerGetStatbuf(h);
    02171     he->tag = RPMTAG_PACKAGETIME;
    02172     he->t = RPM_UINT64_TYPE;
    02173     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
    02174 /*@-type@*/
    02175     he->p.ui64p[0] = (rpmuint64_t)st->st_mtime;
    02176 /*@=type@*/
    02177     he->freeData = 1;
    02178     he->c = 1;
    02179     return 0;
    02180 }
    02181
    02188 static int pkgsizeTag(Header h, HE_t he)
    02189         /*@modifies he @*/
    02190 {
    02191     struct stat * st = headerGetStatbuf(h);
    02192     he->tag = RPMTAG_PACKAGESIZE;
    02193     he->t = RPM_UINT64_TYPE;
    02194     he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
    02195     he->p.ui64p[0] = (rpmuint64_t)st->st_size;
    02196     he->freeData = 1;
    02197     he->c = 1;
    02198     return 0;
    02199 }
    02200
    02206 /*@only@*/
    02207 static char * hGetNVRA(Header h)
    02208         /*@globals internalState @*/
    02209         /*@modifies h, internalState @*/
    02210 {
    02211     const char * N = NULL;
    02212     const char * V = NULL;
    02213     const char * R = NULL;
    02214     const char * A = NULL;
    02215     size_t nb = 0;
    02216     char * NVRA, * t;
    02217
    02218     (void) headerNEVRA(h, &N, NULL, &V, &R, &A);
    02219     if (N)      nb += strlen(N);
    02220     if (V)      nb += strlen(V) + 1;
    02221     if (R)      nb += strlen(R) + 1;
    02222 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
    02223     /* do not expose the architecture as this is too less
    02224        information, as in OpenPKG the "platform" is described by the
    02225        architecture+operating-system combination. But as the whole
    02226        "platform" information is actually overkill, just revert to the
    02227        RPM 4 behaviour and do not expose any such information at all. */
    02228 #else
    02229     if (A)      nb += strlen(A) + 1;
    02230 #endif
    02231     nb++;
    02232     NVRA = t = xmalloc(nb);
    02233     *t = '\0';
    02234     if (N)      t = stpcpy(t, N);
    02235     if (V)      t = stpcpy( stpcpy(t, "-"), V);
    02236     if (R)      t = stpcpy( stpcpy(t, "-"), R);
    02237 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
    02238     /* do not expose the architecture as this is too less
    02239        information, as in OpenPKG the "platform" is described by the
    02240        architecture+operating-system combination. But as the whole
    02241        "platform" information is actually overkill, just revert to the
    02242        RPM 4 behaviour and do not expose any such information at all. */
    02243 #else
    02244     if (A)      t = stpcpy( stpcpy(t, "."), A);
    02245 #endif
    02246     N = _free(N);
    02247     V = _free(V);
    02248     R = _free(R);
    02249     A = _free(A);
    02250     return NVRA;
    02251 }
    02252
    02259 static int nvraTag(Header h, HE_t he)
    02260         /*@globals internalState @*/
    02261         /*@modifies h, he, internalState @*/
    02262 {
    02263     he->t = RPM_STRING_TYPE;
    02264     he->p.str = hGetNVRA(h);
    02265     he->c = 1;
    02266     he->freeData = 1;
    02267     return 0;
    02268 }
    02269
    02287 static void rpmfiBuildFNames(Header h, rpmTag tagN,
    02288                 /*@null@*/ /*@out@*/ const char *** fnp,
    02289                 /*@null@*/ /*@out@*/ rpmTagCount * fcp)
    02290         /*@globals internalState @*/
    02291         /*@modifies *fnp, *fcp, internalState @*/
    02292 {
    02293     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    02294     rpmTag dirNameTag = 0;
    02295     rpmTag dirIndexesTag = 0;
    02296     rpmTagData baseNames = { .ptr = NULL };
    02297     rpmTagData dirNames = { .ptr = NULL };
    02298     rpmTagData dirIndexes = { .ptr = NULL };
    02299     rpmTagData fileNames;
    02300     rpmTagCount count;
    02301     size_t size;
    02302     int isSource =
    02303         (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
    02304          headerIsEntry(h, RPMTAG_ARCH) != 0);
    02305     char * t;
    02306     unsigned i;
    02307     int xx;
    02308
    02309     if (tagN == RPMTAG_BASENAMES) {
    02310         dirNameTag = RPMTAG_DIRNAMES;
    02311         dirIndexesTag = RPMTAG_DIRINDEXES;
    02312     } else if (tagN == RPMTAG_ORIGBASENAMES) {
    02313         dirNameTag = RPMTAG_ORIGDIRNAMES;
    02314         dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
    02315     } else {
    02316         if (fnp) *fnp = NULL;
    02317         if (fcp) *fcp = 0;
    02318         return;         /* programmer error */
    02319     }
    02320
    02321 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    02322     he->tag = tagN;
    02323     xx = headerGet(h, he, 0);
    02324     /* XXX 3.0.x SRPM's can be used, relative fn's at RPMTAG_OLDFILENAMES. */
    02325     if (xx == 0 && isSource) {
    02326         he->tag = RPMTAG_OLDFILENAMES;
    02327         xx = headerGet(h, he, 0);
    02328         if (xx) {
    02329             dirNames.argv = xcalloc(3, sizeof(*dirNames.argv));
    02330             dirNames.argv[0] = (const char *)&dirNames.argv[2];
    02331             dirIndexes.ui32p  = xcalloc(he->c, sizeof(*dirIndexes.ui32p));
    02332         }
    02333     }
    02334     baseNames.argv = he->p.argv;
    02335     count = he->c;
    02336
    02337     if (!xx) {
    02338         if (fnp) *fnp = NULL;
    02339         if (fcp) *fcp = 0;
    02340         return;         /* no file list */
    02341     }
    02342
    02343     he->tag = dirNameTag;
    02344     if ((xx = headerGet(h, he, 0)) != 0)
    02345         dirNames.argv = he->p.argv;
    02346
    02347     he->tag = dirIndexesTag;
    02348     if ((xx = headerGet(h, he, 0)) != 0)
    02349         dirIndexes.ui32p = he->p.ui32p;
    02350 /*@=compmempass@*/
    02351
    02352     size = sizeof(*fileNames.argv) * count;
    02353     for (i = 0; i < (unsigned)count; i++) {
    02354         const char * dn = NULL;
    02355         (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
    02356         size += strlen(baseNames.argv[i]) + strlen(dn) + 1;
    02357     }
    02358
    02359     fileNames.argv = xmalloc(size);
    02360     t = (char *)&fileNames.argv[count];
    02361     for (i = 0; i < (unsigned)count; i++) {
    02362         const char * dn = NULL;
    02363         (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
    02364         fileNames.argv[i] = t;
    02365         t = stpcpy( stpcpy(t, dn), baseNames.argv[i]);
    02366         *t++ = '\0';
    02367     }
    02368     baseNames.ptr = _free(baseNames.ptr);
    02369     dirNames.ptr = _free(dirNames.ptr);
    02370     dirIndexes.ptr = _free(dirIndexes.ptr);
    02371
    02372 /*@-onlytrans@*/
    02373     if (fnp)
    02374         *fnp = fileNames.argv;
    02375     else
    02376         fileNames.ptr = _free(fileNames.ptr);
    02377 /*@=onlytrans@*/
    02378     if (fcp) *fcp = count;
    02379 }
    02380
    02388 static int _fnTag(Header h, HE_t he, rpmTag tag)
    02389         /*@globals internalState @*/
    02390         /*@modifies he, internalState @*/
    02391 {
    02392     he->t = RPM_STRING_ARRAY_TYPE;
    02393     rpmfiBuildFNames(h, tag, &he->p.argv, &he->c);
    02394     he->freeData = 1;
    02395     return 0;
    02396 }
    02397
    02398 static int filenamesTag(Header h, HE_t he)
    02399         /*@globals internalState @*/
    02400         /*@modifies he, internalState @*/
    02401 {
    02402     he->tag = tagValue("Filenames");
    02403     return _fnTag(h, he, RPMTAG_BASENAMES);
    02404 }
    02405
    02406 static int filepathsTag(Header h, HE_t he)
    02407         /*@globals internalState @*/
    02408         /*@modifies he, internalState @*/
    02409 {
    02410     he->tag = RPMTAG_FILEPATHS;
    02411     return _fnTag(h, he, RPMTAG_BASENAMES);
    02412 }
    02413
    02414 static int origpathsTag(Header h, HE_t he)
    02415         /*@globals internalState @*/
    02416         /*@modifies he, internalState @*/
    02417 {
    02418     he->tag = RPMTAG_ORIGPATHS;
    02419     return _fnTag(h, he, RPMTAG_ORIGBASENAMES);
    02420 }
    02421
    02431 static int debevrfmtTag(/*@unused@*/ Header h, HE_t he,
    02432                 HE_t Nhe, HE_t EVRhe, HE_t Fhe)
    02433         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02434         /*@modifies he, Nhe, rpmGlobalMacroContext, internalState @*/
    02435 {
    02436     char * t, * te;
    02437     size_t nb = 0;
    02438     int rc = 1;
    02439
    02440     he->t = RPM_STRING_ARRAY_TYPE;
    02441     he->c = 0;
    02442     he->freeData = 1;
    02443     for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
    02444         nb += sizeof(*he->p.argv);
    02445         nb += strlen(Nhe->p.argv[Nhe->ix]) + 1;
    02446         if (*EVRhe->p.argv[Nhe->ix] != '\0')
    02447             nb += strlen(EVRhe->p.argv[Nhe->ix]) + (sizeof(" (== )")-1);
    02448         he->c++;
    02449     }
    02450     nb += sizeof(*he->p.argv);
    02451
    02452     he->p.argv = xmalloc(nb);
    02453     te = (char *) &he->p.argv[he->c+1];
    02454
    02455     he->c = 0;
    02456     for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
    02457         he->p.argv[he->c++] = te;
    02458         if (*EVRhe->p.argv[Nhe->ix] != '\0') {
    02459             char opstr[4], * op = opstr;
    02460             if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_LESS)
    02461                 *op++ = '<';
    02462             if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_GREATER)
    02463                 *op++ = '>';
    02464             if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_EQUAL)
    02465                 *op++ = '=';
    02466             *op = '\0';
    02467             t = rpmExpand(Nhe->p.argv[Nhe->ix],
    02468                         " (", opstr, " ", EVRhe->p.argv[Nhe->ix], ")", NULL);
    02469         } else
    02470             t = rpmExpand(Nhe->p.argv[Nhe->ix], NULL);
    02471         te = stpcpy(te, t);
    02472         te++;
    02473         t = _free(t);
    02474     }
    02475     he->p.argv[he->c] = NULL;
    02476     rc = 0;
    02477
    02478     return rc;
    02479 }
    02480
    02490 static int debevrTag(Header h, HE_t he, rpmTag tagN, rpmTag tagEVR, rpmTag tagF)
    02491         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02492         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    02493 {
    02494     HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
    02495     HE_t EVRhe = memset(alloca(sizeof(*EVRhe)), 0, sizeof(*EVRhe));
    02496     HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
    02497     int rc = 1;
    02498     int xx;
    02499
    02500     Nhe->tag = tagN;
    02501     if (!(xx = headerGet(h, Nhe, 0)))
    02502         goto exit;
    02503     EVRhe->tag = tagEVR;
    02504     if (!(xx = headerGet(h, EVRhe, 0)))
    02505         goto exit;
    02506 assert(EVRhe->c == Nhe->c);
    02507     Fhe->tag = tagF;
    02508     if (!(xx = headerGet(h, Fhe, 0)))
    02509         goto exit;
    02510 assert(Fhe->c == Nhe->c);
    02511
    02512     rc = debevrfmtTag(h, he, Nhe, EVRhe, Fhe);
    02513
    02514 exit:
    02515     Nhe->p.ptr = _free(Nhe->p.ptr);
    02516     EVRhe->p.ptr = _free(EVRhe->p.ptr);
    02517     Fhe->p.ptr = _free(Fhe->p.ptr);
    02518     return rc;
    02519 }
    02520
    02527 static int debconflictsTag(Header h, HE_t he)
    02528         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02529         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    02530 {
    02531     he->tag = tagValue("Debconflicts");
    02532     return debevrTag(h, he,
    02533         RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
    02534 }
    02535
    02536 static int debdependsTag(Header h, HE_t he)
    02537         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02538         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    02539 {
    02540     he->tag = tagValue("Debdepends");
    02541     return debevrTag(h, he,
    02542         RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
    02543 }
    02544
    02545 static int debobsoletesTag(Header h, HE_t he)
    02546         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02547         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    02548 {
    02549     he->tag = tagValue("Debobsoletes");
    02550     return debevrTag(h, he,
    02551         RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
    02552 }
    02553
    02554 static int debprovidesTag(Header h, HE_t he)
    02555         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02556         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    02557 {
    02558     he->tag = tagValue("Debprovides");
    02559     return debevrTag(h, he,
    02560         RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
    02561 }
    02562
    02569 static int debmd5sumsTag(Header h, HE_t he)
    02570         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    02571         /*@modifies he, rpmGlobalMacroContext, internalState @*/
    02572 {
    02573     HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
    02574     HE_t Dhe = memset(alloca(sizeof(*Dhe)), 0, sizeof(*Dhe));
    02575     char * t, * te;
    02576     size_t nb = 0;
    02577     int rc = 1;
    02578     int xx;
    02579
    02580     Nhe->tag = RPMTAG_FILEPATHS;
    02581     if (!(xx = headerGet(h, Nhe, 0)))
    02582         goto exit;
    02583     Dhe->tag = RPMTAG_FILEDIGESTS;
    02584     if (!(xx = headerGet(h, Dhe, 0)))
    02585         goto exit;
    02586 assert(Dhe->c == Nhe->c);
    02587
    02588     he->tag = tagValue("Debmd5sums");
    02589     he->t = RPM_STRING_ARRAY_TYPE;
    02590     he->c = 0;
    02591     he->freeData = 1;
    02592     for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) {
    02593         if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix]))
    02594             continue;
    02595         nb += sizeof(*he->p.argv);
    02596         nb += strlen(Dhe->p.argv[Dhe->ix]) + sizeof("  ") + strlen(Nhe->p.argv[Dhe->ix]) - 1;
    02597         he->c++;
    02598     }
    02599     nb += sizeof(*he->p.argv);
    02600
    02601     he->p.argv = xmalloc(nb);
    02602     te = (char *) &he->p.argv[he->c+1];
    02603
    02604     he->c = 0;
    02605     for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) {
    02606         if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix]))
    02607             continue;
    02608         he->p.argv[he->c++] = te;
    02609         t = rpmExpand(Dhe->p.argv[Dhe->ix], "  ", Nhe->p.argv[Dhe->ix]+1, NULL);
    02610         te = stpcpy(te, t);
    02611         te++;
    02612         t = _free(t);
    02613     }
    02614     he->p.argv[he->c] = NULL;
    02615     rc = 0;
    02616
    02617 exit:
    02618     Nhe->p.ptr = _free(Nhe->p.ptr);
    02619     Dhe->p.ptr = _free(Dhe->p.ptr);
    02620     return rc;
    02621 }
    02622
    02623 static int filestatTag(Header h, HE_t he)
    02624         /*@globals internalState @*/
    02625         /*@modifies he, internalState @*/
    02626 {
    02627     rpmTagData paths = { .ptr = NULL };
    02628     /* _dev */
    02629     rpmTagData _ino = { .ptr = NULL };
    02630     rpmTagData _mode = { .ptr = NULL };
    02631     /* _nlink */
    02632     /* _uid */
    02633     /* _gid */
    02634     rpmTagData _rdev = { .ptr = NULL };
    02635     rpmTagData _size = { .ptr = NULL };
    02636     /* _blksize */
    02637     /* _blocks */
    02638     /* _atime */
    02639     rpmTagData _mtime = { .ptr = NULL };
    02640     /* st_ctime */
    02641     int rc;
    02642
    02643     he->tag = RPMTAG_FILEPATHS;
    02644     if ((rc = _fnTag(h, he, RPMTAG_BASENAMES)) != 0 || he->c == 0)
    02645         goto exit;
    02646
    02647 exit:
    02648     paths.ptr = _free(paths.ptr);
    02649     _ino.ptr = _free(_ino.ptr);
    02650     _mode.ptr = _free(_mode.ptr);
    02651     _rdev.ptr = _free(_rdev.ptr);
    02652     _size.ptr = _free(_size.ptr);
    02653     _mtime.ptr = _free(_mtime.ptr);
    02654     return rc;
    02655 }
    02656
    02657 static int wnlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
    02658                 HE_t PNhe, /*@null@*/ HE_t PEVRhe, /*@null@*/ HE_t PFhe)
    02659         /*@globals rpmGlobalMacroContext, h_errno,
    02660                 fileSystem, internalState @*/
    02661         /*@modifies *avp, *hitp, rpmGlobalMacroContext,
    02662                 fileSystem, internalState @*/
    02663 {
    02664     HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
    02665     HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
    02666     HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
    02667     HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
    02668     rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
    02669     const char * key = PNhe->p.argv[PNhe->ix];
    02670     size_t keylen = 0;
    02671     rpmmi mi;
    02672     rpmTag tagN = RPMTAG_REQUIRENAME;
    02673     rpmTag tagEVR = RPMTAG_REQUIREVERSION;
    02674     rpmTag tagF = RPMTAG_REQUIREFLAGS;
    02675     rpmuint32_t PFlags;
    02676     rpmuint32_t RFlags;
    02677     EVR_t Pevr;
    02678     Header oh;
    02679     int rc = 0;
    02680     int xx;
    02681
    02682     if (tagNVRA == 0)
    02683         tagNVRA = RPMTAG_NVRA;
    02684
    02685     PFlags = (PFhe != NULL ? (PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK) : 0);
    02686     Pevr = rpmEVRnew(PFlags, 1);
    02687
    02688     if (PEVRhe != NULL)
    02689         xx = rpmEVRparse(xstrdup(PEVRhe->p.argv[PNhe->ix]), Pevr);
    02690
    02691     RNhe->tag = tagN;
    02692     REVRhe->tag = tagEVR;
    02693     RFhe->tag = tagF;
    02694
    02695     mi = rpmmiInit(_rpmdb, tagN, key, keylen);
    02696     if (hitp && *hitp)
    02697         xx = rpmmiPrune(mi, (int *)argiData(*hitp), argiCount(*hitp), 0);
    02698     while ((oh = rpmmiNext(mi)) != NULL) {
    02699         if (!headerGet(oh, RNhe, 0))
    02700             goto bottom;
    02701         if (PEVRhe != NULL) {
    02702             if (!headerGet(oh, REVRhe, 0))
    02703                 goto bottom;
    02704 assert(REVRhe->c == RNhe->c);
    02705             if (!headerGet(oh, RFhe, 0))
    02706                 goto bottom;
    02707 assert(RFhe->c == RNhe->c);
    02708         }
    02709
    02710         for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
    02711             if (strcmp(PNhe->p.argv[PNhe->ix], RNhe->p.argv[RNhe->ix]))
    02712                 /*@innercontinue@*/ continue;
    02713             if (PEVRhe == NULL)
    02714                 goto bingo;
    02715             RFlags = RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK;
    02716             {   EVR_t Revr = rpmEVRnew(RFlags, 1);
    02717                 if (!(PFlags && RFlags))
    02718                     xx = 1;
    02719                 else {
    02720                     xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
    02721                     xx = rpmEVRoverlap(Pevr, Revr);
    02722                 }
    02723                 Revr = rpmEVRfree(Revr);
    02724             }
    02725             if (xx)
    02726                 goto bingo;
    02727         }
    02728         goto bottom;
    02729
    02730 bingo:
    02731         NVRAhe->tag = tagNVRA;
    02732         xx = headerGet(oh, NVRAhe, 0);
    02733         if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
    02734             xx = argvAdd(avp, NVRAhe->p.str);
    02735             xx = argvSort(*avp, NULL);
    02736             if (hitp != NULL)
    02737                 xx = argiAdd(hitp, -1, rpmmiInstance(mi));
    02738             rc++;
    02739         }
    02740
    02741 bottom:
    02742         RNhe->p.ptr = _free(RNhe->p.ptr);
    02743         REVRhe->p.ptr = _free(REVRhe->p.ptr);
    02744         RFhe->p.ptr = _free(RFhe->p.ptr);
    02745         NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
    02746     }
    02747     mi = rpmmiFree(mi);
    02748
    02749     Pevr = rpmEVRfree(Pevr);
    02750
    02751     return rc;
    02752 }
    02753
    02754 static int whatneedsTag(Header h, HE_t he)
    02755         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    02756         /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
    02757 {
    02758     HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
    02759     HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
    02760     HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
    02761     HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
    02762     HE_t FNhe = memset(alloca(sizeof(*FNhe)), 0, sizeof(*FNhe));
    02763     rpmTag tagNVRA = RPMTAG_NVRA;
    02764     ARGV_t pkgs = NULL;
    02765     ARGI_t hits = NULL;
    02766     int rc = 1;
    02767
    02768     PNhe->tag = RPMTAG_PROVIDENAME;
    02769     if (!headerGet(h, PNhe, 0))
    02770         goto exit;
    02771     PEVRhe->tag = RPMTAG_PROVIDEVERSION;
    02772     if (!headerGet(h, PEVRhe, 0))
    02773         goto exit;
    02774 assert(PEVRhe->c == PNhe->c);
    02775     PFhe->tag = RPMTAG_PROVIDEFLAGS;
    02776     if (!headerGet(h, PFhe, 0))
    02777         goto exit;
    02778 assert(PFhe->c == PNhe->c);
    02779
    02780     FNhe->tag = RPMTAG_FILEPATHS;
    02781     if (!headerGet(h, FNhe, 0))
    02782         goto exit;
    02783
    02784     NVRAhe->tag = tagNVRA;;
    02785     if (!headerGet(h, NVRAhe, 0))
    02786         goto exit;
    02787
    02788     (void) argvAdd(&pkgs, NVRAhe->p.str);
    02789
    02790     for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++)
    02791         (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, PNhe, PEVRhe, PFhe);
    02792     for (FNhe->ix = 0; FNhe->ix < (int)FNhe->c; FNhe->ix++)
    02793         (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, FNhe, NULL, NULL);
    02794
    02795     /* Convert package NVRA array to Header string array. */
    02796     {   size_t nb = 0;
    02797         char * te;
    02798         rpmuint32_t i;
    02799
    02800         he->t = RPM_STRING_ARRAY_TYPE;
    02801         he->c = argvCount(pkgs);
    02802         nb = 0;
    02803         for (i = 0; i < he->c; i++) {
    02804             nb += sizeof(*he->p.argv);
    02805             nb += strlen(pkgs[i]) + 1;
    02806         }
    02807         nb += sizeof(*he->p.argv);
    02808
    02809         he->p.argv = xmalloc(nb);
    02810         te = (char *) &he->p.argv[he->c+1];
    02811
    02812         for (i = 0; i < he->c; i++) {
    02813             he->p.argv[i] = te;
    02814             te = stpcpy(te, pkgs[i]);
    02815             te++;
    02816         }
    02817         he->p.argv[he->c] = NULL;
    02818     }
    02819
    02820     hits = argiFree(hits);
    02821     pkgs = argvFree(pkgs);
    02822     rc = 0;
    02823
    02824 exit:
    02825     NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
    02826     PNhe->p.ptr = _free(PNhe->p.ptr);
    02827     PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
    02828     PFhe->p.ptr = _free(PFhe->p.ptr);
    02829     FNhe->p.ptr = _free(FNhe->p.ptr);
    02830     return rc;
    02831 }
    02832
    02833 static int nwlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
    02834                 HE_t RNhe, /*@null@*/ HE_t REVRhe, /*@null@*/ HE_t RFhe)
    02835         /*@globals rpmGlobalMacroContext, h_errno,
    02836                 fileSystem, internalState @*/
    02837         /*@modifies *avp, *hitp, REVRhe, rpmGlobalMacroContext,
    02838                 fileSystem, internalState @*/
    02839 {
    02840     HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
    02841     HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
    02842     HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
    02843     HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
    02844     rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
    02845     const char * key = RNhe->p.argv[RNhe->ix];
    02846     size_t keylen = 0;
    02847     rpmmi mi;
    02848     rpmTag tagN = tagN = (*RNhe->p.argv[RNhe->ix] == '/')
    02849         ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME;
    02850     rpmTag tagEVR = RPMTAG_PROVIDEVERSION;
    02851     rpmTag tagF = RPMTAG_PROVIDEFLAGS;
    02852     rpmuint32_t PFlags;
    02853     rpmuint32_t RFlags;
    02854     EVR_t Revr;
    02855     Header oh;
    02856     int rc = 0;
    02857     int xx;
    02858
    02859     if (tagNVRA == 0)
    02860         tagNVRA = RPMTAG_NVRA;
    02861
    02862     RFlags = (RFhe != NULL ? (RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK) : 0);
    02863     Revr = rpmEVRnew(RFlags, 1);
    02864
    02865     if (REVRhe != NULL)
    02866         xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
    02867
    02868     PNhe->tag = tagN;
    02869     PEVRhe->tag = tagEVR;
    02870     PFhe->tag = tagF;
    02871
    02872     mi = rpmmiInit(_rpmdb, tagN, key, keylen);
    02873     if (hitp && *hitp)
    02874         xx = rpmmiPrune(mi, (int *)argiData(*hitp), argiCount(*hitp), 0);
    02875     while ((oh = rpmmiNext(mi)) != NULL) {
    02876         if (!headerGet(oh, PNhe, 0))
    02877             goto bottom;
    02878         if (REVRhe != NULL) {
    02879             if (!headerGet(oh, PEVRhe, 0))
    02880                 goto bottom;
    02881 assert(PEVRhe->c == PNhe->c);
    02882             if (!headerGet(oh, PFhe, 0))
    02883                 goto bottom;
    02884 assert(PFhe->c == PNhe->c);
    02885         }
    02886
    02887         for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) {
    02888             if (strcmp(RNhe->p.argv[RNhe->ix], PNhe->p.argv[PNhe->ix]))
    02889                 /*@innercontinue@*/ continue;
    02890             if (REVRhe == NULL)
    02891                 goto bingo;
    02892             PFlags = PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK;
    02893             {   EVR_t Pevr = rpmEVRnew(PFlags, 1);
    02894                 if (!(PFlags && RFlags))
    02895                     xx = 1;
    02896                 else {
    02897                     xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr);
    02898                     xx = rpmEVRoverlap(Revr, Pevr);
    02899                 }
    02900                 Pevr = rpmEVRfree(Pevr);
    02901             }
    02902             if (xx)
    02903                 goto bingo;
    02904         }
    02905         goto bottom;
    02906
    02907 bingo:
    02908         NVRAhe->tag = tagNVRA;
    02909         xx = headerGet(oh, NVRAhe, 0);
    02910         if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
    02911             xx = argvAdd(avp, NVRAhe->p.str);
    02912             xx = argvSort(*avp, NULL);
    02913             if (hitp != NULL)
    02914                 xx = argiAdd(hitp, -1, rpmmiInstance(mi));
    02915             rc++;
    02916         }
    02917
    02918 bottom:
    02919         PNhe->p.ptr = _free(PNhe->p.ptr);
    02920         PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
    02921         PFhe->p.ptr = _free(PFhe->p.ptr);
    02922         NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
    02923     }
    02924     mi = rpmmiFree(mi);
    02925
    02926     Revr = rpmEVRfree(Revr);
    02927
    02928     return rc;
    02929 }
    02930
    02931 static int needswhatTag(Header h, HE_t he)
    02932         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    02933         /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
    02934 {
    02935     HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
    02936     HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
    02937     HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
    02938     HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
    02939     rpmTag tagNVRA = RPMTAG_NVRA;
    02940     ARGV_t pkgs = NULL;
    02941     ARGI_t hits = NULL;
    02942     int rc = 1;
    02943
    02944     RNhe->tag = RPMTAG_REQUIRENAME;
    02945     if (!headerGet(h, RNhe, 0))
    02946         goto exit;
    02947     REVRhe->tag = RPMTAG_REQUIREVERSION;
    02948     if (!headerGet(h, REVRhe, 0))
    02949         goto exit;
    02950 assert(REVRhe->c == RNhe->c);
    02951     RFhe->tag = RPMTAG_REQUIREFLAGS;
    02952     if (!headerGet(h, RFhe, 0))
    02953         goto exit;
    02954 assert(RFhe->c == RNhe->c);
    02955
    02956     NVRAhe->tag = tagNVRA;;
    02957     if (!headerGet(h, NVRAhe, 0))
    02958         goto exit;
    02959
    02960     (void) argvAdd(&pkgs, NVRAhe->p.str);
    02961
    02962     for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
    02963         if (*RNhe->p.argv[RNhe->ix] == '/' || *REVRhe->p.argv[RNhe->ix] == '\0')
    02964             (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, NULL, NULL);
    02965         else
    02966             (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, REVRhe, RFhe);
    02967     }
    02968
    02969     /* Convert package NVRA array to Header string array. */
    02970     {   size_t nb = 0;
    02971         char * te;
    02972         rpmuint32_t i;
    02973
    02974         he->t = RPM_STRING_ARRAY_TYPE;
    02975         he->c = argvCount(pkgs);
    02976         nb = 0;
    02977         for (i = 0; i < he->c; i++) {
    02978             nb += sizeof(*he->p.argv);
    02979             nb += strlen(pkgs[i]) + 1;
    02980         }
    02981         nb += sizeof(*he->p.argv);
    02982
    02983         he->p.argv = xmalloc(nb);
    02984         te = (char *) &he->p.argv[he->c+1];
    02985
    02986         for (i = 0; i < he->c; i++) {
    02987             he->p.argv[i] = te;
    02988             te = stpcpy(te, pkgs[i]);
    02989             te++;
    02990         }
    02991         he->p.argv[he->c] = NULL;
    02992     }
    02993
    02994     hits = argiFree(hits);
    02995     pkgs = argvFree(pkgs);
    02996     rc = 0;
    02997
    02998 exit:
    02999     NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
    03000     RNhe->p.ptr = _free(RNhe->p.ptr);
    03001     REVRhe->p.ptr = _free(REVRhe->p.ptr);
    03002     RFhe->p.ptr = _free(RFhe->p.ptr);
    03003     return rc;
    03004 }
    03005
    03006 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F,
    03007                 rpmuint32_t i)
    03008         /*@*/
    03009 {
    03010     int a = -2, b = -2;
    03011
    03012     if (N.argv[i] == NULL || *N.argv[i] == '\0')
    03013         return 1;
    03014     if (tag == RPMTAG_REQUIRENAME && i > 0
    03015      && !(a=strcmp(N.argv[i], N.argv[i-1]))
    03016      && !(b=strcmp(EVR.argv[i], EVR.argv[i-1]))
    03017      && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e)))
    03018         return 1;
    03019     return 0;
    03020 }
    03021
    03022 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
    03023         /*@globals internalState @*/
    03024         /*@modifies he, internalState @*/
    03025 {
    03026     rpmTag tag = he->tag;
    03027     rpmTagData N = { .ptr = NULL };
    03028     rpmTagData EVR = { .ptr = NULL };
    03029     rpmTagData F = { .ptr = NULL };
    03030     size_t nb;
    03031     rpmuint32_t ac;
    03032     rpmuint32_t c;
    03033     rpmuint32_t i;
    03034     char *t;
    03035     int rc = 1;         /* assume failure */
    03036     int xx;
    03037
    03038 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    03039     xx = headerGet(h, he, 0);
    03040     if (xx == 0) goto exit;
    03041     N.argv = he->p.argv;
    03042     c = he->c;
    03043
    03044     he->tag = EVRtag;
    03045     xx = headerGet(h, he, 0);
    03046     if (xx == 0) goto exit;
    03047     EVR.argv = he->p.argv;
    03048
    03049     he->tag = Ftag;
    03050     xx = headerGet(h, he, 0);
    03051     if (xx == 0) goto exit;
    03052     F.ui32p = he->p.ui32p;
    03053
    03054     nb = sizeof(*he->p.argv);
    03055     ac = 0;
    03056     for (i = 0; i < c; i++) {
    03057 /*@-nullstate@*/        /* EVR.argv might be NULL */
    03058         if (PRCOSkip(tag, N, EVR, F, i))
    03059             continue;
    03060 /*@=nullstate@*/
    03061         ac++;
    03062         nb += sizeof(*he->p.argv);
    03063         nb += sizeof("<rpm:entry name=\"\"/>");
    03064         if (*N.argv[i] == '/')
    03065             nb += xmlstrlen(N.argv[i]);
    03066         else
    03067             nb += strlen(N.argv[i]);
    03068         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
    03069             nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1;
    03070             nb += strlen(EVR.argv[i]);
    03071             if (strchr(EVR.argv[i], ':') != NULL)
    03072                 nb -= 2;
    03073             if (strchr(EVR.argv[i], '-') != NULL)
    03074                 nb += sizeof(" rel=\"\"") - 2;
    03075         }
    03076 #ifdef  NOTNOW
    03077         if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
    03078             nb += sizeof(" pre=\"1\"") - 1;
    03079 #endif
    03080     }
    03081
    03082     he->t = RPM_STRING_ARRAY_TYPE;
    03083     he->c = ac;
    03084     he->freeData = 1;
    03085     he->p.argv = xmalloc(nb + BUFSIZ);  /* XXX hack: leave slop */
    03086     t = (char *) &he->p.argv[he->c + 1];
    03087     ac = 0;
    03088     for (i = 0; i < c; i++) {
    03089 /*@-nullstate@*/        /* EVR.argv might be NULL */
    03090         if (PRCOSkip(tag, N, EVR, F, i))
    03091             continue;
    03092 /*@=nullstate@*/
    03093         he->p.argv[ac++] = t;
    03094         t = stpcpy(t, "<rpm:entry");
    03095         t = stpcpy(t, " name=\"");
    03096         if (*N.argv[i] == '/') {
    03097             t = xmlstrcpy(t, N.argv[i]);        t += strlen(t);
    03098         } else
    03099             t = stpcpy(t, N.argv[i]);
    03100         t = stpcpy(t, "\"");
    03101 /*@-readonlytrans@*/
    03102         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
    03103             static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
    03104             rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
    03105             const char *E, *V, *R;
    03106             char *f, *fe;
    03107             t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\"");
    03108             f = (char *) EVR.argv[i];
    03109             for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++)
    03110                 {};
    03111             if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
    03112             V = f;
    03113             for (fe = f; *fe != '\0' && *fe != '-'; fe++)
    03114                 {};
    03115             if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
    03116             t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\"");
    03117             t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\"");
    03118             if (R != NULL)
    03119                 t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\"");
    03120         }
    03121 /*@=readonlytrans@*/
    03122 #ifdef  NOTNOW
    03123         if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
    03124             t = stpcpy(t, " pre=\"1\"");
    03125 #endif
    03126         t = stpcpy(t, "/>");
    03127         *t++ = '\0';
    03128     }
    03129     he->p.argv[he->c] = NULL;
    03130 /*@=compmempass@*/
    03131     rc = 0;
    03132
    03133 exit:
    03134 /*@-kepttrans@*/        /* N.argv may be kept. */
    03135     N.argv = _free(N.argv);
    03136 /*@=kepttrans@*/
    03137 /*@-usereleased@*/      /* EVR.argv may be dead. */
    03138     EVR.argv = _free(EVR.argv);
    03139 /*@=usereleased@*/
    03140     F.ui32p = _free(F.ui32p);
    03141     return rc;
    03142 }
    03143
    03144 static int PxmlTag(Header h, HE_t he)
    03145         /*@globals internalState @*/
    03146         /*@modifies he, internalState @*/
    03147 {
    03148     he->tag = RPMTAG_PROVIDENAME;
    03149     return PRCOxmlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
    03150 }
    03151
    03152 static int RxmlTag(Header h, HE_t he)
    03153         /*@globals internalState @*/
    03154         /*@modifies he, internalState @*/
    03155 {
    03156     he->tag = RPMTAG_REQUIRENAME;
    03157     return PRCOxmlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
    03158 }
    03159
    03160 static int CxmlTag(Header h, HE_t he)
    03161         /*@globals internalState @*/
    03162         /*@modifies he, internalState @*/
    03163 {
    03164     he->tag = RPMTAG_CONFLICTNAME;
    03165     return PRCOxmlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
    03166 }
    03167
    03168 static int OxmlTag(Header h, HE_t he)
    03169         /*@globals internalState @*/
    03170         /*@modifies he, internalState @*/
    03171 {
    03172     he->tag = RPMTAG_OBSOLETENAME;
    03173     return PRCOxmlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
    03174 }
    03175
    03181 static size_t sqlstrlen(const char * s)
    03182         /*@*/
    03183 {
    03184     size_t len = 0;
    03185     int c;
    03186
    03187     while ((c = (int) *s++) != (int) '\0') {
    03188         switch (c) {
    03189         case '\'':      len += 1;                       /*@fallthrough@*/
    03190         default:        len += 1;                       /*@switchbreak@*/ break;
    03191         }
    03192     }
    03193     return len;
    03194 }
    03195
    03202 static char * sqlstrcpy(/*@returned@*/ char * t, const char * s)
    03203         /*@modifies t @*/
    03204 {
    03205     char * te = t;
    03206     int c;
    03207
    03208     while ((c = (int) *s++) != (int) '\0') {
    03209         switch (c) {
    03210         case '\'':      *te++ = (char) c;               /*@fallthrough@*/
    03211         default:        *te++ = (char) c;               /*@switchbreak@*/ break;
    03212         }
    03213     }
    03214     *te = '\0';
    03215     return t;
    03216 }
    03217
    03224 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av)
    03225         /*@*/
    03226 {
    03227     int ix = (he->ix > 0 ? he->ix : 0);
    03228     char * val;
    03229
    03230 assert(ix == 0);
    03231     if (he->t != RPM_STRING_TYPE) {
    03232         val = xstrdup(_("(not a string)"));
    03233     } else {
    03234         const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
    03235         size_t nb;
    03236         char * t;
    03237
    03238         if (s == NULL) {
    03239             /* XXX better error msg? */
    03240             val = xstrdup(_("(not a string)"));
    03241             goto exit;
    03242         }
    03243
    03244         nb = sqlstrlen(s);
    03245         val = t = xcalloc(1, nb + 1);
    03246         t = sqlstrcpy(t, s);    t += strlen(t);
    03247         *t = '\0';
    03248         s = _free(s);
    03249     }
    03250
    03251 exit:
    03252     return val;
    03253 }
    03254
    03255 /*@-compmempass -kepttrans -nullstate -usereleased @*/
    03256 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
    03257         /*@globals internalState @*/
    03258         /*@modifies he, internalState @*/
    03259 {
    03260     rpmTag tag = he->tag;
    03261     rpmTagData N = { .ptr = NULL };
    03262     rpmTagData EVR = { .ptr = NULL };
    03263     rpmTagData F = { .ptr = NULL };
    03264     char instance[64];
    03265     size_t nb;
    03266     rpmuint32_t ac;
    03267     rpmuint32_t c;
    03268     rpmuint32_t i;
    03269     char *t;
    03270     int rc = 1;         /* assume failure */
    03271     int xx;
    03272
    03273 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    03274     xx = headerGet(h, he, 0);
    03275     if (xx == 0) goto exit;
    03276     N.argv = he->p.argv;
    03277     c = he->c;
    03278
    03279     he->tag = EVRtag;
    03280     xx = headerGet(h, he, 0);
    03281     if (xx == 0) goto exit;
    03282     EVR.argv = he->p.argv;
    03283
    03284     he->tag = Ftag;
    03285     xx = headerGet(h, he, 0);
    03286     if (xx == 0) goto exit;
    03287     F.ui32p = he->p.ui32p;
    03288
    03289     xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
    03290     nb = sizeof(*he->p.argv);
    03291     ac = 0;
    03292     for (i = 0; i < c; i++) {
    03293 /*@-nullstate@*/        /* EVR.argv might be NULL */
    03294         if (PRCOSkip(tag, N, EVR, F, i))
    03295             continue;
    03296 /*@=nullstate@*/
    03297         ac++;
    03298         nb += sizeof(*he->p.argv);
    03299         nb += strlen(instance) + sizeof(", '', '', '', '', ''");
    03300         if (tag == RPMTAG_REQUIRENAME)
    03301             nb += sizeof(", ''") - 1;
    03302         nb += strlen(N.argv[i]);
    03303         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
    03304             nb += strlen(EVR.argv[i]);
    03305             nb += sizeof("EQ0") - 1;
    03306         }
    03307 #ifdef  NOTNOW
    03308         if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
    03309             nb += sizeof("1") - 1;
    03310 #endif
    03311     }
    03312
    03313     he->t = RPM_STRING_ARRAY_TYPE;
    03314     he->c = ac;
    03315     he->freeData = 1;
    03316     he->p.argv = xmalloc(nb + BUFSIZ);  /* XXX hack: leave slop */
    03317     t = (char *) &he->p.argv[he->c + 1];
    03318     ac = 0;
    03319     for (i = 0; i < c; i++) {
    03320 /*@-nullstate@*/        /* EVR.argv might be NULL */
    03321         if (PRCOSkip(tag, N, EVR, F, i))
    03322             continue;
    03323 /*@=nullstate@*/
    03324         he->p.argv[ac++] = t;
    03325         t = stpcpy(t, instance);
    03326         t = stpcpy( stpcpy( stpcpy(t, ", '"), N.argv[i]), "'");
    03327 /*@-readonlytrans@*/
    03328         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
    03329             static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
    03330             rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
    03331             const char *E, *V, *R;
    03332             char *f, *fe;
    03333             t = stpcpy( stpcpy( stpcpy(t, ", '"), Fstr[Fx]), "'");
    03334             f = (char *) EVR.argv[i];
    03335             for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++)
    03336                 {};
    03337             if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
    03338             V = f;
    03339             for (fe = f; *fe != '\0' && *fe != '-'; fe++)
    03340                 {};
    03341             if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
    03342             t = stpcpy( stpcpy( stpcpy(t, ", '"), (E && *E ? E : "0")), "'");
    03343             t = stpcpy( stpcpy( stpcpy(t, ", '"), V), "'");
    03344             t = stpcpy( stpcpy( stpcpy(t, ", '"), (R ? R : "")), "'");
    03345         } else
    03346             t = stpcpy(t, ", '', '', '', ''");
    03347 /*@=readonlytrans@*/
    03348 #ifdef  NOTNOW
    03349         if (tag == RPMTAG_REQUIRENAME)
    03350             t = stpcpy(stpcpy(stpcpy(t, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'");
    03351 #endif
    03352         *t++ = '\0';
    03353     }
    03354     he->p.argv[he->c] = NULL;
    03355 /*@=compmempass@*/
    03356     rc = 0;
    03357
    03358 exit:
    03359 /*@-kepttrans@*/        /* N.argv may be kept. */
    03360     N.argv = _free(N.argv);
    03361 /*@=kepttrans@*/
    03362 /*@-usereleased@*/      /* EVR.argv may be dead. */
    03363     EVR.argv = _free(EVR.argv);
    03364 /*@=usereleased@*/
    03365     F.ui32p = _free(F.ui32p);
    03366     return rc;
    03367 }
    03368
    03369 static int PsqlTag(Header h, HE_t he)
    03370         /*@globals internalState @*/
    03371         /*@modifies he, internalState @*/
    03372 {
    03373     he->tag = RPMTAG_PROVIDENAME;
    03374     return PRCOsqlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
    03375 }
    03376
    03377 static int RsqlTag(Header h, HE_t he)
    03378         /*@globals internalState @*/
    03379         /*@modifies he, internalState @*/
    03380 {
    03381     he->tag = RPMTAG_REQUIRENAME;
    03382     return PRCOsqlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
    03383 }
    03384
    03385 static int CsqlTag(Header h, HE_t he)
    03386         /*@globals internalState @*/
    03387         /*@modifies he, internalState @*/
    03388 {
    03389     he->tag = RPMTAG_CONFLICTNAME;
    03390     return PRCOsqlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
    03391 }
    03392
    03393 static int OsqlTag(Header h, HE_t he)
    03394         /*@globals internalState @*/
    03395         /*@modifies he, internalState @*/
    03396 {
    03397     he->tag = RPMTAG_OBSOLETENAME;
    03398     return PRCOsqlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
    03399 }
    03400
    03401 static int PRCOyamlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
    03402         /*@globals internalState @*/
    03403         /*@modifies he, internalState @*/
    03404 {
    03405     rpmTag tag = he->tag;
    03406     rpmTagData N = { .ptr = NULL };
    03407     rpmTagData EVR = { .ptr = NULL };
    03408     rpmTagData F = { .ptr = NULL };
    03409     size_t nb;
    03410     rpmuint32_t ac;
    03411     rpmuint32_t c;
    03412     rpmuint32_t i;
    03413     char *t;
    03414     int rc = 1;         /* assume failure */
    03415     int indent = 0;
    03416     int xx;
    03417
    03418 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    03419     xx = headerGet(h, he, 0);
    03420     if (xx == 0) goto exit;
    03421     N.argv = he->p.argv;
    03422     c = he->c;
    03423
    03424     he->tag = EVRtag;
    03425     xx = headerGet(h, he, 0);
    03426     if (xx == 0) goto exit;
    03427     EVR.argv = he->p.argv;
    03428
    03429     he->tag = Ftag;
    03430     xx = headerGet(h, he, 0);
    03431     if (xx == 0) goto exit;
    03432     F.ui32p = he->p.ui32p;
    03433
    03434     nb = sizeof(*he->p.argv);
    03435     ac = 0;
    03436     for (i = 0; i < c; i++) {
    03437 /*@-nullstate@*/        /* EVR.argv might be NULL */
    03438         if (PRCOSkip(tag, N, EVR, F, i))
    03439             continue;
    03440 /*@=nullstate@*/
    03441         ac++;
    03442         nb += sizeof(*he->p.argv);
    03443         nb += sizeof("- ");
    03444         if (*N.argv[i] == '/')
    03445             nb += yamlstrlen(N.argv[i], indent);
    03446         else
    03447             nb += strlen(N.argv[i]);
    03448         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
    03449             nb += sizeof(" >= ") - 1;
    03450             nb += strlen(EVR.argv[i]);
    03451         }
    03452     }
    03453
    03454     he->t = RPM_STRING_ARRAY_TYPE;
    03455     he->c = ac;
    03456     he->freeData = 1;
    03457     he->p.argv = xmalloc(nb + BUFSIZ);  /* XXX hack: leave slop */
    03458     t = (char *) &he->p.argv[he->c + 1];
    03459     ac = 0;
    03460     for (i = 0; i < c; i++) {
    03461 /*@-nullstate@*/        /* EVR.argv might be NULL */
    03462         if (PRCOSkip(tag, N, EVR, F, i))
    03463             continue;
    03464 /*@=nullstate@*/
    03465         he->p.argv[ac++] = t;
    03466         t = stpcpy(t, "- ");
    03467         if (*N.argv[i] == '/') {
    03468             t = yamlstrcpy(t, N.argv[i], indent);       t += strlen(t);
    03469         } else
    03470             t = stpcpy(t, N.argv[i]);
    03471 /*@-readonlytrans@*/
    03472         if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
    03473             static char *Fstr[] = { "?0","<",">","?3","=","<=",">=","?7" };
    03474             rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
    03475             t = stpcpy( stpcpy( stpcpy(t, " "), Fstr[Fx]), " ");
    03476             t = stpcpy(t, EVR.argv[i]);
    03477         }
    03478 /*@=readonlytrans@*/
    03479         *t++ = '\0';
    03480     }
    03481     he->p.argv[he->c] = NULL;
    03482 /*@=compmempass@*/
    03483     rc = 0;
    03484
    03485 exit:
    03486 /*@-kepttrans@*/        /* N.argv may be kept. */
    03487     N.argv = _free(N.argv);
    03488 /*@=kepttrans@*/
    03489 /*@-usereleased@*/      /* EVR.argv may be dead. */
    03490     EVR.argv = _free(EVR.argv);
    03491 /*@=usereleased@*/
    03492     F.ui32p = _free(F.ui32p);
    03493     return rc;
    03494 }
    03495
    03496 static int PyamlTag(Header h, HE_t he)
    03497         /*@globals internalState @*/
    03498         /*@modifies he, internalState @*/
    03499 {
    03500     he->tag = RPMTAG_PROVIDENAME;
    03501     return PRCOyamlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
    03502 }
    03503
    03504 static int RyamlTag(Header h, HE_t he)
    03505         /*@globals internalState @*/
    03506         /*@modifies he, internalState @*/
    03507 {
    03508     he->tag = RPMTAG_REQUIRENAME;
    03509     return PRCOyamlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
    03510 }
    03511
    03512 static int CyamlTag(Header h, HE_t he)
    03513         /*@globals internalState @*/
    03514         /*@modifies he, internalState @*/
    03515 {
    03516     he->tag = RPMTAG_CONFLICTNAME;
    03517     return PRCOyamlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
    03518 }
    03519
    03520 static int OyamlTag(Header h, HE_t he)
    03521         /*@globals internalState @*/
    03522         /*@modifies he, internalState @*/
    03523 {
    03524     he->tag = RPMTAG_OBSOLETENAME;
    03525     return PRCOyamlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
    03526 }
    03527
    03528 static int FDGSkip(rpmTagData DN, rpmTagData BN, rpmTagData DI, rpmuint32_t i)
    03529         /*@*/
    03530 {
    03531     const char * dn = DN.argv[DI.ui32p[i]];
    03532     size_t dnlen = strlen(dn);
    03533
    03534 assert(dn != NULL);
    03535     if (strstr(dn, "bin/") != NULL)
    03536         return 1;
    03537     if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen))
    03538         return 1;
    03539     if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail"))
    03540         return 1;
    03541     return 2;
    03542 }
    03543
    03544 static int FDGxmlTag(Header h, HE_t he, int lvl)
    03545         /*@globals internalState @*/
    03546         /*@modifies he, internalState @*/
    03547 {
    03548     rpmTagData BN = { .ptr = NULL };
    03549     rpmTagData DN = { .ptr = NULL };
    03550     rpmTagData DI = { .ptr = NULL };
    03551     rpmTagData FMODES = { .ptr = NULL };
    03552     rpmTagData FFLAGS = { .ptr = NULL };
    03553     size_t nb;
    03554     rpmuint32_t ac;
    03555     rpmuint32_t c;
    03556     rpmuint32_t i;
    03557     char *t;
    03558     int rc = 1;         /* assume failure */
    03559     int xx;
    03560
    03561 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    03562     he->tag = RPMTAG_BASENAMES;
    03563     xx = headerGet(h, he, 0);
    03564     if (xx == 0) goto exit;
    03565     BN.argv = he->p.argv;
    03566     c = he->c;
    03567
    03568     he->tag = RPMTAG_DIRNAMES;
    03569     xx = headerGet(h, he, 0);
    03570     if (xx == 0) goto exit;
    03571     DN.argv = he->p.argv;
    03572
    03573     he->tag = RPMTAG_DIRINDEXES;
    03574     xx = headerGet(h, he, 0);
    03575     if (xx == 0) goto exit;
    03576     DI.ui32p = he->p.ui32p;
    03577
    03578     he->tag = RPMTAG_FILEMODES;
    03579     xx = headerGet(h, he, 0);
    03580     if (xx == 0) goto exit;
    03581     FMODES.ui16p = he->p.ui16p;
    03582
    03583     he->tag = RPMTAG_FILEFLAGS;
    03584     xx = headerGet(h, he, 0);
    03585     if (xx == 0) goto exit;
    03586     FFLAGS.ui32p = he->p.ui32p;
    03587
    03588     nb = sizeof(*he->p.argv);
    03589     ac = 0;
    03590     for (i = 0; i < c; i++) {
    03591         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03592             continue;
    03593         ac++;
    03594         nb += sizeof(*he->p.argv);
    03595         nb += sizeof("<file></file>");
    03596         nb += xmlstrlen(DN.argv[DI.ui32p[i]]);
    03597         nb += xmlstrlen(BN.argv[i]);
    03598         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03599             nb += sizeof(" type=\"ghost\"") - 1;
    03600         else if (S_ISDIR(FMODES.ui16p[i])) {
    03601             nb += sizeof(" type=\"dir\"") - 1;
    03602 #ifdef  NOTYET
    03603             nb += sizeof("/") - 1;
    03604 #endif
    03605         }
    03606     }
    03607
    03608     he->t = RPM_STRING_ARRAY_TYPE;
    03609     he->c = ac;
    03610     he->freeData = 1;
    03611     he->p.argv = xmalloc(nb);
    03612     t = (char *) &he->p.argv[he->c + 1];
    03613     ac = 0;
    03614     /* FIXME: Files, then dirs, finally ghosts breaks sort order.  */
    03615     for (i = 0; i < c; i++) {
    03616         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03617             continue;
    03618         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03619             continue;
    03620         if (S_ISDIR(FMODES.ui16p[i]))
    03621             continue;
    03622         he->p.argv[ac++] = t;
    03623         t = stpcpy(t, "<file>");
    03624         t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
    03625         t = xmlstrcpy(t, BN.argv[i]);           t += strlen(t);
    03626         t = stpcpy(t, "</file>");
    03627         *t++ = '\0';
    03628     }
    03629     for (i = 0; i < c; i++) {
    03630         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03631             continue;
    03632         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03633             continue;
    03634         if (!S_ISDIR(FMODES.ui16p[i]))
    03635             continue;
    03636         he->p.argv[ac++] = t;
    03637         t = stpcpy(t, "<file type=\"dir\">");
    03638         t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
    03639         t = xmlstrcpy(t, BN.argv[i]);           t += strlen(t);
    03640 #ifdef  NOTYET
    03641         /* Append the pesky trailing / to directories. */
    03642         if (t[-1] != '/')
    03643             t = stpcpy(t, "/");
    03644 #endif
    03645         t = stpcpy(t, "</file>");
    03646         *t++ = '\0';
    03647     }
    03648     for (i = 0; i < c; i++) {
    03649         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03650             continue;
    03651         if (!(FFLAGS.ui32p[i] & 0x40))  /* XXX RPMFILE_GHOST */
    03652             continue;
    03653         he->p.argv[ac++] = t;
    03654         t = stpcpy(t, "<file type=\"ghost\">");
    03655         t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
    03656         t = xmlstrcpy(t, BN.argv[i]);           t += strlen(t);
    03657         t = stpcpy(t, "</file>");
    03658         *t++ = '\0';
    03659     }
    03660
    03661     he->p.argv[he->c] = NULL;
    03662 /*@=compmempass@*/
    03663     rc = 0;
    03664
    03665 exit:
    03666 /*@-kepttrans@*/        /* {BN,DN,DI}.argv may be kept. */
    03667     BN.argv = _free(BN.argv);
    03668 /*@-usereleased@*/      /* DN.argv may be dead. */
    03669     DN.argv = _free(DN.argv);
    03670 /*@=usereleased@*/
    03671     DI.ui32p = _free(DI.ui32p);
    03672 /*@=kepttrans@*/
    03673     FMODES.ui16p = _free(FMODES.ui16p);
    03674 /*@-usereleased@*/      /* FFLAGS.argv may be dead. */
    03675     FFLAGS.ui32p = _free(FFLAGS.ui32p);
    03676 /*@=usereleased@*/
    03677     return rc;
    03678 }
    03679
    03680 static int F1xmlTag(Header h, HE_t he)
    03681         /*@globals internalState @*/
    03682         /*@modifies he, internalState @*/
    03683 {
    03684     he->tag = RPMTAG_BASENAMES;
    03685     return FDGxmlTag(h, he, 1);
    03686 }
    03687
    03688 static int F2xmlTag(Header h, HE_t he)
    03689         /*@globals internalState @*/
    03690         /*@modifies he, internalState @*/
    03691 {
    03692     he->tag = RPMTAG_BASENAMES;
    03693     return FDGxmlTag(h, he, 2);
    03694 }
    03695
    03696 static int FDGsqlTag(Header h, HE_t he, int lvl)
    03697         /*@globals internalState @*/
    03698         /*@modifies he, internalState @*/
    03699 {
    03700     rpmTagData BN = { .ptr = NULL };
    03701     rpmTagData DN = { .ptr = NULL };
    03702     rpmTagData DI = { .ptr = NULL };
    03703     rpmTagData FMODES = { .ptr = NULL };
    03704     rpmTagData FFLAGS = { .ptr = NULL };
    03705     char instance[64];
    03706     size_t nb;
    03707     rpmuint32_t ac;
    03708     rpmuint32_t c;
    03709     rpmuint32_t i;
    03710     char *t;
    03711     int rc = 1;         /* assume failure */
    03712     int xx;
    03713
    03714 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    03715     he->tag = RPMTAG_BASENAMES;
    03716     xx = headerGet(h, he, 0);
    03717     if (xx == 0) goto exit;
    03718     BN.argv = he->p.argv;
    03719     c = he->c;
    03720
    03721     he->tag = RPMTAG_DIRNAMES;
    03722     xx = headerGet(h, he, 0);
    03723     if (xx == 0) goto exit;
    03724     DN.argv = he->p.argv;
    03725
    03726     he->tag = RPMTAG_DIRINDEXES;
    03727     xx = headerGet(h, he, 0);
    03728     if (xx == 0) goto exit;
    03729     DI.ui32p = he->p.ui32p;
    03730
    03731     he->tag = RPMTAG_FILEMODES;
    03732     xx = headerGet(h, he, 0);
    03733     if (xx == 0) goto exit;
    03734     FMODES.ui16p = he->p.ui16p;
    03735
    03736     he->tag = RPMTAG_FILEFLAGS;
    03737     xx = headerGet(h, he, 0);
    03738     if (xx == 0) goto exit;
    03739     FFLAGS.ui32p = he->p.ui32p;
    03740
    03741     xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
    03742     nb = sizeof(*he->p.argv);
    03743     ac = 0;
    03744     for (i = 0; i < c; i++) {
    03745         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03746             continue;
    03747         ac++;
    03748         nb += sizeof(*he->p.argv);
    03749         nb += strlen(instance) + sizeof(", '', ''");
    03750         nb += strlen(DN.argv[DI.ui32p[i]]);
    03751         nb += strlen(BN.argv[i]);
    03752         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03753             nb += sizeof("ghost") - 1;
    03754         else if (S_ISDIR(FMODES.ui16p[i])) {
    03755             nb += sizeof("dir") - 1;
    03756 #ifdef  NOTYET
    03757             nb += sizeof("/") - 1;
    03758 #endif
    03759         } else
    03760             nb += sizeof("file") - 1;
    03761     }
    03762
    03763     he->t = RPM_STRING_ARRAY_TYPE;
    03764     he->c = ac;
    03765     he->freeData = 1;
    03766     he->p.argv = xmalloc(nb);
    03767     t = (char *) &he->p.argv[he->c + 1];
    03768     ac = 0;
    03769     /* FIXME: Files, then dirs, finally ghosts breaks sort order.  */
    03770     for (i = 0; i < c; i++) {
    03771         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03772             continue;
    03773         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03774             continue;
    03775         if (S_ISDIR(FMODES.ui16p[i]))
    03776             continue;
    03777         he->p.argv[ac++] = t;
    03778         t = stpcpy( stpcpy(t, instance), ", '");
    03779         t = strcpy(t, DN.argv[DI.ui32p[i]]);    t += strlen(t);
    03780         t = strcpy(t, BN.argv[i]);              t += strlen(t);
    03781         t = stpcpy(t, "', 'file'");
    03782         *t++ = '\0';
    03783     }
    03784     for (i = 0; i < c; i++) {
    03785         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03786             continue;
    03787         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03788             continue;
    03789         if (!S_ISDIR(FMODES.ui16p[i]))
    03790             continue;
    03791         he->p.argv[ac++] = t;
    03792         t = stpcpy( stpcpy(t, instance), ", '");
    03793         t = strcpy(t, DN.argv[DI.ui32p[i]]);    t += strlen(t);
    03794         t = strcpy(t, BN.argv[i]);              t += strlen(t);
    03795 #ifdef  NOTYET
    03796         /* Append the pesky trailing / to directories. */
    03797         if (t[-1] != '/')
    03798             t = stpcpy(t, "/");
    03799 #endif
    03800         t = stpcpy(t, "', 'dir'");
    03801         *t++ = '\0';
    03802     }
    03803     for (i = 0; i < c; i++) {
    03804         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03805             continue;
    03806         if (!(FFLAGS.ui32p[i] & 0x40))  /* XXX RPMFILE_GHOST */
    03807             continue;
    03808         he->p.argv[ac++] = t;
    03809         t = stpcpy( stpcpy(t, instance), ", '");
    03810         t = strcpy(t, DN.argv[DI.ui32p[i]]);    t += strlen(t);
    03811         t = strcpy(t, BN.argv[i]);              t += strlen(t);
    03812         t = stpcpy(t, "', 'ghost'");
    03813         *t++ = '\0';
    03814     }
    03815
    03816     he->p.argv[he->c] = NULL;
    03817 /*@=compmempass@*/
    03818     rc = 0;
    03819
    03820 exit:
    03821 /*@-kepttrans@*/        /* {BN,DN,DI}.argv may be kept. */
    03822     BN.argv = _free(BN.argv);
    03823 /*@-usereleased@*/      /* DN.argv may be dead. */
    03824     DN.argv = _free(DN.argv);
    03825 /*@=usereleased@*/
    03826     DI.ui32p = _free(DI.ui32p);
    03827 /*@=kepttrans@*/
    03828     FMODES.ui16p = _free(FMODES.ui16p);
    03829 /*@-usereleased@*/      /* FFLAGS.argv may be dead. */
    03830     FFLAGS.ui32p = _free(FFLAGS.ui32p);
    03831 /*@=usereleased@*/
    03832     return rc;
    03833 }
    03834
    03835 static int F1sqlTag(Header h, HE_t he)
    03836         /*@globals internalState @*/
    03837         /*@modifies he, internalState @*/
    03838 {
    03839     he->tag = RPMTAG_BASENAMES;
    03840     return FDGsqlTag(h, he, 1);
    03841 }
    03842
    03843 static int F2sqlTag(Header h, HE_t he)
    03844         /*@globals internalState @*/
    03845         /*@modifies he, internalState @*/
    03846 {
    03847     he->tag = RPMTAG_BASENAMES;
    03848     return FDGsqlTag(h, he, 2);
    03849 }
    03850
    03851 static int FDGyamlTag(Header h, HE_t he, int lvl)
    03852         /*@globals internalState @*/
    03853         /*@modifies he, internalState @*/
    03854 {
    03855     rpmTagData BN = { .ptr = NULL };
    03856     rpmTagData DN = { .ptr = NULL };
    03857     rpmTagData DI = { .ptr = NULL };
    03858     rpmTagData FMODES = { .ptr = NULL };
    03859     rpmTagData FFLAGS = { .ptr = NULL };
    03860     size_t nb;
    03861     rpmuint32_t ac;
    03862     rpmuint32_t c;
    03863     rpmuint32_t i;
    03864     char *t;
    03865     int rc = 1;         /* assume failure */
    03866     int indent = 0;
    03867     int xx;
    03868
    03869 /*@-compmempass@*/      /* use separate HE_t, not rpmTagData, containers. */
    03870     he->tag = RPMTAG_BASENAMES;
    03871     xx = headerGet(h, he, 0);
    03872     if (xx == 0) goto exit;
    03873     BN.argv = he->p.argv;
    03874     c = he->c;
    03875
    03876     he->tag = RPMTAG_DIRNAMES;
    03877     xx = headerGet(h, he, 0);
    03878     if (xx == 0) goto exit;
    03879     DN.argv = he->p.argv;
    03880
    03881     he->tag = RPMTAG_DIRINDEXES;
    03882     xx = headerGet(h, he, 0);
    03883     if (xx == 0) goto exit;
    03884     DI.ui32p = he->p.ui32p;
    03885
    03886     he->tag = RPMTAG_FILEMODES;
    03887     xx = headerGet(h, he, 0);
    03888     if (xx == 0) goto exit;
    03889     FMODES.ui16p = he->p.ui16p;
    03890
    03891     he->tag = RPMTAG_FILEFLAGS;
    03892     xx = headerGet(h, he, 0);
    03893     if (xx == 0) goto exit;
    03894     FFLAGS.ui32p = he->p.ui32p;
    03895
    03896     nb = sizeof(*he->p.argv);
    03897     ac = 0;
    03898     for (i = 0; i < c; i++) {
    03899         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03900             continue;
    03901         ac++;
    03902         nb += sizeof(*he->p.argv);
    03903         nb += sizeof("- ");
    03904         nb += yamlstrlen(DN.argv[DI.ui32p[i]], indent);
    03905         nb += yamlstrlen(BN.argv[i], indent);
    03906         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03907             nb += sizeof("") - 1;
    03908         else if (S_ISDIR(FMODES.ui16p[i]))
    03909             nb += sizeof("/") - 1;
    03910     }
    03911
    03912     he->t = RPM_STRING_ARRAY_TYPE;
    03913     he->c = ac;
    03914     he->freeData = 1;
    03915     he->p.argv = xmalloc(nb);
    03916     t = (char *) &he->p.argv[he->c + 1];
    03917     ac = 0;
    03918     /* FIXME: Files, then dirs, finally ghosts breaks sort order.  */
    03919     for (i = 0; i < c; i++) {
    03920         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03921             continue;
    03922         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03923             continue;
    03924         if (S_ISDIR(FMODES.ui16p[i]))
    03925             continue;
    03926         he->p.argv[ac++] = t;
    03927         t = stpcpy(t, "- ");
    03928         t = yamlstrcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
    03929         t = yamlstrcpy(t, BN.argv[i], indent);          t += strlen(t);
    03930         t = stpcpy(t, "");
    03931         *t++ = '\0';
    03932     }
    03933     for (i = 0; i < c; i++) {
    03934         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03935             continue;
    03936         if (FFLAGS.ui32p[i] & 0x40)     /* XXX RPMFILE_GHOST */
    03937             continue;
    03938         if (!S_ISDIR(FMODES.ui16p[i]))
    03939             continue;
    03940         he->p.argv[ac++] = t;
    03941         t = stpcpy(t, "- ");
    03942         t = yamlstrcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
    03943         t = yamlstrcpy(t, BN.argv[i], indent);          t += strlen(t);
    03944         /* Append the pesky trailing / to directories. */
    03945         if (t[-1] != '/')
    03946             t = stpcpy(t, "/");
    03947         *t++ = '\0';
    03948     }
    03949     for (i = 0; i < c; i++) {
    03950         if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
    03951             continue;
    03952         if (!(FFLAGS.ui32p[i] & 0x40))  /* XXX RPMFILE_GHOST */
    03953             continue;
    03954         he->p.argv[ac++] = t;
    03955         t = stpcpy(t, "- ");
    03956         t = yamlstrcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
    03957         t = yamlstrcpy(t, BN.argv[i], indent);          t += strlen(t);
    03958         *t++ = '\0';
    03959     }
    03960
    03961     he->p.argv[he->c] = NULL;
    03962 /*@=compmempass@*/
    03963     rc = 0;
    03964
    03965 exit:
    03966 /*@-kepttrans@*/        /* {BN,DN,DI}.argv may be kept. */
    03967     BN.argv = _free(BN.argv);
    03968 /*@-usereleased@*/      /* DN.argv may be dead. */
    03969     DN.argv = _free(DN.argv);
    03970 /*@=usereleased@*/
    03971     DI.ui32p = _free(DI.ui32p);
    03972 /*@=kepttrans@*/
    03973     FMODES.ui16p = _free(FMODES.ui16p);
    03974 /*@-usereleased@*/      /* FFLAGS.argv may be dead. */
    03975     FFLAGS.ui32p = _free(FFLAGS.ui32p);
    03976 /*@=usereleased@*/
    03977     return rc;
    03978 }
    03979
    03980 static int F1yamlTag(Header h, HE_t he)
    03981         /*@globals internalState @*/
    03982         /*@modifies he, internalState @*/
    03983 {
    03984     he->tag = RPMTAG_BASENAMES;
    03985     return FDGyamlTag(h, he, 1);
    03986 }
    03987
    03988 static int F2yamlTag(Header h, HE_t he)
    03989         /*@globals internalState @*/
    03990         /*@modifies he, internalState @*/
    03991 {
    03992     he->tag = RPMTAG_BASENAMES;
    03993     return FDGyamlTag(h, he, 2);
    03994 }
    03995
    04002 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av)
    04003         /*@*/
    04004 {
    04005     char * val;
    04006
    04007     if (he->t != RPM_STRING_TYPE) {
    04008         val = xstrdup(_("(not a string)"));
    04009     } else {
    04010         const char * bn;
    04011         const char * s;
    04012         size_t nb;
    04013         char * t;
    04014
    04015 assert(he->p.str != NULL);
    04016         /* Get rightmost '/' in string (i.e. basename(3) behavior). */
    04017         if ((bn = strrchr(he->p.str, '/')) != NULL)
    04018             bn++;
    04019         else
    04020             bn = he->p.str;
    04021
    04022         /* Convert to utf8, escape for XML CDATA. */
    04023         s = strdup_locale_convert(bn, (av ? av[0] : NULL));
    04024         if (s == NULL) {
    04025             /* XXX better error msg? */
    04026             val = xstrdup(_("(not a string)"));
    04027             goto exit;
    04028         }
    04029
    04030         nb = xmlstrlen(s);
    04031         val = t = xcalloc(1, nb + 1);
    04032         t = xmlstrcpy(t, s);    t += strlen(t);
    04033         *t = '\0';
    04034         s = _free(s);
    04035     }
    04036
    04037 exit:
    04038     return val;
    04039 }
    04040
    04041 typedef struct key_s {
    04042 /*@observer@*/
    04043         const char *name;               /* key name */
    04044         rpmuint32_t value;
    04045 } KEY;
    04046
    04047 /*@unchecked@*/ /*@observer@*/
    04048 static KEY keyDigests[] = {
    04049     { "adler32",        PGPHASHALGO_ADLER32 },
    04050     { "crc32",          PGPHASHALGO_CRC32 },
    04051     { "crc64",          PGPHASHALGO_CRC64 },
    04052     { "haval160",       PGPHASHALGO_HAVAL_5_160 },
    04053     { "jlu32",          PGPHASHALGO_JLU32 },
    04054     { "md2",            PGPHASHALGO_MD2 },
    04055     { "md4",            PGPHASHALGO_MD4 },
    04056     { "md5",            PGPHASHALGO_MD5 },
    04057     { "rmd128",         PGPHASHALGO_RIPEMD128 },
    04058     { "rmd160",         PGPHASHALGO_RIPEMD160 },
    04059     { "rmd256",         PGPHASHALGO_RIPEMD256 },
    04060     { "rmd320",         PGPHASHALGO_RIPEMD320 },
    04061     { "salsa10",        PGPHASHALGO_SALSA10 },
    04062     { "salsa20",        PGPHASHALGO_SALSA20 },
    04063     { "sha1",           PGPHASHALGO_SHA1 },
    04064     { "sha224",         PGPHASHALGO_SHA224 },
    04065     { "sha256",         PGPHASHALGO_SHA256 },
    04066     { "sha384",         PGPHASHALGO_SHA384 },
    04067     { "sha512",         PGPHASHALGO_SHA512 },
    04068     { "tiger192",       PGPHASHALGO_TIGER192 },
    04069 };
    04070 /*@unchecked@*/
    04071 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]);
    04072
    04076 enum keyStat_e {
    04077     STAT_KEYS_NONE      = 0,
    04078     STAT_KEYS_DEV       = (1U <<  0),
    04079     STAT_KEYS_INO       = (1U <<  1),
    04080     STAT_KEYS_MODE      = (1U <<  2),
    04081     STAT_KEYS_NLINK     = (1U <<  3),
    04082     STAT_KEYS_UID       = (1U <<  4),
    04083     STAT_KEYS_GID       = (1U <<  5),
    04084     STAT_KEYS_RDEV      = (1U <<  6),
    04085     STAT_KEYS_SIZE      = (1U <<  7),
    04086     STAT_KEYS_BLKSIZE   = (1U <<  8),
    04087     STAT_KEYS_BLOCKS    = (1U <<  9),
    04088     STAT_KEYS_ATIME     = (1U << 10),
    04089     STAT_KEYS_CTIME     = (1U << 11),
    04090     STAT_KEYS_MTIME     = (1U << 12),
    04091 #ifdef  NOTYET
    04092     STAT_KEYS_FLAGS     = (1U << 13),
    04093 #endif
    04094     STAT_KEYS_SLINK     = (1U << 14),
    04095     STAT_KEYS_DIGEST    = (1U << 15),
    04096 #ifdef  NOTYET
    04097     STAT_KEYS_FCONTEXT  = (1U << 16),
    04098 #endif
    04099     STAT_KEYS_UNAME     = (1U << 17),
    04100     STAT_KEYS_GNAME     = (1U << 18),
    04101 };
    04102
    04103 /*@unchecked@*/ /*@observer@*/
    04104 static KEY keyStat[] = {
    04105     { "adler32",        STAT_KEYS_DIGEST },
    04106     { "atime",          STAT_KEYS_ATIME },
    04107     { "ctime",          STAT_KEYS_CTIME },
    04108     { "blksize",        STAT_KEYS_BLKSIZE },
    04109     { "blocks",         STAT_KEYS_BLOCKS },
    04110     { "crc32",          STAT_KEYS_DIGEST },
    04111     { "crc64",          STAT_KEYS_DIGEST },
    04112     { "dev",            STAT_KEYS_DEV },
    04113 #ifdef  NOTYET
    04114     { "digest",         STAT_KEYS_DIGEST },
    04115     { "fcontext",       STAT_KEYS_FCONTEXT },
    04116     { "flags",          STAT_KEYS_FLAGS },
    04117 #endif
    04118     { "gid",            STAT_KEYS_GID },
    04119     { "gname",          STAT_KEYS_GNAME },
    04120     { "haval160",       STAT_KEYS_DIGEST },
    04121     { "ino",            STAT_KEYS_INO },
    04122     { "jlu32",          STAT_KEYS_DIGEST },
    04123     { "link",           STAT_KEYS_SLINK },
    04124     { "md2",            STAT_KEYS_DIGEST },
    04125     { "md4",            STAT_KEYS_DIGEST },
    04126     { "md5",            STAT_KEYS_DIGEST },
    04127     { "mode",           STAT_KEYS_MODE },
    04128     { "mtime",          STAT_KEYS_MTIME },
    04129     { "nlink",          STAT_KEYS_NLINK },
    04130     { "rdev",           STAT_KEYS_RDEV },
    04131     { "rmd128",         STAT_KEYS_DIGEST },
    04132     { "rmd160",         STAT_KEYS_DIGEST },
    04133     { "rmd256",         STAT_KEYS_DIGEST },
    04134     { "rmd320",         STAT_KEYS_DIGEST },
    04135     { "salsa10",        STAT_KEYS_DIGEST },
    04136     { "salsa20",        STAT_KEYS_DIGEST },
    04137     { "sha1",           STAT_KEYS_DIGEST },
    04138     { "sha224",         STAT_KEYS_DIGEST },
    04139     { "sha256",         STAT_KEYS_DIGEST },
    04140     { "sha384",         STAT_KEYS_DIGEST },
    04141     { "sha512",         STAT_KEYS_DIGEST },
    04142     { "size",           STAT_KEYS_SIZE },
    04143     { "tiger192",       STAT_KEYS_DIGEST },
    04144     { "uid",            STAT_KEYS_UID },
    04145     { "uname",          STAT_KEYS_UNAME },
    04146 };
    04147 /*@unchecked@*/
    04148 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]);
    04149
    04153 enum keyUuids_e {
    04154     UUID_KEYS_NONE      = (0U <<  0),
    04155     UUID_KEYS_V1        = (1U <<  0),
    04156     UUID_KEYS_V3        = (3U <<  0),
    04157     UUID_KEYS_V4        = (4U <<  0),
    04158     UUID_KEYS_V5        = (5U <<  0),
    04159 #ifdef  NOTYET
    04160     UUID_KEYS_STRING    = (0U <<  4),
    04161     UUID_KEYS_SIV       = (1U <<  4),
    04162     UUID_KEYS_BINARY    = (2U <<  4),
    04163     UUID_KEYS_TEXT      = (3U <<  4),
    04164 #endif
    04165 };
    04166
    04167 /*@unchecked@*/ /*@observer@*/
    04168 static KEY keyUuids[] = {
    04169 #ifdef  NOTYET
    04170     { "binary",         UUID_KEYS_BINARY },
    04171     { "siv",            UUID_KEYS_SIV },
    04172     { "string",         UUID_KEYS_STRING },
    04173     { "text",           UUID_KEYS_TEXT },
    04174 #endif
    04175     { "v1",             UUID_KEYS_V1 },
    04176     { "v3",             UUID_KEYS_V3 },
    04177     { "v4",             UUID_KEYS_V4 },
    04178     { "v5",             UUID_KEYS_V5 },
    04179 };
    04180 /*@unchecked@*/
    04181 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]);
    04182
    04185 static int
    04186 keyCmp(const void * a, const void * b)
    04187         /*@*/
    04188 {
    04189     return strcmp(((KEY *)a)->name, ((KEY *)b)->name);
    04190 }
    04191
    04194 static rpmuint32_t
    04195 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name)
    04196         /*@*/
    04197 {
    04198     rpmuint32_t keyval = 0;
    04199
    04200     if (name && * name) {
    04201         KEY needle = { .name = name, .value = 0 };
    04202         KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp);
    04203         if (k)
    04204             keyval = k->value;
    04205     }
    04206     return keyval;
    04207 }
    04208
    04215 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av)
    04216         /*@*/
    04217 {
    04218     int ix = (he->ix > 0 ? he->ix : 0);
    04219     char * val = NULL;
    04220     size_t ns;
    04221
    04222 assert(ix == 0);
    04223     switch(he->t) {
    04224     default:
    04225         val = xstrdup(_("(invalid type :digest)"));
    04226         goto exit;
    04227         /*@notreached@*/ break;
    04228     case RPM_UINT64_TYPE:
    04229         ns = sizeof(he->p.ui64p[0]);
    04230         break;
    04231     case RPM_STRING_TYPE:
    04232         ns = strlen(he->p.str);
    04233         break;
    04234     case RPM_BIN_TYPE:
    04235         ns = he->c;
    04236         break;
    04237     }
    04238
    04239 assert(he->p.ptr != NULL);
    04240     {   rpmuint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL));
    04241         rpmuint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1);
    04242         DIGEST_CTX ctx = rpmDigestInit(algo, 0);
    04243         int xx = rpmDigestUpdate(ctx, he->p.ptr, ns);
    04244         xx = rpmDigestFinal(ctx, &val, NULL, 1);
    04245     }
    04246
    04247 exit:
    04248     return val;
    04249 }
    04250
    04257 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av)
    04258         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    04259         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
    04260 {
    04261 /*@-nullassign@*/
    04262     /*@unchecked@*/ /*@observer@*/
    04263     static const char *avdefault[] = { "mode", NULL };
    04264 /*@=nullassign@*/
    04265     const char * fn = NULL;
    04266     struct stat sb, *st = &sb;
    04267     int ix = (he->ix > 0 ? he->ix : 0);
    04268     char * val = NULL;
    04269     int xx;
    04270     int i;
    04271
    04272     memset(st, 0, sizeof(*st));
    04273 assert(ix == 0);
    04274     switch(he->t) {
    04275     case RPM_BIN_TYPE:
    04276         /* XXX limit to RPMTAG_PACKAGESTAT ... */
    04277         if (he->tag == RPMTAG_PACKAGESTAT)
    04278         if ((size_t)he->c == sizeof(*st)) {
    04279             st = (struct stat *)he->p.ptr;
    04280             break;
    04281         }
    04282         /*@fallthrough @*/
    04283     default:
    04284         val = xstrdup(_("(invalid type :stat)"));
    04285         goto exit;
    04286         /*@notreached@*/ break;
    04287     case RPM_STRING_TYPE:
    04288         fn = he->p.str;
    04289         if (Lstat(fn, st) == 0)
    04290             break;
    04291 /*@-ownedtrans@*/
    04292         val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL);
    04293 /*@=ownedtrans@*/
    04294         goto exit;
    04295         /*@notreached@*/ break;
    04296     }
    04297
    04298     if (!(av && av[0] && *av[0]))
    04299         av = avdefault;
    04300     for (i = 0; av[i] != NULL; i++) {
    04301         char b[BUFSIZ];
    04302         size_t nb = sizeof(b);
    04303         char * nval;
    04304         rpmuint32_t keyval = keyValue(keyStat, nkeyStat, av[i]);
    04305
    04306         nval = NULL;
    04307         b[0] = '\0';
    04308         switch (keyval) {
    04309         default:
    04310             /*@switchbreak@*/ break;
    04311         case STAT_KEYS_NONE:
    04312             /*@switchbreak@*/ break;
    04313         case STAT_KEYS_DEV:
    04314             xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev);
    04315             /*@switchbreak@*/ break;
    04316         case STAT_KEYS_INO:
    04317             xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino);
    04318             /*@switchbreak@*/ break;
    04319         case STAT_KEYS_MODE:
    04320             xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode);
    04321             /*@switchbreak@*/ break;
    04322         case STAT_KEYS_NLINK:
    04323             xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink);
    04324             /*@switchbreak@*/ break;
    04325         case STAT_KEYS_UID:
    04326             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid);
    04327             /*@switchbreak@*/ break;
    04328         case STAT_KEYS_GID:
    04329             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid);
    04330             /*@switchbreak@*/ break;
    04331         case STAT_KEYS_RDEV:
    04332             xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev);
    04333             /*@switchbreak@*/ break;
    04334         case STAT_KEYS_SIZE:
    04335             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size);
    04336             /*@switchbreak@*/ break;
    04337         case STAT_KEYS_BLKSIZE:
    04338             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize);
    04339             /*@switchbreak@*/ break;
    04340         case STAT_KEYS_BLOCKS:
    04341             xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks);
    04342             /*@switchbreak@*/ break;
    04343         case STAT_KEYS_ATIME:
    04344 /*@i@*/     (void) stpcpy(b, ctime((time_t *)&st->st_atime));
    04345             /*@switchbreak@*/ break;
    04346         case STAT_KEYS_CTIME:
    04347 /*@i@*/     (void) stpcpy(b, ctime((time_t *)&st->st_ctime));
    04348             /*@switchbreak@*/ break;
    04349         case STAT_KEYS_MTIME:
    04350 /*@i@*/     (void) stpcpy(b, ctime((time_t *)&st->st_mtime));
    04351             /*@switchbreak@*/ break;
    04352 #ifdef  NOTYET
    04353         case STAT_KEYS_FLAGS:
    04354             /*@switchbreak@*/ break;
    04355 #endif
    04356         case STAT_KEYS_SLINK:
    04357             if (fn != NULL && S_ISLNK(st->st_mode)) {
    04358                 ssize_t size = Readlink(fn, b, nb);
    04359                 if (size == -1) {
    04360                     nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL);
    04361                     (void) stpcpy(b, nval);
    04362                     nval = _free(nval);
    04363                 } else
    04364                     b[size] = '\0';
    04365             }
    04366             /*@switchbreak@*/ break;
    04367         case STAT_KEYS_DIGEST:
    04368             if (fn != NULL && S_ISREG(st->st_mode)) {
    04369                 rpmuint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]);
    04370                 rpmuint32_t algo = (digval ? digval : PGPHASHALGO_SHA1);
    04371                 FD_t fd = Fopen(fn, "r%{?_rpmgio}");
    04372                 if (fd == NULL || Ferror(fd)) {
    04373                     nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL);
    04374                 } else {
    04375                     static int asAscii = 1;
    04376                     char buffer[16 * 1024];
    04377                     fdInitDigest(fd, algo, 0);
    04378                     while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
    04379                         {};
    04380                     if (Ferror(fd))
    04381                         nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL);
    04382                     else
    04383                         fdFiniDigest(fd, algo, &nval, NULL, asAscii);
    04384             }
    04385                 if (nval) {
    04386                     (void) stpcpy(b, nval);
    04387                     nval = _free(nval);
    04388                 }
    04389                 if (fd != NULL)
    04390                     xx = Fclose(fd);
    04391             }
    04392             /*@switchbreak@*/ break;
    04393         case STAT_KEYS_UNAME:
    04394         {   const char * uname = uidToUname(st->st_uid);
    04395             if (uname != NULL)
    04396                 (void) stpcpy(b, uname);
    04397             else
    04398                 xx = snprintf(b, nb, "%u", (unsigned)st->st_uid);
    04399         }   /*@switchbreak@*/ break;
    04400         case STAT_KEYS_GNAME:
    04401         {   const char * gname = gidToGname(st->st_gid);
    04402             if (gname != NULL)
    04403                 (void) stpcpy(b, gname);
    04404             else
    04405                 xx = snprintf(b, nb, "%u", (unsigned)st->st_gid);
    04406         }   /*@switchbreak@*/ break;
    04407         }
    04408         if (b[0] == '\0')
    04409             continue;
    04410         b[nb-1] = '\0';
    04411
    04412         if (val == NULL)
    04413             val = xstrdup(b);
    04414         else {
    04415             nval = rpmExpand(val, " | ", b, NULL);
    04416             val = _free(val);
    04417             val = nval;
    04418         }
    04419     }
    04420
    04421 exit:
    04422     return val;
    04423 }
    04424
    04431 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av)
    04432         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    04433         /*@modifies rpmGlobalMacroContext, internalState @*/
    04434 {
    04435 /*@-nullassign@*/
    04436     /*@unchecked@*/ /*@observer@*/
    04437     static const char *avdefault[] = { "v5", NULL };
    04438 /*@=nullassign@*/
    04439     rpmuint32_t version = 0;
    04440     int ix = (he->ix > 0 ? he->ix : 0);
    04441     char * val = NULL;
    04442     int i;
    04443
    04444 assert(ix == 0);
    04445     switch(he->t) {
    04446     default:
    04447         val = xstrdup(_("(invalid type :uuid)"));
    04448         goto exit;
    04449         /*@notreached@*/ break;
    04450     case RPM_STRING_TYPE:
    04451         break;
    04452     }
    04453
    04454     if (!(av && av[0] && *av[0]))
    04455         av = avdefault;
    04456
    04457     for (i = 0; av[i] != NULL; i++) {
    04458         rpmuint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]);
    04459
    04460         switch (keyval) {
    04461         default:
    04462             /*@switchbreak@*/ break;
    04463         case UUID_KEYS_V1:
    04464         case UUID_KEYS_V3:
    04465         case UUID_KEYS_V4:
    04466         case UUID_KEYS_V5:
    04467             version = keyval;
    04468             /*@switchbreak@*/ break;
    04469         }
    04470     }
    04471
    04472     /* XXX use private tag container to avoid memory issues for now. */
    04473     {   HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
    04474         int xx;
    04475         nhe->tag = he->tag;
    04476         nhe->t = he->t;
    04477         nhe->p.str = xstrdup(he->p.str);
    04478         nhe->c = he->c;
    04479         val = xmalloc((128/4 + 4) + 1);
    04480         *val = '\0';
    04481         xx = str2uuid(nhe, NULL, version, val);
    04482         nhe->p.ptr = _free(nhe->p.ptr);
    04483     }
    04484
    04485 exit:
    04486     return val;
    04487 }
    04488
    04495 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av)
    04496         /*@*/
    04497 {
    04498     int ac = argvCount(av) + 1;
    04499     int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack)));
    04500     char * end;
    04501     char * val = NULL;
    04502     int ix = 0;
    04503     int i;
    04504
    04505     switch(he->t) {
    04506     default:
    04507         val = xstrdup(_("(invalid type :rpn)"));
    04508         goto exit;
    04509         /*@notreached@*/ break;
    04510     case RPM_UINT64_TYPE:
    04511         stack[ix] = he->p.ui64p[0];
    04512         break;
    04513     case RPM_STRING_TYPE:
    04514         end = NULL;
    04515 /*@-unrecog@*/  /* Add annotated prototype. */
    04516         stack[ix] = strtoll(he->p.str, &end, 0);
    04517 /*@=unrecog@*/
    04518         if (end && *end != '\0') {
    04519             val = xstrdup(_("(invalid string :rpn)"));
    04520             goto exit;
    04521         }
    04522         break;
    04523     }
    04524
    04525     if (av != NULL)
    04526     for (i = 0; av[i] != NULL; i++) {
    04527         const char * arg = av[i];
    04528         size_t len = strlen(arg);
    04529         int c = (int) *arg;
    04530
    04531         if (len == 0) {
    04532             /* do nothing */
    04533         } else if (len > 1) {
    04534             if (!(xisdigit(c) || (c == (int)'-' && xisdigit((int) arg[1])))) {
    04535                 val = xstrdup(_("(expected number :rpn)"));
    04536                 goto exit;
    04537             }
    04538             if (++ix == ac) {
    04539                 val = xstrdup(_("(stack overflow :rpn)"));
    04540                 goto exit;
    04541             }
    04542             end = NULL;
    04543             stack[ix] = strtoll(arg, &end, 0);
    04544             if (end && *end != '\0') {
    04545                 val = xstrdup(_("(invalid number :rpn)"));
    04546                 goto exit;
    04547             }
    04548         } else {
    04549             if (ix-- < 1) {
    04550                 val = xstrdup(_("(stack underflow :rpn)"));
    04551                 goto exit;
    04552             }
    04553             switch (c) {
    04554             case '&':   stack[ix] &= stack[ix+1];       /*@switchbreak@*/ break;
    04555             case '|':   stack[ix] |= stack[ix+1];       /*@switchbreak@*/ break;
    04556             case '^':   stack[ix] ^= stack[ix+1];       /*@switchbreak@*/ break;
    04557             case '+':   stack[ix] += stack[ix+1];       /*@switchbreak@*/ break;
    04558             case '-':   stack[ix] -= stack[ix+1];       /*@switchbreak@*/ break;
    04559             case '*':   stack[ix] *= stack[ix+1];       /*@switchbreak@*/ break;
    04560             case '%':
    04561             case '/':
    04562                 if (stack[ix+1] == 0) {
    04563                     val = xstrdup(_("(divide by zero :rpn)"));
    04564                     goto exit;
    04565                 }
    04566                 if (c == (int)'%')
    04567                     stack[ix] %= stack[ix+1];
    04568                 else
    04569                     stack[ix] /= stack[ix+1];
    04570                 /*@switchbreak@*/ break;
    04571             }
    04572         }
    04573     }
    04574
    04575     {   HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
    04576         nhe->tag = he->tag;
    04577         nhe->t = RPM_UINT64_TYPE;
    04578         nhe->p.ui64p = (rpmuint64_t *)&stack[ix];
    04579         nhe->c = 1;
    04580         val = intFormat(nhe, NULL, NULL);
    04581     }
    04582
    04583 exit:
    04584     return val;
    04585 }
    04586
    04593 static /*@only@*/ char * strsubFormat(HE_t he, /*@null@*/ const char ** av)
    04594         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    04595         /*@modifies rpmGlobalMacroContext, internalState @*/
    04596 {
    04597     char * val = NULL;
    04598     int ac = argvCount(av);
    04599     miRE mires = NULL;
    04600     int nmires = 0;
    04601     int xx;
    04602     int i;
    04603
    04604     switch(he->t) {
    04605     default:
    04606         val = xstrdup(_("(invalid type :strsub)"));
    04607         goto exit;
    04608         /*@notreached@*/ break;
    04609     case RPM_STRING_TYPE:
    04610         if (ac < 2 || (ac % 2) != 0) {
    04611             val = xstrdup(_("(invalid args :strsub)"));
    04612             goto exit;
    04613         }
    04614         break;
    04615     }
    04616     if (av == NULL)
    04617         goto noop;
    04618
    04619     /* Create the mire pattern array. */
    04620     for (i = 0; av[i] != NULL; i += 2)
    04621         xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mires, &nmires);
    04622
    04623     /* Find-and-replace first pattern that matches. */
    04624     if (mires != NULL) {
    04625         int noffsets = 3;
    04626         int offsets[3];
    04627         const char * s, * se;
    04628         char * t, * te;
    04629         char * nval;
    04630         size_t slen;
    04631         size_t nb;
    04632
    04633         for (i = 0; i < nmires; i++) {
    04634             miRE mire = mires + i;
    04635
    04636             s = he->p.str;
    04637             slen = strlen(s);
    04638             if ((xx = mireRegexec(mire, s, slen)) < 0)
    04639                 continue;
    04640             xx = mireSetEOptions(mire, offsets, noffsets);
    04641
    04642             /* Replace the string(s). This is just s/find/replace/g */
    04643             val = xstrdup("");
    04644             while (*s != '\0') {
    04645                 nb = strlen(s);
    04646                 if ((se = strchr(s, '\n')) == NULL)
    04647                     se = s + nb;
    04648                 else
    04649                     se++;
    04650
    04651                 offsets[0] = offsets[1] = -1;
    04652                 xx = mireRegexec(mire, s, nb);
    04653
    04654                 nb = 1;
    04655                 /* On match, copy lead-in and match string. */
    04656                 if (xx == 0)
    04657                     nb += offsets[0] + strlen(av[2*i+1]);
    04658                 /* Copy up to EOL on nomatch or insertion. */
    04659                 if (xx != 0 || offsets[1] == offsets[0])
    04660                     nb += (se - (s + offsets[1]));
    04661
    04662                 te = t = xmalloc(nb);
    04663
    04664                 /* On match, copy lead-in and match string. */
    04665                 if (xx == 0) {
    04666                     te = stpcpy( stpncpy(te, s, offsets[0]), av[2*i+1]);
    04667                     s += offsets[1];
    04668                 }
    04669                 /* Copy up to EOL on nomatch or insertion. */
    04670                 if (xx != 0 || offsets[1] == offsets[0]) {
    04671                     s += offsets[1];
    04672                     te = stpncpy(te, s, (se - s));
    04673                     s = se;
    04674                 }
    04675                 *te = '\0';
    04676
    04677                 nval = rpmExpand(val, t, NULL);
    04678                 val = _free(val);
    04679                 val = nval;
    04680                 t = _free(t);
    04681             }
    04682         }
    04683         mires = mireFreeAll(mires, nmires);
    04684     }
    04685
    04686 noop:
    04687     if (val == NULL)
    04688         val = xstrdup(he->p.str);
    04689 exit:
    04690     return val;
    04691 }
    04692
    04693 static struct headerSprintfExtension_s _headerCompoundFormats[] = {
    04694     { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID",
    04695         { .tagFunction = buildtime_uuidTag } },
    04696     { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME",
    04697         { .tagFunction = changelognameTag } },
    04698     { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT",
    04699         { .tagFunction = changelogtextTag } },
    04700     { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",
    04701         { .tagFunction = descriptionTag } },
    04702     { HEADER_EXT_TAG, "RPMTAG_GROUP",
    04703         { .tagFunction = groupTag } },
    04704     { HEADER_EXT_TAG, "RPMTAG_HDRUUID",
    04705         { .tagFunction = hdruuidTag } },
    04706     { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",
    04707         { .tagFunction = instprefixTag } },
    04708     { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID",
    04709         { .tagFunction = installtid_uuidTag } },
    04710     { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID",
    04711         { .tagFunction = installtime_uuidTag } },
    04712     { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID",
    04713         { .tagFunction = origintid_uuidTag } },
    04714     { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID",
    04715         { .tagFunction = origintime_uuidTag } },
    04716     { HEADER_EXT_TAG, "RPMTAG_PKGUUID",
    04717         { .tagFunction = pkguuidTag } },
    04718     { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID",
    04719         { .tagFunction = removetid_uuidTag } },
    04720     { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID",
    04721         { .tagFunction = sourcepkguuidTag } },
    04722     { HEADER_EXT_TAG, "RPMTAG_SUMMARY",
    04723         { .tagFunction = summaryTag } },
    04724     { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",
    04725         { .tagFunction = triggercondsTag } },
    04726     { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",
    04727         { .tagFunction = triggertypeTag } },
    04728     { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE",
    04729         { .tagFunction = dbinstanceTag } },
    04730     { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF",
    04731         { .tagFunction = headerstartoffTag } },
    04732     { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF",
    04733         { .tagFunction = headerendoffTag } },
    04734     { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL",
    04735         { .tagFunction = pkgbaseurlTag } },
    04736     { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST",
    04737         { .tagFunction = pkgdigestTag } },
    04738     { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN",
    04739         { .tagFunction = pkgoriginTag } },
    04740     { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE",
    04741         { .tagFunction = pkgsizeTag } },
    04742     { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME",
    04743         { .tagFunction = pkgmtimeTag } },
    04744     { HEADER_EXT_TAG, "RPMTAG_NVRA",
    04745         { .tagFunction = nvraTag } },
    04746     { HEADER_EXT_TAG, "RPMTAG_FILENAMES",
    04747         { .tagFunction = filenamesTag } },
    04748     { HEADER_EXT_TAG, "RPMTAG_FILEPATHS",
    04749         { .tagFunction = filepathsTag } },
    04750     { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS",
    04751         { .tagFunction = origpathsTag } },
    04752     { HEADER_EXT_TAG, "RPMTAG_FILESTAT",
    04753         { .tagFunction = filestatTag } },
    04754     { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY",
    04755         { .tagFunction = PxmlTag } },
    04756     { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY",
    04757         { .tagFunction = RxmlTag } },
    04758     { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY",
    04759         { .tagFunction = CxmlTag } },
    04760     { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY",
    04761         { .tagFunction = OxmlTag } },
    04762     { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1",
    04763         { .tagFunction = F1xmlTag } },
    04764     { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2",
    04765         { .tagFunction = F2xmlTag } },
    04766     { HEADER_EXT_TAG, "RPMTAG_PROVIDEYAMLENTRY",
    04767         { .tagFunction = PyamlTag } },
    04768     { HEADER_EXT_TAG, "RPMTAG_REQUIREYAMLENTRY",
    04769         { .tagFunction = RyamlTag } },
    04770     { HEADER_EXT_TAG, "RPMTAG_CONFLICTYAMLENTRY",
    04771         { .tagFunction = CyamlTag } },
    04772     { HEADER_EXT_TAG, "RPMTAG_OBSOLETEYAMLENTRY",
    04773         { .tagFunction = OyamlTag } },
    04774     { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY1",
    04775         { .tagFunction = F1yamlTag } },
    04776     { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY2",
    04777         { .tagFunction = F2yamlTag } },
    04778     { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY",
    04779         { .tagFunction = PsqlTag } },
    04780     { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY",
    04781         { .tagFunction = RsqlTag } },
    04782     { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY",
    04783         { .tagFunction = CsqlTag } },
    04784     { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY",
    04785         { .tagFunction = OsqlTag } },
    04786     { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1",
    04787         { .tagFunction = F1sqlTag } },
    04788     { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2",
    04789         { .tagFunction = F2sqlTag } },
    04790     { HEADER_EXT_TAG, "RPMTAG_DEBCONFLICTS",
    04791         { .tagFunction = debconflictsTag } },
    04792     { HEADER_EXT_TAG, "RPMTAG_DEBDEPENDS",
    04793         { .tagFunction = debdependsTag } },
    04794     { HEADER_EXT_TAG, "RPMTAG_DEBMD5SUMS",
    04795         { .tagFunction = debmd5sumsTag } },
    04796     { HEADER_EXT_TAG, "RPMTAG_DEBOBSOLETES",
    04797         { .tagFunction = debobsoletesTag } },
    04798     { HEADER_EXT_TAG, "RPMTAG_DEBPROVIDES",
    04799         { .tagFunction = debprovidesTag } },
    04800     { HEADER_EXT_TAG, "RPMTAG_NEEDSWHAT",
    04801         { .tagFunction = needswhatTag } },
    04802     { HEADER_EXT_TAG, "RPMTAG_WHATNEEDS",
    04803         { .tagFunction = whatneedsTag } },
    04804     { HEADER_EXT_FORMAT, "armor",
    04805         { .fmtFunction = armorFormat } },
    04806     { HEADER_EXT_FORMAT, "base64",
    04807         { .fmtFunction = base64Format } },
    04808     { HEADER_EXT_FORMAT, "bncdata",
    04809         { .fmtFunction = bncdataFormat } },
    04810     { HEADER_EXT_FORMAT, "cdata",
    04811         { .fmtFunction = cdataFormat } },
    04812     { HEADER_EXT_FORMAT, "depflags",
    04813         { .fmtFunction = depflagsFormat } },
    04814     { HEADER_EXT_FORMAT, "deptype",
    04815         { .fmtFunction = deptypeFormat } },
    04816     { HEADER_EXT_FORMAT, "digest",
    04817         { .fmtFunction = digestFormat } },
    04818     { HEADER_EXT_FORMAT, "fflags",
    04819         { .fmtFunction = fflagsFormat } },
    04820     { HEADER_EXT_FORMAT, "iconv",
    04821         { .fmtFunction = iconvFormat } },
    04822     { HEADER_EXT_FORMAT, "perms",
    04823         { .fmtFunction = permsFormat } },
    04824     { HEADER_EXT_FORMAT, "permissions",
    04825         { .fmtFunction = permsFormat } },
    04826     { HEADER_EXT_FORMAT, "pgpsig",
    04827         { .fmtFunction = pgpsigFormat } },
    04828     { HEADER_EXT_FORMAT, "rpn",
    04829         { .fmtFunction = rpnFormat } },
    04830     { HEADER_EXT_FORMAT, "sqlescape",
    04831         { .fmtFunction = sqlescapeFormat } },
    04832     { HEADER_EXT_FORMAT, "stat",
    04833         { .fmtFunction = statFormat } },
    04834     { HEADER_EXT_FORMAT, "strsub",
    04835         { .fmtFunction = strsubFormat } },
    04836     { HEADER_EXT_FORMAT, "triggertype",
    04837         { .fmtFunction = triggertypeFormat } },
    04838     { HEADER_EXT_FORMAT, "utf8",
    04839         { .fmtFunction = iconvFormat } },
    04840     { HEADER_EXT_FORMAT, "uuid",
    04841         { .fmtFunction = uuidFormat } },
    04842     { HEADER_EXT_FORMAT, "xml",
    04843         { .fmtFunction = xmlFormat } },
    04844     { HEADER_EXT_FORMAT, "yaml",
    04845         { .fmtFunction = yamlFormat } },
    04846     { HEADER_EXT_MORE, NULL,            { (void *) &headerDefaultFormats } }
    04847 } ;
    04848
    04849 headerSprintfExtension headerCompoundFormats = &_headerCompoundFormats[0];
    04850
    04851 /*====================================================================*/
    04852
    04853 void rpmDisplayQueryTags(FILE * fp, headerTagTableEntry _rpmTagTable, headerSprintfExtension _rpmHeaderFormats)
    04854 {
    04855     const struct headerTagTableEntry_s * t;
    04856     headerSprintfExtension exts;
    04857     headerSprintfExtension ext;
    04858     int extNum;
    04859
    04860     if (fp == NULL)
    04861         fp = stdout;
    04862     if (_rpmTagTable == NULL)
    04863         _rpmTagTable = rpmTagTable;
    04864
    04865     /* XXX this should use rpmHeaderFormats, but there are linkage problems. */
    04866     if (_rpmHeaderFormats == NULL)
    04867         _rpmHeaderFormats = headerCompoundFormats;
    04868
    04869     for (t = _rpmTagTable; t && t->name; t++) {
    04870         /*@observer@*/
    04871         static const char * tagtypes[] = {
    04872                 "", "char", "uint8", "uint16", "uint32", "uint64",
    04873                 "string", "octets", "argv", "i18nstring",
    04874         };
    04875         rpmuint32_t ttype;
    04876
    04877         if (rpmIsVerbose()) {
    04878             fprintf(fp, "%-20s %6d", t->name + 7, t->val);
    04879             ttype = t->type & RPM_MASK_TYPE;
    04880             if (ttype < RPM_MIN_TYPE || ttype > RPM_MAX_TYPE)
    04881                 continue;
    04882             if (t->type & RPM_OPENPGP_RETURN_TYPE)
    04883                 fprintf(fp, " openpgp");
    04884             if (t->type & RPM_X509_RETURN_TYPE)
    04885                 fprintf(fp, " x509");
    04886             if (t->type & RPM_ASN1_RETURN_TYPE)
    04887                 fprintf(fp, " asn1");
    04888             if (t->type & RPM_OPAQUE_RETURN_TYPE)
    04889                 fprintf(fp, " opaque");
    04890             fprintf(fp, " %s", tagtypes[ttype]);
    04891             if (t->type & RPM_ARRAY_RETURN_TYPE)
    04892                 fprintf(fp, " array");
    04893             if (t->type & RPM_MAPPING_RETURN_TYPE)
    04894                 fprintf(fp, " mapping");
    04895             if (t->type & RPM_PROBE_RETURN_TYPE)
    04896                 fprintf(fp, " probe");
    04897             if (t->type & RPM_TREE_RETURN_TYPE)
    04898                 fprintf(fp, " tree");
    04899         } else
    04900             fprintf(fp, "%s", t->name + 7);
    04901         fprintf(fp, "\n");
    04902     }
    04903
    04904     exts = _rpmHeaderFormats;
    04905     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
    04906         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
    04907     {
    04908         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
    04909             continue;
    04910
    04911         /* XXX don't print header tags twice. */
    04912         if (tagValue(ext->name) > 0)
    04913             continue;
    04914         fprintf(fp, "%s\n", ext->name + 7);
    04915     }
    04916 }
    04917
    04918 /*====================================================================*/
    04919
    04920 #define PARSER_BEGIN    0
    04921 #define PARSER_IN_ARRAY 1
    04922 #define PARSER_IN_EXPR  2
    04923
    04926 typedef /*@abstract@*/ struct sprintfTag_s * sprintfTag;
    04927
    04930 struct sprintfTag_s {
    04931     HE_s he;
    04932 /*@null@*/
    04933     headerTagFormatFunction * fmtfuncs;
    04934 /*@null@*/
    04935     headerTagTagFunction ext;
    04936     int extNum;
    04937 /*@only@*/ /*@relnull@*/
    04938     rpmTag * tagno;
    04939     int justOne;
    04940     int arrayCount;
    04941 /*@kept@*/
    04942     char * format;
    04943 /*@only@*/ /*@relnull@*/
    04944     ARGV_t av;
    04945 /*@only@*/ /*@relnull@*/
    04946     ARGV_t params;
    04947     unsigned pad;
    04948 };
    04949
    04952 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken;
    04953
    04956 struct sprintfToken_s {
    04957     enum {
    04958         PTOK_NONE       = 0,
    04959         PTOK_TAG        = 1,
    04960         PTOK_ARRAY      = 2,
    04961         PTOK_STRING     = 3,
    04962         PTOK_COND       = 4
    04963     } type;
    04964     union {
    04965         struct sprintfTag_s tag;
    04966         struct {
    04967         /*@only@*/
    04968             sprintfToken format;
    04969             size_t numTokens;
    04970         } array;
    04971         struct {
    04972         /*@dependent@*/
    04973             char * string;
    04974             size_t len;
    04975         } string;
    04976         struct {
    04977         /*@only@*/ /*@null@*/
    04978             sprintfToken ifFormat;
    04979             size_t numIfTokens;
    04980         /*@only@*/ /*@null@*/
    04981             sprintfToken elseFormat;
    04982             size_t numElseTokens;
    04983             struct sprintfTag_s tag;
    04984         } cond;
    04985     } u;
    04986 };
    04987
    04990 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs;
    04991
    04994 struct headerSprintfArgs_s {
    04995     Header h;
    04996     char * fmt;
    04997 /*@observer@*/ /*@temp@*/
    04998     headerTagTableEntry tags;
    04999 /*@observer@*/ /*@temp@*/
    05000     headerSprintfExtension exts;
    05001 /*@observer@*/ /*@null@*/
    05002     const char * errmsg;
    05003     HE_t ec;
    05004     int nec;
    05005     sprintfToken format;
    05006 /*@relnull@*/
    05007     HeaderIterator hi;
    05008 /*@owned@*/
    05009     char * val;
    05010     size_t vallen;
    05011     size_t alloced;
    05012     size_t numTokens;
    05013     size_t i;
    05014 };
    05015
    05016 /*@access sprintfTag @*/
    05017 /*@access sprintfToken @*/
    05018 /*@access headerSprintfArgs @*/
    05019
    05022 static char escapedChar(const char ch)
    05023         /*@*/
    05024 {
    05025 /*@-modfilesys@*/
    05026 if (_hdrqf_debug)
    05027 fprintf(stderr, "\t\t\\%c\n", ch);
    05028 /*@=modfilesys@*/
    05029     switch (ch) {
    05030     case 'a':   return '\a';
    05031     case 'b':   return '\b';
    05032     case 'f':   return '\f';
    05033     case 'n':   return '\n';
    05034     case 'r':   return '\r';
    05035     case 't':   return '\t';
    05036     case 'v':   return '\v';
    05037     default:    return ch;
    05038     }
    05039 }
    05040
    05045 /*@relnull@*/
    05046 static HE_t rpmheClean(/*@returned@*/ /*@null@*/ HE_t he)
    05047         /*@modifies he @*/
    05048 {
    05049     if (he) {
    05050         if (he->freeData && he->p.ptr != NULL)
    05051             he->p.ptr = _free(he->p.ptr);
    05052         memset(he, 0, sizeof(*he));
    05053     }
    05054     return he;
    05055 }
    05056
    05063 static /*@null@*/ sprintfToken
    05064 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, size_t num)
    05065         /*@modifies *format @*/
    05066 {
    05067     unsigned i;
    05068
    05069     if (format == NULL) return NULL;
    05070
    05071     for (i = 0; i < (unsigned) num; i++) {
    05072         switch (format[i].type) {
    05073         case PTOK_TAG:
    05074             (void) rpmheClean(&format[i].u.tag.he);
    05075             format[i].u.tag.tagno = _free(format[i].u.tag.tagno);
    05076             format[i].u.tag.av = argvFree(format[i].u.tag.av);
    05077             format[i].u.tag.params = argvFree(format[i].u.tag.params);
    05078 /*@-type@*/
    05079             format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs);
    05080 /*@=type@*/
    05081             /*@switchbreak@*/ break;
    05082         case PTOK_ARRAY:
    05083             format[i].u.array.format =
    05084                 freeFormat(format[i].u.array.format,
    05085                         format[i].u.array.numTokens);
    05086             /*@switchbreak@*/ break;
    05087         case PTOK_COND:
    05088             format[i].u.cond.ifFormat =
    05089                 freeFormat(format[i].u.cond.ifFormat,
    05090                         format[i].u.cond.numIfTokens);
    05091             format[i].u.cond.elseFormat =
    05092                 freeFormat(format[i].u.cond.elseFormat,
    05093                         format[i].u.cond.numElseTokens);
    05094             (void) rpmheClean(&format[i].u.cond.tag.he);
    05095             format[i].u.cond.tag.tagno = _free(format[i].u.cond.tag.tagno);
    05096             format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av);
    05097             format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params);
    05098 /*@-type@*/
    05099             format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs);
    05100 /*@=type@*/
    05101             /*@switchbreak@*/ break;
    05102         case PTOK_NONE:
    05103         case PTOK_STRING:
    05104         default:
    05105             /*@switchbreak@*/ break;
    05106         }
    05107     }
    05108     format = _free(format);
    05109     return NULL;
    05110 }
    05111
    05117 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
    05118         /*@globals fileSystem @*/
    05119         /*@modifies hsa, fileSystem @*/
    05120 {
    05121     sprintfTag tag =
    05122         (hsa->format->type == PTOK_TAG
    05123             ? &hsa->format->u.tag :
    05124         (hsa->format->type == PTOK_ARRAY
    05125             ? &hsa->format->u.array.format->u.tag :
    05126         NULL));
    05127
    05128     if (hsa != NULL) {
    05129         hsa->i = 0;
    05130         if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2)
    05131             hsa->hi = headerInit(hsa->h);
    05132     }
    05133 /*@-nullret@*/
    05134     return hsa;
    05135 /*@=nullret@*/
    05136 }
    05137
    05143 /*@null@*/
    05144 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
    05145         /*@globals internalState @*/
    05146         /*@modifies hsa, internalState @*/
    05147 {
    05148     sprintfToken fmt = NULL;
    05149     sprintfTag tag =
    05150         (hsa->format->type == PTOK_TAG
    05151             ? &hsa->format->u.tag :
    05152         (hsa->format->type == PTOK_ARRAY
    05153             ? &hsa->format->u.array.format->u.tag :
    05154         NULL));
    05155
    05156     if (hsa != NULL && hsa->i < hsa->numTokens) {
    05157         fmt = hsa->format + hsa->i;
    05158         if (hsa->hi == NULL) {
    05159             hsa->i++;
    05160         } else {
    05161             HE_t he = rpmheClean(&tag->he);
    05162             if (!headerNext(hsa->hi, he, 0))
    05163             {
    05164                 tag->tagno[0] = 0;
    05165                 return NULL;
    05166             }
    05167             he->avail = 1;
    05168             tag->tagno[0] = he->tag;
    05169         }
    05170     }
    05171
    05172 /*@-dependenttrans -onlytrans@*/
    05173     return fmt;
    05174 /*@=dependenttrans =onlytrans@*/
    05175 }
    05176
    05182 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
    05183         /*@globals fileSystem @*/
    05184         /*@modifies hsa, fileSystem @*/
    05185 {
    05186     if (hsa != NULL) {
    05187         hsa->hi = headerFini(hsa->hi);
    05188         hsa->i = 0;
    05189     }
    05190 /*@-nullret@*/
    05191     return hsa;
    05192 /*@=nullret@*/
    05193 }
    05194
    05201 /*@dependent@*/ /*@exposed@*/
    05202 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
    05203         /*@modifies hsa */
    05204 {
    05205     if ((hsa->vallen + need) >= hsa->alloced) {
    05206         if (hsa->alloced <= need)
    05207             hsa->alloced += need;
    05208         hsa->alloced <<= 1;
    05209         hsa->val = xrealloc(hsa->val, hsa->alloced+1);
    05210     }
    05211     return hsa->val + hsa->vallen;
    05212 }
    05213
    05221 /*@observer@*/ /*@null@*/
    05222 static const char * myTagName(headerTagTableEntry tbl, rpmuint32_t val,
    05223                 /*@null@*/ rpmuint32_t *typep)
    05224         /*@modifies *typep @*/
    05225 {
    05226     static char name[128];      /* XXX Ick. */
    05227     const char * s;
    05228     char *t;
    05229
    05230     /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
    05231     if (tbl == NULL || tbl == rpmTagTable) {
    05232         s = tagName(val);
    05233         if (s != NULL && typep != NULL)
    05234             *typep = tagType(val);
    05235         return s;
    05236     }
    05237
    05238     for (; tbl->name != NULL; tbl++) {
    05239         if (tbl->val == val)
    05240             break;
    05241     }
    05242     if ((s = tbl->name) == NULL)
    05243         return NULL;
    05244     s += sizeof("RPMTAG_") - 1;
    05245     t = name;
    05246     *t++ = *s++;
    05247     while (*s != '\0')
    05248         *t++ = (char)xtolower((int)*s++);
    05249     *t = '\0';
    05250     if (typep)
    05251         *typep = tbl->type;
    05252     return name;
    05253 }
    05254
    05261 static rpmuint32_t myTagValue(headerTagTableEntry tbl, const char * name)
    05262         /*@*/
    05263 {
    05264     rpmuint32_t val = 0;
    05265
    05266     /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
    05267     if (tbl == NULL || tbl == rpmTagTable)
    05268         val = tagValue(name);
    05269     else
    05270     for (; tbl->name != NULL; tbl++) {
    05271         if (xstrcasecmp(tbl->name, name))
    05272             continue;
    05273         val = tbl->val;
    05274         break;
    05275     }
    05276     return val;
    05277 }
    05278
    05286 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
    05287         /*@modifies token @*/
    05288 {
    05289     headerSprintfExtension exts = hsa->exts;
    05290     headerSprintfExtension ext;
    05291     sprintfTag stag = (token->type == PTOK_COND
    05292         ? &token->u.cond.tag : &token->u.tag);
    05293     int extNum;
    05294     rpmTag tagno = (rpmTag)-1;
    05295
    05296     stag->fmtfuncs = NULL;
    05297     stag->ext = NULL;
    05298     stag->extNum = 0;
    05299
    05300     if (!strcmp(name, "*")) {
    05301         tagno = (rpmTag)-2;
    05302         goto bingo;
    05303     }
    05304
    05305     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
    05306         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
    05307         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
    05308         name = t;
    05309     }
    05310
    05311     /* Search extensions for specific tag override. */
    05312     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
    05313         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
    05314     {
    05315         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
    05316             continue;
    05317         if (!xstrcasecmp(ext->name, name)) {
    05318             stag->ext = ext->u.tagFunction;
    05319             stag->extNum = extNum;
    05320             tagno = tagValue(name);
    05321             goto bingo;
    05322         }
    05323     }
    05324
    05325     /* Search tag names. */
    05326     tagno = myTagValue(hsa->tags, name);
    05327     if (tagno != 0)
    05328         goto bingo;
    05329
    05330     return 1;
    05331
    05332 bingo:
    05333     stag->tagno = xcalloc(1, sizeof(*stag->tagno));
    05334     stag->tagno[0] = tagno;
    05335     /* Search extensions for specific format(s). */
    05336     if (stag->av != NULL) {
    05337         int i;
    05338 /*@-type@*/
    05339         stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs));
    05340 /*@=type@*/
    05341         for (i = 0; stag->av[i] != NULL; i++) {
    05342             for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
    05343                  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1))
    05344             {
    05345                 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
    05346                     /*@innercontinue@*/ continue;
    05347                 if (strcmp(ext->name, stag->av[i]+1))
    05348                     /*@innercontinue@*/ continue;
    05349                 stag->fmtfuncs[i] = ext->u.fmtFunction;
    05350                 /*@innerbreak@*/ break;
    05351             }
    05352         }
    05353     }
    05354     return 0;
    05355 }
    05356
    05357 /* forward ref */
    05366 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
    05367                 char * str, /*@out@*/char ** endPtr)
    05368         /*@modifies hsa, str, token, *endPtr @*/
    05369         /*@requires maxSet(endPtr) >= 0 @*/;
    05370
    05381 static int parseFormat(headerSprintfArgs hsa, char * str,
    05382                 /*@out@*/ sprintfToken * formatPtr,
    05383                 /*@out@*/ size_t * numTokensPtr,
    05384                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
    05385         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
    05386         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
    05387                 /\ maxSet(endPtr) >= 0 @*/
    05388 {
    05389 /*@observer@*/
    05390 static const char *pstates[] = {
    05391 "NORMAL", "ARRAY", "EXPR", "WTF?"
    05392 };
    05393     char * chptr, * start, * next, * dst;
    05394     sprintfToken format;
    05395     sprintfToken token;
    05396     size_t numTokens;
    05397     unsigned i;
    05398     int done = 0;
    05399     int xx;
    05400
    05401 /*@-modfilesys@*/
    05402 if (_hdrqf_debug)
    05403 fprintf(stderr, "-->     parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]);
    05404 /*@=modfilesys@*/
    05405
    05406     /* upper limit on number of individual formats */
    05407     numTokens = 0;
    05408     if (str != NULL)
    05409     for (chptr = str; *chptr != '\0'; chptr++)
    05410         if (*chptr == '%') numTokens++;
    05411     numTokens = numTokens * 2 + 1;
    05412
    05413     format = xcalloc(numTokens, sizeof(*format));
    05414     if (endPtr) *endPtr = NULL;
    05415
    05416 /*@-infloops@*/ /* LCL: can't detect (start, *start) termination */
    05417     dst = start = str;
    05418     numTokens = 0;
    05419     token = NULL;
    05420     if (start != NULL)
    05421     while (*start != '\0') {
    05422         switch (*start) {
    05423         case '%':
    05424             /* handle %% */
    05425             if (*(start + 1) == '%') {
    05426                 if (token == NULL || token->type != PTOK_STRING) {
    05427                     token = format + numTokens++;
    05428                     token->type = PTOK_STRING;
    05429 /*@-temptrans -assignexpose@*/
    05430                     dst = token->u.string.string = start;
    05431 /*@=temptrans =assignexpose@*/
    05432                 }
    05433                 start++;
    05434                 *dst++ = *start++;
    05435                 /*@switchbreak@*/ break;
    05436             }
    05437
    05438             token = format + numTokens++;
    05439             *dst++ = '\0';
    05440             start++;
    05441
    05442             if (*start == '|') {
    05443                 char * newEnd;
    05444
    05445                 start++;
    05446                 if (parseExpression(hsa, token, start, &newEnd))
    05447                 {
    05448                     format = freeFormat(format, numTokens);
    05449                     return 1;
    05450                 }
    05451                 start = newEnd;
    05452                 /*@switchbreak@*/ break;
    05453             }
    05454
    05455 /*@-assignexpose@*/
    05456             token->u.tag.format = start;
    05457 /*@=assignexpose@*/
    05458             token->u.tag.pad = 0;
    05459             token->u.tag.justOne = 0;
    05460             token->u.tag.arrayCount = 0;
    05461
    05462             chptr = start;
    05463             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
    05464             if (!*chptr || *chptr == '%') {
    05465                 hsa->errmsg = _("missing { after %");
    05466                 format = freeFormat(format, numTokens);
    05467                 return 1;
    05468             }
    05469
    05470 /*@-modfilesys@*/
    05471 if (_hdrqf_debug)
    05472 fprintf(stderr, "\tchptr *%p = NUL\n", chptr);
    05473 /*@=modfilesys@*/
    05474             *chptr++ = '\0';
    05475
    05476             while (start < chptr) {
    05477                 if (xisdigit((int)*start)) {
    05478                     i = strtoul(start, &start, 10);
    05479                     token->u.tag.pad += i;
    05480                     start = chptr;
    05481                     /*@innerbreak@*/ break;
    05482                 } else {
    05483                     start++;
    05484                 }
    05485             }
    05486
    05487             if (*start == '=') {
    05488                 token->u.tag.justOne = 1;
    05489                 start++;
    05490             } else if (*start == '#') {
    05491                 token->u.tag.justOne = 1;
    05492                 token->u.tag.arrayCount = 1;
    05493                 start++;
    05494             }
    05495
    05496             next = start;
    05497             while (*next && *next != '}') next++;
    05498             if (!*next) {
    05499                 hsa->errmsg = _("missing } after %{");
    05500                 format = freeFormat(format, numTokens);
    05501                 return 1;
    05502             }
    05503 /*@-modfilesys@*/
    05504 if (_hdrqf_debug)
    05505 fprintf(stderr, "\tnext *%p = NUL\n", next);
    05506 /*@=modfilesys@*/
    05507             *next++ = '\0';
    05508
    05509 #define isSEP(_c)       ((_c) == ':' || (_c) == '|')
    05510             chptr = start;
    05511             while (!(*chptr == '\0' || isSEP(*chptr))) chptr++;
    05512             /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */
    05513             while (isSEP(*chptr)) {
    05514                 if (chptr[1] == '\0' || isSEP(chptr[1])) {
    05515                     hsa->errmsg = _("empty tag format");
    05516                     format = freeFormat(format, numTokens);
    05517                     return 1;
    05518                 }
    05519                 /* Parse the formatter parameter list. */
    05520                 {   char * te = chptr + 1;
    05521                     char * t = strchr(te, '(');
    05522                     char c;
    05523
    05524                     while (!(*te == '\0' || isSEP(*te))) {
    05525 #ifdef  NOTYET  /* XXX some means of escaping is needed */
    05526                         if (te[0] == '\\' && te[1] != '\0') te++;
    05527 #endif
    05528                         te++;
    05529                     }
    05530                     c = *te; *te = '\0';
    05531                     /* Parse (a,b,c) parameter list. */
    05532                     if (t != NULL) {
    05533                         *t++ = '\0';
    05534                         if (te <= t || te[-1] != ')') {
    05535                             hsa->errmsg = _("malformed parameter list");
    05536                             format = freeFormat(format, numTokens);
    05537                             return 1;
    05538                         }
    05539                         te[-1] = '\0';
    05540                         xx = argvAdd(&token->u.tag.params, t);
    05541                     } else
    05542                         xx = argvAdd(&token->u.tag.params, "");
    05543 /*@-modfilesys@*/
    05544 if (_hdrqf_debug)
    05545 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : ""));
    05546 /*@=modfilesys@*/
    05547                     xx = argvAdd(&token->u.tag.av, chptr);
    05548                     *te = c;
    05549                     *chptr = '\0';
    05550                     chptr = te;
    05551                 }
    05552             }
    05553 #undef  isSEP
    05554
    05555             if (*start == '\0') {
    05556                 hsa->errmsg = _("empty tag name");
    05557                 format = freeFormat(format, numTokens);
    05558                 return 1;
    05559             }
    05560
    05561             i = 0;
    05562             token->type = PTOK_TAG;
    05563
    05564             if (findTag(hsa, token, start)) {
    05565                 hsa->errmsg = _("unknown tag");
    05566                 format = freeFormat(format, numTokens);
    05567                 return 1;
    05568             }
    05569
    05570             dst = start = next;
    05571 /*@-modfilesys@*/
    05572 if (_hdrqf_debug)
    05573 fprintf(stderr, "\tdst = start = next %p\n", dst);
    05574 /*@=modfilesys@*/
    05575             /*@switchbreak@*/ break;
    05576
    05577         case '[':
    05578 /*@-modfilesys@*/
    05579 if (_hdrqf_debug)
    05580 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start);
    05581 /*@=modfilesys@*/
    05582             *start++ = '\0';
    05583             token = format + numTokens++;
    05584
    05585             if (parseFormat(hsa, start,
    05586                             &token->u.array.format,
    05587                             &token->u.array.numTokens,
    05588                             &start, PARSER_IN_ARRAY))
    05589             {
    05590                 format = freeFormat(format, numTokens);
    05591                 return 1;
    05592             }
    05593
    05594             if (!start) {
    05595                 hsa->errmsg = _("] expected at end of array");
    05596                 format = freeFormat(format, numTokens);
    05597                 return 1;
    05598             }
    05599
    05600             dst = start;
    05601 /*@-modfilesys@*/
    05602 if (_hdrqf_debug)
    05603 fprintf(stderr, "\tdst = start %p\n", dst);
    05604 /*@=modfilesys@*/
    05605
    05606             token->type = PTOK_ARRAY;
    05607
    05608             /*@switchbreak@*/ break;
    05609
    05610         case ']':
    05611             if (state != PARSER_IN_ARRAY) {
    05612                 hsa->errmsg = _("unexpected ]");
    05613                 format = freeFormat(format, numTokens);
    05614                 return 1;
    05615             }
    05616             *start++ = '\0';
    05617 /*@-modfilesys@*/
    05618 if (_hdrqf_debug)
    05619 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
    05620 /*@=modfilesys@*/
    05621             if (endPtr) *endPtr = start;
    05622             done = 1;
    05623             /*@switchbreak@*/ break;
    05624
    05625         case '}':
    05626             if (state != PARSER_IN_EXPR) {
    05627                 hsa->errmsg = _("unexpected }");
    05628                 format = freeFormat(format, numTokens);
    05629                 return 1;
    05630             }
    05631             *start++ = '\0';
    05632 /*@-modfilesys@*/
    05633 if (_hdrqf_debug)
    05634 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
    05635 /*@=modfilesys@*/
    05636             if (endPtr) *endPtr = start;
    05637             done = 1;
    05638             /*@switchbreak@*/ break;
    05639
    05640         default:
    05641             if (token == NULL || token->type != PTOK_STRING) {
    05642                 token = format + numTokens++;
    05643                 token->type = PTOK_STRING;
    05644 /*@-temptrans -assignexpose@*/
    05645                 dst = token->u.string.string = start;
    05646 /*@=temptrans =assignexpose@*/
    05647             }
    05648
    05649 /*@-modfilesys@*/
    05650 if (_hdrqf_debug)
    05651 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start);
    05652 /*@=modfilesys@*/
    05653             if (start[0] == '\\' && start[1] != '\0') {
    05654                 start++;
    05655                 *dst++ = escapedChar(*start);
    05656                 *start++ = '\0';
    05657             } else {
    05658                 *dst++ = *start++;
    05659             }
    05660             /*@switchbreak@*/ break;
    05661         }
    05662         if (dst < start) *dst = '\0';
    05663         if (done)
    05664             break;
    05665     }
    05666 /*@=infloops@*/
    05667
    05668     if (dst != NULL)
    05669         *dst = '\0';
    05670
    05671     for (i = 0; i < (unsigned) numTokens; i++) {
    05672         token = format + i;
    05673         switch(token->type) {
    05674         default:
    05675             /*@switchbreak@*/ break;
    05676         case PTOK_STRING:
    05677             token->u.string.len = strlen(token->u.string.string);
    05678             /*@switchbreak@*/ break;
    05679         }
    05680     }
    05681
    05682     if (numTokensPtr != NULL)
    05683         *numTokensPtr = numTokens;
    05684     if (formatPtr != NULL)
    05685         *formatPtr = format;
    05686
    05687     return 0;
    05688 }
    05689
    05690 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
    05691                 char * str, /*@out@*/ char ** endPtr)
    05692 {
    05693     char * chptr;
    05694     char * end;
    05695
    05696 /*@-modfilesys@*/
    05697 if (_hdrqf_debug)
    05698 fprintf(stderr, "-->   parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr);
    05699 /*@=modfilesys@*/
    05700
    05701     hsa->errmsg = NULL;
    05702     chptr = str;
    05703     while (*chptr && *chptr != '?') chptr++;
    05704
    05705     if (*chptr != '?') {
    05706         hsa->errmsg = _("? expected in expression");
    05707         return 1;
    05708     }
    05709
    05710     *chptr++ = '\0';
    05711
    05712     if (*chptr != '{') {
    05713         hsa->errmsg = _("{ expected after ? in expression");
    05714         return 1;
    05715     }
    05716
    05717     chptr++;
    05718
    05719     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
    05720                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
    05721         return 1;
    05722
    05723     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
    05724     if (!(end && *end)) {
    05725         hsa->errmsg = _("} expected in expression");
    05726         token->u.cond.ifFormat =
    05727                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    05728         return 1;
    05729     }
    05730
    05731     chptr = end;
    05732     if (*chptr != ':' && *chptr != '|') {
    05733         hsa->errmsg = _(": expected following ? subexpression");
    05734         token->u.cond.ifFormat =
    05735                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    05736         return 1;
    05737     }
    05738
    05739     if (*chptr == '|') {
    05740         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
    05741                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
    05742         {
    05743             token->u.cond.ifFormat =
    05744                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    05745             return 1;
    05746         }
    05747     } else {
    05748         chptr++;
    05749
    05750         if (*chptr != '{') {
    05751             hsa->errmsg = _("{ expected after : in expression");
    05752             token->u.cond.ifFormat =
    05753                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    05754             return 1;
    05755         }
    05756
    05757         chptr++;
    05758
    05759         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
    05760                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
    05761             return 1;
    05762
    05763         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
    05764         if (!(end && *end)) {
    05765             hsa->errmsg = _("} expected in expression");
    05766             token->u.cond.ifFormat =
    05767                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    05768             return 1;
    05769         }
    05770
    05771         chptr = end;
    05772         if (*chptr != '|') {
    05773             hsa->errmsg = _("| expected at end of expression");
    05774             token->u.cond.ifFormat =
    05775                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    05776             token->u.cond.elseFormat =
    05777                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
    05778             return 1;
    05779         }
    05780     }
    05781
    05782     chptr++;
    05783
    05784     *endPtr = chptr;
    05785
    05786     token->type = PTOK_COND;
    05787
    05788     (void) findTag(hsa, token, str);
    05789
    05790     return 0;
    05791 }
    05792
    05801 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
    05802                 HE_t he, HE_t ec)
    05803         /*@modifies he, ec @*/
    05804 {
    05805     int rc = 0;
    05806     if (!ec->avail) {
    05807         he = rpmheClean(he);
    05808         rc = fn(hsa->h, he);
    05809         *ec = *he;      /* structure copy. */
    05810         if (!rc)
    05811             ec->avail = 1;
    05812     } else
    05813         *he = *ec;      /* structure copy. */
    05814     he->freeData = 0;
    05815     rc = (rc == 0);     /* XXX invert getExtension return. */
    05816     return rc;
    05817 }
    05818
    05826 /*@observer@*/ /*@null@*/
    05827 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag,
    05828                 size_t element)
    05829         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    05830         /*@modifies hsa, tag, rpmGlobalMacroContext, internalState @*/
    05831 {
    05832     HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
    05833     HE_t he = &tag->he;
    05834     char * val = NULL;
    05835     size_t need = 0;
    05836     char * t, * te;
    05837     rpmuint64_t ival = 0;
    05838     rpmTagCount countBuf;
    05839     int xx;
    05840
    05841     if (!he->avail) {
    05842         if (tag->ext)
    05843             xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
    05844         else {
    05845             he->tag = tag->tagno[0];    /* XXX necessary? */
    05846             xx = headerGet(hsa->h, he, 0);
    05847         }
    05848         if (!xx) {
    05849             (void) rpmheClean(he);
    05850             he->t = RPM_STRING_TYPE;
    05851             he->p.str = xstrdup("(none)");
    05852             he->c = 1;
    05853             he->freeData = 1;
    05854         }
    05855         he->avail = 1;
    05856     }
    05857
    05858     if (tag->arrayCount) {
    05859         countBuf = he->c;
    05860         he = rpmheClean(he);
    05861         he->t = RPM_UINT32_TYPE;
    05862         he->p.ui32p = &countBuf;
    05863         he->c = 1;
    05864         he->freeData = 0;
    05865     }
    05866
    05867     vhe->tag = he->tag;
    05868
    05869     if (he->p.ptr)
    05870     switch (he->t) {
    05871     default:
    05872         val = xstrdup("(unknown type)");
    05873         need = strlen(val) + 1;
    05874         goto exit;
    05875         /*@notreached@*/ break;
    05876     case RPM_I18NSTRING_TYPE:
    05877     case RPM_STRING_ARRAY_TYPE:
    05878         vhe->t = RPM_STRING_TYPE;
    05879         vhe->p.str = he->p.argv[element];
    05880         vhe->c = he->c;
    05881         vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1);
    05882         break;
    05883     case RPM_STRING_TYPE:
    05884         vhe->p.str = he->p.str;
    05885         vhe->t = RPM_STRING_TYPE;
    05886         vhe->c = 0;
    05887         vhe->ix = -1;
    05888         break;
    05889     case RPM_UINT8_TYPE:
    05890     case RPM_UINT16_TYPE:
    05891     case RPM_UINT32_TYPE:
    05892     case RPM_UINT64_TYPE:
    05893         switch (he->t) {
    05894         default:
    05895 assert(0);      /* XXX keep gcc quiet. */
    05896             /*@innerbreak@*/ break;
    05897         case RPM_UINT8_TYPE:
    05898             ival = (rpmuint64_t)he->p.ui8p[element];
    05899             /*@innerbreak@*/ break;
    05900         case RPM_UINT16_TYPE:
    05901             ival = (rpmuint64_t)he->p.ui16p[element];
    05902             /*@innerbreak@*/ break;
    05903         case RPM_UINT32_TYPE:
    05904             ival = (rpmuint64_t)he->p.ui32p[element];
    05905             /*@innerbreak@*/ break;
    05906         case RPM_UINT64_TYPE:
    05907             ival = he->p.ui64p[element];
    05908             /*@innerbreak@*/ break;
    05909         }
    05910         vhe->t = RPM_UINT64_TYPE;
    05911         vhe->p.ui64p = &ival;
    05912         vhe->c = he->c;
    05913         vhe->ix = (he->c > 1 ? 0 : -1);
    05914         if ((tagType(he->tag) & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
    05915             vhe->ix = 0;
    05916         break;
    05917
    05918     case RPM_BIN_TYPE:
    05919         vhe->t = RPM_BIN_TYPE;
    05920         vhe->p.ptr = he->p.ptr;
    05921         vhe->c = he->c;
    05922         vhe->ix = -1;
    05923         break;
    05924     }
    05925
    05926 /*@-compmempass@*/      /* vhe->p.ui64p is stack, not owned */
    05927     if (tag->fmtfuncs) {
    05928         char * nval;
    05929         int i;
    05930         for (i = 0; tag->av[i] != NULL; i++) {
    05931             headerTagFormatFunction fmt;
    05932             ARGV_t av;
    05933             if ((fmt = tag->fmtfuncs[i]) == NULL)
    05934                 continue;
    05935             /* If !1st formatter, and transformer, not extractor, save val. */
    05936             if (val != NULL && *tag->av[i] == '|') {
    05937                 int ix = vhe->ix;
    05938                 vhe = rpmheClean(vhe);
    05939                 vhe->tag = he->tag;
    05940                 vhe->t = RPM_STRING_TYPE;
    05941                 vhe->p.str = xstrdup(val);
    05942                 vhe->c = he->c;
    05943                 vhe->ix = ix;
    05944                 vhe->freeData = 1;
    05945             }
    05946             av = NULL;
    05947             if (tag->params && tag->params[i] && *tag->params[i] != '\0')
    05948                 xx = argvSplit(&av, tag->params[i], ",");
    05949
    05950             nval = fmt(vhe, av);
    05951
    05952 /*@-castfcnptr -modfilesys@*/
    05953 if (_hdrqf_debug)
    05954 fprintf(stderr, "\t%s(%s) %p(%p,%p) ret \"%s\"\n", tag->av[i], (tag->params ? tag->params[i] : NULL), (void *)fmt, (void *)vhe, (void *)(av ? av : NULL), (val ? val : "(null)"));
    05955 /*@=castfcnptr =modfilesys@*/
    05956
    05957             /* Accumulate (by appending) next formmatter's return string. */
    05958             if (val == NULL)
    05959                 val = xstrdup((nval ? nval : ""));
    05960             else {
    05961                 char * oval = val;
    05962                 /* XXX using ... | ... as separator is feeble. */
    05963                 val = rpmExpand(val, (*val != '\0' ? " | " : ""), nval, NULL);
    05964                 oval = _free(oval);
    05965             }
    05966             nval = _free(nval);
    05967             av = argvFree(av);
    05968         }
    05969     }
    05970     if (val == NULL)
    05971         val = intFormat(vhe, NULL, NULL);
    05972 /*@=compmempass@*/
    05973 assert(val != NULL);
    05974     if (val)
    05975         need = strlen(val) + 1;
    05976
    05977 exit:
    05978     if (val && need > 0) {
    05979         if (tag->format && *tag->format && tag->pad > 0) {
    05980             size_t nb;
    05981             nb = strlen(tag->format) + sizeof("%s");
    05982             t = alloca(nb);
    05983             (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s");
    05984             nb = tag->pad + strlen(val) + 1;
    05985             te = xmalloc(nb);
    05986 /*@-formatconst@*/
    05987             (void) snprintf(te, nb, t, val);
    05988 /*@=formatconst@*/
    05989             te[nb-1] = '\0';
    05990             val = _free(val);
    05991             val = te;
    05992             need += tag->pad;
    05993         }
    05994         t = hsaReserve(hsa, need);
    05995         te = stpcpy(t, val);
    05996         hsa->vallen += (te - t);
    05997         val = _free(val);
    05998     }
    05999
    06000     return (hsa->val + hsa->vallen);
    06001 }
    06002
    06010 /*@observer@*/ /*@null@*/
    06011 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
    06012                 size_t element)
    06013         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    06014         /*@modifies hsa, token, rpmGlobalMacroContext, internalState @*/
    06015 {
    06016     char * t, * te;
    06017     size_t i, j;
    06018     size_t numElements;
    06019     sprintfToken spft;
    06020     sprintfTag tag = NULL;
    06021     HE_t he = NULL;
    06022     size_t condNumFormats;
    06023     size_t need;
    06024     int xx;
    06025
    06026     /* we assume the token and header have been validated already! */
    06027
    06028     switch (token->type) {
    06029     case PTOK_NONE:
    06030         break;
    06031
    06032     case PTOK_STRING:
    06033         need = token->u.string.len;
    06034         if (need == 0) break;
    06035         t = hsaReserve(hsa, need);
    06036         te = stpcpy(t, token->u.string.string);
    06037         hsa->vallen += (te - t);
    06038         break;
    06039
    06040     case PTOK_TAG:
    06041         t = hsa->val + hsa->vallen;
    06042 /*@-modobserver@*/      /* headerCompoundFormats not modified. */
    06043         te = formatValue(hsa, &token->u.tag,
    06044                         (token->u.tag.justOne ? 0 : element));
    06045 /*@=modobserver@*/
    06046         if (te == NULL)
    06047             return NULL;
    06048         break;
    06049
    06050     case PTOK_COND:
    06051         if (token->u.cond.tag.ext
    06052          || headerIsEntry(hsa->h, token->u.cond.tag.tagno[0]))
    06053         {
    06054             spft = token->u.cond.ifFormat;
    06055             condNumFormats = token->u.cond.numIfTokens;
    06056         } else {
    06057             spft = token->u.cond.elseFormat;
    06058             condNumFormats = token->u.cond.numElseTokens;
    06059         }
    06060
    06061         need = condNumFormats * 20;
    06062         if (spft == NULL || need == 0) break;
    06063
    06064         t = hsaReserve(hsa, need);
    06065         for (i = 0; i < condNumFormats; i++, spft++) {
    06066 /*@-modobserver@*/      /* headerCompoundFormats not modified. */
    06067             te = singleSprintf(hsa, spft, element);
    06068 /*@=modobserver@*/
    06069             if (te == NULL)
    06070                 return NULL;
    06071         }
    06072         break;
    06073
    06074     case PTOK_ARRAY:
    06075         numElements = 0;
    06076         spft = token->u.array.format;
    06077         for (i = 0; i < token->u.array.numTokens; i++, spft++)
    06078         {
    06079             tag = &spft->u.tag;
    06080             if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne)
    06081                 continue;
    06082             he = &tag->he;
    06083             if (!he->avail) {
    06084                 he->tag = tag->tagno[0];
    06085                 if (tag->ext)
    06086                     xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
    06087                 else
    06088                     xx = headerGet(hsa->h, he, 0);
    06089                 if (!xx) {
    06090                     (void) rpmheClean(he);
    06091                     continue;
    06092                 }
    06093                 he->avail = 1;
    06094             }
    06095
    06096             /* Check iteration arrays are same dimension (or scalar). */
    06097             switch (he->t) {
    06098             default:
    06099                 if (numElements == 0) {
    06100                     numElements = he->c;
    06101                     /*@switchbreak@*/ break;
    06102                 }
    06103                 if ((size_t)he->c == numElements)
    06104                     /*@switchbreak@*/ break;
    06105                 hsa->errmsg =
    06106                         _("array iterator used with different sized arrays");
    06107                 he = rpmheClean(he);
    06108                 return NULL;
    06109                 /*@notreached@*/ /*@switchbreak@*/ break;
    06110             case RPM_BIN_TYPE:
    06111             case RPM_STRING_TYPE:
    06112                 if (numElements == 0)
    06113                     numElements = 1;
    06114                 /*@switchbreak@*/ break;
    06115             }
    06116         }
    06117         spft = token->u.array.format;
    06118
    06119         if (numElements == 0) {
    06120 #ifdef  DYING   /* XXX lots of pugly "(none)" lines with --conflicts. */
    06121             need = sizeof("(none)\n") - 1;
    06122             t = hsaReserve(hsa, need);
    06123             te = stpcpy(t, "(none)\n");
    06124             hsa->vallen += (te - t);
    06125 #endif
    06126         } else {
    06127             int isxml;
    06128             int isyaml;
    06129
    06130             need = numElements * token->u.array.numTokens;
    06131             if (need == 0) break;
    06132
    06133             tag = &spft->u.tag;
    06134
    06135             /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
    06136             isxml = (spft->type == PTOK_TAG && tag->av != NULL &&
    06137                 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"));
    06138             isyaml = (spft->type == PTOK_TAG && tag->av != NULL &&
    06139                 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"));
    06140
    06141             if (isxml) {
    06142                 const char * tagN;
    06143                 /* XXX display "Tag_0x01234567" for arbitrary tags. */
    06144                 if (tag->tagno != NULL && tag->tagno[0] & 0x40000000) {
    06145                     tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
    06146                 } else
    06147                     tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
    06148 assert(tagN != NULL);   /* XXX can't happen */
    06149                 need = sizeof("  <rpmTag name=\"\">\n") + strlen(tagN);
    06150                 te = t = hsaReserve(hsa, need);
    06151                 te = stpcpy( stpcpy( stpcpy(te, "  <rpmTag name=\""), tagN), "\">\n");
    06152                 hsa->vallen += (te - t);
    06153             }
    06154             if (isyaml) {
    06155                 rpmTagReturnType tagT = 0;
    06156                 const char * tagN;
    06157                 /* XXX display "Tag_0x01234567" for arbitrary tags. */
    06158                 if (tag->tagno != NULL && tag->tagno[0] & 0x40000000) {
    06159                     tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
    06160                     tagT = numElements > 1
    06161                         ?  RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
    06162                 } else
    06163                     tagN = myTagName(hsa->tags, tag->tagno[0], &tagT);
    06164 assert(tagN != NULL);   /* XXX can't happen */
    06165                 need = sizeof("  :     - ") + strlen(tagN);
    06166                 te = t = hsaReserve(hsa, need);
    06167                 *te++ = ' ';
    06168                 *te++ = ' ';
    06169                 te = stpcpy(te, tagN);
    06170                 *te++ = ':';
    06171                 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
    06172                         ? '\n' : ' ');
    06173                 *te = '\0';
    06174                 hsa->vallen += (te - t);
    06175             }
    06176
    06177             need = numElements * token->u.array.numTokens * 10;
    06178             t = hsaReserve(hsa, need);
    06179             for (j = 0; j < numElements; j++) {
    06180                 spft = token->u.array.format;
    06181                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
    06182 /*@-modobserver@*/      /* headerCompoundFormats not modified. */
    06183                     te = singleSprintf(hsa, spft, j);
    06184 /*@=modobserver@*/
    06185                     if (te == NULL)
    06186                         return NULL;
    06187                 }
    06188             }
    06189
    06190             if (isxml) {
    06191                 need = sizeof("  </rpmTag>\n") - 1;
    06192                 te = t = hsaReserve(hsa, need);
    06193                 te = stpcpy(te, "  </rpmTag>\n");
    06194                 hsa->vallen += (te - t);
    06195             }
    06196             if (isyaml) {
    06197 #if 0
    06198                 need = sizeof("\n") - 1;
    06199                 te = t = hsaReserve(hsa, need);
    06200                 te = stpcpy(te, "\n");
    06201                 hsa->vallen += (te - t);
    06202 #endif
    06203             }
    06204
    06205         }
    06206         break;
    06207     }
    06208
    06209     return (hsa->val + hsa->vallen);
    06210 }
    06211
    06218 static /*@only@*/ HE_t
    06219 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp)
    06220         /*@modifies *necp @*/
    06221 {
    06222     headerSprintfExtension ext;
    06223     HE_t ec;
    06224     int extNum = 0;
    06225
    06226     if (exts != NULL)
    06227     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
    06228         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
    06229     {
    06230         ;
    06231     }
    06232     if (necp)
    06233         *necp = extNum;
    06234     ec = xcalloc(extNum+1, sizeof(*ec));        /* XXX +1 unnecessary */
    06235     return ec;
    06236 }
    06237
    06244 static /*@null@*/ HE_t
    06245 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec)
    06246         /*@modifies ec @*/
    06247 {
    06248     headerSprintfExtension ext;
    06249     int extNum;
    06250
    06251     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
    06252         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
    06253     {
    06254         (void) rpmheClean(&ec[extNum]);
    06255     }
    06256
    06257     ec = _free(ec);
    06258     return NULL;
    06259 }
    06260
    06261 char * headerSprintf(Header h, const char * fmt,
    06262                 headerTagTableEntry tags,
    06263                 headerSprintfExtension exts,
    06264                 errmsg_t * errmsg)
    06265 {
    06266     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
    06267     sprintfToken nextfmt;
    06268     sprintfTag tag;
    06269     char * t, * te;
    06270     int isxml;
    06271     int isyaml;
    06272     int need;
    06273
    06274 /*@-modfilesys@*/
    06275 if (_hdrqf_debug)
    06276 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg);
    06277 /*@=modfilesys@*/
    06278
    06279     /* Set some reasonable defaults */
    06280     if (tags == NULL)
    06281         tags = rpmTagTable;
    06282     /* XXX this loses the extensions in lib/formats.c. */
    06283     if (exts == NULL)
    06284         exts = headerCompoundFormats;
    06285
    06286 /*@-assignexpose -castexpose @*/
    06287     hsa->h = headerLink(h);
    06288 /*@=assignexpose =castexpose @*/
    06289     hsa->fmt = xstrdup(fmt);
    06290 /*@-assignexpose -dependenttrans@*/
    06291     hsa->exts = exts;
    06292     hsa->tags = tags;
    06293 /*@=assignexpose =dependenttrans@*/
    06294     hsa->errmsg = NULL;
    06295
    06296     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
    06297         goto exit;
    06298
    06299     hsa->nec = 0;
    06300     hsa->ec = rpmecNew(hsa->exts, &hsa->nec);
    06301     hsa->val = xstrdup("");
    06302
    06303     tag =
    06304         (hsa->format->type == PTOK_TAG
    06305             ? &hsa->format->u.tag :
    06306         (hsa->format->type == PTOK_ARRAY
    06307             ? &hsa->format->u.array.format->u.tag :
    06308         NULL));
    06309
    06310     /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
    06311     isxml = (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 && tag->av != NULL
    06312                 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"));
    06313     isyaml = (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 && tag->av != NULL
    06314                 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"));
    06315
    06316     if (isxml) {
    06317         need = sizeof("<rpmHeader>\n") - 1;
    06318         t = hsaReserve(hsa, need);
    06319         te = stpcpy(t, "<rpmHeader>\n");
    06320         hsa->vallen += (te - t);
    06321     }
    06322     if (isyaml) {
    06323         need = sizeof("- !!omap\n") - 1;
    06324         t = hsaReserve(hsa, need);
    06325         te = stpcpy(t, "- !!omap\n");
    06326         hsa->vallen += (te - t);
    06327     }
    06328
    06329     hsa = hsaInit(hsa);
    06330     while ((nextfmt = hsaNext(hsa)) != NULL) {
    06331 /*@-globs -mods@*/      /* XXX rpmGlobalMacroContext @*/
    06332         te = singleSprintf(hsa, nextfmt, 0);
    06333 /*@=globs =mods @*/
    06334         if (te == NULL) {
    06335             hsa->val = _free(hsa->val);
    06336             break;
    06337         }
    06338     }
    06339     hsa = hsaFini(hsa);
    06340
    06341     if (isxml) {
    06342         need = sizeof("</rpmHeader>\n") - 1;
    06343         t = hsaReserve(hsa, need);
    06344         te = stpcpy(t, "</rpmHeader>\n");
    06345         hsa->vallen += (te - t);
    06346     }
    06347     if (isyaml) {
    06348         need = sizeof("\n") - 1;
    06349         t = hsaReserve(hsa, need);
    06350         te = stpcpy(t, "\n");
    06351         hsa->vallen += (te - t);
    06352     }
    06353
    06354     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
    06355         hsa->val = xrealloc(hsa->val, hsa->vallen+1);
    06356
    06357     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
    06358     hsa->nec = 0;
    06359     hsa->format = freeFormat(hsa->format, hsa->numTokens);
    06360
    06361 exit:
    06362 /*@-dependenttrans -observertrans @*/
    06363     if (errmsg)
    06364         *errmsg = hsa->errmsg;
    06365 /*@=dependenttrans =observertrans @*/
    06366     (void)headerFree(hsa->h);
    06367     hsa->h = NULL;
    06368     hsa->fmt = _free(hsa->fmt);
    06369 /*@-retexpose@*/
    06370     return hsa->val;
    06371 /*@=retexpose@*/
    06372 }