• 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 #include "rpmio_internal.h"
00008 #include <rpmbc.h>      /* XXX beecrypt base64 */
00009 #include <rpmcb.h>      /* XXX rpmIsVerbose */
00010 #include <rpmmacro.h>   /* XXX for %_i18ndomains */
00011 
00012 #define _RPMTAG_INTERNAL
00013 #include <rpmtag.h>
00014 
00015 #include <rpmlib.h>     /* XXX rpmfi, rpmMkdirPath */
00016 #include <rpmfi.h>      /* XXX RPMFILE_FOO */
00017 
00018 #define _RPMEVR_INTERNAL
00019 #include <rpmevr.h>     /* XXX RPMSENSE_FOO */
00020 
00021 #include "legacy.h"
00022 #include "argv.h"
00023 #include "misc.h"
00024 
00025 #include "debug.h"
00026 
00027 /*@unchecked@*/
00028 extern int _hdr_debug;
00029 
00030 /*@access pgpDig @*/
00031 /*@access pgpDigParams @*/
00032 /*@access headerSprintfExtension @*/
00033 /*@access headerTagTableEntry @*/
00034 /*@access Header @*/    /* XXX debugging msgs */
00035 
00042 static char * intFormat(HE_t he, const char *fmt)
00043         /*@*/
00044 {
00045     uint32_t ix = (he->ix > 0 ? he->ix : 0);
00046     uint64_t ival = 0;
00047     const char * istr = NULL;
00048     char * b;
00049     size_t nb = 0;
00050     int xx;
00051 
00052     if (fmt == NULL || *fmt == '\0')
00053         fmt = "d";
00054 
00055     switch (he->t) {
00056     default:
00057         return xstrdup(_("(not a number)"));
00058         /*@notreached@*/ break;
00059     case RPM_UINT8_TYPE:
00060         ival = (uint64_t) he->p.ui8p[ix];
00061         break;
00062     case RPM_UINT16_TYPE:
00063         ival = (uint64_t) he->p.ui16p[ix];
00064         break;
00065     case RPM_UINT32_TYPE:
00066         ival = (uint64_t) he->p.ui32p[ix];
00067         break;
00068     case RPM_UINT64_TYPE:
00069         ival = he->p.ui64p[ix];
00070         break;
00071     case RPM_STRING_TYPE:
00072         istr = he->p.str;
00073         break;
00074     case RPM_STRING_ARRAY_TYPE:
00075         istr = he->p.argv[ix];
00076         break;
00077     case RPM_BIN_TYPE:
00078         {   static char hex[] = "0123456789abcdef";
00079             const char * s = he->p.str;
00080             rpmTagCount c = he->c;
00081             char * t;
00082 
00083             nb = 2 * c + 1;
00084             t = b = alloca(nb+1);
00085             while (c-- > 0) {
00086                 unsigned i;
00087                 i = (unsigned) *s++;
00088                 *t++ = hex[ (i >> 4) & 0xf ];
00089                 *t++ = hex[ (i     ) & 0xf ];
00090             }
00091             *t = '\0';
00092         }   break;
00093     }
00094 
00095     if (istr) {         /* string */
00096         b = (char *)istr;       /* NOCAST */
00097     } else
00098     if (nb == 0) {      /* number */
00099         char myfmt[] = "%llX";
00100         myfmt[3] = ((fmt != NULL && *fmt != '\0') ? *fmt : 'd');
00101         nb = 64;
00102         b = alloca(nb);
00103 /*@-formatconst@*/
00104         xx = snprintf(b, nb, myfmt, ival);
00105 /*@=formatconst@*/
00106         b[nb-1] = '\0';
00107     }
00108 
00109     return xstrdup(b);
00110 }
00111 
00117 static char * octFormat(HE_t he)
00118         /*@*/
00119 {
00120     return intFormat(he, "o");
00121 }
00122 
00128 static char * hexFormat(HE_t he)
00129         /*@*/
00130 {
00131     return intFormat(he, "x");
00132 }
00133 
00139 static char * decFormat(HE_t he)
00140         /*@*/
00141 {
00142     return intFormat(he, "d");
00143 }
00144 
00151 static char * realDateFormat(HE_t he, const char * strftimeFormat)
00152         /*@*/
00153 {
00154     char * val;
00155 
00156     if (he->t != RPM_UINT64_TYPE) {
00157         val = xstrdup(_("(not a number)"));
00158     } else {
00159         struct tm * tstruct;
00160         char buf[50];
00161 
00162         /* this is important if sizeof(uint64_t) ! sizeof(time_t) */
00163         {   time_t dateint = he->p.ui64p[0];
00164             tstruct = localtime(&dateint);
00165         }
00166         buf[0] = '\0';
00167         if (tstruct)
00168             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
00169         buf[sizeof(buf) - 1] = '\0';
00170         val = xstrdup(buf);
00171     }
00172 
00173     return val;
00174 }
00175 
00181 static char * dateFormat(HE_t he)
00182         /*@*/
00183 {
00184     return realDateFormat(he, _("%c"));
00185 }
00186 
00192 static char * dayFormat(HE_t he)
00193         /*@*/
00194 {
00195     return realDateFormat(he, _("%a %b %d %Y"));
00196 }
00197 
00203 static char * shescapeFormat(HE_t he)
00204         /*@*/
00205 {
00206     char * val;
00207     size_t nb;
00208     int xx;
00209 
00210     /* XXX one of these integer types is unnecessary. */
00211     if (he->t == RPM_UINT32_TYPE) {
00212         nb = 20;
00213         val = xmalloc(nb);
00214         xx = snprintf(val, nb, "%u", (unsigned) he->p.ui32p[0]);
00215         val[nb-1] = '\0';
00216     } else if (he->t == RPM_UINT64_TYPE) {
00217         nb = 40;
00218         val = xmalloc(40);
00219 /*@-duplicatequals@*/
00220         xx = snprintf(val, nb, "%llu", (unsigned long long)he->p.ui64p[0]);
00221 /*@=duplicatequals@*/
00222         val[nb-1] = '\0';
00223     } else if (he->t == RPM_STRING_TYPE) {
00224         const char * s = he->p.str;
00225         char * t;
00226         int c;
00227 
00228         nb = 0;
00229         for (s = he->p.str; (c = (int)*s) != 0; s++)  {
00230             nb++;
00231             if (c == (int)'\'')
00232                 nb += 3;
00233         }
00234         nb += 3;
00235         t = val = xmalloc(nb);
00236         *t++ = '\'';
00237         for (s = he->p.str; (c = (int)*s) != 0; s++)  {
00238             if (c == (int)'\'') {
00239                 *t++ = '\'';
00240                 *t++ = '\\';
00241                 *t++ = '\'';
00242             }
00243             *t++ = (char) c;
00244         }
00245         *t++ = '\'';
00246         *t = '\0';
00247     } else
00248         val = xstrdup(_("invalid type"));
00249 
00250     return val;
00251 }
00252 
00253 /*@-type@*/ /* FIX: cast? */
00254 static struct headerSprintfExtension_s _headerDefaultFormats[] = {
00255     { HEADER_EXT_FORMAT, "octal",
00256         { .fmtFunction = octFormat } },
00257     { HEADER_EXT_FORMAT, "oct",
00258         { .fmtFunction = octFormat } },
00259     { HEADER_EXT_FORMAT, "hex",
00260         { .fmtFunction = hexFormat } },
00261     { HEADER_EXT_FORMAT, "decimal",
00262         { .fmtFunction = decFormat } },
00263     { HEADER_EXT_FORMAT, "dec",
00264         { .fmtFunction = decFormat } },
00265     { HEADER_EXT_FORMAT, "date",
00266         { .fmtFunction = dateFormat } },
00267     { HEADER_EXT_FORMAT, "day",
00268         { .fmtFunction = dayFormat } },
00269     { HEADER_EXT_FORMAT, "shescape",
00270         { .fmtFunction = shescapeFormat } },
00271     { HEADER_EXT_LAST, NULL, { NULL } }
00272 };
00273 /*@=type@*/
00274 
00275 headerSprintfExtension headerDefaultFormats = &_headerDefaultFormats[0];
00276 /* XXX FIXME: static for now, refactor from manifest.c later. */
00277 static char * rpmPermsString(int mode)
00278         /*@*/
00279 {
00280     char *perms = xstrdup("----------");
00281    
00282     if (S_ISREG(mode)) 
00283         perms[0] = '-';
00284     else if (S_ISDIR(mode)) 
00285         perms[0] = 'd';
00286     else if (S_ISLNK(mode))
00287         perms[0] = 'l';
00288     else if (S_ISFIFO(mode)) 
00289         perms[0] = 'p';
00290     /*@-unrecog@*/
00291     else if (S_ISSOCK(mode)) 
00292         perms[0] = 's';
00293     /*@=unrecog@*/
00294     else if (S_ISCHR(mode))
00295         perms[0] = 'c';
00296     else if (S_ISBLK(mode))
00297         perms[0] = 'b';
00298     else
00299         perms[0] = '?';
00300 
00301     if (mode & S_IRUSR) perms[1] = 'r';
00302     if (mode & S_IWUSR) perms[2] = 'w';
00303     if (mode & S_IXUSR) perms[3] = 'x';
00304  
00305     if (mode & S_IRGRP) perms[4] = 'r';
00306     if (mode & S_IWGRP) perms[5] = 'w';
00307     if (mode & S_IXGRP) perms[6] = 'x';
00308 
00309     if (mode & S_IROTH) perms[7] = 'r';
00310     if (mode & S_IWOTH) perms[8] = 'w';
00311     if (mode & S_IXOTH) perms[9] = 'x';
00312 
00313     if (mode & S_ISUID)
00314         perms[3] = ((mode & S_IXUSR) ? 's' : 'S'); 
00315 
00316     if (mode & S_ISGID)
00317         perms[6] = ((mode & S_IXGRP) ? 's' : 'S'); 
00318 
00319     if (mode & S_ISVTX)
00320         perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
00321 
00322     return perms;
00323 }
00324 
00330 static /*@only@*/ char * triggertypeFormat(HE_t he)
00331 {
00332     int ix = (he->ix > 0 ? he->ix : 0);
00333     char * val;
00334 
00335 assert(ix == 0);
00336     if (he->t != RPM_UINT64_TYPE)
00337         val = xstrdup(_("(invalid type)"));
00338     else {
00339         uint64_t anint = he->p.ui64p[ix];
00340         if (anint & RPMSENSE_TRIGGERPREIN)
00341             val = xstrdup("prein");
00342         else if (anint & RPMSENSE_TRIGGERIN)
00343             val = xstrdup("in");
00344         else if (anint & RPMSENSE_TRIGGERUN)
00345             val = xstrdup("un");
00346         else if (anint & RPMSENSE_TRIGGERPOSTUN)
00347             val = xstrdup("postun");
00348         else
00349             val = xstrdup("");
00350     }
00351     return val;
00352 }
00353 
00359 static /*@only@*/ char * permsFormat(HE_t he)
00360 {
00361     int ix = (he->ix > 0 ? he->ix : 0);
00362     char * val;
00363 
00364 assert(ix == 0);
00365     if (he->t != RPM_UINT64_TYPE) {
00366         val = xstrdup(_("(invalid type)"));
00367     } else {
00368         uint64_t anint = he->p.ui64p[0];
00369         val = rpmPermsString((int)anint);
00370     }
00371 
00372     return val;
00373 }
00374 
00380 static /*@only@*/ char * fflagsFormat(HE_t he)
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         char buf[15];
00390         uint64_t anint = he->p.ui64p[ix];
00391         buf[0] = '\0';
00392         if (anint & RPMFILE_DOC)
00393             strcat(buf, "d");
00394         if (anint & RPMFILE_CONFIG)
00395             strcat(buf, "c");
00396         if (anint & RPMFILE_SPECFILE)
00397             strcat(buf, "s");
00398         if (anint & RPMFILE_MISSINGOK)
00399             strcat(buf, "m");
00400         if (anint & RPMFILE_NOREPLACE)
00401             strcat(buf, "n");
00402         if (anint & RPMFILE_GHOST)
00403             strcat(buf, "g");
00404         if (anint & RPMFILE_LICENSE)
00405             strcat(buf, "l");
00406         if (anint & RPMFILE_README)
00407             strcat(buf, "r");
00408         val = xstrdup(buf);
00409     }
00410 
00411     return val;
00412 }
00413 
00420 static /*@only@*/ char * armorFormat(HE_t he)
00421         /*@*/
00422 {
00423     int ix = (he->ix > 0 ? he->ix : 0);
00424     const char * enc;
00425     const unsigned char * s;
00426     size_t ns;
00427     int atype;
00428     char * val;
00429 
00430 assert(ix == 0);
00431     switch (he->t) {
00432     case RPM_BIN_TYPE:
00433         s = (unsigned char *) he->p.ui8p;
00434         ns = he->c;
00435         atype = PGPARMOR_SIGNATURE;     /* XXX check pkt for signature */
00436         break;
00437     case RPM_STRING_TYPE:
00438     case RPM_STRING_ARRAY_TYPE:
00439         enc = he->p.str;
00440         s = NULL;
00441         ns = 0;
00442 /*@-moduncon@*/
00443         if (b64decode(enc, (void **)&s, &ns))
00444             return xstrdup(_("(not base64)"));
00445 /*@=moduncon@*/
00446         atype = PGPARMOR_PUBKEY;        /* XXX check pkt for pubkey */
00447         break;
00448     case RPM_UINT8_TYPE:
00449     case RPM_UINT16_TYPE:
00450     case RPM_UINT32_TYPE:
00451     case RPM_UINT64_TYPE:
00452     case RPM_I18NSTRING_TYPE:
00453     default:
00454         return xstrdup(_("(invalid type)"));
00455         /*@notreached@*/ break;
00456     }
00457 
00458     val = pgpArmorWrap(atype, s, ns);
00459     if (atype == PGPARMOR_PUBKEY)
00460         s = _free(s);
00461     return val;
00462 }
00463 
00470 static /*@only@*/ char * base64Format(HE_t he)
00471         /*@*/
00472 {
00473     int ix = (he->ix > 0 ? he->ix : 0);
00474     char * val;
00475 
00476 assert(ix == 0);
00477     if (!(he->t == RPM_BIN_TYPE)) {
00478         val = xstrdup(_("(not a blob)"));
00479     } else {
00480         const char * enc;
00481         char * t;
00482         int lc;
00483         size_t ns = he->c;
00484         size_t nt = ((ns + 2) / 3) * 4;
00485 
00486         /*@-globs@*/
00487         /* Add additional bytes necessary for eol string(s). */
00488         if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
00489             lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
00490         if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
00491             ++lc;
00492             nt += lc * strlen(b64encode_eolstr);
00493         }
00494         /*@=globs@*/
00495 
00496         val = t = xcalloc(1, nt + 1);
00497         *t = '\0';
00498 
00499     /* XXX b64encode accesses uninitialized memory. */
00500     {   unsigned char * _data = xcalloc(1, ns+1);
00501         memcpy(_data, he->p.ptr, ns);
00502 /*@-moduncon@*/
00503         if ((enc = b64encode(_data, ns)) != NULL) {
00504             t = stpcpy(t, enc);
00505             enc = _free(enc);
00506         }
00507 /*@=moduncon@*/
00508         _data = _free(_data);
00509     }
00510     }
00511 
00512 /*@-globstate@*/
00513     return val;
00514 /*@=globstate@*/
00515 }
00516 
00522 static size_t xmlstrlen(const char * s)
00523         /*@*/
00524 {
00525     size_t len = 0;
00526     int c;
00527 
00528     while ((c = (int) *s++) != (int) '\0')
00529     {
00530         switch (c) {
00531         case '<':
00532         case '>':       len += sizeof("&lt;") - 1;      /*@switchbreak@*/ break;
00533         case '&':       len += sizeof("&amp;") - 1;     /*@switchbreak@*/ break;
00534         default:        len += 1;                       /*@switchbreak@*/ break;
00535         }
00536     }
00537     return len;
00538 }
00539 
00546 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s)
00547         /*@modifies t @*/
00548 {
00549     char * te = t;
00550     int c;
00551 
00552     while ((c = (int) *s++) != (int) '\0') {
00553         switch (c) {
00554         case '<':       te = stpcpy(te, "&lt;");        /*@switchbreak@*/ break;
00555         case '>':       te = stpcpy(te, "&gt;");        /*@switchbreak@*/ break;
00556         case '&':       te = stpcpy(te, "&amp;");       /*@switchbreak@*/ break;
00557         default:        *te++ = (char) c;               /*@switchbreak@*/ break;
00558         }
00559     }
00560     *te = '\0';
00561     return t;
00562 }
00563 
00569 static /*@only@*/ char * xmlFormat(HE_t he)
00570         /*@*/
00571 {
00572     int ix = (he->ix > 0 ? he->ix : 0);
00573     const char * xtag = NULL;
00574     size_t nb;
00575     char * val;
00576     const char * s = NULL;
00577     char * t, * te;
00578     uint64_t anint = 0;
00579     int freeit = 0;
00580     int xx;
00581 
00582 assert(ix == 0);
00583 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
00584     switch (he->t) {
00585     case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
00586         s = he->p.argv[ix];
00587         xtag = "string";
00588         /* XXX Force utf8 strings. */
00589         s = xstrdup(s);
00590         s = xstrtolocale(s);
00591         freeit = 1;
00592         break;
00593     case RPM_I18NSTRING_TYPE:   /* XXX currently never happens */
00594     case RPM_STRING_TYPE:
00595         s = he->p.str;
00596         xtag = "string";
00597         /* XXX Force utf8 strings. */
00598         s = xstrdup(s);
00599         s = xstrtolocale(s);
00600         freeit = 1;
00601         break;
00602     case RPM_BIN_TYPE:
00603 /*@-globs -mods@*/
00604     {   int cpl = b64encode_chars_per_line;
00605         b64encode_chars_per_line = 0;
00606 /*@-formatconst@*/
00607         s = base64Format(he);
00608 /*@=formatconst@*/
00609         b64encode_chars_per_line = cpl;
00610         xtag = "base64";
00611         freeit = 1;
00612     }   break;
00613 /*@=globs =mods@*/
00614     case RPM_UINT8_TYPE:
00615         anint = he->p.ui8p[ix];
00616         break;
00617     case RPM_UINT16_TYPE:
00618         anint = he->p.ui16p[ix];
00619         break;
00620     case RPM_UINT32_TYPE:
00621         anint = he->p.ui32p[ix];
00622         break;
00623     case RPM_UINT64_TYPE:
00624         anint = he->p.ui64p[ix];
00625         break;
00626     default:
00627         return xstrdup(_("(invalid xml type)"));
00628         /*@notreached@*/ break;
00629     }
00630 
00631     if (s == NULL) {
00632         int tlen = 64;
00633         t = memset(alloca(tlen+1), 0, tlen+1);
00634 /*@-duplicatequals@*/
00635         if (anint != 0)
00636             xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
00637 /*@=duplicatequals@*/
00638         s = t;
00639         xtag = "integer";
00640     }
00641 
00642     nb = xmlstrlen(s);
00643     if (nb == 0) {
00644         nb += strlen(xtag) + sizeof("\t</>");
00645         te = t = alloca(nb);
00646         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
00647     } else {
00648         nb += 2 * strlen(xtag) + sizeof("\t<></>");
00649         te = t = alloca(nb);
00650         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
00651         te = xmlstrcpy(te, s);
00652         te += strlen(te);
00653         te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
00654     }
00655 
00656     if (freeit)
00657         s = _free(s);
00658 
00659     val = xstrdup(t);
00660 
00661     return val;
00662 }
00663 
00670 static size_t yamlstrlen(const char * s, int lvl)
00671         /*@*/
00672 {
00673     size_t len = 0;
00674     int indent = (lvl > 0);
00675     int c;
00676 
00677     while ((c = (int) *s++) != (int) '\0')
00678     {
00679         if (indent) {
00680             len += 2 * lvl;
00681             indent = 0;
00682         }
00683         if (c == (int) '\n')
00684             indent = (lvl > 0);
00685         len++;
00686     }
00687     return len;
00688 }
00689 
00697 static char * yamlstrcpy(/*@out@*/ /*@returned@*/ char * t, const char * s, int lvl)
00698         /*@modifies t @*/
00699 {
00700     char * te = t;
00701     int indent = (lvl > 0);
00702     int c;
00703 
00704     while ((c = (int) *s++) != (int) '\0') {
00705         if (indent) {
00706             int i;
00707             for (i = 0; i < lvl; i++) {
00708                 *te++ = ' ';
00709                 *te++ = ' ';
00710             }
00711             indent = 0;
00712         }
00713         if (c == (int) '\n')
00714             indent = (lvl > 0);
00715         *te++ = (char) c;
00716     }
00717     *te = '\0';
00718     return t;
00719 }
00720 
00726 static /*@only@*/ char * yamlFormat(HE_t he)
00727         /*@*/
00728 {
00729     int element = he->ix;
00730     int ix = (he->ix > 0 ? he->ix : 0);
00731     const char * xtag = NULL;
00732     size_t nb;
00733     char * val;
00734     const char * s = NULL;
00735     char * t, * te;
00736     uint64_t anint = 0;
00737     int freeit = 0;
00738     int lvl = 0;
00739     int xx;
00740     int c;
00741 
00742 assert(ix == 0);
00743 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
00744     xx = 0;
00745     switch (he->t) {
00746     case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
00747     case RPM_I18NSTRING_TYPE:   /* XXX currently never happens */
00748     case RPM_STRING_TYPE:
00749         s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str);
00750         if (strchr("[", s[0]))  /* leading [ */
00751             xx = 1;
00752         if (xx == 0)
00753         while ((c = (int) *s++) != (int) '\0') {
00754             switch (c) {
00755             default:
00756                 continue;
00757             case '\n':  /* multiline */
00758                 xx = 1;
00759                 /*@switchbreak@*/ break;
00760             case '-':   /* leading "- \"" */
00761             case ':':   /* embedded ": " or ":" at EOL */
00762                 if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
00763                     continue;
00764                 xx = 1;
00765                 /*@switchbreak@*/ break;
00766             }
00767             /*@loopbreak@*/ break;
00768         }
00769         if (xx) {
00770             if (element >= 0) {
00771                 xtag = "- |-\n";
00772                 lvl = 3;
00773             } else {
00774                 xtag = "|-\n";
00775                 lvl = 2;
00776                 if (he->ix < 0) lvl++;  /* XXX extra indent for array[1] */
00777             }
00778         } else {
00779             xtag = (element >= 0 ? "- " : NULL);
00780         }
00781 
00782         /* XXX Force utf8 strings. */
00783         s = xstrdup(he->p.str);
00784         s = xstrtolocale(s);
00785         freeit = 1;
00786         break;
00787     case RPM_BIN_TYPE:
00788 /*@-globs -mods@*/
00789     {   int cpl = b64encode_chars_per_line;
00790         b64encode_chars_per_line = 0;
00791 /*@-formatconst@*/
00792         s = base64Format(he);
00793         element = -element;     /* XXX skip "    " indent. */
00794 /*@=formatconst@*/
00795         b64encode_chars_per_line = cpl;
00796         xtag = "!!binary ";
00797         freeit = 1;
00798     }   break;
00799 /*@=globs =mods@*/
00800     case RPM_UINT8_TYPE:
00801         anint = he->p.ui8p[ix];
00802         break;
00803     case RPM_UINT16_TYPE:
00804         anint = he->p.ui16p[ix];
00805         break;
00806     case RPM_UINT32_TYPE:
00807         anint = he->p.ui32p[ix];
00808         break;
00809     case RPM_UINT64_TYPE:
00810         anint = he->p.ui64p[ix];
00811         break;
00812     default:
00813         return xstrdup(_("(invalid yaml type)"));
00814         /*@notreached@*/ break;
00815     }
00816 
00817     if (s == NULL) {
00818         int tlen = 64;
00819         t = memset(alloca(tlen+1), 0, tlen+1);
00820 /*@-duplicatequals@*/
00821         xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
00822 /*@=duplicatequals@*/
00823         s = t;
00824         xtag = (element >= 0 ? "- " : NULL);
00825     }
00826 
00827     nb = yamlstrlen(s, lvl);
00828     if (nb == 0) {
00829         if (element >= 0)
00830             nb += sizeof("    ") - 1;
00831         nb += sizeof("- ~") - 1;
00832         nb++;
00833         te = t = alloca(nb);
00834         if (element >= 0)
00835             te = stpcpy(te, "    ");
00836         te = stpcpy(te, "- ~");
00837     } else {
00838         if (element >= 0)
00839             nb += sizeof("    ") - 1;
00840         if (xtag)
00841             nb += strlen(xtag);
00842         nb++;
00843         te = t = alloca(nb);
00844         if (element >= 0)
00845             te = stpcpy(te, "    ");
00846         if (xtag)
00847             te = stpcpy(te, xtag);
00848         te = yamlstrcpy(te, s, lvl);
00849         te += strlen(te);
00850     }
00851 
00852     /* XXX s was malloc'd */
00853     if (freeit)
00854         s = _free(s);
00855 
00856     val = xstrdup(t);
00857 
00858     return val;
00859 }
00860 
00866 static /*@only@*/ char * pgpsigFormat(HE_t he)
00867         /*@globals fileSystem, internalState @*/
00868         /*@modifies fileSystem, internalState @*/
00869 {
00870     int ix = (he->ix > 0 ? he->ix : 0);
00871     char * val, * t;
00872 
00873 assert(ix == 0);
00874     if (!(he->t == RPM_BIN_TYPE)) {
00875         val = xstrdup(_("(not a blob)"));
00876     } else {
00877         unsigned char * pkt = (unsigned char *) he->p.ui8p;
00878         unsigned int pktlen = 0;
00879         unsigned int v = (unsigned int) *pkt;
00880         pgpTag tag = 0;
00881         unsigned int plen;
00882         unsigned int hlen = 0;
00883 
00884         if (v & 0x80) {
00885             if (v & 0x40) {
00886                 tag = (v & 0x3f);
00887                 plen = pgpLen((byte *)pkt+1, &hlen);
00888             } else {
00889                 tag = (v >> 2) & 0xf;
00890                 plen = (1 << (v & 0x3));
00891                 hlen = pgpGrab((byte *)pkt+1, plen);
00892             }
00893         
00894             pktlen = 1 + plen + hlen;
00895         }
00896 
00897         if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
00898             val = xstrdup(_("(not an OpenPGP signature)"));
00899         } else {
00900             pgpDig dig = pgpDigNew(0);
00901             pgpDigParams sigp = pgpGetSignature(dig);
00902             size_t nb = 0;
00903             const char *tempstr;
00904 
00905             (void) pgpPrtPkts((byte *)pkt, pktlen, dig, 0);
00906 
00907             val = NULL;
00908         again:
00909             nb += 100;
00910             val = t = xrealloc(val, nb + 1);
00911 
00912             switch (sigp->pubkey_algo) {
00913             case PGPPUBKEYALGO_DSA:
00914                 t = stpcpy(t, "DSA");
00915                 break;
00916             case PGPPUBKEYALGO_RSA:
00917                 t = stpcpy(t, "RSA");
00918                 break;
00919             default:
00920                 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->pubkey_algo);
00921                 t += strlen(t);
00922                 break;
00923             }
00924             if (t + 5 >= val + nb)
00925                 goto again;
00926             *t++ = '/';
00927             switch (sigp->hash_algo) {
00928             case PGPHASHALGO_MD5:
00929                 t = stpcpy(t, "MD5");
00930                 break;
00931             case PGPHASHALGO_SHA1:
00932                 t = stpcpy(t, "SHA1");
00933                 break;
00934             default:
00935                 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->hash_algo);
00936                 t += strlen(t);
00937                 break;
00938             }
00939             if (t + strlen (", ") + 1 >= val + nb)
00940                 goto again;
00941 
00942             t = stpcpy(t, ", ");
00943 
00944             /* this is important if sizeof(uint32_t) ! sizeof(time_t) */
00945             {   time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
00946                 struct tm * tstruct = localtime(&dateint);
00947                 if (tstruct)
00948                     (void) strftime(t, (nb - (t - val)), "%c", tstruct);
00949             }
00950             t += strlen(t);
00951             if (t + strlen (", Key ID ") + 1 >= val + nb)
00952                 goto again;
00953             t = stpcpy(t, ", Key ID ");
00954             tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
00955             if (t + strlen (tempstr) > val + nb)
00956                 goto again;
00957             t = stpcpy(t, tempstr);
00958 
00959             dig = pgpDigFree(dig);
00960         }
00961     }
00962 
00963     return val;
00964 }
00965 
00971 static /*@only@*/ char * depflagsFormat(HE_t he)
00972         /*@*/
00973 {
00974     int ix = (he->ix > 0 ? he->ix : 0);
00975     char * val;
00976 
00977 assert(ix == 0);
00978     if (he->t != RPM_UINT64_TYPE) {
00979         val = xstrdup(_("(invalid type)"));
00980     } else {
00981         uint64_t anint = he->p.ui64p[ix];
00982         char *t, *buf;
00983 
00984         t = buf = alloca(32);
00985         *t = '\0';
00986 
00987 #ifdef  NOTYET  /* XXX appending markers breaks :depflags format. */
00988         if (anint & RPMSENSE_SCRIPT_PRE)
00989             t = stpcpy(t, "(pre)");
00990         else if (anint & RPMSENSE_SCRIPT_POST)
00991             t = stpcpy(t, "(post)");
00992         else if (anint & RPMSENSE_SCRIPT_PREUN)
00993             t = stpcpy(t, "(preun)");
00994         else if (anint & RPMSENSE_SCRIPT_POSTUN)
00995             t = stpcpy(t, "(postun)");
00996 #endif
00997         if (anint & RPMSENSE_SENSEMASK)
00998             *t++ = ' ';
00999         if (anint & RPMSENSE_LESS)
01000             *t++ = '<';
01001         if (anint & RPMSENSE_GREATER)
01002             *t++ = '>';
01003         if (anint & RPMSENSE_EQUAL)
01004             *t++ = '=';
01005         if (anint & RPMSENSE_SENSEMASK)
01006             *t++ = ' ';
01007         *t = '\0';
01008 
01009         val = xstrdup(buf);
01010     }
01011 
01012     return val;
01013 }
01014 
01021 static int instprefixTag(Header h, HE_t he)
01022         /*@modifies he @*/
01023 {
01024     he->tag = RPMTAG_INSTALLPREFIX;
01025     if (headerGet(h, he, 0))
01026         return 0;
01027 
01028     he->tag = RPMTAG_INSTPREFIXES;
01029     if (headerGet(h, he, 0)) {
01030         rpmTagData array = { .argv = he->p.argv };
01031         he->t = RPM_STRING_TYPE;
01032         he->c = 1;
01033         he->p.str = xstrdup(array.argv[0]);
01034         he->freeData = 1;
01035         array.ptr = _free(array.ptr);
01036         return 0;
01037     }
01038     return 1;
01039 }
01040 
01047 static int triggercondsTag(Header h, HE_t he)
01048         /*@modifies he @*/
01049 {
01050     HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
01051     rpmTagData flags = { .ptr = NULL };
01052     rpmTagData indices = { .ptr = NULL };
01053     rpmTagData names = { .ptr = NULL };
01054     rpmTagData versions = { .ptr = NULL };
01055     rpmTagData s;
01056     rpmTagCount numNames;
01057     rpmTagCount numScripts;
01058     unsigned i, j;
01059     int rc = 1;         /* assume failure */
01060     int xx;
01061 
01062     he->freeData = 0;
01063 
01064 /*@-compmempass@*/
01065     _he->tag = RPMTAG_TRIGGERNAME;
01066     xx = headerGet(h, _he, 0);
01067     names.argv = _he->p.argv;
01068     numNames = _he->c;
01069     if (!xx) {          /* no triggers, succeed anyways */
01070         rc = 0;
01071         goto exit;
01072     }
01073 
01074     _he->tag = RPMTAG_TRIGGERINDEX;
01075     xx = headerGet(h, _he, 0);
01076     indices.ui32p = _he->p.ui32p;
01077     if (!xx) goto exit;
01078 
01079     _he->tag = RPMTAG_TRIGGERFLAGS;
01080     xx = headerGet(h, _he, 0);
01081     flags.ui32p = _he->p.ui32p;
01082     if (!xx) goto exit;
01083 
01084     _he->tag = RPMTAG_TRIGGERVERSION;
01085     xx = headerGet(h, _he, 0);
01086     versions.argv = _he->p.argv;
01087     if (!xx) goto exit;
01088 
01089     _he->tag = RPMTAG_TRIGGERSCRIPTS;
01090     xx = headerGet(h, _he, 0);
01091     s.argv = _he->p.argv;
01092     numScripts = _he->c;
01093     if (!xx) goto exit;
01094 /*@=compmempass@*/
01095 
01096     _he->tag = he->tag;
01097     _he->t = RPM_UINT32_TYPE;
01098     _he->p.ui32p = NULL;
01099     _he->c = 1;
01100     _he->freeData = 0;
01101 
01102     he->t = RPM_STRING_ARRAY_TYPE;
01103     he->c = numScripts;
01104 
01105     he->freeData = 1;
01106     he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
01107     for (i = 0; i < (unsigned) he->c; i++) {
01108         char * item, * flagsStr;
01109         char * chptr;
01110 
01111         chptr = xstrdup("");
01112 
01113         for (j = 0; j < (unsigned) numNames; j++) {
01114             if (indices.ui32p[j] != i)
01115                 /*@innercontinue@*/ continue;
01116 
01117             item = xmalloc(strlen(names.argv[j]) + strlen(versions.argv[j]) + 20);
01118 /*@-compmempass@*/
01119             if (flags.ui32p[j] & RPMSENSE_SENSEMASK) {
01120                 _he->p.ui32p = &flags.ui32p[j];
01121                 flagsStr = depflagsFormat(_he);
01122                 sprintf(item, "%s %s %s", names.argv[j], flagsStr, versions.argv[j]);
01123                 flagsStr = _free(flagsStr);
01124             } else
01125                 strcpy(item, names.argv[j]);
01126 /*@=compmempass@*/
01127 
01128             chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
01129             if (*chptr != '\0') strcat(chptr, ", ");
01130             strcat(chptr, item);
01131             item = _free(item);
01132         }
01133 
01134         he->p.argv[i] = chptr;
01135     }
01136     rc = 0;
01137 
01138 exit:
01139     indices.ptr = _free(indices.ptr);
01140     flags.ptr = _free(flags.ptr);
01141     names.ptr = _free(names.ptr);
01142     versions.ptr = _free(versions.ptr);
01143     s.ptr = _free(s.ptr);
01144 
01145     return rc;
01146 }
01147 
01154 static int triggertypeTag(Header h, HE_t he)
01155         /*@modifies he @*/
01156 {
01157     HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
01158     rpmTagData indices;
01159     rpmTagData flags;
01160     rpmTagData s;
01161     rpmTagCount numNames;
01162     rpmTagCount numScripts;
01163     unsigned i, j;
01164     int rc = 1;         /* assume failure */
01165     int xx;
01166 
01167     he->freeData = 0;
01168 
01169 /*@-compmempass@*/
01170     _he->tag = RPMTAG_TRIGGERINDEX;
01171     xx = headerGet(h, _he, 0);
01172     indices.ui32p = _he->p.ui32p;
01173     numNames = _he->c;
01174     if (!xx) goto exit;
01175 
01176     _he->tag = RPMTAG_TRIGGERFLAGS;
01177     xx = headerGet(h, _he, 0);
01178     flags.ui32p = _he->p.ui32p;
01179     if (!xx) goto exit;
01180 
01181     _he->tag = RPMTAG_TRIGGERSCRIPTS;
01182     xx = headerGet(h, _he, 0);
01183     s.argv = _he->p.argv;
01184     numScripts = _he->c;
01185     if (!xx) goto exit;
01186 /*@=compmempass@*/
01187 
01188     he->t = RPM_STRING_ARRAY_TYPE;
01189     he->c = numScripts;
01190 
01191     he->freeData = 1;
01192     he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
01193     for (i = 0; i < (unsigned) he->c; i++) {
01194         for (j = 0; j < (unsigned) numNames; j++) {
01195             if (indices.ui32p[j] != i)
01196                 /*@innercontinue@*/ continue;
01197 
01198             /* XXX FIXME: there's memory leaks here. */
01199             if (flags.ui32p[j] & RPMSENSE_TRIGGERPREIN)
01200                 he->p.argv[i] = xstrdup("prein");
01201             else if (flags.ui32p[j] & RPMSENSE_TRIGGERIN)
01202                 he->p.argv[i] = xstrdup("in");
01203             else if (flags.ui32p[j] & RPMSENSE_TRIGGERUN)
01204                 he->p.argv[i] = xstrdup("un");
01205             else if (flags.ui32p[j] & RPMSENSE_TRIGGERPOSTUN)
01206                 he->p.argv[i] = xstrdup("postun");
01207             else
01208                 he->p.argv[i] = xstrdup("");
01209             /*@innerbreak@*/ break;
01210         }
01211     }
01212     rc = 0;
01213 
01214 exit:
01215     indices.ptr = _free(indices.ptr);
01216     flags.ptr = _free(flags.ptr);
01217     s.ptr = _free(s.ptr);
01218     return 0;
01219 }
01220 
01221 /* I18N look aside diversions */
01222 
01223 #if defined(ENABLE_NLS)
01224 /*@-exportlocal -exportheadervar@*/
01225 /*@unchecked@*/
01226 extern int _nl_msg_cat_cntr;    /* XXX GNU gettext voodoo */
01227 /*@=exportlocal =exportheadervar@*/
01228 #endif
01229 /*@observer@*/ /*@unchecked@*/
01230 static const char * language = "LANGUAGE";
01231 
01232 /*@observer@*/ /*@unchecked@*/
01233 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
01234 
01241 static int i18nTag(Header h, HE_t he)
01242         /*@globals rpmGlobalMacroContext, h_errno @*/
01243         /*@modifies he, rpmGlobalMacroContext @*/
01244 {
01245     char * dstring = rpmExpand(_macro_i18ndomains, NULL);
01246     int rc = 1;         /* assume failure */
01247 
01248     he->t = RPM_STRING_TYPE;
01249     he->p.str = NULL;
01250     he->c = 0;
01251     he->freeData = 0;
01252 
01253     if (dstring && *dstring) {
01254         char *domain, *de;
01255         const char * langval;
01256         const char * msgkey;
01257         const char * msgid;
01258 
01259         {   HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
01260             const char * tn = tagName(he->tag);
01261             char * mk;
01262             size_t nb = sizeof("()");
01263             int xx;
01264             nhe->tag = RPMTAG_NAME;
01265             xx = headerGet(h, nhe, 0);
01266             if (tn)     nb += strlen(tn);
01267             if (nhe->p.str)     nb += strlen(nhe->p.str);
01268             mk = alloca(nb);
01269             sprintf(mk, "%s(%s)", (nhe->p.str ? nhe->p.str : ""), (tn ? tn : ""));
01270             nhe->p.ptr = _free(nhe->p.ptr);
01271             msgkey = mk;
01272         }
01273 
01274         /* change to en_US for msgkey -> msgid resolution */
01275         langval = getenv(language);
01276         (void) setenv(language, "en_US", 1);
01277 #if defined(ENABLE_NLS)
01278 /*@i@*/ ++_nl_msg_cat_cntr;
01279 #endif
01280 
01281         msgid = NULL;
01282         for (domain = dstring; domain != NULL; domain = de) {
01283             de = strchr(domain, ':');
01284             if (de) *de++ = '\0';
01285             msgid = /*@-unrecog@*/ dgettext(domain, msgkey) /*@=unrecog@*/;
01286             if (msgid != msgkey) break;
01287         }
01288 
01289         /* restore previous environment for msgid -> msgstr resolution */
01290         if (langval)
01291             (void) setenv(language, langval, 1);
01292         else
01293             unsetenv(language);
01294 #if defined(ENABLE_NLS)
01295 /*@i@*/ ++_nl_msg_cat_cntr;
01296 #endif
01297 
01298         if (domain && msgid) {
01299             const char * s = /*@-unrecog@*/ dgettext(domain, msgid) /*@=unrecog@*/;
01300             if (s) {
01301                 rc = 0;
01302                 he->p.str = xstrdup(s);
01303                 he->c = 1;
01304                 he->freeData = 1;
01305             }
01306         }
01307     }
01308 
01309 /*@-dependenttrans@*/
01310     dstring = _free(dstring);
01311 /*@=dependenttrans@*/
01312     if (!rc)
01313         return rc;
01314 
01315     rc = headerGet(h, he, HEADERGET_NOEXTENSION);
01316     if (rc) {
01317         rc = 0;
01318         he->p.str = xstrtolocale(he->p.str);
01319         he->freeData = 1;
01320 /*@-nullstate@*/
01321         return rc;
01322 /*@=nullstate@*/
01323     }
01324 
01325     he->t = RPM_STRING_TYPE;
01326     he->p.str = NULL;
01327     he->c = 0;
01328     he->freeData = 0;
01329 
01330     return 1;
01331 }
01332 
01336 static int localeTag(Header h, HE_t he)
01337         /*@modifies he @*/
01338 {
01339     int rc;
01340 
01341     rc = headerGet(h, he, HEADERGET_NOEXTENSION);
01342     if (!rc || he->p.str == NULL || he->c == 0) {
01343         he->t = RPM_STRING_TYPE;
01344         he->freeData = 0;
01345         return 1;
01346     }
01347 
01348     switch (he->t) {
01349     default:
01350         he->freeData = 0;
01351         break;
01352     case RPM_STRING_TYPE:
01353         he->p.str = xstrtolocale(he->p.str);
01354         he->freeData = 1;
01355         break;
01356     case RPM_STRING_ARRAY_TYPE:
01357     {   const char ** argv;
01358         char * te;
01359         size_t l = 0;
01360         unsigned i;
01361         for (i = 0; i < (unsigned) he->c; i++) {
01362             he->p.argv[i] = xstrdup(he->p.argv[i]);
01363             he->p.argv[i] = xstrtolocale(he->p.argv[i]);
01364 assert(he->p.argv[i] != NULL);
01365             l += strlen(he->p.argv[i]) + 1;
01366         }
01367         argv = xmalloc(he->c * sizeof(*argv) + l);
01368         te = (char *)&argv[he->c];
01369         for (i = 0; i < (unsigned) he->c; i++) {
01370             argv[i] = te;
01371             te = stpcpy(te, he->p.argv[i]);
01372             te++;
01373             he->p.argv[i] = _free(he->p.argv[i]);
01374         }
01375         he->p.ptr = _free(he->p.ptr);
01376         he->p.argv = argv;
01377         he->freeData = 1;
01378     }   break;
01379     }
01380 
01381     return 0;
01382 }
01383 
01390 static int summaryTag(Header h, HE_t he)
01391         /*@globals rpmGlobalMacroContext, h_errno @*/
01392         /*@modifies he, rpmGlobalMacroContext @*/
01393 {
01394     he->tag = RPMTAG_SUMMARY;
01395     return i18nTag(h, he);
01396 }
01397 
01404 static int descriptionTag(Header h, HE_t he)
01405         /*@globals rpmGlobalMacroContext, h_errno @*/
01406         /*@modifies he, rpmGlobalMacroContext @*/
01407 {
01408     he->tag = RPMTAG_DESCRIPTION;
01409     return i18nTag(h, he);
01410 }
01411 
01412 static int changelognameTag(Header h, HE_t he)
01413         /*@modifies he @*/
01414 {
01415     he->tag = RPMTAG_CHANGELOGNAME;
01416     return localeTag(h, he);
01417 }
01418 
01419 static int changelogtextTag(Header h, HE_t he)
01420         /*@modifies he @*/
01421 {
01422     he->tag = RPMTAG_CHANGELOGTEXT;
01423     return localeTag(h, he);
01424 }
01425 
01432 static int groupTag(Header h, HE_t he)
01433         /*@globals rpmGlobalMacroContext, h_errno @*/
01434         /*@modifies he, rpmGlobalMacroContext @*/
01435 {
01436     he->tag = RPMTAG_GROUP;
01437     return i18nTag(h, he);
01438 }
01439 
01446 /*@-globuse@*/
01447 static int dbinstanceTag(Header h, HE_t he)
01448         /*@globals rpmGlobalMacroContext, h_errno,
01449                 fileSystem, internalState @*/
01450         /*@modifies he, rpmGlobalMacroContext,
01451                 fileSystem, internalState @*/
01452 {
01453     he->tag = RPMTAG_DBINSTANCE;
01454     he->t = RPM_UINT32_TYPE;
01455     he->p.ui32p = xmalloc(sizeof(*he->p.ui32p));
01456     he->p.ui32p[0] = headerGetInstance(h);
01457     he->freeData = 1;
01458     he->c = 1;
01459     return 0;
01460 }
01461 /*@=globuse@*/
01462 
01468 /*@only@*/
01469 static char * hGetNVRA(Header h)
01470         /*@modifies h @*/
01471 {
01472     const char * N = NULL;
01473     const char * V = NULL;
01474     const char * R = NULL;
01475     const char * A = NULL;
01476     size_t nb = 0;
01477     char * NVRA, * t;
01478 
01479     (void) headerNEVRA(h, &N, NULL, &V, &R, &A);
01480     if (N)      nb += strlen(N);
01481     if (V)      nb += strlen(V) + 1;
01482     if (R)      nb += strlen(R) + 1;
01483 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
01484     /* do not expose the architecture as this is too less
01485        information, as in OpenPKG the "platform" is described by the
01486        architecture+operating-system combination. But as the whole
01487        "platform" information is actually overkill, just revert to the
01488        RPM 4 behaviour and do not expose any such information at all. */
01489 #else
01490     if (A)      nb += strlen(A) + 1;
01491 #endif
01492     nb++;
01493     NVRA = t = xmalloc(nb);
01494     *t = '\0';
01495     if (N)      t = stpcpy(t, N);
01496     if (V)      t = stpcpy( stpcpy(t, "-"), V);
01497     if (R)      t = stpcpy( stpcpy(t, "-"), R);
01498 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
01499     /* do not expose the architecture as this is too less
01500        information, as in OpenPKG the "platform" is described by the
01501        architecture+operating-system combination. But as the whole
01502        "platform" information is actually overkill, just revert to the
01503        RPM 4 behaviour and do not expose any such information at all. */
01504 #else
01505     if (A)      t = stpcpy( stpcpy(t, "."), A);
01506 #endif
01507     N = _free(N);
01508     V = _free(V);
01509     R = _free(R);
01510     A = _free(A);
01511     return NVRA;
01512 }
01513 
01520 /*@-globuse@*/
01521 static int nvraTag(Header h, HE_t he)
01522         /*@globals rpmGlobalMacroContext, h_errno,
01523                 fileSystem, internalState @*/
01524         /*@modifies h, he, rpmGlobalMacroContext,
01525                 fileSystem, internalState @*/
01526 {
01527     he->t = RPM_STRING_TYPE;
01528     he->p.str = hGetNVRA(h);
01529     he->c = 1;
01530     he->freeData = 1;
01531     return 0;
01532 }
01533 /*@=globuse@*/
01534 
01552 static void rpmfiBuildFNames(Header h, rpmTag tagN,
01553                 /*@null@*/ /*@out@*/ const char *** fnp,
01554                 /*@null@*/ /*@out@*/ rpmTagCount * fcp)
01555         /*@modifies *fnp, *fcp @*/
01556 {
01557     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01558     rpmTag dirNameTag = 0;
01559     rpmTag dirIndexesTag = 0;
01560     rpmTagData baseNames;
01561     rpmTagData dirNames;
01562     rpmTagData dirIndexes;
01563     rpmTagData fileNames;
01564     rpmTagCount count;
01565     size_t size;
01566     char * t;
01567     unsigned i;
01568     int xx;
01569 
01570     if (tagN == RPMTAG_BASENAMES) {
01571         dirNameTag = RPMTAG_DIRNAMES;
01572         dirIndexesTag = RPMTAG_DIRINDEXES;
01573     } else if (tagN == RPMTAG_ORIGBASENAMES) {
01574         dirNameTag = RPMTAG_ORIGDIRNAMES;
01575         dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
01576     } else {
01577         if (fnp) *fnp = NULL;
01578         if (fcp) *fcp = 0;
01579         return;         /* programmer error */
01580     }
01581 
01582 /*@-compmempass@*/
01583     he->tag = tagN;
01584     xx = headerGet(h, he, 0);
01585     baseNames.argv = he->p.argv;
01586     count = he->c;
01587 
01588     if (!xx) {
01589         if (fnp) *fnp = NULL;
01590         if (fcp) *fcp = 0;
01591         return;         /* no file list */
01592     }
01593 
01594     he->tag = dirNameTag;
01595     xx = headerGet(h, he, 0);
01596     dirNames.argv = he->p.argv;
01597 
01598     he->tag = dirIndexesTag;
01599     xx = headerGet(h, he, 0);
01600     dirIndexes.ui32p = he->p.ui32p;
01601     count = he->c;
01602 /*@=compmempass@*/
01603 
01604     size = sizeof(*fileNames.argv) * count;
01605     for (i = 0; i < (unsigned)count; i++) {
01606         const char * dn = NULL;
01607         (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
01608         size += strlen(baseNames.argv[i]) + strlen(dn) + 1;
01609     }
01610 
01611     fileNames.argv = xmalloc(size);
01612     t = (char *)&fileNames.argv[count];
01613     for (i = 0; i < (unsigned)count; i++) {
01614         const char * dn = NULL;
01615         (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
01616         fileNames.argv[i] = t;
01617         t = stpcpy( stpcpy(t, dn), baseNames.argv[i]);
01618         *t++ = '\0';
01619     }
01620     baseNames.ptr = _free(baseNames.ptr);
01621     dirNames.ptr = _free(dirNames.ptr);
01622     dirIndexes.ptr = _free(dirIndexes.ptr);
01623 
01624 /*@-onlytrans@*/
01625     if (fnp)
01626         *fnp = fileNames.argv;
01627     else
01628         fileNames.ptr = _free(fileNames.ptr);
01629 /*@=onlytrans@*/
01630     if (fcp) *fcp = count;
01631 }
01632 
01639 static int _fnTag(Header h, HE_t he)
01640         /*@modifies he @*/
01641 {
01642     he->t = RPM_STRING_ARRAY_TYPE;
01643     rpmfiBuildFNames(h, he->tag, &he->p.argv, &he->c);
01644     he->freeData = 1;
01645     return 0;
01646 }
01647 
01648 static int filepathsTag(Header h, HE_t he)
01649         /*@modifies he @*/
01650 {
01651     he->tag = RPMTAG_BASENAMES;
01652     return _fnTag(h, he);
01653 }
01654 
01655 static int origpathsTag(Header h, HE_t he)
01656         /*@modifies he @*/
01657 {
01658     he->tag = RPMTAG_ORIGBASENAMES;
01659     return _fnTag(h, he);
01660 }
01661 
01662 /*@-type@*/ /* FIX: cast? */
01663 static struct headerSprintfExtension_s _headerCompoundFormats[] = {
01664     { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME",
01665         { .tagFunction = changelognameTag } },
01666     { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT",
01667         { .tagFunction = changelogtextTag } },
01668     { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",
01669         { .tagFunction = descriptionTag } },
01670     { HEADER_EXT_TAG, "RPMTAG_GROUP",
01671         { .tagFunction = groupTag } },
01672     { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",
01673         { .tagFunction = instprefixTag } },
01674     { HEADER_EXT_TAG, "RPMTAG_SUMMARY",
01675         { .tagFunction = summaryTag } },
01676     { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",
01677         { .tagFunction = triggercondsTag } },
01678     { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",
01679         { .tagFunction = triggertypeTag } },
01680     { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE",
01681         { .tagFunction = dbinstanceTag } },
01682     { HEADER_EXT_TAG, "RPMTAG_NVRA",
01683         { .tagFunction = nvraTag } },
01684     { HEADER_EXT_TAG, "RPMTAG_FILENAMES",
01685         { .tagFunction = filepathsTag } },
01686     { HEADER_EXT_TAG, "RPMTAG_FILEPATHS",
01687         { .tagFunction = filepathsTag } },
01688     { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS",
01689         { .tagFunction = origpathsTag } },
01690     { HEADER_EXT_FORMAT, "armor",
01691         { .fmtFunction = armorFormat } },
01692     { HEADER_EXT_FORMAT, "base64",
01693         { .fmtFunction = base64Format } },
01694     { HEADER_EXT_FORMAT, "depflags",
01695         { .fmtFunction = depflagsFormat } },
01696     { HEADER_EXT_FORMAT, "fflags",
01697         { .fmtFunction = fflagsFormat } },
01698     { HEADER_EXT_FORMAT, "perms",
01699         { .fmtFunction = permsFormat } },
01700     { HEADER_EXT_FORMAT, "permissions", 
01701         { .fmtFunction = permsFormat } },
01702     { HEADER_EXT_FORMAT, "pgpsig",
01703         { .fmtFunction = pgpsigFormat } },
01704     { HEADER_EXT_FORMAT, "triggertype", 
01705         { .fmtFunction = triggertypeFormat } },
01706     { HEADER_EXT_FORMAT, "xml",
01707         { .fmtFunction = xmlFormat } },
01708     { HEADER_EXT_FORMAT, "yaml",
01709         { .fmtFunction = yamlFormat } },
01710     { HEADER_EXT_MORE, NULL,            { (void *) &headerDefaultFormats } }
01711 } ;
01712 /*@=type@*/
01713 
01714 headerSprintfExtension headerCompoundFormats = &_headerCompoundFormats[0];
01715 
01716 /*====================================================================*/
01717 
01718 void rpmDisplayQueryTags(FILE * fp, headerTagTableEntry _rpmTagTable, headerSprintfExtension _rpmHeaderFormats)
01719 {
01720     const struct headerTagTableEntry_s * t;
01721     headerSprintfExtension exts;
01722     headerSprintfExtension ext;
01723     int extNum;
01724 
01725     if (fp == NULL)
01726         fp = stdout;
01727     if (_rpmTagTable == NULL)
01728         _rpmTagTable = rpmTagTable;
01729 
01730     /* XXX this should use rpmHeaderFormats, but there are linkage problems. */
01731     if (_rpmHeaderFormats == NULL)
01732         _rpmHeaderFormats = headerCompoundFormats;
01733 
01734     for (t = _rpmTagTable; t && t->name; t++) {
01735         /*@observer@*/
01736         static const char * tagtypes[] = {
01737                 "", "char", "uint8", "uint16", "uint32", "uint64",
01738                 "string", "octets", "argv", "i18nstring",
01739         };
01740         uint32_t ttype;
01741 
01742         if (rpmIsVerbose()) {
01743             fprintf(fp, "%-20s %6d", t->name + 7, t->val);
01744             ttype = t->type & RPM_MASK_TYPE;
01745             if (ttype < RPM_MIN_TYPE || ttype > RPM_MAX_TYPE)
01746                 continue;
01747             if (t->type & RPM_OPENPGP_RETURN_TYPE)
01748                 fprintf(fp, " openpgp");
01749             if (t->type & RPM_X509_RETURN_TYPE)
01750                 fprintf(fp, " x509");
01751             if (t->type & RPM_ASN1_RETURN_TYPE)
01752                 fprintf(fp, " asn1");
01753             if (t->type & RPM_OPAQUE_RETURN_TYPE)
01754                 fprintf(fp, " opaque");
01755             fprintf(fp, " %s", tagtypes[ttype]);
01756             if (t->type & RPM_ARRAY_RETURN_TYPE)
01757                 fprintf(fp, " array");
01758             if (t->type & RPM_MAPPING_RETURN_TYPE)
01759                 fprintf(fp, " mapping");
01760             if (t->type & RPM_PROBE_RETURN_TYPE)
01761                 fprintf(fp, " probe");
01762             if (t->type & RPM_TREE_RETURN_TYPE)
01763                 fprintf(fp, " tree");
01764         } else
01765             fprintf(fp, "%s", t->name + 7);
01766         fprintf(fp, "\n");
01767     }
01768 
01769     exts = _rpmHeaderFormats;
01770     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
01771         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
01772     {
01773         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
01774             continue;
01775 
01776         /* XXX don't print header tags twice. */
01777         if (tagValue(ext->name) > 0)
01778             continue;
01779         fprintf(fp, "%s\n", ext->name + 7);
01780     }
01781 }
01782 
01783 /*====================================================================*/
01784 
01785 #define PARSER_BEGIN    0
01786 #define PARSER_IN_ARRAY 1
01787 #define PARSER_IN_EXPR  2
01788 
01791 typedef /*@abstract@*/ struct sprintfTag_s * sprintfTag;
01792 
01795 struct sprintfTag_s {
01796     HE_s he;
01797 /*@null@*/
01798     headerTagFormatFunction fmt;
01799 /*@null@*/
01800     headerTagTagFunction ext;   
01801     int extNum;
01802     rpmTag tagno;
01803     int justOne;
01804     int arrayCount;
01805 /*@kept@*/
01806     char * format;
01807 /*@kept@*/ /*@null@*/
01808     char * type;
01809     unsigned pad;
01810 };
01811 
01814 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken;
01815 
01818 struct sprintfToken_s {
01819     enum {
01820         PTOK_NONE       = 0,
01821         PTOK_TAG        = 1,
01822         PTOK_ARRAY      = 2,
01823         PTOK_STRING     = 3,
01824         PTOK_COND       = 4
01825     } type;
01826     union {
01827         struct sprintfTag_s tag;        
01828         struct {
01829         /*@only@*/
01830             sprintfToken format;
01831             size_t numTokens;
01832         } array;                        
01833         struct {
01834         /*@dependent@*/
01835             char * string;
01836             size_t len;
01837         } string;                       
01838         struct {
01839         /*@only@*/ /*@null@*/
01840             sprintfToken ifFormat;
01841             size_t numIfTokens;
01842         /*@only@*/ /*@null@*/
01843             sprintfToken elseFormat;
01844             size_t numElseTokens;
01845             struct sprintfTag_s tag;
01846         } cond;                         
01847     } u;
01848 };
01849 
01852 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs;
01853 
01856 struct headerSprintfArgs_s {
01857     Header h;
01858     char * fmt;
01859 /*@observer@*/ /*@temp@*/
01860     headerTagTableEntry tags;
01861 /*@observer@*/ /*@temp@*/
01862     headerSprintfExtension exts;
01863 /*@observer@*/ /*@null@*/
01864     const char * errmsg;
01865     HE_t ec;                    
01866     int nec;                    
01867     sprintfToken format;
01868 /*@relnull@*/
01869     HeaderIterator hi;
01870 /*@owned@*/
01871     char * val;
01872     size_t vallen;
01873     size_t alloced;
01874     size_t numTokens;
01875     size_t i;
01876 };
01877 
01878 /*@access sprintfTag @*/
01879 /*@access sprintfToken @*/
01880 /*@access headerSprintfArgs @*/
01881 
01884 static char escapedChar(const char ch)  /*@*/
01885 {
01886 /*@-modfilesys@*/
01887 if (_hdr_debug)
01888 fprintf(stderr, "\t\t\\%c\n", ch);
01889 /*@=modfilesys@*/
01890     switch (ch) {
01891     case 'a':   return '\a';
01892     case 'b':   return '\b';
01893     case 'f':   return '\f';
01894     case 'n':   return '\n';
01895     case 'r':   return '\r';
01896     case 't':   return '\t';
01897     case 'v':   return '\v';
01898     default:    return ch;
01899     }
01900 }
01901 
01906 /*@relnull@*/
01907 static HE_t rpmheClean(/*@returned@*/ /*@null@*/ HE_t he)
01908         /*@modifies he @*/
01909 {
01910     if (he) {
01911         if (he->freeData && he->p.ptr != NULL)
01912             he->p.ptr = _free(he->p.ptr);
01913         memset(he, 0, sizeof(*he));
01914     }
01915     return he;
01916 }
01917 
01924 static /*@null@*/ sprintfToken
01925 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, size_t num)
01926         /*@modifies *format @*/
01927 {
01928     unsigned i;
01929 
01930     if (format == NULL) return NULL;
01931 
01932     for (i = 0; i < (unsigned) num; i++) {
01933         switch (format[i].type) {
01934         case PTOK_TAG:
01935             (void) rpmheClean(&format[i].u.tag.he);
01936             /*@switchbreak@*/ break;
01937         case PTOK_ARRAY:
01938             format[i].u.array.format =
01939                 freeFormat(format[i].u.array.format,
01940                         format[i].u.array.numTokens);
01941             /*@switchbreak@*/ break;
01942         case PTOK_COND:
01943             format[i].u.cond.ifFormat =
01944                 freeFormat(format[i].u.cond.ifFormat, 
01945                         format[i].u.cond.numIfTokens);
01946             format[i].u.cond.elseFormat =
01947                 freeFormat(format[i].u.cond.elseFormat, 
01948                         format[i].u.cond.numElseTokens);
01949             (void) rpmheClean(&format[i].u.cond.tag.he);
01950             /*@switchbreak@*/ break;
01951         case PTOK_NONE:
01952         case PTOK_STRING:
01953         default:
01954             /*@switchbreak@*/ break;
01955         }
01956     }
01957     format = _free(format);
01958     return NULL;
01959 }
01960 
01966 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
01967         /*@modifies hsa */
01968 {
01969     sprintfTag tag =
01970         (hsa->format->type == PTOK_TAG
01971             ? &hsa->format->u.tag :
01972         (hsa->format->type == PTOK_ARRAY
01973             ? &hsa->format->u.array.format->u.tag :
01974         NULL));
01975 
01976     if (hsa != NULL) {
01977         hsa->i = 0;
01978         if (tag != NULL && tag->tagno == -2)
01979             hsa->hi = headerInit(hsa->h);
01980     }
01981 /*@-nullret@*/
01982     return hsa;
01983 /*@=nullret@*/
01984 }
01985 
01991 /*@null@*/
01992 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
01993         /*@modifies hsa */
01994 {
01995     sprintfToken fmt = NULL;
01996     sprintfTag tag =
01997         (hsa->format->type == PTOK_TAG
01998             ? &hsa->format->u.tag :
01999         (hsa->format->type == PTOK_ARRAY
02000             ? &hsa->format->u.array.format->u.tag :
02001         NULL));
02002 
02003     if (hsa != NULL && hsa->i < hsa->numTokens) {
02004         fmt = hsa->format + hsa->i;
02005         if (hsa->hi == NULL) {
02006             hsa->i++;
02007         } else {
02008             HE_t he = rpmheClean(&tag->he);
02009             if (!headerNext(hsa->hi, he, 0))
02010             {
02011                 tag->tagno = 0;
02012                 return NULL;
02013             }
02014             he->avail = 1;
02015             tag->tagno = he->tag;
02016         }
02017     }
02018 
02019 /*@-dependenttrans -onlytrans@*/
02020     return fmt;
02021 /*@=dependenttrans =onlytrans@*/
02022 }
02023 
02029 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02030         /*@modifies hsa */
02031 {
02032     if (hsa != NULL) {
02033         hsa->hi = headerFini(hsa->hi);
02034         hsa->i = 0;
02035     }
02036 /*@-nullret@*/
02037     return hsa;
02038 /*@=nullret@*/
02039 }
02040 
02047 /*@dependent@*/ /*@exposed@*/
02048 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02049         /*@modifies hsa */
02050 {
02051     if ((hsa->vallen + need) >= hsa->alloced) {
02052         if (hsa->alloced <= need)
02053             hsa->alloced += need;
02054         hsa->alloced <<= 1;
02055         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02056     }
02057     return hsa->val + hsa->vallen;
02058 }
02059 
02067 /*@observer@*/ /*@null@*/
02068 static const char * myTagName(headerTagTableEntry tbl, uint32_t val,
02069                 /*@null@*/ uint32_t *typep)
02070         /*@modifies *typep @*/
02071 {
02072     static char name[128];      /* XXX Ick. */
02073     const char * s;
02074     char *t;
02075 
02076     /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
02077     if (tbl == NULL || tbl == rpmTagTable) {
02078         s = tagName(val);
02079         if (s != NULL && typep != NULL)
02080             *typep = tagType(val);
02081         return s;
02082     }
02083 
02084     for (; tbl->name != NULL; tbl++) {
02085         if (tbl->val == val)
02086             break;
02087     }
02088     if ((s = tbl->name) == NULL)
02089         return NULL;
02090     s += sizeof("RPMTAG_") - 1;
02091     t = name;
02092     *t++ = *s++;
02093     while (*s != '\0')
02094         *t++ = (char)xtolower((int)*s++);
02095     *t = '\0';
02096     if (typep)
02097         *typep = tbl->type;
02098     return name;
02099 }
02100 
02107 static uint32_t myTagValue(headerTagTableEntry tbl, const char * name)
02108         /*@*/
02109 {
02110     uint32_t val = 0;
02111 
02112     /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
02113     if (tbl == NULL || tbl == rpmTagTable)
02114         val = tagValue(name);
02115     else
02116     for (; tbl->name != NULL; tbl++) {
02117         if (xstrcasecmp(tbl->name, name))
02118             continue;
02119         val = tbl->val;
02120         break;
02121     }
02122     return val;
02123 }
02124 
02132 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02133         /*@modifies token @*/
02134 {
02135     headerSprintfExtension exts = hsa->exts;
02136     headerSprintfExtension ext;
02137     sprintfTag stag = (token->type == PTOK_COND
02138         ? &token->u.cond.tag : &token->u.tag);
02139     int extNum;
02140 
02141     stag->fmt = NULL;
02142     stag->ext = NULL;
02143     stag->extNum = 0;
02144     stag->tagno = -1;
02145 
02146     if (!strcmp(name, "*")) {
02147         stag->tagno = -2;
02148         goto bingo;
02149     }
02150 
02151     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02152         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02153         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02154         name = t;
02155     }
02156 
02157     /* Search extensions for specific tag override. */
02158     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
02159         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
02160     {
02161         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02162             continue;
02163         if (!xstrcasecmp(ext->name, name)) {
02164             stag->ext = ext->u.tagFunction;
02165             stag->extNum = extNum;
02166             goto bingo;
02167         }
02168     }
02169 
02170     /* Search tag names. */
02171     stag->tagno = myTagValue(hsa->tags, name);
02172     if (stag->tagno != 0)
02173         goto bingo;
02174 
02175     return 1;
02176 
02177 bingo:
02178     /* Search extensions for specific format. */
02179     if (stag->type != NULL)
02180     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02181             ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1))
02182     {
02183         if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02184             continue;
02185         if (!strcmp(ext->name, stag->type)) {
02186             stag->fmt = ext->u.fmtFunction;
02187             break;
02188         }
02189     }
02190     return 0;
02191 }
02192 
02193 /* forward ref */
02202 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02203                 char * str, /*@out@*/char ** endPtr)
02204         /*@modifies hsa, str, token, *endPtr @*/
02205         /*@requires maxSet(endPtr) >= 0 @*/;
02206 
02217 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
02218                 /*@out@*/ sprintfToken * formatPtr,
02219                 /*@out@*/ size_t * numTokensPtr,
02220                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
02221         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
02222         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02223                 /\ maxSet(endPtr) >= 0 @*/
02224 {
02225 /*@observer@*/
02226 static const char *pstates[] = {
02227 "NORMAL", "ARRAY", "EXPR", "WTF?"
02228 };
02229     char * chptr, * start, * next, * dst;
02230     sprintfToken format;
02231     sprintfToken token;
02232     size_t numTokens;
02233     unsigned i;
02234     int done = 0;
02235 
02236 /*@-modfilesys@*/
02237 if (_hdr_debug)
02238 fprintf(stderr, "-->     parseFormat(%p, \"%s\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]);
02239 /*@=modfilesys@*/
02240 
02241     /* upper limit on number of individual formats */
02242     numTokens = 0;
02243     if (str != NULL)
02244     for (chptr = str; *chptr != '\0'; chptr++)
02245         if (*chptr == '%') numTokens++;
02246     numTokens = numTokens * 2 + 1;
02247 
02248     format = xcalloc(numTokens, sizeof(*format));
02249     if (endPtr) *endPtr = NULL;
02250 
02251 /*@-infloops@*/ /* LCL: can't detect done termination */
02252     dst = start = str;
02253     numTokens = 0;
02254     token = NULL;
02255     if (start != NULL)
02256     while (*start != '\0') {
02257         switch (*start) {
02258         case '%':
02259             /* handle %% */
02260             if (*(start + 1) == '%') {
02261                 if (token == NULL || token->type != PTOK_STRING) {
02262                     token = format + numTokens++;
02263                     token->type = PTOK_STRING;
02264                     /*@-temptrans -assignexpose@*/
02265                     dst = token->u.string.string = start;
02266                     /*@=temptrans =assignexpose@*/
02267                 }
02268                 start++;
02269                 *dst++ = *start++;
02270                 /*@switchbreak@*/ break;
02271             } 
02272 
02273             token = format + numTokens++;
02274             *dst++ = '\0';
02275             start++;
02276 
02277             if (*start == '|') {
02278                 char * newEnd;
02279 
02280                 start++;
02281                 if (parseExpression(hsa, token, start, &newEnd))
02282                 {
02283                     format = freeFormat(format, numTokens);
02284                     return 1;
02285                 }
02286                 start = newEnd;
02287                 /*@switchbreak@*/ break;
02288             }
02289 
02290             /*@-assignexpose@*/
02291             token->u.tag.format = start;
02292             /*@=assignexpose@*/
02293             token->u.tag.pad = 0;
02294             token->u.tag.justOne = 0;
02295             token->u.tag.arrayCount = 0;
02296 
02297             chptr = start;
02298             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02299             if (!*chptr || *chptr == '%') {
02300                 hsa->errmsg = _("missing { after %");
02301                 format = freeFormat(format, numTokens);
02302                 return 1;
02303             }
02304 
02305 /*@-modfilesys@*/
02306 if (_hdr_debug)
02307 fprintf(stderr, "\tchptr *%p = NUL\n", chptr);
02308 /*@=modfilesys@*/
02309             *chptr++ = '\0';
02310 
02311             while (start < chptr) {
02312                 if (xisdigit((int)*start)) {
02313                     i = strtoul(start, &start, 10);
02314                     token->u.tag.pad += i;
02315                     start = chptr;
02316                     /*@innerbreak@*/ break;
02317                 } else {
02318                     start++;
02319                 }
02320             }
02321 
02322             if (*start == '=') {
02323                 token->u.tag.justOne = 1;
02324                 start++;
02325             } else if (*start == '#') {
02326                 token->u.tag.justOne = 1;
02327                 token->u.tag.arrayCount = 1;
02328                 start++;
02329             }
02330 
02331             next = start;
02332             while (*next && *next != '}') next++;
02333             if (!*next) {
02334                 hsa->errmsg = _("missing } after %{");
02335                 format = freeFormat(format, numTokens);
02336                 return 1;
02337             }
02338 /*@-modfilesys@*/
02339 if (_hdr_debug)
02340 fprintf(stderr, "\tnext *%p = NUL\n", next);
02341 /*@=modfilesys@*/
02342             *next++ = '\0';
02343 
02344             chptr = start;
02345             while (*chptr && *chptr != ':') chptr++;
02346 
02347             if (*chptr != '\0') {
02348                 *chptr++ = '\0';
02349                 if (!*chptr) {
02350                     hsa->errmsg = _("empty tag format");
02351                     format = freeFormat(format, numTokens);
02352                     return 1;
02353                 }
02354                 /*@-assignexpose@*/
02355                 token->u.tag.type = chptr;
02356                 /*@=assignexpose@*/
02357             } else {
02358                 token->u.tag.type = NULL;
02359             }
02360             
02361             if (!*start) {
02362                 hsa->errmsg = _("empty tag name");
02363                 format = freeFormat(format, numTokens);
02364                 return 1;
02365             }
02366 
02367             i = 0;
02368             token->type = PTOK_TAG;
02369 
02370             if (findTag(hsa, token, start)) {
02371                 hsa->errmsg = _("unknown tag");
02372                 format = freeFormat(format, numTokens);
02373                 return 1;
02374             }
02375 
02376             dst = start = next;
02377 /*@-modfilesys@*/
02378 if (_hdr_debug)
02379 fprintf(stderr, "\tdst = start = next %p\n", dst);
02380 /*@=modfilesys@*/
02381             /*@switchbreak@*/ break;
02382 
02383         case '[':
02384 /*@-modfilesys@*/
02385 if (_hdr_debug)
02386 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start);
02387 /*@=modfilesys@*/
02388             *start++ = '\0';
02389             token = format + numTokens++;
02390 
02391             if (parseFormat(hsa, start,
02392                             &token->u.array.format,
02393                             &token->u.array.numTokens,
02394                             &start, PARSER_IN_ARRAY))
02395             {
02396                 format = freeFormat(format, numTokens);
02397                 return 1;
02398             }
02399 
02400             if (!start) {
02401                 hsa->errmsg = _("] expected at end of array");
02402                 format = freeFormat(format, numTokens);
02403                 return 1;
02404             }
02405 
02406             dst = start;
02407 /*@-modfilesys@*/
02408 if (_hdr_debug)
02409 fprintf(stderr, "\tdst = start %p\n", dst);
02410 /*@=modfilesys@*/
02411 
02412             token->type = PTOK_ARRAY;
02413 
02414             /*@switchbreak@*/ break;
02415 
02416         case ']':
02417             if (state != PARSER_IN_ARRAY) {
02418                 hsa->errmsg = _("unexpected ]");
02419                 format = freeFormat(format, numTokens);
02420                 return 1;
02421             }
02422             *start++ = '\0';
02423 /*@-modfilesys@*/
02424 if (_hdr_debug)
02425 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
02426 /*@=modfilesys@*/
02427             if (endPtr) *endPtr = start;
02428             done = 1;
02429             /*@switchbreak@*/ break;
02430 
02431         case '}':
02432             if (state != PARSER_IN_EXPR) {
02433                 hsa->errmsg = _("unexpected }");
02434                 format = freeFormat(format, numTokens);
02435                 return 1;
02436             }
02437             *start++ = '\0';
02438 /*@-modfilesys@*/
02439 if (_hdr_debug)
02440 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
02441 /*@=modfilesys@*/
02442             if (endPtr) *endPtr = start;
02443             done = 1;
02444             /*@switchbreak@*/ break;
02445 
02446         default:
02447             if (token == NULL || token->type != PTOK_STRING) {
02448                 token = format + numTokens++;
02449                 token->type = PTOK_STRING;
02450                 /*@-temptrans -assignexpose@*/
02451                 dst = token->u.string.string = start;
02452                 /*@=temptrans =assignexpose@*/
02453             }
02454 
02455 /*@-modfilesys@*/
02456 if (_hdr_debug)
02457 fprintf(stderr, "\t*%p = *%p \"%s\"\n", dst, start, start);
02458 /*@=modfilesys@*/
02459             if (*start == '\\') {
02460                 start++;
02461                 *dst++ = escapedChar(*start);
02462                 *start++ = '\0';
02463             } else {
02464                 *dst++ = *start++;
02465             }
02466             /*@switchbreak@*/ break;
02467         }
02468         if (done)
02469             break;
02470     }
02471 /*@=infloops@*/
02472 
02473     if (dst != NULL)
02474         *dst = '\0';
02475 
02476     for (i = 0; i < (unsigned) numTokens; i++) {
02477         token = format + i;
02478         switch(token->type) {
02479         default:
02480             /*@switchbreak@*/ break;
02481         case PTOK_STRING:
02482             token->u.string.len = strlen(token->u.string.string);
02483             /*@switchbreak@*/ break;
02484         }
02485     }
02486 
02487     if (numTokensPtr != NULL)
02488         *numTokensPtr = numTokens;
02489     if (formatPtr != NULL)
02490         *formatPtr = format;
02491 
02492     return 0;
02493 }
02494 
02495 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02496                 char * str, /*@out@*/ char ** endPtr)
02497 {
02498     char * chptr;
02499     char * end;
02500 
02501 /*@-modfilesys@*/
02502 if (_hdr_debug)
02503 fprintf(stderr, "-->   parseExpression(%p, %p, \"%s\", %p)\n", hsa, token, str, endPtr);
02504 /*@=modfilesys@*/
02505 
02506     hsa->errmsg = NULL;
02507     chptr = str;
02508     while (*chptr && *chptr != '?') chptr++;
02509 
02510     if (*chptr != '?') {
02511         hsa->errmsg = _("? expected in expression");
02512         return 1;
02513     }
02514 
02515     *chptr++ = '\0';
02516 
02517     if (*chptr != '{') {
02518         hsa->errmsg = _("{ expected after ? in expression");
02519         return 1;
02520     }
02521 
02522     chptr++;
02523 
02524     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
02525                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
02526         return 1;
02527 
02528     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
02529     if (!(end && *end)) {
02530         hsa->errmsg = _("} expected in expression");
02531         token->u.cond.ifFormat =
02532                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02533         return 1;
02534     }
02535 
02536     chptr = end;
02537     if (*chptr != ':' && *chptr != '|') {
02538         hsa->errmsg = _(": expected following ? subexpression");
02539         token->u.cond.ifFormat =
02540                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02541         return 1;
02542     }
02543 
02544     if (*chptr == '|') {
02545         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
02546                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02547         {
02548             token->u.cond.ifFormat =
02549                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02550             return 1;
02551         }
02552     } else {
02553         chptr++;
02554 
02555         if (*chptr != '{') {
02556             hsa->errmsg = _("{ expected after : in expression");
02557             token->u.cond.ifFormat =
02558                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02559             return 1;
02560         }
02561 
02562         chptr++;
02563 
02564         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
02565                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
02566             return 1;
02567 
02568         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
02569         if (!(end && *end)) {
02570             hsa->errmsg = _("} expected in expression");
02571             token->u.cond.ifFormat =
02572                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02573             return 1;
02574         }
02575 
02576         chptr = end;
02577         if (*chptr != '|') {
02578             hsa->errmsg = _("| expected at end of expression");
02579             token->u.cond.ifFormat =
02580                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02581             token->u.cond.elseFormat =
02582                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02583             return 1;
02584         }
02585     }
02586         
02587     chptr++;
02588 
02589     *endPtr = chptr;
02590 
02591     token->type = PTOK_COND;
02592 
02593     (void) findTag(hsa, token, str);
02594 
02595     return 0;
02596 }
02597 
02606 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
02607                 HE_t he, HE_t ec)
02608         /*@modifies he, ec @*/
02609 {
02610     int rc = 0;
02611     if (!ec->avail) {
02612         he = rpmheClean(he);
02613         rc = fn(hsa->h, he);
02614         *ec = *he;      /* structure copy. */
02615         if (!rc)
02616             ec->avail = 1;
02617     } else
02618         *he = *ec;      /* structure copy. */
02619     he->freeData = 0;
02620     rc = (rc == 0);     /* XXX invert getExtension return. */
02621     return rc;
02622 }
02623 
02631 /*@observer@*/ /*@null@*/
02632 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag,
02633                 uint32_t element)
02634         /*@modifies hsa, tag @*/
02635 {
02636     HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
02637     HE_t he = &tag->he;
02638     char * val = NULL;
02639     size_t need = 0;
02640     char * t, * te;
02641     uint64_t ival = 0;
02642     rpmTagCount countBuf;
02643     int xx;
02644 
02645     if (!he->avail) {
02646         if (tag->ext)
02647             xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
02648         else {
02649             he->tag = tag->tagno;       /* XXX necessary? */
02650             xx = headerGet(hsa->h, he, 0);
02651         }
02652         if (!xx) {
02653             (void) rpmheClean(he);
02654             he->t = RPM_STRING_TYPE;    
02655             he->p.str = xstrdup("(none)");
02656             he->c = 1;
02657             he->freeData = 1;
02658         }
02659         he->avail = 1;
02660     }
02661 
02662     if (tag->arrayCount) {
02663         countBuf = he->c;
02664         he = rpmheClean(he);
02665         he->t = RPM_UINT32_TYPE;
02666         he->p.ui32p = &countBuf;
02667         he->c = 1;
02668         he->freeData = 0;
02669     }
02670 
02671     vhe->tag = he->tag;
02672 
02673     if (he->p.ptr)
02674     switch (he->t) {
02675     default:
02676         val = xstrdup("(unknown type)");
02677         need = strlen(val) + 1;
02678         goto exit;
02679         /*@notreached@*/ break;
02680     case RPM_I18NSTRING_TYPE:
02681     case RPM_STRING_ARRAY_TYPE:
02682         vhe->t = RPM_STRING_TYPE;
02683         vhe->p.str = he->p.argv[element];
02684         vhe->c = he->c;
02685         /* XXX TODO: force array representation? */
02686         vhe->ix = (he->c > 1 ? 0 : -1);
02687         break;
02688     case RPM_STRING_TYPE:
02689         vhe->p.str = he->p.str;
02690         vhe->t = RPM_STRING_TYPE;
02691         vhe->c = he->c;
02692         vhe->ix = -1;
02693         break;
02694     case RPM_UINT8_TYPE:
02695     case RPM_UINT16_TYPE:
02696     case RPM_UINT32_TYPE:
02697     case RPM_UINT64_TYPE:
02698         switch (he->t) {
02699         default:
02700 assert(0);      /* XXX keep gcc quiet. */
02701             /*@innerbreak@*/ break;
02702         case RPM_UINT8_TYPE:
02703             ival = he->p.ui8p[element];
02704             /*@innerbreak@*/ break;
02705         case RPM_UINT16_TYPE:
02706             ival = he->p.ui16p[element];        /* XXX note unsigned. */
02707             /*@innerbreak@*/ break;
02708         case RPM_UINT32_TYPE:
02709             ival = he->p.ui32p[element];
02710             /*@innerbreak@*/ break;
02711         case RPM_UINT64_TYPE:
02712             ival = he->p.ui64p[element];
02713             /*@innerbreak@*/ break;
02714         }
02715         vhe->t = RPM_UINT64_TYPE;
02716         vhe->p.ui64p = &ival;
02717         vhe->c = he->c;
02718         /* XXX TODO: force array representation? */
02719         vhe->ix = (he->c > 1 ? 0 : -1);
02720         break;
02721 
02722     case RPM_BIN_TYPE:
02723         vhe->t = RPM_BIN_TYPE;
02724         vhe->p.ptr = he->p.ptr;
02725         vhe->c = he->c;
02726         vhe->ix = -1;
02727         break;
02728     }
02729 
02730 /*@-compmempass@*/      /* vhe->p.ui64p is stack, not owned */
02731     if (tag->fmt) {
02732         val = tag->fmt(vhe);
02733 assert(val != NULL);
02734     } else {
02735         val = intFormat(vhe, NULL);
02736 assert(val != NULL);
02737     }
02738 /*@=compmempass@*/
02739     if (val)
02740         need = strlen(val) + 1;
02741 
02742 exit:
02743     if (val && need > 0) {
02744         if (tag->format && *tag->format && tag->pad > 0) {
02745             size_t nb;
02746             nb = strlen(tag->format) + sizeof("%s");
02747             t = alloca(nb);
02748             (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s");
02749             nb = tag->pad + strlen(val) + 1;
02750             te = xmalloc(nb);
02751 /*@-formatconst@*/
02752             (void) snprintf(te, nb, t, val);
02753 /*@=formatconst@*/
02754             te[nb-1] = '\0';
02755             val = _free(val);
02756             val = te;
02757             need += tag->pad;
02758         }
02759         t = hsaReserve(hsa, need);
02760         te = stpcpy(t, val);
02761         hsa->vallen += (te - t);
02762         val = _free(val);
02763     }
02764 
02765     return (hsa->val + hsa->vallen);
02766 }
02767 
02775 /*@observer@*/
02776 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
02777                 uint32_t element)
02778         /*@modifies hsa, token @*/
02779 {
02780     char numbuf[64];    /* XXX big enuf for "Tag_0x01234567" */
02781     char * t, * te;
02782     uint32_t i, j;
02783     uint32_t numElements;
02784     sprintfToken spft;
02785     sprintfTag tag = NULL;
02786     HE_t he = NULL;
02787     uint32_t condNumFormats;
02788     size_t need;
02789     int xx;
02790 
02791     /* we assume the token and header have been validated already! */
02792 
02793     switch (token->type) {
02794     case PTOK_NONE:
02795         break;
02796 
02797     case PTOK_STRING:
02798         need = token->u.string.len;
02799         if (need == 0) break;
02800         t = hsaReserve(hsa, need);
02801         te = stpcpy(t, token->u.string.string);
02802         hsa->vallen += (te - t);
02803         break;
02804 
02805     case PTOK_TAG:
02806         t = hsa->val + hsa->vallen;
02807 /*@-modobserver@*/      /* headerCompoundFormats not modified. */
02808         te = formatValue(hsa, &token->u.tag,
02809                         (token->u.tag.justOne ? 0 : element));
02810 /*@=modobserver@*/
02811         if (te == NULL)
02812             return NULL;
02813         break;
02814 
02815     case PTOK_COND:
02816         if (token->u.cond.tag.ext
02817          || headerIsEntry(hsa->h, token->u.cond.tag.tagno))
02818         {
02819             spft = token->u.cond.ifFormat;
02820             condNumFormats = token->u.cond.numIfTokens;
02821         } else {
02822             spft = token->u.cond.elseFormat;
02823             condNumFormats = token->u.cond.numElseTokens;
02824         }
02825 
02826         need = condNumFormats * 20;
02827         if (spft == NULL || need == 0) break;
02828 
02829         t = hsaReserve(hsa, need);
02830         for (i = 0; i < condNumFormats; i++, spft++) {
02831 /*@-modobserver@*/      /* headerCompoundFormats not modified. */
02832             te = singleSprintf(hsa, spft, element);
02833 /*@=modobserver@*/
02834             if (te == NULL)
02835                 return NULL;
02836         }
02837         break;
02838 
02839     case PTOK_ARRAY:
02840         numElements = 0;
02841         spft = token->u.array.format;
02842         for (i = 0; i < token->u.array.numTokens; i++, spft++)
02843         {
02844             tag = &spft->u.tag;
02845             if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne)
02846                 continue;
02847             he = &tag->he;
02848             if (!he->avail) {
02849                 he->tag = tag->tagno;
02850                 if (tag->ext)
02851                     xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
02852                 else
02853                     xx = headerGet(hsa->h, he, 0);
02854                 if (!xx) {
02855                     (void) rpmheClean(he);
02856                     continue;
02857                 }
02858                 he->avail = 1;
02859             }
02860 
02861             /* Check iteration arrays are same dimension (or scalar). */
02862             switch (he->t) {
02863             default:
02864                 if (numElements == 0) {
02865                     numElements = he->c;
02866                     /*@switchbreak@*/ break;
02867                 }
02868                 if (he->c == numElements)
02869                     /*@switchbreak@*/ break;
02870                 hsa->errmsg =
02871                         _("array iterator used with different sized arrays");
02872                 he = rpmheClean(he);
02873                 return NULL;
02874                 /*@notreached@*/ /*@switchbreak@*/ break;
02875             case RPM_BIN_TYPE:
02876             case RPM_STRING_TYPE:
02877                 if (numElements == 0)
02878                     numElements = 1;
02879                 /*@switchbreak@*/ break;
02880             }
02881         }
02882         spft = token->u.array.format;
02883 
02884         if (numElements == 0) {
02885 #ifdef  DYING   /* XXX lots of pugly "(none)" lines with --conflicts. */
02886             need = sizeof("(none)\n") - 1;
02887             t = hsaReserve(hsa, need);
02888             te = stpcpy(t, "(none)\n");
02889             hsa->vallen += (te - t);
02890 #endif
02891         } else {
02892             int isxml;
02893             int isyaml;
02894 
02895             need = numElements * token->u.array.numTokens;
02896             if (need == 0) break;
02897 
02898             tag = &spft->u.tag;
02899 
02900             isxml = (spft->type == PTOK_TAG && tag->type != NULL &&
02901                 !strcmp(tag->type, "xml"));
02902             isyaml = (spft->type == PTOK_TAG && tag->type != NULL &&
02903                 !strcmp(tag->type, "yaml"));
02904 
02905             if (isxml) {
02906                 const char * tagN;
02907                 /* XXX display "Tag_0x01234567" for arbitrary tags. */
02908                 if (tag->tagno & 0x40000000) {
02909                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
02910                                 (unsigned) tag->tagno);
02911                     numbuf[sizeof(numbuf)-1] = '\0';
02912                     tagN = numbuf;
02913                 } else
02914                     tagN = myTagName(hsa->tags, tag->tagno, NULL);
02915                 need = sizeof("  <rpmTag name=\"\">\n") + strlen(tagN);
02916                 te = t = hsaReserve(hsa, need);
02917                 te = stpcpy( stpcpy( stpcpy(te, "  <rpmTag name=\""), tagN), "\">\n");
02918                 hsa->vallen += (te - t);
02919             }
02920             if (isyaml) {
02921                 rpmTag tagT = 0;
02922                 const char * tagN;
02923                 /* XXX display "Tag_0x01234567" for arbitrary tags. */
02924                 if (tag->tagno & 0x40000000) {
02925                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
02926                                 (unsigned) tag->tagno);
02927                     numbuf[sizeof(numbuf)-1] = '\0';
02928                     tagN = numbuf;
02929 /*@-type@*/
02930                     tagT = numElements > 1
02931                         ?  RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
02932 /*@=type@*/
02933                 } else
02934                     tagN = myTagName(hsa->tags, tag->tagno, &tagT);
02935                 need = sizeof("  :     - ") + strlen(tagN);
02936                 te = t = hsaReserve(hsa, need);
02937                 *te++ = ' ';
02938                 *te++ = ' ';
02939                 te = stpcpy(te, tagN);
02940                 *te++ = ':';
02941 /*@-type@*/
02942                 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
02943                         ? '\n' : ' ');
02944 /*@=type@*/
02945                 /* XXX Dirnames: in srpms need "    " indent */
02946 /*@-type@*/
02947                 if (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
02948                  && numElements == 1)
02949 /*@=type@*/
02950                 {
02951                     te = stpcpy(te, "    ");
02952                     if (tag->tagno != 1118)
02953                         te = stpcpy(te, "- ");
02954                 }
02955                 *te = '\0';
02956                 hsa->vallen += (te - t);
02957             }
02958 
02959             need = numElements * token->u.array.numTokens * 10;
02960             t = hsaReserve(hsa, need);
02961             for (j = 0; j < numElements; j++) {
02962                 spft = token->u.array.format;
02963                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
02964 /*@-modobserver@*/      /* headerCompoundFormats not modified. */
02965                     te = singleSprintf(hsa, spft, j);
02966 /*@=modobserver@*/
02967                     if (te == NULL)
02968                         return NULL;
02969                 }
02970             }
02971 
02972             if (isxml) {
02973                 need = sizeof("  </rpmTag>\n") - 1;
02974                 te = t = hsaReserve(hsa, need);
02975                 te = stpcpy(te, "  </rpmTag>\n");
02976                 hsa->vallen += (te - t);
02977             }
02978             if (isyaml) {
02979 #if 0
02980                 need = sizeof("\n") - 1;
02981                 te = t = hsaReserve(hsa, need);
02982                 te = stpcpy(te, "\n");
02983                 hsa->vallen += (te - t);
02984 #endif
02985             }
02986 
02987         }
02988         break;
02989     }
02990 
02991     return (hsa->val + hsa->vallen);
02992 }
02993 
03000 static /*@only@*/ HE_t
03001 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp)
03002         /*@modifies *necp @*/
03003 {
03004     headerSprintfExtension ext;
03005     HE_t ec;
03006     int extNum = 0;
03007 
03008     if (exts != NULL)
03009     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
03010         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
03011     {
03012         ;
03013     }
03014     if (necp)
03015         *necp = extNum;
03016     ec = xcalloc(extNum+1, sizeof(*ec));        /* XXX +1 unnecessary */
03017     return ec;
03018 }
03019 
03026 static /*@null@*/ HE_t
03027 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec)
03028         /*@modifies ec @*/
03029 {
03030     headerSprintfExtension ext;
03031     int extNum;
03032 
03033     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
03034         ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
03035     {
03036         (void) rpmheClean(&ec[extNum]);
03037     }
03038 
03039     ec = _free(ec);
03040     return NULL;
03041 }
03042 
03043 char * headerSprintf(Header h, const char * fmt,
03044                 headerTagTableEntry tags,
03045                 headerSprintfExtension exts,
03046                 errmsg_t * errmsg)
03047 {
03048     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03049     sprintfToken nextfmt;
03050     sprintfTag tag;
03051     char * t, * te;
03052     int isxml;
03053     int isyaml;
03054     int need;
03055 
03056 /*@-modfilesys@*/
03057 if (_hdr_debug)
03058 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg);
03059 /*@=modfilesys@*/
03060 
03061     /* Set some reasonable defaults */
03062     if (tags == NULL)
03063         tags = rpmTagTable;
03064     /* XXX this loses the extensions in lib/formats.c. */
03065     if (exts == NULL)
03066         exts = headerCompoundFormats;
03067  
03068     hsa->h = headerLink(h);
03069     hsa->fmt = xstrdup(fmt);
03070 /*@-assignexpose -dependenttrans@*/
03071     hsa->exts = exts;
03072     hsa->tags = tags;
03073 /*@=assignexpose =dependenttrans@*/
03074     hsa->errmsg = NULL;
03075 
03076     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03077         goto exit;
03078 
03079     hsa->nec = 0;
03080     hsa->ec = rpmecNew(hsa->exts, &hsa->nec);
03081     hsa->val = xstrdup("");
03082 
03083     tag =
03084         (hsa->format->type == PTOK_TAG
03085             ? &hsa->format->u.tag :
03086         (hsa->format->type == PTOK_ARRAY
03087             ? &hsa->format->u.array.format->u.tag :
03088         NULL));
03089     isxml = (tag != NULL && tag->tagno == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03090     isyaml = (tag != NULL && tag->tagno == -2 && tag->type != NULL && !strcmp(tag->type, "yaml"));
03091 
03092     if (isxml) {
03093         need = sizeof("<rpmHeader>\n") - 1;
03094         t = hsaReserve(hsa, need);
03095         te = stpcpy(t, "<rpmHeader>\n");
03096         hsa->vallen += (te - t);
03097     }
03098     if (isyaml) {
03099         need = sizeof("- !!omap\n") - 1;
03100         t = hsaReserve(hsa, need);
03101         te = stpcpy(t, "- !!omap\n");
03102         hsa->vallen += (te - t);
03103     }
03104 
03105     hsa = hsaInit(hsa);
03106     while ((nextfmt = hsaNext(hsa)) != NULL) {
03107 /*@-modobserver@*/      /* headerCompoundFormats not modified. */
03108         te = singleSprintf(hsa, nextfmt, 0);
03109 /*@=modobserver@*/
03110         if (te == NULL) {
03111             hsa->val = _free(hsa->val);
03112             break;
03113         }
03114     }
03115     hsa = hsaFini(hsa);
03116 
03117     if (isxml) {
03118         need = sizeof("</rpmHeader>\n") - 1;
03119         t = hsaReserve(hsa, need);
03120         te = stpcpy(t, "</rpmHeader>\n");
03121         hsa->vallen += (te - t);
03122     }
03123     if (isyaml) {
03124         need = sizeof("\n") - 1;
03125         t = hsaReserve(hsa, need);
03126         te = stpcpy(t, "\n");
03127         hsa->vallen += (te - t);
03128     }
03129 
03130     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03131         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
03132 
03133     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03134     hsa->nec = 0;
03135     hsa->format = freeFormat(hsa->format, hsa->numTokens);
03136 
03137 exit:
03138 /*@-dependenttrans -observertrans @*/
03139     if (errmsg)
03140         *errmsg = hsa->errmsg;
03141 /*@=dependenttrans =observertrans @*/
03142     hsa->h = headerFree(hsa->h);
03143     hsa->fmt = _free(hsa->fmt);
03144 /*@-retexpose@*/
03145     return hsa->val;
03146 /*@=retexpose@*/
03147 }

Generated on Mon Nov 29 2010 05:18:46 for rpm by  doxygen 1.7.2