Bug Summary

File:lib/headerfmt.c
Warning:line 713, column 2
Value stored to 't' is never read

Annotated Source Code

1/** \ingroup header
2 * \file lib/headerfmt.c
3 */
4
5#include "system.h"
6
7#include <stdarg.h>
8#include <rpm/header.h>
9#include <rpm/rpmtag.h>
10#include <rpm/rpmstring.h>
11#include <rpm/rpmpgp.h>
12#include "lib/misc.h" /* format function protos */
13
14#include "debug.h"
15
16#define PARSER_BEGIN0 0
17#define PARSER_IN_ARRAY1 1
18#define PARSER_IN_EXPR2 2
19
20/** \ingroup header
21 */
22typedef struct sprintfTag_s * sprintfTag;
23struct sprintfTag_s {
24 headerFmt fmt;
25 rpmTagVal tag;
26 int justOne;
27 char * format;
28 char * type;
29};
30
31typedef enum {
32 PTOK_NONE = 0,
33 PTOK_TAG,
34 PTOK_ARRAY,
35 PTOK_STRING,
36 PTOK_COND
37} ptokType;
38
39/** \ingroup header
40 */
41typedef struct sprintfToken_s * sprintfToken;
42struct sprintfToken_s {
43 ptokType type;
44 union {
45 struct sprintfTag_s tag; /*!< PTOK_TAG */
46 struct {
47 sprintfToken format;
48 int i;
49 int numTokens;
50 } array; /*!< PTOK_ARRAY */
51 struct {
52 char * string;
53 int len;
54 } string; /*!< PTOK_STRING */
55 struct {
56 sprintfToken ifFormat;
57 int numIfTokens;
58 sprintfToken elseFormat;
59 int numElseTokens;
60 struct sprintfTag_s tag;
61 } cond; /*!< PTOK_COND */
62 } u;
63};
64
65#define HASHTYPE tagCache
66#define HTKEYTYPE rpmTagVal
67#define HTDATATYPE rpmtd
68#include "lib/rpmhash.H"
69#include "lib/rpmhash.C"
70#undef HASHTYPE
71#undef HTKEYTYPE
72#undef HTDATATYPE
73
74/**
75 */
76typedef struct headerSprintfArgs_s {
77 Header h;
78 char * fmt;
79 const char * errmsg;
80 tagCache cache;
81 sprintfToken format;
82 HeaderIterator hi;
83 char * val;
84 size_t vallen;
85 size_t alloced;
86 int numTokens;
87 int i;
88 headerGetFlags hgflags;
89} * headerSprintfArgs;
90
91
92static char escapedChar(const char ch)
93{
94 switch (ch) {
95 case 'a': return '\a';
96 case 'b': return '\b';
97 case 'f': return '\f';
98 case 'n': return '\n';
99 case 'r': return '\r';
100 case 't': return '\t';
101 case 'v': return '\v';
102 default: return ch;
103 }
104}
105
106/**
107 * Destroy headerSprintf format array.
108 * @param format sprintf format array
109 * @param num number of elements
110 * @return NULL always
111 */
112static sprintfToken
113freeFormat( sprintfToken format, int num)
114{
115 int i;
116
117 if (format == NULL((void*)0)) return NULL((void*)0);
118
119 for (i = 0; i < num; i++) {
120 switch (format[i].type) {
121 case PTOK_ARRAY:
122 format[i].u.array.format =
123 freeFormat(format[i].u.array.format,
124 format[i].u.array.numTokens);
125 break;
126 case PTOK_COND:
127 format[i].u.cond.ifFormat =
128 freeFormat(format[i].u.cond.ifFormat,
129 format[i].u.cond.numIfTokens);
130 format[i].u.cond.elseFormat =
131 freeFormat(format[i].u.cond.elseFormat,
132 format[i].u.cond.numElseTokens);
133 break;
134 case PTOK_NONE:
135 case PTOK_TAG:
136 case PTOK_STRING:
137 default:
138 break;
139 }
140 }
141 free(format);
142 return NULL((void*)0);
143}
144
145/**
146 * Initialize an hsa iteration.
147 * @param hsa headerSprintf args
148 */
149static void hsaInit(headerSprintfArgs hsa)
150{
151 sprintfTag tag =
152 (hsa->format->type == PTOK_TAG
153 ? &hsa->format->u.tag :
154 (hsa->format->type == PTOK_ARRAY
155 ? &hsa->format->u.array.format->u.tag :
156 NULL((void*)0)));
157
158 hsa->i = 0;
159 if (tag != NULL((void*)0) && tag->tag == -2)
160 hsa->hi = headerInitIterator(hsa->h);
161 /* Normally with bells and whistles enabled, but raw dump on iteration. */
162 hsa->hgflags = (hsa->hi == NULL((void*)0)) ? HEADERGET_EXT : HEADERGET_RAW;
163}
164
165/**
166 * Return next hsa iteration item.
167 * @param hsa headerSprintf args
168 * @return next sprintfToken (or NULL)
169 */
170static sprintfToken hsaNext(headerSprintfArgs hsa)
171{
172 sprintfToken fmt = NULL((void*)0);
173 sprintfTag tag =
174 (hsa->format->type == PTOK_TAG
175 ? &hsa->format->u.tag :
176 (hsa->format->type == PTOK_ARRAY
177 ? &hsa->format->u.array.format->u.tag :
178 NULL((void*)0)));
179
180 if (hsa->i >= 0 && hsa->i < hsa->numTokens) {
181 fmt = hsa->format + hsa->i;
182 if (hsa->hi == NULL((void*)0)) {
183 hsa->i++;
184 } else {
185 tag->tag = headerNextTag(hsa->hi);
186 if (tag->tag == RPMTAG_NOT_FOUND)
187 fmt = NULL((void*)0);
188 }
189 }
190
191 return fmt;
192}
193
194/**
195 * Finish an hsa iteration.
196 * @param hsa headerSprintf args
197 */
198static void hsaFini(headerSprintfArgs hsa)
199{
200 hsa->hi = headerFreeIterator(hsa->hi);
201 hsa->i = 0;
202}
203
204/**
205 * Reserve sufficient buffer space for next output value.
206 * @param hsa headerSprintf args
207 * @param need no. of bytes to reserve
208 * @return pointer to reserved space
209 */
210static char * hsaReserve(headerSprintfArgs hsa, size_t need)
211{
212 if ((hsa->vallen + need) >= hsa->alloced) {
213 if (hsa->alloced <= need)
214 hsa->alloced += need;
215 hsa->alloced <<= 1;
216 hsa->val = xrealloc(hsa->val, hsa->alloced+1)rrealloc((hsa->val), (hsa->alloced+1));
217 }
218 return hsa->val + hsa->vallen;
219}
220
221RPM_GNUC_PRINTF(2, 3)__attribute__((__format__ (__printf__, 2, 3)))
222static void hsaError(headerSprintfArgs hsa, const char *fmt, ...)
223{
224 /* Use thread local static buffer as headerFormat() errmsg arg is const */
225 static __thread char errbuf[BUFSIZ8192];
226
227 if (fmt == NULL((void*)0)) {
228 hsa->errmsg = NULL((void*)0);
229 } else {
230 va_list ap;
231
232 va_start(ap, fmt)__builtin_va_start(ap, fmt);
233 vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
234 va_end(ap)__builtin_va_end(ap);
235
236 hsa->errmsg = errbuf;
237 }
238}
239
240/**
241 * Search tags for a name.
242 * @param hsa headerSprintf args
243 * @param token parsed fields
244 * @param name name to find
245 * @return 0 on success, 1 on not found
246 */
247static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
248{
249 const char *tagname = name;
250 sprintfTag stag = (token->type == PTOK_COND
251 ? &token->u.cond.tag : &token->u.tag);
252
253 stag->fmt = NULL((void*)0);
254 stag->tag = RPMTAG_NOT_FOUND;
255
256 if (!rstreq(tagname, "*")) {
257 if (rstreqn("RPMTAG_", tagname, sizeof("RPMTAG_")-1)) {
258 tagname += sizeof("RPMTAG");
259 }
260
261 /* Search tag names. */
262 stag->tag = rpmTagGetValue(tagname);
263 if (stag->tag == RPMTAG_NOT_FOUND) return 1;
264
265 } else stag->tag = -2;
266
267 /* Search extensions for specific format. */
268 if (stag->type != NULL((void*)0))
269 stag->fmt = rpmHeaderFormatByName(stag->type);
270
271 return stag->fmt ? 0 : 1;
272}
273
274/* forward ref */
275/**
276 * Parse an expression.
277 * @param hsa headerSprintf args
278 * @param token token
279 * @param str string
280 * @param[out] *endPtr
281 * @return 0 on success
282 */
283static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
284 char * str,char ** endPtr);
285
286/**
287 * Parse a headerSprintf term.
288 * @param hsa headerSprintf args
289 * @param str
290 * @retval *formatPtr
291 * @retval *numTokensPtr
292 * @retval *endPtr
293 * @param state
294 * @return 0 on success
295 */
296static int parseFormat(headerSprintfArgs hsa, char * str,
297 sprintfToken * formatPtr,int * numTokensPtr,
298 char ** endPtr, int state)
299{
300 char * chptr, * start, * next, * dst;
301 sprintfToken format;
302 sprintfToken token;
303 int numTokens;
304 int done = 0;
305
306 /* upper limit on number of individual formats */
307 numTokens = 0;
308 if (str != NULL((void*)0))
309 for (chptr = str; *chptr != '\0'; chptr++)
310 if (*chptr == '%' || *chptr == '[') numTokens++;
311 numTokens = numTokens * 2 + 1;
312
313 format = xcalloc(numTokens, sizeof(*format))rcalloc((numTokens), (sizeof(*format)));
314 if (endPtr) *endPtr = NULL((void*)0);
315
316 dst = start = str;
317 numTokens = 0;
318 token = NULL((void*)0);
319 if (start != NULL((void*)0))
320 while (*start != '\0') {
321 switch (*start) {
322 case '%':
323 /* handle %% */
324 if (*(start + 1) == '%') {
325 if (token == NULL((void*)0) || token->type != PTOK_STRING) {
326 token = format + numTokens++;
327 token->type = PTOK_STRING;
328 dst = token->u.string.string = start;
329 }
330 start++;
331 *dst++ = *start++;
332 break;
333 }
334
335 token = format + numTokens++;
336 *dst++ = '\0';
337 start++;
338
339 if (*start == '|') {
340 char * newEnd;
341
342 start++;
343 if (parseExpression(hsa, token, start, &newEnd)) {
344 goto errxit;
345 }
346 start = newEnd;
347 break;
348 }
349
350 token->u.tag.format = start;
351 token->u.tag.justOne = 0;
352
353 chptr = start;
354 while (*chptr && *chptr != '{' && *chptr != '%') {
355 if (!risdigit(*chptr) && *chptr != '-') {
356 hsaError(hsa, _("invalid field width")dcgettext ("rpm", "invalid field width", 5));
357 goto errxit;
358 }
359 chptr++;
360 }
361 if (!*chptr || *chptr == '%') {
362 hsaError(hsa, _("missing { after %%")dcgettext ("rpm", "missing { after %%", 5));
363 goto errxit;
364 }
365
366 *chptr++ = '\0';
367
368 while (start < chptr) {
369 start++;
370 }
371
372 if (*start == '=') {
373 token->u.tag.justOne = 1;
374 start++;
375 } else if (*start == '#') {
376 token->u.tag.justOne = 1;
377 token->u.tag.type = "arraysize";
378 start++;
379 }
380
381 dst = next = start;
382 while (*next && *next != '}') next++;
383 if (!*next) {
384 hsaError(hsa, _("missing } after %%{")dcgettext ("rpm", "missing } after %%{", 5));
385 goto errxit;
386 }
387 *next++ = '\0';
388
389 chptr = start;
390 while (*chptr && *chptr != ':') chptr++;
391
392 if (*chptr != '\0') {
393 *chptr++ = '\0';
394 if (!*chptr) {
395 hsaError(hsa, _("empty tag format")dcgettext ("rpm", "empty tag format", 5));
396 goto errxit;
397 }
398 token->u.tag.type = chptr;
399 }
400 /* default to string conversion if no formats found by now */
401 if (!token->u.tag.type) {
402 token->u.tag.type = "string";
403 }
404
405 if (!*start) {
406 hsaError(hsa, _("empty tag name")dcgettext ("rpm", "empty tag name", 5));
407 goto errxit;
408 }
409
410 token->type = PTOK_TAG;
411
412 if (findTag(hsa, token, start)) {
413 hsaError(hsa, _("unknown tag: \"%s\"")dcgettext ("rpm", "unknown tag: \"%s\"", 5), start);
414 goto errxit;
415 }
416
417 /* Set justOne = 1 for non ARRAY tags */
418 if (token->type == PTOK_TAG &&
419 !(rpmTagGetReturnType(token->u.tag.tag) &
420 RPM_ARRAY_RETURN_TYPE)) {
421 token->u.tag.justOne = 1;
422 }
423
424 start = next;
425 break;
426
427 case '[':
428 *dst++ = '\0';
429 *start++ = '\0';
430 token = format + numTokens++;
431
432 if (parseFormat(hsa, start,
433 &token->u.array.format,
434 &token->u.array.numTokens,
435 &start, PARSER_IN_ARRAY1)) {
436 goto errxit;
437 }
438
439 if (!start) {
440 hsaError(hsa, _("] expected at end of array")dcgettext ("rpm", "] expected at end of array", 5));
441 goto errxit;
442 }
443
444 dst = start;
445
446 token->type = PTOK_ARRAY;
447
448 break;
449
450 case ']':
451 if (state != PARSER_IN_ARRAY1) {
452 hsaError(hsa, _("unexpected ]")dcgettext ("rpm", "unexpected ]", 5));
453 goto errxit;
454 }
455 *start++ = '\0';
456 if (endPtr) *endPtr = start;
457 done = 1;
458 break;
459
460 case '}':
461 if (state != PARSER_IN_EXPR2) {
462 hsaError(hsa, _("unexpected }")dcgettext ("rpm", "unexpected }", 5));
463 goto errxit;
464 }
465 *start++ = '\0';
466 if (endPtr) *endPtr = start;
467 done = 1;
468 break;
469
470 default:
471 if (token == NULL((void*)0) || token->type != PTOK_STRING) {
472 token = format + numTokens++;
473 token->type = PTOK_STRING;
474 dst = token->u.string.string = start;
475 }
476
477 if (*start == '\\') {
478 start++;
479 *dst++ = escapedChar(*start++);
480 } else {
481 *dst++ = *start++;
482 }
483 break;
484 }
485 if (done)
486 break;
487 }
488
489 if (dst != NULL((void*)0))
490 *dst = '\0';
491
492 for (int i = 0; i < numTokens; i++) {
493 token = format + i;
494 if (token->type == PTOK_STRING)
495 token->u.string.len = strlen(token->u.string.string);
496 }
497
498 *numTokensPtr = numTokens;
499 *formatPtr = format;
500 return 0;
501
502errxit:
503 freeFormat(format, numTokens);
504 return 1;
505}
506
507static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
508 char * str, char ** endPtr)
509{
510 char * chptr;
511 char * end;
512
513 hsaError(hsa, NULL((void*)0));
514 chptr = str;
515 while (*chptr && *chptr != '?') chptr++;
516
517 if (*chptr != '?') {
518 hsaError(hsa, _("? expected in expression")dcgettext ("rpm", "? expected in expression", 5));
519 return 1;
520 }
521
522 *chptr++ = '\0';;
523
524 if (*chptr != '{') {
525 hsaError(hsa, _("{ expected after ? in expression")dcgettext ("rpm", "{ expected after ? in expression", 5));
526 return 1;
527 }
528
529 chptr++;
530
531 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
532 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR2))
533 return 1;
534
535 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
536 if (!(end && *end)) {
537 hsaError(hsa, _("} expected in expression")dcgettext ("rpm", "} expected in expression", 5));
538 token->u.cond.ifFormat =
539 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
540 return 1;
541 }
542
543 chptr = end;
544 if (*chptr != ':' && *chptr != '|') {
545 hsaError(hsa, _(": expected following ? subexpression")dcgettext ("rpm", ": expected following ? subexpression", 5));
546 token->u.cond.ifFormat =
547 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
548 return 1;
549 }
550
551 if (*chptr == '|') {
552 if (parseFormat(hsa, NULL((void*)0), &token->u.cond.elseFormat,
553 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR2))
554 {
555 token->u.cond.ifFormat =
556 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
557 return 1;
558 }
559 } else {
560 chptr++;
561
562 if (*chptr != '{') {
563 hsaError(hsa, _("{ expected after : in expression")dcgettext ("rpm", "{ expected after : in expression", 5));
564 token->u.cond.ifFormat =
565 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
566 return 1;
567 }
568
569 chptr++;
570
571 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
572 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR2))
573 return 1;
574
575 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
576 if (!(end && *end)) {
577 hsaError(hsa, _("} expected in expression")dcgettext ("rpm", "} expected in expression", 5));
578 token->u.cond.ifFormat =
579 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
580 return 1;
581 }
582
583 chptr = end;
584 if (*chptr != '|') {
585 hsaError(hsa, _("| expected at end of expression")dcgettext ("rpm", "| expected at end of expression", 5));
586 token->u.cond.ifFormat =
587 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
588 token->u.cond.elseFormat =
589 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
590 return 1;
591 }
592 }
593
594 chptr++;
595
596 *endPtr = chptr;
597
598 token->type = PTOK_COND;
599
600 (void) findTag(hsa, token, str);
601
602 return 0;
603}
604
605static rpmtd getCached(tagCache cache, rpmTagVal tag)
606{
607 rpmtd *res = NULL((void*)0);
608 return tagCacheGetEntry(cache, tag, &res, NULL((void*)0), NULL((void*)0)) ? res[0] : NULL((void*)0);
609}
610
611/**
612 * Do headerGet() just once for given tag, cache results.
613 * @param hsa headerSprintf args
614 * @param tag
615 * @retval *typeptr
616 * @retval *data
617 * @retval *countptr
618 * @return 1 on success, 0 on failure
619 */
620static rpmtd getData(headerSprintfArgs hsa, rpmTagVal tag)
621{
622 rpmtd td = NULL((void*)0);
623
624 if (!(td = getCached(hsa->cache, tag))) {
625 td = rpmtdNew();
626 if (!headerGet(hsa->h, tag, td, hsa->hgflags)) {
627 rpmtdFree(td);
628 return NULL((void*)0);
629 }
630 tagCacheAddEntry(hsa->cache, tag, td);
631 }
632
633 return td;
634}
635
636/**
637 * formatValue
638 * @param hsa headerSprintf args
639 * @param tag
640 * @param element
641 * @return end of formatted string (NULL on error)
642 */
643static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
644{
645 char * val = NULL((void*)0);
646 size_t need = 0;
647 char * t, * te;
648 rpmtd td;
649
650 if ((td = getData(hsa, tag->tag)) && td->count > element) {
651 td->ix = element; /* Ick, use iterators instead */
652 val = rpmHeaderFormatCall(tag->fmt, td);
653 } else {
654 val = xstrdup("(none)")rstrdup(("(none)"));
655 }
656
657 /* Handle field width + justification formatting if specified */
658 if (tag->format && *tag->format) {
659 char *tval = NULL((void*)0);
660 /* user string + extra for '%', format char and trailing '\0' */
661 char fmtbuf[strlen(tag->format) + 3];
662
663 sprintf(fmtbuf, "%%%ss", tag->format);
664 rasprintf(&tval, fmtbuf, val);
665 free(val);
666 val = tval;
667 }
668
669 need = strlen(val);
670
671 if (val && need > 0) {
672 t = hsaReserve(hsa, need);
673 te = stpcpy(t, val);
674 hsa->vallen += (te - t);
675 }
676 free(val);
677
678 return (hsa->val + hsa->vallen);
679}
680
681/**
682 * Format a single headerSprintf item.
683 * @param hsa headerSprintf args
684 * @param token
685 * @param element
686 * @return end of formatted string (NULL on error)
687 */
688static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
689 int element)
690{
691 char * t, * te;
692 int i, j, found, singleItem;
693 int count, numElements;
694 sprintfToken spft;
695 int condNumFormats;
696 size_t need;
697
698 /* we assume the token and header have been validated already! */
699
700 switch (token->type) {
701 case PTOK_NONE:
702 break;
703
704 case PTOK_STRING:
705 need = token->u.string.len;
706 if (need == 0) break;
707 t = hsaReserve(hsa, need);
708 te = stpcpy(t, token->u.string.string);
709 hsa->vallen += (te - t);
710 break;
711
712 case PTOK_TAG:
713 t = hsa->val + hsa->vallen;
Value stored to 't' is never read
714 te = formatValue(hsa, &token->u.tag,
715 (token->u.tag.justOne ? 0 : element));
716 if (te == NULL((void*)0))
717 return NULL((void*)0);
718 break;
719
720 case PTOK_COND:
721 if (getData(hsa, token->u.cond.tag.tag) ||
722 headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
723 spft = token->u.cond.ifFormat;
724 condNumFormats = token->u.cond.numIfTokens;
725 } else {
726 spft = token->u.cond.elseFormat;
727 condNumFormats = token->u.cond.numElseTokens;
728 }
729
730 need = condNumFormats * 20;
731 if (spft == NULL((void*)0) || need == 0) break;
732
733 t = hsaReserve(hsa, need);
734 for (i = 0; i < condNumFormats; i++, spft++) {
735 te = singleSprintf(hsa, spft, element);
736 if (te == NULL((void*)0))
737 return NULL((void*)0);
738 }
739 break;
740
741 case PTOK_ARRAY:
742 numElements = -1;
743 singleItem = 0;
744 found = 0;
745 spft = token->u.array.format;
746 /* get number of array items */
747 for (i = 0; i < token->u.array.numTokens; i++, spft++)
748 {
749 rpmtd td = NULL((void*)0);
750 if (spft->type != PTOK_TAG) continue;
751
752 if (!(td = getData(hsa, spft->u.tag.tag))) {
753 continue;
754 }
755
756 count = rpmtdCount(td);
757 found = 1;
758
759 if (spft->u.tag.justOne) {
760 if (count) {
761 singleItem = 1;
762 }
763 continue;
764 }
765
766
767 if (numElements > 0 && count != numElements)
768 switch (td->type) {
769 default:
770 hsaError(hsa,
771 _("array iterator used with different sized arrays")dcgettext ("rpm", "array iterator used with different sized arrays"
, 5)
);
772 return NULL((void*)0);
773 break;
774 case RPM_BIN_TYPE:
775 case RPM_STRING_TYPE:
776 break;
777 }
778 if (count > numElements)
779 numElements = count;
780 }
781
782 if (numElements == -1 && singleItem) {
783 /* only justOne elements */
784 numElements = 1;
785 } else if (numElements == -1) {
786 /* nothing at all */
787 numElements = 0;
788 }
789
790 if (found) {
791 int isxml;
792
793 need = numElements * token->u.array.numTokens * 10;
794 if (need == 0) break;
795
796 spft = token->u.array.format;
797 isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL((void*)0) &&
798 rstreq(spft->u.tag.type, "xml"));
799
800 if (isxml) {
801 const char * tagN = rpmTagGetName(spft->u.tag.tag);
802
803 need = sizeof(" <rpmTag name=\"\">\n") - 1;
804 if (tagN != NULL((void*)0))
805 need += strlen(tagN);
806 t = hsaReserve(hsa, need);
807 te = stpcpy(t, " <rpmTag name=\"");
808 if (tagN != NULL((void*)0))
809 te = stpcpy(te, tagN);
810 te = stpcpy(te, "\">\n");
811 hsa->vallen += (te - t);
812 }
813
814 t = hsaReserve(hsa, need);
815 for (j = 0; j < numElements; j++) {
816 spft = token->u.array.format;
817 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
818 te = singleSprintf(hsa, spft, j);
819 if (te == NULL((void*)0))
820 return NULL((void*)0);
821 }
822 }
823
824 if (isxml) {
825 need = sizeof(" </rpmTag>\n") - 1;
826 t = hsaReserve(hsa, need);
827 te = stpcpy(t, " </rpmTag>\n");
828 hsa->vallen += (te - t);
829 }
830
831 }
832 break;
833 }
834
835 return (hsa->val + hsa->vallen);
836}
837
838static int tagCmp(rpmTagVal a, rpmTagVal b)
839{
840 return (a != b);
841}
842
843static unsigned int tagId(rpmTagVal tag)
844{
845 return tag;
846}
847
848char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg)
849{
850 struct headerSprintfArgs_s hsa;
851 sprintfToken nextfmt;
852 sprintfTag tag;
853 char * t, * te;
854 int isxml;
855 size_t need;
856
857 memset(&hsa, 0, sizeof(hsa));
858 hsa.h = headerLink(h);
859 hsa.fmt = xstrdup(fmt)rstrdup((fmt));
860 hsa.errmsg = NULL((void*)0);
861
862 if (parseFormat(&hsa, hsa.fmt, &hsa.format, &hsa.numTokens, NULL((void*)0), PARSER_BEGIN0))
863 goto exit;
864
865 hsa.cache = tagCacheCreate(128, tagId, tagCmp, NULL((void*)0), rpmtdFree);
866 hsa.val = xstrdup("")rstrdup((""));
867
868 tag =
869 (hsa.format->type == PTOK_TAG
870 ? &hsa.format->u.tag :
871 (hsa.format->type == PTOK_ARRAY
872 ? &hsa.format->u.array.format->u.tag :
873 NULL((void*)0)));
874 isxml = (tag != NULL((void*)0) && tag->tag == -2 && tag->type != NULL((void*)0) && rstreq(tag->type, "xml"));
875
876 if (isxml) {
877 need = sizeof("<rpmHeader>\n") - 1;
878 t = hsaReserve(&hsa, need);
879 te = stpcpy(t, "<rpmHeader>\n");
880 hsa.vallen += (te - t);
881 }
882
883 hsaInit(&hsa);
884 while ((nextfmt = hsaNext(&hsa)) != NULL((void*)0)) {
885 te = singleSprintf(&hsa, nextfmt, 0);
886 if (te == NULL((void*)0)) {
887 hsa.val = _free(hsa.val)rfree((hsa.val));
888 break;
889 }
890 }
891 hsaFini(&hsa);
892
893 if (isxml) {
894 need = sizeof("</rpmHeader>\n") - 1;
895 t = hsaReserve(&hsa, need);
896 te = stpcpy(t, "</rpmHeader>\n");
897 hsa.vallen += (te - t);
898 }
899
900 if (hsa.val != NULL((void*)0) && hsa.vallen < hsa.alloced)
901 hsa.val = xrealloc(hsa.val, hsa.vallen+1)rrealloc((hsa.val), (hsa.vallen+1));
902
903 hsa.cache = tagCacheFree(hsa.cache);
904 hsa.format = freeFormat(hsa.format, hsa.numTokens);
905
906exit:
907 if (errmsg)
908 *errmsg = hsa.errmsg;
909 hsa.h = headerFree(hsa.h);
910 hsa.fmt = _free(hsa.fmt)rfree((hsa.fmt));
911 return hsa.val;
912}
913