rpm  5.4.15
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  te = xstrdup(t);
946  t = _free(t);
947  t = te;
948 
949 if (_iconv_errno)
950 fprintf(stderr, "warning: %s: from iconv(%s -> %s) for \"%s\" -> \"%s\"\n", strerror(_iconv_errno), fromcode, tocode, buffer, t);
951 
952  } else
953 #endif
954  t = xstrdup((s ? s : ""));
955 
956  return t;
957 }
958 
965 static /*@only@*/ char * cdataFormat(HE_t he, /*@null@*/ const char ** av)
966  /*@*/
967 {
968  int ix = (he->ix > 0 ? he->ix : 0);
969  char * val;
970 int lvl = 0;
971 spew_t spew = &_xml_spew;
972 
973 assert(ix == 0);
974  if (he->t != RPM_STRING_TYPE) {
975  val = xstrdup(_("(not a string)"));
976  } else {
977  const char * s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
978  size_t nb = spew->spew_strlen(s, lvl);
979  char * t = xmalloc(nb + 1);
980 
981  val = t;
982  t = spew->spew_strcpy(t, s, lvl); t += strlen(t);
983  *t = '\0';
984  s = _free(s);
985  }
986 
987  return val;
988 }
989 
996 static /*@only@*/ char * iconvFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
997  /*@*/
998 {
999  int ix = (he->ix > 0 ? he->ix : 0);
1000  char * val = NULL;
1001 
1002 assert(ix == 0);
1003  if (he->t == RPM_STRING_TYPE)
1004  val = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1005  if (val == NULL)
1006  val = xstrdup(_("(not a string)"));
1007 
1008  return val;
1009 }
1010 
1017 static /*@only@*/ char * xmlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1018  /*@*/
1019 {
1020  int ix = (he->ix > 0 ? he->ix : 0);
1021  const char * xtag = NULL;
1022  char * val;
1023  const char * s = NULL;
1024  uint64_t anint = 0;
1025 int lvl = 0;
1026 spew_t spew = &_xml_spew;
1027 
1028 assert(ix == 0);
1029 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
1030 
1031  switch (he->t) {
1032  case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
1033  /*@fallthrough@*/
1034  case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
1035 assert(0);
1036  /*@notreached@*/
1037  case RPM_STRING_TYPE:
1038  xtag = "string";
1039  s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1040  break;
1041  case RPM_BIN_TYPE:
1042 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */
1043  { int cpl = b64encode_chars_per_line;
1044  b64encode_chars_per_line = 0;
1045 /*@-formatconst@*/
1046  s = base64Format(he, NULL);
1047 /*@=formatconst@*/
1048  b64encode_chars_per_line = cpl;
1049  xtag = "base64";
1050  } break;
1051 /*@=globs =mods@*/
1052  case RPM_UINT8_TYPE:
1053  anint = (uint64_t)he->p.ui8p[ix];
1054  break;
1055  case RPM_UINT16_TYPE:
1056  anint = (uint64_t)he->p.ui16p[ix];
1057  break;
1058  case RPM_UINT32_TYPE:
1059  anint = (uint64_t)he->p.ui32p[ix];
1060  break;
1061  case RPM_UINT64_TYPE:
1062  anint = he->p.ui64p[ix];
1063  break;
1064  default:
1065  val = xstrdup(_("(invalid xml type)"));
1066  goto exit;
1067  /*@notreached@*/ break;
1068  }
1069 
1070  if (s == NULL) {
1071  static int tlen = 64;
1072  char * t = xmalloc(tlen+1);
1073  int xx;
1074 
1075  *t = '\0';
1076  if (anint != 0) /* XXX empty XML tag sets 0 as default? */
1077  xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
1078  s = t;
1079  xtag = "integer";
1080  }
1081 
1082  {
1083  size_t nb = spew->spew_strlen(s, lvl);
1084  char * t, * te;
1085 
1086  if (nb == 0) {
1087  nb += strlen(xtag) + sizeof("\t</>");
1088  t = te = alloca(nb);
1089  *te = '\0';
1090  te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
1091  } else {
1092  nb += 2 * strlen(xtag) + sizeof("\t<></>");
1093  t = te = alloca(nb);
1094  *te = '\0';
1095  te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
1096  te = spew->spew_strcpy(te, s, lvl);
1097  te += strlen(te);
1098  te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
1099  }
1100 
1101  val = xstrdup(t);
1102  }
1103 
1104  s = _free(s);
1105 
1106 exit:
1107  return val;
1108 }
1109 
1116 static /*@only@*/ char * yamlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1117  /*@*/
1118 {
1119  int element = he->ix;
1120  int ix = (he->ix > 0 ? he->ix : 0);
1121  const char * xtag = NULL;
1122  char * val;
1123  const char * s = NULL;
1124  uint64_t anint = 0;
1125  int xx = 0;
1126  int ls = 0;
1127  int c;
1128 int lvl = 0;
1129 spew_t spew = &_yaml_spew;
1130 
1131 assert(ix == 0);
1132 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
1133 
1134  switch (he->t) {
1135  case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
1136  /*@fallthrough@*/
1137  case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
1138 assert(0);
1139  /*@notreached@*/
1140  case RPM_STRING_TYPE:
1141  s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str);
1142  if (strchr("[", s[0])) /* leading [ */
1143  xx = 1;
1144  if (xx == 0)
1145  while ((c = (int) *s++) != (int) '\0') {
1146  switch (c) {
1147  default:
1148  continue;
1149  case '\n': /* multiline */
1150  xx = 1;
1151  if (s[0] == ' ' || s[0] == '\t') /* leading space */
1152  ls = 1;
1153  continue;
1154  case '-': /* leading "- \"" */
1155  case ':': /* embedded ": " or ":" at EOL */
1156  if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
1157  continue;
1158  xx = 1;
1159  /*@switchbreak@*/ break;
1160  }
1161  /*@loopbreak@*/ break;
1162  }
1163  if (xx) {
1164  if (ls) { /* leading spaces means we need to specify the indent */
1165  if (element >= 0) {
1166  lvl = 3;
1167  xtag = "- |3-\n";
1168  } else if (he->ix < 0) {
1169  lvl = 3; /* XXX extra indent for array[1] */
1170  xtag = "|3-\n";
1171  } else {
1172  lvl = 2;
1173  xtag = "|2-\n";
1174  }
1175  } else {
1176  if (element >= 0) {
1177  lvl = 3;
1178  xtag = "- |-\n";
1179  } else {
1180  lvl = 2;
1181  if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */
1182  xtag = "|-\n";
1183  }
1184  }
1185  } else {
1186  xtag = (element >= 0 ? "- " : NULL);
1187  }
1188 
1189  s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1190  break;
1191  case RPM_BIN_TYPE:
1192 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */
1193  { int cpl = b64encode_chars_per_line;
1194  b64encode_chars_per_line = 0;
1195 /*@-formatconst@*/
1196  s = base64Format(he, NULL);
1197  element = -element; /* XXX skip " " indent. */
1198 /*@=formatconst@*/
1199  b64encode_chars_per_line = cpl;
1200  xtag = "!!binary ";
1201  } break;
1202 /*@=globs =mods@*/
1203  case RPM_UINT8_TYPE:
1204  anint = (uint64_t)he->p.ui8p[ix];
1205  break;
1206  case RPM_UINT16_TYPE:
1207  anint = (uint64_t)he->p.ui16p[ix];
1208  break;
1209  case RPM_UINT32_TYPE:
1210  anint = (uint64_t)he->p.ui32p[ix];
1211  break;
1212  case RPM_UINT64_TYPE:
1213  anint = he->p.ui64p[ix];
1214  break;
1215  default:
1216  val = xstrdup(_("(invalid yaml type)"));
1217  goto exit;
1218  /*@notreached@*/ break;
1219  }
1220 
1221  if (s == NULL) {
1222  static int tlen = 64;
1223  char * t = xmalloc(tlen+1);
1224 /*@-duplicatequals@*/
1225  xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
1226 /*@=duplicatequals@*/
1227  s = t;
1228  xtag = (element >= 0 ? "- " : NULL);
1229  }
1230 
1231  {
1232  size_t nb = spew->spew_strlen(s, lvl);
1233  char * t, * te;
1234 
1235  if (nb == 0) {
1236  if (element >= 0)
1237  nb += sizeof(" ") - 1;
1238  nb += sizeof("- ~") - 1;
1239  nb++;
1240  t = te = alloca(nb);
1241  *te = '\0';
1242  if (element >= 0)
1243  te = stpcpy(te, " ");
1244  te = stpcpy(te, "- ~");
1245  } else {
1246  if (element >= 0)
1247  nb += sizeof(" ") - 1;
1248  if (xtag)
1249  nb += strlen(xtag);
1250  nb++;
1251  t = te = alloca(nb);
1252  *te = '\0';
1253  if (element >= 0)
1254  te = stpcpy(te, " ");
1255  if (xtag)
1256  te = stpcpy(te, xtag);
1257  te = spew->spew_strcpy(te, s, lvl);
1258  te += strlen(te);
1259  }
1260 
1261  val = xstrdup(t);
1262  }
1263 
1264  s = _free(s);
1265 
1266 exit:
1267  return val;
1268 }
1269 
1276 static /*@only@*/
1277 char * jsonFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1278  /*@*/
1279 {
1280  int element = he->ix;
1281  int ix = (he->ix > 0 ? he->ix : 0);
1282  char * val;
1283  const char * s = NULL;
1284  uint64_t anint = 0;
1285  int xx = 0;
1286  int c;
1287 int lvl = 0;
1288 spew_t spew = &_json_spew;
1289 
1290 assert(ix == 0);
1291 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
1292 
1293  switch (he->t) {
1294  case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
1295  /*@fallthrough@*/
1296  case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
1297 assert(0);
1298  /*@notreached@*/
1299  case RPM_STRING_TYPE:
1300  s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
1301  break;
1302  case RPM_BIN_TYPE:
1303  { int cpl = b64encode_chars_per_line;
1304  b64encode_chars_per_line = 0;
1305  s = base64Format(he, NULL);
1306  element = -element; /* XXX skip " " indent. */
1307  b64encode_chars_per_line = cpl;
1308  } break;
1309  case RPM_UINT8_TYPE:
1310  anint = (uint64_t)he->p.ui8p[ix];
1311  break;
1312  case RPM_UINT16_TYPE:
1313  anint = (uint64_t)he->p.ui16p[ix];
1314  break;
1315  case RPM_UINT32_TYPE:
1316  anint = (uint64_t)he->p.ui32p[ix];
1317  break;
1318  case RPM_UINT64_TYPE:
1319  anint = he->p.ui64p[ix];
1320  break;
1321  default:
1322  val = xstrdup(_("(invalid json type)"));
1323  goto exit;
1324  /*@notreached@*/ break;
1325  }
1326 
1327  if (s == NULL) {
1328  static int tlen = 64;
1329  char * t = xmalloc(tlen+1);
1330  xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
1331  s = t;
1332  c = '\0';
1333  } else
1334  c = '"';
1335 
1336  {
1337  size_t nb = spew->spew_strlen(s, lvl);
1338  char * t, * te;
1339 
1340  t = te = alloca(nb + sizeof("\"\","));
1341  *te = '\0';
1342  if (c != '\0') *te++ = c;
1343  if (nb) {
1344  te = spew->spew_strcpy(te, s, lvl);
1345  te += strlen(te);
1346  }
1347  if (c != '\0') *te++ = c;
1348  *te++ = ',';
1349  *te = '\0';
1350 
1351  val = xstrdup(t);
1352  }
1353 
1354  s = _free(s);
1355 
1356 exit:
1357  return val;
1358 }
1359 
1360 /*====================================================================*/
1361 
1368 static /*@only@*/ char * pgpsigFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1369  /*@globals fileSystem, internalState @*/
1370  /*@modifies fileSystem, internalState @*/
1371 {
1372  int ix = (he->ix > 0 ? he->ix : 0);
1373  char * val, * t;
1374 
1375 assert(ix == 0);
1376  if (!(he->t == RPM_BIN_TYPE)) {
1377  val = xstrdup(_("(not a blob)"));
1378  } else {
1379  rpmuint8_t * pkt = he->p.ui8p;
1380  unsigned int pktlen = 0;
1381  unsigned int v = (unsigned int) *pkt;
1382  pgpTag tag = 0;
1383  unsigned int plen;
1384  unsigned int hlen = 0;
1385 
1386  if (v & 0x80) {
1387  if (v & 0x40) {
1388  tag = (v & 0x3f);
1389  plen = pgpLen(pkt+1, &hlen);
1390  } else {
1391  tag = (v >> 2) & 0xf;
1392  plen = (1 << (v & 0x3));
1393  hlen = pgpGrab(pkt+1, plen);
1394  }
1395 
1396  pktlen = 1 + plen + hlen;
1397  }
1398 
1399  if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
1400  val = xstrdup(_("(not an OpenPGP signature)"));
1401  } else {
1402  pgpDig dig = pgpDigNew(RPMVSF_DEFAULT, 0);
1403  pgpDigParams sigp = pgpGetSignature(dig);
1404  size_t nb = 0;
1405  const char *tempstr;
1406 
1407  (void) pgpPrtPkts(pkt, pktlen, dig, 0);
1408 
1409  val = NULL;
1410  again:
1411  nb += 100;
1412  val = t = xrealloc(val, nb + 1);
1413 
1414  t = stpcpy(t, _pgpPubkeyAlgo2Name(sigp->pubkey_algo));
1415  if (t + 5 >= val + nb)
1416  goto again;
1417 
1418  *t++ = '/';
1419  t = stpcpy(t, _pgpHashAlgo2Name(sigp->hash_algo));
1420  if (t + strlen (", ") + 1 >= val + nb)
1421  goto again;
1422 
1423  t = stpcpy(t, ", ");
1424 
1425  /* this is important if sizeof(rpmuint32_t) ! sizeof(time_t) */
1426  { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
1427  struct tm * tstruct = localtime(&dateint);
1428  if (tstruct)
1429  (void) strftime(t, (nb - (t - val)), "%c", tstruct);
1430  }
1431  t += strlen(t);
1432  if (t + strlen (", Key ID ") + 1 >= val + nb)
1433  goto again;
1434  t = stpcpy(t, ", Key ID ");
1435  tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
1436  if (t + strlen (tempstr) > val + nb)
1437  goto again;
1438  t = stpcpy(t, tempstr);
1439 
1440  dig = pgpDigFree(dig);
1441  }
1442  }
1443 
1444  return val;
1445 }
1446 
1453 static /*@only@*/
1454 char * depflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1455  /*@*/
1456 {
1457  int ix = (he->ix > 0 ? he->ix : 0);
1458  char * val;
1459 
1460 assert(ix == 0);
1461  if (he->t != RPM_UINT64_TYPE) {
1462  val = xstrdup(_("(invalid type)"));
1463  } else {
1464  rpmuint64_t anint = he->p.ui64p[ix];
1465  char *t, *te;
1466 
1467  t = te = alloca(32);
1468  *te = '\0';
1469 
1470 #ifdef NOTYET /* XXX appending markers breaks :depflags format. */
1471  if (anint & RPMSENSE_SCRIPT_PRE)
1472  te = stpcpy(te, "(pre)");
1473  else if (anint & RPMSENSE_SCRIPT_POST)
1474  te = stpcpy(te, "(post)");
1475  else if (anint & RPMSENSE_SCRIPT_PREUN)
1476  te = stpcpy(te, "(preun)");
1477  else if (anint & RPMSENSE_SCRIPT_POSTUN)
1478  te = stpcpy(te, "(postun)");
1479 #endif
1480  if (anint & RPMSENSE_SENSEMASK)
1481  *te++ = ' ';
1482  if (anint & RPMSENSE_LESS)
1483  *te++ = '<';
1484  if (anint & RPMSENSE_GREATER)
1485  *te++ = '>';
1486  if (anint & RPMSENSE_EQUAL)
1487  *te++ = '=';
1488  if (anint & RPMSENSE_SENSEMASK)
1489  *te++ = ' ';
1490  *te = '\0';
1491 
1492  val = xstrdup(t);
1493  }
1494 
1495  return val;
1496 }
1497 
1505 static /*@only@*/
1506 char * deptypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1507  /*@*/
1508 {
1509  int ix = (he->ix > 0 ? he->ix : 0);
1510  char * val;
1511 
1512 assert(ix == 0);
1513  if (he->t != RPM_UINT64_TYPE) {
1514  val = xstrdup(_("(invalid type)"));
1515  } else {
1516  rpmuint64_t anint = he->p.ui64p[ix];
1517  char *t, *te;
1518 
1519  t = te = alloca(32);
1520  *te = '\0';
1521 
1522  if (anint & RPMSENSE_SCRIPT_PRE)
1523  te = stpcpy(te, "pre");
1524  else if (anint & RPMSENSE_SCRIPT_POST)
1525  te = stpcpy(te, "post");
1526  else if (anint & RPMSENSE_SCRIPT_PREUN)
1527  te = stpcpy(te, "preun");
1528  else if (anint & RPMSENSE_SCRIPT_POSTUN)
1529  te = stpcpy(te, "postun");
1530  else if (anint & RPMSENSE_SCRIPT_VERIFY)
1531  te = stpcpy(te, "verify");
1532  else if (anint & RPMSENSE_RPMLIB)
1533  te = stpcpy(te, "rpmlib");
1534  else if (anint & RPMSENSE_INTERP)
1535  te = stpcpy(te, "interp");
1536  else if (anint & (RPMSENSE_FIND_PROVIDES | RPMSENSE_FIND_REQUIRES))
1537  te = stpcpy(te, "auto");
1538  else
1539  te = stpcpy(te, "manual");
1540  *te = '\0';
1541 
1542  val = xstrdup(t);
1543  }
1544 
1545  return val;
1546 }
1547 
1548 #ifdef NOTYET
1549 static const char * bfstring(unsigned int x, const char * xbf)
1550 {
1551  const char * s = xbf;
1552  static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1553  static char buf[BUFSIZ];
1554  char * t, * te;
1555  unsigned radix;
1556  unsigned c, i, k;
1557 
1558  radix = (s != NULL ? *s++ : 16);
1559 
1560  if (radix <= 1 || radix >= 32)
1561  radix = 16;
1562 
1563  t = buf;
1564  switch (radix) {
1565  case 8: *t++ = '0'; break;
1566  case 16: *t++ = '0'; *t++ = 'x'; break;
1567  }
1568 
1569  i = 0;
1570  k = x;
1571  do { i++; k /= radix; } while (k);
1572 
1573  te = t + i;
1574 
1575  k = x;
1576  do { --i; t[i] = digits[k % radix]; k /= radix; } while (k);
1577 
1578  t = te;
1579  i = '<';
1580  if (s != NULL)
1581  while ((c = *s++) != '\0') {
1582  if (c > ' ') continue;
1583 
1584  k = (1 << (c - 1));
1585  if (!(x & k)) continue;
1586 
1587  if (t == te) *t++ = '=';
1588 
1589  *t++ = i;
1590  i = ',';
1591  while (*s > ' ')
1592  *t++ = *s++;
1593  }
1594  if (t > te) *t++ = '>';
1595  *t = '\0';
1596  return buf;
1597 }
1598 #endif
1599 
1606 static /*@only@*/
1607 char * hintFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1608  /*@*/
1609 {
1610  int ix = (he->ix > 0 ? he->ix : 0);
1611  char * val;
1612 
1613 assert(ix == 0);
1614  if (he->t != RPM_UINT64_TYPE) {
1615  val = xstrdup(_("(invalid type)"));
1616  } else {
1617  rpmuint64_t anint = he->p.ui64p[ix];
1618  char *t, *buf;
1619 
1620  t = buf = alloca(32);
1621  *t = '\0';
1622 
1623  if (anint & RPMSENSE_MISSINGOK)
1624  t = stpcpy(t, "(hint)");
1625  *t = '\0';
1626 
1627  val = xstrdup(buf);
1628  }
1629 
1630  return val;
1631 }
1638 static int instprefixTag(Header h, HE_t he)
1639  /*@globals internalState @*/
1640  /*@modifies he, internalState @*/
1641 {
1642  he->tag = RPMTAG_INSTALLPREFIX;
1643  if (headerGet(h, he, 0))
1644  return 0;
1645 
1646  he->tag = RPMTAG_INSTPREFIXES;
1647  if (headerGet(h, he, 0)) {
1648  rpmTagData array = { .argv = he->p.argv };
1649  he->t = RPM_STRING_TYPE;
1650  he->c = 1;
1651  he->p.str = xstrdup(array.argv[0]);
1652  he->freeData = 1;
1653  array.ptr = _free(array.ptr);
1654  return 0;
1655  }
1656  return 1;
1657 }
1658 
1666 static int tv2uuidv1(/*@unused@*/ Header h, HE_t he, struct timeval *tv)
1667  /*@modifies he @*/
1668 {
1669  rpmuint64_t uuid_time = ((rpmuint64_t)tv->tv_sec * 10000000) +
1670  (tv->tv_usec * 10) + 0x01B21DD213814000ULL;
1671 
1672  he->t = RPM_BIN_TYPE;
1673  he->c = 128/8;
1674  he->p.ptr = xcalloc(1, he->c);
1675  he->freeData = 1;
1676  if (rpmuuidMake(1, NULL, NULL, NULL, (unsigned char *)he->p.ui8p)) {
1677  he->p.ptr = _free(he->p.ptr);
1678  he->freeData = 0;
1679  return 1;
1680  }
1681 
1682  he->p.ui8p[6] &= 0xf0; /* preserve version, clear time_hi nibble */
1683  he->p.ui8p[8] &= 0xc0; /* preserve variant, clear clock */
1684  he->p.ui8p[9] &= 0x00;
1685 
1686  he->p.ui8p[3] = (rpmuint8_t)(uuid_time >> 0);
1687  he->p.ui8p[2] = (rpmuint8_t)(uuid_time >> 8);
1688  he->p.ui8p[1] = (rpmuint8_t)(uuid_time >> 16);
1689  he->p.ui8p[0] = (rpmuint8_t)(uuid_time >> 24);
1690  he->p.ui8p[5] = (rpmuint8_t)(uuid_time >> 32);
1691  he->p.ui8p[4] = (rpmuint8_t)(uuid_time >> 40);
1692  he->p.ui8p[6] |= (rpmuint8_t)(uuid_time >> 56) & 0x0f;
1693 
1694 #ifdef NOTYET
1695  /* XXX Jigger up a non-zero (but constant) clock value. Is this needed? */
1696  he->p.ui8p[8] |= (he->p.ui8p[2] & 0x3f);
1697  he->p.ui8p[9] |= he->p.ui8p[3]
1698 #endif
1699 
1700  return 0;
1701 }
1702 
1709 static int tag2uuidv1(Header h, HE_t he)
1710  /*@globals internalState @*/
1711  /*@modifies he, internalState @*/
1712 {
1713  struct timeval tv;
1714 
1715  if (!headerGet(h, he, 0))
1716  return 1;
1717  tv.tv_sec = (long) he->p.ui32p[0];
1718  tv.tv_usec = (long) (he->c > 1 ? he->p.ui32p[1] : 0);
1719  he->p.ptr = _free(he->p.ptr);
1720  return tv2uuidv1(h, he, &tv);
1721 }
1722 
1730  /*@globals internalState @*/
1731  /*@modifies he, internalState @*/
1732 {
1733  he->tag = RPMTAG_INSTALLTIME;
1734  return tag2uuidv1(h, he);
1735 }
1736 
1743 static int buildtime_uuidTag(Header h, HE_t he)
1744  /*@globals internalState @*/
1745  /*@modifies he, internalState @*/
1746 {
1747  he->tag = RPMTAG_BUILDTIME;
1748  return tag2uuidv1(h, he);
1749 }
1750 
1757 static int origintime_uuidTag(Header h, HE_t he)
1758  /*@globals internalState @*/
1759  /*@modifies he, internalState @*/
1760 {
1761  he->tag = RPMTAG_ORIGINTIME;
1762  return tag2uuidv1(h, he);
1763 }
1764 
1771 static int installtid_uuidTag(Header h, HE_t he)
1772  /*@globals internalState @*/
1773  /*@modifies he, internalState @*/
1774 {
1775  he->tag = RPMTAG_INSTALLTID;
1776  return tag2uuidv1(h, he);
1777 }
1778 
1785 static int removetid_uuidTag(Header h, HE_t he)
1786  /*@globals internalState @*/
1787  /*@modifies he, internalState @*/
1788 {
1789  he->tag = RPMTAG_REMOVETID;
1790  return tag2uuidv1(h, he);
1791 }
1792 
1799 static int origintid_uuidTag(Header h, HE_t he)
1800  /*@globals internalState @*/
1801  /*@modifies he, internalState @*/
1802 {
1803  he->tag = RPMTAG_ORIGINTID;
1804  return tag2uuidv1(h, he);
1805 }
1806 
1807 /*@unchecked@*/ /*@observer@*/
1808 static const char uuid_ns[] = "ns:URL";
1809 /*@unchecked@*/ /*@observer@*/
1810 static const char uuid_auth[] = "%{?_uuid_auth}%{!?_uuid_auth:http://rpm5.org}";
1811 /*@unchecked@*/ /*@observer@*/
1812 static const char uuid_path[] = "%{?_uuid_path}%{!?_uuid_path:/package}";
1813 /*@unchecked@*/
1815 
1824 static int str2uuid(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
1825  rpmuint32_t version, char * val)
1826  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1827  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1828 {
1829  const char * ns = NULL;
1830  const char * tagn = tagName(he->tag);
1831  const char * s = NULL;
1832 char * t = (val ? val : alloca(40));
1833  int rc;
1834 
1835  /* XXX Substitute Pkgid & Hdrid strings for aliases. */
1836  if (!strcmp("Sigmd5", tagn))
1837  tagn = "Pkgid";
1838  else if (!strcmp("Sha1header", tagn))
1839  tagn = "Hdrid";
1840 
1841  switch (version) {
1842  default:
1843  version = uuid_version;
1844  /*@fallthrough@*/
1845  case 3:
1846  case 5:
1847 assert(he->t == RPM_STRING_TYPE);
1848  ns = uuid_ns;
1849  s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/",
1850  he->p.str, NULL);
1851  /*@fallthrough@*/
1852  case 4:
1853  break;
1854  }
1855  he->p.ptr = _free(he->p.ptr);
1856  he->t = RPM_BIN_TYPE;
1857  he->c = 128/8;
1858  he->p.ptr = xcalloc(1, he->c);
1859  he->freeData = 1;
1860  rc = rpmuuidMake((int)version, ns, s, t, (unsigned char *)he->p.ui8p);
1861  if (rc) {
1862  he->p.ptr = _free(he->p.ptr);
1863  he->freeData = 0;
1864  }
1865  s = _free(s);
1866 
1867  return rc;
1868 }
1869 
1876 static int tag2uuidv5(Header h, HE_t he)
1877  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1878  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1879 {
1880  if (!headerGet(h, he, 0))
1881  return 1;
1882  switch (he->t) {
1883  default:
1884 assert(0);
1885  /*@notreached@*/ break;
1886  case RPM_BIN_TYPE: { /* Convert RPMTAG_PKGID from binary => hex. */
1887  static const char hex[] = "0123456789abcdef";
1888  char * t;
1889  char * te;
1890  rpmuint32_t i;
1891 
1892  t = te = xmalloc (2*he->c + 1);
1893  for (i = 0; i < he->c; i++) {
1894  *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ];
1895  *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ];
1896  }
1897  *te = '\0';
1898  he->p.ptr = _free(he->p.ptr);
1899  he->t = RPM_STRING_TYPE;
1900  he->p.ptr = t;
1901  he->c = 1;
1902  he->freeData = 1;
1903  } break;
1904  case RPM_STRING_TYPE:
1905  break;
1906  }
1907  return str2uuid(he, NULL, 0, NULL);
1908 }
1909 
1916 static int pkguuidTag(Header h, HE_t he)
1917  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1918  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1919 {
1920  he->tag = RPMTAG_PKGID;
1921  return tag2uuidv5(h, he);
1922 }
1923 
1930 static int sourcepkguuidTag(Header h, HE_t he)
1931  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1932  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1933 {
1934  he->tag = RPMTAG_SOURCEPKGID;
1935  return tag2uuidv5(h, he);
1936 }
1937 
1944 static int hdruuidTag(Header h, HE_t he)
1945  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1946  /*@modifies he, rpmGlobalMacroContext, internalState @*/
1947 {
1948  he->tag = RPMTAG_HDRID;
1949  return tag2uuidv5(h, he);
1950 }
1951 
1958 static int triggercondsTag(Header h, HE_t he)
1959  /*@globals internalState @*/
1960  /*@modifies he, internalState @*/
1961 {
1962  HE_t _he = (HE_t) memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
1963  HE_t Fhe = (HE_t) memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
1964  HE_t Ihe = (HE_t) memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
1965  HE_t Nhe = (HE_t) memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
1966  HE_t Vhe = (HE_t) memset(alloca(sizeof(*Vhe)), 0, sizeof(*Vhe));
1967  HE_t She = (HE_t) memset(alloca(sizeof(*She)), 0, sizeof(*She));
1968  rpmuint64_t anint;
1969  unsigned i, j;
1970  int rc = 1; /* assume failure */
1971  int xx;
1972 
1973  he->freeData = 0;
1974 
1975  Nhe->tag = RPMTAG_TRIGGERNAME;
1976  xx = headerGet(h, Nhe, 0);
1977  if (!xx) { /* no triggers, succeed anyways */
1978  rc = 0;
1979  goto exit;
1980  }
1981 
1982  Ihe->tag = RPMTAG_TRIGGERINDEX;
1983  xx = headerGet(h, Ihe, 0);
1984  if (!xx) goto exit;
1985 
1986  Fhe->tag = RPMTAG_TRIGGERFLAGS;
1987  xx = headerGet(h, Fhe, 0);
1988  if (!xx) goto exit;
1989 
1990  Vhe->tag = RPMTAG_TRIGGERVERSION;
1991  xx = headerGet(h, Vhe, 0);
1992  if (!xx) goto exit;
1993 
1994  She->tag = RPMTAG_TRIGGERSCRIPTS;
1995  xx = headerGet(h, She, 0);
1996  if (!xx) goto exit;
1997 
1998  _he->tag = he->tag;
1999  _he->t = RPM_UINT64_TYPE;
2000  _he->p.ui64p = &anint;
2001  _he->c = 1;
2002  _he->freeData = 0;
2003 
2004  he->t = RPM_STRING_ARRAY_TYPE;
2005  he->c = She->c;
2006 
2007  he->freeData = 1;
2008  he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
2009  for (i = 0; i < (unsigned) he->c; i++) {
2010  char * item, * flagsStr;
2011  char * chptr;
2012 
2013  chptr = xstrdup("");
2014 
2015  for (j = 0; j < Nhe->c; j++) {
2016  if (Ihe->p.ui32p[j] != i)
2017  /*@innercontinue@*/ continue;
2018 
2019  item = xmalloc(strlen(Nhe->p.argv[j]) + strlen(Vhe->p.argv[j]) + 20);
2020 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
2021  if (Fhe->p.ui32p[j] & RPMSENSE_SENSEMASK) {
2022  anint = Fhe->p.ui32p[j];
2023  flagsStr = depflagsFormat(_he, NULL);
2024  sprintf(item, "%s%s%s", Nhe->p.argv[j], flagsStr, Vhe->p.argv[j]);
2025  flagsStr = _free(flagsStr);
2026  } else
2027  strcpy(item, Nhe->p.argv[j]);
2028 /*@=compmempass@*/
2029 
2030  chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
2031  if (*chptr != '\0') strcat(chptr, ", ");
2032  strcat(chptr, item);
2033  item = _free(item);
2034  }
2035 
2036  he->p.argv[i] = chptr;
2037  }
2038  rc = 0;
2039 
2040 exit:
2041  Ihe->p.ptr = _free(Ihe->p.ptr);
2042  Fhe->p.ptr = _free(Fhe->p.ptr);
2043  Nhe->p.ptr = _free(Nhe->p.ptr);
2044  Vhe->p.ptr = _free(Vhe->p.ptr);
2045  She->p.ptr = _free(She->p.ptr);
2046 
2047  return rc;
2048 }
2049 
2056 static int triggertypeTag(Header h, HE_t he)
2057  /*@globals internalState @*/
2058  /*@modifies he, internalState @*/
2059 {
2060  HE_t _he = (HE_t) memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
2061  rpmTagData indices = { .ptr = NULL };
2062  rpmTagData flags = { .ptr = NULL };
2063  rpmTagData s = { .ptr = NULL };
2064  rpmTagCount numNames;
2065  rpmTagCount numScripts;
2066  unsigned i, j;
2067  int rc = 1; /* assume failure */
2068  int xx;
2069 
2070  he->freeData = 0;
2071 
2072 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
2073  _he->tag = RPMTAG_TRIGGERINDEX;
2074  xx = headerGet(h, _he, 0);
2075  if (!xx) goto exit;
2076  indices.ui32p = _he->p.ui32p;
2077  numNames = _he->c;
2078 
2079  _he->tag = RPMTAG_TRIGGERFLAGS;
2080  xx = headerGet(h, _he, 0);
2081  if (!xx) goto exit;
2082  flags.ui32p = _he->p.ui32p;
2083 
2084  _he->tag = RPMTAG_TRIGGERSCRIPTS;
2085  xx = headerGet(h, _he, 0);
2086  if (!xx) goto exit;
2087  s.argv = _he->p.argv;
2088  numScripts = _he->c;
2089 /*@=compmempass@*/
2090 
2091  he->t = RPM_STRING_ARRAY_TYPE;
2092  he->c = numScripts;
2093 
2094  he->freeData = 1;
2095  he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
2096  for (i = 0; i < (unsigned) he->c; i++) {
2097  for (j = 0; j < (unsigned) numNames; j++) {
2098  if (indices.ui32p[j] != i) {
2099  he->p.argv[i] = NULL;
2100  /*@innercontinue@*/ continue;
2101  }
2102 
2103  /* XXX FIXME: there's memory leaks here. */
2104  if (flags.ui32p[j] & RPMSENSE_TRIGGERPREIN)
2105  he->p.argv[i] = xstrdup("prein");
2106  else if (flags.ui32p[j] & RPMSENSE_TRIGGERIN)
2107  he->p.argv[i] = xstrdup("in");
2108  else if (flags.ui32p[j] & RPMSENSE_TRIGGERUN)
2109  he->p.argv[i] = xstrdup("un");
2110  else if (flags.ui32p[j] & RPMSENSE_TRIGGERPOSTUN)
2111  he->p.argv[i] = xstrdup("postun");
2112  else
2113  he->p.argv[i] = xstrdup("");
2114  /*@innerbreak@*/ break;
2115  }
2116  }
2117  rc = 0;
2118 
2119 exit:
2120  indices.ptr = _free(indices.ptr);
2121  flags.ptr = _free(flags.ptr);
2122  s.ptr = _free(s.ptr);
2123  return 0;
2124 }
2125 
2126 /* I18N look aside diversions */
2127 
2128 #if defined(ENABLE_NLS)
2129 /*@-exportlocal -exportheadervar@*/
2130 /*@unchecked@*/
2131 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
2132 /*@=exportlocal =exportheadervar@*/
2133 #endif
2134 /*@observer@*/ /*@unchecked@*/
2135 static const char * language = "LANGUAGE";
2136 
2137 /*@observer@*/ /*@unchecked@*/
2138 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
2139 
2146 static int i18nTag(Header h, HE_t he)
2147  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2148  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2149 {
2150  char * dstring = rpmExpand(_macro_i18ndomains, NULL);
2151  int rc = 1; /* assume failure */
2152 
2153  he->t = RPM_STRING_TYPE;
2154  he->p.str = NULL;
2155  he->c = 0;
2156  he->freeData = 0;
2157 
2158  if (dstring && *dstring) {
2159  char *domain, *de;
2160  const char * langval;
2161  const char * msgkey;
2162  const char * msgid;
2163 
2164  { HE_t nhe = (HE_t) memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
2165  const char * tn;
2166  char * mk;
2167  size_t nb = sizeof("()");
2168  int xx;
2169 
2170  nhe->tag = RPMTAG_NAME;
2171  xx = headerGet(h, nhe, 0);
2172  /*
2173  * XXX Ick, tagName() is called by headerGet(), and the tagName()
2174  * buffer is valid only until next tagName() call.
2175  * For now, do the tagName() lookup after headerGet().
2176  */
2177  tn = tagName(he->tag);
2178  if (tn) nb += strlen(tn);
2179  if (nhe->p.str) nb += strlen(nhe->p.str);
2180  mk = alloca(nb);
2181  (void) snprintf(mk, nb, "%s(%s)",
2182  (nhe->p.str ? nhe->p.str : ""), (tn ? tn : ""));
2183  mk[nb-1] = '\0';
2184  nhe->p.ptr = _free(nhe->p.ptr);
2185  msgkey = mk;
2186  }
2187 
2188  /* change to en_US for msgkey -> msgid resolution */
2189  langval = getenv(language);
2190  (void) setenv(language, "en_US", 1);
2191 #if defined(ENABLE_NLS)
2192 /*@i@*/ ++_nl_msg_cat_cntr;
2193 #endif
2194 
2195  msgid = NULL;
2196  for (domain = dstring; domain != NULL; domain = de) {
2197  de = strchr(domain, ':');
2198  if (de) *de++ = '\0';
2199 /*@-unrecog@*/
2200  msgid = dgettext(domain, msgkey);
2201 /*@=unrecog@*/
2202  if (msgid != msgkey) break;
2203  }
2204 
2205  /* restore previous environment for msgid -> msgstr resolution */
2206  if (langval)
2207  (void) setenv(language, langval, 1);
2208  else
2209  unsetenv(language);
2210 #if defined(ENABLE_NLS)
2211 /*@i@*/ ++_nl_msg_cat_cntr;
2212 #endif
2213 
2214  if (domain && msgid) {
2215 /*@-unrecog@*/
2216  const char * s = dgettext(domain, msgid);
2217 /*@=unrecog@*/
2218  if (s) {
2219  rc = 0;
2220  he->p.str = xstrdup(s);
2221  he->c = 1;
2222  he->freeData = 1;
2223  }
2224  }
2225  }
2226 
2227 /*@-dependenttrans@*/
2228  dstring = _free(dstring);
2229 /*@=dependenttrans@*/
2230  if (!rc)
2231  return rc;
2232 
2233  rc = headerGet(h, he, HEADERGET_NOEXTENSION);
2234  if (rc) {
2235  rc = 0;
2236  he->p.str = xstrtolocale(he->p.str);
2237  he->freeData = 1;
2238  return rc;
2239  }
2240 
2241  he->t = RPM_STRING_TYPE;
2242  he->p.str = NULL;
2243  he->c = 0;
2244  he->freeData = 0;
2245 
2246  return 1;
2247 }
2248 
2252 static int localeTag(Header h, HE_t he)
2253  /*@globals internalState @*/
2254  /*@modifies he, internalState @*/
2255 {
2256  int rc;
2257 
2258  rc = headerGet(h, he, HEADERGET_NOEXTENSION);
2259  if (!rc || he->p.str == NULL || he->c == 0) {
2260  he->t = RPM_STRING_TYPE;
2261  he->freeData = 0;
2262  return 1;
2263  }
2264 
2265  switch (he->t) {
2266  default:
2267  he->freeData = 0;
2268  break;
2269  case RPM_STRING_TYPE:
2270  he->p.str = xstrtolocale(he->p.str);
2271  he->freeData = 1;
2272  break;
2273  case RPM_STRING_ARRAY_TYPE:
2274  { const char ** argv;
2275  char * te;
2276  size_t l = 0;
2277  unsigned i;
2278  for (i = 0; i < (unsigned) he->c; i++) {
2279  he->p.argv[i] = xstrdup(he->p.argv[i]);
2280  he->p.argv[i] = xstrtolocale(he->p.argv[i]);
2281 assert(he->p.argv[i] != NULL);
2282  l += strlen(he->p.argv[i]) + 1;
2283  }
2284  argv = xmalloc(he->c * sizeof(*argv) + l);
2285  te = (char *)&argv[he->c];
2286  for (i = 0; i < (unsigned) he->c; i++) {
2287  argv[i] = te;
2288  te = stpcpy(te, he->p.argv[i]);
2289  te++;
2290  he->p.argv[i] = _free(he->p.argv[i]);
2291  }
2292  he->p.ptr = _free(he->p.ptr);
2293  he->p.argv = argv;
2294  he->freeData = 1;
2295  } break;
2296  }
2297 
2298  return 0;
2299 }
2300 
2307 static int summaryTag(Header h, HE_t he)
2308  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2309  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2310 {
2311  he->tag = RPMTAG_SUMMARY;
2312  return i18nTag(h, he);
2313 }
2314 
2321 static int descriptionTag(Header h, HE_t he)
2322  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2323  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2324 {
2325  he->tag = RPMTAG_DESCRIPTION;
2326  return i18nTag(h, he);
2327 }
2328 
2329 static int changelognameTag(Header h, HE_t he)
2330  /*@globals internalState @*/
2331  /*@modifies he, internalState @*/
2332 {
2333  he->tag = RPMTAG_CHANGELOGNAME;
2334  return localeTag(h, he);
2335 }
2336 
2337 static int changelogtextTag(Header h, HE_t he)
2338  /*@globals internalState @*/
2339  /*@modifies he, internalState @*/
2340 {
2341  he->tag = RPMTAG_CHANGELOGTEXT;
2342  return localeTag(h, he);
2343 }
2344 
2351 static int groupTag(Header h, HE_t he)
2352  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2353  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2354 {
2355  he->tag = RPMTAG_GROUP;
2356  return i18nTag(h, he);
2357 }
2358 
2365 static int dbinstanceTag(Header h, HE_t he)
2366  /*@modifies he @*/
2367 {
2368  he->tag = RPMTAG_DBINSTANCE;
2369  he->t = RPM_UINT32_TYPE;
2370  he->p.ui32p = xmalloc(sizeof(*he->p.ui32p));
2371  he->p.ui32p[0] = headerGetInstance(h);
2372  he->freeData = 1;
2373  he->c = 1;
2374  return 0;
2375 }
2376 
2383 static int headerstartoffTag(Header h, HE_t he)
2384  /*@modifies he @*/
2385 {
2386  he->tag = RPMTAG_HEADERSTARTOFF;
2387  he->t = RPM_UINT64_TYPE;
2388  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2389  he->p.ui64p[0] = headerGetStartOff(h);
2390  he->freeData = 1;
2391  he->c = 1;
2392  return 0;
2393 }
2394 
2401 static int headerendoffTag(Header h, HE_t he)
2402  /*@modifies he @*/
2403 {
2404  he->tag = RPMTAG_HEADERENDOFF;
2405  he->t = RPM_UINT64_TYPE;
2406  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2407  he->p.ui64p[0] = headerGetEndOff(h);
2408  he->freeData = 1;
2409  he->c = 1;
2410  return 0;
2411 }
2412 
2419 static int pkgoriginTag(Header h, HE_t he)
2420  /*@globals internalState @*/
2421  /*@modifies he, internalState @*/
2422 {
2423  const char * origin;
2424  int rc = 1;
2425 
2426  he->tag = RPMTAG_PACKAGEORIGIN;
2427  if (!headerGet(h, he, HEADERGET_NOEXTENSION)
2428  && (origin = headerGetOrigin(h)) != NULL)
2429  {
2430  he->t = RPM_STRING_TYPE;
2431  he->p.str = xstrdup(origin);
2432  he->c = 1;
2433  he->freeData = 1;
2434  rc = 0;
2435  }
2436  return rc;
2437 }
2438 
2445 static int pkgbaseurlTag(Header h, HE_t he)
2446  /*@globals internalState @*/
2447  /*@modifies he, internalState @*/
2448 {
2449  const char * baseurl;
2450  int rc = 1;
2451 
2452  he->tag = RPMTAG_PACKAGEBASEURL;
2453  if (!headerGet(h, he, HEADERGET_NOEXTENSION)
2454  && (baseurl = headerGetBaseURL(h)) != NULL)
2455  {
2456  he->t = RPM_STRING_TYPE;
2457  he->p.str = xstrdup(baseurl);
2458  he->c = 1;
2459  he->freeData = 1;
2460  rc = 0;
2461  }
2462  return rc;
2463 }
2464 
2471 static int pkgdigestTag(Header h, HE_t he)
2472  /*@modifies he @*/
2473 {
2474  const char * digest;
2475  int rc = 1;
2476 
2477  he->tag = RPMTAG_PACKAGEDIGEST;
2478  if ((digest = headerGetDigest(h)) != NULL)
2479  {
2480  he->t = RPM_STRING_TYPE;
2481  he->p.str = xstrdup(digest);
2482  he->c = 1;
2483  he->freeData = 1;
2484  rc = 0;
2485  }
2486  return rc;
2487 }
2488 
2495 static int pkgmtimeTag(Header h, HE_t he)
2496  /*@modifies he @*/
2497 {
2498  struct stat * st = headerGetStatbuf(h);
2499  he->tag = RPMTAG_PACKAGETIME;
2500  he->t = RPM_UINT64_TYPE;
2501  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2502 /*@-type@*/
2503  he->p.ui64p[0] = (rpmuint64_t)st->st_mtime;
2504 /*@=type@*/
2505  he->freeData = 1;
2506  he->c = 1;
2507  return 0;
2508 }
2509 
2516 static int pkgsizeTag(Header h, HE_t he)
2517  /*@modifies he @*/
2518 {
2519  struct stat * st = headerGetStatbuf(h);
2520  he->tag = RPMTAG_PACKAGESIZE;
2521  he->t = RPM_UINT64_TYPE;
2522  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2523  he->p.ui64p[0] = (rpmuint64_t)st->st_size;
2524  he->freeData = 1;
2525  he->c = 1;
2526  return 0;
2527 }
2528 
2534 /*@only@*/
2535 static char * hGetNVRA(Header h)
2536  /*@globals internalState @*/
2537  /*@modifies h, internalState @*/
2538 {
2539  const char * N = NULL;
2540  const char * V = NULL;
2541  const char * R = NULL;
2542  const char * A = NULL;
2543  size_t nb = 0;
2544  char * NVRA, * t;
2545 
2546  (void) headerNEVRA(h, &N, NULL, &V, &R, &A);
2547  if (N) nb += strlen(N);
2548  if (V) nb += strlen(V) + 1;
2549  if (R) nb += strlen(R) + 1;
2550 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
2551  /* do not expose the architecture as this is too less
2552  information, as in OpenPKG the "platform" is described by the
2553  architecture+operating-system combination. But as the whole
2554  "platform" information is actually overkill, just revert to the
2555  RPM 4 behaviour and do not expose any such information at all. */
2556 #else
2557  if (A) nb += strlen(A) + 1;
2558 #endif
2559  nb++;
2560  NVRA = t = xmalloc(nb);
2561  *t = '\0';
2562  if (N) t = stpcpy(t, N);
2563  if (V) t = stpcpy( stpcpy(t, "-"), V);
2564  if (R) t = stpcpy( stpcpy(t, "-"), R);
2565 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
2566  /* do not expose the architecture as this is too less
2567  information, as in OpenPKG the "platform" is described by the
2568  architecture+operating-system combination. But as the whole
2569  "platform" information is actually overkill, just revert to the
2570  RPM 4 behaviour and do not expose any such information at all. */
2571 #else
2572  if (A) t = stpcpy( stpcpy(t, "."), A);
2573 #endif
2574  N = _free(N);
2575  V = _free(V);
2576  R = _free(R);
2577  A = _free(A);
2578  return NVRA;
2579 }
2580 
2587 static int nvraTag(Header h, HE_t he)
2588  /*@globals internalState @*/
2589  /*@modifies h, he, internalState @*/
2590 {
2591  he->t = RPM_STRING_TYPE;
2592  he->p.str = hGetNVRA(h);
2593  he->c = 1;
2594  he->freeData = 1;
2595  return 0;
2596 }
2597 
2615 static void rpmfiBuildFNames(Header h, rpmTag tagN,
2616  /*@null@*/ /*@out@*/ const char *** fnp,
2617  /*@null@*/ /*@out@*/ rpmTagCount * fcp)
2618  /*@globals internalState @*/
2619  /*@modifies *fnp, *fcp, internalState @*/
2620 {
2621  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
2622  rpmTag dirNameTag = 0;
2623  rpmTag dirIndexesTag = 0;
2624  rpmTagData baseNames = { .ptr = NULL };
2625  rpmTagData dirNames = { .ptr = NULL };
2626  rpmTagData dirIndexes = { .ptr = NULL };
2627  rpmTagData fileNames;
2628  rpmTagCount count;
2629  size_t size;
2630  int isSource =
2631  (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
2632  headerIsEntry(h, RPMTAG_ARCH) != 0);
2633  char * t;
2634  unsigned i;
2635  int xx;
2636 
2637  if (tagN == RPMTAG_BASENAMES) {
2638  dirNameTag = RPMTAG_DIRNAMES;
2639  dirIndexesTag = RPMTAG_DIRINDEXES;
2640  } else if (tagN == RPMTAG_ORIGBASENAMES) {
2641  dirNameTag = RPMTAG_ORIGDIRNAMES;
2642  dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
2643  } else {
2644  if (fnp) *fnp = NULL;
2645  if (fcp) *fcp = 0;
2646  return; /* programmer error */
2647  }
2648 
2649 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
2650  he->tag = tagN;
2651  xx = headerGet(h, he, 0);
2652  /* XXX 3.0.x SRPM's can be used, relative fn's at RPMTAG_OLDFILENAMES. */
2653  if (xx == 0 && isSource) {
2654  he->tag = RPMTAG_OLDFILENAMES;
2655  xx = headerGet(h, he, 0);
2656  if (xx) {
2657  dirNames.argv = xcalloc(3, sizeof(*dirNames.argv));
2658  dirNames.argv[0] = (const char *)&dirNames.argv[2];
2659  dirIndexes.ui32p = xcalloc(he->c, sizeof(*dirIndexes.ui32p));
2660  }
2661  }
2662  baseNames.argv = he->p.argv;
2663  count = he->c;
2664 
2665  if (!xx) {
2666  if (fnp) *fnp = NULL;
2667  if (fcp) *fcp = 0;
2668  return; /* no file list */
2669  }
2670 
2671  he->tag = dirNameTag;
2672  if ((xx = headerGet(h, he, 0)) != 0)
2673  dirNames.argv = he->p.argv;
2674 
2675  he->tag = dirIndexesTag;
2676  if ((xx = headerGet(h, he, 0)) != 0)
2677  dirIndexes.ui32p = he->p.ui32p;
2678 /*@=compmempass@*/
2679 
2680  size = sizeof(*fileNames.argv) * count;
2681  for (i = 0; i < (unsigned)count; i++) {
2682  const char * dn = NULL;
2683  (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
2684  size += strlen(baseNames.argv[i]) + strlen(dn) + 1;
2685  }
2686 
2687  fileNames.argv = xmalloc(size);
2688  t = (char *)&fileNames.argv[count];
2689  for (i = 0; i < (unsigned)count; i++) {
2690  const char * dn = NULL;
2691  (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
2692  fileNames.argv[i] = t;
2693  t = stpcpy( stpcpy(t, dn), baseNames.argv[i]);
2694  *t++ = '\0';
2695  }
2696  baseNames.ptr = _free(baseNames.ptr);
2697  dirNames.ptr = _free(dirNames.ptr);
2698  dirIndexes.ptr = _free(dirIndexes.ptr);
2699 
2700 /*@-onlytrans@*/
2701  if (fnp)
2702  *fnp = fileNames.argv;
2703  else
2704  fileNames.ptr = _free(fileNames.ptr);
2705 /*@=onlytrans@*/
2706  if (fcp) *fcp = count;
2707 }
2708 
2716 static int _fnTag(Header h, HE_t he, rpmTag tag)
2717  /*@globals internalState @*/
2718  /*@modifies he, internalState @*/
2719 {
2720  he->t = RPM_STRING_ARRAY_TYPE;
2721  rpmfiBuildFNames(h, tag, &he->p.argv, &he->c);
2722  he->freeData = 1;
2723  /* XXX headerGet() rc on RPMTAG_FILEPATHS w empty list. */
2724  if (he->p.argv && he->p.argv[0] && he->c > 0)
2725  return 0;
2726  he->p.ptr = _free(he->p.ptr);
2727  he->c = 0;
2728  return 1;
2729 }
2730 
2731 static int filenamesTag(Header h, HE_t he)
2732  /*@globals internalState @*/
2733  /*@modifies he, internalState @*/
2734 {
2735  he->tag = tagValue("Filenames");
2736  return _fnTag(h, he, RPMTAG_BASENAMES);
2737 }
2738 
2739 static int filepathsTag(Header h, HE_t he)
2740  /*@globals internalState @*/
2741  /*@modifies he, internalState @*/
2742 {
2743  he->tag = RPMTAG_FILEPATHS;
2744  return _fnTag(h, he, RPMTAG_BASENAMES);
2745 }
2746 
2747 static int origpathsTag(Header h, HE_t he)
2748  /*@globals internalState @*/
2749  /*@modifies he, internalState @*/
2750 {
2751  he->tag = RPMTAG_ORIGPATHS;
2752  return _fnTag(h, he, RPMTAG_ORIGBASENAMES);
2753 }
2754 
2764 static int debevrfmtTag(/*@unused@*/ Header h, HE_t he,
2765  HE_t Nhe, HE_t EVRhe, HE_t Fhe)
2766  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2767  /*@modifies he, Nhe, rpmGlobalMacroContext, internalState @*/
2768 {
2769  char * t, * te;
2770  size_t nb = 0;
2771  int rc = 1;
2772 
2773  he->t = RPM_STRING_ARRAY_TYPE;
2774  he->c = 0;
2775  he->freeData = 1;
2776  for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
2777  nb += sizeof(*he->p.argv);
2778  nb += strlen(Nhe->p.argv[Nhe->ix]) + 1;
2779  if (*EVRhe->p.argv[Nhe->ix] != '\0')
2780  nb += strlen(EVRhe->p.argv[Nhe->ix]) + (sizeof(" (== )")-1);
2781  he->c++;
2782  }
2783  nb += sizeof(*he->p.argv);
2784 
2785  he->p.argv = xmalloc(nb);
2786  te = (char *) &he->p.argv[he->c+1];
2787 
2788  he->c = 0;
2789  for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
2790  he->p.argv[he->c++] = te;
2791  if (*EVRhe->p.argv[Nhe->ix] != '\0') {
2792  char opstr[4], * op = opstr;
2793  if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_LESS)
2794  *op++ = '<';
2795  if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_GREATER)
2796  *op++ = '>';
2797  if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_EQUAL)
2798  *op++ = '=';
2799  *op = '\0';
2800  t = rpmExpand(Nhe->p.argv[Nhe->ix],
2801  " (", opstr, " ", EVRhe->p.argv[Nhe->ix], ")", NULL);
2802  } else
2803  t = rpmExpand(Nhe->p.argv[Nhe->ix], NULL);
2804  te = stpcpy(te, t);
2805  te++;
2806  t = _free(t);
2807  }
2808  he->p.argv[he->c] = NULL;
2809  rc = 0;
2810 
2811  return rc;
2812 }
2813 
2823 static int debevrTag(Header h, HE_t he, rpmTag tagN, rpmTag tagEVR, rpmTag tagF)
2824  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2825  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2826 {
2827  HE_t Nhe = (HE_t) memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
2828  HE_t EVRhe = (HE_t) memset(alloca(sizeof(*EVRhe)), 0, sizeof(*EVRhe));
2829  HE_t Fhe = (HE_t) memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
2830  int rc = 1;
2831  int xx;
2832 
2833  Nhe->tag = tagN;
2834  if (!(xx = headerGet(h, Nhe, 0)))
2835  goto exit;
2836  EVRhe->tag = tagEVR;
2837  if (!(xx = headerGet(h, EVRhe, 0)))
2838  goto exit;
2839 assert(EVRhe->c == Nhe->c);
2840  Fhe->tag = tagF;
2841  if (!(xx = headerGet(h, Fhe, 0)))
2842  goto exit;
2843 assert(Fhe->c == Nhe->c);
2844 
2845  rc = debevrfmtTag(h, he, Nhe, EVRhe, Fhe);
2846 
2847 exit:
2848  Nhe->p.ptr = _free(Nhe->p.ptr);
2849  EVRhe->p.ptr = _free(EVRhe->p.ptr);
2850  Fhe->p.ptr = _free(Fhe->p.ptr);
2851  return rc;
2852 }
2853 
2860 static int debconflictsTag(Header h, HE_t he)
2861  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2862  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2863 {
2864  he->tag = tagValue("Debconflicts");
2865  return debevrTag(h, he,
2867 }
2868 
2869 static int debdependsTag(Header h, HE_t he)
2870  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2871  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2872 {
2873  he->tag = tagValue("Debdepends");
2874  return debevrTag(h, he,
2876 }
2877 
2878 static int debobsoletesTag(Header h, HE_t he)
2879  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2880  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2881 {
2882  he->tag = tagValue("Debobsoletes");
2883  return debevrTag(h, he,
2885 }
2886 
2887 static int debprovidesTag(Header h, HE_t he)
2888  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2889  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2890 {
2891  he->tag = tagValue("Debprovides");
2892  return debevrTag(h, he,
2894 }
2895 
2902 static int debmd5sumsTag(Header h, HE_t he)
2903  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2904  /*@modifies he, rpmGlobalMacroContext, internalState @*/
2905 {
2906  HE_t Nhe = (HE_t) memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
2907  HE_t Dhe = (HE_t) memset(alloca(sizeof(*Dhe)), 0, sizeof(*Dhe));
2908  char * t, * te;
2909  size_t nb = 0;
2910  int rc = 1;
2911  int xx;
2912 
2913  Nhe->tag = RPMTAG_FILEPATHS;
2914  if (!(xx = headerGet(h, Nhe, 0)))
2915  goto exit;
2916  Dhe->tag = RPMTAG_FILEDIGESTS;
2917  if (!(xx = headerGet(h, Dhe, 0)))
2918  goto exit;
2919 assert(Dhe->c == Nhe->c);
2920 
2921  he->tag = tagValue("Debmd5sums");
2922  he->t = RPM_STRING_ARRAY_TYPE;
2923  he->c = 0;
2924  he->freeData = 1;
2925  for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) {
2926  if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix]))
2927  continue;
2928  nb += sizeof(*he->p.argv);
2929  nb += strlen(Dhe->p.argv[Dhe->ix]) + sizeof(" ") + strlen(Nhe->p.argv[Dhe->ix]) - 1;
2930  he->c++;
2931  }
2932  nb += sizeof(*he->p.argv);
2933 
2934  he->p.argv = xmalloc(nb);
2935  te = (char *) &he->p.argv[he->c+1];
2936 
2937  he->c = 0;
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  he->p.argv[he->c++] = te;
2942  t = rpmExpand(Dhe->p.argv[Dhe->ix], " ", Nhe->p.argv[Dhe->ix]+1, NULL);
2943  te = stpcpy(te, t);
2944  te++;
2945  t = _free(t);
2946  }
2947  he->p.argv[he->c] = NULL;
2948  rc = 0;
2949 
2950 exit:
2951  Nhe->p.ptr = _free(Nhe->p.ptr);
2952  Dhe->p.ptr = _free(Dhe->p.ptr);
2953  return rc;
2954 }
2955 
2956 static int filestatTag(Header h, HE_t he)
2957  /*@globals internalState @*/
2958  /*@modifies he, internalState @*/
2959 {
2960  rpmTagData paths = { .ptr = NULL };
2961  /* _dev */
2962  rpmTagData _ino = { .ptr = NULL };
2963  rpmTagData _mode = { .ptr = NULL };
2964  /* _nlink */
2965  /* _uid */
2966  /* _gid */
2967  rpmTagData _rdev = { .ptr = NULL };
2968  rpmTagData _size = { .ptr = NULL };
2969  /* _blksize */
2970  /* _blocks */
2971  /* _atime */
2972  rpmTagData _mtime = { .ptr = NULL };
2973  /* st_ctime */
2974  int rc;
2975 
2976  he->tag = RPMTAG_FILEPATHS;
2977  if ((rc = _fnTag(h, he, RPMTAG_BASENAMES)) != 0 || he->c == 0)
2978  goto exit;
2979 
2980 exit:
2981  paths.ptr = _free(paths.ptr);
2982  _ino.ptr = _free(_ino.ptr);
2983  _mode.ptr = _free(_mode.ptr);
2984  _rdev.ptr = _free(_rdev.ptr);
2985  _size.ptr = _free(_size.ptr);
2986  _mtime.ptr = _free(_mtime.ptr);
2987  return rc;
2988 }
2989 
2990 static int wnlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
2991  HE_t PNhe, /*@null@*/ HE_t PEVRhe, /*@null@*/ HE_t PFhe)
2992  /*@globals rpmGlobalMacroContext, h_errno,
2993  fileSystem, internalState @*/
2994  /*@modifies *avp, *hitp, rpmGlobalMacroContext,
2995  fileSystem, internalState @*/
2996 {
2997  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
2998  HE_t RNhe = (HE_t) memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
2999  HE_t REVRhe = (HE_t) memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
3000  HE_t RFhe = (HE_t) memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
3001  rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
3002  const char * key = PNhe->p.argv[PNhe->ix];
3003  size_t keylen = 0;
3004  rpmmi mi;
3005  rpmTag tagN = RPMTAG_REQUIRENAME;
3006  rpmTag tagEVR = RPMTAG_REQUIREVERSION;
3007  rpmTag tagF = RPMTAG_REQUIREFLAGS;
3008  rpmuint32_t PFlags;
3009  rpmuint32_t RFlags;
3010  EVR_t Pevr;
3011  Header oh;
3012  int rc = 0;
3013  int xx;
3014 
3015  if (tagNVRA == 0)
3016  tagNVRA = RPMTAG_NVRA;
3017 
3018  PFlags = (PFhe != NULL ? (PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK) : 0);
3019  Pevr = rpmEVRnew(PFlags, 1);
3020 
3021  if (PEVRhe != NULL)
3022  xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr);
3023 
3024  RNhe->tag = tagN;
3025  REVRhe->tag = tagEVR;
3026  RFhe->tag = tagF;
3027 
3028  mi = rpmmiInit(_rpmdb, tagN, key, keylen);
3029  if (hitp && *hitp)
3030  xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0);
3031  while ((oh = rpmmiNext(mi)) != NULL) {
3032  if (!headerGet(oh, RNhe, 0))
3033  goto bottom;
3034  if (PEVRhe != NULL) {
3035  if (!headerGet(oh, REVRhe, 0))
3036  goto bottom;
3037 assert(REVRhe->c == RNhe->c);
3038  if (!headerGet(oh, RFhe, 0))
3039  goto bottom;
3040 assert(RFhe->c == RNhe->c);
3041  }
3042 
3043  for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
3044  if (strcmp(PNhe->p.argv[PNhe->ix], RNhe->p.argv[RNhe->ix]))
3045  /*@innercontinue@*/ continue;
3046  if (PEVRhe == NULL)
3047  goto bingo;
3048  RFlags = RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK;
3049  { EVR_t Revr = rpmEVRnew(RFlags, 1);
3050  if (!(PFlags && RFlags))
3051  xx = 1;
3052  else {
3053  xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
3054  xx = rpmEVRoverlap(Pevr, Revr);
3055  }
3056  Revr = rpmEVRfree(Revr);
3057  }
3058  if (xx)
3059  goto bingo;
3060  }
3061  goto bottom;
3062 
3063 bingo:
3064  NVRAhe->tag = tagNVRA;
3065  xx = headerGet(oh, NVRAhe, 0);
3066  if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
3067  xx = argvAdd(avp, NVRAhe->p.str);
3068  xx = argvSort(*avp, NULL);
3069  if (hitp != NULL)
3070  xx = argiAdd(hitp, -1, rpmmiInstance(mi));
3071  rc++;
3072  }
3073 
3074 bottom:
3075  RNhe->p.ptr = _free(RNhe->p.ptr);
3076  REVRhe->p.ptr = _free(REVRhe->p.ptr);
3077  RFhe->p.ptr = _free(RFhe->p.ptr);
3078  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3079  }
3080  mi = rpmmiFree(mi);
3081 
3082  Pevr = rpmEVRfree(Pevr);
3083 
3084  return rc;
3085 }
3086 
3087 static int whatneedsTag(Header h, HE_t he)
3088  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3089  /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
3090 {
3091  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
3092  HE_t PNhe = (HE_t) memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
3093  HE_t PEVRhe = (HE_t) memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
3094  HE_t PFhe = (HE_t) memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
3095  HE_t FNhe = (HE_t) memset(alloca(sizeof(*FNhe)), 0, sizeof(*FNhe));
3096  rpmTag tagNVRA = RPMTAG_NVRA;
3097  ARGV_t pkgs = NULL;
3098  ARGI_t hits = NULL;
3099  int rc = 1;
3100 
3101  PNhe->tag = RPMTAG_PROVIDENAME;
3102  if (!headerGet(h, PNhe, 0))
3103  goto exit;
3104  PEVRhe->tag = RPMTAG_PROVIDEVERSION;
3105  if (!headerGet(h, PEVRhe, 0))
3106  goto exit;
3107 assert(PEVRhe->c == PNhe->c);
3108  PFhe->tag = RPMTAG_PROVIDEFLAGS;
3109  if (!headerGet(h, PFhe, 0))
3110  goto exit;
3111 assert(PFhe->c == PNhe->c);
3112 
3113  FNhe->tag = RPMTAG_FILEPATHS;
3114  if (!headerGet(h, FNhe, 0))
3115  goto exit;
3116 
3117  NVRAhe->tag = tagNVRA;;
3118  if (!headerGet(h, NVRAhe, 0))
3119  goto exit;
3120 
3121  (void) argvAdd(&pkgs, NVRAhe->p.str);
3122 
3123  for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++)
3124  (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, PNhe, PEVRhe, PFhe);
3125  for (FNhe->ix = 0; FNhe->ix < (int)FNhe->c; FNhe->ix++)
3126  (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, FNhe, NULL, NULL);
3127 
3128  /* Convert package NVRA array to Header string array. */
3129  { size_t nb = 0;
3130  char * te;
3131  rpmuint32_t i;
3132 
3133  he->t = RPM_STRING_ARRAY_TYPE;
3134  he->c = argvCount(pkgs);
3135  nb = 0;
3136  for (i = 0; i < he->c; i++) {
3137  nb += sizeof(*he->p.argv);
3138  nb += strlen(pkgs[i]) + 1;
3139  }
3140  nb += sizeof(*he->p.argv);
3141 
3142  he->p.argv = xmalloc(nb);
3143  te = (char *) &he->p.argv[he->c+1];
3144 
3145  for (i = 0; i < he->c; i++) {
3146  he->p.argv[i] = te;
3147  te = stpcpy(te, pkgs[i]);
3148  te++;
3149  }
3150  he->p.argv[he->c] = NULL;
3151  }
3152 
3153  hits = argiFree(hits);
3154  pkgs = argvFree(pkgs);
3155  rc = 0;
3156 
3157 exit:
3158  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3159  PNhe->p.ptr = _free(PNhe->p.ptr);
3160  PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
3161  PFhe->p.ptr = _free(PFhe->p.ptr);
3162  FNhe->p.ptr = _free(FNhe->p.ptr);
3163  return rc;
3164 }
3165 
3166 static int nwlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
3167  HE_t RNhe, /*@null@*/ HE_t REVRhe, /*@null@*/ HE_t RFhe)
3168  /*@globals rpmGlobalMacroContext, h_errno,
3169  fileSystem, internalState @*/
3170  /*@modifies *avp, *hitp, REVRhe, rpmGlobalMacroContext,
3171  fileSystem, internalState @*/
3172 {
3173  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
3174  HE_t PNhe = (HE_t) memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
3175  HE_t PEVRhe = (HE_t) memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
3176  HE_t PFhe = (HE_t) memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
3177  rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
3178  const char * key = RNhe->p.argv[RNhe->ix];
3179  size_t keylen = 0;
3180  rpmmi mi;
3181  rpmTag tagN = (*RNhe->p.argv[RNhe->ix] == '/')
3183  rpmTag tagEVR = RPMTAG_PROVIDEVERSION;
3184  rpmTag tagF = RPMTAG_PROVIDEFLAGS;
3185  rpmuint32_t PFlags;
3186  rpmuint32_t RFlags;
3187  EVR_t Revr;
3188  Header oh;
3189  int rc = 0;
3190  int xx;
3191 
3192  if (tagNVRA == 0)
3193  tagNVRA = RPMTAG_NVRA;
3194 
3195  RFlags = (RFhe != NULL ? (RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK) : 0);
3196  Revr = rpmEVRnew(RFlags, 1);
3197 
3198  if (REVRhe != NULL)
3199  xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
3200 
3201  PNhe->tag = tagN;
3202  PEVRhe->tag = tagEVR;
3203  PFhe->tag = tagF;
3204 
3205  mi = rpmmiInit(_rpmdb, tagN, key, keylen);
3206  if (hitp && *hitp)
3207  xx = rpmmiPrune(mi, (uint32_t *)argiData(*hitp), argiCount(*hitp), 0);
3208  while ((oh = rpmmiNext(mi)) != NULL) {
3209  if (!headerGet(oh, PNhe, 0))
3210  goto bottom;
3211  if (REVRhe != NULL) {
3212  if (!headerGet(oh, PEVRhe, 0))
3213  goto bottom;
3214 assert(PEVRhe->c == PNhe->c);
3215  if (!headerGet(oh, PFhe, 0))
3216  goto bottom;
3217 assert(PFhe->c == PNhe->c);
3218  }
3219 
3220  for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) {
3221  if (strcmp(RNhe->p.argv[RNhe->ix], PNhe->p.argv[PNhe->ix]))
3222  /*@innercontinue@*/ continue;
3223  if (REVRhe == NULL)
3224  goto bingo;
3225  PFlags = PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK;
3226  { EVR_t Pevr = rpmEVRnew(PFlags, 1);
3227  if (!(PFlags && RFlags))
3228  xx = 1;
3229  else {
3230  xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr);
3231  xx = rpmEVRoverlap(Revr, Pevr);
3232  }
3233  Pevr = rpmEVRfree(Pevr);
3234  }
3235  if (xx)
3236  goto bingo;
3237  }
3238  goto bottom;
3239 
3240 bingo:
3241  NVRAhe->tag = tagNVRA;
3242  xx = headerGet(oh, NVRAhe, 0);
3243  if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
3244  xx = argvAdd(avp, NVRAhe->p.str);
3245  xx = argvSort(*avp, NULL);
3246  if (hitp != NULL)
3247  xx = argiAdd(hitp, -1, rpmmiInstance(mi));
3248  rc++;
3249  }
3250 
3251 bottom:
3252  PNhe->p.ptr = _free(PNhe->p.ptr);
3253  PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
3254  PFhe->p.ptr = _free(PFhe->p.ptr);
3255  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3256  }
3257  mi = rpmmiFree(mi);
3258 
3259  Revr = rpmEVRfree(Revr);
3260 
3261  return rc;
3262 }
3263 
3264 static int needswhatTag(Header h, HE_t he)
3265  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3266  /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
3267 {
3268  HE_t NVRAhe = (HE_t) memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
3269  HE_t RNhe = (HE_t) memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
3270  HE_t REVRhe = (HE_t) memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
3271  HE_t RFhe = (HE_t) memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
3272  rpmTag tagNVRA = RPMTAG_NVRA;
3273  ARGV_t pkgs = NULL;
3274  ARGI_t hits = NULL;
3275  int rc = 1;
3276 
3277  RNhe->tag = RPMTAG_REQUIRENAME;
3278  if (!headerGet(h, RNhe, 0))
3279  goto exit;
3280  REVRhe->tag = RPMTAG_REQUIREVERSION;
3281  if (!headerGet(h, REVRhe, 0))
3282  goto exit;
3283 assert(REVRhe->c == RNhe->c);
3284  RFhe->tag = RPMTAG_REQUIREFLAGS;
3285  if (!headerGet(h, RFhe, 0))
3286  goto exit;
3287 assert(RFhe->c == RNhe->c);
3288 
3289  NVRAhe->tag = tagNVRA;;
3290  if (!headerGet(h, NVRAhe, 0))
3291  goto exit;
3292 
3293  (void) argvAdd(&pkgs, NVRAhe->p.str);
3294 
3295  for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
3296  if (*RNhe->p.argv[RNhe->ix] == '/' || *REVRhe->p.argv[RNhe->ix] == '\0')
3297  (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, NULL, NULL);
3298  else
3299  (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, REVRhe, RFhe);
3300  }
3301 
3302  /* Convert package NVRA array to Header string array. */
3303  { size_t nb = 0;
3304  char * te;
3305  rpmuint32_t i;
3306 
3307  he->t = RPM_STRING_ARRAY_TYPE;
3308  he->c = argvCount(pkgs);
3309  nb = 0;
3310  for (i = 0; i < he->c; i++) {
3311  nb += sizeof(*he->p.argv);
3312  nb += strlen(pkgs[i]) + 1;
3313  }
3314  nb += sizeof(*he->p.argv);
3315 
3316  he->p.argv = xmalloc(nb);
3317  te = (char *) &he->p.argv[he->c+1];
3318 
3319  for (i = 0; i < he->c; i++) {
3320  he->p.argv[i] = te;
3321  te = stpcpy(te, pkgs[i]);
3322  te++;
3323  }
3324  he->p.argv[he->c] = NULL;
3325  }
3326 
3327  hits = argiFree(hits);
3328  pkgs = argvFree(pkgs);
3329  rc = 0;
3330 
3331 exit:
3332  NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3333  RNhe->p.ptr = _free(RNhe->p.ptr);
3334  REVRhe->p.ptr = _free(REVRhe->p.ptr);
3335  RFhe->p.ptr = _free(RFhe->p.ptr);
3336  return rc;
3337 }
3338 
3339 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F,
3340  uint32_t i)
3341  /*@*/
3342 {
3343  int a = -2, b = -2;
3344  int rc = 0;
3345 
3346 assert(N.argv[i] != NULL && *N.argv[i] != '\0');
3347 
3348  if (tag == RPMTAG_REQUIRENAME && i > 0
3349  && !(a=strcmp(N.argv[i], N.argv[i-1]))
3350  && !(b=strcmp(EVR.argv[i], EVR.argv[i-1]))
3351  && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e)) )
3352  rc = 1;
3353  return rc;
3354 }
3355 
3356 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3357  /*@globals internalState @*/
3358  /*@modifies he, internalState @*/
3359 {
3360  rpmTag tag = he->tag;
3361  rpmTagData N = { .ptr = NULL };
3362  rpmTagData EVR = { .ptr = NULL };
3363  rpmTagData F = { .ptr = NULL };
3364  size_t nb;
3365  uint32_t ac;
3366  uint32_t c;
3367  uint32_t i;
3368  char *t;
3369  int rc = 1; /* assume failure */
3370  int xx;
3371 int lvl = 0;
3372 spew_t spew = &_xml_spew;
3373 
3374 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3375  xx = headerGet(h, he, 0);
3376  if (xx == 0) goto exit;
3377  N.argv = he->p.argv;
3378  c = he->c;
3379 
3380  he->tag = EVRtag;
3381  xx = headerGet(h, he, 0);
3382  if (xx == 0) goto exit;
3383  EVR.argv = he->p.argv;
3384 
3385  he->tag = Ftag;
3386  xx = headerGet(h, he, 0);
3387  if (xx == 0) goto exit;
3388  F.ui32p = he->p.ui32p;
3389 
3390  nb = sizeof(*he->p.argv);
3391  ac = 0;
3392  for (i = 0; i < c; i++) {
3393 /*@-nullstate@*/ /* EVR.argv might be NULL */
3394  if (PRCOSkip(tag, N, EVR, F, i))
3395  continue;
3396 /*@=nullstate@*/
3397  ac++;
3398  nb += sizeof(*he->p.argv);
3399  nb += sizeof("<rpm:entry name=\"\"/>");
3400  if (*N.argv[i] == '/')
3401  nb += spew->spew_strlen(N.argv[i], lvl);
3402  else
3403  nb += strlen(N.argv[i]);
3404  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3405  nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1;
3406  nb += strlen(EVR.argv[i]);
3407  if (strchr(EVR.argv[i], ':') != NULL)
3408  nb -= 2;
3409  if (strchr(EVR.argv[i], '-') != NULL)
3410  nb += sizeof(" rel=\"\"") - 2;
3411  }
3412 #ifdef NOTNOW
3413  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3414  nb += sizeof(" pre=\"1\"") - 1;
3415 #endif
3416  }
3417 
3418  he->t = RPM_STRING_ARRAY_TYPE;
3419  he->c = ac;
3420  he->freeData = 1;
3421  he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
3422  t = (char *) &he->p.argv[he->c + 1];
3423  ac = 0;
3424  for (i = 0; i < c; i++) {
3425 /*@-nullstate@*/ /* EVR.argv might be NULL */
3426  if (PRCOSkip(tag, N, EVR, F, i))
3427  continue;
3428 /*@=nullstate@*/
3429  he->p.argv[ac++] = t;
3430  t = stpcpy(t, "<rpm:entry");
3431  t = stpcpy(t, " name=\"");
3432  if (*N.argv[i] == '/') {
3433  t = spew->spew_strcpy(t, N.argv[i], lvl); t += strlen(t);
3434  } else
3435  t = stpcpy(t, N.argv[i]);
3436  t = stpcpy(t, "\"");
3437 /*@-readonlytrans@*/
3438  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3439  static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
3440  rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3441  const char *E, *V, *R;
3442  char *f, *fe;
3443  t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\"");
3444  f = (char *) EVR.argv[i];
3445  for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++)
3446  {};
3447  if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
3448  V = f;
3449  for (fe = f; *fe != '\0' && *fe != '-'; fe++)
3450  {};
3451  if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
3452  t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\"");
3453  t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\"");
3454  if (R != NULL)
3455  t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\"");
3456  }
3457 /*@=readonlytrans@*/
3458 #ifdef NOTNOW
3459  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3460  t = stpcpy(t, " pre=\"1\"");
3461 #endif
3462  t = stpcpy(t, "/>");
3463  *t++ = '\0';
3464  }
3465  he->p.argv[he->c] = NULL;
3466 /*@=compmempass@*/
3467  rc = 0;
3468 
3469 exit:
3470 /*@-kepttrans@*/ /* N.argv may be kept. */
3471  N.argv = _free(N.argv);
3472 /*@=kepttrans@*/
3473 /*@-usereleased@*/ /* EVR.argv may be dead. */
3474  EVR.argv = _free(EVR.argv);
3475 /*@=usereleased@*/
3476  F.ui32p = _free(F.ui32p);
3477  return rc;
3478 }
3479 
3480 static int PxmlTag(Header h, HE_t he)
3481  /*@globals internalState @*/
3482  /*@modifies he, internalState @*/
3483 {
3484  he->tag = RPMTAG_PROVIDENAME;
3486 }
3487 
3488 static int RxmlTag(Header h, HE_t he)
3489  /*@globals internalState @*/
3490  /*@modifies he, internalState @*/
3491 {
3492  he->tag = RPMTAG_REQUIRENAME;
3494 }
3495 
3496 static int CxmlTag(Header h, HE_t he)
3497  /*@globals internalState @*/
3498  /*@modifies he, internalState @*/
3499 {
3500  he->tag = RPMTAG_CONFLICTNAME;
3502 }
3503 
3504 static int OxmlTag(Header h, HE_t he)
3505  /*@globals internalState @*/
3506  /*@modifies he, internalState @*/
3507 {
3508  he->tag = RPMTAG_OBSOLETENAME;
3510 }
3511 
3520 static /*@only@*/ char * spewescapeFormat(HE_t he, /*@null@*/ const char ** av,
3521  spew_t spew, int lvl)
3522  /*@*/
3523 {
3524  int ix = (he->ix > 0 ? he->ix : 0);
3525  char * val;
3526 
3527 assert(ix == 0);
3528  if (he->t != RPM_STRING_TYPE) {
3529  val = xstrdup(_("(not a string)"));
3530  } else {
3531  const char * s = strdup_iconv_check(he->p.str, (av ? av[0] : NULL));
3532  size_t nb = spew->spew_strlen(s, lvl);
3533  char * t = xmalloc(nb+1);;
3534  val = t;
3535  t = spew->spew_strcpy(t, s, lvl); t += strlen(t);
3536  *t = '\0';
3537  s = _free(s);
3538  }
3539 
3540  return val;
3541 }
3542 
3543 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */
3544 static /*@only@*/ char * jsonescapeFormat(HE_t he, /*@null@*/ const char ** av)
3545  /*@*/
3546 {
3547  return spewescapeFormat(he, av, &_json_spew, 0);
3548 }
3549 #endif
3550 
3551 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av)
3552  /*@*/
3553 {
3554  return spewescapeFormat(he, av, &_sql_spew, 0);
3555 }
3556 
3557 /*@-compmempass -kepttrans -nullstate -usereleased @*/
3558 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3559  /*@globals internalState @*/
3560  /*@modifies he, internalState @*/
3561 {
3562  static char q = '"';
3563  rpmTag tag = he->tag;
3564  rpmTagData N = { .ptr = NULL };
3565  rpmTagData EVR = { .ptr = NULL };
3566  rpmTagData F = { .ptr = NULL };
3567  char instance[64];
3568  size_t nb;
3569  uint32_t ac;
3570  uint32_t c;
3571  uint32_t i;
3572  char *te;
3573  int rc = 1; /* assume failure */
3574  int xx;
3575 
3576 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3577  xx = headerGet(h, he, 0);
3578  if (xx == 0) goto exit;
3579  N.argv = he->p.argv;
3580  c = he->c;
3581 
3582  he->tag = EVRtag;
3583  xx = headerGet(h, he, 0);
3584  if (xx == 0) goto exit;
3585  EVR.argv = he->p.argv;
3586 
3587  he->tag = Ftag;
3588  xx = headerGet(h, he, 0);
3589  if (xx == 0) goto exit;
3590  F.ui32p = he->p.ui32p;
3591 
3592  xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
3593  nb = 0;
3594  ac = 0;
3595  for (i = 0; i < c; i++) {
3596 /*@-nullstate@*/ /* EVR.argv might be NULL */
3597  if (PRCOSkip(tag, N, EVR, F, i))
3598  continue;
3599 /*@=nullstate@*/
3600  ac++;
3601  nb += strlen(instance) + sizeof(", '', '', '', '', ''") - 1;
3602  if (tag == RPMTAG_REQUIRENAME)
3603  nb += sizeof(", ''") - 1;
3604  nb += strlen(N.argv[i]);
3605  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3606  uint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3607  EVR_t Revr = rpmEVRnew(Fx, 1);
3608  int xx = rpmEVRparse(EVR.argv[i], Revr);
3609  const char * E = Revr->F[RPMEVR_E];
3610  const char * V = Revr->F[RPMEVR_V];
3611 #ifdef NOTYET /* XXX rpmrepo? */
3612  const char * T = Revr->F[RPMEVR_T];
3613 #endif
3614  const char * R = Revr->F[RPMEVR_R];
3615 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3616  const char * D = Revr->F[RPMEVR_D];
3617 #endif
3618  xx = xx;
3619  nb += (sizeof(", 'EQ'")-1);
3620  nb += (sizeof(", ''")-1) + strlen(E);
3621  nb += (sizeof(", ''")-1) + strlen(V);
3622 #ifdef NOTYET /* XXX rpmrepo? */
3623  nb += (sizeof(", ''")-1) + strlen(T);
3624 #endif
3625  nb += (sizeof(", ''")-1) + strlen(R);
3626 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3627  nb += (sizeof(", ''")-1) + strlen(D);
3628 #endif
3629  Revr = rpmEVRfree(Revr);
3630  }
3631 #ifdef NOTNOW
3632  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3633  nb += sizeof("1") - 1;
3634 #endif
3635  nb++;
3636  }
3637 
3638  nb += (ac + 1) * sizeof(*he->p.argv);
3639 
3640  he->t = RPM_STRING_ARRAY_TYPE;
3641  he->c = ac;
3642  he->freeData = 1;
3643  he->p.argv = xmalloc(nb);
3644  te = (char *) &he->p.argv[ac + 1];
3645  *te = '\0';
3646  ac = 0;
3647  for (i = 0; i < c; i++) {
3648 /*@-nullstate@*/ /* EVR.argv might be NULL */
3649  if (PRCOSkip(tag, N, EVR, F, i))
3650  continue;
3651 /*@=nullstate@*/
3652  he->p.argv[ac++] = te;
3653  te = stpcpy(te, instance);
3654  *te++ = ','; *te++ = ' ';
3655  *te++ = q; te = stpcpy(te, N.argv[i]); *te++ = q;
3656 /*@-readonlytrans@*/
3657  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3658  static const char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
3659  uint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3660  EVR_t Revr = rpmEVRnew(Fx, 1);
3661  int xx = rpmEVRparse(EVR.argv[i], Revr);
3662  const char * E = Revr->F[RPMEVR_E];
3663  const char * V = Revr->F[RPMEVR_V];
3664 #ifdef NOTYET /* XXX rpmrepo? */
3665  const char * T = Revr->F[RPMEVR_T];
3666 #endif
3667  const char * R = Revr->F[RPMEVR_R];
3668 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3669  const char * D = Revr->F[RPMEVR_D];
3670 #endif
3671  xx = xx;
3672  *te++ = ','; *te++ = ' ';
3673  *te++ = q; te = stpcpy(te, Fstr[Fx]); *te++ = q;
3674  *te++ = ','; *te++ = ' ';
3675  *te++ = q; te = stpcpy(te, E); *te++ = q;
3676  *te++ = ','; *te++ = ' ';
3677  *te++ = q; te = stpcpy(te, V); *te++ = q;
3678 #ifdef NOTYET /* XXX rpmrepo? */
3679  *te++ = ','; *te++ = ' ';
3680  *te++ = q; te = stpcpy(te, T); *te++ = q;
3681 #endif
3682  *te++ = ','; *te++ = ' ';
3683  *te++ = q; te = stpcpy(te, R); *te++ = q;
3684 #ifdef NOTYET /* XXX turning this on breaks rpmrepo */
3685  *te++ = ','; *te++ = ' ';
3686  *te++ = q; te = stpcpy(te, D); *te++ = q;
3687 #endif
3688  Revr = rpmEVRfree(Revr);
3689  } else {
3690  /* XXX FIXME: handle RPMEVR_T and RPMEVR_D? */
3691  *te++ = ','; *te++ = ' ';
3692  *te++ = q; *te++ = q;
3693  *te++ = ','; *te++ = ' ';
3694  *te++ = q; *te++ = q;
3695  *te++ = ','; *te++ = ' ';
3696  *te++ = q; *te++ = q;
3697  *te++ = ','; *te++ = ' ';
3698  *te++ = q; *te++ = q;
3699  }
3700 /*@=readonlytrans@*/
3701 #ifdef NOTNOW
3702  if (tag == RPMTAG_REQUIRENAME)
3703  te = stpcpy(stpcpy(stpcpy(te, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'");
3704 #endif
3705  *te++ = '\0';
3706  }
3707  he->p.argv[ac] = NULL;
3708 /*@=compmempass@*/
3709  rc = 0;
3710 
3711 exit:
3712 /*@-kepttrans@*/ /* N.argv may be kept. */
3713  N.argv = _free(N.argv);
3714 /*@=kepttrans@*/
3715 /*@-usereleased@*/ /* EVR.argv may be dead. */
3716  EVR.argv = _free(EVR.argv);
3717 /*@=usereleased@*/
3718  F.ui32p = _free(F.ui32p);
3719  return rc;
3720 }
3721 
3722 static int PsqlTag(Header h, HE_t he)
3723  /*@globals internalState @*/
3724  /*@modifies he, internalState @*/
3725 {
3726  he->tag = RPMTAG_PROVIDENAME;
3728 }
3729 
3730 static int RsqlTag(Header h, HE_t he)
3731  /*@globals internalState @*/
3732  /*@modifies he, internalState @*/
3733 {
3734  he->tag = RPMTAG_REQUIRENAME;
3736 }
3737 
3738 static int CsqlTag(Header h, HE_t he)
3739  /*@globals internalState @*/
3740  /*@modifies he, internalState @*/
3741 {
3742  he->tag = RPMTAG_CONFLICTNAME;
3744 }
3745 
3746 static int OsqlTag(Header h, HE_t he)
3747  /*@globals internalState @*/
3748  /*@modifies he, internalState @*/
3749 {
3750  he->tag = RPMTAG_OBSOLETENAME;
3752 }
3753 
3754 static int PRCOyamlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3755  /*@globals internalState @*/
3756  /*@modifies he, internalState @*/
3757 {
3758  rpmTag tag = he->tag;
3759  rpmTagData N = { .ptr = NULL };
3760  rpmTagData EVR = { .ptr = NULL };
3761  rpmTagData F = { .ptr = NULL };
3762  size_t nb;
3763  rpmuint32_t ac;
3764  rpmuint32_t c;
3765  rpmuint32_t i;
3766  char *t;
3767  int rc = 1; /* assume failure */
3768  int xx;
3769 int indent = 0;
3770 spew_t spew = &_yaml_spew;
3771 
3772 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3773  xx = headerGet(h, he, 0);
3774  if (xx == 0) goto exit;
3775  N.argv = he->p.argv;
3776  c = he->c;
3777 
3778  he->tag = EVRtag;
3779  xx = headerGet(h, he, 0);
3780  if (xx == 0) goto exit;
3781  EVR.argv = he->p.argv;
3782 
3783  he->tag = Ftag;
3784  xx = headerGet(h, he, 0);
3785  if (xx == 0) goto exit;
3786  F.ui32p = he->p.ui32p;
3787 
3788  nb = sizeof(*he->p.argv);
3789  ac = 0;
3790  for (i = 0; i < c; i++) {
3791 /*@-nullstate@*/ /* EVR.argv might be NULL */
3792  if (PRCOSkip(tag, N, EVR, F, i))
3793  continue;
3794 /*@=nullstate@*/
3795  ac++;
3796  nb += sizeof(*he->p.argv);
3797  nb += sizeof("- ");
3798  if (*N.argv[i] == '/')
3799  nb += spew->spew_strlen(N.argv[i], indent);
3800  else
3801  nb += strlen(N.argv[i]);
3802  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3803  nb += sizeof(" >= ") - 1;
3804  nb += strlen(EVR.argv[i]);
3805  }
3806  }
3807 
3808  he->t = RPM_STRING_ARRAY_TYPE;
3809  he->c = ac;
3810  he->freeData = 1;
3811  he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
3812  t = (char *) &he->p.argv[he->c + 1];
3813  ac = 0;
3814  for (i = 0; i < c; i++) {
3815 /*@-nullstate@*/ /* EVR.argv might be NULL */
3816  if (PRCOSkip(tag, N, EVR, F, i))
3817  continue;
3818 /*@=nullstate@*/
3819  he->p.argv[ac++] = t;
3820  t = stpcpy(t, "- ");
3821  if (*N.argv[i] == '/') {
3822  t = spew->spew_strcpy(t, N.argv[i], indent); t += strlen(t);
3823  } else
3824  t = stpcpy(t, N.argv[i]);
3825 /*@-readonlytrans@*/
3826  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3827  static char *Fstr[] = { "?0","<",">","?3","=","<=",">=","?7" };
3828  rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3829  t = stpcpy( stpcpy( stpcpy(t, " "), Fstr[Fx]), " ");
3830  t = stpcpy(t, EVR.argv[i]);
3831  }
3832 /*@=readonlytrans@*/
3833  *t++ = '\0';
3834  }
3835  he->p.argv[he->c] = NULL;
3836 /*@=compmempass@*/
3837  rc = 0;
3838 
3839 exit:
3840 /*@-kepttrans@*/ /* N.argv may be kept. */
3841  N.argv = _free(N.argv);
3842 /*@=kepttrans@*/
3843 /*@-usereleased@*/ /* EVR.argv may be dead. */
3844  EVR.argv = _free(EVR.argv);
3845 /*@=usereleased@*/
3846  F.ui32p = _free(F.ui32p);
3847  return rc;
3848 }
3849 
3850 static int PyamlTag(Header h, HE_t he)
3851  /*@globals internalState @*/
3852  /*@modifies he, internalState @*/
3853 {
3854  int rc;
3855  he->tag = RPMTAG_PROVIDENAME;
3858  return rc;
3859 }
3860 
3861 static int RyamlTag(Header h, HE_t he)
3862  /*@globals internalState @*/
3863  /*@modifies he, internalState @*/
3864 {
3865  int rc;
3866  he->tag = RPMTAG_REQUIRENAME;
3869  return rc;
3870 }
3871 
3872 static int CyamlTag(Header h, HE_t he)
3873  /*@globals internalState @*/
3874  /*@modifies he, internalState @*/
3875 {
3876  int rc;
3877  he->tag = RPMTAG_CONFLICTNAME;
3880  return rc;
3881 }
3882 
3883 static int OyamlTag(Header h, HE_t he)
3884  /*@globals internalState @*/
3885  /*@modifies he, internalState @*/
3886 {
3887  int rc;
3888  he->tag = RPMTAG_OBSOLETENAME;
3891  return rc;
3892 }
3893 
3895  /*@*/
3896 {
3897  const char * dn = DN.argv[DI.ui32p[i]];
3898  size_t dnlen = strlen(dn);
3899 
3900 assert(dn != NULL);
3901  if (strstr(dn, "bin/") != NULL)
3902  return 1;
3903  if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen))
3904  return 1;
3905  if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail"))
3906  return 1;
3907  return 2;
3908 }
3909 
3910 static int FDGxmlTag(Header h, HE_t he, int lvl)
3911  /*@globals internalState @*/
3912  /*@modifies he, internalState @*/
3913 {
3914  rpmTagData BN = { .ptr = NULL };
3915  rpmTagData DN = { .ptr = NULL };
3916  rpmTagData DI = { .ptr = NULL };
3917  rpmTagData FMODES = { .ptr = NULL };
3918  rpmTagData FFLAGS = { .ptr = NULL };
3919  size_t nb;
3920  rpmuint32_t ac;
3921  rpmuint32_t c;
3922  rpmuint32_t i;
3923  char *t;
3924  int rc = 1; /* assume failure */
3925  int xx;
3926 spew_t spew = &_xml_spew;
3927 
3928 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3929  he->tag = RPMTAG_BASENAMES;
3930  xx = headerGet(h, he, 0);
3931  if (xx == 0) goto exit;
3932  BN.argv = he->p.argv;
3933  c = he->c;
3934 
3935  he->tag = RPMTAG_DIRNAMES;
3936  xx = headerGet(h, he, 0);
3937  if (xx == 0) goto exit;
3938  DN.argv = he->p.argv;
3939 
3940  he->tag = RPMTAG_DIRINDEXES;
3941  xx = headerGet(h, he, 0);
3942  if (xx == 0) goto exit;
3943  DI.ui32p = he->p.ui32p;
3944 
3945  he->tag = RPMTAG_FILEMODES;
3946  xx = headerGet(h, he, 0);
3947  if (xx == 0) goto exit;
3948  FMODES.ui16p = he->p.ui16p;
3949 
3950  he->tag = RPMTAG_FILEFLAGS;
3951  xx = headerGet(h, he, 0);
3952  if (xx == 0) goto exit;
3953  FFLAGS.ui32p = he->p.ui32p;
3954 
3955  nb = sizeof(*he->p.argv);
3956  ac = 0;
3957  for (i = 0; i < c; i++) {
3958  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3959  continue;
3960  ac++;
3961  nb += sizeof(*he->p.argv);
3962  nb += sizeof("<file></file>");
3963  nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], lvl);
3964  nb += spew->spew_strlen(BN.argv[i], lvl);
3965  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3966  nb += sizeof(" type=\"ghost\"") - 1;
3967  else if (S_ISDIR(FMODES.ui16p[i])) {
3968  nb += sizeof(" type=\"dir\"") - 1;
3969 #ifdef NOTYET
3970  nb += sizeof("/") - 1;
3971 #endif
3972  }
3973  }
3974 
3975  he->t = RPM_STRING_ARRAY_TYPE;
3976  he->c = ac;
3977  he->freeData = 1;
3978  he->p.argv = xmalloc(nb);
3979  t = (char *) &he->p.argv[he->c + 1];
3980  ac = 0;
3981  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
3982  for (i = 0; i < c; i++) {
3983  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3984  continue;
3985  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3986  continue;
3987  if (S_ISDIR(FMODES.ui16p[i]))
3988  continue;
3989  he->p.argv[ac++] = t;
3990  t = stpcpy(t, "<file>");
3991  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t);
3992  t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t);
3993  t = stpcpy(t, "</file>");
3994  *t++ = '\0';
3995  }
3996  for (i = 0; i < c; i++) {
3997  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3998  continue;
3999  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4000  continue;
4001  if (!S_ISDIR(FMODES.ui16p[i]))
4002  continue;
4003  he->p.argv[ac++] = t;
4004  t = stpcpy(t, "<file type=\"dir\">");
4005  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t);
4006  t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t);
4007 #ifdef NOTYET
4008  /* Append the pesky trailing / to directories. */
4009  if (t[-1] != '/')
4010  t = stpcpy(t, "/");
4011 #endif
4012  t = stpcpy(t, "</file>");
4013  *t++ = '\0';
4014  }
4015  for (i = 0; i < c; i++) {
4016  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4017  continue;
4018  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
4019  continue;
4020  he->p.argv[ac++] = t;
4021  t = stpcpy(t, "<file type=\"ghost\">");
4022  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], lvl); t += strlen(t);
4023  t = spew->spew_strcpy(t, BN.argv[i], lvl); t += strlen(t);
4024  t = stpcpy(t, "</file>");
4025  *t++ = '\0';
4026  }
4027 
4028  he->p.argv[he->c] = NULL;
4029 /*@=compmempass@*/
4030  rc = 0;
4031 
4032 exit:
4033 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
4034  BN.argv = _free(BN.argv);
4035 /*@-usereleased@*/ /* DN.argv may be dead. */
4036  DN.argv = _free(DN.argv);
4037 /*@=usereleased@*/
4038  DI.ui32p = _free(DI.ui32p);
4039 /*@=kepttrans@*/
4040  FMODES.ui16p = _free(FMODES.ui16p);
4041 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
4042  FFLAGS.ui32p = _free(FFLAGS.ui32p);
4043 /*@=usereleased@*/
4044  return rc;
4045 }
4046 
4047 static int F1xmlTag(Header h, HE_t he)
4048  /*@globals internalState @*/
4049  /*@modifies he, internalState @*/
4050 {
4051  he->tag = RPMTAG_BASENAMES;
4052  return FDGxmlTag(h, he, 1);
4053 }
4054 
4055 static int F2xmlTag(Header h, HE_t he)
4056  /*@globals internalState @*/
4057  /*@modifies he, internalState @*/
4058 {
4059  he->tag = RPMTAG_BASENAMES;
4060  return FDGxmlTag(h, he, 2);
4061 }
4062 
4063 static int FDGsqlTag(Header h, HE_t he, int lvl)
4064  /*@globals internalState @*/
4065  /*@modifies he, internalState @*/
4066 {
4067  rpmTagData BN = { .ptr = NULL };
4068  rpmTagData DN = { .ptr = NULL };
4069  rpmTagData DI = { .ptr = NULL };
4070  rpmTagData FMODES = { .ptr = NULL };
4071  rpmTagData FFLAGS = { .ptr = NULL };
4072  char instance[64];
4073  size_t nb;
4074  rpmuint32_t ac;
4075  rpmuint32_t c;
4076  rpmuint32_t i;
4077  char *t;
4078  int rc = 1; /* assume failure */
4079  int xx;
4080 
4081 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
4082  he->tag = RPMTAG_BASENAMES;
4083  xx = headerGet(h, he, 0);
4084  if (xx == 0) goto exit;
4085  BN.argv = he->p.argv;
4086  c = he->c;
4087 
4088  he->tag = RPMTAG_DIRNAMES;
4089  xx = headerGet(h, he, 0);
4090  if (xx == 0) goto exit;
4091  DN.argv = he->p.argv;
4092 
4093  he->tag = RPMTAG_DIRINDEXES;
4094  xx = headerGet(h, he, 0);
4095  if (xx == 0) goto exit;
4096  DI.ui32p = he->p.ui32p;
4097 
4098  he->tag = RPMTAG_FILEMODES;
4099  xx = headerGet(h, he, 0);
4100  if (xx == 0) goto exit;
4101  FMODES.ui16p = he->p.ui16p;
4102 
4103  he->tag = RPMTAG_FILEFLAGS;
4104  xx = headerGet(h, he, 0);
4105  if (xx == 0) goto exit;
4106  FFLAGS.ui32p = he->p.ui32p;
4107 
4108  xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
4109  nb = sizeof(*he->p.argv);
4110  ac = 0;
4111  for (i = 0; i < c; i++) {
4112  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4113  continue;
4114  ac++;
4115  nb += sizeof(*he->p.argv);
4116  nb += strlen(instance) + sizeof(", '', ''");
4117  nb += strlen(DN.argv[DI.ui32p[i]]);
4118  nb += strlen(BN.argv[i]);
4119  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4120  nb += sizeof("ghost") - 1;
4121  else if (S_ISDIR(FMODES.ui16p[i])) {
4122  nb += sizeof("dir") - 1;
4123 #ifdef NOTYET
4124  nb += sizeof("/") - 1;
4125 #endif
4126  } else
4127  nb += sizeof("file") - 1;
4128  }
4129 
4130  he->t = RPM_STRING_ARRAY_TYPE;
4131  he->c = ac;
4132  he->freeData = 1;
4133  he->p.argv = xmalloc(nb);
4134  t = (char *) &he->p.argv[he->c + 1];
4135  ac = 0;
4136  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
4137  for (i = 0; i < c; i++) {
4138  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4139  continue;
4140  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4141  continue;
4142  if (S_ISDIR(FMODES.ui16p[i]))
4143  continue;
4144  he->p.argv[ac++] = t;
4145  t = stpcpy( stpcpy(t, instance), ", '");
4146  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
4147  t = strcpy(t, BN.argv[i]); t += strlen(t);
4148  t = stpcpy(t, "', 'file'");
4149  *t++ = '\0';
4150  }
4151  for (i = 0; i < c; i++) {
4152  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4153  continue;
4154  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4155  continue;
4156  if (!S_ISDIR(FMODES.ui16p[i]))
4157  continue;
4158  he->p.argv[ac++] = t;
4159  t = stpcpy( stpcpy(t, instance), ", '");
4160  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
4161  t = strcpy(t, BN.argv[i]); t += strlen(t);
4162 #ifdef NOTYET
4163  /* Append the pesky trailing / to directories. */
4164  if (t[-1] != '/')
4165  t = stpcpy(t, "/");
4166 #endif
4167  t = stpcpy(t, "', 'dir'");
4168  *t++ = '\0';
4169  }
4170  for (i = 0; i < c; i++) {
4171  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4172  continue;
4173  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
4174  continue;
4175  he->p.argv[ac++] = t;
4176  t = stpcpy( stpcpy(t, instance), ", '");
4177  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
4178  t = strcpy(t, BN.argv[i]); t += strlen(t);
4179  t = stpcpy(t, "', 'ghost'");
4180  *t++ = '\0';
4181  }
4182 
4183  he->p.argv[he->c] = NULL;
4184 /*@=compmempass@*/
4185  rc = 0;
4186 
4187 exit:
4188 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
4189  BN.argv = _free(BN.argv);
4190 /*@-usereleased@*/ /* DN.argv may be dead. */
4191  DN.argv = _free(DN.argv);
4192 /*@=usereleased@*/
4193  DI.ui32p = _free(DI.ui32p);
4194 /*@=kepttrans@*/
4195  FMODES.ui16p = _free(FMODES.ui16p);
4196 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
4197  FFLAGS.ui32p = _free(FFLAGS.ui32p);
4198 /*@=usereleased@*/
4199  return rc;
4200 }
4201 
4202 static int F1sqlTag(Header h, HE_t he)
4203  /*@globals internalState @*/
4204  /*@modifies he, internalState @*/
4205 {
4206  he->tag = RPMTAG_BASENAMES;
4207  return FDGsqlTag(h, he, 1);
4208 }
4209 
4210 static int F2sqlTag(Header h, HE_t he)
4211  /*@globals internalState @*/
4212  /*@modifies he, internalState @*/
4213 {
4214  he->tag = RPMTAG_BASENAMES;
4215  return FDGsqlTag(h, he, 2);
4216 }
4217 
4218 static int FDGyamlTag(Header h, HE_t he, int lvl)
4219  /*@globals internalState @*/
4220  /*@modifies he, internalState @*/
4221 {
4222  rpmTagData BN = { .ptr = NULL };
4223  rpmTagData DN = { .ptr = NULL };
4224  rpmTagData DI = { .ptr = NULL };
4225  rpmTagData FMODES = { .ptr = NULL };
4226  rpmTagData FFLAGS = { .ptr = NULL };
4227  size_t nb;
4228  rpmuint32_t ac;
4229  rpmuint32_t c;
4230  rpmuint32_t i;
4231  char *t;
4232  int rc = 1; /* assume failure */
4233  int xx;
4234 int indent = 0;
4235 spew_t spew = &_yaml_spew;
4236 
4237 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
4238  he->tag = RPMTAG_BASENAMES;
4239  xx = headerGet(h, he, 0);
4240  if (xx == 0) goto exit;
4241  BN.argv = he->p.argv;
4242  c = he->c;
4243 
4244  he->tag = RPMTAG_DIRNAMES;
4245  xx = headerGet(h, he, 0);
4246  if (xx == 0) goto exit;
4247  DN.argv = he->p.argv;
4248 
4249  he->tag = RPMTAG_DIRINDEXES;
4250  xx = headerGet(h, he, 0);
4251  if (xx == 0) goto exit;
4252  DI.ui32p = he->p.ui32p;
4253 
4254  he->tag = RPMTAG_FILEMODES;
4255  xx = headerGet(h, he, 0);
4256  if (xx == 0) goto exit;
4257  FMODES.ui16p = he->p.ui16p;
4258 
4259  he->tag = RPMTAG_FILEFLAGS;
4260  xx = headerGet(h, he, 0);
4261  if (xx == 0) goto exit;
4262  FFLAGS.ui32p = he->p.ui32p;
4263 
4264  nb = sizeof(*he->p.argv);
4265  ac = 0;
4266  for (i = 0; i < c; i++) {
4267  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4268  continue;
4269  ac++;
4270  nb += sizeof(*he->p.argv);
4271  nb += sizeof("- ");
4272  nb += spew->spew_strlen(DN.argv[DI.ui32p[i]], indent);
4273  nb += spew->spew_strlen(BN.argv[i], indent);
4274  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4275  nb += sizeof("") - 1;
4276  else if (S_ISDIR(FMODES.ui16p[i]))
4277  nb += sizeof("/") - 1;
4278  }
4279 
4280  he->t = RPM_STRING_ARRAY_TYPE;
4281  he->c = ac;
4282  he->freeData = 1;
4283  he->p.argv = xmalloc(nb);
4284  t = (char *) &he->p.argv[he->c + 1];
4285  ac = 0;
4286  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
4287  for (i = 0; i < c; i++) {
4288  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4289  continue;
4290  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4291  continue;
4292  if (S_ISDIR(FMODES.ui16p[i]))
4293  continue;
4294  he->p.argv[ac++] = t;
4295  t = stpcpy(t, "- ");
4296  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
4297  t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t);
4298  t = stpcpy(t, "");
4299  *t++ = '\0';
4300  }
4301  for (i = 0; i < c; i++) {
4302  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4303  continue;
4304  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
4305  continue;
4306  if (!S_ISDIR(FMODES.ui16p[i]))
4307  continue;
4308  he->p.argv[ac++] = t;
4309  t = stpcpy(t, "- ");
4310  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
4311  t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t);
4312  /* Append the pesky trailing / to directories. */
4313  if (t[-1] != '/')
4314  t = stpcpy(t, "/");
4315  *t++ = '\0';
4316  }
4317  for (i = 0; i < c; i++) {
4318  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
4319  continue;
4320  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
4321  continue;
4322  he->p.argv[ac++] = t;
4323  t = stpcpy(t, "- ");
4324  t = spew->spew_strcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
4325  t = spew->spew_strcpy(t, BN.argv[i], indent); t += strlen(t);
4326  *t++ = '\0';
4327  }
4328 
4329  he->p.argv[he->c] = NULL;
4330 /*@=compmempass@*/
4331  rc = 0;
4332 
4333 exit:
4334 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
4335  BN.argv = _free(BN.argv);
4336 /*@-usereleased@*/ /* DN.argv may be dead. */
4337  DN.argv = _free(DN.argv);
4338 /*@=usereleased@*/
4339  DI.ui32p = _free(DI.ui32p);
4340 /*@=kepttrans@*/
4341  FMODES.ui16p = _free(FMODES.ui16p);
4342 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
4343  FFLAGS.ui32p = _free(FFLAGS.ui32p);
4344 /*@=usereleased@*/
4345  return rc;
4346 }
4347 
4348 static int F1yamlTag(Header h, HE_t he)
4349  /*@globals internalState @*/
4350  /*@modifies he, internalState @*/
4351 {
4352  he->tag = RPMTAG_BASENAMES;
4353  return FDGyamlTag(h, he, 1);
4354 }
4355 
4356 static int F2yamlTag(Header h, HE_t he)
4357  /*@globals internalState @*/
4358  /*@modifies he, internalState @*/
4359 {
4360  he->tag = RPMTAG_BASENAMES;
4361  return FDGyamlTag(h, he, 2);
4362 }
4363 
4370 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av)
4371  /*@*/
4372 {
4373  char * val;
4374 
4375  if (he->t != RPM_STRING_TYPE) {
4376  val = xstrdup(_("(not a string)"));
4377  } else {
4378  const char * bn;
4379  const char * s;
4380  size_t nb;
4381  char * t;
4382 int lvl = 0;
4383 spew_t spew = &_xml_spew;
4384 
4385 assert(he->p.str != NULL);
4386  /* Get rightmost '/' in string (i.e. basename(3) behavior). */
4387  if ((bn = strrchr(he->p.str, '/')) != NULL)
4388  bn++;
4389  else
4390  bn = he->p.str;
4391 
4392  s = strdup_iconv_check(bn, (av ? av[0] : NULL));
4393  nb = spew->spew_strlen(s, lvl);
4394  t = xmalloc(nb + 1);
4395  val = t;
4396  t = spew->spew_strcpy(t, s, lvl); t += strlen(t);
4397  *t = '\0';
4398  s = _free(s);
4399  }
4400 
4401  return val;
4402 }
4403 
4404 typedef struct key_s {
4405 /*@observer@*/
4406  const char *name; /* key name */
4408 } KEY;
4409 
4410 /*@unchecked@*/ /*@observer@*/
4411 static KEY keyDigests[] = {
4412  { "adler32", PGPHASHALGO_ADLER32 },
4413  { "crc32", PGPHASHALGO_CRC32 },
4414  { "crc64", PGPHASHALGO_CRC64 },
4415  { "haval160", PGPHASHALGO_HAVAL_5_160 },
4416  { "jlu32", PGPHASHALGO_JLU32 },
4417  { "md2", PGPHASHALGO_MD2 },
4418  { "md4", PGPHASHALGO_MD4 },
4419  { "md5", PGPHASHALGO_MD5 },
4420  { "rmd128", PGPHASHALGO_RIPEMD128 },
4421  { "rmd160", PGPHASHALGO_RIPEMD160 },
4422  { "rmd256", PGPHASHALGO_RIPEMD256 },
4423  { "rmd320", PGPHASHALGO_RIPEMD320 },
4424  { "salsa10", PGPHASHALGO_SALSA10 },
4425  { "salsa20", PGPHASHALGO_SALSA20 },
4426  { "sha1", PGPHASHALGO_SHA1 },
4427  { "sha224", PGPHASHALGO_SHA224 },
4428  { "sha256", PGPHASHALGO_SHA256 },
4429  { "sha384", PGPHASHALGO_SHA384 },
4430  { "sha512", PGPHASHALGO_SHA512 },
4431  { "tiger192", PGPHASHALGO_TIGER192 },
4432 };
4433 /*@unchecked@*/
4434 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]);
4435 
4441  STAT_KEYS_DEV = (1U << 0),
4442  STAT_KEYS_INO = (1U << 1),
4443  STAT_KEYS_MODE = (1U << 2),
4444  STAT_KEYS_NLINK = (1U << 3),
4445  STAT_KEYS_UID = (1U << 4),
4446  STAT_KEYS_GID = (1U << 5),
4447  STAT_KEYS_RDEV = (1U << 6),
4448  STAT_KEYS_SIZE = (1U << 7),
4449  STAT_KEYS_BLKSIZE = (1U << 8),
4450  STAT_KEYS_BLOCKS = (1U << 9),
4451  STAT_KEYS_ATIME = (1U << 10),
4452  STAT_KEYS_CTIME = (1U << 11),
4453  STAT_KEYS_MTIME = (1U << 12),
4454 #ifdef NOTYET
4455  STAT_KEYS_FLAGS = (1U << 13),
4456 #endif
4457  STAT_KEYS_SLINK = (1U << 14),
4458  STAT_KEYS_DIGEST = (1U << 15),
4459 #ifdef NOTYET
4460  STAT_KEYS_FCONTEXT = (1U << 16),
4461 #endif
4462  STAT_KEYS_UNAME = (1U << 17),
4463  STAT_KEYS_GNAME = (1U << 18),
4464 };
4465 
4466 /*@unchecked@*/ /*@observer@*/
4467 static KEY keyStat[] = {
4468  { "adler32", STAT_KEYS_DIGEST },
4469  { "atime", STAT_KEYS_ATIME },
4470  { "ctime", STAT_KEYS_CTIME },
4471  { "blksize", STAT_KEYS_BLKSIZE },
4472  { "blocks", STAT_KEYS_BLOCKS },
4473  { "crc32", STAT_KEYS_DIGEST },
4474  { "crc64", STAT_KEYS_DIGEST },
4475  { "dev", STAT_KEYS_DEV },
4476 #ifdef NOTYET
4477  { "digest", STAT_KEYS_DIGEST },
4478  { "fcontext", STAT_KEYS_FCONTEXT },
4479  { "flags", STAT_KEYS_FLAGS },
4480 #endif
4481  { "gid", STAT_KEYS_GID },
4482  { "gname", STAT_KEYS_GNAME },
4483  { "haval160", STAT_KEYS_DIGEST },
4484  { "ino", STAT_KEYS_INO },
4485  { "jlu32", STAT_KEYS_DIGEST },
4486  { "link", STAT_KEYS_SLINK },
4487  { "md2", STAT_KEYS_DIGEST },
4488  { "md4", STAT_KEYS_DIGEST },
4489  { "md5", STAT_KEYS_DIGEST },
4490  { "mode", STAT_KEYS_MODE },
4491  { "mtime", STAT_KEYS_MTIME },
4492  { "nlink", STAT_KEYS_NLINK },
4493  { "rdev", STAT_KEYS_RDEV },
4494  { "rmd128", STAT_KEYS_DIGEST },
4495  { "rmd160", STAT_KEYS_DIGEST },
4496  { "rmd256", STAT_KEYS_DIGEST },
4497  { "rmd320", STAT_KEYS_DIGEST },
4498  { "salsa10", STAT_KEYS_DIGEST },
4499  { "salsa20", STAT_KEYS_DIGEST },
4500  { "sha1", STAT_KEYS_DIGEST },
4501  { "sha224", STAT_KEYS_DIGEST },
4502  { "sha256", STAT_KEYS_DIGEST },
4503  { "sha384", STAT_KEYS_DIGEST },
4504  { "sha512", STAT_KEYS_DIGEST },
4505  { "size", STAT_KEYS_SIZE },
4506  { "tiger192", STAT_KEYS_DIGEST },
4507  { "uid", STAT_KEYS_UID },
4508  { "uname", STAT_KEYS_UNAME },
4509 };
4510 /*@unchecked@*/
4511 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]);
4512 
4517  UUID_KEYS_NONE = (0U << 0),
4518  UUID_KEYS_V1 = (1U << 0),
4519  UUID_KEYS_V3 = (3U << 0),
4520  UUID_KEYS_V4 = (4U << 0),
4521  UUID_KEYS_V5 = (5U << 0),
4522 #ifdef NOTYET
4523  UUID_KEYS_STRING = (0U << 4),
4524  UUID_KEYS_SIV = (1U << 4),
4525  UUID_KEYS_BINARY = (2U << 4),
4526  UUID_KEYS_TEXT = (3U << 4),
4527 #endif
4528 };
4529 
4530 /*@unchecked@*/ /*@observer@*/
4531 static KEY keyUuids[] = {
4532 #ifdef NOTYET
4533  { "binary", UUID_KEYS_BINARY },
4534  { "siv", UUID_KEYS_SIV },
4535  { "string", UUID_KEYS_STRING },
4536  { "text", UUID_KEYS_TEXT },
4537 #endif
4538  { "v1", UUID_KEYS_V1 },
4539  { "v3", UUID_KEYS_V3 },
4540  { "v4", UUID_KEYS_V4 },
4541  { "v5", UUID_KEYS_V5 },
4542 };
4543 /*@unchecked@*/
4544 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]);
4545 
4548 static int
4549 keyCmp(const void * a, const void * b)
4550  /*@*/
4551 {
4552  return strcmp(((KEY *)a)->name, ((KEY *)b)->name);
4553 }
4554 
4557 static rpmuint32_t
4558 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name)
4559  /*@*/
4560 {
4561  rpmuint32_t keyval = 0;
4562 
4563  if (name && * name) {
4564  KEY needle = { .name = name, .value = 0 };
4565  KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp);
4566  if (k)
4567  keyval = k->value;
4568  }
4569  return keyval;
4570 }
4571 
4578 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av)
4579  /*@*/
4580 {
4581  int ix = (he->ix > 0 ? he->ix : 0);
4582  char * val = NULL;
4583  size_t ns;
4584 
4585 assert(ix == 0);
4586  switch(he->t) {
4587  default:
4588  val = xstrdup(_("(invalid type :digest)"));
4589  goto exit;
4590  /*@notreached@*/ break;
4591  case RPM_UINT64_TYPE:
4592  ns = sizeof(he->p.ui64p[0]);
4593  break;
4594  case RPM_STRING_TYPE:
4595  ns = strlen(he->p.str);
4596  break;
4597  case RPM_BIN_TYPE:
4598  ns = he->c;
4599  break;
4600  }
4601 
4602 assert(he->p.ptr != NULL);
4603  { rpmuint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL));
4604  rpmuint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1);
4605  DIGEST_CTX ctx = rpmDigestInit(algo, 0);
4606  int xx = rpmDigestUpdate(ctx, he->p.ptr, ns);
4607  xx = rpmDigestFinal(ctx, &val, NULL, 1);
4608  }
4609 
4610 exit:
4611  return val;
4612 }
4613 
4620 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av)
4621  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
4622  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
4623 {
4624 /*@-nullassign@*/
4625  /*@unchecked@*/ /*@observer@*/
4626  static const char *avdefault[] = { "mode", NULL };
4627 /*@=nullassign@*/
4628  const char * fn = NULL;
4629  struct stat sb, *st = &sb;
4630  int ix = (he->ix > 0 ? he->ix : 0);
4631  char * val = NULL;
4632  int xx;
4633  int i;
4634 
4635  memset(st, 0, sizeof(*st));
4636 assert(ix == 0);
4637  switch(he->t) {
4638  case RPM_BIN_TYPE:
4639  /* XXX limit to RPMTAG_PACKAGESTAT ... */
4640  if (he->tag == RPMTAG_PACKAGESTAT)
4641  if ((size_t)he->c == sizeof(*st)) {
4642  st = (struct stat *)he->p.ptr;
4643  break;
4644  }
4645  /*@fallthrough @*/
4646  default:
4647  val = xstrdup(_("(invalid type :stat)"));
4648  goto exit;
4649  /*@notreached@*/ break;
4650  case RPM_STRING_TYPE:
4651  fn = he->p.str;
4652  if (Lstat(fn, st) == 0)
4653  break;
4654 /*@-ownedtrans@*/
4655  val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL);
4656 /*@=ownedtrans@*/
4657  goto exit;
4658  /*@notreached@*/ break;
4659  }
4660 
4661  if (!(av && av[0] && *av[0]))
4662  av = avdefault;
4663  for (i = 0; av[i] != NULL; i++) {
4664  char b[BUFSIZ+1]; /* XXX coverity #103583 */
4665  size_t nb = sizeof(b)-1;
4666  char * nval;
4667  rpmuint32_t keyval = keyValue(keyStat, nkeyStat, av[i]);
4668 
4669  nval = NULL;
4670  b[0] = '\0';
4671  switch (keyval) {
4672  default:
4673  /*@switchbreak@*/ break;
4674  case STAT_KEYS_NONE:
4675  /*@switchbreak@*/ break;
4676  case STAT_KEYS_DEV:
4677  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev);
4678  /*@switchbreak@*/ break;
4679  case STAT_KEYS_INO:
4680  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino);
4681  /*@switchbreak@*/ break;
4682  case STAT_KEYS_MODE:
4683  xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode);
4684  /*@switchbreak@*/ break;
4685  case STAT_KEYS_NLINK:
4686  xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink);
4687  /*@switchbreak@*/ break;
4688  case STAT_KEYS_UID:
4689  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid);
4690  /*@switchbreak@*/ break;
4691  case STAT_KEYS_GID:
4692  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid);
4693  /*@switchbreak@*/ break;
4694  case STAT_KEYS_RDEV:
4695  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev);
4696  /*@switchbreak@*/ break;
4697  case STAT_KEYS_SIZE:
4698  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size);
4699  /*@switchbreak@*/ break;
4700  case STAT_KEYS_BLKSIZE:
4701  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize);
4702  /*@switchbreak@*/ break;
4703  case STAT_KEYS_BLOCKS:
4704  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks);
4705  /*@switchbreak@*/ break;
4706  case STAT_KEYS_ATIME:
4707 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_atime));
4708  /*@switchbreak@*/ break;
4709  case STAT_KEYS_CTIME:
4710 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_ctime));
4711  /*@switchbreak@*/ break;
4712  case STAT_KEYS_MTIME:
4713 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_mtime));
4714  /*@switchbreak@*/ break;
4715 #ifdef NOTYET
4716  case STAT_KEYS_FLAGS:
4717  /*@switchbreak@*/ break;
4718 #endif
4719  case STAT_KEYS_SLINK:
4720  if (fn != NULL && S_ISLNK(st->st_mode)) {
4721  ssize_t size = Readlink(fn, b, nb);
4722  if (size == -1) {
4723  nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL);
4724  (void) stpcpy(b, nval);
4725  nval = _free(nval);
4726  } else
4727  b[size] = '\0';
4728  }
4729  /*@switchbreak@*/ break;
4730  case STAT_KEYS_DIGEST:
4731  if (fn != NULL && S_ISREG(st->st_mode)) {
4732  rpmuint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]);
4733  rpmuint32_t algo = (digval ? digval : PGPHASHALGO_SHA1);
4734  FD_t fd = Fopen(fn, "r%{?_rpmgio}");
4735  if (fd == NULL || Ferror(fd)) {
4736  nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL);
4737  } else {
4738  static int asAscii = 1;
4739  char buffer[16 * 1024];
4740  fdInitDigest(fd, algo, 0);
4741  while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
4742  {};
4743  if (Ferror(fd))
4744  nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL);
4745  else
4746  fdFiniDigest(fd, algo, &nval, NULL, asAscii);
4747  }
4748  if (nval) {
4749  (void) stpcpy(b, nval);
4750  nval = _free(nval);
4751  }
4752  if (fd != NULL)
4753  xx = Fclose(fd);
4754  }
4755  /*@switchbreak@*/ break;
4756  case STAT_KEYS_UNAME:
4757  { const char * uname = uidToUname(st->st_uid);
4758  if (uname != NULL)
4759  (void) stpcpy(b, uname);
4760  else
4761  xx = snprintf(b, nb, "%u", (unsigned)st->st_uid);
4762  } /*@switchbreak@*/ break;
4763  case STAT_KEYS_GNAME:
4764  { const char * gname = gidToGname(st->st_gid);
4765  if (gname != NULL)
4766  (void) stpcpy(b, gname);
4767  else
4768  xx = snprintf(b, nb, "%u", (unsigned)st->st_gid);
4769  } /*@switchbreak@*/ break;
4770  }
4771  if (b[0] == '\0')
4772  continue;
4773  b[nb-1] = '\0';
4774 
4775  if (val == NULL)
4776  val = xstrdup(b);
4777  else {
4778  nval = rpmExpand(val, " | ", b, NULL);
4779  val = _free(val);
4780  val = nval;
4781  }
4782  }
4783 
4784 exit:
4785  return val;
4786 }
4787 
4794 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av)
4795  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
4796  /*@modifies rpmGlobalMacroContext, internalState @*/
4797 {
4798  static const char hex[] = "0123456789abcdef";
4799  /* XXX use private tag container to avoid memory issues for now. */
4800  HE_t nhe = (HE_t) memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
4801 /*@-nullassign@*/
4802  /*@unchecked@*/ /*@observer@*/
4803  static const char *avdefault[] = { "v5", NULL };
4804 /*@=nullassign@*/
4805  int ix = (he->ix > 0 ? he->ix : 0);
4806  char * val = NULL;
4807  struct timeval tv;
4808  char * t;
4809  char * te;
4810  uint32_t i;
4811 
4812 assert(ix == 0);
4813  val = xmalloc((128/4 + 4) + 1);
4814  *val = '\0';
4815 
4816  nhe->tag = he->tag;
4817  nhe->t = he->t;
4818  switch(he->t) {
4819  default:
4820  val = _free(val);
4821  val = xstrdup(_("(invalid type :uuid)"));
4822  goto exit;
4823  /*@notreached@*/ break;
4824  case RPM_UINT64_TYPE:
4825  /* XXX Limit to tag time stamps with UUIDv1 direct conversion. */
4826  switch (he->tag) {
4827  default:
4828  val = _free(val);
4829  val = xstrdup(_("(invalid tag :uuid)"));
4830  goto exit;
4831  break;
4832  case RPMTAG_INSTALLTIME:
4833  case RPMTAG_BUILDTIME:
4834  case RPMTAG_ORIGINTIME:
4835  case RPMTAG_INSTALLTID:
4836  case RPMTAG_REMOVETID:
4837  case RPMTAG_ORIGINTID:
4838 
4839  /* Convert tag time stamp to UUIDv1. */
4840  tv.tv_sec = (long) he->p.ui64p[0];
4841  tv.tv_usec = (long) (he->c > 1 ? he->p.ui64p[1] : 0);
4842  ix = tv2uuidv1(NULL, nhe, &tv);
4843 
4844  /* Convert UUIDv1 to display string. */
4845  te = val;
4846  for (i = 0; i < nhe->c; i++) {
4847  *te++ = hex[ (int)((nhe->p.ui8p[i] >> 4) & 0x0f) ];
4848  *te++ = hex[ (int)((nhe->p.ui8p[i] ) & 0x0f) ];
4849  if (i == 3 || i == 5 || i == 7 || i == 9)
4850  *te++ = '-';
4851  }
4852  *te = '\0';
4853  goto exit; /* XXX immediate exit for UUIDv1 */
4854  break;
4855  }
4856  break;
4857  case RPM_BIN_TYPE:
4858  /* XXX Limit to tag binary digests with djb formatting in UUIDv5. */
4859  switch (he->tag) {
4860  default:
4861  val = _free(val);
4862  val = xstrdup(_("(invalid tag :uuid)"));
4863  goto exit;
4864  break;
4865  case RPMTAG_PKGID:
4866  case RPMTAG_SOURCEPKGID:
4867  /* Convert RPMTAG_*PKGID from binary => hex. */
4868  t = te = xmalloc(2*he->c + 1);
4869  for (i = 0; i < he->c; i++) {
4870  *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ];
4871  *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ];
4872  }
4873  *te = '\0';
4874  nhe->t = RPM_STRING_TYPE;
4875  nhe->p.ptr = t;
4876  nhe->c = 1;
4877  break;
4878  }
4879  break;
4880  case RPM_STRING_TYPE:
4881  nhe->c = 1;
4882  nhe->p.ptr = xstrdup(he->p.str);
4883  break;
4884  }
4885 
4886  if (!(av && av[0] && *av[0]))
4887  av = avdefault;
4888 
4889  for (i = 0; av[i] != NULL; i++) {
4890  uint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]);
4891 
4892  switch (keyval) {
4893  default:
4894  /*@switchbreak@*/ break;
4895  case UUID_KEYS_V1:
4896  case UUID_KEYS_V3:
4897  case UUID_KEYS_V4:
4898  case UUID_KEYS_V5:
4899  ix = str2uuid(nhe, NULL, keyval, val);
4900  goto exit; /* XXX exit after first found. */
4901  break;
4902  }
4903  }
4904 
4905 exit:
4906  nhe->p.ptr = _free(nhe->p.ptr);
4907  return val;
4908 }
4909 
4916 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av)
4917  /*@*/
4918 {
4919  int ac = argvCount(av) + 1;
4920  int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack)));
4921  char * end;
4922  char * val = NULL;
4923  int ix = 0;
4924  int i;
4925 
4926  switch(he->t) {
4927  default:
4928  val = xstrdup(_("(invalid type :rpn)"));
4929  goto exit;
4930  /*@notreached@*/ break;
4931  case RPM_UINT64_TYPE:
4932  stack[ix] = he->p.ui64p[0];
4933  break;
4934  case RPM_STRING_TYPE:
4935  end = NULL;
4936 /*@-unrecog@*/ /* Add annotated prototype. */
4937  stack[ix] = strtoll(he->p.str, &end, 0);
4938 /*@=unrecog@*/
4939  if (end && *end != '\0') {
4940  val = xstrdup(_("(invalid string :rpn)"));
4941  goto exit;
4942  }
4943  break;
4944  }
4945 
4946  if (av != NULL)
4947  for (i = 0; av[i] != NULL; i++) {
4948  const char * arg = av[i];
4949  size_t len = strlen(arg);
4950  int c = (int) *arg;
4951 
4952  if (len == 0) {
4953  /* do nothing */
4954  } else if (len > 1) {
4955  if (!(xisdigit(c) || (c == (int)'-' && xisdigit((int) arg[1])))) {
4956  val = xstrdup(_("(expected number :rpn)"));
4957  goto exit;
4958  }
4959  if (++ix == ac) {
4960  val = xstrdup(_("(stack overflow :rpn)"));
4961  goto exit;
4962  }
4963  end = NULL;
4964  stack[ix] = strtoll(arg, &end, 0);
4965  if (end && *end != '\0') {
4966  val = xstrdup(_("(invalid number :rpn)"));
4967  goto exit;
4968  }
4969  } else {
4970  if (ix-- < 1) {
4971  val = xstrdup(_("(stack underflow :rpn)"));
4972  goto exit;
4973  }
4974  switch (c) {
4975  case '&': stack[ix] &= stack[ix+1]; /*@switchbreak@*/ break;
4976  case '|': stack[ix] |= stack[ix+1]; /*@switchbreak@*/ break;
4977  case '^': stack[ix] ^= stack[ix+1]; /*@switchbreak@*/ break;
4978  case '+': stack[ix] += stack[ix+1]; /*@switchbreak@*/ break;
4979  case '-': stack[ix] -= stack[ix+1]; /*@switchbreak@*/ break;
4980  case '*': stack[ix] *= stack[ix+1]; /*@switchbreak@*/ break;
4981  case '%':
4982  case '/':
4983  if (stack[ix+1] == 0) {
4984  val = xstrdup(_("(divide by zero :rpn)"));
4985  goto exit;
4986  }
4987  if (c == (int)'%')
4988  stack[ix] %= stack[ix+1];
4989  else
4990  stack[ix] /= stack[ix+1];
4991  /*@switchbreak@*/ break;
4992  }
4993  }
4994  }
4995 
4996  { HE_t nhe = (HE_t) memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
4997  nhe->tag = he->tag;
4998  nhe->t = RPM_UINT64_TYPE;
4999  nhe->p.ui64p = (rpmuint64_t *)&stack[ix];
5000  nhe->c = 1;
5001  val = intFormat(nhe, NULL, NULL);
5002  }
5003 
5004 exit:
5005  return val;
5006 }
5007 
5014 static /*@only@*/ char * strsubFormat(HE_t he, /*@null@*/ const char ** av)
5015  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
5016  /*@modifies rpmGlobalMacroContext, internalState @*/
5017 {
5018  char * val = NULL;
5019  int ac = argvCount(av);
5020  miRE mires = NULL;
5021  int nmires = 0;
5022  int xx;
5023  int i;
5024 
5025  switch(he->t) {
5026  default:
5027  val = xstrdup(_("(invalid type :strsub)"));
5028  goto exit;
5029  /*@notreached@*/ break;
5030  case RPM_STRING_TYPE:
5031  if (ac < 2 || (ac % 2) != 0) {
5032  val = xstrdup(_("(invalid args :strsub)"));
5033  goto exit;
5034  }
5035  break;
5036  }
5037  if (av == NULL)
5038  goto noop;
5039 
5040  /* Create the mire pattern array. */
5041  for (i = 0; av[i] != NULL; i += 2)
5042  xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mires, &nmires);
5043 
5044  /* Find-and-replace first pattern that matches. */
5045  if (mires != NULL) {
5046  int noffsets = 3;
5047  int offsets[3];
5048  const char * s, * se;
5049  char * t, * te;
5050  char * nval;
5051  size_t slen;
5052  size_t nb;
5053 
5054  for (i = 0; i < nmires; i++) {
5055  miRE mire = mires + i;
5056 
5057  s = he->p.str;
5058  slen = strlen(s);
5059  if ((xx = mireRegexec(mire, s, slen)) < 0)
5060  continue;
5061  xx = mireSetEOptions(mire, offsets, noffsets);
5062 
5063  /* Replace the string(s). This is just s/find/replace/g */
5064  val = xstrdup("");
5065  while (*s != '\0') {
5066  nb = strlen(s);
5067  if ((se = strchr(s, '\n')) == NULL)
5068  se = s + nb;
5069  else
5070  se++;
5071 
5072  offsets[0] = offsets[1] = -1;
5073  xx = mireRegexec(mire, s, nb);
5074 
5075  nb = 1;
5076  /* On match, copy lead-in and match string. */
5077  if (xx == 0)
5078  nb += offsets[0] + strlen(av[2*i+1]);
5079  /* Copy up to EOL on nomatch or insertion. */
5080  if (xx != 0 || offsets[1] == offsets[0])
5081  nb += (se - (s + offsets[1]));
5082 
5083  te = t = xmalloc(nb);
5084 
5085  /* On match, copy lead-in and match string. */
5086  if (xx == 0) {
5087  te = stpcpy( stpncpy(te, s, offsets[0]), av[2*i+1]);
5088  s += offsets[1];
5089  }
5090  /* Copy up to EOL on nomatch or insertion. */
5091  if (xx != 0 || offsets[1] == offsets[0]) {
5092  s += offsets[1];
5093  te = stpncpy(te, s, (se - s));
5094  s = se;
5095  }
5096  *te = '\0';
5097 
5098  nval = rpmExpand(val, t, NULL);
5099  val = _free(val);
5100  val = nval;
5101  t = _free(t);
5102  }
5103  }
5104  mires = mireFreeAll(mires, nmires);
5105  }
5106 
5107 noop:
5108  if (val == NULL)
5109  val = xstrdup(he->p.str);
5110 exit:
5111  return val;
5112 }
5113 
5114 static struct headerSprintfExtension_s _headerCompoundFormats[] = {
5115  { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID",
5116  { .tagFunction = buildtime_uuidTag } },
5117  { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME",
5118  { .tagFunction = changelognameTag } },
5119  { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT",
5120  { .tagFunction = changelogtextTag } },
5121  { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",
5122  { .tagFunction = descriptionTag } },
5123  { HEADER_EXT_TAG, "RPMTAG_GROUP",
5124  { .tagFunction = groupTag } },
5125  { HEADER_EXT_TAG, "RPMTAG_HDRUUID",
5126  { .tagFunction = hdruuidTag } },
5127  { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",
5128  { .tagFunction = instprefixTag } },
5129  { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID",
5130  { .tagFunction = installtid_uuidTag } },
5131  { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID",
5132  { .tagFunction = installtime_uuidTag } },
5133  { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID",
5134  { .tagFunction = origintid_uuidTag } },
5135  { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID",
5136  { .tagFunction = origintime_uuidTag } },
5137  { HEADER_EXT_TAG, "RPMTAG_PKGUUID",
5138  { .tagFunction = pkguuidTag } },
5139  { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID",
5140  { .tagFunction = removetid_uuidTag } },
5141  { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID",
5142  { .tagFunction = sourcepkguuidTag } },
5143  { HEADER_EXT_TAG, "RPMTAG_SUMMARY",
5144  { .tagFunction = summaryTag } },
5145  { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",
5146  { .tagFunction = triggercondsTag } },
5147  { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",
5148  { .tagFunction = triggertypeTag } },
5149  { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE",
5150  { .tagFunction = dbinstanceTag } },
5151  { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF",
5152  { .tagFunction = headerstartoffTag } },
5153  { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF",
5154  { .tagFunction = headerendoffTag } },
5155  { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL",
5156  { .tagFunction = pkgbaseurlTag } },
5157  { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST",
5158  { .tagFunction = pkgdigestTag } },
5159  { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN",
5160  { .tagFunction = pkgoriginTag } },
5161  { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE",
5162  { .tagFunction = pkgsizeTag } },
5163  { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME",
5164  { .tagFunction = pkgmtimeTag } },
5165  { HEADER_EXT_TAG, "RPMTAG_NVRA",
5166  { .tagFunction = nvraTag } },
5167  { HEADER_EXT_TAG, "RPMTAG_FILENAMES",
5168  { .tagFunction = filenamesTag } },
5169  { HEADER_EXT_TAG, "RPMTAG_FILEPATHS",
5170  { .tagFunction = filepathsTag } },
5171  { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS",
5172  { .tagFunction = origpathsTag } },
5173  { HEADER_EXT_TAG, "RPMTAG_FILESTAT",
5174  { .tagFunction = filestatTag } },
5175  { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY",
5176  { .tagFunction = PxmlTag } },
5177  { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY",
5178  { .tagFunction = RxmlTag } },
5179  { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY",
5180  { .tagFunction = CxmlTag } },
5181  { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY",
5182  { .tagFunction = OxmlTag } },
5183  { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1",
5184  { .tagFunction = F1xmlTag } },
5185  { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2",
5186  { .tagFunction = F2xmlTag } },
5187  { HEADER_EXT_TAG, "RPMTAG_PROVIDEYAMLENTRY",
5188  { .tagFunction = PyamlTag } },
5189  { HEADER_EXT_TAG, "RPMTAG_REQUIREYAMLENTRY",
5190  { .tagFunction = RyamlTag } },
5191  { HEADER_EXT_TAG, "RPMTAG_CONFLICTYAMLENTRY",
5192  { .tagFunction = CyamlTag } },
5193  { HEADER_EXT_TAG, "RPMTAG_OBSOLETEYAMLENTRY",
5194  { .tagFunction = OyamlTag } },
5195  { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY1",
5196  { .tagFunction = F1yamlTag } },
5197  { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY2",
5198  { .tagFunction = F2yamlTag } },
5199  { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY",
5200  { .tagFunction = PsqlTag } },
5201  { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY",
5202  { .tagFunction = RsqlTag } },
5203  { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY",
5204  { .tagFunction = CsqlTag } },
5205  { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY",
5206  { .tagFunction = OsqlTag } },
5207  { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1",
5208  { .tagFunction = F1sqlTag } },
5209  { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2",
5210  { .tagFunction = F2sqlTag } },
5211  { HEADER_EXT_TAG, "RPMTAG_DEBCONFLICTS",
5212  { .tagFunction = debconflictsTag } },
5213  { HEADER_EXT_TAG, "RPMTAG_DEBDEPENDS",
5214  { .tagFunction = debdependsTag } },
5215  { HEADER_EXT_TAG, "RPMTAG_DEBMD5SUMS",
5216  { .tagFunction = debmd5sumsTag } },
5217  { HEADER_EXT_TAG, "RPMTAG_DEBOBSOLETES",
5218  { .tagFunction = debobsoletesTag } },
5219  { HEADER_EXT_TAG, "RPMTAG_DEBPROVIDES",
5220  { .tagFunction = debprovidesTag } },
5221  { HEADER_EXT_TAG, "RPMTAG_NEEDSWHAT",
5222  { .tagFunction = needswhatTag } },
5223  { HEADER_EXT_TAG, "RPMTAG_WHATNEEDS",
5224  { .tagFunction = whatneedsTag } },
5225  { HEADER_EXT_FORMAT, "armor",
5226  { .fmtFunction = armorFormat } },
5227  { HEADER_EXT_FORMAT, "base64",
5228  { .fmtFunction = base64Format } },
5229  { HEADER_EXT_FORMAT, "bncdata",
5230  { .fmtFunction = bncdataFormat } },
5231  { HEADER_EXT_FORMAT, "cdata",
5232  { .fmtFunction = cdataFormat } },
5233  { HEADER_EXT_FORMAT, "depflags",
5234  { .fmtFunction = depflagsFormat } },
5235  { HEADER_EXT_FORMAT, "deptype",
5236  { .fmtFunction = deptypeFormat } },
5237  { HEADER_EXT_FORMAT, "digest",
5238  { .fmtFunction = digestFormat } },
5239  { HEADER_EXT_FORMAT, "fflags",
5240  { .fmtFunction = fflagsFormat } },
5241  { HEADER_EXT_FORMAT, "hint",
5242  { .fmtFunction = hintFormat } },
5243  { HEADER_EXT_FORMAT, "iconv",
5244  { .fmtFunction = iconvFormat } },
5245  { HEADER_EXT_FORMAT, "json",
5246  { .fmtFunction = jsonFormat } },
5247 #ifndef DYING /* XXX is :json gud enuf? there are side effects ... */
5248  { HEADER_EXT_FORMAT, "jsonescape",
5249  { .fmtFunction = jsonescapeFormat } },
5250 #endif
5251  { HEADER_EXT_FORMAT, "perms",
5252  { .fmtFunction = permsFormat } },
5253  { HEADER_EXT_FORMAT, "permissions",
5254  { .fmtFunction = permsFormat } },
5255  { HEADER_EXT_FORMAT, "pgpsig",
5256  { .fmtFunction = pgpsigFormat } },
5257  { HEADER_EXT_FORMAT, "rpn",
5258  { .fmtFunction = rpnFormat } },
5259  { HEADER_EXT_FORMAT, "sqlescape",
5260  { .fmtFunction = sqlescapeFormat } },
5261  { HEADER_EXT_FORMAT, "stat",
5262  { .fmtFunction = statFormat } },
5263  { HEADER_EXT_FORMAT, "strsub",
5264  { .fmtFunction = strsubFormat } },
5265  { HEADER_EXT_FORMAT, "triggertype",
5266  { .fmtFunction = triggertypeFormat } },
5267  { HEADER_EXT_FORMAT, "utf8",
5268  { .fmtFunction = iconvFormat } },
5269  { HEADER_EXT_FORMAT, "uuid",
5270  { .fmtFunction = uuidFormat } },
5271  { HEADER_EXT_FORMAT, "xml",
5272  { .fmtFunction = xmlFormat } },
5273  { HEADER_EXT_FORMAT, "yaml",
5274  { .fmtFunction = yamlFormat } },
5275  { HEADER_EXT_MORE, NULL, { (void *) &headerDefaultFormats } }
5276 } ;
5277 
5278 headerSprintfExtension headerCompoundFormats = &_headerCompoundFormats[0];
5279 
5280 /*====================================================================*/
5281 
5283 {
5284  const struct headerTagTableEntry_s * t;
5287  int extNum;
5288 
5289  if (fp == NULL)
5290  fp = stdout;
5291  if (_rpmTagTable == NULL)
5292  _rpmTagTable = rpmTagTable;
5293 
5294  /* XXX this should use rpmHeaderFormats, but there are linkage problems. */
5295  if (_rpmHeaderFormats == NULL)
5296  _rpmHeaderFormats = headerCompoundFormats;
5297 
5298  for (t = _rpmTagTable; t && t->name; t++) {
5299  /*@observer@*/
5300  static const char * tagtypes[] = {
5301  "", "char", "uint8", "uint16", "uint32", "uint64",
5302  "string", "octets", "argv", "i18nstring",
5303  };
5304  rpmuint32_t ttype;
5305 
5306  if (rpmIsVerbose()) {
5307  fprintf(fp, "%-20s %6d", t->name + 7, t->val);
5308  ttype = t->type & RPM_MASK_TYPE;
5309  if (ttype < RPM_MIN_TYPE || ttype > RPM_MAX_TYPE)
5310  continue;
5311  if (t->type & RPM_OPENPGP_RETURN_TYPE)
5312  fprintf(fp, " openpgp");
5313  if (t->type & RPM_X509_RETURN_TYPE)
5314  fprintf(fp, " x509");
5315  if (t->type & RPM_ASN1_RETURN_TYPE)
5316  fprintf(fp, " asn1");
5317  if (t->type & RPM_OPAQUE_RETURN_TYPE)
5318  fprintf(fp, " opaque");
5319  fprintf(fp, " %s", tagtypes[ttype]);
5320  if (t->type & RPM_ARRAY_RETURN_TYPE)
5321  fprintf(fp, " array");
5322  if (t->type & RPM_MAPPING_RETURN_TYPE)
5323  fprintf(fp, " mapping");
5324  if (t->type & RPM_PROBE_RETURN_TYPE)
5325  fprintf(fp, " probe");
5326  if (t->type & RPM_TREE_RETURN_TYPE)
5327  fprintf(fp, " tree");
5328  } else
5329  fprintf(fp, "%s", t->name + 7);
5330  fprintf(fp, "\n");
5331  }
5332 
5333  exts = _rpmHeaderFormats;
5334  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
5335  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
5336  {
5337  if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
5338  continue;
5339 
5340  /* XXX don't print header tags twice. */
5341  if (tagValue(ext->name) > 0)
5342  continue;
5343  fprintf(fp, "%s\n", ext->name + 7);
5344  }
5345 }
5346 
5347 /*====================================================================*/
5348 
5349 #define PARSER_BEGIN 0
5350 #define PARSER_IN_ARRAY 1
5351 #define PARSER_IN_EXPR 2
5352 
5355 typedef /*@abstract@*/ struct sprintfTag_s * sprintfTag;
5356 
5361 /*@null@*/
5362  headerTagFormatFunction * fmtfuncs;
5363 /*@null@*/
5364  headerTagTagFunction ext;
5365  int extNum;
5366 /*@only@*/ /*@relnull@*/
5368  int justOne;
5370 /*@kept@*/
5371  char * format;
5372 /*@only@*/ /*@relnull@*/
5374 /*@only@*/ /*@relnull@*/
5376  unsigned pad;
5377 };
5378 
5381 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken;
5382 
5385 typedef enum {
5391 } sprintfToken_e;
5392 
5397  union {
5399  struct {
5400  /*@only@*/
5401  sprintfToken format;
5402  size_t numTokens;
5403  } array;
5404  struct {
5405  /*@dependent@*/
5406  char * string;
5407  size_t len;
5408  } string;
5409  struct {
5410  /*@only@*/ /*@null@*/
5411  sprintfToken ifFormat;
5412  size_t numIfTokens;
5413  /*@only@*/ /*@null@*/
5414  sprintfToken elseFormat;
5416  struct sprintfTag_s tag;
5417  } cond;
5418  } u;
5419 };
5420 
5423 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs;
5424 
5429  char * fmt;
5430 /*@observer@*/ /*@temp@*/
5432 /*@observer@*/ /*@temp@*/
5434 /*@observer@*/ /*@null@*/
5435  const char * errmsg;
5437  int nec;
5438  sprintfToken format;
5439 /*@relnull@*/
5441 /*@owned@*/
5442  char * val;
5443  size_t vallen;
5444  size_t alloced;
5445  size_t numTokens;
5446  size_t i;
5447 };
5448 
5449 /*@access sprintfTag @*/
5450 /*@access sprintfToken @*/
5451 /*@access headerSprintfArgs @*/
5452 
5455 static char escapedChar(const char ch)
5456  /*@*/
5457 {
5458 /*@-modfilesys@*/
5459 if (_hdrqf_debug)
5460 fprintf(stderr, "\t\t\\%c\n", ch);
5461 /*@=modfilesys@*/
5462  switch (ch) {
5463  case 'a': return '\a';
5464  case 'b': return '\b';
5465  case 'f': return '\f';
5466  case 'n': return '\n';
5467  case 'r': return '\r';
5468  case 't': return '\t';
5469  case 'v': return '\v';
5470  default: return ch;
5471  }
5472 }
5473 
5478 /*@relnull@*/
5479 static HE_t rpmheClean(/*@returned@*/ /*@null@*/ HE_t he)
5480  /*@modifies he @*/
5481 {
5482  if (he) {
5483  if (he->freeData && he->p.ptr != NULL)
5484  he->p.ptr = _free(he->p.ptr);
5485  memset(he, 0, sizeof(*he));
5486  }
5487  return he;
5488 }
5489 
5496 static /*@null@*/ sprintfToken
5497 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, size_t num)
5498  /*@modifies *format @*/
5499 {
5500  unsigned i;
5501 
5502  if (format == NULL) return NULL;
5503 
5504  for (i = 0; i < (unsigned) num; i++) {
5505  switch (format[i].type) {
5506  case PTOK_TAG:
5507  (void) rpmheClean(&format[i].u.tag.he);
5508  format[i].u.tag.tagno = _free(format[i].u.tag.tagno);
5509  format[i].u.tag.av = argvFree(format[i].u.tag.av);
5510  format[i].u.tag.params = argvFree(format[i].u.tag.params);
5511 /*@-type@*/
5512  format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs);
5513 /*@=type@*/
5514  /*@switchbreak@*/ break;
5515  case PTOK_ARRAY:
5516  format[i].u.array.format =
5517  freeFormat(format[i].u.array.format,
5518  format[i].u.array.numTokens);
5519  /*@switchbreak@*/ break;
5520  case PTOK_COND:
5521  format[i].u.cond.ifFormat =
5522  freeFormat(format[i].u.cond.ifFormat,
5523  format[i].u.cond.numIfTokens);
5524  format[i].u.cond.elseFormat =
5525  freeFormat(format[i].u.cond.elseFormat,
5526  format[i].u.cond.numElseTokens);
5527  (void) rpmheClean(&format[i].u.cond.tag.he);
5528  format[i].u.cond.tag.tagno = _free(format[i].u.cond.tag.tagno);
5529  format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av);
5530  format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params);
5531 /*@-type@*/
5532  format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs);
5533 /*@=type@*/
5534  /*@switchbreak@*/ break;
5535  case PTOK_NONE:
5536  case PTOK_STRING:
5537  default:
5538  /*@switchbreak@*/ break;
5539  }
5540  }
5541  format = _free(format);
5542  return NULL;
5543 }
5544 
5550 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
5551  /*@globals fileSystem @*/
5552  /*@modifies hsa, fileSystem @*/
5553 {
5554  sprintfTag tag =
5555  (hsa->format->type == PTOK_TAG
5556  ? &hsa->format->u.tag :
5557  (hsa->format->type == PTOK_ARRAY
5558  ? &hsa->format->u.array.format->u.tag :
5559  NULL));
5560 
5561  if (hsa != NULL) {
5562  hsa->i = 0;
5563  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2)
5564  hsa->hi = headerInit(hsa->h);
5565  }
5566 /*@-nullret@*/
5567  return hsa;
5568 /*@=nullret@*/
5569 }
5570 
5576 /*@null@*/
5577 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
5578  /*@globals internalState @*/
5579  /*@modifies hsa, internalState @*/
5580 {
5581  sprintfToken fmt = NULL;
5582  sprintfTag tag =
5583  (hsa->format->type == PTOK_TAG
5584  ? &hsa->format->u.tag :
5585  (hsa->format->type == PTOK_ARRAY
5586  ? &hsa->format->u.array.format->u.tag :
5587  NULL));
5588 
5589  if (hsa != NULL && hsa->i < hsa->numTokens) {
5590  fmt = hsa->format + hsa->i;
5591  if (hsa->hi == NULL) {
5592  hsa->i++;
5593  } else {
5594  HE_t he = rpmheClean(&tag->he);
5595  if (!headerNext(hsa->hi, he, 0))
5596  {
5597  tag->tagno[0] = 0;
5598  return NULL;
5599  }
5600  he->avail = 1;
5601  tag->tagno[0] = he->tag;
5602  }
5603  }
5604 
5605 /*@-dependenttrans -onlytrans@*/
5606  return fmt;
5607 /*@=dependenttrans =onlytrans@*/
5608 }
5609 
5615 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
5616  /*@globals fileSystem @*/
5617  /*@modifies hsa, fileSystem @*/
5618 {
5619  if (hsa != NULL) {
5620  hsa->hi = headerFini(hsa->hi);
5621  hsa->i = 0;
5622  }
5623 /*@-nullret@*/
5624  return hsa;
5625 /*@=nullret@*/
5626 }
5627 
5634 /*@dependent@*/ /*@exposed@*/
5635 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
5636  /*@modifies hsa */
5637 {
5638  if ((hsa->vallen + need) >= hsa->alloced) {
5639  if (hsa->alloced <= need)
5640  hsa->alloced += need;
5641  hsa->alloced <<= 1;
5642  hsa->val = xrealloc(hsa->val, hsa->alloced+1);
5643  }
5644  return hsa->val + hsa->vallen;
5645 }
5646 
5654 /*@observer@*/ /*@null@*/
5655 static const char * myTagName(headerTagTableEntry tbl, rpmuint32_t val,
5656  /*@null@*/ rpmuint32_t *typep)
5657  /*@modifies *typep @*/
5658 {
5659  static char name[128]; /* XXX Ick. */
5660  const char * s;
5661  char *t;
5662 
5663  /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
5664  if (tbl == NULL || tbl == rpmTagTable) {
5665  s = tagName(val);
5666  if (s != NULL && typep != NULL)
5667  *typep = tagType(val);
5668  return s;
5669  }
5670 
5671  for (; tbl->name != NULL; tbl++) {
5672  if (tbl->val == val)
5673  break;
5674  }
5675  if ((s = tbl->name) == NULL)
5676  return NULL;
5677  s += sizeof("RPMTAG_") - 1;
5678  t = name;
5679  *t++ = *s++;
5680  while (*s != '\0')
5681  *t++ = (char)xtolower((int)*s++);
5682  *t = '\0';
5683  if (typep)
5684  *typep = tbl->type;
5685  return name;
5686 }
5687 
5695  /*@*/
5696 {
5697  rpmuint32_t val = 0;
5698 
5699  /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
5700  if (tbl == NULL || tbl == rpmTagTable)
5701  val = tagValue(name);
5702  else
5703  for (; tbl->name != NULL; tbl++) {
5704  if (xstrcasecmp(tbl->name, name))
5705  continue;
5706  val = tbl->val;
5707  break;
5708  }
5709  return val;
5710 }
5711 
5719 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
5720  /*@modifies token @*/
5721 {
5722  headerSprintfExtension exts = hsa->exts;
5724  sprintfTag stag = (token->type == PTOK_COND
5725  ? &token->u.cond.tag : &token->u.tag);
5726  int extNum;
5727  rpmTag tagno = (rpmTag)-1;
5728 
5729  stag->fmtfuncs = NULL;
5730  stag->ext = NULL;
5731  stag->extNum = 0;
5732 
5733  if (!strcmp(name, "*")) {
5734  tagno = (rpmTag)-2;
5735  goto bingo;
5736  }
5737 
5738  if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
5739  char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
5740  (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
5741  name = t;
5742  }
5743 
5744  /* Search extensions for specific tag override. */
5745  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
5746  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
5747  {
5748  if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
5749  continue;
5750  if (!xstrcasecmp(ext->name, name)) {
5751  stag->ext = ext->u.tagFunction;
5752  stag->extNum = extNum;
5753  tagno = tagValue(name);
5754  goto bingo;
5755  }
5756  }
5757 
5758  /* Search tag names. */
5759  tagno = myTagValue(hsa->tags, name);
5760  if (tagno != 0)
5761  goto bingo;
5762 
5763  return 1;
5764 
5765 bingo:
5766  stag->tagno = xcalloc(1, sizeof(*stag->tagno));
5767  stag->tagno[0] = tagno;
5768  /* Search extensions for specific format(s). */
5769  if (stag->av != NULL) {
5770  int i;
5771 /*@-type@*/
5772  stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs));
5773 /*@=type@*/
5774  for (i = 0; stag->av[i] != NULL; i++) {
5775  for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
5776  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1))
5777  {
5778  if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
5779  /*@innercontinue@*/ continue;
5780  if (strcmp(ext->name, stag->av[i]+1))
5781  /*@innercontinue@*/ continue;
5782  stag->fmtfuncs[i] = ext->u.fmtFunction;
5783  /*@innerbreak@*/ break;
5784  }
5785  }
5786  }
5787  return 0;
5788 }
5789 
5790 /* forward ref */
5799 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
5800  char * str, /*@out@*/char ** endPtr)
5801  /*@modifies hsa, str, token, *endPtr @*/
5802  /*@requires maxSet(endPtr) >= 0 @*/;
5803 
5814 static int parseFormat(headerSprintfArgs hsa, char * str,
5815  /*@out@*/ sprintfToken * formatPtr,
5816  /*@out@*/ size_t * numTokensPtr,
5817  /*@null@*/ /*@out@*/ char ** endPtr, int state)
5818  /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
5819  /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
5820  /\ maxSet(endPtr) >= 0 @*/
5821 {
5822 /*@observer@*/
5823 static const char *pstates[] = {
5824 "NORMAL", "ARRAY", "EXPR", "WTF?"
5825 };
5826  char * chptr, * start, * next, * dst;
5827  sprintfToken format;
5828  sprintfToken token;
5829  size_t numTokens;
5830  unsigned i;
5831  int done = 0;
5832  int xx;
5833 
5834 /*@-modfilesys@*/
5835 if (_hdrqf_debug)
5836 fprintf(stderr, "--> parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]);
5837 /*@=modfilesys@*/
5838 
5839  /* upper limit on number of individual formats */
5840  numTokens = 0;
5841  if (str != NULL)
5842  for (chptr = str; *chptr != '\0'; chptr++)
5843  if (*chptr == '%' || *chptr == '[') numTokens++;
5844  numTokens = numTokens * 2 + 1;
5845 
5846  format = xcalloc(numTokens, sizeof(*format));
5847  if (endPtr) *endPtr = NULL;
5848 
5849 /*@-infloops@*/ /* LCL: can't detect (start, *start) termination */
5850  dst = start = str;
5851  numTokens = 0;
5852  token = NULL;
5853  if (start != NULL)
5854  while (*start != '\0') {
5855  switch (*start) {
5856  case '%':
5857  /* handle %% */
5858  if (*(start + 1) == '%') {
5859  if (token == NULL || token->type != PTOK_STRING) {
5860  token = format + numTokens++;
5861  token->type = PTOK_STRING;
5862 /*@-temptrans -assignexpose@*/
5863  dst = token->u.string.string = start;
5864 /*@=temptrans =assignexpose@*/
5865  }
5866  start++;
5867  *dst++ = *start++;
5868  /*@switchbreak@*/ break;
5869  }
5870 
5871  token = format + numTokens++;
5872  *dst++ = '\0';
5873  start++;
5874 
5875  if (*start == '|') {
5876  char * newEnd;
5877 
5878  start++;
5879  if (parseExpression(hsa, token, start, &newEnd))
5880  {
5881  format = freeFormat(format, numTokens);
5882  return 1;
5883  }
5884  start = newEnd;
5885  /*@switchbreak@*/ break;
5886  }
5887 
5888 /*@-assignexpose@*/
5889  token->u.tag.format = start;
5890 /*@=assignexpose@*/
5891  token->u.tag.pad = 0;
5892  token->u.tag.justOne = 0;
5893  token->u.tag.arrayCount = 0;
5894 
5895  chptr = start;
5896  while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
5897  if (!*chptr || *chptr == '%') {
5898  hsa->errmsg = _("missing { after %");
5899  format = freeFormat(format, numTokens);
5900  return 1;
5901  }
5902 
5903 /*@-modfilesys@*/
5904 if (_hdrqf_debug)
5905 fprintf(stderr, "\tchptr *%p = NUL\n", chptr);
5906 /*@=modfilesys@*/
5907  *chptr++ = '\0';
5908 
5909  while (start < chptr) {
5910  if (xisdigit((int)*start)) {
5911  i = strtoul(start, &start, 10);
5912  token->u.tag.pad += i;
5913  start = chptr;
5914  /*@innerbreak@*/ break;
5915  } else {
5916  start++;
5917  }
5918  }
5919 
5920  if (*start == '=') {
5921  token->u.tag.justOne = 1;
5922  start++;
5923  } else if (*start == '#') {
5924  token->u.tag.justOne = 1;
5925  token->u.tag.arrayCount = 1;
5926  start++;
5927  }
5928 
5929  next = start;
5930  while (*next && *next != '}') next++;
5931  if (!*next) {
5932  hsa->errmsg = _("missing } after %{");
5933  format = freeFormat(format, numTokens);
5934  return 1;
5935  }
5936 /*@-modfilesys@*/
5937 if (_hdrqf_debug)
5938 fprintf(stderr, "\tnext *%p = NUL\n", next);
5939 /*@=modfilesys@*/
5940  *next++ = '\0';
5941 
5942 #define isSEP(_c) ((_c) == ':' || (_c) == '|')
5943  chptr = start;
5944  while (!(*chptr == '\0' || isSEP(*chptr))) chptr++;
5945  /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */
5946  while (isSEP(*chptr)) {
5947  if (chptr[1] == '\0' || isSEP(chptr[1])) {
5948  hsa->errmsg = _("empty tag format");
5949  format = freeFormat(format, numTokens);
5950  return 1;
5951  }
5952  /* Parse the formatter parameter list. */
5953  { char * te = chptr + 1;
5954  char * t = strchr(te, '(');
5955  char c;
5956 
5957  while (!(*te == '\0' || isSEP(*te))) {
5958 #ifdef NOTYET /* XXX some means of escaping is needed */
5959  if (te[0] == '\\' && te[1] != '\0') te++;
5960 #endif
5961  te++;
5962  }
5963  c = *te; *te = '\0';
5964  /* Parse (a,b,c) parameter list. */
5965  if (t != NULL) {
5966  *t++ = '\0';
5967  if (te <= t || te[-1] != ')') {
5968  *te = c; /* coverity #1214085 */
5969  hsa->errmsg = _("malformed parameter list");
5970  format = freeFormat(format, numTokens);
5971  return 1;
5972  }
5973  te[-1] = '\0';
5974  xx = argvAdd(&token->u.tag.params, t);
5975  } else
5976  xx = argvAdd(&token->u.tag.params, "");
5977 /*@-modfilesys@*/
5978 if (_hdrqf_debug)
5979 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : ""));
5980 /*@=modfilesys@*/
5981  xx = argvAdd(&token->u.tag.av, chptr);
5982  *te = c;
5983  *chptr = '\0';
5984  chptr = te;
5985  }
5986  }
5987 #undef isSEP
5988 
5989  if (*start == '\0') {
5990  hsa->errmsg = _("empty tag name");
5991  format = freeFormat(format, numTokens);
5992  return 1;
5993  }
5994 
5995  i = 0;
5996  token->type = PTOK_TAG;
5997 
5998  if (findTag(hsa, token, start)) {
5999  hsa->errmsg = _("unknown tag");
6000  format = freeFormat(format, numTokens);
6001  return 1;
6002  }
6003 
6004  dst = start = next;
6005 /*@-modfilesys@*/
6006 if (_hdrqf_debug)
6007 fprintf(stderr, "\tdst = start = next %p\n", dst);
6008 /*@=modfilesys@*/
6009  /*@switchbreak@*/ break;
6010 
6011  case '[':
6012 /*@-modfilesys@*/
6013 if (_hdrqf_debug)
6014 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start);
6015 /*@=modfilesys@*/
6016  *start++ = '\0';
6017  token = format + numTokens++;
6018 
6019  if (parseFormat(hsa, start,
6020  &token->u.array.format,
6021  &token->u.array.numTokens,
6022  &start, PARSER_IN_ARRAY))
6023  {
6024  format = freeFormat(format, numTokens);
6025  return 1;
6026  }
6027 
6028  if (!start) {
6029  hsa->errmsg = _("] expected at end of array");
6030  format = freeFormat(format, numTokens);
6031  return 1;
6032  }
6033 
6034  dst = start;
6035 /*@-modfilesys@*/
6036 if (_hdrqf_debug)
6037 fprintf(stderr, "\tdst = start %p\n", dst);
6038 /*@=modfilesys@*/
6039 
6040  token->type = PTOK_ARRAY;
6041 
6042  /*@switchbreak@*/ break;
6043 
6044  case ']':
6045  if (state != PARSER_IN_ARRAY) {
6046  hsa->errmsg = _("unexpected ]");
6047  format = freeFormat(format, numTokens);
6048  return 1;
6049  }
6050  *start++ = '\0';
6051 /*@-modfilesys@*/
6052 if (_hdrqf_debug)
6053 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
6054 /*@=modfilesys@*/
6055  if (endPtr) *endPtr = start;
6056  done = 1;
6057  /*@switchbreak@*/ break;
6058 
6059  case '}':
6060  if (state != PARSER_IN_EXPR) {
6061  hsa->errmsg = _("unexpected }");
6062  format = freeFormat(format, numTokens);
6063  return 1;
6064  }
6065  *start++ = '\0';
6066 /*@-modfilesys@*/
6067 if (_hdrqf_debug)
6068 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
6069 /*@=modfilesys@*/
6070  if (endPtr) *endPtr = start;
6071  done = 1;
6072  /*@switchbreak@*/ break;
6073 
6074  default:
6075  if (token == NULL || token->type != PTOK_STRING) {
6076  token = format + numTokens++;
6077  token->type = PTOK_STRING;
6078 /*@-temptrans -assignexpose@*/
6079  dst = token->u.string.string = start;
6080 /*@=temptrans =assignexpose@*/
6081  }
6082 
6083 /*@-modfilesys@*/
6084 if (_hdrqf_debug)
6085 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start);
6086 /*@=modfilesys@*/
6087  if (start[0] == '\\' && start[1] != '\0') {
6088  start++;
6089  *dst++ = escapedChar(*start);
6090  *start++ = '\0';
6091  } else {
6092  *dst++ = *start++;
6093  }
6094  /*@switchbreak@*/ break;
6095  }
6096  if (dst < start) *dst = '\0';
6097  if (done)
6098  break;
6099  }
6100 /*@=infloops@*/
6101 
6102  if (dst != NULL)
6103  *dst = '\0';
6104 
6105  for (i = 0; i < (unsigned) numTokens; i++) {
6106  token = format + i;
6107  switch(token->type) {
6108  default:
6109  /*@switchbreak@*/ break;
6110  case PTOK_STRING:
6111  token->u.string.len = strlen(token->u.string.string);
6112  /*@switchbreak@*/ break;
6113  }
6114  }
6115 
6116  if (numTokensPtr != NULL)
6117  *numTokensPtr = numTokens;
6118  if (formatPtr != NULL)
6119  *formatPtr = format;
6120 
6121  return 0;
6122 }
6123 
6124 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
6125  char * str, /*@out@*/ char ** endPtr)
6126 {
6127  char * chptr;
6128  char * end;
6129 
6130 /*@-modfilesys@*/
6131 if (_hdrqf_debug)
6132 fprintf(stderr, "--> parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr);
6133 /*@=modfilesys@*/
6134 
6135  hsa->errmsg = NULL;
6136  chptr = str;
6137  while (*chptr && *chptr != '?') chptr++;
6138 
6139  if (*chptr != '?') {
6140  hsa->errmsg = _("? expected in expression");
6141  return 1;
6142  }
6143 
6144  *chptr++ = '\0';
6145 
6146  if (*chptr != '{') {
6147  hsa->errmsg = _("{ expected after ? in expression");
6148  return 1;
6149  }
6150 
6151  chptr++;
6152 
6153  if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
6154  &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
6155  return 1;
6156 
6157  /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
6158  if (!(end && *end)) {
6159  hsa->errmsg = _("} expected in expression");
6160  token->u.cond.ifFormat =
6161  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6162  return 1;
6163  }
6164 
6165  chptr = end;
6166  if (*chptr != ':' && *chptr != '|') {
6167  hsa->errmsg = _(": expected following ? subexpression");
6168  token->u.cond.ifFormat =
6169  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6170  return 1;
6171  }
6172 
6173  if (*chptr == '|') {
6174  if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
6175  &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
6176  {
6177  token->u.cond.ifFormat =
6178  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6179  return 1;
6180  }
6181  } else {
6182  chptr++;
6183 
6184  if (*chptr != '{') {
6185  hsa->errmsg = _("{ expected after : in expression");
6186  token->u.cond.ifFormat =
6187  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6188  return 1;
6189  }
6190 
6191  chptr++;
6192 
6193  if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
6194  &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
6195  return 1;
6196 
6197  /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
6198  if (!(end && *end)) {
6199  hsa->errmsg = _("} expected in expression");
6200  token->u.cond.ifFormat =
6201  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6202  return 1;
6203  }
6204 
6205  chptr = end;
6206  if (*chptr != '|') {
6207  hsa->errmsg = _("| expected at end of expression");
6208  token->u.cond.ifFormat =
6209  freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
6210  token->u.cond.elseFormat =
6211  freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
6212  return 1;
6213  }
6214  }
6215 
6216  chptr++;
6217 
6218  *endPtr = chptr;
6219 
6220  token->type = PTOK_COND;
6221 
6222  (void) findTag(hsa, token, str);
6223 
6224  return 0;
6225 }
6226 
6235 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
6236  HE_t he, HE_t ec)
6237  /*@modifies he, ec @*/
6238 {
6239  int rc = 0;
6240  if (!ec->avail) {
6241  he = rpmheClean(he);
6242  rc = fn(hsa->h, he);
6243  *ec = *he; /* structure copy. */
6244  if (!rc)
6245  ec->avail = 1;
6246  } else
6247  *he = *ec; /* structure copy. */
6248  he->freeData = 0;
6249  rc = (rc == 0); /* XXX invert getExtension return. */
6250  return rc;
6251 }
6252 
6260 /*@observer@*/ /*@null@*/
6261 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag,
6262  size_t element)
6263  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
6264  /*@modifies hsa, tag, rpmGlobalMacroContext, internalState @*/
6265 {
6266  HE_t vhe = (HE_t) memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
6267  HE_t he = &tag->he;
6268  char * val = NULL;
6269  size_t need = 0;
6270  char * t, * te;
6271  rpmuint64_t ival = 0;
6272  rpmTagCount countBuf;
6273  int xx;
6274 
6275  if (!he->avail) {
6276  if (tag->ext)
6277  xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
6278  else {
6279  he->tag = tag->tagno[0]; /* XXX necessary? */
6280  xx = headerGet(hsa->h, he, 0);
6281  }
6282  if (!xx) {
6283  (void) rpmheClean(he);
6284  he->t = RPM_STRING_TYPE;
6285  he->p.str = xstrdup("(none)");
6286  he->c = 1;
6287  he->freeData = 1;
6288  }
6289  he->avail = 1;
6290  }
6291 
6292  if (tag->arrayCount) {
6293  countBuf = he->c;
6294  he = rpmheClean(he);
6295  he->t = RPM_UINT32_TYPE;
6296  he->p.ui32p = &countBuf;
6297  he->c = 1;
6298  he->freeData = 0;
6299  }
6300 
6301  vhe->tag = he->tag;
6302 
6303  if (he->p.ptr)
6304  switch (he->t) {
6305  default:
6306  val = xstrdup("(unknown type)");
6307  need = strlen(val) + 1;
6308  goto exit;
6309  /*@notreached@*/ break;
6310 #if defined(SUPPORT_I18NSTRING_TYPE)
6311  case RPM_I18NSTRING_TYPE:
6312 #endif
6313  case RPM_STRING_ARRAY_TYPE:
6314  vhe->t = RPM_STRING_TYPE;
6315  vhe->p.str = he->p.argv[element];
6316  vhe->c = he->c;
6317  vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1);
6318  break;
6319 #if !defined(SUPPORT_I18NSTRING_TYPE)
6320  case RPM_I18NSTRING_TYPE:
6321 assert(0);
6322 #endif
6323  case RPM_STRING_TYPE:
6324  vhe->p.str = he->p.str;
6325  vhe->t = RPM_STRING_TYPE;
6326  vhe->c = 0;
6327  vhe->ix = -1;
6328  break;
6329  case RPM_UINT8_TYPE:
6330  case RPM_UINT16_TYPE:
6331  case RPM_UINT32_TYPE:
6332  case RPM_UINT64_TYPE:
6333  switch (he->t) {
6334  default:
6335 assert(0); /* XXX keep gcc quiet. */
6336  /*@innerbreak@*/ break;
6337  case RPM_UINT8_TYPE:
6338  ival = (rpmuint64_t)he->p.ui8p[element];
6339  /*@innerbreak@*/ break;
6340  case RPM_UINT16_TYPE:
6341  ival = (rpmuint64_t)he->p.ui16p[element];
6342  /*@innerbreak@*/ break;
6343  case RPM_UINT32_TYPE:
6344  ival = (rpmuint64_t)he->p.ui32p[element];
6345  /*@innerbreak@*/ break;
6346  case RPM_UINT64_TYPE:
6347  ival = he->p.ui64p[element];
6348  /*@innerbreak@*/ break;
6349  }
6350  vhe->t = RPM_UINT64_TYPE;
6351  vhe->p.ui64p = &ival;
6352  vhe->c = he->c;
6353  vhe->ix = (he->c > 1 ? 0 : -1);
6355  vhe->ix = 0;
6356  break;
6357 
6358  case RPM_BIN_TYPE:
6359  vhe->t = RPM_BIN_TYPE;
6360  vhe->p.ptr = he->p.ptr;
6361  vhe->c = he->c;
6362  vhe->ix = -1;
6363  break;
6364  }
6365 
6366 /*@-compmempass@*/ /* vhe->p.ui64p is stack, not owned */
6367  if (tag->fmtfuncs) {
6368  char * nval = NULL;
6369  int i;
6370  for (i = 0; tag->av[i] != NULL; i++) {
6371  headerTagFormatFunction fmt;
6372  ARGV_t av;
6373  if ((fmt = tag->fmtfuncs[i]) == NULL)
6374  continue;
6375  /* If !1st formatter, and transformer, not extractor, save val. */
6376  if (val != NULL && *tag->av[i] == '|') {
6377  int ix = vhe->ix;
6378  vhe = rpmheClean(vhe);
6379  vhe->tag = he->tag;
6380  vhe->t = RPM_STRING_TYPE;
6381  vhe->p.str = xstrdup(val);
6382  vhe->c = he->c;
6383  vhe->ix = ix;
6384  vhe->freeData = 1;
6385  }
6386  av = NULL;
6387  if (tag->params && tag->params[i] && *tag->params[i] != '\0')
6388  xx = argvSplit(&av, tag->params[i], ",");
6389 
6390  nval = fmt(vhe, av);
6391 
6392 /*@-castfcnptr -modfilesys@*/
6393 if (_hdrqf_debug)
6394 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)"));
6395 /*@=castfcnptr =modfilesys@*/
6396 
6397  /* Accumulate (by appending) next formatter's return string. */
6398  if (val == NULL)
6399  val = xstrdup((nval ? nval : ""));
6400  else {
6401  char * oval = val;
6402  /* XXX using ... | ... as separator is feeble. */
6403  val = rpmExpand(val, (*val != '\0' ? " | " : ""), nval, NULL);
6404  oval = _free(oval);
6405  }
6406  nval = _free(nval);
6407  av = argvFree(av);
6408  }
6409  }
6410 
6411  if (val == NULL)
6412  val = intFormat(vhe, NULL, NULL);
6413 /*@=compmempass@*/
6414 assert(val != NULL);
6415  if (val)
6416  need = strlen(val) + 1;
6417 
6418 exit:
6419  if (val && need > 0) {
6420  if (tag->format && *tag->format && tag->pad > 0) {
6421  size_t nb;
6422  nb = strlen(tag->format) + sizeof("%s");
6423  t = alloca(nb);
6424  (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s");
6425  nb = tag->pad + strlen(val) + 1;
6426  te = xmalloc(nb);
6427 /*@-formatconst@*/
6428  (void) snprintf(te, nb, t, val);
6429 /*@=formatconst@*/
6430  te[nb-1] = '\0';
6431  val = _free(val);
6432  val = te;
6433  need += tag->pad;
6434  }
6435  t = hsaReserve(hsa, need);
6436  te = stpcpy(t, val);
6437  hsa->vallen += (te - t);
6438  val = _free(val);
6439  }
6440 
6441  return (hsa->val + hsa->vallen);
6442 }
6443 
6451 /*@observer@*/ /*@null@*/
6452 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
6453  size_t element)
6454  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
6455  /*@modifies hsa, token, rpmGlobalMacroContext, internalState @*/
6456 {
6457  char * t, * te;
6458  size_t i, j;
6459  size_t numElements;
6460  sprintfToken spft;
6461  sprintfTag tag = NULL;
6462  HE_t he = NULL;
6463  size_t condNumFormats;
6464  size_t need;
6465  int xx;
6466 
6467  /* we assume the token and header have been validated already! */
6468 
6469  switch (token->type) {
6470  case PTOK_NONE:
6471  break;
6472 
6473  case PTOK_STRING:
6474  need = token->u.string.len;
6475  if (need == 0) break;
6476  t = hsaReserve(hsa, need);
6477  te = stpcpy(t, token->u.string.string);
6478  hsa->vallen += (te - t);
6479  break;
6480 
6481  case PTOK_TAG:
6482  t = hsa->val + hsa->vallen;
6483 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6484  te = formatValue(hsa, &token->u.tag,
6485  (token->u.tag.justOne ? 0 : element));
6486 /*@=modobserver@*/
6487  if (te == NULL)
6488  return NULL;
6489  break;
6490 
6491  case PTOK_COND:
6492  if (token->u.cond.tag.ext
6493  || headerIsEntry(hsa->h, token->u.cond.tag.tagno[0]))
6494  {
6495  spft = token->u.cond.ifFormat;
6496  condNumFormats = token->u.cond.numIfTokens;
6497  } else {
6498  spft = token->u.cond.elseFormat;
6499  condNumFormats = token->u.cond.numElseTokens;
6500  }
6501 
6502  need = condNumFormats * 20;
6503  if (spft == NULL || need == 0) break;
6504 
6505  t = hsaReserve(hsa, need);
6506  for (i = 0; i < condNumFormats; i++, spft++) {
6507 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6508  te = singleSprintf(hsa, spft, element);
6509 /*@=modobserver@*/
6510  if (te == NULL)
6511  return NULL;
6512  }
6513  break;
6514 
6515  case PTOK_ARRAY:
6516  numElements = 0;
6517  spft = token->u.array.format;
6518  for (i = 0; i < token->u.array.numTokens; i++, spft++)
6519  {
6520  tag = &spft->u.tag;
6521  if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne)
6522  continue;
6523  he = &tag->he;
6524  if (!he->avail) {
6525  he->tag = tag->tagno[0];
6526  if (tag->ext)
6527  xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
6528  else
6529  xx = headerGet(hsa->h, he, 0);
6530  if (!xx) {
6531  (void) rpmheClean(he);
6532  continue;
6533  }
6534  he->avail = 1;
6535  }
6536 
6537  /* Check iteration arrays are same dimension (or scalar). */
6538  switch (he->t) {
6539  default:
6540  if (numElements == 0) {
6541  numElements = he->c;
6542  /*@switchbreak@*/ break;
6543  }
6544  if ((size_t)he->c == numElements)
6545  /*@switchbreak@*/ break;
6546  hsa->errmsg =
6547  _("array iterator used with different sized arrays");
6548  he = rpmheClean(he);
6549  return NULL;
6550  /*@notreached@*/ /*@switchbreak@*/ break;
6551  case RPM_BIN_TYPE:
6552  case RPM_STRING_TYPE:
6553  if (numElements == 0)
6554  numElements = 1;
6555  /*@switchbreak@*/ break;
6556  }
6557  }
6558  spft = token->u.array.format;
6559 
6560  if (numElements == 0) {
6561 #ifdef DYING /* XXX lots of pugly "(none)" lines with --conflicts. */
6562  need = sizeof("(none)\n") - 1;
6563  t = hsaReserve(hsa, need);
6564  te = stpcpy(t, "(none)\n");
6565  hsa->vallen += (te - t);
6566 #endif
6567  } else {
6568  rpmTagReturnType tagT = 0;
6569  const char * tagN = NULL;
6570  spew_t spew = NULL;
6571 
6572  need = numElements * token->u.array.numTokens;
6573  if (need == 0) break;
6574 
6575  tag = &spft->u.tag;
6576 
6577 spew = NULL;
6578  /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
6579  if (spft->type == PTOK_TAG && tag->av != NULL
6580  && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"))
6581  spew = &_xml_spew;
6582  if (spft->type == PTOK_TAG && tag->av != NULL
6583  && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"))
6584  spew = &_yaml_spew;
6585  if (spft->type == PTOK_TAG && tag->av != NULL
6586  && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json"))
6587  spew = &_json_spew;
6588 
6589  if (spew == &_xml_spew) {
6590 assert(tag->tagno != NULL);
6591  /* XXX display "Tag_0x01234567" for arbitrary tags. */
6592  if (tag->tagno[0] & 0x40000000) {
6593  tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6594  } else
6595  tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6596  need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN);
6597  te = t = hsaReserve(hsa, need);
6598  te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n");
6599  hsa->vallen += (te - t);
6600  }
6601  if (spew == &_yaml_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  tagT = numElements > 1
6608  } else
6609  tagN = myTagName(hsa->tags, tag->tagno[0], &tagT);
6610  need = sizeof(" : - ") + strlen(tagN);
6611  te = t = hsaReserve(hsa, need);
6612  *te++ = ' ';
6613  *te++ = ' ';
6614  te = stpcpy(te, tagN);
6615  *te++ = ':';
6616  *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
6617  ? '\n' : ' ');
6618  *te = '\0';
6619  hsa->vallen += (te - t);
6620  }
6621  if (spew == &_json_spew) {
6622 assert(tag->tagno != NULL);
6623  /* XXX display "Tag_0x01234567" for arbitrary tags. */
6624  if (tag->tagno[0] & 0x40000000) {
6625  tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6626  tagT = numElements > 1
6628  } else
6629  if (tag->tagno[0] == RPMTAG_HDRID) { /* RPMTAG_SHA1HEADER */
6630  tagN = "_id"; /* XXX mongo primary key name */
6631  } else
6632  tagN = myTagName(hsa->tags, tag->tagno[0], &tagT);
6633  need = sizeof(" : [ ") + strlen(tagN);
6634  te = t = hsaReserve(hsa, need);
6635  te = stpcpy( stpcpy( stpcpy(te, " "), tagN), ": ");
6637  te = stpcpy(te, "[ ");
6638  hsa->vallen += (te - t);
6639  }
6640 
6641  need = numElements * token->u.array.numTokens * 10;
6642  t = hsaReserve(hsa, need);
6643  for (j = 0; j < numElements; j++) {
6644  spft = token->u.array.format;
6645  for (i = 0; i < token->u.array.numTokens; i++, spft++) {
6646 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6647  te = singleSprintf(hsa, spft, j);
6648 /*@=modobserver@*/
6649  if (te == NULL)
6650  return NULL;
6651  }
6652  }
6653 
6654  if (spew == &_xml_spew) {
6655  need = sizeof(" </rpmTag>\n") - 1;
6656  te = t = hsaReserve(hsa, need);
6657  te = stpcpy(te, " </rpmTag>\n");
6658  hsa->vallen += (te - t);
6659  }
6660  if (spew == &_json_spew) {
6661  if ((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE) {
6662  need = sizeof(" ],\n") - 1;
6663  te = t = hsaReserve(hsa, need);
6664  te = stpcpy(te, " ],\n");
6665  hsa->vallen += (te - t);
6666  } else {
6667  need = sizeof("\n") - 1;
6668  te = t = hsaReserve(hsa, need);
6669  te = stpcpy(te, "\n");
6670  hsa->vallen += (te - t);
6671  }
6672  }
6673 
6674  }
6675  break;
6676  }
6677 
6678  return (hsa->val + hsa->vallen);
6679 }
6680 
6687 static /*@only@*/ HE_t
6688 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp)
6689  /*@modifies *necp @*/
6690 {
6692  HE_t ec;
6693  int extNum = 0;
6694 
6695  if (exts != NULL)
6696  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
6697  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
6698  {
6699  ;
6700  }
6701  if (necp)
6702  *necp = extNum;
6703  ec = (HE_t) xcalloc(extNum+1, sizeof(*ec)); /* XXX +1 unnecessary */
6704  return ec;
6705 }
6706 
6713 static /*@null@*/ HE_t
6714 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec)
6715  /*@modifies ec @*/
6716 {
6718  int extNum;
6719 
6720  for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
6721  ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
6722  {
6723  (void) rpmheClean(&ec[extNum]);
6724  }
6725 
6726  ec = _free(ec);
6727  return NULL;
6728 }
6729 
6730 char * headerSprintf(Header h, const char * fmt,
6731  headerTagTableEntry tags,
6733  errmsg_t * errmsg)
6734 {
6735  headerSprintfArgs hsa = (headerSprintfArgs) memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
6736  sprintfToken nextfmt;
6737  sprintfTag tag;
6738  char * t, * te;
6739  size_t need;
6740 spew_t spew = NULL;
6741 
6742 /*@-modfilesys@*/
6743 if (_hdrqf_debug)
6744 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg);
6745 /*@=modfilesys@*/
6746 
6747  /* Set some reasonable defaults */
6748  if (tags == NULL)
6749  tags = rpmTagTable;
6750  /* XXX this loses the extensions in lib/formats.c. */
6751  if (exts == NULL)
6752  exts = headerCompoundFormats;
6753 
6754 /*@-assignexpose -castexpose @*/
6755  hsa->h = headerLink(h);
6756 /*@=assignexpose =castexpose @*/
6757  hsa->fmt = xstrdup(fmt);
6758 /*@-assignexpose -dependenttrans@*/
6759  hsa->exts = exts;
6760  hsa->tags = tags;
6761 /*@=assignexpose =dependenttrans@*/
6762  hsa->errmsg = NULL;
6763 
6764  if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
6765  goto exit;
6766 
6767  hsa->nec = 0;
6768  hsa->ec = rpmecNew(hsa->exts, &hsa->nec);
6769  hsa->val = xstrdup("");
6770 
6771  tag =
6772  (hsa->format->type == PTOK_TAG
6773  ? &hsa->format->u.tag :
6774  (hsa->format->type == PTOK_ARRAY
6775  ? &hsa->format->u.array.format->u.tag :
6776  NULL));
6777 
6778 spew = NULL;
6779  /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
6780  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2
6781  && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"))
6782  spew = &_xml_spew;
6783  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2
6784  && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"))
6785  spew = &_yaml_spew;
6786  if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2
6787  && tag->av != NULL && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "json"))
6788  spew = &_json_spew;
6789 
6790  if (spew && spew->spew_init && spew->spew_init[0]) {
6791  char * spew_init = rpmExpand(spew->spew_init, NULL);
6792  need = strlen(spew_init);
6793  t = hsaReserve(hsa, need);
6794  te = stpcpy(t, spew_init);
6795  hsa->vallen += (te - t);
6796  spew_init = _free(spew_init);
6797  }
6798 
6799  hsa = hsaInit(hsa);
6800  while ((nextfmt = hsaNext(hsa)) != NULL) {
6801 /*@-globs -mods@*/ /* XXX rpmGlobalMacroContext @*/
6802  te = singleSprintf(hsa, nextfmt, 0);
6803 /*@=globs =mods @*/
6804  if (te == NULL) {
6805  hsa->val = _free(hsa->val);
6806  break;
6807  }
6808  }
6809  hsa = hsaFini(hsa);
6810 
6811  if (spew && spew->spew_fini && spew->spew_fini[0]) {
6812  char * spew_fini = rpmExpand(spew->spew_fini, NULL);
6813  need = strlen(spew_fini);
6814  t = hsaReserve(hsa, need);
6815  te = stpcpy(t, spew_fini);
6816  hsa->vallen += (te - t);
6817  spew_fini = _free(spew_fini);
6818  }
6819 
6820  if (hsa->val != NULL && hsa->vallen < hsa->alloced)
6821  hsa->val = (char *) xrealloc(hsa->val, hsa->vallen+1);
6822 
6823  hsa->ec = rpmecFree(hsa->exts, hsa->ec);
6824  hsa->nec = 0;
6825  hsa->format = freeFormat(hsa->format, hsa->numTokens);
6826 
6827 exit:
6828 /*@-dependenttrans -observertrans @*/
6829  if (errmsg)
6830  *errmsg = hsa->errmsg;
6831 /*@=dependenttrans =observertrans @*/
6832  (void)headerFree(hsa->h);
6833  hsa->h = NULL;
6834  hsa->fmt = _free(hsa->fmt);
6835 /*@-retexpose@*/
6836  return hsa->val;
6837 /*@=retexpose@*/
6838 }
const bson * b
Definition: bson.h:280
rpmTagType t
Definition: rpmtag.h:504
enum rpmTagReturnType_e rpmTagReturnType
Identify how to return the header data type.
int rpmmiPrune(rpmmi mi, uint32_t *hdrNums, int nHdrNums, int sorted)
Remove items from set of package instances to iterate.
Definition: rpmdb.c:2453
static char * depflagsFormat(HE_t he, const char **av)
Format dependency flags for display.
Definition: hdrfmt.c:1454
static int buildtime_uuidTag(Header h, HE_t he)
Retrieve build time and convert to UUIDv1.
Definition: hdrfmt.c:1743
const char * str
Definition: rpmtag.h:73
int arrayCount
Definition: hdrfmt.c:5369
rpmTag tag
Definition: rpmtag.h:503
static size_t nkeyUuids
Definition: hdrfmt.c:4544
static char * hGetNVRA(Header h)
Return (malloc'd) header name-version-release.arch string.
Definition: hdrfmt.c:2535
int rpmuuidMake(int version, const char *ns, const char *data, char *buf_str, unsigned char *buf_bin)
Generate a Universally Unique Identifier (UUID).
Definition: rpmuuid.c:23
static int debdependsTag(Header h, HE_t he)
Definition: hdrfmt.c:2869
static char * triggertypeFormat(HE_t he, const char **av)
Identify type of trigger.
Definition: hdrfmt.c:655
const char ** argv
Definition: rpmtag.h:75
headerTagTableEntry rpmTagTable
Automatically generated table of tag name/value pairs.
Definition: tagtbl.c:239
int mireSetEOptions(miRE mire, int *offsets, int noffsets)
Initialize pattern execute options (PCRE only).
Definition: mire.c:156
union sprintfToken_s::@3 u
#define RPM_MAX_TYPE
Definition: rpmtag.h:42
static char * sqlstrcpy(char *t, const char *s, int lvl)
Copy source string to target, doubling single quotes.
Definition: hdrfmt.c:572
static KEY keyStat[]
Definition: hdrfmt.c:4467
struct headerSprintfArgs_s * headerSprintfArgs
Definition: hdrfmt.c:5423
int headerIsEntry(Header h, rpmTag tag)
Check if tag is in header.
Definition: header.c:1439
const char * headerGetDigest(Header h)
Return digest of origin *.rpm file.
Definition: header.c:1242
pgpDig pgpDigFree(pgpDig dig)
Destroy a container for parsed OpenPGP packates.
const char const char size_t len
Definition: bson.h:823
static char * rpnFormat(HE_t he, const char **av)
Return arithmetic expressions of input.
Definition: hdrfmt.c:4916
char * getenv(const char *name)
static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F, uint32_t i)
Definition: hdrfmt.c:3339
static int PxmlTag(Header h, HE_t he)
Definition: hdrfmt.c:3480
static char * cdataFormat(HE_t he, const char **av)
Encode string for use in XML CDATA.
Definition: hdrfmt.c:965
#define RPMSENSE_SENSEMASK
Definition: rpmevr.h:76
static char * uuidFormat(HE_t he, const char **av)
Reformat tag string as a UUID.
Definition: hdrfmt.c:4794
ARGI_t argiFree(ARGI_t argi)
Destroy an argi array.
Definition: argv.c:34
static int _fnTag(Header h, HE_t he, rpmTag tag)
Retrieve file paths.
Definition: hdrfmt.c:2716
const char * xstrtolocale(const char *str)
Force encoding of string.
Definition: strtolocale.c:15
void * mireFreeAll(miRE mire, int nmire)
Destroy compiled patterns.
Definition: mire.c:96
static char * strdup_iconv_check(const char *buffer, const char *tocode)
Definition: hdrfmt.c:882
static int CxmlTag(Header h, HE_t he)
Definition: hdrfmt.c:3496
static HE_t rpmecNew(const headerSprintfExtension exts, int *necp)
Create an extension cache.
Definition: hdrfmt.c:6688
static char * dayFormat(HE_t he, const char **av)
Return day formatted data.
Definition: hdrfmt.c:246
uint32_t rpmmiInstance(rpmmi mi)
Return header instance for current position of rpmdb iterator.
Definition: rpmdb.c:1747
Definition: hdrfmt.c:332
char * xstrdup(const char *str)
Definition: rpmmalloc.c:321
const char * name
Definition: hdrfmt.c:4406
static int parseFormat(headerSprintfArgs hsa, char *str, sprintfToken *formatPtr, size_t *numTokensPtr, char **endPtr, int state)
Parse a headerSprintf term.
Definition: hdrfmt.c:5814
static int pkgbaseurlTag(Header h, HE_t he)
Retrieve package baseurl from header.
Definition: hdrfmt.c:2445
rpmuint32_t * ui32p
Definition: rpmtag.h:70
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2833
static const char * _iconv_fromcode
Definition: hdrfmt.c:878
Definition: libsql.c:29
struct pgpDigParams_s * pgpDigParams
Definition: rpmiotypes.h:101
static int instprefixTag(Header h, HE_t he)
Retrieve install prefixes.
Definition: hdrfmt.c:1638
static unsigned int pgpLen(const rpmuint8_t *s, unsigned int *lenp)
Return length of an OpenPGP packet.
Definition: rpmpgp.h:1053
DIGEST_CTX rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags)
Initialize digest context.
Definition: digest.c:247
char * rpmGetPath(const char *path,...)
Return (malloc'ed) expanded, canonicalized, file path.
Definition: macro.c:3431
keyUuids_e
Bit field enum for stat(2) keys.
Definition: hdrfmt.c:4516
Structure(s) used for file info tag sets.
int headerGet(Header h, HE_t he, unsigned int flags)
Retrieve extension or tag value from a header.
Definition: header.c:2231
#define PARSER_IN_EXPR
Definition: hdrfmt.c:5351
static int headerstartoffTag(Header h, HE_t he)
Retrieve starting byte offset of header.
Definition: hdrfmt.c:2383
static unsigned int pgpGrab(const rpmuint8_t *s, size_t nbytes)
Return (native-endian) integer from big-endian representation.
Definition: rpmpgp.h:1036
static int filestatTag(Header h, HE_t he)
Definition: hdrfmt.c:2956
sprintfToken ifFormat
Definition: hdrfmt.c:5411
struct key_s KEY
const struct spew_s * spew_t
Definition: hdrfmt.c:331
static HE_t rpmecFree(const headerSprintfExtension exts, HE_t ec)
Destroy an extension cache.
Definition: hdrfmt.c:6714
The Header data structure.
static char * octFormat(HE_t he, const char **av)
Return octal formatted data.
Definition: hdrfmt.c:165
HeaderIterator headerFini(HeaderIterator hi)
Destroy header tag container iterator.
Definition: header.c:2134
char * gidToGname(gid_t gid)
Definition: ugid.c:171
static int summaryTag(Header h, HE_t he)
Retrieve summary text.
Definition: hdrfmt.c:2307
sprintfToken format
Definition: hdrfmt.c:5438
rpmuint32_t headerGetEndOff(Header h)
Return header ending byte offset.
Definition: header.c:1302
rpmuint16_t * ui16p
Definition: rpmtag.h:69
static int RyamlTag(Header h, HE_t he)
Definition: hdrfmt.c:3861
rpmuint32_t headerGetStartOff(Header h)
Return header starting byte offset.
Definition: header.c:1290
#define HEADERGET_NOEXTENSION
Definition: rpmtag.h:775
static const char uuid_ns[]
Definition: hdrfmt.c:1808
int setenv(const char *name, const char *value, int replace)
HeaderIterator headerInit(Header h)
Create header tag iterator.
Definition: header.c:2144
#define RPMTAG_PKGID
Definition: rpmtag.h:160
int justOne
Definition: hdrfmt.c:5368
Definition: rpmdb.c:436
Structure(s) and routine(s) used for classifying and parsing names.
#define S_ISLNK(mode)
Definition: system.h:651
char * pgpArmorWrap(rpmuint8_t atype, const unsigned char *s, size_t ns)
Wrap a OpenPGP packets in ascii armor for transport.
Definition: rpmpgp.c:1749
headerTagFormatFunction * fmtfuncs
Definition: hdrfmt.c:5362
int errno
struct sprintfToken_s::@3::@4 array
static const char * _iconv_tocode
Definition: hdrfmt.c:876
static char * spewescapeFormat(HE_t he, const char **av, spew_t spew, int lvl)
Encode string for use by SQL/JSON markup.
Definition: hdrfmt.c:3520
static struct headerSprintfExtension_s _rpmHeaderFormats[]
Definition: formats.c:274
static int pkguuidTag(Header h, HE_t he)
Retrieve pkgid and convert to UUIDv5.
Definition: hdrfmt.c:1916
int rpmEVRparse(const char *evrstr, EVR_t evr)
Split EVR string into epoch, version, and release components.
Definition: rpmevr.c:181
static int localeTag(Header h, HE_t he)
Retrieve text and convert to locale.
Definition: hdrfmt.c:2252
const char * buffer
Definition: bson.h:289
static const char * myTagName(headerTagTableEntry tbl, rpmuint32_t val, rpmuint32_t *typep)
Return tag name from value.
Definition: hdrfmt.c:5655
static const char * language
Definition: hdrfmt.c:2135
struct EVR_s * EVR_t
Definition: rpmevr.h:22
static int sourcepkguuidTag(Header h, HE_t he)
Retrieve sourcepkgid and convert to UUIDv5.
Definition: hdrfmt.c:1930
Header tag iterator data structure.
Definition: header.c:2129
static int triggertypeTag(Header h, HE_t he)
Retrieve trigger type info.
Definition: hdrfmt.c:2056
#define S_ISSOCK(mode)
Definition: system.h:655
int headerNext(HeaderIterator hi, HE_t he, unsigned int flags)
Return next tag from header.
Definition: header.c:2158
static int debevrTag(Header h, HE_t he, rpmTag tagN, rpmTag tagEVR, rpmTag tagF)
Retrieve and return Debian formatted dependecies for –deb:control.
Definition: hdrfmt.c:2823
static void fdInitDigest(FD_t fd, pgpHashAlgo hashalgo, int _flags)
Attach digest to fd.
int argiCount(ARGI_t argi)
Return no.
Definition: argv.c:55
static headerSprintfArgs hsaInit(headerSprintfArgs hsa)
Initialize an hsa iteration.
Definition: hdrfmt.c:5550
char * headerSprintf(Header h, const char *fmt, headerTagTableEntry tags, headerSprintfExtension exts, errmsg_t *errmsg)
Return formatted output string from header tags.
Definition: hdrfmt.c:6730
int ix
Definition: rpmtag.h:508
static char * sqlescapeFormat(HE_t he, const char **av)
Definition: hdrfmt.c:3551
static int debobsoletesTag(Header h, HE_t he)
Definition: hdrfmt.c:2878
ARGV_t av
Definition: hdrfmt.c:5373
rpmTag tagValue(const char *tagstr)
Return tag value from name.
Definition: tagname.c:446
static char * jsonescapeFormat(HE_t he, const char **av)
Definition: hdrfmt.c:3544
static size_t sqlstrlen(const char *s, int lvl)
Return length of string represented with single quotes doubled.
Definition: hdrfmt.c:550
rpmmi rpmmiInit(rpmdb db, rpmTag tag, const void *keyp, size_t keylen)
Return database iterator.
Definition: rpmdb.c:2495
headerTagTableEntry tags
Definition: hdrfmt.c:5431
static const struct spew_s _sql_spew
Definition: hdrfmt.c:590
static char * pgpsigFormat(HE_t he, const char **av)
Display signature fingerprint and time.
Definition: hdrfmt.c:1368
static int F1xmlTag(Header h, HE_t he)
Definition: hdrfmt.c:4047
static char * jsonstrcpy(char *t, const char *s, int lvl)
Copy source string to target, doubling single quotes.
Definition: hdrfmt.c:508
static int xtolower(int c)
Definition: rpmiotypes.h:574
char * alloca()
HeaderIterator hi
Definition: hdrfmt.c:5440
const char * str
Definition: bson.h:593
static int whatneedsTag(Header h, HE_t he)
Definition: hdrfmt.c:3087
static int removetid_uuidTag(Header h, HE_t he)
Retrieve remove tid and convert to UUIDv1.
Definition: hdrfmt.c:1785
static const char uuid_path[]
Definition: hdrfmt.c:1812
#define dgettext(DomainName, Text)
Definition: system.h:528
static size_t nkeyStat
Definition: hdrfmt.c:4511
unsigned int rpmuint32_t
Definition: rpmiotypes.h:28
struct _HE_s * HE_t
Definition: rpmtag.h:59
static int groupTag(Header h, HE_t he)
Retrieve group text.
Definition: hdrfmt.c:2351
keyStat_e
Bit field enum for stat(2) keys.
Definition: hdrfmt.c:4439
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:300
static char * strsubFormat(HE_t he, const char **av)
Replace string values.
Definition: hdrfmt.c:5014
void * ptr
Definition: rpmtag.h:67
static char * xmlFormat(HE_t he, const char **av)
Wrap tag data in simple header xml markup.
Definition: hdrfmt.c:1017
static HE_t rpmheClean(HE_t he)
Clean a tag container, free'ing attached malloc's.
Definition: hdrfmt.c:5479
const char const bson_bool_t v
Definition: bson.h:919
static int FDGSkip(rpmTagData DN, rpmTagData BN, rpmTagData DI, rpmuint32_t i)
Definition: hdrfmt.c:3894
static int origintime_uuidTag(Header h, HE_t he)
Retrieve origin time and convert to UUIDv1.
Definition: hdrfmt.c:1757
int rpmDigestUpdate(DIGEST_CTX ctx, const void *data, size_t len)
Update context with next plain text buffer.
Definition: digest.c:986
static rpmuint32_t myTagValue(headerTagTableEntry tbl, const char *name)
Return tag value from name.
Definition: hdrfmt.c:5694
static struct headerSprintfExtension_s _headerCompoundFormats[]
Definition: hdrfmt.c:5114
static sprintfToken freeFormat(sprintfToken format, size_t num)
Destroy headerSprintf format array.
Definition: hdrfmt.c:5497
static char * dateFormat(HE_t he, const char **av)
Return date formatted data.
Definition: hdrfmt.c:234
static const char * _pgpPubkeyAlgo2Name(uint32_t algo)
Definition: rpmpgp.h:1191
static int PyamlTag(Header h, HE_t he)
Definition: hdrfmt.c:3850
const char * mode
Definition: mongo.h:440
unsigned int avail
Definition: rpmtag.h:510
static size_t xmlstrlen(const char *s, int lvl)
Return length of string represented with xml characters substituted.
Definition: hdrfmt.c:350
static int triggercondsTag(Header h, HE_t he)
Retrieve trigger info.
Definition: hdrfmt.c:1958
static int hdruuidTag(Header h, HE_t he)
Retrieve hdrid and convert to UUIDv5.
Definition: hdrfmt.c:1944
static char * xmlstrcpy(char *t, const char *s, int lvl)
Copy source string to target, substituting for xml characters.
Definition: hdrfmt.c:374
static int nvraTag(Header h, HE_t he)
Retrieve N-V-R.A compound string from header.
Definition: hdrfmt.c:2587
unsigned char rpmuint8_t
Private int typedefs to avoid C99 portability issues.
Definition: rpmiotypes.h:26
sprintfToken format
Definition: hdrfmt.c:5401
#define PARSER_IN_ARRAY
Definition: hdrfmt.c:5350
static size_t jsonstrlen(const char *s, int lvl)
Return length of string represented with single quotes doubled.
Definition: hdrfmt.c:479
char * string
Definition: hdrfmt.c:5406
unsigned int tagType(rpmTag tag)
Return tag data type from value.
Definition: tagname.c:441
static char * jsonFormat(HE_t he, const char **av)
Wrap tag data in simple header json markup.
Definition: hdrfmt.c:1277
int argvCount(const ARGV_t argv)
Return no.
Definition: argv.c:71
mongo_error_t err
Definition: mongo.h:922
static const struct spew_s _xml_spew
Definition: hdrfmt.c:394
char * stpncpy(char *dest, const char *src, size_t n)
int Lstat(const char *path, struct stat *st)
lstat(2) clone.
Definition: rpmrpc.c:1401
static int installtime_uuidTag(Header h, HE_t he)
Retrieve install time and convert to UUIDv1.
Definition: hdrfmt.c:1729
#define PARSER_BEGIN
Definition: hdrfmt.c:5349
rpmTagData p
Definition: rpmtag.h:506
static const struct headerTagTableEntry_s _rpmTagTable[]
Definition: tagtbl.c:9
unsigned long long rpmuint64_t
Definition: rpmiotypes.h:29
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
struct miRE_s * miRE
Definition: mire.h:60
static char * fflagsFormat(HE_t he, const char **av)
Format file flags for display.
Definition: hdrfmt.c:709
struct stat * headerGetStatbuf(Header h)
Return header stat(2) buffer (of origin *.rpm file).
Definition: header.c:1228
static char * decFormat(HE_t he, const char **av)
Return decimal formatted data.
Definition: hdrfmt.c:189
static KEY keyUuids[]
Definition: hdrfmt.c:4531
static char * armorFormat(HE_t he, const char **av)
Wrap a pubkey in ascii armor for display.
Definition: hdrfmt.c:751
const char * tagName(rpmTag tag)
Return tag name from value.
Definition: tagname.c:436
pgpDigParams pgpGetSignature(pgpDig dig)
Return OpenPGP signature parameters.
Definition: rpmpgp.c:1392
static int descriptionTag(Header h, HE_t he)
Retrieve description text.
Definition: hdrfmt.c:2321
static int origpathsTag(Header h, HE_t he)
Definition: hdrfmt.c:2747
size_t numElseTokens
Definition: hdrfmt.c:5415
size_t(* spew_strlen)(const char *s, int lvl)
Definition: hdrfmt.c:337
size_t numIfTokens
Definition: hdrfmt.c:5412
static int str2uuid(HE_t he, const char **av, rpmuint32_t version, char *val)
Convert tag string to UUID.
Definition: hdrfmt.c:1824
struct sprintfToken_s * sprintfToken
Definition: hdrfmt.c:5381
Digest private data.
Definition: digest.c:130
static int pkgmtimeTag(Header h, HE_t he)
Retrieve *.rpm package st->st_mtime from header.
Definition: hdrfmt.c:2495
The FD_t File Handle data structure.
static void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo, void *datap, size_t *lenp, int asAscii)
static void rpmfiBuildFNames(Header h, rpmTag tagN, const char ***fnp, rpmTagCount *fcp)
Retrieve file names from header.
Definition: hdrfmt.c:2615
struct pgpDig_s * pgpDig
Definition: rpmiotypes.h:97
static int parseExpression(headerSprintfArgs hsa, sprintfToken token, char *str, char **endPtr)
Parse a headerSprintf expression.
Definition: hdrfmt.c:6124
struct rpmdb_s * rpmdb
Database of headers and tag value indices.
Definition: rpmtypes.h:43
static int OyamlTag(Header h, HE_t he)
Definition: hdrfmt.c:3883
static int installtid_uuidTag(Header h, HE_t he)
Retrieve install tid and convert to UUIDv1.
Definition: hdrfmt.c:1771
int argvAdd(ARGV_t *argvp, ARGstr_t val)
Add a string to an argv array.
Definition: argv.c:199
const struct headerSprintfExtension_s * headerSprintfExtension
Definition: rpmtag.h:134
static char * bncdataFormat(HE_t he, const char **av)
Encode the basename of a string for use in XML CDATA.
Definition: hdrfmt.c:4370
rpmTagCount c
Definition: rpmtag.h:507
int mireRegexec(miRE mire, const char *val, size_t vallen)
Execute pattern match.
Definition: mire.c:396
static const char * _macro_i18ndomains
Definition: hdrfmt.c:2138
int xstrcasecmp(const char *s1, const char *s2)
Locale insensitive strcasecmp(3).
Definition: strcasecmp.c:9
static KEY keyDigests[]
Definition: hdrfmt.c:4411
static int F2xmlTag(Header h, HE_t he)
Definition: hdrfmt.c:4055
static int CyamlTag(Header h, HE_t he)
Definition: hdrfmt.c:3872
struct sprintfTag_s tag
Definition: hdrfmt.c:5398
Header headerFree(Header h)
Dereference a header instance.
unsigned pad
Definition: hdrfmt.c:5376
sprintfToken_e type
Definition: hdrfmt.c:5396
const char const bson const bson * op
Definition: mongo.h:505
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3238
const char * headerGetOrigin(Header h)
Return header origin (e.g path or URL).
Definition: header.c:1184
static char * hsaReserve(headerSprintfArgs hsa, size_t need)
Reserve sufficient buffer space for next output value.
Definition: hdrfmt.c:5635
static int pkgsizeTag(Header h, HE_t he)
Retrieve *.rpm package st->st_size from header.
Definition: hdrfmt.c:2516
static int tag2uuidv1(Header h, HE_t he)
Retrieve time and convert to UUIDv1.
Definition: hdrfmt.c:1709
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
const char const char int arg
Definition: mongo.h:777
void unsetenv(const char *name)
rpmuint8_t * ui8p
Definition: rpmtag.h:68
rpmmi rpmmiFree(rpmmi mi)
Destroy rpm database iterator.
sprintfToken_e
Definition: hdrfmt.c:5385
char * format
Definition: hdrfmt.c:5371
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
static int nwlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp, HE_t RNhe, HE_t REVRhe, HE_t RFhe)
Definition: hdrfmt.c:3166
static int debprovidesTag(Header h, HE_t he)
Definition: hdrfmt.c:2887
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
static int FDGyamlTag(Header h, HE_t he, int lvl)
Definition: hdrfmt.c:4218
static size_t yamlstrlen(const char *s, int lvl)
Return length of string represented with yaml indentation.
Definition: hdrfmt.c:410
static int debmd5sumsTag(Header h, HE_t he)
Retrieve digest/path pairs for –deb:md5sums.
Definition: hdrfmt.c:2902
static char * yamlFormat(HE_t he, const char **av)
Wrap tag data in simple header yaml markup.
Definition: hdrfmt.c:1116
#define isSEP(_c)
static int tag2uuidv5(Header h, HE_t he)
Retrieve tag and convert to UUIDv5.
Definition: hdrfmt.c:1876
struct sprintfToken_s::@3::@6 cond
static int dbinstanceTag(Header h, HE_t he)
Retrieve db instance from header.
Definition: hdrfmt.c:2365
static int pkgdigestTag(Header h, HE_t he)
Retrieve package digest from header.
Definition: hdrfmt.c:2471
size_t numTokens
Definition: hdrfmt.c:5402
Header headerLink(Header h)
Reference a header instance.
static const char * _pgpHashAlgo2Name(uint32_t algo)
Definition: rpmpgp.h:1184
EVR_t rpmEVRnew(uint32_t Flags, int initialize)
Create a new EVR container.
Definition: rpmevr.c:31
int Readlink(const char *path, char *buf, size_t bufsiz)
readlink(2) clone.
Definition: rpmrpc.c:2154
sprintfToken elseFormat
Definition: hdrfmt.c:5414
static const struct spew_s _yaml_spew
Definition: hdrfmt.c:463
headerTagTagFunction ext
Definition: hdrfmt.c:5364
static int OsqlTag(Header h, HE_t he)
Definition: hdrfmt.c:3746
static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
Definition: hdrfmt.c:3558
static char * yamlstrcpy(char *t, const char *s, int lvl)
Copy source string to target, indenting for yaml.
Definition: hdrfmt.c:437
pgpDig pgpDigNew(pgpVSFlags vsflags, pgpPubkeyAlgo pubkey_algo)
Create a container for parsed OpenPGP packates.
Definition: rpmpgp.c:1314
static int FDGsqlTag(Header h, HE_t he, int lvl)
Definition: hdrfmt.c:4063
const char * errmsg_t
Definition: rpmtag.h:18
static int pkgoriginTag(Header h, HE_t he)
Retrieve package origin from header.
Definition: hdrfmt.c:2419
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
static int headerendoffTag(Header h, HE_t he)
Retrieve ending byte offset of header.
Definition: hdrfmt.c:2401
static char * iconvFormat(HE_t he, const char **av)
Convert string encoding.
Definition: hdrfmt.c:996
static int needswhatTag(Header h, HE_t he)
Definition: hdrfmt.c:3264
static char * statFormat(HE_t he, const char **av)
Return file info.
Definition: hdrfmt.c:4620
Definition: rpmtag.h:502
static int F1yamlTag(Header h, HE_t he)
Definition: hdrfmt.c:4348
EVR_t rpmEVRfree(EVR_t evr)
Destroy an EVR container.
Definition: rpmevr.c:47
const char const int i
Definition: bson.h:778
static int xisdigit(int c)
Definition: rpmiotypes.h:546
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
static int snprintf(char *buf, int nb, const char *fmt,...)
Definition: rpmps.c:220
const char const bson * key
Definition: mongo.h:717
int rpmEVRoverlap(EVR_t a, EVR_t b)
Compare EVR containers for overlap.
Definition: rpmevr.c:339
unsigned int freeData
Definition: rpmtag.h:509
headerSprintfExtension exts
Definition: hdrfmt.c:5433
char * stpcpy(char *dest, const char *src)
static char * rpmPermsString(int mode)
Definition: hdrfmt.c:601
static int OxmlTag(Header h, HE_t he)
Definition: hdrfmt.c:3504
static sprintfToken hsaNext(headerSprintfArgs hsa)
Return next hsa iteration item.
Definition: hdrfmt.c:5577
const char const char size_t size
Definition: bson.h:895
static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token, size_t element)
Format a single headerSprintf item.
Definition: hdrfmt.c:6452
static int i18nTag(Header h, HE_t he)
Retrieve i18n text.
Definition: hdrfmt.c:2146
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
char * uidToUname(uid_t uid)
Definition: ugid.c:135
int headerNEVRA(Header h, const char **np, const char **ep, const char **vp, const char **rp, const char **ap)
Return name, epoch, version, release, arch strings from header.
Definition: hdrNVR.c:162
Header rpmmiNext(rpmmi mi)
Return next package header from iteration.
Definition: rpmdb.c:2252
static int filepathsTag(Header h, HE_t he)
Definition: hdrfmt.c:2739
static char * realDateFormat(HE_t he, const char **av, const char *strftimeFormat)
Return strftime formatted data.
Definition: hdrfmt.c:202
static int changelognameTag(Header h, HE_t he)
Definition: hdrfmt.c:2329
const char * spew_name
Definition: hdrfmt.c:334
Structure(s) and routine(s) used for EVR parsing and comparison.
void rpmDisplayQueryTags(FILE *fp, headerTagTableEntry _rpmTagTable, headerSprintfExtension _rpmHeaderFormats)
Display list of tags that can be used in –queryformat.
Definition: hdrfmt.c:5282
static size_t nkeyDigests
Definition: hdrfmt.c:4434
static int debconflictsTag(Header h, HE_t he)
Retrieve Depends: and Conflicts: for –deb:control.
Definition: hdrfmt.c:2860
const struct headerTagTableEntry_s * headerTagTableEntry
Definition: rpmtag.h:525
int argiAdd(ARGI_t *argip, int ix, int val)
Add an int to an argi array.
Definition: argv.c:178
#define RPMTAG_HDRID
Definition: rpmtag.h:170
static struct headerSprintfExtension_s _headerDefaultFormats[]
Definition: hdrfmt.c:308
static int RsqlTag(Header h, HE_t he)
Definition: hdrfmt.c:3730
int _hdrqf_debug
Definition: hdrfmt.c:69
struct sprintfTag_s * sprintfTag
Definition: hdrfmt.c:5355
int argvSplit(ARGV_t *argvp, const char *str, const char *seps)
Split a string into an argv array.
Definition: argv.c:233
#define rpmIsVerbose()
Definition: rpmcb.h:21
static char * hintFormat(HE_t he, const char **av)
Format dependency flags for display.
Definition: hdrfmt.c:1607
ARGV_t argvSearch(ARGV_t argv, ARGstr_t val, int(*compar)(ARGstr_t *, ARGstr_t *))
Find an element in an argv array.
Definition: argv.c:146
static int tv2uuidv1(Header h, HE_t he, struct timeval *tv)
Convert unix timeval to UUIDv1.
Definition: hdrfmt.c:1666
enum pgpTag_e pgpTag
4.3.
static rpmuint32_t keyValue(KEY *keys, size_t nkeys, const char *name)
Definition: hdrfmt.c:4558
static int keyCmp(const void *a, const void *b)
Definition: hdrfmt.c:4549
static char * permsFormat(HE_t he, const char **av)
Format file permissions for display.
Definition: hdrfmt.c:686
const char char type
Definition: bson.h:908
static char * deptypeFormat(HE_t he, const char **av)
Format dependency type for display.
Definition: hdrfmt.c:1506
int pgpPrtPkts(const rpmuint8_t *pkts, size_t pktlen, pgpDig dig, int printing)
Print/parse a OpenPGP packet(s).
Definition: rpmpgp.c:1518
int argvSort(ARGV_t argv, int(*compar)(ARGstr_t *, ARGstr_t *))
Sort an argv array.
Definition: argv.c:137
static int filenamesTag(Header h, HE_t he)
Definition: hdrfmt.c:2731
const char * spew_fini
Definition: hdrfmt.c:336
int rpmDigestFinal(DIGEST_CTX ctx, void *datap, size_t *lenp, int asAscii)
Return digest and destroy context.
Definition: digest.c:1000
static int PsqlTag(Header h, HE_t he)
Definition: hdrfmt.c:3722
static int findTag(headerSprintfArgs hsa, sprintfToken token, const char *name)
Search extensions and tags for a name.
Definition: hdrfmt.c:5719
static headerSprintfArgs hsaFini(headerSprintfArgs hsa)
Finish an hsa iteration.
Definition: hdrfmt.c:5615
size_t len
Definition: hdrfmt.c:5407
static int wnlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp, HE_t PNhe, HE_t PEVRhe, HE_t PFhe)
Definition: hdrfmt.c:2990
#define RPM_MASK_TYPE
Definition: rpmtag.h:43
static int indent
Definition: rpmgi.c:47
void * headerGetRpmdb(Header h)
Return rpmdb pointer.
Definition: header.c:1259
static const char * name
headerSprintfExtension headerDefaultFormats
Supported default header tag output formats.
Definition: hdrfmt.c:328
int mireAppend(rpmMireMode mode, int tag, const char *pattern, const unsigned char *table, miRE *mirep, int *nmirep)
Append pattern to array.
Definition: mire.c:497
#define _(Text)
Definition: system.h:29
static int PRCOyamlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
Definition: hdrfmt.c:3754
ARGV_t params
Definition: hdrfmt.c:5375
static char * digestFormat(HE_t he, const char **av)
Return digest of tag data.
Definition: hdrfmt.c:4578
static int debevrfmtTag(Header h, HE_t he, HE_t Nhe, HE_t EVRhe, HE_t Fhe)
Return Debian formatted dependencies as string array.
Definition: hdrfmt.c:2764
#define xmalloc
Definition: system.h:32
static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
Definition: hdrfmt.c:3356
rpmTag * tagno
Definition: hdrfmt.c:5367
int extNum
Definition: hdrfmt.c:5365
ARGstr_t * ARGV_t
Definition: argv.h:12
static int F1sqlTag(Header h, HE_t he)
Definition: hdrfmt.c:4202
Access RPM indices using Berkeley DB interface(s).
enum rpmTag_e rpmTag
Definition: rpmtag.h:470
char *(* spew_strcpy)(char *t, const char *s, int lvl)
Definition: hdrfmt.c:339
static char * pgpHexStr(const rpmuint8_t *p, size_t plen)
Return hex formatted representation of bytes.
Definition: rpmpgp.h:1124
static rpmuint32_t uuid_version
Definition: hdrfmt.c:1814
const char * errmsg
Definition: hdrfmt.c:5435
static int CsqlTag(Header h, HE_t he)
Definition: hdrfmt.c:3738
static char * intFormat(HE_t he, const char **av, const char *fmt)
Convert tag data representation.
Definition: hdrfmt.c:87
Definition: argv.h:16
static const char uuid_auth[]
Definition: hdrfmt.c:1810
static char escapedChar(const char ch)
Definition: hdrfmt.c:5455
static int F2yamlTag(Header h, HE_t he)
Definition: hdrfmt.c:4356
static int FDGxmlTag(Header h, HE_t he, int lvl)
Definition: hdrfmt.c:3910
uint32_t headerGetInstance(Header h)
Return header instance (if from rpmdb).
Definition: header.c:1275
static char * hexFormat(HE_t he, const char **av)
Return hex formatted data.
Definition: hdrfmt.c:177
ARGint_t argiData(ARGI_t argi)
Return data from argi array.
Definition: argv.c:63
static int changelogtextTag(Header h, HE_t he)
Definition: hdrfmt.c:2337
const char * headerGetBaseURL(Header h)
Return header base URL (e.g path or URL).
Definition: header.c:1212
static const struct spew_s _json_spew
Definition: hdrfmt.c:533
const char * spew_init
Definition: hdrfmt.c:335
static int F2sqlTag(Header h, HE_t he)
Definition: hdrfmt.c:4210
#define xrealloc
Definition: system.h:35
rpmuint32_t rpmTagCount
Definition: rpmtag.h:55
static int RxmlTag(Header h, HE_t he)
Definition: hdrfmt.c:3488
headerSprintfExtension headerCompoundFormats
Supported default header extension/tag output formats.
Definition: hdrfmt.c:5278
static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn, HE_t he, HE_t ec)
Call a header extension only once, saving results.
Definition: hdrfmt.c:6235
static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, size_t element)
Format a single item's value.
Definition: hdrfmt.c:6261
static char * base64Format(HE_t he, const char **av)
Encode binary data in base64 for display.
Definition: hdrfmt.c:804
int j
Definition: mongo.h:438
const char const bson int num
Definition: mongo.h:485
rpmuint32_t value
Definition: hdrfmt.c:4407
static int origintid_uuidTag(Header h, HE_t he)
Retrieve origin tid and convert to UUIDv1.
Definition: hdrfmt.c:1799
rpmuint64_t * ui64p
Definition: rpmtag.h:71
const char * ns
Definition: mongo.h:326
static char * shescapeFormat(HE_t he, const char **av)
Return shell escape formatted data.
Definition: hdrfmt.c:258