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