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