File: | lib/headerfmt.c |
Warning: | line 733, column 2 Value stored to 't' is never read |
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 | */ |
22 | typedef struct sprintfTag_s * sprintfTag; |
23 | struct sprintfTag_s { |
24 | headerFmt fmt; |
25 | rpmTagVal tag; |
26 | int justOne; |
27 | char * format; |
28 | char * type; |
29 | }; |
30 | |
31 | typedef enum { |
32 | PTOK_NONE = 0, |
33 | PTOK_TAG, |
34 | PTOK_ARRAY, |
35 | PTOK_STRING, |
36 | PTOK_COND |
37 | } ptokType; |
38 | |
39 | /** \ingroup header |
40 | */ |
41 | typedef struct sprintfToken_s * sprintfToken; |
42 | struct 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 | */ |
76 | typedef 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 | |
92 | static 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 | */ |
112 | static sprintfToken |
113 | freeFormat( 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 | */ |
149 | static 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 | */ |
170 | static 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 | */ |
198 | static 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 | */ |
210 | static 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 | |
221 | RPM_GNUC_PRINTF(2, 3)__attribute__((__format__ (__printf__, 2, 3))) |
222 | static 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 | */ |
247 | static 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 | */ |
283 | static 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 | */ |
296 | static 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 | |
502 | errxit: |
503 | freeFormat(format, numTokens); |
504 | return 1; |
505 | } |
506 | |
507 | static 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 | |
605 | static 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 | */ |
620 | static 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 | */ |
643 | static 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 | */ |
688 | static 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; |
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); |
Value stored to 't' is never read | |
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 | |
838 | static int tagCmp(rpmTagVal a, rpmTagVal b) |
839 | { |
840 | return (a != b); |
841 | } |
842 | |
843 | static unsigned int tagId(rpmTagVal tag) |
844 | { |
845 | return tag; |
846 | } |
847 | |
848 | char * 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 | |
906 | exit: |
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 |