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

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