• 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 }

Generated on Fri Dec 3 2010 20:54:01 for rpm by  doxygen 1.7.2