rpm  5.4.10
hdrfmt.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 /* XXX todo: these should likely be in "system.h" */
8 #if defined(HAVE_ICONV)
9 #include <iconv.h>
10 #if defined(__LCLINT__)
11 /*@-declundef -exportheader -incondefs @*/
12 extern /*@only@*/ iconv_t iconv_open(const char *__tocode, const char *__fromcode)
13  /*@*/;
14 
15 extern size_t iconv(iconv_t __cd, /*@null@*/ char ** __inbuf,
16  /*@out@*/ size_t * __inbytesleft,
17  /*@out@*/ char ** __outbuf,
18  /*@out@*/ size_t * __outbytesleft)
19  /*@modifies __cd,
20  *__inbuf, *__inbytesleft, *__outbuf, *__outbytesleft @*/;
21 
22 extern int iconv_close(/*@only@*/ iconv_t __cd)
23  /*@modifies __cd @*/;
24 /*@=declundef =exportheader =incondefs @*/
25 #endif
26 #endif
27 
28 #if defined(HAVE_LANGINFO_H)
29 #include <langinfo.h>
30 #if defined(__LCLINT__)
31 /*@-declundef -exportheader -incondefs @*/
32 extern char *nl_langinfo (nl_item __item)
33  /*@*/;
34 /*@=declundef =exportheader =incondefs @*/
35 #endif
36 #endif
37 
38 #define _MIRE_INTERNAL
39 #include "rpmio_internal.h"
40 #include <rpmbc.h> /* XXX beecrypt base64 */
41 #include <rpmcb.h> /* XXX rpmIsVerbose */
42 #include <rpmmacro.h> /* XXX for %_i18ndomains */
43 #include <rpmuuid.h>
44 #include <argv.h>
45 #include <ugid.h>
46 
47 #define _RPMTAG_INTERNAL
48 #include <rpmtag.h>
49 #define _RPMEVR_INTERNAL
50 #include <rpmevr.h> /* XXX RPMSENSE_FOO */
51 #include <rpmns.h>
52 #include <rpmdb.h>
53 
54 #include <rpmtypes.h> /* XXX rpmfi */
55 #include "misc.h" /* XXX rpmMkdirPath */
56 #include <rpmfi.h> /* XXX RPMFILE_FOO */
57 
58 #include "legacy.h"
59 #include "misc.h"
60 
61 #include "debug.h"
62 
63 
64 #ifdef __cplusplus
65 GENfree(HE_t)
66 #endif /* __cplusplus */
67 
68 /*@unchecked@*/
70 
71 /*@access pgpDig @*/
72 /*@access pgpDigParams @*/
73 /*@access headerSprintfExtension @*/
74 /*@access headerTagTableEntry @*/
75 /*@access Header @*/ /* XXX debugging msgs */
76 /*@access EVR_t @*/
77 /*@access rpmdb @*/ /* XXX for casts */
78 /*@access miRE @*/
79 
87 static char * intFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
88  /*@null@*/ const char *fmt)
89  /*@*/
90 {
91  rpmuint32_t ix = (he->ix > 0 ? he->ix : 0);
92  rpmuint64_t ival = 0;
93  const char * istr = NULL;
94  char * b;
95  size_t nb = 0;
96  int xx;
97 
98  if (fmt == NULL || *fmt == '\0')
99  fmt = "d";
100 
101  switch (he->t) {
102  default:
103  return xstrdup(_("(not a number)"));
104  /*@notreached@*/ break;
105  case RPM_UINT8_TYPE:
106  ival = (rpmuint64_t) he->p.ui8p[ix];
107  break;
108  case RPM_UINT16_TYPE:
109  ival = (rpmuint64_t) he->p.ui16p[ix];
110  break;
111  case RPM_UINT32_TYPE:
112  ival = (rpmuint64_t) he->p.ui32p[ix];
113  break;
114  case RPM_UINT64_TYPE:
115  ival = he->p.ui64p[ix];
116  break;
117  case RPM_STRING_TYPE:
118  istr = he->p.str;
119  break;
121  istr = he->p.argv[ix];
122  break;
123  case RPM_BIN_TYPE:
124  { static char hex[] = "0123456789abcdef";
125  const char * s = he->p.str;
126  rpmTagCount c = he->c;
127  char * t;
128 
129  nb = 2 * c + 1;
130  t = b = alloca(nb+1);
131  while (c-- > 0) {
132  unsigned i;
133  i = (unsigned) *s++;
134  *t++ = hex[ (i >> 4) & 0xf ];
135  *t++ = hex[ (i ) & 0xf ];
136  }
137  *t = '\0';
138  } break;
139  }
140 
141  if (istr) { /* string */
142  b = (char *)istr; /* NOCAST */
143  } else
144  if (nb == 0) { /* number */
145  char myfmt[] = "%llX";
146  myfmt[3] = ((fmt != NULL && *fmt != '\0') ? *fmt : 'd');
147  nb = 64;
148  b = alloca(nb);
149 /*@-formatconst@*/
150  xx = snprintf(b, nb, myfmt, ival);
151 /*@=formatconst@*/
152  b[nb-1] = '\0';
153  } else
154  b = "";
155 
156  return xstrdup(b);
157 }
158 
165 static char * octFormat(HE_t he, /*@null@*/ const char ** av)
166  /*@*/
167 {
168  return intFormat(he, av, "o");
169 }
170 
177 static char * hexFormat(HE_t he, /*@null@*/ const char ** av)
178  /*@*/
179 {
180  return intFormat(he, av, "x");
181 }
182 
189 static char * decFormat(HE_t he, /*@null@*/ const char ** av)
190  /*@*/
191 {
192  return intFormat(he, av, "d");
193 }
194 
202 static char * realDateFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
203  const char * strftimeFormat)
204  /*@*/
205 {
206  char * val;
207 
208  if (he->t != RPM_UINT64_TYPE) {
209  val = xstrdup(_("(not a number)"));
210  } else {
211  struct tm * tstruct;
212  char buf[50];
213 
214  /* this is important if sizeof(rpmuint64_t) ! sizeof(time_t) */
215  { time_t dateint = he->p.ui64p[0];
216  tstruct = localtime(&dateint);
217  }
218  buf[0] = '\0';
219  if (tstruct)
220  (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
221  buf[sizeof(buf) - 1] = '\0';
222  val = xstrdup(buf);
223  }
224 
225  return val;
226 }
227 
234 static char * dateFormat(HE_t he, /*@null@*/ const char ** av)
235  /*@*/
236 {
237  return realDateFormat(he, av, _("%c"));
238 }
239 
246 static char * dayFormat(HE_t he, /*@null@*/ const char ** av)
247  /*@*/
248 {
249  return realDateFormat(he, av, _("%a %b %d %Y"));
250 }
251 
258 static char * shescapeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
259  /*@*/
260 {
261  char * val;
262  size_t nb;
263  int xx;
264 
265  /* XXX one of these integer types is unnecessary. */
266  if (he->t == RPM_UINT32_TYPE) {
267  nb = 20;
268  val = xmalloc(nb);
269  xx = snprintf(val, nb, "%u", (unsigned) he->p.ui32p[0]);
270  val[nb-1] = '\0';
271  } else if (he->t == RPM_UINT64_TYPE) {
272  nb = 40;
273  val = xmalloc(40);
274 /*@-duplicatequals@*/
275  xx = snprintf(val, nb, "%llu", (unsigned long long)he->p.ui64p[0]);
276 /*@=duplicatequals@*/
277  val[nb-1] = '\0';
278  } else if (he->t == RPM_STRING_TYPE) {
279  const char * s = he->p.str;
280  char * t;
281  int c;
282 
283  nb = 0;
284  for (s = he->p.str; (c = (int)*s) != 0; s++) {
285  nb++;
286  if (c == (int)'\'')
287  nb += 3;
288  }
289  nb += 3;
290  t = val = xmalloc(nb);
291  *t++ = '\'';
292  for (s = he->p.str; (c = (int)*s) != 0; s++) {
293  if (c == (int)'\'') {
294  *t++ = '\'';
295  *t++ = '\\';
296  *t++ = '\'';
297  }
298  *t++ = (char) c;
299  }
300  *t++ = '\'';
301  *t = '\0';
302  } else
303  val = xstrdup(_("invalid type"));
304 
305  return val;
306 }
307 
308 static struct headerSprintfExtension_s _headerDefaultFormats[] = {
309  { HEADER_EXT_FORMAT, "octal",
310  { .fmtFunction = octFormat } },
311  { HEADER_EXT_FORMAT, "oct",
312  { .fmtFunction = octFormat } },
313  { HEADER_EXT_FORMAT, "hex",
314  { .fmtFunction = hexFormat } },
315  { HEADER_EXT_FORMAT, "decimal",
316  { .fmtFunction = decFormat } },
317  { HEADER_EXT_FORMAT, "dec",
318  { .fmtFunction = decFormat } },
319  { HEADER_EXT_FORMAT, "date",
320  { .fmtFunction = dateFormat } },
321  { HEADER_EXT_FORMAT, "day",
322  { .fmtFunction = dayFormat } },
323  { HEADER_EXT_FORMAT, "shescape",
324  { .fmtFunction = shescapeFormat } },
325  { HEADER_EXT_LAST, NULL, { NULL } }
326 };
327 
328 headerSprintfExtension headerDefaultFormats = &_headerDefaultFormats[0];
329 
330 /*====================================================================*/
331 typedef const struct spew_s * spew_t;
332 struct spew_s {
333 /*@observer@*/
334  const char * spew_name;
335  const char * spew_init;
336  const char * spew_fini;
337  size_t (*spew_strlen) (const char * s, int lvl)
338  /*@*/;
339  char * (*spew_strcpy) (/*@returned@*/ char * t, const char * s, int lvl)
340  /*@modifies t @*/;
341 };
342 
343 /*====================================================================*/
350 static size_t xmlstrlen(const char * s, /*@unused@*/ int lvl)
351  /*@*/
352 {
353  size_t len = 0;
354  int c;
355 
356  while ((c = (int) *s++) != (int) '\0') {
357  switch (c) {
358  case '<':
359  case '>': len += sizeof("&lt;") - 1; /*@switchbreak@*/ break;
360  case '&': len += sizeof("&amp;") - 1; /*@switchbreak@*/ break;
361  default: len += 1; /*@switchbreak@*/ break;
362  }
363  }
364  return len;
365 }
366 
374 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s,
375  /*@unused@*/ int lvl)
376  /*@modifies t @*/
377 {
378  char * te = t;
379  int c;
380 
381  while ((c = (int) *s++) != (int) '\0') {
382  switch (c) {
383  case '<': te = stpcpy(te, "&lt;"); /*@switchbreak@*/ break;
384  case '>': te = stpcpy(te, "&gt;"); /*@switchbreak@*/ break;
385  case '&': te = stpcpy(te, "&amp;"); /*@switchbreak@*/ break;
386  default: *te++ = (char) c; /*@switchbreak@*/ break;
387  }
388  }
389  *te = '\0';
390  return t;
391 }
392 
393 /*@unchecked@*/ /*@observer@*/
394 static const struct spew_s _xml_spew = {
395  .spew_name = "xml",
396  .spew_init = "<rpmHeader>\n",
397  .spew_fini = "</rpmHeader>\n",
398  .spew_strlen = xmlstrlen,
399  .spew_strcpy = xmlstrcpy
400 };
401 
402 /*====================================================================*/
403 
410 static size_t yamlstrlen(const char * s, int lvl)
411  /*@*/
412 {
413  size_t len = 0;
414  int indent = (lvl > 0);
415  int c;
416 
417  while ((c = (int) *s++) != (int) '\0')
418  {
419  if (indent) {
420  len += 2 * lvl;
421  indent = 0;
422  }
423  if (c == (int) '\n')
424  indent = (lvl > 0);
425  len++;
426  }
427  return len;
428 }
429 
437 static char * yamlstrcpy(/*@out@*/ /*@returned@*/ char * t, const char * s,
438  int lvl)
439  /*@modifies t @*/
440 {
441  char * te = t;
442  int indent = (lvl > 0);
443  int c;
444 
445  while ((c = (int) *s++) != (int) '\0') {
446  if (indent) {
447  int i;
448  for (i = 0; i < lvl; i++) {
449  *te++ = ' ';
450  *te++ = ' ';
451  }
452  indent = 0;
453  }
454  if (c == (int) '\n')
455  indent = (lvl > 0);
456  *te++ = (char) c;
457  }
458  *te = '\0';
459  return t;
460 }
461 
462 /*@unchecked@*/ /*@observer@*/
463 static const struct spew_s _yaml_spew = {
464  .spew_name = "yaml",
465  .spew_init = "- !!omap\n",
466  .spew_fini = "\n",
467  .spew_strlen = yamlstrlen,
468  .spew_strcpy = yamlstrcpy
469 };
470 
471 /*====================================================================*/
472 
479 static size_t jsonstrlen(const char * s, /*@unused@*/ int lvl)
480  /*@*/
481 {
482  size_t len = 0;
483  int c;
484 
485  while ((c = (int) *s++) != (int) '\0') {
486  switch (c) {
487  case '\b':
488  case '\t':
489  case '\n':
490  case '\f':
491  case '\r':
492  case '"':
493  case '\\': len += 1; /*@fallthrough@*/
494  default: len += 1; /*@switchbreak@*/ break;
495  /* XXX todo: emit \u1234 here somehow */
496  }
497  }
498  return len;
499 }
500 
508 static char * jsonstrcpy(/*@returned@*/ char * t, const char * s,
509  /*@unused@*/ int lvl)
510  /*@modifies t @*/
511 {
512  char * te = t;
513  int c;
514 
515  while ((c = (int) *s++) != (int) '\0') {
516  switch (c) {
517  case '\b': *te++ = '\\'; *te++ = 'b'; /*@switchbreak@*/ break;
518  case '\t': *te++ = '\\'; *te++ = 't'; /*@switchbreak@*/ break;
519  case '\n': *te++ = '\\'; *te++ = 'n'; /*@switchbreak@*/ break;
520  case '\f': *te++ = '\\'; *te++ = 'f'; /*@switchbreak@*/ break;
521  case '\r': *te++ = '\\'; *te++ = 'r'; /*@switchbreak@*/ break;
522  case '"': *te++ = '\\'; *te++ = '"'; /*@switchbreak@*/ break;
523  case '\\': *te++ = '\\'; *te++ = '\\'; /*@switchbreak@*/ break;
524  default: *te++ = (char) c; /*@switchbreak@*/ break;
525  /* XXX todo: emit \u1234 here somehow */
526  }
527  }
528  *te = '\0';
529  return t;
530 }
531 
532 /*@unchecked@*/ /*@observer@*/
533 static const struct spew_s _json_spew = {
534  .spew_name = "json",
535  /* XXX non-functional atm, /usr/lib/rpm/qf *.mongo template for now. */
536  .spew_init = "db.%{?__mongodb_collection}%{!?__mongodb_collection:packages}.save({\n",
537  .spew_fini = "});\n",
538  .spew_strlen = jsonstrlen,
539  .spew_strcpy = jsonstrcpy
540 };
541 
542 /*====================================================================*/
543 
550 static size_t sqlstrlen(const char * s, /*@unused@*/ int lvl)
551  /*@*/
552 {
553  size_t len = 0;
554  int c;
555 
556  while ((c = (int) *s++) != (int) '\0') {
557  switch (c) {
558  case '\'': len += 1; /*@fallthrough@*/
559  default: len += 1; /*@switchbreak@*/ break;
560  }
561  }
562  return len;
563 }
564 
572 static char * sqlstrcpy(/*@returned@*/ char * t, const char * s,
573  /*@unused@*/ int lvl)
574  /*@modifies t @*/
575 {
576  char * te = t;
577  int c;
578 
579  while ((c = (int) *s++) != (int) '\0') {
580  switch (c) {
581  case '\'': *te++ = (char) c; /*@fallthrough@*/
582  default: *te++ = (char) c; /*@switchbreak@*/ break;
583  }
584  }
585  *te = '\0';
586  return t;
587 }
588 
589 /*@unchecked@*/ /*@observer@*/
590 static const struct spew_s _sql_spew = {
591  .spew_name = "sql",
592  .spew_init = "",
593  .spew_fini = "",
594  .spew_strlen = sqlstrlen,
595  .spew_strcpy = sqlstrcpy
596 };
597 
598 /*====================================================================*/
599 
600 /* XXX FIXME: static for now, refactor from manifest.c later. */
601 static char * rpmPermsString(int mode)
602  /*@*/
603 {
604  char *perms = xstrdup("----------");
605 
606  if (S_ISREG(mode))
607  perms[0] = '-';
608  else if (S_ISDIR(mode))
609  perms[0] = 'd';
610  else if (S_ISLNK(mode))
611  perms[0] = 'l';
612  else if (S_ISFIFO(mode))
613  perms[0] = 'p';
614 /*@-unrecog@*/
615  else if (S_ISSOCK(mode))
616  perms[0] = 's';
617 /*@=unrecog@*/
618  else if (S_ISCHR(mode))
619  perms[0] = 'c';
620  else if (S_ISBLK(mode))
621  perms[0] = 'b';
622  else
623  perms[0] = '?';
624 
625  if (mode & S_IRUSR) perms[1] = 'r';
626  if (mode & S_IWUSR) perms[2] = 'w';
627  if (mode & S_IXUSR) perms[3] = 'x';
628 
629  if (mode & S_IRGRP) perms[4] = 'r';
630  if (mode & S_IWGRP) perms[5] = 'w';
631  if (mode & S_IXGRP) perms[6] = 'x';
632 
633  if (mode & S_IROTH) perms[7] = 'r';
634  if (mode & S_IWOTH) perms[8] = 'w';
635  if (mode & S_IXOTH) perms[9] = 'x';
636 
637  if (mode & S_ISUID)
638  perms[3] = ((mode & S_IXUSR) ? 's' : 'S');
639 
640  if (mode & S_ISGID)
641  perms[6] = ((mode & S_IXGRP) ? 's' : 'S');
642 
643  if (mode & S_ISVTX)
644  perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
645 
646  return perms;
647 }
648 
655 static /*@only@*/ char * triggertypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
656  /*@*/
657 {
658  int ix = (he->ix > 0 ? he->ix : 0);
659  char * val;
660 
661 assert(ix == 0);
662  if (he->t != RPM_UINT64_TYPE)
663  val = xstrdup(_("(invalid type)"));
664  else {
665  rpmuint64_t anint = he->p.ui64p[ix];
666  if (anint & RPMSENSE_TRIGGERPREIN)
667  val = xstrdup("prein");
668  else if (anint & RPMSENSE_TRIGGERIN)
669  val = xstrdup("in");
670  else if (anint & RPMSENSE_TRIGGERUN)
671  val = xstrdup("un");
672  else if (anint & RPMSENSE_TRIGGERPOSTUN)
673  val = xstrdup("postun");
674  else
675  val = xstrdup("");
676  }
677  return val;
678 }
679 
686 static /*@only@*/ char * permsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
687  /*@*/
688 {
689  int ix = (he->ix > 0 ? he->ix : 0);
690  char * val;
691 
692 assert(ix == 0);
693  if (he->t != RPM_UINT64_TYPE) {
694  val = xstrdup(_("(invalid type)"));
695  } else {
696  rpmuint64_t anint = he->p.ui64p[0];
697  val = rpmPermsString((int)anint);
698  }
699 
700  return val;
701 }
702 
709 static /*@only@*/ char * fflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
710  /*@*/
711 {
712  int ix = (he->ix >= 0 ? he->ix : 0);
713  char * val;
714 
715 assert(ix == 0);
716  if (he->t != RPM_UINT64_TYPE) {
717  val = xstrdup(_("(invalid type)"));
718  } else {
719  char buf[15];
720  rpmuint64_t anint = he->p.ui64p[ix];
721  buf[0] = '\0';
722  if (anint & RPMFILE_DOC)
723  strcat(buf, "d");
724  if (anint & RPMFILE_CONFIG)
725  strcat(buf, "c");
726  if (anint & RPMFILE_SPECFILE)
727  strcat(buf, "s");
728  if (anint & RPMFILE_MISSINGOK)
729  strcat(buf, "m");
730  if (anint & RPMFILE_NOREPLACE)
731  strcat(buf, "n");
732  if (anint & RPMFILE_GHOST)
733  strcat(buf, "g");
734  if (anint & RPMFILE_LICENSE)
735  strcat(buf, "l");
736  if (anint & RPMFILE_README)
737  strcat(buf, "r");
738  val = xstrdup(buf);
739  }
740 
741  return val;
742 }
743 
751 static /*@only@*/ char * armorFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
752  /*@*/
753 {
754  int ix = (he->ix > 0 ? he->ix : 0);
755  const char * enc;
756  const unsigned char * s;
757  size_t ns;
758  rpmuint8_t atype;
759  char * val;
760 
761 assert(ix == 0);
762  switch (he->t) {
763  case RPM_BIN_TYPE:
764  s = (unsigned char *) he->p.ui8p;
765  ns = he->c;
766  atype = (rpmuint8_t)PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
767  break;
768  case RPM_STRING_TYPE:
770  enc = he->p.str;
771  s = NULL;
772  ns = 0;
773 /*@-moduncon@*/
774  if (b64decode(enc, (void *)&s, &ns))
775  return xstrdup(_("(not base64)"));
776 /*@=moduncon@*/
777  atype = (rpmuint8_t)PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
778  break;
779 #if defined(SUPPORT_I18NSTRING_TYPE)
780  case RPM_I18NSTRING_TYPE:
781 #endif
782  case RPM_UINT8_TYPE:
783  case RPM_UINT16_TYPE:
784  case RPM_UINT32_TYPE:
785  case RPM_UINT64_TYPE:
786  default:
787  return xstrdup(_("(invalid type)"));
788  /*@notreached@*/ break;
789  }
790 
791  val = pgpArmorWrap(atype, s, ns);
792  if (atype == (rpmuint8_t)PGPARMOR_PUBKEY)
793  s = _free(s);
794  return val;
795 }
796 
804 static /*@only@*/ char * base64Format(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
805  /*@*/
806 {
807  int ix = (he->ix > 0 ? he->ix : 0);
808  char * val;
809  const char * enc;
810  char * t;
811  int lc;
812  size_t ns;
813  size_t nt;
814 
815 assert(ix == 0);
816  switch(he->t) {
817  default:
818  val = xstrdup(_("(invalid type :base64)"));
819  goto exit;
820  /*@notreached@*/ break;
821  case RPM_UINT64_TYPE:
822  ns = sizeof(he->p.ui64p[0]);
823  break;
824  case RPM_STRING_TYPE:
825  ns = strlen(he->p.str);
826  break;
827  case RPM_BIN_TYPE:
828  ns = he->c;
829  break;
830  }
831 
832  nt = ((ns + 2) / 3) * 4;
833 
834 /*@-globs@*/
835  /* Add additional bytes necessary for eol string(s). */
836  if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
837  lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
838  if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
839  ++lc;
840  nt += lc * strlen(b64encode_eolstr);
841  }
842 /*@=globs@*/
843 
844  val = t = xcalloc(1, nt + 1);
845  *t = '\0';
846 
847  /* XXX b64encode accesses uninitialized memory. */
848  { unsigned char * _data = xcalloc(1, ns+1);
849 assert(he->p.ptr != NULL);
850  memcpy(_data, he->p.ptr, ns);
851 /*@-moduncon@*/
852  if ((enc = b64encode(_data, ns)) != NULL) {
853  t = stpcpy(t, enc);
854  enc = _free(enc);
855  }
856 /*@=moduncon@*/
857  _data = _free(_data);
858  }
859 
860 exit:
861 /*@-globstate@*/ /* b64encode_eolstr annotation */
862  return val;
863 /*@=globstate@*/
864 }
865 
866 /*====================================================================*/
867 
868 #if defined(__GLIBC__) /* XXX todo: find where iconv(3) was implemented. */
869 /* XXX using "//TRANSLIT" instead assumes known fromcode? */
870 /*@unchecked@*/
871 static const char * _iconv_tocode = "UTF-8//IGNORE";
872 /*@unchecked@*/
873 static const char * _iconv_fromcode = "UTF-8";
874 #else
875 /*@unchecked@*/
876 static const char * _iconv_tocode = "UTF-8";
877 /*@unchecked@*/
878 static const char * _iconv_fromcode = NULL;
879 #endif
880 
881 static /*@only@*/ /*@null@*/ char *
882 strdup_iconv_check (/*@null@*/ const char * buffer,
883  /*@null@*/ const char * tocode)
884  /*@*/
885 {
886  const char *s = buffer;
887  char *t = NULL;
888 #if defined(HAVE_ICONV)
889  const char *fromcode = _iconv_fromcode;
890  iconv_t fd;
891 
892 assert(buffer != NULL);
893 
894  if (tocode == NULL)
895  tocode = _iconv_tocode;
896 assert(tocode != NULL);
897 
898 #ifdef HAVE_LANGINFO_H
899  /* XXX the current locale's encoding != package data encodings. */
900  if (fromcode == NULL)
901  fromcode = nl_langinfo (CODESET);
902 #endif
903 assert(fromcode != NULL);
904 
905  if ((fd = iconv_open(tocode, fromcode)) != (iconv_t)-1) {
906  size_t ileft = strlen(s);
907  size_t nt = ileft;
908  char * te = t = xmalloc((nt + 1) * sizeof(*t));
909  size_t oleft = ileft;
910  size_t err = iconv(fd, NULL, NULL, NULL, NULL);
911  const char *sprev = NULL;
912  int _iconv_errno = 0;
913  int done = 0;
914 
915  while (done == 0 && _iconv_errno == 0) {
916  err = iconv(fd, (char **)&s, &ileft, &te, &oleft);
917  if (err == (size_t)-1) {
918  switch (errno) {
919  case E2BIG:
920  { size_t used = (size_t)(te - t);
921  nt *= 2;
922  t = xrealloc(t, (nt + 1) * sizeof(*t));
923  te = t + used;
924  oleft = nt - used;
925  } /*@switchbreak@*/ break;
926  case EINVAL:
927  done = 1;
928  /*@fallthrough@*/
929  case EILSEQ:
930  default:
931  _iconv_errno = errno;
932  /*@switchbreak@*/ break;
933  }
934  } else
935  if (sprev == NULL) {
936  sprev = s;
937  s = NULL;
938  ileft = 0;
939  } else
940  done = 1;
941  }
942  if (iconv_close(fd))
943  _iconv_errno = errno;
944  *te = '\0';
945  t = xstrdup(t);
946 
947 if (_iconv_errno)
948 fprintf(stderr, "warning: %s: from iconv(%s -> %s) for \"%s\" -> \"%s\"\n", strerror(_iconv_errno), fromcode, tocode, buffer, t);
949 
950  } else
951 #endif
952  t = xstrdup((s ? s : ""));
953 
954  return t;
955 }
956 
963 static /*@only@*/ char * cdataFormat(HE_t he, /*@null@*/ const char ** av)
964  /*@*/
965 {
966  int ix = (he->ix > 0 ? he->ix : 0);
967  char * val;
968 int lvl = 0;
969 spew_t spew = &_xml_spew;
970 
971 assert(ix == 0);
972  if (he->t != RPM_STRING_TYPE) {
973  val = xstrdup(_("(not a string)"));
974  } else {
975  const char * s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
976  size_t nb = spew->spew_strlen(s, lvl);
977  char * t = xmalloc(nb + 1);
978 
979  val = t;
980  t = spew->spew_strcpy(t, s, lvl); t += strlen(t);
981  *t = '\0';
982  s = _free(s);
983  }
984 
985  return val;
986 }
987 
994 static /*@only@*/ char * iconvFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
995  /*@*/
996 {
997  int ix = (he->ix > 0 ? he->ix : 0);
998  char * val = NULL;
999 
1000 assert(ix == 0);
1001  if (he->t == RPM_STRING_TYPE)
1002  val = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1003  if (val == NULL)
1004  val = xstrdup(_("(not a string)"));
1005 
1006  return val;
1007 }
1008 
1015 static /*@only@*/ char * xmlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1016  /*@*/
1017 {
1018  int ix = (he->ix > 0 ? he->ix : 0);
1019  const char * xtag = NULL;
1020  char * val;
1021  const char * s = NULL;
1022  uint64_t anint = 0;
1023 int lvl = 0;
1024 spew_t spew = &_xml_spew;
1025 
1026 assert(ix == 0);
1027 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
1028 
1029  switch (he->t) {
1030  case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
1031  case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
1032 assert(0);
1033  case RPM_STRING_TYPE:
1034  xtag = "string";
1035  s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1036  break;
1037  case RPM_BIN_TYPE:
1038 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */
1039  { int cpl = b64encode_chars_per_line;
1040  b64encode_chars_per_line = 0;
1041 /*@-formatconst@*/
1042  s = base64Format(he, NULL);
1043 /*@=formatconst@*/
1044  b64encode_chars_per_line = cpl;
1045  xtag = "base64";
1046  } break;
1047 /*@=globs =mods@*/
1048  case RPM_UINT8_TYPE:
1049  anint = (uint64_t)he->p.ui8p[ix];
1050  break;
1051  case RPM_UINT16_TYPE:
1052  anint = (uint64_t)he->p.ui16p[ix];
1053  break;
1054  case RPM_UINT32_TYPE:
1055  anint = (uint64_t)he->p.ui32p[ix];
1056  break;
1057  case RPM_UINT64_TYPE:
1058  anint = he->p.ui64p[ix];
1059  break;
1060  default:
1061  val = xstrdup(_("(invalid xml type)"));
1062  goto exit;
1063  /*@notreached@*/ break;
1064  }
1065 
1066  if (s == NULL) {
1067  static int tlen = 64;
1068  char * t = xmalloc(tlen+1);
1069  int xx;
1070 
1071  *t = '\0';
1072  if (anint != 0) /* XXX empty XML tag sets 0 as default? */
1073  xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
1074  s = t;
1075  xtag = "integer";
1076  }
1077 
1078  {
1079  size_t nb = spew->spew_strlen(s, lvl);
1080  char * t, * te;
1081 
1082  if (nb == 0) {
1083  nb += strlen(xtag) + sizeof("\t</>");
1084  te = t = alloca(nb);
1085  te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
1086  } else {
1087  nb += 2 * strlen(xtag) + sizeof("\t<></>");
1088  te = t = alloca(nb);
1089  te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
1090  te = spew->spew_strcpy(te, s, lvl);
1091  te += strlen(te);
1092  te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
1093  }
1094 
1095  val = xstrdup(t);
1096  }
1097 
1098  s = _free(s);
1099 
1100 exit:
1101  return val;
1102 }
1103 
1110 static /*@only@*/ char * yamlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1111  /*@*/
1112 {
1113  int element = he->ix;
1114  int ix = (he->ix > 0 ? he->ix : 0);
1115  const char * xtag = NULL;
1116  int freetag = 0;
1117  char * val;
1118  const char * s = NULL;
1119  uint64_t anint = 0;
1120  int xx = 0;
1121  int ls = 0;
1122  int c;
1123 int lvl = 0;
1124 spew_t spew = &_yaml_spew;
1125 
1126 assert(ix == 0);
1127 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
1128 
1129  switch (he->t) {
1130  case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
1131  case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
1132 assert(0);
1133  case RPM_STRING_TYPE:
1134  s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str);
1135  if (strchr("[", s[0])) /* leading [ */
1136  xx = 1;
1137  if (xx == 0)
1138  while ((c = (int) *s++) != (int) '\0') {
1139  switch (c) {
1140  default:
1141  continue;
1142  case '\n': /* multiline */
1143  xx = 1;
1144  if (s[0] == ' ' || s[0] == '\t') /* leading space */
1145  ls = 1;
1146  continue;
1147  case '-': /* leading "- \"" */
1148  case ':': /* embedded ": " or ":" at EOL */
1149  if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
1150  continue;
1151  xx = 1;
1152  /*@switchbreak@*/ break;
1153  }
1154  /*@loopbreak@*/ break;
1155  }
1156  if (xx) {
1157  if (ls) { /* leading spaces means we need to specify the indent */
1158  xtag = xmalloc(strlen("- |##-\n") + 1);
1159  freetag = 1;
1160  if (element >= 0) {
1161  lvl = 3;
1162  sprintf((char *)xtag, "- |%d-\n", lvl);
1163  } else {
1164  lvl = 2;
1165  if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */
1166  sprintf((char *)xtag, "|%d-\n", lvl);
1167  }
1168  } else {
1169  if (element >= 0) {
1170  xtag = "- |-\n";
1171  lvl = 3;
1172  } else {
1173  xtag = "|-\n";
1174  lvl = 2;
1175  if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */
1176  }
1177  }
1178  } else {
1179  xtag = (element >= 0 ? "- " : NULL);
1180  }
1181 
1182  s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1183  break;
1184  case RPM_BIN_TYPE:
1185 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */
1186  { int cpl = b64encode_chars_per_line;
1187  b64encode_chars_per_line = 0;
1188 /*@-formatconst@*/
1189  s = base64Format(he, NULL);
1190  element = -element; /* XXX skip " " indent. */
1191 /*@=formatconst@*/
1192  b64encode_chars_per_line = cpl;
1193  xtag = "!!binary ";
1194  } break;
1195 /*@=globs =mods@*/
1196  case RPM_UINT8_TYPE:
1197  anint = (uint64_t)he->p.ui8p[ix];
1198  break;
1199  case RPM_UINT16_TYPE:
1200  anint = (uint64_t)he->p.ui16p[ix];
1201  break;
1202  case RPM_UINT32_TYPE:
1203  anint = (uint64_t)he->p.ui32p[ix];
1204  break;
1205  case RPM_UINT64_TYPE:
1206  anint = he->p.ui64p[ix];
1207  break;
1208  default:
1209  val = xstrdup(_("(invalid yaml type)"));
1210  goto exit;
1211  /*@notreached@*/ break;
1212  }
1213 
1214  if (s == NULL) {
1215  static int tlen = 64;
1216  char * t = xmalloc(tlen+1);
1217 /*@-duplicatequals@*/
1218  xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
1219 /*@=duplicatequals@*/
1220  s = t;
1221  xtag = (element >= 0 ? "- " : NULL);
1222  }
1223 
1224  {
1225  size_t nb = spew->spew_strlen(s, lvl);
1226  char * t, * te;
1227 
1228  if (nb == 0) {
1229  if (element >= 0)
1230  nb += sizeof(" ") - 1;
1231  nb += sizeof("- ~") - 1;
1232  nb++;
1233  te = t = alloca(nb);
1234  if (element >= 0)
1235  te = stpcpy(te, " ");
1236  te = stpcpy(te, "- ~");
1237  } else {
1238  if (element >= 0)
1239  nb += sizeof(" ") - 1;
1240  if (xtag)
1241  nb += strlen(xtag);
1242  nb++;
1243  te = t = alloca(nb);
1244  if (element >= 0)
1245  te = stpcpy(te, " ");
1246  if (xtag)
1247  te = stpcpy(te, xtag);
1248 /*@-modobserver -observertrans -statictrans @*/ /* XXX LCL: can't see freetag flow */
1249  if (freetag)
1250  xtag = _free(xtag);
1251 /*@=modobserver =observertrans =statictrans @*/
1252  te = spew->spew_strcpy(te, s, lvl);
1253  te += strlen(te);
1254  }
1255 
1256  val = xstrdup(t);
1257  }
1258 
1259  s = _free(s);
1260 
1261 exit:
1262  return val;
1263 }
1264 
1271 static /*@only@*/
1272 char * jsonFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1273  /*@*/
1274 {
1275  int element = he->ix;
1276  int ix = (he->ix > 0 ? he->ix : 0);
1277  char * val;
1278  const char * s = NULL;
1279  uint64_t anint = 0;
1280  int xx = 0;
1281  int c;
1282 int lvl = 0;
1283 spew_t spew = &_json_spew;
1284 
1285 assert(ix == 0);
1286 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
1287 
1288  switch (he->t) {
1289  case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
1290  case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
1291 assert(0);
1292  case RPM_STRING_TYPE:
1293  s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1294  break;
1295  case RPM_BIN_TYPE:
1296  { int cpl = b64encode_chars_per_line;
1297  b64encode_chars_per_line = 0;
1298  s = base64Format(he, NULL);
1299  element = -element; /* XXX skip " " indent. */
1300  b64encode_chars_per_line = cpl;
1301  } break;
1302  case RPM_UINT8_TYPE:
1303  anint = (uint64_t)he->p.ui8p[ix];
1304  break;
1305  case RPM_UINT16_TYPE:
1306  anint = (uint64_t)he->p.ui16p[ix];
1307  break;
1308  case RPM_UINT32_TYPE:
1309  anint = (uint64_t)he->p.ui32p[ix];
1310  break;
1311  case RPM_UINT64_TYPE:
1312  anint = he->p.ui64p[ix];
1313  break;
1314  default:
1315  val = xstrdup(_("(invalid json type)"));
1316  goto exit;
1317  /*@notreached@*/ break;
1318  }
1319 
1320  if (s == NULL) {
1321  static int tlen = 64;
1322  char * t = xmalloc(tlen+1);
1323  xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
1324  s = t;
1325  c = '\0';
1326  } else
1327  c = '"';
1328 
1329  {
1330  size_t nb = spew->spew_strlen(s, lvl);
1331  char * t, * te;
1332 
1333  te = t = alloca(nb + sizeof("\"\","));
1334  if (c != '\0') *te++ = c;
1335  if (nb) {
1336  te = spew->spew_strcpy(te, s, lvl);
1337  te += strlen(te);
1338  }
1339  if (c != '\0') *te++ = c;
1340  *te++ = ',';
1341  *te = '\0';
1342 
1343  val = xstrdup(t);
1344  }
1345 
1346  s = _free(s);
1347 
1348 exit:
1349  return val;
1350 }
1351 
1352 /*====================================================================*/
1353 
1360 static /*@only@*/ char * pgpsigFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1361  /*@globals fileSystem, internalState @*/
1362  /*@modifies fileSystem, internalState @*/
1363 {
1364  int ix = (he->ix > 0 ? he->ix : 0);
1365  char * val, * t;
1366 
1367 assert(ix == 0);
1368  if (!(he->t == RPM_BIN_TYPE)) {
1369  val = xstrdup(_("(not a blob)"));
1370  } else {
1371  rpmuint8_t * pkt = he->p.ui8p;
1372  unsigned int pktlen = 0;
1373  unsigned int v = (unsigned int) *pkt;
1374  pgpTag tag = 0;
1375  unsigned int plen;
1376  unsigned int hlen = 0;
1377 
1378  if (v & 0x80) {
1379  if (v & 0x40) {
1380  tag = (v & 0x3f);
1381  plen = pgpLen(pkt+1, &hlen);
1382  } else {
1383  tag = (v >> 2) & 0xf;
1384  plen = (1 << (v & 0x3));
1385  hlen = pgpGrab(pkt+1, plen);
1386  }
1387 
1388  pktlen = 1 + plen + hlen;
1389  }
1390 
1391  if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
1392  val = xstrdup(_("(not an OpenPGP signature)"));
1393  } else {
1394  pgpDig dig = pgpDigNew(RPMVSF_DEFAULT, 0);
1395  pgpDigParams sigp = pgpGetSignature(dig);
1396  size_t nb = 0;
1397  const char *tempstr;
1398 
1399  (void) pgpPrtPkts(pkt, pktlen, dig, 0);
1400 
1401  val = NULL;
1402  again:
1403  nb += 100;
1404  val = t = xrealloc(val, nb + 1);
1405 
1406  switch (sigp->pubkey_algo) {
1407  case PGPPUBKEYALGO_DSA:
1408  t = stpcpy(t, "DSA");
1409  break;
1410  case PGPPUBKEYALGO_RSA:
1411  t = stpcpy(t, "RSA");
1412  break;
1413  default:
1414  (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->pubkey_algo);
1415  t += strlen(t);
1416  break;
1417  }
1418  if (t + 5 >= val + nb)
1419  goto again;
1420  *t++ = '/';
1421  switch (sigp->hash_algo) {
1422  case PGPHASHALGO_MD5:
1423  t = stpcpy(t, "MD5");
1424  break;
1425  case PGPHASHALGO_SHA1:
1426  t = stpcpy(t, "SHA1");
1427  break;
1428  default:
1429  (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->hash_algo);
1430  t += strlen(t);
1431  break;
1432  }
1433  if (t + strlen (", ") + 1 >= val + nb)
1434  goto again;
1435 
1436  t = stpcpy(t, ", ");
1437 
1438  /* this is important if sizeof(rpmuint32_t) ! sizeof(time_t) */
1439  { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
1440  struct tm * tstruct = localtime(&dateint);
1441  if (tstruct)
1442  (void) strftime(t, (nb - (t - val)), "%c", tstruct);
1443  }
1444  t += strlen(t);
1445  if (t + strlen (", Key ID ") + 1 >= val + nb)
1446  goto again;
1447  t = stpcpy(t, ", Key ID ");
1448  tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
1449  if (t + strlen (tempstr) > val + nb)
1450  goto again;
1451  t = stpcpy(t, tempstr);
1452 
1453  dig = pgpDigFree(dig);
1454  }
1455  }
1456 
1457  return val;
1458 }
1459 
1466 static /*@only@*/
1467 char * depflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1468  /*@*/
1469 {
1470  int ix = (he->ix > 0 ? he->ix : 0);
1471  char * val;
1472 
1473 assert(ix == 0);
1474  if (he->t != RPM_UINT64_TYPE) {
1475  val = xstrdup(_("(invalid type)"));
1476  } else {
1477  rpmuint64_t anint = he->p.ui64p[ix];
1478  char *t, *buf;
1479 
1480  t = buf = alloca(32);
1481  *t = '\0';
1482 
1483 #ifdef NOTYET /* XXX appending markers breaks :depflags format. */
1484  if (anint & RPMSENSE_SCRIPT_PRE)
1485  t = stpcpy(t, "(pre)");
1486  else if (anint & RPMSENSE_SCRIPT_POST)
1487  t = stpcpy(t, "(post)");
1488  else if (anint & RPMSENSE_SCRIPT_PREUN)
1489  t = stpcpy(t, "(preun)");
1490  else if (anint & RPMSENSE_SCRIPT_POSTUN)
1491  t = stpcpy(t, "(postun)");
1492 #endif
1493  if (anint & RPMSENSE_SENSEMASK)
1494  *t++ = ' ';
1495  if (anint & RPMSENSE_LESS)
1496  *t++ = '<';
1497  if (anint & RPMSENSE_GREATER)
1498  *t++ = '>';
1499  if (anint & RPMSENSE_EQUAL)
1500  *t++ = '=';
1501  if (anint & RPMSENSE_SENSEMASK)
1502  *t++ = ' ';
1503  *t = '\0';
1504 
1505  val = xstrdup(buf);
1506  }
1507 
1508  return val;
1509 }
1510 
1518 static /*@only@*/
1519 char * deptypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1520  /*@*/
1521 {
1522  int ix = (he->ix > 0 ? he->ix : 0);
1523  char * val;
1524 
1525 assert(ix == 0);
1526  if (he->t != RPM_UINT64_TYPE) {
1527  val = xstrdup(_("(invalid type)"));
1528  } else {
1529  rpmuint64_t anint = he->p.ui64p[ix];
1530  char *t, *buf;
1531 
1532  t = buf = alloca(32);
1533  *t = '\0';
1534 
1535  if (anint & RPMSENSE_SCRIPT_PRE)
1536  t = stpcpy(t, "pre");
1537  else if (anint & RPMSENSE_SCRIPT_POST)
1538  t = stpcpy(t, "post");
1539  else if (anint & RPMSENSE_SCRIPT_PREUN)
1540  t = stpcpy(t, "preun");
1541  else if (anint & RPMSENSE_SCRIPT_POSTUN)
1542  t = stpcpy(t, "postun");
1543  else if (anint & RPMSENSE_SCRIPT_VERIFY)
1544  t = stpcpy(t, "verify");
1545  else if (anint & RPMSENSE_RPMLIB)
1546  t = stpcpy(t, "rpmlib");
1547  else if (anint & RPMSENSE_INTERP)
1548  t = stpcpy(t, "interp");
1549  else if (anint & (RPMSENSE_FIND_PROVIDES | RPMSENSE_FIND_REQUIRES))
1550  t = stpcpy(t, "auto");
1551  else
1552  t = stpcpy(t, "manual");
1553  *t = '\0';
1554 
1555  val = xstrdup(buf);
1556  }
1557 
1558  return val;
1559 }
1560 
1561 #ifdef NOTYET
1562 static const char * bfstring(unsigned int x, const char * xbf)
1563 {
1564  const char * s = xbf;
1565  static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1566  static char buf[BUFSIZ];
1567  char * t, * te;
1568  unsigned radix;
1569  unsigned c, i, k;
1570 
1571  radix = (s != NULL ? *s++ : 16);
1572 
1573  if (radix <= 1 || radix >= 32)
1574  radix = 16;
1575 
1576  t = buf;
1577  switch (radix) {
1578  case 8: *t++ = '0'; break;
1579  case 16: *t++ = '0'; *t++ = 'x'; break;
1580  }
1581 
1582  i = 0;
1583  k = x;
1584  do { i++; k /= radix; } while (k);
1585 
1586  te = t + i;
1587 
1588  k = x;
1589  do { --i; t[i] = digits[k % radix]; k /= radix; } while (k);
1590 
1591  t = te;
1592  i = '<';
1593  if (s != NULL)
1594  while ((c = *s++) != '\0') {
1595  if (c > ' ') continue;
1596 
1597  k = (1 << (c - 1));
1598  if (!(x & k)) continue;
1599 
1600  if (t == te) *t++ = '=';
1601 
1602  *t++ = i;
1603  i = ',';
1604  while (*s > ' ')
1605  *t++ = *s++;
1606  }
1607  if (t > te) *t++ = '>';
1608  *t = '\0';
1609  return buf;
1610 }
1611 #endif
1612 
1619 static /*@only@*/
1620 char * hintFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1621  /*@*/
1622 {
1623  int ix = (he->ix > 0 ? he->ix : 0);
1624  char * val;
1625 
1626 assert(ix == 0);
1627  if (he->t != RPM_UINT64_TYPE) {
1628  val = xstrdup(_("(invalid type)"));
1629  } else {
1630  rpmuint64_t anint = he->p.ui64p[ix];
1631  char *t, *buf;
1632 
1633  t = buf = alloca(32);
1634  *t = '\0';
1635 
1636  if (anint & RPMSENSE_MISSINGOK)
1637  t = stpcpy(t, "(hint)");
1638  *t = '\0';
1639 
1640  val = xstrdup(buf);
1641  }
1642 
1643  return val;
1644 }
1651 static int instprefixTag(Header h, HE_t he)
1652  /*@globals internalState @*/
1653  /*@modifies he, internalState @*/
1654 {
1655  he->tag = RPMTAG_INSTALLPREFIX;
1656  if (headerGet(h, he, 0))
1657  return 0;
1658 
1659  he->tag = RPMTAG_INSTPREFIXES;
1660  if (headerGet(h, he, 0)) {
1661  rpmTagData array = { .argv = he->p.argv };
1662  he->t = RPM_STRING_TYPE;
1663  he->c = 1;
1664  he->p.str = xstrdup(array.argv[0]);
1665  he->freeData = 1;
1666  array.ptr = _free(array.ptr);
1667  return 0;
1668  }
1669  return 1;
1670 }
1671 
1679 static int tv2uuidv1(/*@unused@*/ Header h, HE_t he, struct timeval *tv)
1680  /*@modifies he @*/
1681 {
1682  rpmuint64_t uuid_time = ((rpmuint64_t)tv->tv_sec * 10000000) +
1683  (tv->tv_usec * 10) + 0x01B21DD213814000ULL;
1684 
1685  he->t = RPM_BIN_TYPE;
1686  he->c = 128/8;
1687  he->p.ptr = xcalloc(1, he->c);
1688  he->freeData = 1;
1689  if (rpmuuidMake(1, NULL, NULL, NULL, (unsigned char *)he->p.ui8p)) {
1690  he->p.ptr = _free(he->p.ptr);
1691  he->freeData = 0;
1692  return 1;
1693  }
1694 
1695  he->p.ui8p[6] &= 0xf0; /* preserve version, clear time_hi nibble */
1696  he->p.ui8p[8] &= 0xc0; /* preserve variant, clear clock */
1697  he->p.ui8p[9] &= 0x00;
1698 
1699  he->p.ui8p[3] = (rpmuint8_t)(uuid_time >> 0);
1700  he->p.ui8p[2] = (rpmuint8_t)(uuid_time >> 8);
1701  he->p.ui8p[1] = (rpmuint8_t)(uuid_time >> 16);
1702  he->p.ui8p[0] = (rpmuint8_t)(uuid_time >> 24);
1703  he->p.ui8p[5] = (rpmuint8_t)(uuid_time >> 32);
1704  he->p.ui8p[4] = (rpmuint8_t)(uuid_time >> 40);
1705  he->p.ui8p[6] |= (rpmuint8_t)(uuid_time >> 56) & 0x0f;
1706 
1707 #ifdef NOTYET
1708  /* XXX Jigger up a non-zero (but constant) clock value. Is this needed? */
1709  he->p.ui8p[8] |= (he->p.ui8p[2] & 0x3f);
1710  he->p.ui8p[9] |= he->p.ui8p[3]
1711 #endif
1712 
1713  return 0;
1714 }
1715 
1722 static int tag2uuidv1(Header h, HE_t he)
1723  /*@globals internalState @*/
1724  /*@modifies he, internalState @*/
1725 {
1726  struct timeval tv;
1727 
1728  if (!headerGet(h, he, 0))
1729  return 1;
1730  tv.tv_sec = (long) he->p.ui32p[0];
1731  tv.tv_usec = (long) (he->c > 1 ? he->p.ui32p[1] : 0);
1732  he->p.ptr = _free(he->p.ptr);
1733  return tv2uuidv1(h, he, &tv);
1734 }
1735 
1743  /*@globals internalState @*/
1744  /*@modifies he, internalState @*/
1745 {
1746  he->tag = RPMTAG_INSTALLTIME;
1747  return tag2uuidv1(h, he);
1748 }
1749 
1756 static int buildtime_uuidTag(Header h, HE_t he)
1757  /*@globals internalState @*/
1758  /*@modifies he, internalState @*/
1759 {
1760  he->tag = RPMTAG_BUILDTIME;
1761  return tag2uuidv1(h, he);
1762 }
1763 
1770 static int origintime_uuidTag(Header h, HE_t he)
1771  /*@globals internalState @*/
1772  /*@modifies he, internalState @*/
1773 {
1774  he->tag = RPMTAG_ORIGINTIME;
1775  return tag2uuidv1(h, he);
1776 }
1777 
1784 static int installtid_uuidTag(Header h, HE_t he)
1785  /*@globals internalState @*/
1786  /*@modifies he, internalState @*/
1787 {
1788  he->tag = RPMTAG_INSTALLTID;
1789  return tag2uuidv1(h, he);
1790 }
1791 
1798 static int removetid_uuidTag(Header h, HE_t he)
1799  /*@globals internalState @*/
1800  /*@modifies he, internalState @*/
1801 {
1802  he->tag = RPMTAG_REMOVETID;
1803  return tag2uuidv1(h, he);
1804 }
1805 
1812 static int origintid_uuidTag(Header h, HE_t he)
1813  /*@globals internalState @*/
1814  /*@modifies he, internalState @*/
1815 {
1816  he->tag = RPMTAG_ORIGINTID;
1817  return tag2uuidv1(h, he);
1818 }
1819 
1820 /*@unchecked@*/ /*@observer@*/
1821 static const char uuid_ns[] = "ns:URL";
1822 /*@unchecked@*/ /*@observer@*/
1823 static const char uuid_auth[] = "%{?_uuid_auth}%{!?_uuid_auth:http://rpm5.org}";
1824 /*@unchecked@*/ /*@observer@*/
1825 static const char uuid_path[] = "%{?_uuid_path}%{!?_uuid_path:/package}";
1826 /*@unchecked@*/
1828 
1837 static int str2uuid(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
1838  rpmuint32_t version, char * val)
1839  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1840  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1841 {
1842  const char * ns = NULL;
1843  const char * tagn = tagName(he->tag);
1844  const char * s = NULL;
1845 char * t = (val ? val : alloca(40));
1846  int rc;
1847 
1848  /* XXX Substitute Pkgid & Hdrid strings for aliases. */
1849  if (!strcmp("Sigmd5", tagn))
1850  tagn = "Pkgid";
1851  else if (!strcmp("Sha1header", tagn))
1852  tagn = "Hdrid";
1853 
1854  switch (version) {
1855  default:
1856  version = uuid_version;
1857  /*@fallthrough@*/
1858  case 3:
1859  case 5:
1860 assert(he->t == RPM_STRING_TYPE);
1861  ns = uuid_ns;
1862  s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/",
1863  he->p.str, NULL);
1864  /*@fallthrough@*/
1865  case 4:
1866  break;
1867  }
1868  he->p.ptr = _free(he->p.ptr);
1869  he->t = RPM_BIN_TYPE;
1870  he->c = 128/8;
1871  he->p.ptr = xcalloc(1, he->c);
1872  he->freeData = 1;
1873  rc = rpmuuidMake((int)version, ns, s, t, (unsigned char *)he->p.ui8p);
1874  if (rc) {
1875  he->p.ptr = _free(he->p.ptr);
1876  he->freeData = 0;
1877  }
1878  s = _free(s);
1879 
1880  return rc;
1881 }
1882 
1889 static int tag2uuidv5(Header h, HE_t he)
1890  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1891  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1892 {
1893  if (!headerGet(h, he, 0))
1894  return 1;
1895  switch (he->t) {
1896  default:
1897 assert(0);
1898  /*@notreached@*/ break;
1899  case RPM_BIN_TYPE: { /* Convert RPMTAG_PKGID from binary => hex. */
1900  static const char hex[] = "0123456789abcdef";
1901  char * t;
1902  char * te;
1903  rpmuint32_t i;
1904 
1905  t = te = xmalloc (2*he->c + 1);
1906  for (i = 0; i < he->c; i++) {
1907  *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ];
1908  *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ];
1909  }
1910  *te = '\0';
1911  he->p.ptr = _free(he->p.ptr);
1912  he->t = RPM_STRING_TYPE;
1913  he->p.ptr = t;
1914  he->c = 1;
1915  he->freeData = 1;
1916  } break;
1917  case RPM_STRING_TYPE:
1918  break;
1919  }
1920  return str2uuid(he, NULL, 0, NULL);
1921 }
1922 
1929 static int pkguuidTag(Header h, HE_t he)
1930  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1931  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1932 {
1933  he->tag = RPMTAG_PKGID;
1934  return tag2uuidv5(h, he);
1935 }
1936 
1943 static int sourcepkguuidTag(Header h, HE_t he)
1944  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1945  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1946 {
1947  he->tag = RPMTAG_SOURCEPKGID;
1948  return tag2uuidv5(h, he);
1949 }
1950 
1957 static int hdruuidTag(Header h, HE_t he)
1958  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1959  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1960 {
1961  he->tag = RPMTAG_HDRID;
1962  return tag2uuidv5(h, he);
1963 }
1964 
1971 static int triggercondsTag(Header h, HE_t he)
1972  /*@globals internalState @*/
1973  /*@modifies he, internalState @*/
1974 {
1975  HE_t _he = (HE_t) memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
1976  HE_t Fhe = (HE_t) memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
1977  HE_t Ihe = (HE_t) memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
1978  HE_t Nhe = (HE_t) memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
1979  HE_t Vhe = (HE_t) memset(alloca(sizeof(*Vhe)), 0, sizeof(*Vhe));
1980  HE_t She = (HE_t) memset(alloca(sizeof(*She)), 0, sizeof(*She));
1981  rpmuint64_t anint;
1982  unsigned i, j;
1983  int rc = 1; /* assume failure */
1984  int xx;
1985 
1986  he->freeData = 0;
1987 
1988  Nhe->tag = RPMTAG_TRIGGERNAME;
1989  xx = headerGet(h, Nhe, 0);
1990  if (!xx) { /* no triggers, succeed anyways */
1991  rc = 0;
1992  goto exit;
1993  }
1994 
1995  Ihe->tag = RPMTAG_TRIGGERINDEX;
1996  xx = headerGet(h, Ihe, 0);
1997  if (!xx) goto exit;
1998 
1999  Fhe->tag = RPMTAG_TRIGGERFLAGS;
2000  xx = headerGet(h, Fhe, 0);
2001  if (!xx) goto exit;
2002 
2003  Vhe->tag = RPMTAG_TRIGGERVERSION;
2004  xx = headerGet(h, Vhe, 0);
2005  if (!xx) goto exit;
2006 
2007  She->tag = RPMTAG_TRIGGERSCRIPTS;
2008  xx = headerGet(h, She, 0);
2009  if (!xx) goto exit;
2010 
2011  _he->tag = he->tag;
2012  _he->t = RPM_UINT64_TYPE;
2013  _he->p.ui64p = &anint;
2014  _he->c = 1;
2015  _he->freeData = 0;
2016 
2017  he->t = RPM_STRING_ARRAY_TYPE;
2018  he->c = She->c;
2019 
2020  he->freeData = 1;
2021  he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
2022  for (i = 0; i < (unsigned) he->c; i++) {
2023  char * item, * flagsStr;
2024  char * chptr;
2025 
2026  chptr = xstrdup("");
2027 
2028  for (j = 0; j < Nhe->c; j++) {
2029  if (Ihe->p.ui32p[j] != i)
2030  /*@innercontinue@*/ continue;
2031 
2032  item = xmalloc(strlen(Nhe->p.argv[j]) + strlen(Vhe->p.argv[j]) + 20);
2033 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
2034  if (Fhe->p.ui32p[j] & RPMSENSE_SENSEMASK) {
2035  anint = Fhe->p.ui32p[j];
2036  flagsStr = depflagsFormat(_he, NULL);
2037  sprintf(item, "%s%s%s", Nhe->p.argv[j], flagsStr, Vhe->p.argv[j]);
2038  flagsStr = _free(flagsStr);
2039  } else
2040  strcpy(item, Nhe->p.argv[j]);
2041 /*@=compmempass@*/
2042 
2043  chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
2044  if (*chptr != '\0') strcat(chptr, ", ");
2045  strcat(chptr, item);
2046  item = _free(item);
2047  }
2048 
2049  he->p.argv[i] = chptr;
2050  }
2051  rc = 0;
2052 
2053 exit:
2054  Ihe->p.ptr = _free(Ihe->p.ptr);
2055  Fhe->p.ptr = _free(Fhe->p.ptr);
2056  Nhe->p.ptr = _free(Nhe->p.ptr);
2057  Vhe->p.ptr = _free(Vhe->p.ptr);
2058  She->p.ptr = _free(She->p.ptr);
2059 
2060  return rc;
2061 }
2062 
2069 static int triggertypeTag(Header h, HE_t he)
2070  /*@globals internalState @*/
2071  /*@modifies he, internalState @*/
2072 {
2073  HE_t _he = (HE_t) memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
2074  rpmTagData indices = { .ptr = NULL };
2075  rpmTagData flags = { .ptr = NULL };
2076  rpmTagData s = { .ptr = NULL };
2077  rpmTagCount numNames;
2078  rpmTagCount numScripts;
2079  unsigned i, j;
2080  int rc = 1; /* assume failure */
2081  int xx;
2082 
2083  he->freeData = 0;
2084 
2085 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
2086  _he->tag = RPMTAG_TRIGGERINDEX;
2087  xx = headerGet(h, _he, 0);
2088  if (!xx) goto exit;
2089  indices.ui32p = _he->p.ui32p;
2090  numNames = _he->c;
2091 
2092  _he->tag = RPMTAG_TRIGGERFLAGS;
2093  xx = headerGet(h, _he, 0);
2094  if (!xx) goto exit;
2095  flags.ui32p = _he->p.ui32p;
2096 
2097  _he->tag = RPMTAG_TRIGGERSCRIPTS;
2098  xx = headerGet(h, _he, 0);
2099  if (!xx) goto exit;
2100  s.argv = _he->p.argv;
2101  numScripts = _he->c;
2102 /*@=compmempass@*/
2103 
2104  he->t = RPM_STRING_ARRAY_TYPE;
2105  he->c = numScripts;
2106 
2107  he->freeData = 1;
2108  he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
2109  for (i = 0; i < (unsigned) he->c; i++) {
2110  for (j = 0; j < (unsigned) numNames; j++) {
2111  if (indices.ui32p[j] != i) {
2112  he->p.argv[i] = NULL;
2113  /*@innercontinue@*/ continue;
2114  }
2115 
2116  /* XXX FIXME: there's memory leaks here. */
2117  if (flags.ui32p[j] & RPMSENSE_TRIGGERPREIN)
2118  he->p.argv[i] = xstrdup("prein");
2119  else if (flags.ui32p[j] & RPMSENSE_TRIGGERIN)
2120  he->p.argv[i] = xstrdup("in");
2121  else if (flags.ui32p[j] & RPMSENSE_TRIGGERUN)
2122  he->p.argv[i] = xstrdup("un");
2123  else if (flags.ui32p[j] & RPMSENSE_TRIGGERPOSTUN)
2124  he->p.argv[i] = xstrdup("postun");
2125  else
2126  he->p.argv[i] = xstrdup("");
2127  /*@innerbreak@*/ break;
2128  }
2129  }
2130  rc = 0;
2131 
2132 exit:
2133  indices.ptr = _free(indices.ptr);
2134  flags.ptr = _free(flags.ptr);
2135  s.ptr = _free(s.ptr);
2136  return 0;
2137 }
2138 
2139 /* I18N look aside diversions */
2140 
2141 #if defined(ENABLE_NLS)
2142 /*@-exportlocal -exportheadervar@*/
2143 /*@unchecked@*/
2144 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
2145 /*@=exportlocal =exportheadervar@*/
2146 #endif
2147 /*@observer@*/ /*@unchecked@*/
2148 static const char * language = "LANGUAGE";
2149 
2150 /*@observer@*/ /*@unchecked@*/
2151 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
2152 
2159 static int i18nTag(Header h, HE_t he)
2160  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2161  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2162 {
2163  char * dstring = rpmExpand(_macro_i18ndomains, NULL);
2164  int rc = 1; /* assume failure */
2165 
2166  he->t = RPM_STRING_TYPE;
2167  he->p.str = NULL;
2168  he->c = 0;
2169  he->freeData = 0;
2170 
2171  if (dstring && *dstring) {
2172  char *domain, *de;
2173  const char * langval;
2174  const char * msgkey;
2175  const char * msgid;
2176 
2177  { HE_t nhe = (HE_t) memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
2178  const char * tn;
2179  char * mk;
2180  size_t nb = sizeof("()");
2181  int xx;
2182 
2183  nhe->tag = RPMTAG_NAME;
2184  xx = headerGet(h, nhe, 0);
2185  /*
2186  * XXX Ick, tagName() is called by headerGet(), and the tagName()
2187  * buffer is valid only until next tagName() call.
2188  * For now, do the tagName() lookup after headerGet().
2189  */
2190  tn = tagName(he->tag);
2191  if (tn) nb += strlen(tn);
2192  if (nhe->p.str) nb += strlen(nhe->p.str);
2193  mk = alloca(nb);
2194  (void) snprintf(mk, nb, "%s(%s)",
2195  (nhe->p.str ? nhe->p.str : ""), (tn ? tn : ""));
2196  mk[nb-1] = '\0';
2197  nhe->p.ptr = _free(nhe->p.ptr);
2198  msgkey = mk;
2199  }
2200 
2201  /* change to en_US for msgkey -> msgid resolution */
2202  langval = getenv(language);
2203  (void) setenv(language, "en_US", 1);
2204 #if defined(ENABLE_NLS)
2205 /*@i@*/ ++_nl_msg_cat_cntr;
2206 #endif
2207 
2208  msgid = NULL;
2209  for (domain = dstring; domain != NULL; domain = de) {
2210  de = strchr(domain, ':');
2211  if (de) *de++ = '\0';
2212 /*@-unrecog@*/
2213  msgid = dgettext(domain, msgkey);
2214 /*@=unrecog@*/
2215  if (msgid != msgkey) break;
2216  }
2217 
2218  /* restore previous environment for msgid -> msgstr resolution */
2219  if (langval)
2220  (void) setenv(language, langval, 1);
2221  else
2222  unsetenv(language);
2223 #if defined(ENABLE_NLS)
2224 /*@i@*/ ++_nl_msg_cat_cntr;
2225 #endif
2226 
2227  if (domain && msgid) {
2228 /*@-unrecog@*/
2229  const char * s = dgettext(domain, msgid);
2230 /*@=unrecog@*/
2231  if (s) {
2232  rc = 0;
2233  he->p.str = xstrdup(s);
2234  he->c = 1;
2235  he->freeData = 1;
2236  }
2237  }
2238  }
2239 
2240 /*@-dependenttrans@*/
2241  dstring = _free(dstring);
2242 /*@=dependenttrans@*/
2243  if (!rc)
2244  return rc;
2245 
2246  rc = headerGet(h, he, HEADERGET_NOEXTENSION);
2247  if (rc) {
2248  rc = 0;
2249  he->p.str = xstrtolocale(he->p.str);
2250  he->freeData = 1;
2251  return rc;
2252  }
2253 
2254  he->t = RPM_STRING_TYPE;
2255  he->p.str = NULL;
2256  he->c = 0;
2257  he->freeData = 0;
2258 
2259  return 1;
2260 }
2261 
2265 static int localeTag(Header h, HE_t he)
2266  /*@globals internalState @*/
2267  /*@modifies he, internalState @*/
2268 {
2269  int rc;
2270 
2271  rc = headerGet(h, he, HEADERGET_NOEXTENSION);
2272  if (!rc || he->p.str == NULL || he->c == 0) {
2273  he->t = RPM_STRING_TYPE;
2274  he->freeData = 0;
2275  return 1;
2276  }
2277 
2278  switch (he->t) {
2279  default:
2280  he->freeData = 0;
2281  break;
2282  case RPM_STRING_TYPE:
2283  he->p.str = xstrtolocale(he->p.str);
2284  he->freeData = 1;
2285  break;
2286  case RPM_STRING_ARRAY_TYPE:
2287  { const char ** argv;
2288  char * te;
2289  size_t l = 0;
2290  unsigned i;
2291  for (i = 0; i < (unsigned) he->c; i++) {
2292  he->p.argv[i] = xstrdup(he->p.argv[i]);
2293  he->p.argv[i] = xstrtolocale(he->p.argv[i]);
2294 assert(he->p.argv[i] != NULL);
2295  l += strlen(he->p.argv[i]) + 1;
2296  }
2297  argv = xmalloc(he->c * sizeof(*argv) + l);
2298  te = (char *)&argv[he->c];
2299  for (i = 0; i < (unsigned) he->c; i++) {
2300  argv[i] = te;
2301  te = stpcpy(te, he->p.argv[i]);
2302  te++;
2303  he->p.argv[i] = _free(he->p.argv[i]);
2304  }
2305  he->p.ptr = _free(he->p.ptr);
2306  he->p.argv = argv;
2307  he->freeData = 1;
2308  } break;
2309  }
2310 
2311  return 0;
2312 }
2313 
2320 static int summaryTag(Header h, HE_t he)
2321  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2322  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2323 {
2324  he->tag = RPMTAG_SUMMARY;
2325  return i18nTag(h, he);
2326 }
2327 
2334 static int descriptionTag(Header h, HE_t he)
2335  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2336  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2337 {
2338  he->tag = RPMTAG_DESCRIPTION;
2339  return i18nTag(h, he);
2340 }
2341 
2342 static int changelognameTag(Header h, HE_t he)
2343  /*@globals internalState @*/
2344  /*@modifies he, internalState @*/
2345 {
2346  he->tag = RPMTAG_CHANGELOGNAME;
2347  return localeTag(h, he);
2348 }
2349 
2350 static int changelogtextTag(Header h, HE_t he)
2351  /*@globals internalState @*/
2352  /*@modifies he, internalState @*/
2353 {
2354  he->tag = RPMTAG_CHANGELOGTEXT;
2355  return localeTag(h, he);
2356 }
2357 
2364 static int groupTag(Header h, HE_t he)
2365  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2366  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2367 {
2368  he->tag = RPMTAG_GROUP;
2369  return i18nTag(h, he);
2370 }
2371 
2378 static int dbinstanceTag(Header h, HE_t he)
2379  /*@modifies he @*/
2380 {
2381  he->tag = RPMTAG_DBINSTANCE;
2382  he->t = RPM_UINT32_TYPE;
2383  he->p.ui32p = xmalloc(sizeof(*he->p.ui32p));
2384  he->p.ui32p[0] = headerGetInstance(h);
2385  he->freeData = 1;
2386  he->c = 1;
2387  return 0;
2388 }
2389 
2396 static int headerstartoffTag(Header h, HE_t he)
2397  /*@modifies he @*/
2398 {
2399  he->tag = RPMTAG_HEADERSTARTOFF;
2400  he->t = RPM_UINT64_TYPE;
2401  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2402  he->p.ui64p[0] = headerGetStartOff(h);
2403  he->freeData = 1;
2404  he->c = 1;
2405  return 0;
2406 }
2407 
2414 static int headerendoffTag(Header h, HE_t he)
2415  /*@modifies he @*/
2416 {
2417  he->tag = RPMTAG_HEADERENDOFF;
2418  he->t = RPM_UINT64_TYPE;
2419  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2420  he->p.ui64p[0] = headerGetEndOff(h);
2421  he->freeData = 1;
2422  he->c = 1;
2423  return 0;
2424 }
2425 
2432 static int pkgoriginTag(Header h, HE_t he)
2433  /*@globals internalState @*/
2434  /*@modifies he, internalState @*/
2435 {
2436  const char * origin;
2437  int rc = 1;
2438 
2439  he->tag = RPMTAG_PACKAGEORIGIN;
2440  if (!headerGet(h, he, HEADERGET_NOEXTENSION)
2441  && (origin = headerGetOrigin(h)) != NULL)
2442  {
2443  he->t = RPM_STRING_TYPE;
2444  he->p.str = xstrdup(origin);
2445  he->c = 1;
2446  he->freeData = 1;
2447  rc = 0;
2448  }
2449  return rc;
2450 }
2451 
2458 static int pkgbaseurlTag(Header h, HE_t he)
2459  /*@globals internalState @*/
2460  /*@modifies he, internalState @*/
2461 {
2462  const char * baseurl;
2463  int rc = 1;
2464 
2465  he->tag = RPMTAG_PACKAGEBASEURL;
2466  if (!headerGet(h, he, HEADERGET_NOEXTENSION)
2467  && (baseurl = headerGetBaseURL(h)) != NULL)
2468  {
2469  he->t = RPM_STRING_TYPE;
2470  he->p.str = xstrdup(baseurl);
2471  he->c = 1;
2472  he->freeData = 1;
2473  rc = 0;
2474  }
2475  return rc;
2476 }
2477 
2484 static int pkgdigestTag(Header h, HE_t he)
2485  /*@modifies he @*/
2486 {
2487  const char * digest;
2488  int rc = 1;
2489 
2490  he->tag = RPMTAG_PACKAGEDIGEST;
2491  if ((digest = headerGetDigest(h)) != NULL)
2492  {
2493  he->t = RPM_STRING_TYPE;
2494  he->p.str = xstrdup(digest);
2495  he->c = 1;
2496  he->freeData = 1;
2497  rc = 0;
2498  }
2499  return rc;
2500 }
2501 
2508 static int pkgmtimeTag(Header h, HE_t he)
2509  /*@modifies he @*/
2510 {
2511  struct stat * st = headerGetStatbuf(h);
2512  he->tag = RPMTAG_PACKAGETIME;
2513  he->t = RPM_UINT64_TYPE;
2514  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2515 /*@-type@*/
2516  he->p.ui64p[0] = (rpmuint64_t)st->st_mtime;
2517 /*@=type@*/
2518  he->freeData = 1;
2519  he->c = 1;
2520  return 0;
2521 }
2522 
2529 static int pkgsizeTag(Header h, HE_t he)
2530  /*@modifies he @*/
2531 {
2532  struct stat * st = headerGetStatbuf(h);
2533  he->tag = RPMTAG_PACKAGESIZE;
2534  he->t = RPM_UINT64_TYPE;
2535  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2536  he->p.ui64p[0] = (rpmuint64_t)st->st_size;
2537  he->freeData = 1;
2538  he->c = 1;
2539  return 0;
2540 }
2541 
2547 /*@only@*/
2548 static char * hGetNVRA(Header h)
2549  /*@globals internalState @*/
2550  /*@modifies h, internalState @*/
2551 {
2552  const char * N = NULL;
2553  const char * V = NULL;
2554  const char * R = NULL;
2555  const char * A = NULL;
2556  size_t nb = 0;
2557  char * NVRA, * t;
2558 
2559  (void) headerNEVRA(h, &N, NULL, &V, &R, &A);
2560  if (N) nb += strlen(N);
2561  if (V) nb += strlen(V) + 1;
2562  if (R) nb += strlen(R) + 1;
2563 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
2564  /* do not expose the architecture as this is too less
2565  information, as in OpenPKG the "platform" is described by the
2566  architecture+operating-system combination. But as the whole
2567  "platform" information is actually overkill, just revert to the
2568  RPM 4 behaviour and do not expose any such information at all. */
2569 #else
2570  if (A) nb += strlen(A) + 1;
2571 #endif
2572  nb++;
2573  NVRA = t = xmalloc(nb);
2574  *t = '\0';
2575  if (N) t = stpcpy(t, N);
2576  if (V) t = stpcpy( stpcpy(t, "-"), V);
2577  if (R) t = stpcpy( stpcpy(t, "-"), R);
2578 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
2579  /* do not expose the architecture as this is too less
2580  information, as in OpenPKG the "platform" is described by the
2581  architecture+operating-system combination. But as the whole
2582  "platform" information is actually overkill, just revert to the
2583  RPM 4 behaviour and do not expose any such information at all. */
2584 #else
2585  if (A) t = stpcpy( stpcpy(t, "."), A);
2586 #endif
2587  N = _free(N);
2588  V = _free(V);
2589  R = _free(R);
2590  A = _free(A);
2591  return NVRA;
2592 }
2593 
2600 static int nvraTag(Header h, HE_t he)
2601  /*@globals internalState @*/
2602  /*@modifies h, he, internalState @*/
2603 {
2604  he->t = RPM_STRING_TYPE;
2605  he->p.str = hGetNVRA(h);
2606  he->c = 1;
2607  he->freeData = 1;
2608  return 0;
2609 }
2610 
2628 static void rpmfiBuildFNames(Header h, rpmTag tagN,
2629  /*@null@*/ /*@out@*/ const char *** fnp,
2630  /*@null@*/ /*@out@*/ rpmTagCount * fcp)
2631  /*@globals internalState @*/
2632  /*@modifies *fnp, *fcp, internalState @*/
2633 {
2634  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2635  rpmTag dirNameTag = 0;
2636  rpmTag dirIndexesTag = 0;
2637  rpmTagData baseNames = { .ptr = NULL };
2638  rpmTagData dirNames = { .ptr = NULL };
2639  rpmTagData dirIndexes = { .ptr = NULL };
2640  rpmTagData fileNames;
2641  rpmTagCount count;
2642  size_t size;
2643  int isSource =
2644  (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
2645  headerIsEntry(h, RPMTAG_ARCH) != 0);
2646  char * t;
2647  unsigned i;
2648  int xx;
2649 
2650  if (tagN == RPMTAG_BASENAMES) {
2651  dirNameTag = RPMTAG_DIRNAMES;
2652  dirIndexesTag = RPMTAG_DIRINDEXES;
2653  } else if (tagN == RPMTAG_ORIGBASENAMES) {
2654  dirNameTag = RPMTAG_ORIGDIRNAMES;
2655  dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
2656  } else {
2657  if (fnp) *fnp = NULL;
2658  if (fcp) *fcp = 0;
2659  return; /* programmer error */
2660  }
2661 
2662 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
2663  he->tag = tagN;
2664  xx = headerGet(h, he, 0);
2665  /* XXX 3.0.x SRPM's can be used, relative fn's at RPMTAG_OLDFILENAMES. */
2666  if (xx == 0 && isSource) {
2667  he->tag = RPMTAG_OLDFILENAMES;
2668  xx = headerGet(h, he, 0);
2669  if (xx) {
2670  dirNames.argv = xcalloc(3, sizeof(*dirNames.argv));
2671  dirNames.argv[0] = (const char *)&dirNames.argv[2];
2672  dirIndexes.ui32p = xcalloc(he->c, sizeof(*dirIndexes.ui32p));
2673  }
2674  }
2675  baseNames.argv = he->p.argv;
2676  count = he->c;
2677 
2678  if (!xx) {
2679  if (fnp) *fnp = NULL;
2680  if (fcp) *fcp = 0;
2681  return; /* no file list */
2682  }
2683 
2684  he->tag = dirNameTag;
2685  if ((xx = headerGet(h, he, 0)) != 0)
2686  dirNames.argv = he->p.argv;
2687 
2688  he->tag = dirIndexesTag;
2689  if ((xx = headerGet(h, he, 0)) != 0)
2690  dirIndexes.ui32p = he->p.ui32p;
2691 /*@=compmempass@*/
2692 
2693  size = sizeof(*fileNames.argv) * count;
2694  for (i = 0; i < (unsigned)count; i++) {
2695  const char * dn = NULL;
2696  (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
2697  size += strlen(baseNames.argv[i]) + strlen(dn) + 1;
2698  }
2699 
2700  fileNames.argv = xmalloc(size);
2701  t = (char *)&fileNames.argv[count];
2702  for (i = 0; i < (unsigned)count; i++) {
2703  const char * dn = NULL;
2704  (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
2705  fileNames.argv[i] = t;
2706  t = stpcpy( stpcpy(t, dn), baseNames.argv[i]);
2707  *t++ = '\0';
2708  }
2709  baseNames.ptr = _free(baseNames.ptr);
2710  dirNames.ptr = _free(dirNames.ptr);
2711  dirIndexes.ptr = _free(dirIndexes.ptr);
2712 
2713 /*@-onlytrans@*/
2714  if (fnp)
2715  *fnp = fileNames.argv;
2716  else
2717  fileNames.ptr = _free(fileNames.ptr);
2718 /*@=onlytrans@*/
2719  if (fcp) *fcp = count;
2720 }
2721 
2729 static int _fnTag(Header h, HE_t he, rpmTag tag)
2730  /*@globals internalState @*/
2731  /*@modifies he, internalState @*/
2732 {
2733  he->t = RPM_STRING_ARRAY_TYPE;
2734  rpmfiBuildFNames(h, tag, &he->p.argv, &he->c);
2735  he->freeData = 1;
2736  /* XXX headerGet() rc on RPMTAG_FILEPATHS w empty list. */
2737  if (he->p.argv && he->p.argv[0] && he->c > 0)
2738  return 0;
2739  he->p.ptr = _free(he->p.ptr);
2740  he->c = 0;
2741  return 1;
2742 }
2743 
2744 static int filenamesTag(Header h, HE_t he)
2745  /*@globals internalState @*/
2746  /*@modifies he, internalState @*/
2747 {
2748  he->tag = tagValue("Filenames");
2749  return _fnTag(h, he, RPMTAG_BASENAMES);
2750 }
2751 
2752 static int filepathsTag(Header h, HE_t he)
2753  /*@globals internalState @*/
2754  /*@modifies he, internalState @*/
2755 {
2756  he->tag = RPMTAG_FILEPATHS;
2757  return _fnTag(h, he, RPMTAG_BASENAMES);
2758 }
2759 
2760 static int origpathsTag(Header h, HE_t he)
2761  /*@globals internalState @*/
2762  /*@modifies he, internalState @*/
2763 {
2764  he->tag = RPMTAG_ORIGPATHS;
2765  return _fnTag(h, he, RPMTAG_ORIGBASENAMES);
2766 }
2767 
2777 static int debevrfmtTag(/*@unused@*/ Header h, HE_t he,
2778  HE_t Nhe, HE_t EVRhe, HE_t Fhe)
2779  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2780  /*@modifies he, Nhe, rpmGlobalMacroContext, internalState @*/
2781 {
2782  char * t, * te;
2783  size_t nb = 0;
2784  int rc = 1;
2785 
2786  he->t = RPM_STRING_ARRAY_TYPE;
2787  he->c = 0;
2788  he->freeData = 1;
2789  for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
2790  nb += sizeof(*he->p.argv);
2791  nb += strlen(Nhe->p.argv[Nhe->ix]) + 1;
2792  if (*EVRhe->p.argv[Nhe->ix] != '\0')
2793  nb += strlen(EVRhe->p.argv[Nhe->ix]) + (sizeof(" (== )")-1);
2794  he->c++;
2795  }
2796  nb += sizeof(*he->p.argv);
2797 
2798  he->p.argv = xmalloc(nb);
2799  te = (char *) &he->p.argv[he->c+1];
2800 
2801  he->c = 0;
2802  for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
2803  he->p.argv[he->c++] = te;
2804  if (*EVRhe->p.argv[Nhe->ix] != '\0') {
2805  char opstr[4], * op = opstr;
2806  if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_LESS)
2807  *op++ = '<';
2808  if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_GREATER)
2809  *op++ = '>';
2810  if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_EQUAL)
2811  *op++ = '=';
2812  *op = '\0';
2813  t = rpmExpand(Nhe->p.argv[Nhe->ix],
2814  " (", opstr, " ", EVRhe->p.argv[Nhe->ix], ")", NULL);
2815  } else
2816  t = rpmExpand(Nhe->p.argv[Nhe->ix], NULL);
2817  te = stpcpy(te, t);
2818  te++;
2819  t = _free(t);
2820  }
2821  he->p.argv[he->c] = NULL;
2822  rc = 0;
2823 
2824  return rc;
2825 }
2826 
2836 static int debevrTag(Header h, HE_t he, rpmTag tagN, rpmTag tagEVR, rpmTag tagF)
2837  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2838  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2839 {
2840  HE_t Nhe = (HE_t) memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
2841  HE_t EVRhe = (HE_t) memset(alloca(sizeof(*EVRhe)), 0, sizeof(*EVRhe));
2842  HE_t Fhe = (HE_t) memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
2843  int rc = 1;
2844  int xx;
2845 
2846  Nhe->tag = tagN;
2847  if (!(xx = headerGet(h, Nhe, 0)))
2848  goto exit;
2849  EVRhe->tag = tagEVR;
2850  if (!(xx = headerGet(h, EVRhe, 0)))
2851  goto exit;
2852 assert(EVRhe->c == Nhe->c);
2853  Fhe->tag = tagF;
2854  if (!(xx = headerGet(h, Fhe, 0)))
2855  goto exit;
2856 assert(Fhe->c == Nhe->c);
2857 
2858  rc = debevrfmtTag(h, he, Nhe, EVRhe, Fhe);
2859 
2860 exit:
2861  Nhe->p.ptr = _free(Nhe->p.ptr);
2862  EVRhe->p.ptr = _free(EVRhe->p.ptr);
2863  Fhe->p.ptr = _free(Fhe->p.ptr);
2864  return rc;
2865 }
2866 
2873 static int debconflictsTag(Header h, HE_t he)
2874  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2875  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2876 {
2877  he->tag = tagValue("Debconflicts");
2878  return debevrTag(h, he,
2880 }
2881 
2882 static int debdependsTag(Header h, HE_t he)
2883  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2884  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2885 {
2886  he->tag = tagValue("Debdepends");
2887  return debevrTag(h, he,
2889 }
2890 
2891 static int debobsoletesTag(Header h, HE_t he)
2892  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2893  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2894 {
2895  he->tag = tagValue("Debobsoletes");
2896  return debevrTag(h, he,
2898 }
2899 
2900 static int debprovidesTag(Header h, HE_t he)
2901  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2902  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2903 {
2904  he->tag = tagValue("Debprovides");
2905  return debevrTag(h, he,
2907 }
2908 
2915 static int debmd5sumsTag(Header h, HE_t he)
2916  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2917  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2918 {
2919  HE_t Nhe = (HE_t) memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
2920  HE_t Dhe = (HE_t) memset(alloca(sizeof(*Dhe)), 0, sizeof(*Dhe));
2921  char * t, * te;
2922  size_t nb = 0;
2923  int rc = 1;
2924  int xx;
2925 
2926  Nhe->tag = RPMTAG_FILEPATHS;
2927  if (!(xx = headerGet(h, Nhe, 0)))
2928  goto exit;
2929  Dhe->tag = RPMTAG_FILEDIGESTS;
2930  if (!(xx = headerGet(h, Dhe, 0)))
2931  goto exit;
2932 assert(Dhe->c == Nhe->c);
2933 
2934  he->tag = tagValue("Debmd5sums");
2935  he->t = RPM_STRING_ARRAY_TYPE;
2936  he->c = 0;
2937  he->freeData = 1;
2938  for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) {
2939  if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix]))
2940  continue;
2941  nb += sizeof(*he->p.argv);
2942  nb += strlen(Dhe->p.argv[Dhe->ix]) + sizeof(" ") + strlen(Nhe->p.argv[Dhe->ix]) - 1;
2943  he->c++;
2944  }
2945  nb += sizeof(*he->p.argv);
2946 
2947  he->p.argv = xmalloc(nb);
2948  te = (char *) &he->p.argv[he->c+1];
2949 
2950  he->c = 0;
2951  for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) {
2952  if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix]))
2953  continue;
2954  he->p.argv[he->c++] = te;
2955  t = rpmExpand(Dhe->p.argv[Dhe->ix], " ", Nhe->p.argv[Dhe->ix]+1, NULL);
2956  te = stpcpy(te, t);
2957  te++;
2958  t = _free(t);
2959  }
2960  he->p.argv[he->c] = NULL;
2961  rc = 0;
2962 
2963 exit:
2964  Nhe->p.ptr = _free(Nhe->p.ptr);
2965  Dhe->p.ptr = _free(Dhe->p.ptr);
2966  return rc;
2967 }
2968 
2969 static int filestatTag(Header h, HE_t he)
2970  /*@globals internalState @*/
2971  /*@modifies he, internalState @*/
2972 {
2973  rpmTagData paths = { .ptr = NULL };
2974  /* _dev */
2975  rpmTagData _ino = { .ptr = NULL };
2976  rpmTagData _mode = { .ptr = NULL };
2977  /* _nlink */
2978  /* _uid */
2979  /* _gid */
2980  rpmTagData _rdev = { .ptr = NULL };
2981  rpmTagData _size = { .ptr = NULL };
2982  /* _blksize */
2983  /* _blocks */
2984  /* _atime */
2985  rpmTagData _mtime = { .ptr = NULL };
2986  /* st_ctime */
2987  int rc;
2988 
2989  he->tag = RPMTAG_FILEPATHS;
2990  if ((rc = _fnTag(h, he, RPMTAG_BASENAMES)) != 0 || he->c == 0)
2991  goto exit;
2992 
2993 exit:
2994  paths.ptr = _free(paths.ptr);
2995  _ino.ptr = _free(_ino.ptr);
2996  _mode.ptr = _free(_mode.ptr);
2997  _rdev.ptr = _free(_rdev.ptr);
2998  _size.ptr = _free(_size.ptr);
2999  _mtime.ptr = _free(_mtime.ptr);
3000  return rc;
3001 }
3002 
3003 static int wnlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
3004  HE_t PNhe, /*@null@*/ HE_t PEVRhe, /*@null@*/ HE_t PFhe)
3005  /*@globals rpmGlobalMacroContext, h_errno,
3006  fileSystem, internalState @*/
3007  /*@modifies *avp, *hitp, rpmGlobalMacroContext,
3008  fileSystem, internalState @*/
3009 {
3010  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
3011  HE_t RNhe = (HE_t) memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
3012  HE_t REVRhe = (HE_t) memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
3013  HE_t RFhe = (HE_t) memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
3014  rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
3015  const char * key = PNhe->p.argv[PNhe->ix];
3016  size_t keylen = 0;
3017  rpmmi mi;
3018  rpmTag tagN = RPMTAG_REQUIRENAME;
3019  rpmTag tagEVR = RPMTAG_REQUIREVERSION;
3020  rpmTag tagF = RPMTAG_REQUIREFLAGS;
3021  rpmuint32_t PFlags;
3022  rpmuint32_t RFlags;
3023  EVR_t Pevr;
3024  Header oh;
3025  int rc = 0;
3026  int xx;
3027 
3028  if (tagNVRA == 0)
3029  tagNVRA = RPMTAG_NVRA;
3030 
3031  PFlags = (PFhe != NULL ? (PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK) : 0);
3032  Pevr = rpmEVRnew(PFlags, 1);
3033 
3034  if (PEVRhe != NULL)
3035  xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr);
3036 
3037  RNhe->tag = tagN;
3038  REVRhe->tag = tagEVR;
3039  RFhe->tag = tagF;
3040 
3041  mi = rpmmiInit(_rpmdb, tagN, key, keylen);
3042  if (hitp && *hitp)
3043  xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0);
3044  while ((oh = rpmmiNext(mi)) != NULL) {
3045  if (!headerGet(oh, RNhe, 0))
3046  goto bottom;
3047  if (PEVRhe != NULL) {
3048  if (!headerGet(oh, REVRhe, 0))
3049  goto bottom;
3050 assert(REVRhe->c == RNhe->c);
3051  if (!headerGet(oh, RFhe, 0))
3052  goto bottom;
3053 assert(RFhe->c == RNhe->c);
3054  }
3055 
3056  for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
3057  if (strcmp(PNhe->p.argv[PNhe->ix], RNhe->p.argv[RNhe->ix]))
3058  /*@innercontinue@*/ continue;
3059  if (PEVRhe == NULL)
3060  goto bingo;
3061  RFlags = RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK;
3062  { EVR_t Revr = rpmEVRnew(RFlags, 1);
3063  if (!(PFlags && RFlags))
3064  xx = 1;
3065  else {
3066  xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
3067  xx = rpmEVRoverlap(Pevr, Revr);
3068  }
3069  Revr = rpmEVRfree(Revr);
3070  }
3071  if (xx)
3072  goto bingo;
3073  }
3074  goto bottom;
3075 
3076 bingo:
3077  NVRAhe->tag = tagNVRA;
3078  xx = headerGet(oh, NVRAhe, 0);
3079  if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
3080  xx = argvAdd(avp, NVRAhe->p.str);
3081  xx = argvSort(*avp, NULL);
3082  if (hitp != NULL)
3083  xx = argiAdd(hitp, -1, rpmmiInstance(mi));
3084  rc++;
3085  }
3086 
3087 bottom:
3088  RNhe->p.ptr = _free(RNhe->p.ptr);
3089  REVRhe->p.ptr = _free(REVRhe->p.ptr);
3090  RFhe->p.ptr = _free(RFhe->p.ptr);
3091  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3092  }
3093  mi = rpmmiFree(mi);
3094 
3095  Pevr = rpmEVRfree(Pevr);
3096 
3097  return rc;
3098 }
3099 
3100 static int whatneedsTag(Header h, HE_t he)
3101  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3102  /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
3103 {
3104  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
3105  HE_t PNhe = (HE_t) memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
3106  HE_t PEVRhe = (HE_t) memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
3107  HE_t PFhe = (HE_t) memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
3108  HE_t FNhe = (HE_t) memset(alloca(sizeof(*FNhe)), 0, sizeof(*FNhe));
3109  rpmTag tagNVRA = RPMTAG_NVRA;
3110  ARGV_t pkgs = NULL;
3111  ARGI_t hits = NULL;
3112  int rc = 1;
3113 
3114  PNhe->tag = RPMTAG_PROVIDENAME;
3115  if (!headerGet(h, PNhe, 0))
3116  goto exit;
3117  PEVRhe->tag = RPMTAG_PROVIDEVERSION;
3118  if (!headerGet(h, PEVRhe, 0))
3119  goto exit;
3120 assert(PEVRhe->c == PNhe->c);
3121  PFhe->tag = RPMTAG_PROVIDEFLAGS;
3122  if (!headerGet(h, PFhe, 0))
3123  goto exit;
3124 assert(PFhe->c == PNhe->c);
3125 
3126  FNhe->tag = RPMTAG_FILEPATHS;
3127  if (!headerGet(h, FNhe, 0))
3128  goto exit;
3129 
3130  NVRAhe->tag = tagNVRA;;
3131  if (!headerGet(h, NVRAhe, 0))
3132  goto exit;
3133 
3134  (void) argvAdd(&pkgs, NVRAhe->p.str);
3135 
3136  for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++)
3137  (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, PNhe, PEVRhe, PFhe);
3138  for (FNhe->ix = 0; FNhe->ix < (int)FNhe->c; FNhe->ix++)
3139  (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, FNhe, NULL, NULL);
3140 
3141  /* Convert package NVRA array to Header string array. */
3142  { size_t nb = 0;
3143  char * te;
3144  rpmuint32_t i;
3145 
3146  he->t = RPM_STRING_ARRAY_TYPE;
3147  he->c = argvCount(pkgs);
3148  nb = 0;
3149  for (i = 0; i < he->c; i++) {
3150  nb += sizeof(*he->p.argv);
3151  nb += strlen(pkgs[i]) + 1;
3152  }
3153  nb += sizeof(*he->p.argv);
3154 
3155  he->p.argv = xmalloc(nb);
3156  te = (char *) &he->p.argv[he->c+1];
3157 
3158  for (i = 0; i < he->c; i++) {
3159  he->p.argv[i] = te;
3160  te = stpcpy(te, pkgs[i]);
3161  te++;
3162  }
3163  he->p.argv[he->c] = NULL;
3164  }
3165 
3166  hits = argiFree(hits);
3167  pkgs = argvFree(pkgs);
3168  rc = 0;
3169 
3170 exit:
3171  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3172  PNhe->p.ptr = _free(PNhe->p.ptr);
3173  PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
3174  PFhe->p.ptr = _free(PFhe->p.ptr);
3175  FNhe->p.ptr = _free(FNhe->p.ptr);
3176  return rc;
3177 }
3178 
3179 static int nwlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
3180  HE_t RNhe, /*@null@*/ HE_t REVRhe, /*@null@*/ HE_t RFhe)
3181  /*@globals rpmGlobalMacroContext, h_errno,
3182  fileSystem, internalState @*/
3183  /*@modifies *avp, *hitp, REVRhe, rpmGlobalMacroContext,
3184  fileSystem, internalState @*/
3185 {
3186  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
3187  HE_t PNhe = (HE_t) memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
3188  HE_t PEVRhe = (HE_t) memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
3189  HE_t PFhe = (HE_t) memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
3190  rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
3191  const char * key = RNhe->p.argv[RNhe->ix];
3192  size_t keylen = 0;
3193  rpmmi mi;
3194  rpmTag tagN = tagN = (*RNhe->p.argv[RNhe->ix] == '/')
3196  rpmTag tagEVR = RPMTAG_PROVIDEVERSION;
3197  rpmTag tagF = RPMTAG_PROVIDEFLAGS;
3198  rpmuint32_t PFlags;
3199  rpmuint32_t RFlags;
3200  EVR_t Revr;
3201  Header oh;
3202  int rc = 0;
3203  int xx;
3204 
3205  if (tagNVRA == 0)
3206  tagNVRA = RPMTAG_NVRA;
3207 
3208  RFlags = (RFhe != NULL ? (RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK) : 0);
3209  Revr = rpmEVRnew(RFlags, 1);
3210 
3211  if (REVRhe != NULL)
3212  xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
3213 
3214  PNhe->tag = tagN;
3215  PEVRhe->tag = tagEVR;
3216  PFhe->tag = tagF;
3217 
3218  mi = rpmmiInit(_rpmdb, tagN, key, keylen);
3219  if (hitp && *hitp)
3220  xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0);
3221  while ((oh = rpmmiNext(mi)) != NULL) {
3222  if (!headerGet(oh, PNhe, 0))
3223  goto bottom;
3224  if (REVRhe != NULL) {
3225  if (!headerGet(oh, PEVRhe, 0))
3226  goto bottom;
3227 assert(PEVRhe->c == PNhe->c);
3228  if (!headerGet(oh, PFhe, 0))
3229  goto bottom;
3230 assert(PFhe->c == PNhe->c);
3231  }
3232 
3233  for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) {
3234  if (strcmp(RNhe->p.argv[RNhe->ix], PNhe->p.argv[PNhe->ix]))
3235  /*@innercontinue@*/ continue;
3236  if (REVRhe == NULL)
3237  goto bingo;
3238  PFlags = PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK;
3239  { EVR_t Pevr = rpmEVRnew(PFlags, 1);
3240  if (!(PFlags && RFlags))
3241  xx = 1;
3242  else {
3243  xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr);
3244  xx = rpmEVRoverlap(Revr, Pevr);
3245  }
3246  Pevr = rpmEVRfree(Pevr);
3247  }
3248  if (xx)
3249  goto bingo;
3250  }
3251  goto bottom;
3252 
3253 bingo:
3254  NVRAhe->tag = tagNVRA;
3255  xx = headerGet(oh, NVRAhe, 0);
3256  if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
3257  xx = argvAdd(avp, NVRAhe->p.str);
3258  xx = argvSort(*avp, NULL);
3259  if (hitp != NULL)
3260  xx = argiAdd(hitp, -1, rpmmiInstance(mi));
3261  rc++;
3262  }
3263 
3264 bottom:
3265  PNhe->p.ptr = _free(PNhe->p.ptr);
3266  PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
3267  PFhe->p.ptr = _free(PFhe->p.ptr);
3268  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3269  }
3270  mi = rpmmiFree(mi);
3271 
3272  Revr = rpmEVRfree(Revr);
3273 
3274  return rc;
3275 }
3276 
3277 static int needswhatTag(Header h, HE_t he)
3278  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3279  /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
3280 {
3281  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
3282  HE_t RNhe = (HE_t) memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
3283  HE_t REVRhe = (HE_t) memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
3284  HE_t RFhe = (HE_t) memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
3285  rpmTag tagNVRA = RPMTAG_NVRA;
3286  ARGV_t pkgs = NULL;
3287  ARGI_t hits = NULL;
3288  int rc = 1;
3289 
3290  RNhe->tag = RPMTAG_REQUIRENAME;
3291  if (!headerGet(h, RNhe, 0))
3292  goto exit;
3293  REVRhe->tag = RPMTAG_REQUIREVERSION;
3294  if (!headerGet(h, REVRhe, 0))
3295  goto exit;
3296 assert(REVRhe->c == RNhe->c);
3297  RFhe->tag = RPMTAG_REQUIREFLAGS;
3298  if (!headerGet(h, RFhe, 0))
3299  goto exit;
3300 assert(RFhe->c == RNhe->c);
3301 
3302  NVRAhe->tag = tagNVRA;;
3303  if (!headerGet(h, NVRAhe, 0))
3304  goto exit;
3305 
3306  (void) argvAdd(&pkgs, NVRAhe->p.str);
3307 
3308  for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
3309  if (*RNhe->p.argv[RNhe->ix] == '/' || *REVRhe->p.argv[RNhe->ix] == '\0')
3310  (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, NULL, NULL);
3311  else
3312  (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, REVRhe, RFhe);
3313  }
3314 
3315  /* Convert package NVRA array to Header string array. */
3316  { size_t nb = 0;
3317  char * te;
3318  rpmuint32_t i;
3319 
3320  he->t = RPM_STRING_ARRAY_TYPE;
3321  he->c = argvCount(pkgs);
3322  nb = 0;
3323  for (i = 0; i < he->c; i++) {
3324  nb += sizeof(*he->p.argv);
3325  nb += strlen(pkgs[i]) + 1;
3326  }
3327  nb += sizeof(*he->p.argv);
3328 
3329  he->p.argv = xmalloc(nb);
3330  te = (char *) &he->p.argv[he->c+1];
3331 
3332  for (i = 0; i < he->c; i++) {
3333  he->p.argv[i] = te;
3334  te = stpcpy(te, pkgs[i]);
3335  te++;
3336  }
3337  he->p.argv[he->c] = NULL;
3338  }
3339 
3340  hits = argiFree(hits);
3341  pkgs = argvFree(pkgs);
3342  rc = 0;
3343 
3344 exit:
3345  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3346  RNhe->p.ptr = _free(RNhe->p.ptr);
3347  REVRhe->p.ptr = _free(REVRhe->p.ptr);
3348  RFhe->p.ptr = _free(RFhe->p.ptr);
3349  return rc;
3350 }
3351 
3352 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F,
3353  uint32_t i)
3354  /*@*/
3355 {
3356  int a = -2, b = -2;
3357  int rc = 0;
3358 
3359 assert(N.argv[i] != NULL && *N.argv[i] != '\0');
3360 
3361  if (tag == RPMTAG_REQUIRENAME && i > 0
3362  && !(a=strcmp(N.argv[i], N.argv[i-1]))
3363  && !(b=strcmp(EVR.argv[i], EVR.argv[i-1]))
3364  && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e)) )
3365  rc = 1;
3366  return rc;
3367 }
3368 
3369 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3370  /*@globals internalState @*/
3371  /*@modifies he, internalState @*/
3372 {
3373  rpmTag tag = he->tag;
3374  rpmTagData N = { .ptr = NULL };
3375  rpmTagData EVR = { .ptr = NULL };
3376  rpmTagData F = { .ptr = NULL };
3377  size_t nb;
3378  uint32_t ac;
3379  uint32_t c;
3380  uint32_t i;
3381  char *t;
3382  int rc = 1; /* assume failure */
3383  int xx;
3384 int lvl = 0;
3385 spew_t spew = &_xml_spew;
3386 
3387 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3388  xx = headerGet(h, he, 0);
3389  if (xx == 0) goto exit;
3390  N.argv = he->p.argv;
3391  c = he->c;
3392 
3393  he->tag = EVRtag;
3394  xx = headerGet(h, he, 0);
3395  if (xx == 0) goto exit;
3396  EVR.argv = he->p.argv;
3397 
3398  he->tag = Ftag;
3399  xx = headerGet(h, he, 0);
3400  if (xx == 0) goto exit;
3401  F.ui32p = he->p.ui32p;
3402 
3403  nb = sizeof(*he->p.argv);
3404  ac = 0;
3405  for (i = 0; i < c; i++) {
3406 /*@-nullstate@*/ /* EVR.argv might be NULL */
3407  if (PRCOSkip(tag, N, EVR, F, i))
3408  continue;
3409 /*@=nullstate@*/
3410  ac++;
3411  nb += sizeof(*he->p.argv);
3412  nb += sizeof("<rpm:entry name=\"\"/>");
3413  if (*N.argv[i] == '/')
3414  nb += spew->spew_strlen(N.argv[i], lvl);
3415  else
3416  nb += strlen(N.argv[i]);
3417  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3418  nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1;
3419  nb += strlen(EVR.argv[i]);
3420  if (strchr(EVR.argv[i], ':') != NULL)
3421  nb -= 2;
3422  if (strchr(EVR.argv[i], '-') != NULL)
3423  nb += sizeof(" rel=\"\"") - 2;
3424  }
3425 #ifdef NOTNOW
3426  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3427  nb += sizeof(" pre=\"1\"") - 1;
3428 #endif
3429  }
3430 
3431  he->t = RPM_STRING_ARRAY_TYPE;
3432  he->c = ac;
3433  he->freeData = 1;
3434  he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
3435  t = (char *) &he->p.argv[he->c + 1];
3436  ac = 0;
3437  for (i = 0; i < c; i++) {
3438 /*@-nullstate@*/ /* EVR.argv might be NULL */
3439  if (PRCOSkip(tag, N, EVR, F, i))
3440  continue;
3441 /*@=nullstate@*/
3442  he->p.argv[ac++] = t;
3443  t = stpcpy(t, "<rpm:entry");
3444  t = stpcpy(t, " name=\"");
3445  if (*N.argv[i] == '/') {
3446  t = spew->spew_strcpy(t, N.argv[i], lvl); t += strlen(t);
3447  } else
3448  t = stpcpy(t, N.argv[i]);
3449  t = stpcpy(t, "\"");
3450 /*@-readonlytrans@*/
3451  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3452  static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
3453  rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3454  const char *E, *V, *R;
3455  char *f, *fe;
3456  t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\"");
3457  f = (char *) EVR.argv[i];
3458  for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++)
3459  {};
3460  if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
3461  V = f;
3462  for (fe = f; *fe != '\0' && *fe != '-'; fe++)
3463  {};
3464  if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
3465  t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\"");
3466  t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\"");
3467  if (R != NULL)
3468  t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\"");
3469  }
3470 /*@=readonlytrans@*/
3471 #ifdef NOTNOW
3472  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3473  t = stpcpy(t, " pre=\"1\"");
3474 #endif
3475  t = stpcpy(t, "/>");
3476  *t++ = '\0';
3477  }
3478  he->p.argv[he->c] = NULL;
3479 /*@=compmempass@*/
3480  rc = 0;
3481 
3482 exit:
3483 /*@-kepttrans@*/ /* N.argv may be kept. */
3484  N.argv = _free(N.argv);
3485 /*@=kepttrans@*/
3486 /*@-usereleased@*/ /* EVR.argv may be dead. */
3487  EVR.argv = _free(EVR.argv);
3488 /*@=usereleased@*/
3489  F.ui32p = _free(F.ui32p);
3490  return rc;
3491 }
3492 
3493 static int PxmlTag(Header h, HE_t he)
3494  /*@globals internalState @*/
3495  /*@modifies he, internalState @*/
3496 {
3497  he->tag = RPMTAG_PROVIDENAME;
3499 }
3500 
3501 static int RxmlTag(Header h, HE_t he)
3502  /*@globals internalState @*/
3503  /*@modifies he, internalState @*/
3504 {
3505  he->tag = RPMTAG_REQUIRENAME;
3507 }
3508 
3509 static int CxmlTag(Header h, HE_t he)
3510  /*@globals internalState @*/
3511  /*@modifies he, internalState @*/
3512 {
3513  he->tag = RPMTAG_CONFLICTNAME;
3515 }
3516 
3517 static int OxmlTag(Header h, HE_t he)
3518  /*@globals internalState @*/
3519  /*@modifies he, internalState @*/
3520 {
3521  he->tag = RPMTAG_OBSOLETENAME;
3523 }
3524 
3533 static /*@only@*/ char * spewescapeFormat(HE_t he, /*@null@*/ const char ** av,
3534  spew_t spew, int lvl)
3535  /*@*/
3536 {
3537  int ix = (he->ix > 0 ? he->ix : 0);
3538  char * val;
3539 
3540 assert(ix == 0);
3541  if (he->t != RPM_STRING_TYPE) {
3542  val = xstrdup(_("(not a string)"));
3543  } else {
3544  const char * s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
3545  size_t nb = spew->spew_strlen(s, lvl);
3546  char * t = xmalloc(nb+1);;
3547  val = t;
3548  t = spew->spew_strcpy(t, s, lvl); t += strlen(t);
3549  *t = '\0';
3550  s = _free(s);
3551  }
3552 
3553  return val;
3554 }
3555 
3556 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */
3557 static /*@only@*/ char * jsonescapeFormat(HE_t he, /*@null@*/ const char ** av)
3558  /*@*/
3559 {
3560  return spewescapeFormat(he, av, &_json_spew, 0);
3561 }
3562 #endif
3563 
3564 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av)
3565  /*@*/
3566 {
3567  return spewescapeFormat(he, av, &_sql_spew, 0);
3568 }
3569 
3570 /*@-compmempass -kepttrans -nullstate -usereleased @*/
3571 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3572  /*@globals internalState @*/
3573  /*@modifies he, internalState @*/
3574 {
3575  static char q = '"';
3576  rpmTag tag = he->tag;
3577  rpmTagData N = { .ptr = NULL };
3578  rpmTagData EVR = { .ptr = NULL };
3579  rpmTagData F = { .ptr = NULL };
3580  char instance[64];
3581  size_t nb;
3582  uint32_t ac;
3583  uint32_t c;
3584  uint32_t i;
3585  char *te;
3586  int rc = 1; /* assume failure */
3587  int xx;
3588 
3589 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3590  xx = headerGet(h, he, 0);
3591  if (xx == 0) goto exit;
3592  N.argv = he->p.argv;
3593  c = he->c;
3594 
3595  he->tag = EVRtag;
3596  xx = headerGet(h, he, 0);
3597  if (xx == 0) goto exit;
3598  EVR.argv = he->p.argv;
3599 
3600  he->tag = Ftag;
3601  xx = headerGet(h, he, 0);
3602  if (xx == 0) goto exit;
3603  F.ui32p = he->p.ui32p;
3604 
3605  xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
3606  nb = 0;
3607  ac = 0;
3608  for (i = 0; i < c; i++) {
3609 /*@-nullstate@*/ /* EVR.argv might be NULL */
3610  if (PRCOSkip(tag, N, EVR, F, i))
3611  continue;
3612 /*@=nullstate@*/
3613  ac++;
3614  nb += strlen(instance) + sizeof(", '', '', '', '', ''") - 1;
3615  if (tag == RPMTAG_REQUIRENAME)
3616  nb += sizeof(", ''") - 1;
3617  nb += strlen(N.argv[i]);
3618  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3619  uint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3620  EVR_t Revr = rpmEVRnew(Fx, 1);
3621  int xx = rpmEVRparse(EVR.argv[i], Revr);
3622  const char * E = Revr->F[RPMEVR_E];
3623  const char * V = Revr->F[RPMEVR_V];
3624 #ifdef NOTYET /* XXX rpmrepo? */
3625  const char * T = Revr->F[RPMEVR_T];
3626 #endif
3627  const char * R = Revr->F[RPMEVR_R];
3628 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3629  const char * D = Revr->F[RPMEVR_D];
3630 #endif
3631  xx = xx;
3632  nb += (sizeof(", 'EQ'")-1);
3633  nb += (sizeof(", ''")-1) + strlen(E);
3634  nb += (sizeof(", ''")-1) + strlen(V);
3635 #ifdef NOTYET /* XXX rpmrepo? */
3636  nb += (sizeof(", ''")-1) + strlen(T);
3637 #endif
3638  nb += (sizeof(", ''")-1) + strlen(R);
3639 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3640  nb += (sizeof(", ''")-1) + strlen(D);
3641 #endif
3642  Revr = rpmEVRfree(Revr);
3643  }
3644 #ifdef NOTNOW
3645  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3646  nb += sizeof("1") - 1;
3647 #endif
3648  nb++;
3649  }
3650 
3651  nb += (ac + 1) * sizeof(*he->p.argv);
3652 
3653  he->t = RPM_STRING_ARRAY_TYPE;
3654  he->c = ac;
3655  he->freeData = 1;
3656  he->p.argv = xmalloc(nb);
3657  te = (char *) &he->p.argv[ac + 1];
3658  *te = '\0';
3659  ac = 0;
3660  for (i = 0; i < c; i++) {
3661 /*@-nullstate@*/ /* EVR.argv might be NULL */
3662  if (PRCOSkip(tag, N, EVR, F, i))
3663  continue;
3664 /*@=nullstate@*/
3665  he->p.argv[ac++] = te;
3666  te = stpcpy(te, instance);
3667  *te++ = ','; *te++ = ' ';
3668  *te++ = q; te = stpcpy(te, N.argv[i]); *te++ = q;
3669 /*@-readonlytrans@*/
3670  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3671  static const char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
3672  uint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3673  EVR_t Revr = rpmEVRnew(Fx, 1);
3674  int xx = rpmEVRparse(EVR.argv[i], Revr);
3675  const char * E = Revr->F[RPMEVR_E];
3676  const char * V = Revr->F[RPMEVR_V];
3677 #ifdef NOTYET /* XXX rpmrepo? */
3678  const char * T = Revr->F[RPMEVR_T];
3679 #endif
3680  const char * R = Revr->F[RPMEVR_R];
3681 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3682  const char * D = Revr->F[RPMEVR_D];
3683 #endif
3684  xx = xx;
3685  *te++ = ','; *te++ = ' ';
3686  *te++ = q; te = stpcpy(te, Fstr[Fx]); *te++ = q;
3687  *te++ = ','; *te++ = ' ';
3688  *te++ = q; te = stpcpy(te, E); *te++ = q;
3689  *te++ = ','; *te++ = ' ';
3690  *te++ = q; te = stpcpy(te, V); *te++ = q;
3691 #ifdef NOTYET /* XXX rpmrepo? */
3692  *te++ = ','; *te++ = ' ';
3693  *te++ = q; te = stpcpy(te, T); *te++ = q;
3694 #endif
3695  *te++ = ','; *te++ = ' ';
3696  *te++ = q; te = stpcpy(te, R); *te++ = q;
3697 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3698  *te++ = ','; *te++ = ' ';
3699  *te++ = q; te = stpcpy(te, D); *te++ = q;
3700 #endif
3701  Revr = rpmEVRfree(Revr);
3702  } else {
3703  /* XXX FIXME: handle RPMEVR_T and RPMEVR_D? */
3704  *te++ = ','; *te++ = ' ';
3705  *te++ = q; *te++ = q;
3706  *te++ = ','; *te++ = ' ';
3707  *te++ = q; *te++ = q;
3708  *te++ = ','; *te++ = ' ';
3709  *te++ = q; *te++ = q;
3710  *te++ = ','; *te++ = ' ';
3711  *te++ = q; *te++ = q;
3712  }
3713 /*@=readonlytrans@*/
3714 #ifdef NOTNOW
3715  if (tag == RPMTAG_REQUIRENAME)
3716  te = stpcpy(stpcpy(stpcpy(te, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'");
3717 #endif
3718  *te++ = '\0';
3719  }
3720  he->p.argv[ac] = NULL;
3721 /*@=compmempass@*/
3722  rc = 0;
3723 
3724 exit:
3725 /*@-kepttrans@*/ /* N.argv may be kept. */
3726  N.argv = _free(N.argv);
3727 /*@=kepttrans@*/
3728 /*@-usereleased@*/ /* EVR.argv may be dead. */
3729  EVR.argv = _free(EVR.argv);
3730 /*@=usereleased@*/
3731  F.ui32p = _free(F.ui32p);
3732  return rc;
3733 }
3734 
3735 static int PsqlTag(Header h, HE_t he)
3736  /*@globals internalState @*/
3737  /*@modifies he, internalState @*/
3738 {
3739  he->tag = RPMTAG_PROVIDENAME;
3741 }
3742 
3743 static int RsqlTag(Header h, HE_t he)
3744  /*@globals internalState @*/
3745  /*@modifies he, internalState @*/
3746 {
3747  he->tag = RPMTAG_REQUIRENAME;
3749 }
3750 
3751 static int CsqlTag(Header h, HE_t he)
3752  /*@globals internalState @*/
3753  /*@modifies he, internalState @*/
3754 {
3755  he->tag = RPMTAG_CONFLICTNAME;
3757 }
3758 
3759 static int OsqlTag(Header h, HE_t he)
3760  /*@globals internalState @*/
3761  /*@modifies he, internalState @*/
3762 {
3763  he->tag = RPMTAG_OBSOLETENAME;
3765 }
3766 
3767 static int PRCOyamlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3768  /*@globals internalState @*/
3769  /*@modifies he, internalState @*/
3770 {
3771  rpmTag tag = he->tag;
3772  rpmTagData N = { .ptr = NULL };
3773  rpmTagData EVR = { .ptr = NULL };
3774  rpmTagData F = { .ptr = NULL };
3775  size_t nb;
3776  rpmuint32_t ac;
3777  rpmuint32_t c;
3778  rpmuint32_t i;
3779  char *t;
3780  int rc = 1; /* assume failure */
3781  int xx;
3782 int indent = 0;
3783 spew_t spew = &_yaml_spew;
3784 
3785 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3786  xx = headerGet(h, he, 0);
3787  if (xx == 0) goto exit;
3788  N.argv = he->p.argv;
3789  c = he->c;
3790 
3791  he->tag = EVRtag;
3792  xx = headerGet(h, he, 0);
3793  if (xx == 0) goto exit;
3794  EVR.argv = he->p.argv;
3795 
3796  he->tag = Ftag;
3797  xx = headerGet(h, he, 0);
3798  if (xx == 0) goto exit;
3799  F.ui32p = he->p.ui32p;
3800 
3801  nb = sizeof(*he->p.argv);
3802  ac = 0;
3803  for (i = 0; i < c; i++) {
3804 /*@-nullstate@*/ /* EVR.argv might be NULL */
3805  if (PRCOSkip(tag, N, EVR, F, i))
3806  continue;
3807 /*@=nullstate@*/
3808  ac++;
3809  nb += sizeof(*he->p.argv);
3810  nb += sizeof("- ");
3811  if (*N.argv[i] == '/')
3812  nb += spew->spew_strlen(N.argv[i], indent);
3813  else
3814  nb += strlen(N.argv[i]);
3815  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3816  nb += sizeof(" >= ") - 1;
3817  nb += strlen(EVR.argv[i]);
3818  }
3819  }
3820 
3821  he->t = RPM_STRING_ARRAY_TYPE;
3822  he->c = ac;
3823  he->freeData = 1;
3824  he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
3825  t = (char *) &he->p.argv[he->c + 1];
3826  ac = 0;
3827  for (i = 0; i < c; i++) {
3828 /*@-nullstate@*/ /* EVR.argv might be NULL */
3829  if (PRCOSkip(tag, N, EVR, F, i))
3830  continue;
3831 /*@=nullstate@*/
3832  he->p.argv[ac++] = t;
3833  t = stpcpy(t, "- ");
3834  if (*N.argv[i] == '/') {
3835  t = spew->spew_strcpy(t, N.argv[i], indent); t += strlen(t);
3836  } else
3837  t = stpcpy(t, N.argv[i]);
3838 /*@-readonlytrans@*/
3839  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3840  static char *Fstr[] = { "?0","<",">","?3","=","<=",">=","?7" };
3841  rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3842  t = stpcpy( stpcpy( stpcpy(t, " "), Fstr[Fx]), " ");
3843  t = stpcpy(t, EVR.argv[i]);
3844  }
3845 /*@=readonlytrans@*/
3846  *t++ = '\0';
3847  }
3848  he->p.argv[he->c] = NULL;
3849 /*@=compmempass@*/
3850  rc = 0;
3851 
3852 exit:
3853 /*@-kepttrans@*/ /* N.argv may be kept. */
3854  N.argv = _free(N.argv);
3855 /*@=kepttrans@*/
3856 /*@-usereleased@*/ /* EVR.argv may be dead. */
3857  EVR.argv = _free(EVR.argv);
3858 /*@=usereleased@*/
3859  F.ui32p = _free(F.ui32p);
3860  return rc;
3861 }
3862 
3863 static int PyamlTag(Header h, HE_t he)
3864  /*@globals internalState @*/
3865  /*@modifies he, internalState @*/
3866 {
3867  int rc;
3868  he->tag = RPMTAG_PROVIDENAME;
3871  return rc;
3872 }
3873 
3874 static int RyamlTag(Header h, HE_t he)
3875  /*@globals internalState @*/
3876  /*@modifies he, internalState @*/
3877 {
3878  int rc;
3879  he->tag = RPMTAG_REQUIRENAME;
3882  return rc;
3883 }
3884 
3885 static int CyamlTag(Header h, HE_t he)
3886  /*@globals internalState @*/
3887  /*@modifies he, internalState @*/
3888 {
3889  int rc;
3890  he->tag = RPMTAG_CONFLICTNAME;
3893  return rc;
3894 }
3895 
3896 static int OyamlTag(Header h, HE_t he)
3897  /*@globals internalState @*/
3898  /*@modifies he, internalState @*/
3899 {
3900  int rc;
3901  he->tag = RPMTAG_OBSOLETENAME;
3904  return rc;
3905 }
3906 
3908  /*@*/
3909 {
3910  const char * dn = DN.argv[DI.ui32p[i]];
3911  size_t dnlen = strlen(dn);
3912 
3913 assert(dn != NULL);
3914  if (strstr(dn, "bin/") != NULL)
3915  return 1;
3916  if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen))
3917  return 1;
3918  if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail"))
3919  return 1;
3920  return 2;
3921 }
3922 
3923 static int FDGxmlTag(Header h, HE_t he, int lvl)
3924  /*@globals internalState @*/
3925  /*@modifies he, internalState @*/
3926 {
3927  rpmTagData BN = { .ptr = NULL };
3928  rpmTagData DN = { .ptr = NULL };
3929  rpmTagData DI = { .ptr = NULL };
3930  rpmTagData FMODES = { .ptr = NULL };
3931  rpmTagData FFLAGS = { .ptr = NULL };
3932  size_t nb;
3933  rpmuint32_t ac;
3934  rpmuint32_t c;
3935  rpmuint32_t i;
3936  char *t;
3937  int rc = 1; /* assume failure */
3938  int xx;
3939 spew_t spew = &_xml_spew;
3940 
3941 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3942  he->tag = RPMTAG_BASENAMES;
3943  xx = headerGet(h, he, 0);
3944  if (xx == 0) goto exit;
3945  BN.argv = he->p.argv;
3946  c = he->c;
3947 
3948  he->tag = RPMTAG_DIRNAMES;
3949  xx = headerGet(h, he, 0);
3950  if (xx == 0) goto exit;
3951  DN.argv = he->p.argv;
3952 
3953  he->tag = RPMTAG_DIRINDEXES;
3954  xx = headerGet(h, he, 0);
3955  if (xx == 0) goto exit;
3956  DI.ui32p = he->p.ui32p;
3957 
3958  he->tag = RPMTAG_FILEMODES;
3959  xx = headerGet(h, he, 0);
3960  if (xx == 0) goto exit;
3961  FMODES.ui16p = he->p.ui16p;
3962 
3963  he->tag = RPMTAG_FILEFLAGS;
3964  xx = headerGet(h, he, 0);
3965  if (xx == 0) goto exit;
3966  FFLAGS.ui32p = he->p.ui32p;
3967 
3968  nb = sizeof(*he->p.argv);
3969  ac = 0;
3970  for (i = 0; i < c; i++) {
3971  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3972  continue;
3973  ac++;
3974  nb += sizeof(*he->p.argv);
3975  nb += sizeof("<file></file>");
3976  nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], lvl);
3977  nb += spew->spew_strlen(BN.argv[i], lvl);
3978  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3979  nb += sizeof(" type=\"ghost\"") - 1;
3980  else if (S_ISDIR(FMODES.ui16p[i])) {
3981  nb += sizeof(" type=\"dir\"") - 1;
3982 #ifdef NOTYET
3983  nb += sizeof("/") - 1;
3984 #endif
3985  }
3986  }
3987 
3988  he->t = RPM_STRING_ARRAY_TYPE;
3989  he->c = ac;
3990  he->freeData = 1;
3991  he->p.argv = xmalloc(nb);
3992  t = (char *) &he->p.argv[he->c + 1];
3993  ac = 0;
3994  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
3995  for (i = 0; i < c; i++) {
3996  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3997  continue;
3998  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3999  continue;
4000  if (S_ISDIR(FMODES.ui16p[i]))
4001  continue;
4002  he->p.argv[ac++] = t;
4003  t = stpcpy(t, "<file>");
4004  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t);
4005  t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t);
4006  t = stpcpy(t, "</file>");
4007  *t++ = '\0';
4008  }
4009  for (i = 0; i < c; i++) {
4010  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4011  continue;
4012  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4013  continue;
4014  if (!S_ISDIR(FMODES.ui16p[i]))
4015  continue;
4016  he->p.argv[ac++] = t;
4017  t = stpcpy(t, "<file type=\"dir\">");
4018  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t);
4019  t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t);
4020 #ifdef NOTYET
4021  /* Append the pesky trailing / to directories. */
4022  if (t[-1] != '/')
4023  t = stpcpy(t, "/");
4024 #endif
4025  t = stpcpy(t, "</file>");
4026  *t++ = '\0';
4027  }
4028  for (i = 0; i < c; i++) {
4029  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4030  continue;
4031  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
4032  continue;
4033  he->p.argv[ac++] = t;
4034  t = stpcpy(t, "<file type=\"ghost\">");
4035  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t);
4036  t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t);
4037  t = stpcpy(t, "</file>");
4038  *t++ = '\0';
4039  }
4040 
4041  he->p.argv[he->c] = NULL;
4042 /*@=compmempass@*/
4043  rc = 0;
4044 
4045 exit:
4046 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
4047  BN.argv = _free(BN.argv);
4048 /*@-usereleased@*/ /* DN.argv may be dead. */
4049  DN.argv = _free(DN.argv);
4050 /*@=usereleased@*/
4051  DI.ui32p = _free(DI.ui32p);
4052 /*@=kepttrans@*/
4053  FMODES.ui16p = _free(FMODES.ui16p);
4054 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
4055  FFLAGS.ui32p = _free(FFLAGS.ui32p);
4056 /*@=usereleased@*/
4057  return rc;
4058 }
4059 
4060 static int F1xmlTag(Header h, HE_t he)
4061  /*@globals internalState @*/
4062  /*@modifies he, internalState @*/
4063 {
4064  he->tag = RPMTAG_BASENAMES;
4065  return FDGxmlTag(h, he, 1);
4066 }
4067 
4068 static int F2xmlTag(Header h, HE_t he)
4069  /*@globals internalState @*/
4070  /*@modifies he, internalState @*/
4071 {
4072  he->tag = RPMTAG_BASENAMES;
4073  return FDGxmlTag(h, he, 2);
4074 }
4075 
4076 static int FDGsqlTag(Header h, HE_t he, int lvl)
4077  /*@globals internalState @*/
4078  /*@modifies he, internalState @*/
4079 {
4080  rpmTagData BN = { .ptr = NULL };
4081  rpmTagData DN = { .ptr = NULL };
4082  rpmTagData DI = { .ptr = NULL };
4083  rpmTagData FMODES = { .ptr = NULL };
4084  rpmTagData FFLAGS = { .ptr = NULL };
4085  char instance[64];
4086  size_t nb;
4087  rpmuint32_t ac;
4088  rpmuint32_t c;
4089  rpmuint32_t i;
4090  char *t;
4091  int rc = 1; /* assume failure */
4092  int xx;
4093 
4094 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
4095  he->tag = RPMTAG_BASENAMES;
4096  xx = headerGet(h, he, 0);
4097  if (xx == 0) goto exit;
4098  BN.argv = he->p.argv;
4099  c = he->c;
4100 
4101  he->tag = RPMTAG_DIRNAMES;
4102  xx = headerGet(h, he, 0);
4103  if (xx == 0) goto exit;
4104  DN.argv = he->p.argv;
4105 
4106  he->tag = RPMTAG_DIRINDEXES;
4107  xx = headerGet(h, he, 0);
4108  if (xx == 0) goto exit;
4109  DI.ui32p = he->p.ui32p;
4110 
4111  he->tag = RPMTAG_FILEMODES;
4112  xx = headerGet(h, he, 0);
4113  if (xx == 0) goto exit;
4114  FMODES.ui16p = he->p.ui16p;
4115 
4116  he->tag = RPMTAG_FILEFLAGS;
4117  xx = headerGet(h, he, 0);
4118  if (xx == 0) goto exit;
4119  FFLAGS.ui32p = he->p.ui32p;
4120 
4121  xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
4122  nb = sizeof(*he->p.argv);
4123  ac = 0;
4124  for (i = 0; i < c; i++) {
4125  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4126  continue;
4127  ac++;
4128  nb += sizeof(*he->p.argv);
4129  nb += strlen(instance) + sizeof(", '', ''");
4130  nb += strlen(DN.argv[DI.ui32p[i]]);
4131  nb += strlen(BN.argv[i]);
4132  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4133  nb += sizeof("ghost") - 1;
4134  else if (S_ISDIR(FMODES.ui16p[i])) {
4135  nb += sizeof("dir") - 1;
4136 #ifdef NOTYET
4137  nb += sizeof("/") - 1;
4138 #endif
4139  } else
4140  nb += sizeof("file") - 1;
4141  }
4142 
4143  he->t = RPM_STRING_ARRAY_TYPE;
4144  he->c = ac;
4145  he->freeData = 1;
4146  he->p.argv = xmalloc(nb);
4147  t = (char *) &he->p.argv[he->c + 1];
4148  ac = 0;
4149  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
4150  for (i = 0; i < c; i++) {
4151  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4152  continue;
4153  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4154  continue;
4155  if (S_ISDIR(FMODES.ui16p[i]))
4156  continue;
4157  he->p.argv[ac++] = t;
4158  t = stpcpy( stpcpy(t, instance), ", '");
4159  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
4160  t = strcpy(t, BN.argv[i]); t += strlen(t);
4161  t = stpcpy(t, "', 'file'");
4162  *t++ = '\0';
4163  }
4164  for (i = 0; i < c; i++) {
4165  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4166  continue;
4167  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4168  continue;
4169  if (!S_ISDIR(FMODES.ui16p[i]))
4170  continue;
4171  he->p.argv[ac++] = t;
4172  t = stpcpy( stpcpy(t, instance), ", '");
4173  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
4174  t = strcpy(t, BN.argv[i]); t += strlen(t);
4175 #ifdef NOTYET
4176  /* Append the pesky trailing / to directories. */
4177  if (t[-1] != '/')
4178  t = stpcpy(t, "/");
4179 #endif
4180  t = stpcpy(t, "', 'dir'");
4181  *t++ = '\0';
4182  }
4183  for (i = 0; i < c; i++) {
4184  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4185  continue;
4186  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
4187  continue;
4188  he->p.argv[ac++] = t;
4189  t = stpcpy( stpcpy(t, instance), ", '");
4190  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
4191  t = strcpy(t, BN.argv[i]); t += strlen(t);
4192  t = stpcpy(t, "', 'ghost'");
4193  *t++ = '\0';
4194  }
4195 
4196  he->p.argv[he->c] = NULL;
4197 /*@=compmempass@*/
4198  rc = 0;
4199 
4200 exit:
4201 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
4202  BN.argv = _free(BN.argv);
4203 /*@-usereleased@*/ /* DN.argv may be dead. */
4204  DN.argv = _free(DN.argv);
4205 /*@=usereleased@*/
4206  DI.ui32p = _free(DI.ui32p);
4207 /*@=kepttrans@*/
4208  FMODES.ui16p = _free(FMODES.ui16p);
4209 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
4210  FFLAGS.ui32p = _free(FFLAGS.ui32p);
4211 /*@=usereleased@*/
4212  return rc;
4213 }
4214 
4215 static int F1sqlTag(Header h, HE_t he)
4216  /*@globals internalState @*/
4217  /*@modifies he, internalState @*/
4218 {
4219  he->tag = RPMTAG_BASENAMES;
4220  return FDGsqlTag(h, he, 1);
4221 }
4222 
4223 static int F2sqlTag(Header h, HE_t he)
4224  /*@globals internalState @*/
4225  /*@modifies he, internalState @*/
4226 {
4227  he->tag = RPMTAG_BASENAMES;
4228  return FDGsqlTag(h, he, 2);
4229 }
4230 
4231 static int FDGyamlTag(Header h, HE_t he, int lvl)
4232  /*@globals internalState @*/
4233  /*@modifies he, internalState @*/
4234 {
4235  rpmTagData BN = { .ptr = NULL };
4236  rpmTagData DN = { .ptr = NULL };
4237  rpmTagData DI = { .ptr = NULL };
4238  rpmTagData FMODES = { .ptr = NULL };
4239  rpmTagData FFLAGS = { .ptr = NULL };
4240  size_t nb;
4241  rpmuint32_t ac;
4242  rpmuint32_t c;
4243  rpmuint32_t i;
4244  char *t;
4245  int rc = 1; /* assume failure */
4246  int xx;
4247 int indent = 0;
4248 spew_t spew = &_yaml_spew;
4249 
4250 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
4251  he->tag = RPMTAG_BASENAMES;
4252  xx = headerGet(h, he, 0);
4253  if (xx == 0) goto exit;
4254  BN.argv = he->p.argv;
4255  c = he->c;
4256 
4257  he->tag = RPMTAG_DIRNAMES;
4258  xx = headerGet(h, he, 0);
4259  if (xx == 0) goto exit;
4260  DN.argv = he->p.argv;
4261 
4262  he->tag = RPMTAG_DIRINDEXES;
4263  xx = headerGet(h, he, 0);
4264  if (xx == 0) goto exit;
4265  DI.ui32p = he->p.ui32p;
4266 
4267  he->tag = RPMTAG_FILEMODES;
4268  xx = headerGet(h, he, 0);
4269  if (xx == 0) goto exit;
4270  FMODES.ui16p = he->p.ui16p;
4271 
4272  he->tag = RPMTAG_FILEFLAGS;
4273  xx = headerGet(h, he, 0);
4274  if (xx == 0) goto exit;
4275  FFLAGS.ui32p = he->p.ui32p;
4276 
4277  nb = sizeof(*he->p.argv);
4278  ac = 0;
4279  for (i = 0; i < c; i++) {
4280  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4281  continue;
4282  ac++;
4283  nb += sizeof(*he->p.argv);
4284  nb += sizeof("- ");
4285  nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], indent);
4286  nb += spew->spew_strlen(BN.argv[i], indent);
4287  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4288  nb += sizeof("") - 1;
4289  else if (S_ISDIR(FMODES.ui16p[i]))
4290  nb += sizeof("/") - 1;
4291  }
4292 
4293  he->t = RPM_STRING_ARRAY_TYPE;
4294  he->c = ac;
4295  he->freeData = 1;
4296  he->p.argv = xmalloc(nb);
4297  t = (char *) &he->p.argv[he->c + 1];
4298  ac = 0;
4299  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
4300  for (i = 0; i < c; i++) {
4301  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4302  continue;
4303  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4304  continue;
4305  if (S_ISDIR(FMODES.ui16p[i]))
4306  continue;
4307  he->p.argv[ac++] = t;
4308  t = stpcpy(t, "- ");
4309  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
4310  t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t);
4311  t = stpcpy(t, "");
4312  *t++ = '\0';
4313  }
4314  for (i = 0; i < c; i++) {
4315  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4316  continue;
4317  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4318  continue;
4319  if (!S_ISDIR(FMODES.ui16p[i]))
4320  continue;
4321  he->p.argv[ac++] = t;
4322  t = stpcpy(t, "- ");
4323  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
4324  t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t);
4325  /* Append the pesky trailing / to directories. */
4326  if (t[-1] != '/')
4327  t = stpcpy(t, "/");
4328  *t++ = '\0';
4329  }
4330  for (i = 0; i < c; i++) {
4331  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4332  continue;
4333  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
4334  continue;
4335  he->p.argv[ac++] = t;
4336  t = stpcpy(t, "- ");
4337  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
4338  t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t);
4339  *t++ = '\0';
4340  }
4341 
4342  he->p.argv[he->c] = NULL;
4343 /*@=compmempass@*/
4344  rc = 0;
4345 
4346 exit:
4347 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
4348  BN.argv = _free(BN.argv);
4349 /*@-usereleased@*/ /* DN.argv may be dead. */
4350  DN.argv = _free(DN.argv);
4351 /*@=usereleased@*/
4352  DI.ui32p = _free(DI.ui32p);
4353 /*@=kepttrans@*/
4354  FMODES.ui16p = _free(FMODES.ui16p);
4355 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
4356  FFLAGS.ui32p = _free(FFLAGS.ui32p);
4357 /*@=usereleased@*/
4358  return rc;
4359 }
4360 
4361 static int F1yamlTag(Header h, HE_t he)
4362  /*@globals internalState @*/
4363  /*@modifies he, internalState @*/
4364 {
4365  he->tag = RPMTAG_BASENAMES;
4366  return FDGyamlTag(h, he, 1);
4367 }
4368 
4369 static int F2yamlTag(Header h, HE_t he)
4370  /*@globals internalState @*/
4371  /*@modifies he, internalState @*/
4372 {
4373  he->tag = RPMTAG_BASENAMES;
4374  return FDGyamlTag(h, he, 2);
4375 }
4376 
4383 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av)
4384  /*@*/
4385 {
4386  char * val;
4387 
4388  if (he->t != RPM_STRING_TYPE) {
4389  val = xstrdup(_("(not a string)"));
4390  } else {
4391  const char * bn;
4392  const char * s;
4393  size_t nb;
4394  char * t;
4395 int lvl = 0;
4396 spew_t spew = &_xml_spew;
4397 
4398 assert(he->p.str != NULL);
4399  /* Get rightmost '/' in string (i.e. basename(3) behavior). */
4400  if ((bn = strrchr(he->p.str, '/')) != NULL)
4401  bn++;
4402  else
4403  bn = he->p.str;
4404 
4405  s = strdup_iconv_check(bn, (av ? av[0] : NULL));
4406  nb = spew->spew_strlen(s, lvl);
4407  t = xmalloc(nb + 1);
4408  val = t;
4409  t = spew->spew_strcpy(t, s, lvl); t += strlen(t);
4410  *t = '\0';
4411  s = _free(s);
4412  }
4413 
4414  return val;
4415 }
4416 
4417 typedef struct key_s {
4418 /*@observer@*/
4419  const char *name; /* key name */
4421 } KEY;
4422 
4423 /*@unchecked@*/ /*@observer@*/
4424 static KEY keyDigests[] = {
4425  { "adler32", PGPHASHALGO_ADLER32 },
4426  { "crc32", PGPHASHALGO_CRC32 },
4427  { "crc64", PGPHASHALGO_CRC64 },
4428  { "haval160", PGPHASHALGO_HAVAL_5_160 },
4429  { "jlu32", PGPHASHALGO_JLU32 },
4430  { "md2", PGPHASHALGO_MD2 },
4431  { "md4", PGPHASHALGO_MD4 },
4432  { "md5", PGPHASHALGO_MD5 },
4433  { "rmd128", PGPHASHALGO_RIPEMD128 },
4434  { "rmd160", PGPHASHALGO_RIPEMD160 },
4435  { "rmd256", PGPHASHALGO_RIPEMD256 },
4436  { "rmd320", PGPHASHALGO_RIPEMD320 },
4437  { "salsa10", PGPHASHALGO_SALSA10 },
4438  { "salsa20", PGPHASHALGO_SALSA20 },
4439  { "sha1", PGPHASHALGO_SHA1 },
4440  { "sha224", PGPHASHALGO_SHA224 },
4441  { "sha256", PGPHASHALGO_SHA256 },
4442  { "sha384", PGPHASHALGO_SHA384 },
4443  { "sha512", PGPHASHALGO_SHA512 },
4444  { "tiger192", PGPHASHALGO_TIGER192 },
4445 };
4446 /*@unchecked@*/
4447 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]);
4448 
4454  STAT_KEYS_DEV = (1U << 0),
4455  STAT_KEYS_INO = (1U << 1),
4456  STAT_KEYS_MODE = (1U << 2),
4457  STAT_KEYS_NLINK = (1U << 3),
4458  STAT_KEYS_UID = (1U << 4),
4459  STAT_KEYS_GID = (1U << 5),
4460  STAT_KEYS_RDEV = (1U << 6),
4461  STAT_KEYS_SIZE = (1U << 7),
4462  STAT_KEYS_BLKSIZE = (1U << 8),
4463  STAT_KEYS_BLOCKS = (1U << 9),
4464  STAT_KEYS_ATIME = (1U << 10),
4465  STAT_KEYS_CTIME = (1U << 11),
4466  STAT_KEYS_MTIME = (1U << 12),
4467 #ifdef NOTYET
4468  STAT_KEYS_FLAGS = (1U << 13),
4469 #endif
4470  STAT_KEYS_SLINK = (1U << 14),
4471  STAT_KEYS_DIGEST = (1U << 15),
4472 #ifdef NOTYET
4473  STAT_KEYS_FCONTEXT = (1U << 16),
4474 #endif
4475  STAT_KEYS_UNAME = (1U << 17),
4476  STAT_KEYS_GNAME = (1U << 18),
4477 };
4478 
4479 /*@unchecked@*/ /*@observer@*/
4480 static KEY keyStat[] = {
4481  { "adler32", STAT_KEYS_DIGEST },
4482  { "atime", STAT_KEYS_ATIME },
4483  { "ctime", STAT_KEYS_CTIME },
4484  { "blksize", STAT_KEYS_BLKSIZE },
4485  { "blocks", STAT_KEYS_BLOCKS },
4486  { "crc32", STAT_KEYS_DIGEST },
4487  { "crc64", STAT_KEYS_DIGEST },
4488  { "dev", STAT_KEYS_DEV },
4489 #ifdef NOTYET
4490  { "digest", STAT_KEYS_DIGEST },
4491  { "fcontext", STAT_KEYS_FCONTEXT },
4492  { "flags", STAT_KEYS_FLAGS },
4493 #endif
4494  { "gid", STAT_KEYS_GID },
4495  { "gname", STAT_KEYS_GNAME },
4496  { "haval160", STAT_KEYS_DIGEST },
4497  { "ino", STAT_KEYS_INO },
4498  { "jlu32", STAT_KEYS_DIGEST },
4499  { "link", STAT_KEYS_SLINK },
4500  { "md2", STAT_KEYS_DIGEST },
4501  { "md4", STAT_KEYS_DIGEST },
4502  { "md5", STAT_KEYS_DIGEST },
4503  { "mode", STAT_KEYS_MODE },
4504  { "mtime", STAT_KEYS_MTIME },
4505  { "nlink", STAT_KEYS_NLINK },
4506  { "rdev", STAT_KEYS_RDEV },
4507  { "rmd128", STAT_KEYS_DIGEST },
4508  { "rmd160", STAT_KEYS_DIGEST },
4509  { "rmd256", STAT_KEYS_DIGEST },
4510  { "rmd320", STAT_KEYS_DIGEST },
4511  { "salsa10", STAT_KEYS_DIGEST },
4512  { "salsa20", STAT_KEYS_DIGEST },
4513  { "sha1", STAT_KEYS_DIGEST },
4514  { "sha224", STAT_KEYS_DIGEST },
4515  { "sha256", STAT_KEYS_DIGEST },
4516  { "sha384", STAT_KEYS_DIGEST },
4517  { "sha512", STAT_KEYS_DIGEST },
4518  { "size", STAT_KEYS_SIZE },
4519  { "tiger192", STAT_KEYS_DIGEST },
4520  { "uid", STAT_KEYS_UID },
4521  { "uname", STAT_KEYS_UNAME },
4522 };
4523 /*@unchecked@*/
4524 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]);
4525 
4530  UUID_KEYS_NONE = (0U << 0),
4531  UUID_KEYS_V1 = (1U << 0),
4532  UUID_KEYS_V3 = (3U << 0),
4533  UUID_KEYS_V4 = (4U << 0),
4534  UUID_KEYS_V5 = (5U << 0),
4535 #ifdef NOTYET
4536  UUID_KEYS_STRING = (0U << 4),
4537  UUID_KEYS_SIV = (1U << 4),
4538  UUID_KEYS_BINARY = (2U << 4),
4539  UUID_KEYS_TEXT = (3U << 4),
4540 #endif
4541 };
4542 
4543 /*@unchecked@*/ /*@observer@*/
4544 static KEY keyUuids[] = {
4545 #ifdef NOTYET
4546  { "binary", UUID_KEYS_BINARY },
4547  { "siv", UUID_KEYS_SIV },
4548  { "string", UUID_KEYS_STRING },
4549  { "text", UUID_KEYS_TEXT },
4550 #endif
4551  { "v1", UUID_KEYS_V1 },
4552  { "v3", UUID_KEYS_V3 },
4553  { "v4", UUID_KEYS_V4 },
4554  { "v5", UUID_KEYS_V5 },
4555 };
4556 /*@unchecked@*/
4557 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]);
4558 
4561 static int
4562 keyCmp(const void * a, const void * b)
4563  /*@*/
4564 {
4565  return strcmp(((KEY *)a)->name, ((KEY *)b)->name);
4566 }
4567 
4570 static rpmuint32_t
4571 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name)
4572  /*@*/
4573 {
4574  rpmuint32_t keyval = 0;
4575 
4576  if (name && * name) {
4577  KEY needle = { .name = name, .value = 0 };
4578  KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp);
4579  if (k)
4580  keyval = k->value;
4581  }
4582  return keyval;
4583 }
4584 
4591 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av)
4592  /*@*/
4593 {
4594  int ix = (he->ix > 0 ? he->ix : 0);
4595  char * val = NULL;
4596  size_t ns;
4597 
4598 assert(ix == 0);
4599  switch(he->t) {
4600  default:
4601  val = xstrdup(_("(invalid type :digest)"));
4602  goto exit;
4603  /*@notreached@*/ break;
4604  case RPM_UINT64_TYPE:
4605  ns = sizeof(he->p.ui64p[0]);
4606  break;
4607  case RPM_STRING_TYPE:
4608  ns = strlen(he->p.str);
4609  break;
4610  case RPM_BIN_TYPE:
4611  ns = he->c;
4612  break;
4613  }
4614 
4615 assert(he->p.ptr != NULL);
4616  { rpmuint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL));
4617  rpmuint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1);
4618  DIGEST_CTX ctx = rpmDigestInit(algo, 0);
4619  int xx = rpmDigestUpdate(ctx, he->p.ptr, ns);
4620  xx = rpmDigestFinal(ctx, &val, NULL, 1);
4621  }
4622 
4623 exit:
4624  return val;
4625 }
4626 
4633 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av)
4634  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
4635  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
4636 {
4637 /*@-nullassign@*/
4638  /*@unchecked@*/ /*@observer@*/
4639  static const char *avdefault[] = { "mode", NULL };
4640 /*@=nullassign@*/
4641  const char * fn = NULL;
4642  struct stat sb, *st = &sb;
4643  int ix = (he->ix > 0 ? he->ix : 0);
4644  char * val = NULL;
4645  int xx;
4646  int i;
4647 
4648  memset(st, 0, sizeof(*st));
4649 assert(ix == 0);
4650  switch(he->t) {
4651  case RPM_BIN_TYPE:
4652  /* XXX limit to RPMTAG_PACKAGESTAT ... */
4653  if (he->tag == RPMTAG_PACKAGESTAT)
4654  if ((size_t)he->c == sizeof(*st)) {
4655  st = (struct stat *)he->p.ptr;
4656  break;
4657  }
4658  /*@fallthrough @*/
4659  default:
4660  val = xstrdup(_("(invalid type :stat)"));
4661  goto exit;
4662  /*@notreached@*/ break;
4663  case RPM_STRING_TYPE:
4664  fn = he->p.str;
4665  if (Lstat(fn, st) == 0)
4666  break;
4667 /*@-ownedtrans@*/
4668  val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL);
4669 /*@=ownedtrans@*/
4670  goto exit;
4671  /*@notreached@*/ break;
4672  }
4673 
4674  if (!(av && av[0] && *av[0]))
4675  av = avdefault;
4676  for (i = 0; av[i] != NULL; i++) {
4677  char b[BUFSIZ];
4678  size_t nb = sizeof(b);
4679  char * nval;
4680  rpmuint32_t keyval = keyValue(keyStat, nkeyStat, av[i]);
4681 
4682  nval = NULL;
4683  b[0] = '\0';
4684  switch (keyval) {
4685  default:
4686  /*@switchbreak@*/ break;
4687  case STAT_KEYS_NONE:
4688  /*@switchbreak@*/ break;
4689  case STAT_KEYS_DEV:
4690  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev);
4691  /*@switchbreak@*/ break;
4692  case STAT_KEYS_INO:
4693  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino);
4694  /*@switchbreak@*/ break;
4695  case STAT_KEYS_MODE:
4696  xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode);
4697  /*@switchbreak@*/ break;
4698  case STAT_KEYS_NLINK:
4699  xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink);
4700  /*@switchbreak@*/ break;
4701  case STAT_KEYS_UID:
4702  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid);
4703  /*@switchbreak@*/ break;
4704  case STAT_KEYS_GID:
4705  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid);
4706  /*@switchbreak@*/ break;
4707  case STAT_KEYS_RDEV:
4708  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev);
4709  /*@switchbreak@*/ break;
4710  case STAT_KEYS_SIZE:
4711  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size);
4712  /*@switchbreak@*/ break;
4713  case STAT_KEYS_BLKSIZE:
4714  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize);
4715  /*@switchbreak@*/ break;
4716  case STAT_KEYS_BLOCKS:
4717  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks);
4718  /*@switchbreak@*/ break;
4719  case STAT_KEYS_ATIME:
4720 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_atime));
4721  /*@switchbreak@*/ break;
4722  case STAT_KEYS_CTIME:
4723 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_ctime));
4724  /*@switchbreak@*/ break;
4725  case STAT_KEYS_MTIME:
4726 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_mtime));
4727  /*@switchbreak@*/ break;
4728 #ifdef NOTYET
4729  case STAT_KEYS_FLAGS:
4730  /*@switchbreak@*/ break;
4731 #endif
4732  case STAT_KEYS_SLINK:
4733  if (fn != NULL && S_ISLNK(st->st_mode)) {
4734  ssize_t size = Readlink(fn, b, nb);
4735  if (size == -1) {
4736  nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL);
4737  (void) stpcpy(b, nval);
4738  nval = _free(nval);
4739  } else
4740  b[size] = '\0';
4741  }
4742  /*@switchbreak@*/ break;
4743  case STAT_KEYS_DIGEST:
4744  if (fn != NULL && S_ISREG(st->st_mode)) {
4745  rpmuint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]);
4746  rpmuint32_t algo = (digval ? digval : PGPHASHALGO_SHA1);
4747  FD_t fd = Fopen(fn, "r%{?_rpmgio}");
4748  if (fd == NULL || Ferror(fd)) {
4749  nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL);
4750  } else {
4751  static int asAscii = 1;
4752  char buffer[16 * 1024];
4753  fdInitDigest(fd, algo, 0);
4754  while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
4755  {};
4756  if (Ferror(fd))
4757  nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL);
4758  else
4759  fdFiniDigest(fd, algo, &nval, NULL, asAscii);
4760  }
4761  if (nval) {
4762  (void) stpcpy(b, nval);
4763  nval = _free(nval);
4764  }
4765  if (fd != NULL)
4766  xx = Fclose(fd);
4767  }
4768  /*@switchbreak@*/ break;
4769  case STAT_KEYS_UNAME:
4770  { const char * uname = uidToUname(st->st_uid);
4771  if (uname != NULL)
4772  (void) stpcpy(b, uname);
4773  else
4774  xx = snprintf(b, nb, "%u", (unsigned)st->st_uid);
4775  } /*@switchbreak@*/ break;
4776  case STAT_KEYS_GNAME:
4777  { const char * gname = gidToGname(st->st_gid);
4778  if (gname != NULL)
4779  (void) stpcpy(b, gname);
4780  else
4781  xx = snprintf(b, nb, "%u", (unsigned)st->st_gid);
4782  } /*@switchbreak@*/ break;
4783  }
4784  if (b[0] == '\0')
4785  continue;
4786  b[nb-1] = '\0';
4787 
4788  if (val == NULL)
4789  val = xstrdup(b);
4790  else {
4791  nval = rpmExpand(val, " | ", b, NULL);
4792  val = _free(val);
4793  val = nval;
4794  }
4795  }
4796 
4797 exit:
4798  return val;
4799 }
4800 
4807 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av)
4808  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
4809  /*@modifies rpmGlobalMacroContext, internalState @*/
4810 {
4811  static const char hex[] = "0123456789abcdef";
4812  /* XXX use private tag container to avoid memory issues for now. */
4813  HE_t nhe = (HE_t) memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
4814 /*@-nullassign@*/
4815  /*@unchecked@*/ /*@observer@*/
4816  static const char *avdefault[] = { "v5", NULL };
4817 /*@=nullassign@*/
4818  int ix = (he->ix > 0 ? he->ix : 0);
4819  char * val = NULL;
4820  struct timeval tv;
4821  char * t;
4822  char * te;
4823  uint32_t i;
4824 
4825 assert(ix == 0);
4826  val = xmalloc((128/4 + 4) + 1);
4827  *val = '\0';
4828 
4829  nhe->tag = he->tag;
4830  nhe->t = he->t;
4831  switch(he->t) {
4832  default:
4833  val = _free(val);
4834  val = xstrdup(_("(invalid type :uuid)"));
4835  goto exit;
4836  /*@notreached@*/ break;
4837  case RPM_UINT64_TYPE:
4838  /* XXX Limit to tag time stamps with UUIDv1 direct conversion. */
4839  switch (he->tag) {
4840  default:
4841  val = _free(val);
4842  val = xstrdup(_("(invalid tag :uuid)"));
4843  goto exit;
4844  break;
4845  case RPMTAG_INSTALLTIME:
4846  case RPMTAG_BUILDTIME:
4847  case RPMTAG_ORIGINTIME:
4848  case RPMTAG_INSTALLTID:
4849  case RPMTAG_REMOVETID:
4850  case RPMTAG_ORIGINTID:
4851 
4852  /* Convert tag time stamp to UUIDv1. */
4853  tv.tv_sec = (long) he->p.ui64p[0];
4854  tv.tv_usec = (long) (he->c > 1 ? he->p.ui64p[1] : 0);
4855  ix = tv2uuidv1(NULL, nhe, &tv);
4856 
4857  /* Convert UUIDv1 to display string. */
4858  te = val;
4859  for (i = 0; i < nhe->c; i++) {
4860  *te++ = hex[ (int)((nhe->p.ui8p[i] >> 4) & 0x0f) ];
4861  *te++ = hex[ (int)((nhe->p.ui8p[i] ) & 0x0f) ];
4862  if (i == 3 || i == 5 || i == 7 || i == 9)
4863  *te++ = '-';
4864  }
4865  *te = '\0';
4866  goto exit; /* XXX immediate exit for UUIDv1 */
4867  break;
4868  }
4869  break;
4870  case RPM_BIN_TYPE:
4871  /* XXX Limit to tag binary digests with djb formatting in UUIDv5. */
4872  switch (he->tag) {
4873  default:
4874  val = _free(val);
4875  val = xstrdup(_("(invalid tag :uuid)"));
4876  goto exit;
4877  break;
4878  case RPMTAG_PKGID:
4879  case RPMTAG_SOURCEPKGID:
4880  /* Convert RPMTAG_*PKGID from binary => hex. */
4881  t = te = xmalloc(2*he->c + 1);
4882  for (i = 0; i < he->c; i++) {
4883  *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ];
4884  *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ];
4885  }
4886  *te = '\0';
4887  nhe->t = RPM_STRING_TYPE;
4888  nhe->p.ptr = t;
4889  nhe->c = 1;
4890  break;
4891  }
4892  break;
4893  case RPM_STRING_TYPE:
4894  nhe->c = 1;
4895  nhe->p.ptr = xstrdup(he->p.str);
4896  break;
4897  }
4898 
4899  if (!(av && av[0] && *av[0]))
4900  av = avdefault;
4901 
4902  for (i = 0; av[i] != NULL; i++) {
4903  uint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]);
4904 
4905  switch (keyval) {
4906  default:
4907  /*@switchbreak@*/ break;
4908  case UUID_KEYS_V1:
4909  case UUID_KEYS_V3:
4910  case UUID_KEYS_V4:
4911  case UUID_KEYS_V5:
4912  ix = str2uuid(nhe, NULL, keyval, val);
4913  goto exit; /* XXX exit after first found. */
4914  break;
4915  }
4916  }
4917 
4918 exit:
4919  nhe->p.ptr = _free(nhe->p.ptr);
4920  return val;
4921 }
4922 
4929 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av)
4930  /*@*/
4931 {
4932  int ac = argvCount(av) + 1;
4933  int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack)));
4934  char * end;
4935  char * val = NULL;
4936  int ix = 0;
4937  int i;
4938 
4939  switch(he->t) {
4940  default:
4941  val = xstrdup(_("(invalid type :rpn)"));
4942  goto exit;
4943  /*@notreached@*/ break;
4944  case RPM_UINT64_TYPE:
4945  stack[ix] = he->p.ui64p[0];
4946  break;
4947  case RPM_STRING_TYPE:
4948  end = NULL;
4949 /*@-unrecog@*/ /* Add annotated prototype. */
4950  stack[ix] = strtoll(he->p.str, &end, 0);
4951 /*@=unrecog@*/
4952  if (end && *end != '\0') {
4953  val = xstrdup(_("(invalid string :rpn)"));
4954  goto exit;
4955  }
4956  break;
4957  }
4958 
4959  if (av != NULL)
4960  for (i = 0; av[i] != NULL; i++) {
4961  const char * arg = av[i];
4962  size_t len = strlen(arg);
4963  int c = (int) *arg;
4964 
4965  if (len == 0) {
4966  /* do nothing */
4967  } else if (len > 1) {
4968  if (!(xisdigit(c) || (c == (int)'-' && xisdigit((int) arg[1])))) {
4969  val = xstrdup(_("(expected number :rpn)"));
4970  goto exit;
4971  }
4972  if (++ix == ac) {
4973  val = xstrdup(_("(stack overflow :rpn)"));
4974  goto exit;
4975  }
4976  end = NULL;
4977  stack[ix] = strtoll(arg, &end, 0);
4978  if (end && *end != '\0') {
4979  val = xstrdup(_("(invalid number :rpn)"));
4980  goto exit;
4981  }
4982  } else {
4983  if (ix-- < 1) {
4984  val = xstrdup(_("(stack underflow :rpn)"));
4985  goto exit;
4986  }
4987  switch (c) {
4988  case '&': stack[ix] &= stack[ix+1]; /*@switchbreak@*/ break;
4989  case '|': stack[ix] |= stack[ix+1]; /*@switchbreak@*/ break;
4990  case '^': stack[ix] ^= stack[ix+1]; /*@switchbreak@*/ break;
4991  case '+': stack[ix] += stack[ix+1]; /*@switchbreak@*/ break;
4992  case '-': stack[ix] -= stack[ix+1]; /*@switchbreak@*/ break;
4993  case '*': stack[ix] *= stack[ix+1]; /*@switchbreak@*/ break;
4994  case '%':
4995  case '/':
4996  if (stack[ix+1] == 0) {
4997  val = xstrdup(_("(divide by zero :rpn)"));
4998  goto exit;
4999  }
5000  if (c == (int)'%')
5001  stack[ix] %= stack[ix+1];
5002  else
5003  stack[ix] /= stack[ix+1];
5004  /*@switchbreak@*/ break;
5005  }
5006  }
5007  }
5008 
5009  { HE_t nhe = (HE_t) memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
5010  nhe->tag = he->tag;
5011  nhe->t = RPM_UINT64_TYPE;
5012  nhe->p.ui64p = (rpmuint64_t *)&stack[ix];
5013  nhe->c = 1;
5014  val = intFormat(nhe, NULL, NULL);
5015  }
5016 
5017 exit:
5018  return val;
5019 }
5020 
5027 static /*@only@*/ char * strsubFormat(HE_t he, /*@null@*/ const char ** av)
5028  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
5029  /*@modifies rpmGlobalMacroContext, internalState @*/
5030 {
5031  char * val = NULL;
5032  int ac = argvCount(av);
5033  miRE mires = NULL;
5034  int nmires = 0;
5035  int xx;
5036  int i;
5037 
5038  switch(he->t) {
5039  default:
5040  val = xstrdup(_("(invalid type :strsub)"));
5041  goto exit;
5042  /*@notreached@*/ break;
5043  case RPM_STRING_TYPE:
5044  if (ac < 2 || (ac % 2) != 0) {
5045  val = xstrdup(_("(invalid args :strsub)"));
5046  goto exit;
5047  }
5048  break;
5049  }
5050  if (av == NULL)
5051  goto noop;
5052 
5053  /* Create the mire pattern array. */
5054  for (i = 0; av[i] != NULL; i += 2)
5055  xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mires, &nmires);
5056 
5057  /* Find-and-replace first pattern that matches. */
5058  if (mires != NULL) {
5059  int noffsets = 3;
5060  int offsets[3];
5061  const char * s, * se;
5062  char * t, * te;
5063  char * nval;
5064  size_t slen;
5065  size_t nb;
5066 
5067  for (i = 0; i < nmires; i++) {
5068  miRE mire = mires + i;
5069 
5070  s = he->p.str;
5071  slen = strlen(s);
5072  if ((xx = mireRegexec(mire, s, slen)) < 0)
5073  continue;
5074  xx = mireSetEOptions(mire, offsets, noffsets);
5075 
5076  /* Replace the string(s). This is just s/find/replace/g */
5077  val = xstrdup("");
5078  while (*s != '\0') {
5079  nb = strlen(s);
5080  if ((se = strchr(s, '\n')) == NULL)
5081  se = s + nb;
5082  else
5083  se++;
5084 
5085  offsets[0] = offsets[1] = -1;
5086  xx = mireRegexec(mire, s, nb);
5087 
5088  nb = 1;
5089  /* On match, copy lead-in and match string. */
5090  if (xx == 0)
5091  nb += offsets[0] + strlen(av[2*i+1]);
5092  /* Copy up to EOL on nomatch or insertion. */
5093  if (xx != 0 || offsets[1] == offsets[0])
5094  nb += (se - (s + offsets[1]));
5095 
5096  te = t = xmalloc(nb);
5097 
5098  /* On match, copy lead-in and match string. */
5099  if (xx == 0) {
5100  te = stpcpy( stpncpy(te, s, offsets[0]), av[2*i+1]);
5101  s += offsets[1];
5102  }
5103  /* Copy up to EOL on nomatch or insertion. */
5104  if (xx != 0 || offsets[1] == offsets[0]) {
5105  s += offsets[1];
5106  te = stpncpy(te, s, (se - s));
5107  s = se;
5108  }
5109  *te = '\0';
5110 
5111  nval = rpmExpand(val, t, NULL);
5112  val = _free(val);
5113  val = nval;
5114  t = _free(t);
5115  }
5116  }
5117  mires = mireFreeAll(mires, nmires);
5118  }
5119 
5120 noop:
5121  if (val == NULL)
5122  val = xstrdup(he->p.str);
5123 exit:
5124  return val;
5125 }
5126 
5127 static struct headerSprintfExtension_s _headerCompoundFormats[] = {
5128  { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID",
5129  { .tagFunction = buildtime_uuidTag } },
5130  { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME",
5131  { .tagFunction = changelognameTag } },
5132  { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT",
5133  { .tagFunction = changelogtextTag } },
5134  { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",
5135  { .tagFunction = descriptionTag } },
5136  { HEADER_EXT_TAG, "RPMTAG_GROUP",
5137  { .tagFunction = groupTag } },
5138  { HEADER_EXT_TAG, "RPMTAG_HDRUUID",
5139  { .tagFunction = hdruuidTag } },
5140  { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",
5141  { .tagFunction = instprefixTag } },
5142  { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID",
5143  { .tagFunction = installtid_uuidTag } },
5144  { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID",
5145  { .tagFunction = installtime_uuidTag } },
5146  { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID",
5147  { .tagFunction = origintid_uuidTag } },
5148  { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID",
5149  { .tagFunction = origintime_uuidTag } },
5150  { HEADER_EXT_TAG, "RPMTAG_PKGUUID",
5151  { .tagFunction = pkguuidTag } },
5152  { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID",
5153  { .tagFunction = removetid_uuidTag } },
5154  { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID",
5155  { .tagFunction = sourcepkguuidTag } },
5156  { HEADER_EXT_TAG, "RPMTAG_SUMMARY",
5157  { .tagFunction = summaryTag } },
5158  { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",
5159  { .tagFunction = triggercondsTag } },
5160  { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",
5161  { .tagFunction = triggertypeTag } },
5162  { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE",
5163  { .tagFunction = dbinstanceTag } },
5164  { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF",
5165  { .tagFunction = headerstartoffTag } },
5166  { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF",
5167  { .tagFunction = headerendoffTag } },
5168  { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL",
5169  { .tagFunction = pkgbaseurlTag } },
5170  { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST",
5171  { .tagFunction = pkgdigestTag } },
5172  { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN",
5173  { .tagFunction = pkgoriginTag } },
5174  { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE",
5175  { .tagFunction = pkgsizeTag } },
5176  { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME",
5177  { .tagFunction = pkgmtimeTag } },
5178  { HEADER_EXT_TAG, "RPMTAG_NVRA",
5179  { .tagFunction = nvraTag } },
5180  { HEADER_EXT_TAG, "RPMTAG_FILENAMES",
5181  { .tagFunction = filenamesTag } },
5182  { HEADER_EXT_TAG, "RPMTAG_FILEPATHS",
5183  { .tagFunction = filepathsTag } },
5184  { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS",
5185  { .tagFunction = origpathsTag } },
5186  { HEADER_EXT_TAG, "RPMTAG_FILESTAT",
5187  { .tagFunction = filestatTag } },
5188  { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY",
5189  { .tagFunction = PxmlTag } },
5190  { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY",
5191  { .tagFunction = RxmlTag } },
5192  { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY",
5193  { .tagFunction = CxmlTag } },
5194  { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY",
5195  { .tagFunction = OxmlTag } },
5196  { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1",
5197  { .tagFunction = F1xmlTag } },
5198  { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2",
5199  { .tagFunction = F2xmlTag } },
5200  { HEADER_EXT_TAG, "RPMTAG_PROVIDEYAMLENTRY",
5201  { .tagFunction = PyamlTag } },
5202  { HEADER_EXT_TAG, "RPMTAG_REQUIREYAMLENTRY",
5203  { .tagFunction = RyamlTag } },
5204  { HEADER_EXT_TAG, "RPMTAG_CONFLICTYAMLENTRY",
5205  { .tagFunction = CyamlTag } },
5206  { HEADER_EXT_TAG, "RPMTAG_OBSOLETEYAMLENTRY",
5207  { .tagFunction = OyamlTag } },
5208  { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY1",
5209  { .tagFunction = F1yamlTag } },
5210  { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY2",
5211  { .tagFunction = F2yamlTag } },
5212  { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY",
5213  { .tagFunction = PsqlTag } },
5214  { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY",
5215  { .tagFunction = RsqlTag } },
5216  { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY",
5217  { .tagFunction = CsqlTag } },
5218  { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY",
5219  { .tagFunction = OsqlTag } },
5220  { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1",
5221  { .tagFunction = F1sqlTag } },
5222  { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2",
5223  { .tagFunction = F2sqlTag } },
5224  { HEADER_EXT_TAG, "RPMTAG_DEBCONFLICTS",
5225  { .tagFunction = debconflictsTag } },
5226  { HEADER_EXT_TAG, "RPMTAG_DEBDEPENDS",
5227  { .tagFunction = debdependsTag } },
5228  { HEADER_EXT_TAG, "RPMTAG_DEBMD5SUMS",
5229  { .tagFunction = debmd5sumsTag } },
5230  { HEADER_EXT_TAG, "RPMTAG_DEBOBSOLETES",
5231  { .tagFunction = debobsoletesTag } },
5232  { HEADER_EXT_TAG, "RPMTAG_DEBPROVIDES",
5233  { .tagFunction = debprovidesTag } },
5234  { HEADER_EXT_TAG, "RPMTAG_NEEDSWHAT",
5235  { .tagFunction = needswhatTag } },
5236  { HEADER_EXT_TAG, "RPMTAG_WHATNEEDS",
5237  { .tagFunction = whatneedsTag } },
5238  { HEADER_EXT_FORMAT, "armor",
5239  { .fmtFunction = armorFormat } },
5240  { HEADER_EXT_FORMAT, "base64",
5241  { .fmtFunction = base64Format } },
5242  { HEADER_EXT_FORMAT, "bncdata",
5243  { .fmtFunction = bncdataFormat } },
5244  { HEADER_EXT_FORMAT, "cdata",
5245  { .fmtFunction = cdataFormat } },
5246  { HEADER_EXT_FORMAT, "depflags",
5247  { .fmtFunction = depflagsFormat } },
5248  { HEADER_EXT_FORMAT, "deptype",
5249  { .fmtFunction = deptypeFormat } },
5250  { HEADER_EXT_FORMAT, "digest",
5251  { .fmtFunction = digestFormat } },
5252  { HEADER_EXT_FORMAT, "fflags",
5253  { .fmtFunction = fflagsFormat } },
5254  { HEADER_EXT_FORMAT, "hint",
5255  { .fmtFunction = hintFormat } },
5256  { HEADER_EXT_FORMAT, "iconv",
5257  { .fmtFunction = iconvFormat } },
5258  { HEADER_EXT_FORMAT, "json",
5259  { .fmtFunction = jsonFormat } },
5260 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */
5261  { HEADER_EXT_FORMAT, "jsonescape",
5262  { .fmtFunction = jsonescapeFormat } },
5263 #endif
5264  { HEADER_EXT_FORMAT, "perms",
5265  { .fmtFunction = permsFormat } },
5266  { HEADER_EXT_FORMAT, "permissions",
5267  { .fmtFunction = permsFormat } },
5268  { HEADER_EXT_FORMAT, "pgpsig",
5269  { .fmtFunction = pgpsigFormat } },
5270  { HEADER_EXT_FORMAT, "rpn",
5271  { .fmtFunction = rpnFormat } },
5272  { HEADER_EXT_FORMAT, "sqlescape",
5273  { .fmtFunction = sqlescapeFormat } },
5274  { HEADER_EXT_FORMAT, "stat",
5275  { .fmtFunction = statFormat } },
5276  { HEADER_EXT_FORMAT, "strsub",
5277  { .fmtFunction = strsubFormat } },
5278  { HEADER_EXT_FORMAT, "triggertype",
5279  { .fmtFunction = triggertypeFormat } },
5280  { HEADER_EXT_FORMAT, "utf8",
5281  { .fmtFunction = iconvFormat } },
5282  { HEADER_EXT_FORMAT, "uuid",
5283  { .fmtFunction = uuidFormat } },
5284  { HEADER_EXT_FORMAT, "xml",
5285  { .fmtFunction = xmlFormat } },
5286  { HEADER_EXT_FORMAT, "yaml",
5287  { .fmtFunction = yamlFormat } },
5288  { HEADER_EXT_MORE, NULL, { (void *) &headerDefaultFormats } }
5289 } ;
5290 
5291 headerSprintfExtension headerCompoundFormats = &_headerCompoundFormats[0];
5292 
5293 /*====================================================================*/
5294 
5296 {
5297  const struct headerTagTableEntry_s * t;
5300  int extNum;
5301 
5302  if (fp == NULL)
5303  fp = stdout;
5304  if (_rpmTagTable == NULL)
5305  _rpmTagTable = rpmTagTable;
5306 
5307  /* XXX this should use rpmHeaderFormats, but there are linkage problems. */
5308  if (_rpmHeaderFormats == NULL)
5309  _rpmHeaderFormats = headerCompoundFormats;
5310 
5311  for (t = _rpmTagTable; t && t->name; t++) {
5312  /*@observer@*/
5313  static const char * tagtypes[] = {
5314  "", "char", "uint8", "uint16", "uint32", "uint64",
5315  "string", "octets", "argv", "i18nstring",
5316  };
5317  rpmuint32_t ttype;
5318 
5319  if (rpmIsVerbose()) {
5320  fprintf(fp, "%-20s %6d", t->name + 7, t->val);
5321  ttype = t->type & RPM_MASK_TYPE;
5322  if (ttype < RPM_MIN_TYPE || ttype > RPM_MAX_TYPE)
5323  continue;
5324  if (t->type & RPM_OPENPGP_RETURN_TYPE)
5325  fprintf(fp, " openpgp");
5326  if (t->type & RPM_X509_RETURN_TYPE)
5327  fprintf(fp, " x509");
5328  if (t->type & RPM_ASN1_RETURN_TYPE)
5329  fprintf(fp, " asn1");
5330  if (t->type & RPM_OPAQUE_RETURN_TYPE)
5331  fprintf(fp, " opaque");
5332  fprintf(fp, " %s", tagtypes[ttype]);
5333  if (t->type & RPM_ARRAY_RETURN_TYPE)
5334  fprintf(fp, " array");
5335  if (t->type & RPM_MAPPING_RETURN_TYPE)
5336  fprintf(fp, " mapping");
5337  if (t->type & RPM_PROBE_RETURN_TYPE)
5338  fprintf(fp, " probe");
5339  if (t->type & RPM_TREE_RETURN_TYPE)
5340  fprintf(fp, " tree");
5341  } else
5342  fprintf(fp, "%s", t->name + 7);
5343  fprintf(fp, "\n");
5344  }
5345 
5346  exts = _rpmHeaderFormats;
5347  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
5348  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
5349  {
5350  if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
5351  continue;
5352 
5353  /* XXX don't print header tags twice. */
5354  if (tagValue(ext->name) > 0)
5355  continue;
5356  fprintf(fp, "%s\n", ext->name + 7);
5357  }
5358 }
5359 
5360 /*====================================================================*/
5361 
5362 #define PARSER_BEGIN 0
5363 #define PARSER_IN_ARRAY 1
5364 #define PARSER_IN_EXPR 2
5365 
5368 typedef /*@abstract@*/ struct sprintfTag_s * sprintfTag;
5369 
5374 /*@null@*/
5375  headerTagFormatFunction * fmtfuncs;
5376 /*@null@*/
5377  headerTagTagFunction ext;
5378  int extNum;
5379 /*@only@*/ /*@relnull@*/
5381  int justOne;
5383 /*@kept@*/
5384  char * format;
5385 /*@only@*/ /*@relnull@*/
5387 /*@only@*/ /*@relnull@*/
5389  unsigned pad;
5390 };
5391 
5394 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken;
5395 
5398 typedef enum {
5404 } sprintfToken_e;
5405 
5410  union {
5412  struct {
5413  /*@only@*/
5414  sprintfToken format;
5415  size_t numTokens;
5416  } array;
5417  struct {
5418  /*@dependent@*/
5419  char * string;
5420  size_t len;
5421  } string;
5422  struct {
5423  /*@only@*/ /*@null@*/
5424  sprintfToken ifFormat;
5425  size_t numIfTokens;
5426  /*@only@*/ /*@null@*/
5427  sprintfToken elseFormat;
5429  struct sprintfTag_s tag;
5430  } cond;
5431  } u;
5432 };
5433 
5436 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs;
5437 
5442  char * fmt;
5443 /*@observer@*/ /*@temp@*/
5445 /*@observer@*/ /*@temp@*/
5447 /*@observer@*/ /*@null@*/
5448  const char * errmsg;
5450  int nec;
5451  sprintfToken format;
5452 /*@relnull@*/
5454 /*@owned@*/
5455  char * val;
5456  size_t vallen;
5457  size_t alloced;
5458  size_t numTokens;
5459  size_t i;
5460 };
5461 
5462 /*@access sprintfTag @*/
5463 /*@access sprintfToken @*/
5464 /*@access headerSprintfArgs @*/
5465 
5468 static char escapedChar(const char ch)
5469  /*@*/
5470 {
5471 /*@-modfilesys@*/
5472 if (_hdrqf_debug)
5473 fprintf(stderr, "\t\t\\%c\n", ch);
5474 /*@=modfilesys@*/
5475  switch (ch) {
5476  case 'a': return '\a';
5477  case 'b': return '\b';
5478  case 'f': return '\f';
5479  case 'n': return '\n';
5480  case 'r': return '\r';
5481  case 't': return '\t';
5482  case 'v': return '\v';
5483  default: return ch;
5484  }
5485 }
5486 
5491 /*@relnull@*/
5492 static HE_t rpmheClean(/*@returned@*/ /*@null@*/ HE_t he)
5493  /*@modifies he @*/
5494 {
5495  if (he) {
5496  if (he->freeData && he->p.ptr != NULL)
5497  he->p.ptr = _free(he->p.ptr);
5498  memset(he, 0, sizeof(*he));
5499  }
5500  return he;
5501 }
5502 
5509 static /*@null@*/ sprintfToken
5510 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, size_t num)
5511  /*@modifies *format @*/
5512 {
5513  unsigned i;
5514 
5515  if (format == NULL) return NULL;
5516 
5517  for (i = 0; i < (unsigned) num; i++) {
5518  switch (format[i].type) {
5519  case PTOK_TAG:
5520  (void) rpmheClean(&format[i].u.tag.he);
5521  format[i].u.tag.tagno = _free(format[i].u.tag.tagno);
5522  format[i].u.tag.av = argvFree(format[i].u.tag.av);
5523  format[i].u.tag.params = argvFree(format[i].u.tag.params);
5524 /*@-type@*/
5525  format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs);
5526 /*@=type@*/
5527  /*@switchbreak@*/ break;
5528  case PTOK_ARRAY:
5529  format[i].u.array.format =
5530  freeFormat(format[i].u.array.format,
5531  format[i].u.array.numTokens);
5532  /*@switchbreak@*/ break;
5533  case PTOK_COND:
5534  format[i].u.cond.ifFormat =
5535  freeFormat(format[i].u.cond.ifFormat,
5536  format[i].u.cond.numIfTokens);
5537  format[i].u.cond.elseFormat =
5538  freeFormat(format[i].u.cond.elseFormat,
5539  format[i].u.cond.numElseTokens);
5540  (void) rpmheClean(&format[i].u.cond.tag.he);
5541  format[i].u.cond.tag.tagno = _free(format[i].u.cond.tag.tagno);
5542  format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av);
5543  format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params);
5544 /*@-type@*/
5545  format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs);
5546 /*@=type@*/
5547  /*@switchbreak@*/ break;
5548  case PTOK_NONE:
5549  case PTOK_STRING:
5550  default:
5551  /*@switchbreak@*/ break;
5552  }
5553  }
5554  format = _free(format);
5555  return NULL;
5556 }
5557 
5563 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
5564  /*@globals fileSystem @*/
5565  /*@modifies hsa, fileSystem @*/
5566 {
5567  sprintfTag tag =
5568  (hsa->format->type == PTOK_TAG
5569  ? &hsa->format->u.tag :
5570  (hsa->format->type == PTOK_ARRAY
5571  ? &hsa->format->u.array.format->u.tag :
5572  NULL));
5573 
5574  if (hsa != NULL) {
5575  hsa->i = 0;
5576  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2)
5577  hsa->hi = headerInit(hsa->h);
5578  }
5579 /*@-nullret@*/
5580  return hsa;
5581 /*@=nullret@*/
5582 }
5583 
5589 /*@null@*/
5590 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
5591  /*@globals internalState @*/
5592  /*@modifies hsa, internalState @*/
5593 {
5594  sprintfToken fmt = NULL;
5595  sprintfTag tag =
5596  (hsa->format->type == PTOK_TAG
5597  ? &hsa->format->u.tag :
5598  (hsa->format->type == PTOK_ARRAY
5599  ? &hsa->format->u.array.format->u.tag :
5600  NULL));
5601 
5602  if (hsa != NULL && hsa->i < hsa->numTokens) {
5603  fmt = hsa->format + hsa->i;
5604  if (hsa->hi == NULL) {
5605  hsa->i++;
5606  } else {
5607  HE_t he = rpmheClean(&tag->he);
5608  if (!headerNext(hsa->hi, he, 0))
5609  {
5610  tag->tagno[0] = 0;
5611  return NULL;
5612  }
5613  he->avail = 1;
5614  tag->tagno[0] = he->tag;
5615  }
5616  }
5617 
5618 /*@-dependenttrans -onlytrans@*/
5619  return fmt;
5620 /*@=dependenttrans =onlytrans@*/
5621 }
5622 
5628 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
5629  /*@globals fileSystem @*/
5630  /*@modifies hsa, fileSystem @*/
5631 {
5632  if (hsa != NULL) {
5633  hsa->hi = headerFini(hsa->hi);
5634  hsa->i = 0;
5635  }
5636 /*@-nullret@*/
5637  return hsa;
5638 /*@=nullret@*/
5639 }
5640 
5647 /*@dependent@*/ /*@exposed@*/
5648 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
5649  /*@modifies hsa */
5650 {
5651  if ((hsa->vallen + need) >= hsa->alloced) {
5652  if (hsa->alloced <= need)
5653  hsa->alloced += need;
5654  hsa->alloced <<= 1;
5655  hsa->val = xrealloc(hsa->val, hsa->alloced+1);
5656  }
5657  return hsa->val + hsa->vallen;
5658 }
5659 
5667 /*@observer@*/ /*@null@*/
5668 static const char * myTagName(headerTagTableEntry tbl, rpmuint32_t val,
5669  /*@null@*/ rpmuint32_t *typep)
5670  /*@modifies *typep @*/
5671 {
5672  static char name[128]; /* XXX Ick. */
5673  const char * s;
5674  char *t;
5675 
5676  /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
5677  if (tbl == NULL || tbl == rpmTagTable) {
5678  s = tagName(val);
5679  if (s != NULL && typep != NULL)
5680  *typep = tagType(val);
5681  return s;
5682  }
5683 
5684  for (; tbl->name != NULL; tbl++) {
5685  if (tbl->val == val)
5686  break;
5687  }
5688  if ((s = tbl->name) == NULL)
5689  return NULL;
5690  s += sizeof("RPMTAG_") - 1;
5691  t = name;
5692  *t++ = *s++;
5693  while (*s != '\0')
5694  *t++ = (char)xtolower((int)*s++);
5695  *t = '\0';
5696  if (typep)
5697  *typep = tbl->type;
5698  return name;
5699 }
5700 
5708  /*@*/
5709 {
5710  rpmuint32_t val = 0;
5711 
5712  /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
5713  if (tbl == NULL || tbl == rpmTagTable)
5714  val = tagValue(name);
5715  else
5716  for (; tbl->name != NULL; tbl++) {
5717  if (xstrcasecmp(tbl->name, name))
5718  continue;
5719  val = tbl->val;
5720  break;
5721  }
5722  return val;
5723 }
5724 
5732 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
5733  /*@modifies token @*/
5734 {
5735  headerSprintfExtension exts = hsa->exts;
5737  sprintfTag stag = (token->type == PTOK_COND
5738  ? &token->u.cond.tag : &token->u.tag);
5739  int extNum;
5740  rpmTag tagno = (rpmTag)-1;
5741 
5742  stag->fmtfuncs = NULL;
5743  stag->ext = NULL;
5744  stag->extNum = 0;
5745 
5746  if (!strcmp(name, "*")) {
5747  tagno = (rpmTag)-2;
5748  goto bingo;
5749  }
5750 
5751  if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
5752  char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
5753  (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
5754  name = t;
5755  }
5756 
5757  /* Search extensions for specific tag override. */
5758  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
5759  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
5760  {
5761  if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
5762  continue;
5763  if (!xstrcasecmp(ext->name, name)) {
5764  stag->ext = ext->u.tagFunction;
5765  stag->extNum = extNum;
5766  tagno = tagValue(name);
5767  goto bingo;
5768  }
5769  }
5770 
5771  /* Search tag names. */
5772  tagno = myTagValue(hsa->tags, name);
5773  if (tagno != 0)
5774  goto bingo;
5775 
5776  return 1;
5777 
5778 bingo:
5779  stag->tagno = xcalloc(1, sizeof(*stag->tagno));
5780  stag->tagno[0] = tagno;
5781  /* Search extensions for specific format(s). */
5782  if (stag->av != NULL) {
5783  int i;
5784 /*@-type@*/
5785  stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs));
5786 /*@=type@*/
5787  for (i = 0; stag->av[i] != NULL; i++) {
5788  for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
5789  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1))
5790  {
5791  if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
5792  /*@innercontinue@*/ continue;
5793  if (strcmp(ext->name, stag->av[i]+1))
5794  /*@innercontinue@*/ continue;
5795  stag->fmtfuncs[i] = ext->u.fmtFunction;
5796  /*@innerbreak@*/ break;
5797  }
5798  }
5799  }
5800  return 0;
5801 }
5802 
5803 /* forward ref */
5812 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
5813  char * str, /*@out@*/char ** endPtr)
5814  /*@modifies hsa, str, token, *endPtr @*/
5815  /*@requires maxSet(endPtr) >= 0 @*/;
5816 
5827 static int parseFormat(headerSprintfArgs hsa, char * str,
5828  /*@out@*/ sprintfToken * formatPtr,
5829  /*@out@*/ size_t * numTokensPtr,
5830  /*@null@*/ /*@out@*/ char ** endPtr, int state)
5831  /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
5832  /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
5833  /\ maxSet(endPtr) >= 0 @*/
5834 {
5835 /*@observer@*/
5836 static const char *pstates[] = {
5837 "NORMAL", "ARRAY", "EXPR", "WTF?"
5838 };
5839  char * chptr, * start, * next, * dst;
5840  sprintfToken format;
5841  sprintfToken token;
5842  size_t numTokens;
5843  unsigned i;
5844  int done = 0;
5845  int xx;
5846 
5847 /*@-modfilesys@*/
5848 if (_hdrqf_debug)
5849 fprintf(stderr, "--> parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]);
5850 /*@=modfilesys@*/
5851 
5852  /* upper limit on number of individual formats */
5853  numTokens = 0;
5854  if (str != NULL)
5855  for (chptr = str; *chptr != '\0'; chptr++)
5856  if (*chptr == '%' || *chptr == '[') numTokens++;
5857  numTokens = numTokens * 2 + 1;
5858 
5859  format = xcalloc(numTokens, sizeof(*format));
5860  if (endPtr) *endPtr = NULL;
5861 
5862 /*@-infloops@*/ /* LCL: can't detect (start, *start) termination */
5863  dst = start = str;
5864  numTokens = 0;
5865  token = NULL;
5866  if (start != NULL)
5867  while (*start != '\0') {
5868  switch (*start) {
5869  case '%':
5870  /* handle %% */
5871  if (*(start + 1) == '%') {
5872  if (token == NULL || token->type != PTOK_STRING) {
5873  token = format + numTokens++;
5874  token->type = PTOK_STRING;
5875 /*@-temptrans -assignexpose@*/
5876  dst = token->u.string.string = start;
5877 /*@=temptrans =assignexpose@*/
5878  }
5879  start++;
5880  *dst++ = *start++;
5881  /*@switchbreak@*/ break;
5882  }
5883 
5884  token = format + numTokens++;
5885  *dst++ = '\0';
5886  start++;
5887 
5888  if (*start == '|') {
5889  char * newEnd;
5890 
5891  start++;
5892  if (parseExpression(hsa, token, start, &newEnd))
5893  {
5894  format = freeFormat(format, numTokens);
5895  return 1;
5896  }
5897  start = newEnd;
5898  /*@switchbreak@*/ break;
5899  }
5900 
5901 /*@-assignexpose@*/
5902  token->u.tag.format = start;
5903 /*@=assignexpose@*/
5904  token->u.tag.pad = 0;
5905  token->u.tag.justOne = 0;
5906  token->u.tag.arrayCount = 0;
5907 
5908  chptr = start;
5909  while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
5910  if (!*chptr || *chptr == '%') {
5911  hsa->errmsg = _("missing { after %");
5912  format = freeFormat(format, numTokens);
5913  return 1;
5914  }
5915 
5916 /*@-modfilesys@*/
5917 if (_hdrqf_debug)
5918 fprintf(stderr, "\tchptr *%p = NUL\n", chptr);
5919 /*@=modfilesys@*/
5920  *chptr++ = '\0';
5921 
5922  while (start < chptr) {
5923  if (xisdigit((int)*start)) {
5924  i = strtoul(start, &start, 10);
5925  token->u.tag.pad += i;
5926  start = chptr;
5927  /*@innerbreak@*/ break;
5928  } else {
5929  start++;
5930  }
5931  }
5932 
5933  if (*start == '=') {
5934  token->u.tag.justOne = 1;
5935  start++;
5936  } else if (*start == '#') {
5937  token->u.tag.justOne = 1;
5938  token->u.tag.arrayCount = 1;
5939  start++;
5940  }
5941 
5942  next = start;
5943  while (*next && *next != '}') next++;
5944  if (!*next) {
5945  hsa->errmsg = _("missing } after %{");
5946  format = freeFormat(format, numTokens);
5947  return 1;
5948  }
5949 /*@-modfilesys@*/
5950 if (_hdrqf_debug)
5951 fprintf(stderr, "\tnext *%p = NUL\n", next);
5952 /*@=modfilesys@*/
5953  *next++ = '\0';
5954 
5955 #define isSEP(_c) ((_c) == ':' || (_c) == '|')
5956  chptr = start;
5957  while (!(*chptr == '\0' || isSEP(*chptr))) chptr++;
5958  /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */
5959  while (isSEP(*chptr)) {
5960  if (chptr[1] == '\0' || isSEP(chptr[1])) {
5961  hsa->errmsg = _("empty tag format");
5962  format = freeFormat(format, numTokens);
5963  return 1;
5964  }
5965  /* Parse the formatter parameter list. */
5966  { char * te = chptr + 1;
5967  char * t = strchr(te, '(');
5968  char c;
5969 
5970  while (!(*te == '\0' || isSEP(*te))) {
5971 #ifdef NOTYET /* XXX some means of escaping is needed */
5972  if (te[0] == '\\' && te[1] != '\0') te++;
5973 #endif
5974  te++;
5975  }
5976  c = *te; *te = '\0';
5977  /* Parse (a,b,c) parameter list. */
5978  if (t != NULL) {
5979  *t++ = '\0';
5980  if (te <= t || te[-1] != ')') {
5981  hsa->errmsg = _("malformed parameter list");
5982  format = freeFormat(format, numTokens);
5983  return 1;
5984  }
5985  te[-1] = '\0';
5986  xx = argvAdd(&token->u.tag.params, t);
5987  } else
5988  xx = argvAdd(&token->u.tag.params, "");
5989 /*@-modfilesys@*/
5990 if (_hdrqf_debug)
5991 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : ""));
5992 /*@=modfilesys@*/
5993  xx = argvAdd(&token->u.tag.av, chptr);
5994  *te = c;
5995  *chptr = '\0';
5996  chptr = te;
5997  }
5998  }
5999 #undef isSEP
6000 
6001  if (*start == '\0') {
6002  hsa->errmsg = _("empty tag name");
6003  format = freeFormat(format, numTokens);
6004  return 1;
6005  }
6006 
6007  i = 0;
6008  token->type = PTOK_TAG;
6009 
6010  if (findTag(hsa, token, start)) {
6011  hsa->errmsg = _("unknown tag");
6012  format = freeFormat(format, numTokens);
6013  return 1;
6014  }
6015 
6016  dst = start = next;
6017 /*@-modfilesys@*/
6018 if (_hdrqf_debug)
6019 fprintf(stderr, "\tdst = start = next %p\n", dst);
6020 /*@=modfilesys@*/
6021  /*@switchbreak@*/ break;
6022 
6023  case '[':
6024 /*@-modfilesys@*/
6025 if (_hdrqf_debug)
6026 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start);
6027 /*@=modfilesys@*/
6028  *start++ = '\0';
6029  token = format + numTokens++;
6030 
6031  if (parseFormat(hsa, start,
6032  &token->u.array.format,
6033  &token->u.array.numTokens,
6034  &start, PARSER_IN_ARRAY))
6035  {
6036  format = freeFormat(format, numTokens);
6037  return 1;
6038  }
6039 
6040  if (!start) {
6041  hsa->errmsg = _("] expected at end of array");
6042  format = freeFormat(format, numTokens);
6043  return 1;
6044  }
6045 
6046  dst = start;
6047 /*@-modfilesys@*/
6048 if (_hdrqf_debug)
6049 fprintf(stderr, "\tdst = start %p\n", dst);
6050 /*@=modfilesys@*/
6051 
6052  token->type = PTOK_ARRAY;
6053 
6054  /*@switchbreak@*/ break;
6055 
6056  case ']':
6057  if (state != PARSER_IN_ARRAY) {
6058  hsa->errmsg = _("unexpected ]");
6059  format = freeFormat(format, numTokens);
6060  return 1;
6061  }
6062  *start++ = '\0';
6063 /*@-modfilesys@*/
6064 if (_hdrqf_debug)
6065 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
6066 /*@=modfilesys@*/
6067  if (endPtr) *endPtr = start;
6068  done = 1;
6069  /*@switchbreak@*/ break;
6070 
6071  case '}':
6072  if (state != PARSER_IN_EXPR) {
6073  hsa->errmsg = _("unexpected }");
6074  format = freeFormat(format, numTokens);
6075  return 1;
6076  }
6077  *start++ = '\0';
6078 /*@-modfilesys@*/
6079 if (_hdrqf_debug)
6080 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
6081 /*@=modfilesys@*/
6082  if (endPtr) *endPtr = start;
6083  done = 1;
6084  /*@switchbreak@*/ break;
6085 
6086  default:
6087  if (token == NULL || token->type != PTOK_STRING) {
6088  token = format + numTokens++;
6089  token->type = PTOK_STRING;
6090 /*@-temptrans -assignexpose@*/
6091  dst = token->u.string.string = start;
6092 /*@=temptrans =assignexpose@*/
6093  }
6094 
6095 /*@-modfilesys@*/
6096 if (_hdrqf_debug)
6097 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start);
6098 /*@=modfilesys@*/
6099  if (start[0] == '\\' && start[1] != '\0') {
6100  start++;
6101  *dst++ = escapedChar(*start);
6102  *start++ = '\0';
6103  } else {
6104  *dst++ = *start++;
6105  }
6106  /*@switchbreak@*/ break;
6107  }
6108  if (dst < start) *dst = '\0';
6109  if (done)
6110  break;
6111  }
6112 /*@=infloops@*/
6113 
6114  if (dst != NULL)
6115  *dst = '\0';
6116 
6117  for (i = 0; i < (unsigned) numTokens; i++) {
6118  token = format + i;
6119  switch(token->type) {
6120  default:
6121  /*@switchbreak@*/ break;
6122  case PTOK_STRING:
6123  token->u.string.len = strlen(token->u.string.string);
6124  /*@switchbreak@*/ break;
6125  }
6126  }
6127 
6128  if (numTokensPtr != NULL)
6129  *numTokensPtr = numTokens;
6130  if (formatPtr != NULL)
6131  *formatPtr = format;
6132 
6133  return 0;
6134 }
6135 
6136 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
6137  char * str, /*@out@*/ char ** endPtr)
6138 {
6139  char * chptr;
6140  char * end;
6141 
6142 /*@-modfilesys@*/
6143 if (_hdrqf_debug)
6144 fprintf(stderr, "--> parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr);
6145 /*@=modfilesys@*/
6146 
6147  hsa->errmsg = NULL;
6148  chptr = str;
6149  while (*chptr && *chptr != '?') chptr++;
6150 
6151  if (*chptr != '?') {
6152  hsa->errmsg = _("? expected in expression");
6153  return 1;
6154  }
6155 
6156  *chptr++ = '\0';
6157 
6158  if (*chptr != '{') {
6159  hsa->errmsg = _("{ expected after ? in expression");
6160  return 1;
6161  }
6162 
6163  chptr++;
6164 
6165  if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
6166  &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
6167  return 1;
6168 
6169  /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
6170  if (!(end && *end)) {
6171  hsa->errmsg = _("} expected in expression");
6172  token->u.cond.ifFormat =
6173  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6174  return 1;
6175  }
6176 
6177  chptr = end;
6178  if (*chptr != ':' && *chptr != '|') {
6179  hsa->errmsg = _(": expected following ? subexpression");
6180  token->u.cond.ifFormat =
6181  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6182  return 1;
6183  }
6184 
6185  if (*chptr == '|') {
6186  if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
6187  &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
6188  {
6189  token->u.cond.ifFormat =
6190  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6191  return 1;
6192  }
6193  } else {
6194  chptr++;
6195 
6196  if (*chptr != '{') {
6197  hsa->errmsg = _("{ expected after : in expression");
6198  token->u.cond.ifFormat =
6199  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6200  return 1;
6201  }
6202 
6203  chptr++;
6204 
6205  if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
6206  &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
6207  return 1;
6208 
6209  /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
6210  if (!(end && *end)) {
6211  hsa->errmsg = _("} expected in expression");
6212  token->u.cond.ifFormat =
6213  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6214  return 1;
6215  }
6216 
6217  chptr = end;
6218  if (*chptr != '|') {
6219  hsa->errmsg = _("| expected at end of expression");
6220  token->u.cond.ifFormat =
6221  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6222  token->u.cond.elseFormat =
6223  freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
6224  return 1;
6225  }
6226  }
6227 
6228  chptr++;
6229 
6230  *endPtr = chptr;
6231 
6232  token->type = PTOK_COND;
6233 
6234  (void) findTag(hsa, token, str);
6235 
6236  return 0;
6237 }
6238 
6247 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
6248  HE_t he, HE_t ec)
6249  /*@modifies he, ec @*/
6250 {
6251  int rc = 0;
6252  if (!ec->avail) {
6253  he = rpmheClean(he);
6254  rc = fn(hsa->h, he);
6255  *ec = *he; /* structure copy. */
6256  if (!rc)
6257  ec->avail = 1;
6258  } else
6259  *he = *ec; /* structure copy. */
6260  he->freeData = 0;
6261  rc = (rc == 0); /* XXX invert getExtension return. */
6262  return rc;
6263 }
6264 
6272 /*@observer@*/ /*@null@*/
6273 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag,
6274  size_t element)
6275  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
6276  /*@modifies hsa, tag, rpmGlobalMacroContext, internalState @*/
6277 {
6278  HE_t vhe = (HE_t) memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
6279  HE_t he = &tag->he;
6280  char * val = NULL;
6281  size_t need = 0;
6282  char * t, * te;
6283  rpmuint64_t ival = 0;
6284  rpmTagCount countBuf;
6285  int xx;
6286 
6287  if (!he->avail) {
6288  if (tag->ext)
6289  xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
6290  else {
6291  he->tag = tag->tagno[0]; /* XXX necessary? */
6292  xx = headerGet(hsa->h, he, 0);
6293  }
6294  if (!xx) {
6295  (void) rpmheClean(he);
6296  he->t = RPM_STRING_TYPE;
6297  he->p.str = xstrdup("(none)");
6298  he->c = 1;
6299  he->freeData = 1;
6300  }
6301  he->avail = 1;
6302  }
6303 
6304  if (tag->arrayCount) {
6305  countBuf = he->c;
6306  he = rpmheClean(he);
6307  he->t = RPM_UINT32_TYPE;
6308  he->p.ui32p = &countBuf;
6309  he->c = 1;
6310  he->freeData = 0;
6311  }
6312 
6313  vhe->tag = he->tag;
6314 
6315  if (he->p.ptr)
6316  switch (he->t) {
6317  default:
6318  val = xstrdup("(unknown type)");
6319  need = strlen(val) + 1;
6320  goto exit;
6321  /*@notreached@*/ break;
6322 #if defined(SUPPORT_I18NSTRING_TYPE)
6323  case RPM_I18NSTRING_TYPE:
6324 #endif
6325  case RPM_STRING_ARRAY_TYPE:
6326  vhe->t = RPM_STRING_TYPE;
6327  vhe->p.str = he->p.argv[element];
6328  vhe->c = he->c;
6329  vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1);
6330  break;
6331 #if !defined(SUPPORT_I18NSTRING_TYPE)
6332  case RPM_I18NSTRING_TYPE:
6333 assert(0);
6334 #endif
6335  case RPM_STRING_TYPE:
6336  vhe->p.str = he->p.str;
6337  vhe->t = RPM_STRING_TYPE;
6338  vhe->c = 0;
6339  vhe->ix = -1;
6340  break;
6341  case RPM_UINT8_TYPE:
6342  case RPM_UINT16_TYPE:
6343  case RPM_UINT32_TYPE:
6344  case RPM_UINT64_TYPE:
6345  switch (he->t) {
6346  default:
6347 assert(0); /* XXX keep gcc quiet. */
6348  /*@innerbreak@*/ break;
6349  case RPM_UINT8_TYPE:
6350  ival = (rpmuint64_t)he->p.ui8p[element];
6351  /*@innerbreak@*/ break;
6352  case RPM_UINT16_TYPE:
6353  ival = (rpmuint64_t)he->p.ui16p[element];
6354  /*@innerbreak@*/ break;
6355  case RPM_UINT32_TYPE:
6356  ival = (rpmuint64_t)he->p.ui32p[element];
6357  /*@innerbreak@*/ break;
6358  case RPM_UINT64_TYPE:
6359  ival = he->p.ui64p[element];
6360  /*@innerbreak@*/ break;
6361  }
6362  vhe->t = RPM_UINT64_TYPE;
6363  vhe->p.ui64p = &ival;
6364  vhe->c = he->c;
6365  vhe->ix = (he->c > 1 ? 0 : -1);
6367  vhe->ix = 0;
6368  break;
6369 
6370  case RPM_BIN_TYPE:
6371  vhe->t = RPM_BIN_TYPE;
6372  vhe->p.ptr = he->p.ptr;
6373  vhe->c = he->c;
6374  vhe->ix = -1;
6375  break;
6376  }
6377 
6378 /*@-compmempass@*/ /* vhe->p.ui64p is stack, not owned */
6379  if (tag->fmtfuncs) {
6380  char * nval = NULL;
6381  int i;
6382  for (i = 0; tag->av[i] != NULL; i++) {
6383  headerTagFormatFunction fmt;
6384  ARGV_t av;
6385  if ((fmt = tag->fmtfuncs[i]) == NULL)
6386  continue;
6387  /* If !1st formatter, and transformer, not extractor, save val. */
6388  if (val != NULL && *tag->av[i] == '|') {
6389  int ix = vhe->ix;
6390  vhe = rpmheClean(vhe);
6391  vhe->tag = he->tag;
6392  vhe->t = RPM_STRING_TYPE;
6393  vhe->p.str = xstrdup(val);
6394  vhe->c = he->c;
6395  vhe->ix = ix;
6396  vhe->freeData = 1;
6397  }
6398  av = NULL;
6399  if (tag->params && tag->params[i] && *tag->params[i] != '\0')
6400  xx = argvSplit(&av, tag->params[i], ",");
6401 
6402  nval = fmt(vhe, av);
6403 
6404 /*@-castfcnptr -modfilesys@*/
6405 if (_hdrqf_debug)
6406 fprintf(stderr, "\t%s(%s) %p(%p,%p) |%s|\n", tag->av[i], (tag->params ? tag->params[i] : NULL), (void *)fmt, (void *)vhe, (void *)(av ? av : NULL), (nval ? nval : "(null)"));
6407 /*@=castfcnptr =modfilesys@*/
6408 
6409  /* Accumulate (by appending) next formatter's return string. */
6410  if (val == NULL)
6411  val = xstrdup((nval ? nval : ""));
6412  else {
6413  char * oval = val;
6414  /* XXX using ... | ... as separator is feeble. */
6415  val = rpmExpand(val, (*val != '\0' ? " | " : ""), nval, NULL);
6416  oval = _free(oval);
6417  }
6418  nval = _free(nval);
6419  av = argvFree(av);
6420  }
6421  }
6422 
6423  if (val == NULL)
6424  val = intFormat(vhe, NULL, NULL);
6425 /*@=compmempass@*/
6426 assert(val != NULL);
6427  if (val)
6428  need = strlen(val) + 1;
6429 
6430 exit:
6431  if (val && need > 0) {
6432  if (tag->format && *tag->format && tag->pad > 0) {
6433  size_t nb;
6434  nb = strlen(tag->format) + sizeof("%s");
6435  t = alloca(nb);
6436  (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s");
6437  nb = tag->pad + strlen(val) + 1;
6438  te = xmalloc(nb);
6439 /*@-formatconst@*/
6440  (void) snprintf(te, nb, t, val);
6441 /*@=formatconst@*/
6442  te[nb-1] = '\0';
6443  val = _free(val);
6444  val = te;
6445  need += tag->pad;
6446  }
6447  t = hsaReserve(hsa, need);
6448  te = stpcpy(t, val);
6449  hsa->vallen += (te - t);
6450  val = _free(val);
6451  }
6452 
6453  return (hsa->val + hsa->vallen);
6454 }
6455 
6463 /*@observer@*/ /*@null@*/
6464 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
6465  size_t element)
6466  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
6467  /*@modifies hsa, token, rpmGlobalMacroContext, internalState @*/
6468 {
6469  char * t, * te;
6470  size_t i, j;
6471  size_t numElements;
6472  sprintfToken spft;
6473  sprintfTag tag = NULL;
6474  HE_t he = NULL;
6475  size_t condNumFormats;
6476  size_t need;
6477  int xx;
6478 
6479  /* we assume the token and header have been validated already! */
6480 
6481  switch (token->type) {
6482  case PTOK_NONE:
6483  break;
6484 
6485  case PTOK_STRING:
6486  need = token->u.string.len;
6487  if (need == 0) break;
6488  t = hsaReserve(hsa, need);
6489  te = stpcpy(t, token->u.string.string);
6490  hsa->vallen += (te - t);
6491  break;
6492 
6493  case PTOK_TAG:
6494  t = hsa->val + hsa->vallen;
6495 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6496  te = formatValue(hsa, &token->u.tag,
6497  (token->u.tag.justOne ? 0 : element));
6498 /*@=modobserver@*/
6499  if (te == NULL)
6500  return NULL;
6501  break;
6502 
6503  case PTOK_COND:
6504  if (token->u.cond.tag.ext
6505  || headerIsEntry(hsa->h, token->u.cond.tag.tagno[0]))
6506  {
6507  spft = token->u.cond.ifFormat;
6508  condNumFormats = token->u.cond.numIfTokens;
6509  } else {
6510  spft = token->u.cond.elseFormat;
6511  condNumFormats = token->u.cond.numElseTokens;
6512  }
6513 
6514  need = condNumFormats * 20;
6515  if (spft == NULL || need == 0) break;
6516 
6517  t = hsaReserve(hsa, need);
6518  for (i = 0; i < condNumFormats; i++, spft++) {
6519 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6520  te = singleSprintf(hsa, spft, element);
6521 /*@=modobserver@*/
6522  if (te == NULL)
6523  return NULL;
6524  }
6525  break;
6526 
6527  case PTOK_ARRAY:
6528  numElements = 0;
6529  spft = token->u.array.format;
6530  for (i = 0; i < token->u.array.numTokens; i++, spft++)
6531  {
6532  tag = &spft->u.tag;
6533  if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne)
6534  continue;
6535  he = &tag->he;
6536  if (!he->avail) {
6537  he->tag = tag->tagno[0];
6538  if (tag->ext)
6539  xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
6540  else
6541  xx = headerGet(hsa->h, he, 0);
6542  if (!xx) {
6543  (void) rpmheClean(he);
6544  continue;
6545  }
6546  he->avail = 1;
6547  }
6548 
6549  /* Check iteration arrays are same dimension (or scalar). */
6550  switch (he->t) {
6551  default:
6552  if (numElements == 0) {
6553  numElements = he->c;
6554  /*@switchbreak@*/ break;
6555  }
6556  if ((size_t)he->c == numElements)
6557  /*@switchbreak@*/ break;
6558  hsa->errmsg =
6559  _("array iterator used with different sized arrays");
6560  he = rpmheClean(he);
6561  return NULL;
6562  /*@notreached@*/ /*@switchbreak@*/ break;
6563  case RPM_BIN_TYPE:
6564  case RPM_STRING_TYPE:
6565  if (numElements == 0)
6566  numElements = 1;
6567  /*@switchbreak@*/ break;
6568  }
6569  }
6570  spft = token->u.array.format;
6571 
6572  if (numElements == 0) {
6573 #ifdef DYING /* XXX lots of pugly "(none)" lines with --conflicts. */
6574  need = sizeof("(none)\n") - 1;
6575  t = hsaReserve(hsa, need);
6576  te = stpcpy(t, "(none)\n");
6577  hsa->vallen += (te - t);
6578 #endif
6579  } else {
6580  rpmTagReturnType tagT = 0;
6581  const char * tagN = NULL;
6582  spew_t spew = NULL;
6583 
6584  need = numElements * token->u.array.numTokens;
6585  if (need == 0) break;
6586 
6587  tag = &spft->u.tag;
6588 
6589 spew = NULL;
6590  /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
6591  if (spft->type == PTOK_TAG && tag->av != NULL
6592  && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"))
6593  spew = &_xml_spew;
6594  if (spft->type == PTOK_TAG && tag->av != NULL
6595  && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"))
6596  spew = &_yaml_spew;
6597  if (spft->type == PTOK_TAG && tag->av != NULL
6598  && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json"))
6599  spew = &_json_spew;
6600 
6601  if (spew == &_xml_spew) {
6602 assert(tag->tagno != NULL);
6603  /* XXX display "Tag_0x01234567" for arbitrary tags. */
6604  if (tag->tagno[0] & 0x40000000) {
6605  tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6606  } else
6607  tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6608  need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN);
6609  te = t = hsaReserve(hsa, need);
6610  te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n");
6611  hsa->vallen += (te - t);
6612  }
6613  if (spew == &_yaml_spew) {
6614 assert(tag->tagno != NULL);
6615  /* XXX display "Tag_0x01234567" for arbitrary tags. */
6616  if (tag->tagno[0] & 0x40000000) {
6617  tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6618  tagT = numElements > 1
6620  } else
6621  tagN = myTagName(hsa->tags, tag->tagno[0], &tagT);
6622  need = sizeof(" : - ") + strlen(tagN);
6623  te = t = hsaReserve(hsa, need);
6624  *te++ = ' ';
6625  *te++ = ' ';
6626  te = stpcpy(te, tagN);
6627  *te++ = ':';
6628  *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
6629  ? '\n' : ' ');
6630  *te = '\0';
6631  hsa->vallen += (te - t);
6632  }
6633  if (spew == &_json_spew) {
6634 assert(tag->tagno != NULL);
6635  /* XXX display "Tag_0x01234567" for arbitrary tags. */
6636  if (tag->tagno[0] & 0x40000000) {
6637  tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6638  tagT = numElements > 1
6640  } else
6641  if (tag->tagno[0] == RPMTAG_HDRID) { /* RPMTAG_SHA1HEADER */
6642  tagN = "_id"; /* XXX mongo primary key name */
6643  } else
6644  tagN = myTagName(hsa->tags, tag->tagno[0], &tagT);
6645  need = sizeof(" : [ ") + strlen(tagN);
6646  te = t = hsaReserve(hsa, need);
6647  te = stpcpy( stpcpy( stpcpy(te, " "), tagN), ": ");
6649  te = stpcpy(te, "[ ");
6650  hsa->vallen += (te - t);
6651  }
6652 
6653  need = numElements * token->u.array.numTokens * 10;
6654  t = hsaReserve(hsa, need);
6655  for (j = 0; j < numElements; j++) {
6656  spft = token->u.array.format;
6657  for (i = 0; i < token->u.array.numTokens; i++, spft++) {
6658 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6659  te = singleSprintf(hsa, spft, j);
6660 /*@=modobserver@*/
6661  if (te == NULL)
6662  return NULL;
6663  }
6664  }
6665 
6666  if (spew == &_xml_spew) {
6667  need = sizeof(" </rpmTag>\n") - 1;
6668  te = t = hsaReserve(hsa, need);
6669  te = stpcpy(te, " </rpmTag>\n");
6670  hsa->vallen += (te - t);
6671  }
6672  if (spew == &_json_spew) {
6673  if ((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) {
6674  need = sizeof(" ],\n") - 1;
6675  te = t = hsaReserve(hsa, need);
6676  te = stpcpy(te, " ],\n");
6677  hsa->vallen += (te - t);
6678  } else {
6679  need = sizeof("\n") - 1;
6680  te = t = hsaReserve(hsa, need);
6681  te = stpcpy(te, "\n");
6682  hsa->vallen += (te - t);
6683  }
6684  }
6685 
6686  }
6687  break;
6688  }
6689 
6690  return (hsa->val + hsa->vallen);
6691 }
6692 
6699 static /*@only@*/ HE_t
6700 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp)
6701  /*@modifies *necp @*/
6702 {
6704  HE_t ec;
6705  int extNum = 0;
6706 
6707  if (exts != NULL)
6708  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
6709  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
6710  {
6711  ;
6712  }
6713  if (necp)
6714  *necp = extNum;
6715  ec = (HE_t) xcalloc(extNum+1, sizeof(*ec)); /* XXX +1 unnecessary */
6716  return ec;
6717 }
6718 
6725 static /*@null@*/ HE_t
6726 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec)
6727  /*@modifies ec @*/
6728 {
6730  int extNum;
6731 
6732  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
6733  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
6734  {
6735  (void) rpmheClean(&ec[extNum]);
6736  }
6737 
6738  ec = _free(ec);
6739  return NULL;
6740 }
6741 
6742 char * headerSprintf(Header h, const char * fmt,
6743  headerTagTableEntry tags,
6745  errmsg_t * errmsg)
6746 {
6747  headerSprintfArgs hsa = (headerSprintfArgs) memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
6748  sprintfToken nextfmt;
6749  sprintfTag tag;
6750  char * t, * te;
6751  size_t need;
6752 spew_t spew = NULL;
6753 
6754 /*@-modfilesys@*/
6755 if (_hdrqf_debug)
6756 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg);
6757 /*@=modfilesys@*/
6758 
6759  /* Set some reasonable defaults */
6760  if (tags == NULL)
6761  tags = rpmTagTable;
6762  /* XXX this loses the extensions in lib/formats.c. */
6763  if (exts == NULL)
6764  exts = headerCompoundFormats;
6765 
6766 /*@-assignexpose -castexpose @*/
6767  hsa->h = headerLink(h);
6768 /*@=assignexpose =castexpose @*/
6769  hsa->fmt = xstrdup(fmt);
6770 /*@-assignexpose -dependenttrans@*/
6771  hsa->exts = exts;
6772  hsa->tags = tags;
6773 /*@=assignexpose =dependenttrans@*/
6774  hsa->errmsg = NULL;
6775 
6776  if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
6777  goto exit;
6778 
6779  hsa->nec = 0;
6780  hsa->ec = rpmecNew(hsa->exts, &hsa->nec);
6781  hsa->val = xstrdup("");
6782 
6783  tag =
6784  (hsa->format->type == PTOK_TAG
6785  ? &hsa->format->u.tag :
6786  (hsa->format->type == PTOK_ARRAY
6787  ? &hsa->format->u.array.format->u.tag :
6788  NULL));
6789 
6790 spew = NULL;
6791  /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
6792  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2
6793  && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"))
6794  spew = &_xml_spew;
6795  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2
6796  && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"))
6797  spew = &_yaml_spew;
6798  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2
6799  && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json"))
6800  spew = &_json_spew;
6801 
6802  if (spew && spew->spew_init && spew->spew_init[0]) {
6803  char * spew_init = rpmExpand(spew->spew_init, NULL);
6804  need = strlen(spew_init);
6805  t = hsaReserve(hsa, need);
6806  te = stpcpy(t, spew_init);
6807  hsa->vallen += (te - t);
6808  spew_init = _free(spew_init);
6809  }
6810 
6811  hsa = hsaInit(hsa);
6812  while ((nextfmt = hsaNext(hsa)) != NULL) {
6813 /*@-globs -mods@*/ /* XXX rpmGlobalMacroContext @*/
6814  te = singleSprintf(hsa, nextfmt, 0);
6815 /*@=globs =mods @*/
6816  if (te == NULL) {
6817  hsa->val = _free(hsa->val);
6818  break;
6819  }
6820  }
6821  hsa = hsaFini(hsa);
6822 
6823  if (spew && spew->spew_fini && spew->spew_fini[0]) {
6824  char * spew_fini = rpmExpand(spew->spew_fini, NULL);
6825  need = strlen(spew_fini);
6826  t = hsaReserve(hsa, need);
6827  te = stpcpy(t, spew_fini);
6828  hsa->vallen += (te - t);
6829  spew_fini = _free(spew_fini);
6830  }
6831 
6832  if (hsa->val != NULL && hsa->vallen < hsa->alloced)
6833  hsa->val = (char *) xrealloc(hsa->val, hsa->vallen+1);
6834 
6835  hsa->ec = rpmecFree(hsa->exts, hsa->ec);
6836  hsa->nec = 0;
6837  hsa->format = freeFormat(hsa->format, hsa->numTokens);
6838 
6839 exit:
6840 /*@-dependenttrans -observertrans @*/
6841  if (errmsg)
6842  *errmsg = hsa->errmsg;
6843 /*@=dependenttrans =observertrans @*/
6844  (void)headerFree(hsa->h);
6845  hsa->h = NULL;
6846  hsa->fmt = _free(hsa->fmt);
6847 /*@-retexpose@*/
6848  return hsa->val;
6849 /*@=retexpose@*/
6850 }