00001
00005 #include "system.h"
00006
00007 #include "rpmio_internal.h"
00008 #include <rpmbc.h>
00009 #include <rpmcb.h>
00010 #include <rpmmacro.h>
00011
00012 #define _RPMTAG_INTERNAL
00013 #include <rpmtag.h>
00014
00015 #include <rpmlib.h>
00016 #include <rpmfi.h>
00017
00018 #define _RPMEVR_INTERNAL
00019 #include <rpmevr.h>
00020
00021 #include "legacy.h"
00022 #include "argv.h"
00023 #include "misc.h"
00024
00025 #include "debug.h"
00026
00027
00028 extern int _hdr_debug;
00029
00030
00031
00032
00033
00034
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 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) {
00096 b = (char *)istr;
00097 } else
00098 if (nb == 0) {
00099 char myfmt[] = "%llX";
00100 myfmt[3] = ((fmt != NULL && *fmt != '\0') ? *fmt : 'd');
00101 nb = 64;
00102 b = alloca(nb);
00103
00104 xx = snprintf(b, nb, myfmt, ival);
00105
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
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
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
00220 xx = snprintf(val, nb, "%llu", (unsigned long long)he->p.ui64p[0]);
00221
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
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
00274
00275 headerSprintfExtension headerDefaultFormats = &_headerDefaultFormats[0];
00276
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
00291 else if (S_ISSOCK(mode))
00292 perms[0] = 's';
00293
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 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 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 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 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;
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
00443 if (b64decode(enc, (void **)&s, &ns))
00444 return xstrdup(_("(not base64)"));
00445
00446 atype = PGPARMOR_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 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 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
00487
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
00495
00496 val = t = xcalloc(1, nt + 1);
00497 *t = '\0';
00498
00499
00500 { unsigned char * _data = xcalloc(1, ns+1);
00501 memcpy(_data, he->p.ptr, ns);
00502
00503 if ((enc = b64encode(_data, ns)) != NULL) {
00504 t = stpcpy(t, enc);
00505 enc = _free(enc);
00506 }
00507
00508 _data = _free(_data);
00509 }
00510 }
00511
00512
00513 return val;
00514
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("<") - 1; break;
00533 case '&': len += sizeof("&") - 1; break;
00534 default: len += 1; break;
00535 }
00536 }
00537 return len;
00538 }
00539
00546 static char * xmlstrcpy( char * t, const char * s)
00547
00548 {
00549 char * te = t;
00550 int c;
00551
00552 while ((c = (int) *s++) != (int) '\0') {
00553 switch (c) {
00554 case '<': te = stpcpy(te, "<"); break;
00555 case '>': te = stpcpy(te, ">"); break;
00556 case '&': te = stpcpy(te, "&"); break;
00557 default: *te++ = (char) c; break;
00558 }
00559 }
00560 *te = '\0';
00561 return t;
00562 }
00563
00569 static 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:
00586 s = he->p.argv[ix];
00587 xtag = "string";
00588
00589 s = xstrdup(s);
00590 s = xstrtolocale(s);
00591 freeit = 1;
00592 break;
00593 case RPM_I18NSTRING_TYPE:
00594 case RPM_STRING_TYPE:
00595 s = he->p.str;
00596 xtag = "string";
00597
00598 s = xstrdup(s);
00599 s = xstrtolocale(s);
00600 freeit = 1;
00601 break;
00602 case RPM_BIN_TYPE:
00603
00604 { int cpl = b64encode_chars_per_line;
00605 b64encode_chars_per_line = 0;
00606
00607 s = base64Format(he);
00608
00609 b64encode_chars_per_line = cpl;
00610 xtag = "base64";
00611 freeit = 1;
00612 } break;
00613
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 break;
00629 }
00630
00631 if (s == NULL) {
00632 int tlen = 64;
00633 t = memset(alloca(tlen+1), 0, tlen+1);
00634
00635 if (anint != 0)
00636 xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
00637
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( char * t, const char * s, int lvl)
00698
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 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:
00747 case RPM_I18NSTRING_TYPE:
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]))
00751 xx = 1;
00752 if (xx == 0)
00753 while ((c = (int) *s++) != (int) '\0') {
00754 switch (c) {
00755 default:
00756 continue;
00757 case '\n':
00758 xx = 1;
00759 break;
00760 case '-':
00761 case ':':
00762 if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
00763 continue;
00764 xx = 1;
00765 break;
00766 }
00767 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++;
00777 }
00778 } else {
00779 xtag = (element >= 0 ? "- " : NULL);
00780 }
00781
00782
00783 s = xstrdup(he->p.str);
00784 s = xstrtolocale(s);
00785 freeit = 1;
00786 break;
00787 case RPM_BIN_TYPE:
00788
00789 { int cpl = b64encode_chars_per_line;
00790 b64encode_chars_per_line = 0;
00791
00792 s = base64Format(he);
00793 element = -element;
00794
00795 b64encode_chars_per_line = cpl;
00796 xtag = "!!binary ";
00797 freeit = 1;
00798 } break;
00799
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 break;
00815 }
00816
00817 if (s == NULL) {
00818 int tlen = 64;
00819 t = memset(alloca(tlen+1), 0, tlen+1);
00820
00821 xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
00822
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
00853 if (freeit)
00854 s = _free(s);
00855
00856 val = xstrdup(t);
00857
00858 return val;
00859 }
00860
00866 static char * pgpsigFormat(HE_t he)
00867
00868
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
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 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
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
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
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;
01060 int xx;
01061
01062 he->freeData = 0;
01063
01064
01065 _he->tag = RPMTAG_TRIGGERNAME;
01066 xx = headerGet(h, _he, 0);
01067 names.argv = _he->p.argv;
01068 numNames = _he->c;
01069 if (!xx) {
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
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 continue;
01116
01117 item = xmalloc(strlen(names.argv[j]) + strlen(versions.argv[j]) + 20);
01118
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
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
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;
01165 int xx;
01166
01167 he->freeData = 0;
01168
01169
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
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 continue;
01197
01198
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 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
01222
01223 #if defined(ENABLE_NLS)
01224
01225
01226 extern int _nl_msg_cat_cntr;
01227
01228 #endif
01229
01230 static const char * language = "LANGUAGE";
01231
01232
01233 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
01234
01241 static int i18nTag(Header h, HE_t he)
01242
01243
01244 {
01245 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
01246 int rc = 1;
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
01275 langval = getenv(language);
01276 (void) setenv(language, "en_US", 1);
01277 #if defined(ENABLE_NLS)
01278 ++_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 = dgettext(domain, msgkey) ;
01286 if (msgid != msgkey) break;
01287 }
01288
01289
01290 if (langval)
01291 (void) setenv(language, langval, 1);
01292 else
01293 unsetenv(language);
01294 #if defined(ENABLE_NLS)
01295 ++_nl_msg_cat_cntr;
01296 #endif
01297
01298 if (domain && msgid) {
01299 const char * s = dgettext(domain, msgid) ;
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
01310 dstring = _free(dstring);
01311
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
01321 return rc;
01322
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
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
01392
01393 {
01394 he->tag = RPMTAG_SUMMARY;
01395 return i18nTag(h, he);
01396 }
01397
01404 static int descriptionTag(Header h, HE_t he)
01405
01406
01407 {
01408 he->tag = RPMTAG_DESCRIPTION;
01409 return i18nTag(h, he);
01410 }
01411
01412 static int changelognameTag(Header h, HE_t he)
01413
01414 {
01415 he->tag = RPMTAG_CHANGELOGNAME;
01416 return localeTag(h, he);
01417 }
01418
01419 static int changelogtextTag(Header h, HE_t he)
01420
01421 {
01422 he->tag = RPMTAG_CHANGELOGTEXT;
01423 return localeTag(h, he);
01424 }
01425
01432 static int groupTag(Header h, HE_t he)
01433
01434
01435 {
01436 he->tag = RPMTAG_GROUP;
01437 return i18nTag(h, he);
01438 }
01439
01446
01447 static int dbinstanceTag(Header h, HE_t he)
01448
01449
01450
01451
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
01462
01468
01469 static char * hGetNVRA(Header h)
01470
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)
01484
01485
01486
01487
01488
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)
01499
01500
01501
01502
01503
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
01521 static int nvraTag(Header h, HE_t he)
01522
01523
01524
01525
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
01534
01552 static void rpmfiBuildFNames(Header h, rpmTag tagN,
01553 const char *** fnp,
01554 rpmTagCount * fcp)
01555
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;
01580 }
01581
01582
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;
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
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
01625 if (fnp)
01626 *fnp = fileNames.argv;
01627 else
01628 fileNames.ptr = _free(fileNames.ptr);
01629
01630 if (fcp) *fcp = count;
01631 }
01632
01639 static int _fnTag(Header h, HE_t he)
01640
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
01650 {
01651 he->tag = RPMTAG_BASENAMES;
01652 return _fnTag(h, he);
01653 }
01654
01655 static int origpathsTag(Header h, HE_t he)
01656
01657 {
01658 he->tag = RPMTAG_ORIGBASENAMES;
01659 return _fnTag(h, he);
01660 }
01661
01662
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
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
01731 if (_rpmHeaderFormats == NULL)
01732 _rpmHeaderFormats = headerCompoundFormats;
01733
01734 for (t = _rpmTagTable; t && t->name; t++) {
01735
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
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 struct sprintfTag_s * sprintfTag;
01792
01795 struct sprintfTag_s {
01796 HE_s he;
01797
01798 headerTagFormatFunction fmt;
01799
01800 headerTagTagFunction ext;
01801 int extNum;
01802 rpmTag tagno;
01803 int justOne;
01804 int arrayCount;
01805
01806 char * format;
01807
01808 char * type;
01809 unsigned pad;
01810 };
01811
01814 typedef 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
01830 sprintfToken format;
01831 size_t numTokens;
01832 } array;
01833 struct {
01834
01835 char * string;
01836 size_t len;
01837 } string;
01838 struct {
01839
01840 sprintfToken ifFormat;
01841 size_t numIfTokens;
01842
01843 sprintfToken elseFormat;
01844 size_t numElseTokens;
01845 struct sprintfTag_s tag;
01846 } cond;
01847 } u;
01848 };
01849
01852 typedef struct headerSprintfArgs_s * headerSprintfArgs;
01853
01856 struct headerSprintfArgs_s {
01857 Header h;
01858 char * fmt;
01859
01860 headerTagTableEntry tags;
01861
01862 headerSprintfExtension exts;
01863
01864 const char * errmsg;
01865 HE_t ec;
01866 int nec;
01867 sprintfToken format;
01868
01869 HeaderIterator hi;
01870
01871 char * val;
01872 size_t vallen;
01873 size_t alloced;
01874 size_t numTokens;
01875 size_t i;
01876 };
01877
01878
01879
01880
01881
01884 static char escapedChar(const char ch)
01885 {
01886
01887 if (_hdr_debug)
01888 fprintf(stderr, "\t\t\\%c\n", ch);
01889
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
01907 static HE_t rpmheClean( HE_t he)
01908
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 sprintfToken
01925 freeFormat( sprintfToken format, size_t num)
01926
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 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 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 break;
01951 case PTOK_NONE:
01952 case PTOK_STRING:
01953 default:
01954 break;
01955 }
01956 }
01957 format = _free(format);
01958 return NULL;
01959 }
01960
01966 static headerSprintfArgs hsaInit( headerSprintfArgs hsa)
01967
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
01982 return hsa;
01983
01984 }
01985
01991
01992 static sprintfToken hsaNext( headerSprintfArgs hsa)
01993
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
02020 return fmt;
02021
02022 }
02023
02029 static headerSprintfArgs hsaFini( headerSprintfArgs hsa)
02030
02031 {
02032 if (hsa != NULL) {
02033 hsa->hi = headerFini(hsa->hi);
02034 hsa->i = 0;
02035 }
02036
02037 return hsa;
02038
02039 }
02040
02047
02048 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02049
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
02068 static const char * myTagName(headerTagTableEntry tbl, uint32_t val,
02069 uint32_t *typep)
02070
02071 {
02072 static char name[128];
02073 const char * s;
02074 char *t;
02075
02076
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
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
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
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
02171 stag->tagno = myTagValue(hsa->tags, name);
02172 if (stag->tagno != 0)
02173 goto bingo;
02174
02175 return 1;
02176
02177 bingo:
02178
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
02202 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02203 char * str, char ** endPtr)
02204
02205 ;
02206
02217 static int parseFormat(headerSprintfArgs hsa, char * str,
02218 sprintfToken * formatPtr,
02219 size_t * numTokensPtr,
02220 char ** endPtr, int state)
02221
02222
02223
02224 {
02225
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
02237 if (_hdr_debug)
02238 fprintf(stderr, "--> parseFormat(%p, \"%s\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]);
02239
02240
02241
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
02252 dst = start = str;
02253 numTokens = 0;
02254 token = NULL;
02255 if (start != NULL)
02256 while (*start != '\0') {
02257 switch (*start) {
02258 case '%':
02259
02260 if (*(start + 1) == '%') {
02261 if (token == NULL || token->type != PTOK_STRING) {
02262 token = format + numTokens++;
02263 token->type = PTOK_STRING;
02264
02265 dst = token->u.string.string = start;
02266
02267 }
02268 start++;
02269 *dst++ = *start++;
02270 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 break;
02288 }
02289
02290
02291 token->u.tag.format = start;
02292
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
02306 if (_hdr_debug)
02307 fprintf(stderr, "\tchptr *%p = NUL\n", chptr);
02308
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 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
02339 if (_hdr_debug)
02340 fprintf(stderr, "\tnext *%p = NUL\n", next);
02341
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
02355 token->u.tag.type = chptr;
02356
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
02378 if (_hdr_debug)
02379 fprintf(stderr, "\tdst = start = next %p\n", dst);
02380
02381 break;
02382
02383 case '[':
02384
02385 if (_hdr_debug)
02386 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start);
02387
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
02408 if (_hdr_debug)
02409 fprintf(stderr, "\tdst = start %p\n", dst);
02410
02411
02412 token->type = PTOK_ARRAY;
02413
02414 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
02424 if (_hdr_debug)
02425 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
02426
02427 if (endPtr) *endPtr = start;
02428 done = 1;
02429 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
02439 if (_hdr_debug)
02440 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
02441
02442 if (endPtr) *endPtr = start;
02443 done = 1;
02444 break;
02445
02446 default:
02447 if (token == NULL || token->type != PTOK_STRING) {
02448 token = format + numTokens++;
02449 token->type = PTOK_STRING;
02450
02451 dst = token->u.string.string = start;
02452
02453 }
02454
02455
02456 if (_hdr_debug)
02457 fprintf(stderr, "\t*%p = *%p \"%s\"\n", dst, start, start);
02458
02459 if (*start == '\\') {
02460 start++;
02461 *dst++ = escapedChar(*start);
02462 *start++ = '\0';
02463 } else {
02464 *dst++ = *start++;
02465 }
02466 break;
02467 }
02468 if (done)
02469 break;
02470 }
02471
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 break;
02481 case PTOK_STRING:
02482 token->u.string.len = strlen(token->u.string.string);
02483 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, char ** endPtr)
02497 {
02498 char * chptr;
02499 char * end;
02500
02501
02502 if (_hdr_debug)
02503 fprintf(stderr, "--> parseExpression(%p, %p, \"%s\", %p)\n", hsa, token, str, endPtr);
02504
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
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
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
02609 {
02610 int rc = 0;
02611 if (!ec->avail) {
02612 he = rpmheClean(he);
02613 rc = fn(hsa->h, he);
02614 *ec = *he;
02615 if (!rc)
02616 ec->avail = 1;
02617 } else
02618 *he = *ec;
02619 he->freeData = 0;
02620 rc = (rc == 0);
02621 return rc;
02622 }
02623
02631
02632 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag,
02633 uint32_t element)
02634
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;
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 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
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);
02701 break;
02702 case RPM_UINT8_TYPE:
02703 ival = he->p.ui8p[element];
02704 break;
02705 case RPM_UINT16_TYPE:
02706 ival = he->p.ui16p[element];
02707 break;
02708 case RPM_UINT32_TYPE:
02709 ival = he->p.ui32p[element];
02710 break;
02711 case RPM_UINT64_TYPE:
02712 ival = he->p.ui64p[element];
02713 break;
02714 }
02715 vhe->t = RPM_UINT64_TYPE;
02716 vhe->p.ui64p = &ival;
02717 vhe->c = he->c;
02718
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
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
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
02752 (void) snprintf(te, nb, t, val);
02753
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
02776 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
02777 uint32_t element)
02778
02779 {
02780 char numbuf[64];
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
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
02808 te = formatValue(hsa, &token->u.tag,
02809 (token->u.tag.justOne ? 0 : element));
02810
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
02832 te = singleSprintf(hsa, spft, element);
02833
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
02862 switch (he->t) {
02863 default:
02864 if (numElements == 0) {
02865 numElements = he->c;
02866 break;
02867 }
02868 if (he->c == numElements)
02869 break;
02870 hsa->errmsg =
02871 _("array iterator used with different sized arrays");
02872 he = rpmheClean(he);
02873 return NULL;
02874 break;
02875 case RPM_BIN_TYPE:
02876 case RPM_STRING_TYPE:
02877 if (numElements == 0)
02878 numElements = 1;
02879 break;
02880 }
02881 }
02882 spft = token->u.array.format;
02883
02884 if (numElements == 0) {
02885 #ifdef DYING
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
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
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
02930 tagT = numElements > 1
02931 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
02932
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
02942 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
02943 ? '\n' : ' ');
02944
02945
02946
02947 if (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
02948 && numElements == 1)
02949
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
02965 te = singleSprintf(hsa, spft, j);
02966
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 HE_t
03001 rpmecNew(const headerSprintfExtension exts, int * necp)
03002
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));
03017 return ec;
03018 }
03019
03026 static HE_t
03027 rpmecFree(const headerSprintfExtension exts, HE_t ec)
03028
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
03057 if (_hdr_debug)
03058 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg);
03059
03060
03061
03062 if (tags == NULL)
03063 tags = rpmTagTable;
03064
03065 if (exts == NULL)
03066 exts = headerCompoundFormats;
03067
03068 hsa->h = headerLink(h);
03069 hsa->fmt = xstrdup(fmt);
03070
03071 hsa->exts = exts;
03072 hsa->tags = tags;
03073
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
03108 te = singleSprintf(hsa, nextfmt, 0);
03109
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
03139 if (errmsg)
03140 *errmsg = hsa->errmsg;
03141
03142 hsa->h = headerFree(hsa->h);
03143 hsa->fmt = _free(hsa->fmt);
03144
03145 return hsa->val;
03146
03147 }