5 #undef REMALLOC_HEADER_REGION
9 /* RPM - Copyright (C) 1995-2000 Red Hat Software */
11 /* Data written to file descriptors is in network byte order. */
12 /* Data read from file descriptors is expected to be in */
13 /* network byte order and is converted on the fly to host order. */
17 #if !defined(__LCLINT__)
18 #include <netinet/in.h>
19 #endif /* __LCLINT__ */
25 /*@-redecl@*/ /* FIX: avoid rpmlib.h, need for debugging. */
26 /*@observer@*/ const char *const tagName(int tag) /*@*/;
30 * Teach header.c about legacy tags.
32 #define HEADER_OLDFILENAMES 1027
33 #define HEADER_BASENAMES 1117
35 #define INDEX_MALLOC_SIZE 8
37 #define PARSER_BEGIN 0
38 #define PARSER_IN_ARRAY 1
39 #define PARSER_IN_EXPR 2
41 static unsigned char header_magic[8] = {
42 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
46 * Alignment needs (and sizeof scalars types) for internal rpm data types.
48 static int typeSizes[] = {
49 0, /*!< RPM_NULL_TYPE */
50 1, /*!< RPM_CHAR_TYPE */
51 1, /*!< RPM_INT8_TYPE */
52 2, /*!< RPM_INT16_TYPE */
53 4, /*!< RPM_INT32_TYPE */
54 -1, /*!< RPM_INT64_TYPE */
55 -1, /*!< RPM_STRING_TYPE */
56 1, /*!< RPM_BIN_TYPE */
57 -1, /*!< RPM_STRING_ARRAY_TYPE */
58 -1 /*!< RPM_I18NSTRING_TYPE */
62 * Description of tag data.
65 int_32 tag; /*!< Tag identifier. */
66 int_32 type; /*!< Tag data type. */
67 int_32 offset; /*!< Offset into data segment (ondisk only). */
68 int_32 count; /*!< Number of tag elements. */
71 #define REGION_TAG_TYPE RPM_BIN_TYPE
72 #define REGION_TAG_COUNT sizeof(struct entryInfo)
74 #define ENTRY_IS_REGION(_e) ((_e)->info.tag < HEADER_I18NTABLE)
75 #define ENTRY_IN_REGION(_e) ((_e)->info.offset < 0)
78 * A single tag from a Header.
81 struct entryInfo info; /*!< Description of tag data. */
82 /*@owned@*/ void * data; /*!< Location of tag data. */
83 int length; /*!< No. bytes of data. */
84 int rdlen; /*!< No. bytes of data in region. */
88 * The Header data structure.
91 /*@owned@*/ struct indexEntry * index; /*!< Array of tags. */
92 int indexUsed; /*!< Current size of tag array. */
93 int indexAlloced; /*!< Allocated size of tag array. */
94 int region_allocated; /*!< Is 1st header region allocated? */
95 int sorted; /*!< Are header entries sorted? */
96 int legacy; /*!< Header came from legacy source? */
97 /*@refs@*/ int nrefs; /*!< Reference count. */
103 /*@null@*/ headerTagTagFunction ext; /*!< if NULL tag element is invalid */
108 /*@kept@*/ char * format;
109 /*@kept@*/ /*@null@*/ char * type;
115 struct extensionCache {
120 /*@owned@*/ const void * data;
125 struct sprintfToken {
135 /*@only@*/ struct sprintfToken * format;
138 struct sprintfTag tag;
140 /*@dependent@*/ char * string;
144 /*@only@*/ /*@null@*/ struct sprintfToken * ifFormat;
146 /*@only@*/ /*@null@*/ struct sprintfToken * elseFormat;
148 struct sprintfTag tag;
154 * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
155 * @param p memory to free
156 * @return NULL always
158 /*@unused@*/ static inline /*@null@*/ void *
159 _free(/*@only@*/ /*@null@*/ const void * p) /*@modifies *p @*/
161 if (p != NULL) free((void *)p);
166 * Return length of entry data.
167 * @param type entry data type
168 * @param p entry data
169 * @param count entry item count
170 * @param onDisk data is concatenated strings (with NUL's))?
171 * @return no. bytes in data
174 static int dataLength(int_32 type, const void * p, int_32 count, int onDisk)
175 /*@modifies fileSystem @*/
180 case RPM_STRING_TYPE:
181 if (count == 1) { /* Special case -- p is just the string */
182 length = strlen(p) + 1;
185 /* This should not be allowed */
186 fprintf(stderr, _("dataLength() RPM_STRING_TYPE count must be 1.\n"));
188 /*@notreached@*/ break;
190 case RPM_STRING_ARRAY_TYPE:
191 case RPM_I18NSTRING_TYPE:
194 /* This is like RPM_STRING_TYPE, except it's *always* an array */
195 /* Compute sum of length of all strings, including null terminators */
199 const char * chptr = p;
203 thisLen = strlen(chptr) + 1;
208 const char ** src = (const char **)p;
210 /* add one for null termination */
211 length += strlen(*src++) + 1;
217 if (typeSizes[type] != -1) {
218 length = typeSizes[type] * count;
221 fprintf(stderr, _("Data type %d not supported\n"), (int) type);
223 /*@notreached@*/ break;
230 * Swap int_32 and int_16 arrays within header region.
232 * This code is way more twisty than I would like.
234 * A bug with RPM_I18NSTRING_TYPE in rpm-2.5.x (fixed in August 1998)
235 * causes the offset and length of elements in a header region to disagree
236 * regarding the total length of the region data.
238 * The "fix" is to compute the size using both offset and length and
239 * return the larger of the two numbers as the size of the region.
240 * Kinda like computing left and right Riemann sums of the data elements
241 * to determine the size of a data structure, go figger :-).
243 * There's one other twist if a header region tag is in the set to be swabbed,
244 * as the data for a header region is located after all other tag data.
246 * @param entry header entry
247 * @param il no. of entries
248 * @param dl start no. bytes of data
249 * @param pe header physical entry pointer (swapped)
250 * @param dataStart header data
251 * @param regionid region offset
252 * @return no. bytes of data in region, -1 on error
254 static int regionSwab(/*@null@*/ struct indexEntry * entry, int il, int dl,
255 const struct entryInfo * pe, char * dataStart, int regionid)
256 /*@modifies *entry, *dataStart @*/
262 for (; il > 0; il--, pe++) {
263 struct indexEntry ie;
266 ie.info.tag = ntohl(pe->tag);
267 ie.info.type = ntohl(pe->type);
268 if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
270 ie.info.count = ntohl(pe->count);
271 ie.info.offset = ntohl(pe->offset);
272 ie.data = t = dataStart + ie.info.offset;
273 ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1);
277 ie.info.offset = regionid;
278 *entry = ie; /* structure assignment */
284 if (typeSizes[type] > 1) {
286 diff = typeSizes[type] - (dl % typeSizes[type]);
287 if (diff != typeSizes[type]) {
291 tdel = (tprev ? (t - tprev) : 0);
294 tprev = (ie.info.tag < HEADER_I18NTABLE)
297 /* Perform endian conversions */
298 switch (ntohl(pe->type)) {
300 { int_32 * it = (int_32 *)t;
301 for (; ie.info.count > 0; ie.info.count--, it += 1)
306 { int_16 * it = (int_16 *) t;
307 for (; ie.info.count > 0; ie.info.count--, it += 1)
316 tdel = (tprev ? (t - tprev) : 0);
324 * Retrieve data from header entry.
325 * @todo Permit retrieval of regions other than HEADER_IMUTABLE.
326 * @param entry header entry
327 * @retval type address of type (or NULL)
328 * @retval p address of data (or NULL)
329 * @retval c address of count (or NULL)
330 * @param minMem string pointers refer to header memory?
331 * @return 1 on success, otherwise error.
333 static int copyEntry(const struct indexEntry * entry,
334 /*@null@*/ /*@out@*/ int_32 * type,
335 /*@null@*/ /*@out@*/ const void ** p,
336 /*@null@*/ /*@out@*/ int_32 * c,
338 /*@modifies *type, *p, *c @*/
340 int_32 count = entry->info.count;
341 int rc = 1; /* XXX 1 on success. */
344 switch (entry->info.type) {
346 /* XXX this only works for HEADER_IMMUTABLE */
347 if (ENTRY_IS_REGION(entry)) {
348 int_32 * ei = ((int_32 *)entry->data) - 2;
349 struct entryInfo * pe = (struct entryInfo *) (ei + 2);
350 char * dataStart = (char *) (pe + ntohl(ei[0]));
351 int_32 rdl = -entry->info.offset; /* negative offset */
352 int_32 ril = rdl/sizeof(*pe);
354 count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) +
355 entry->rdlen + REGION_TAG_COUNT;
359 ei[1] = htonl(entry->rdlen + REGION_TAG_COUNT);
360 pe = (struct entryInfo *) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
361 dataStart = (char *) memcpy(pe + ril, dataStart,
362 (entry->rdlen + REGION_TAG_COUNT));
364 rc = regionSwab(NULL, ril, 0, pe, dataStart, 0);
365 /* XXX 1 on success. */
366 rc = (rc < 0) ? 0 : 1;
368 count = entry->length;
370 ? memcpy(xmalloc(count), entry->data, count)
374 case RPM_STRING_TYPE:
380 case RPM_STRING_ARRAY_TYPE:
381 case RPM_I18NSTRING_TYPE:
382 { const char ** ptrEntry;
383 int tableSize = count * sizeof(char *);
389 *p = xmalloc(tableSize);
390 ptrEntry = (const char **) *p;
393 t = xmalloc(tableSize + entry->length);
395 ptrEntry = (const char **) *p;
397 memcpy(t, entry->data, entry->length);
400 for (i = 0; i < count; i++) {
411 if (type) *type = entry->info.type;
417 * Header tag iterator data structure.
419 struct headerIteratorS {
420 Header h; /*!< Header being iterated. */
421 int next_index; /*!< Next tag index. */
424 HeaderIterator headerInitIterator(Header h)
426 HeaderIterator hi = xmalloc(sizeof(struct headerIteratorS));
430 hi->h = headerLink(h);
435 void headerFreeIterator(HeaderIterator hi)
437 hi->h = headerFree(hi->h);
441 int headerNextIterator(HeaderIterator hi,
442 int_32 * tag, int_32 * type, const void ** p, int_32 * c)
445 int slot = hi->next_index;
446 struct indexEntry * entry = NULL;
449 for (slot = hi->next_index; slot < h->indexUsed; slot++) {
450 entry = h->index + slot;
451 if (!ENTRY_IS_REGION(entry))
454 hi->next_index = slot;
455 if (entry == NULL || slot >= h->indexUsed)
460 *tag = entry->info.tag;
462 rc = copyEntry(entry, type, p, c, 0);
464 /* XXX 1 on success */
465 return ((rc == 1) ? 1 : 0);
470 static int indexCmp(const void *avp, const void *bvp) /*@*/
472 const struct indexEntry * ap = avp, * bp = bvp;
473 return (ap->info.tag - bp->info.tag);
476 void headerSort(Header h)
479 qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
486 static int offsetCmp(const void *avp, const void *bvp) /*@*/
488 const struct indexEntry * ap = avp, * bp = bvp;
489 int rc = (ap->info.offset - bp->info.offset);
492 rc = (ap->info.tag - bp->info.tag);
496 void headerUnsort(Header h)
498 qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
501 Header headerCopy(Header h)
503 Header nh = headerNew();
505 int_32 tag, type, count;
508 for (hi = headerInitIterator(h);
509 headerNextIterator(hi, &tag, &type, &ptr, &count);
510 ptr = headerFreeData((void *)ptr, type))
512 if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
514 headerFreeIterator(hi);
516 return headerReload(nh, HEADER_IMAGE);
519 Header headerLoad(void *uh)
521 int_32 *ei = (int_32 *) uh;
522 int_32 il = ntohl(ei[0]); /* index length */
523 int_32 dl = ntohl(ei[1]); /* data length */
524 int pvlen = sizeof(il) + sizeof(dl) +
525 (il * sizeof(struct entryInfo)) + dl;
526 #ifdef REMALLOC_HEADER_REGION
527 void * pv = memcpy(xmalloc(pvlen), uh, pvlen);
531 Header h = xcalloc(1, sizeof(*h));
532 struct entryInfo * pe;
534 struct indexEntry * entry;
539 pe = (struct entryInfo *) &ei[2];
540 dataStart = (char *) (pe + il);
542 h->indexAlloced = il + 1;
544 h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
546 #ifdef REMALLOC_HEADER_REGION
547 h->region_allocated = 1;
549 h->region_allocated = 0;
554 * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
555 * %verifyscript tag that needs to be diddled.
557 if (ntohl(pe->tag) == 15 &&
558 ntohl(pe->type) == RPM_STRING_TYPE &&
559 ntohl(pe->count) == 1)
561 pe->tag = htonl(1079);
566 if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
568 entry->info.type = REGION_TAG_TYPE;
569 entry->info.tag = HEADER_IMAGE;
570 entry->info.count = REGION_TAG_COUNT;
571 entry->info.offset = ((char *)pe - dataStart); /* negative offset */
574 entry->length = pvlen - sizeof(il) - sizeof(dl);
575 rdlen = regionSwab(entry+1, il, 0, pe, dataStart, entry->info.offset);
576 if (rdlen != dl) goto errxit;
577 entry->rdlen = rdlen;
581 int nb = ntohl(pe->count);
586 entry->info.type = htonl(pe->type);
587 if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
589 entry->info.count = htonl(pe->count);
591 { int off = ntohl(pe->offset);
593 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
594 rdl = -ntohl(stei[2]); /* negative offset */
595 ril = rdl/sizeof(*pe);
596 entry->info.tag = htonl(pe->tag);
599 rdl = (ril * sizeof(struct entryInfo));
600 entry->info.tag = HEADER_IMAGE;
603 entry->info.offset = -rdl; /* negative offset */
606 entry->length = pvlen - sizeof(il) - sizeof(dl);
607 rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, entry->info.offset);
608 if (rdlen < 0) goto errxit;
609 entry->rdlen = rdlen;
611 if (ril < h->indexUsed) {
612 struct indexEntry * newEntry = entry + ril;
613 int ne = (h->indexUsed - ril);
614 int rid = entry->info.offset+1;
617 /* Load dribble entries from region. */
618 rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, rid);
619 if (rc < 0) goto errxit;
622 { struct indexEntry * firstEntry = newEntry;
623 int save = h->indexUsed;
626 /* Dribble entries replace duplicate region entries. */
628 for (j = 0; j < ne; j++, newEntry++) {
629 (void) headerRemoveEntry(h, newEntry->info.tag);
630 if (newEntry->info.tag == HEADER_BASENAMES)
631 (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
634 /* If any duplicate entries were replaced, move new entries down. */
635 if (h->indexUsed < (save - ne)) {
636 memmove(h->index + h->indexUsed, firstEntry,
637 (ne * sizeof(*entry)));
652 h->index = _free(h->index);
663 Header headerCopyLoad(void *uh)
665 int_32 *ei = (int_32 *) uh;
666 int_32 il = ntohl(ei[0]); /* index length */
667 int_32 dl = ntohl(ei[1]); /* data length */
668 int pvlen = sizeof(il) + sizeof(dl) +
669 (il * sizeof(struct entryInfo)) + dl;
670 void * nuh = memcpy(xmalloc(pvlen), uh, pvlen);
678 h->region_allocated = 1;
683 int headerDrips(const Header h)
685 struct indexEntry * entry;
688 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
689 if (ENTRY_IS_REGION(entry)) {
690 int rid = entry->info.offset;
692 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
693 if (entry->info.offset <= rid)
701 /* Ignore deleted drips. */
702 if (entry->data == NULL || entry->length <= 0)
711 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
712 /*@out@*/ int * lengthPtr)
713 /*@modifies h, *lengthPtr @*/
716 struct entryInfo * pe;
723 struct indexEntry * entry;
726 int drlen, ndribbles;
730 /* Sort entries by (offset,tag). */
733 /* Compute (il,dl) for all tags, including those deleted in region. */
735 drlen = ndribbles = driplen = ndrips = 0;
736 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
737 if (ENTRY_IS_REGION(entry)) {
738 int_32 rdl = -entry->info.offset; /* negative offset */
739 int_32 ril = rdl/sizeof(*pe);
740 int rid = entry->info.offset;
743 dl += entry->rdlen + entry->info.count;
744 /* XXX Legacy regions do not include the region tag and data. */
745 if (i == 0 && h->legacy)
748 /* Skip rest of entries in region, but account for dribbles. */
749 for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
750 if (entry->info.offset <= rid)
754 type = entry->info.type;
755 if (typeSizes[type] > 1) {
757 diff = typeSizes[type] - (dl % typeSizes[type]);
758 if (diff != typeSizes[type]) {
767 drlen += entry->length;
775 /* Ignore deleted drips. */
776 if (entry->data == NULL || entry->length <= 0)
780 type = entry->info.type;
781 if (typeSizes[type] > 1) {
783 diff = typeSizes[type] - (dl % typeSizes[type]);
784 if (diff != typeSizes[type]) {
794 driplen += entry->length;
797 len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
803 pe = (struct entryInfo *) &ei[2];
804 dataStart = te = (char *) (pe + il);
807 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
813 if (entry->data == NULL || entry->length <= 0)
817 pe->tag = htonl(entry->info.tag);
818 pe->type = htonl(entry->info.type);
819 pe->count = htonl(entry->info.count);
821 if (ENTRY_IS_REGION(entry)) {
822 int_32 rdl = -entry->info.offset; /* negative offset */
823 int_32 ril = rdl/sizeof(*pe) + ndribbles;
824 int rid = entry->info.offset;
826 src = (char *)entry->data;
827 rdlen = entry->rdlen;
829 /* XXX Legacy regions do not include the region tag and data. */
830 if (i == 0 && h->legacy) {
834 memcpy(pe+1, src, rdl);
835 memcpy(te, src + rdl, rdlen);
838 pe->offset = htonl(te - dataStart);
841 stei[2] = htonl(-rdl-entry->info.count);
843 memcpy(te, stei, entry->info.count);
844 te += entry->info.count;
846 rdlen += entry->info.count;
848 count = regionSwab(NULL, ril, 0, pe, t, 0);
849 if (count != rdlen) goto errxit;
853 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
854 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
856 { struct entryInfo * se = (struct entryInfo *)src;
857 int off = ntohl(se->offset);
858 pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
860 te += entry->info.count + drlen;
862 count = regionSwab(NULL, ril, 0, pe, t, 0);
863 if (count != (rdlen + entry->info.count + drlen)) goto errxit;
866 /* Skip rest of entries in region. */
867 while (i < h->indexUsed && entry->info.offset <= rid+1) {
877 /* Ignore deleted drips. */
878 if (entry->data == NULL || entry->length <= 0)
882 type = entry->info.type;
883 if (typeSizes[type] > 1) {
885 diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
886 if (diff != typeSizes[type]) {
893 pe->offset = htonl(te - dataStart);
895 /* copy data w/ endian conversions */
896 switch (entry->info.type) {
898 count = entry->info.count;
901 *((int_32 *)te) = htonl(*((int_32 *)src));
902 te += sizeof(int_32);
903 src += sizeof(int_32);
908 count = entry->info.count;
911 *((int_16 *)te) = htons(*((int_16 *)src));
912 te += sizeof(int_16);
913 src += sizeof(int_16);
918 memcpy(te, entry->data, entry->length);
925 /* Insure that there are no memcpy underruns/overruns. */
926 if (((char *)pe) != dataStart) goto errxit;
927 if ((((char *)ei)+len) != te) goto errxit;
944 void * headerUnload(Header h)
947 void * uh = doHeaderUnload(h, &length);
951 Header headerReload(Header h, int tag)
956 void * uh = doHeaderUnload(h, &length);
967 if (nh->region_allocated)
969 nh->region_allocated = 1;
970 if (ENTRY_IS_REGION(nh->index)) {
971 if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
972 nh->index[0].info.tag = tag;
977 int headerWrite(FD_t fd, Header h, enum hMagic magicp)
985 uh = doHeaderUnload(h, &length);
989 case HEADER_MAGIC_YES:
990 nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
991 if (nb != sizeof(header_magic))
994 case HEADER_MAGIC_NO:
998 nb = Fwrite(uh, sizeof(char), length, fd);
1002 return (nb == length ? 0 : 1);
1005 Header headerRead(FD_t fd, enum hMagic magicp)
1017 memset(block, 0, sizeof(block));
1019 if (magicp == HEADER_MAGIC_YES)
1022 if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
1027 if (magicp == HEADER_MAGIC_YES) {
1029 if (memcmp(&magic, header_magic, sizeof(magic)))
1031 reserved = block[i++];
1034 il = ntohl(block[i++]);
1035 dl = ntohl(block[i++]);
1037 len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo)) + dl;
1040 * XXX Limit total size of header to 32Mb (~16 times largest known size).
1042 if (len > (32*1024*1024))
1048 len -= sizeof(il) + sizeof(dl);
1050 if (timedRead(fd, (char *)&ei[2], len) != len)
1057 if (h->region_allocated)
1059 h->region_allocated = 1;
1065 void headerDump(Header h, FILE *f, int flags,
1066 const struct headerTagTableEntry * tags)
1069 struct indexEntry *p;
1070 const struct headerTagTableEntry * tage;
1074 /* First write out the length of the index (count of index entries) */
1075 fprintf(f, "Entry count: %d\n", h->indexUsed);
1077 /* Now write the index */
1079 fprintf(f, "\n CT TAG TYPE "
1081 for (i = 0; i < h->indexUsed; i++) {
1082 switch (p->info.type) {
1083 case RPM_NULL_TYPE: type = "NULL"; break;
1084 case RPM_CHAR_TYPE: type = "CHAR"; break;
1085 case RPM_BIN_TYPE: type = "BIN"; break;
1086 case RPM_INT8_TYPE: type = "INT8"; break;
1087 case RPM_INT16_TYPE: type = "INT16"; break;
1088 case RPM_INT32_TYPE: type = "INT32"; break;
1089 /*case RPM_INT64_TYPE: type = "INT64"; break;*/
1090 case RPM_STRING_TYPE: type = "STRING"; break;
1091 case RPM_STRING_ARRAY_TYPE: type = "STRING_ARRAY"; break;
1092 case RPM_I18NSTRING_TYPE: type = "I18N_STRING"; break;
1093 default: type = "(unknown)"; break;
1097 while (tage->name && tage->val != p->info.tag) tage++;
1104 fprintf(f, "Entry : %3.3d (%d)%-14s %-18s 0x%.8x %.8d\n", i,
1105 p->info.tag, tag, type, (unsigned) p->info.offset,
1106 (int) p->info.count);
1108 if (flags & HEADER_DUMP_INLINE) {
1110 int c = p->info.count;
1113 /* Print the data inline */
1114 switch (p->info.type) {
1115 case RPM_INT32_TYPE:
1117 fprintf(f, " Data: %.3d 0x%08x (%d)\n", ct++,
1118 (unsigned) *((int_32 *) dp),
1119 (int) *((int_32 *) dp));
1120 dp += sizeof(int_32);
1124 case RPM_INT16_TYPE:
1126 fprintf(f, " Data: %.3d 0x%04x (%d)\n", ct++,
1127 (unsigned) (*((int_16 *) dp) & 0xffff),
1128 (int) *((int_16 *) dp));
1129 dp += sizeof(int_16);
1134 fprintf(f, " Data: %.3d 0x%02x (%d)\n", ct++,
1135 (unsigned) (*((int_8 *) dp) & 0xff),
1136 (int) *((int_8 *) dp));
1137 dp += sizeof(int_8);
1142 fprintf(f, " Data: %.3d ", ct);
1144 fprintf(f, "%02x ", (unsigned) (*(int_8 *)dp & 0xff));
1146 dp += sizeof(int_8);
1148 /*@loopbreak@*/ break;
1156 char ch = (char) *((char *) dp);
1157 fprintf(f, " Data: %.3d 0x%2x %c (%d)\n", ct++,
1158 (unsigned)(ch & 0xff),
1159 (isprint(ch) ? ch : ' '),
1160 (int) *((char *) dp));
1164 case RPM_STRING_TYPE:
1165 case RPM_STRING_ARRAY_TYPE:
1166 case RPM_I18NSTRING_TYPE:
1168 fprintf(f, " Data: %.3d %s\n", ct++, (char *) dp);
1174 fprintf(stderr, _("Data type %d not supported\n"),
1175 (int) p->info.type);
1184 * Find matching (tag,type) entry in header.
1186 * @param tag entry tag
1187 * @param type entry type
1188 * @return header entry
1191 struct indexEntry * findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
1194 struct indexEntry * entry, * entry2, * last;
1195 struct indexEntry key;
1197 if (h == NULL) return NULL;
1198 if (!h->sorted) headerSort(h);
1203 bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
1207 if (type == RPM_NULL_TYPE)
1210 /* look backwards */
1211 while (entry->info.tag == tag && entry->info.type != type &&
1212 entry > h->index) entry--;
1214 if (entry->info.tag == tag && entry->info.type == type)
1217 last = h->index + h->indexUsed;
1218 while (entry2->info.tag == tag && entry2->info.type != type &&
1219 entry2 < last) entry2++;
1221 if (entry->info.tag == tag && entry->info.type == type)
1227 int headerIsEntry(Header h, int_32 tag)
1229 /*@-mods@*/ /*@ FIX: h modified by sort. */
1230 return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
1234 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, const void ** p,
1237 struct indexEntry * entry;
1240 if (p == NULL) return headerIsEntry(h, tag);
1242 /* First find the tag */
1243 /*@-mods@*/ /*@ FIX: h modified by sort. */
1244 entry = findEntry(h, tag, RPM_NULL_TYPE);
1252 rc = copyEntry(entry, type, p, c, 0);
1254 /* XXX 1 on success */
1255 return ((rc == 1) ? 1 : 0);
1259 * Does locale match entry in header i18n table?
1262 * The range [l,le) contains the next locale to match:
1263 * ll[_CC][.EEEEE][@dddd]
1265 * ll ISO language code (in lowercase).
1266 * CC (optional) ISO coutnry code (in uppercase).
1267 * EEEEE (optional) encoding (not really standardized).
1268 * dddd (optional) dialect.
1271 * @param td header i18n table data, NUL terminated
1272 * @param l start of locale to match
1273 * @param le end of locale to match
1274 * @return 1 on match, 0 on no match
1276 static int headerMatchLocale(const char *td, const char *l, const char *le)
1283 { const char *s, *ll, *CC, *EE, *dd;
1286 /* Copy the buffer and parse out components on the fly. */
1287 lbuf = alloca(le - l + 1);
1288 for (s = l, ll = t = lbuf; *s; s++, t++) {
1308 if (ll) /* ISO language should be lower case */
1309 for (t = ll; *t; t++) *t = tolower(*t);
1310 if (CC) /* ISO country code should be upper case */
1311 for (t = CC; *t; t++) *t = toupper(*t);
1313 /* There are a total of 16 cases to attempt to match. */
1317 /* First try a complete match. */
1318 if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
1321 /* Next, try stripping optional dialect and matching. */
1322 for (fe = l; fe < le && *fe != '@'; fe++)
1324 if (fe < le && !strncmp(td, l, (fe - l)))
1327 /* Next, try stripping optional codeset and matching. */
1328 for (fe = l; fe < le && *fe != '.'; fe++)
1330 if (fe < le && !strncmp(td, l, (fe - l)))
1333 /* Finally, try stripping optional country code and matching. */
1334 for (fe = l; fe < le && *fe != '_'; fe++)
1336 if (fe < le && !strncmp(td, l, (fe - l)))
1343 * Return i18n string from header that matches locale.
1345 * @param entry i18n string data
1346 * @return matching i18n string (or 1st string if no match)
1348 /*@dependent@*/ static char *
1349 headerFindI18NString(Header h, struct indexEntry *entry)
1351 const char *lang, *l, *le;
1352 struct indexEntry * table;
1354 /* XXX Drepper sez' this is the order. */
1355 if ((lang = getenv("LANGUAGE")) == NULL &&
1356 (lang = getenv("LC_ALL")) == NULL &&
1357 (lang = getenv("LC_MESSAGES")) == NULL &&
1358 (lang = getenv("LANG")) == NULL)
1359 /*@-retalias@*/ return entry->data; /*@=retalias@*/
1361 if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
1362 /*@-retalias@*/ return entry->data; /*@=retalias@*/
1364 for (l = lang; *l != '\0'; l = le) {
1369 while (*l && *l == ':') /* skip leading colons */
1373 for (le = l; *le && *le != ':'; le++) /* find end of this locale */
1376 /* For each entry in the header ... */
1377 for (langNum = 0, td = table->data, ed = entry->data;
1378 langNum < entry->info.count;
1379 langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
1381 if (headerMatchLocale(td, l, le))
1387 /*@-retalias@*/ return entry->data; /*@=retalias@*/
1391 * Retrieve tag data from header.
1393 * @param tag tag to retrieve
1394 * @retval type address of type (or NULL)
1395 * @retval p address of data (or NULL)
1396 * @retval c address of count (or NULL)
1397 * @param minMem string pointers reference header memory?
1398 * @return 1 on success, 0 on not found
1400 static int intGetEntry(Header h, int_32 tag, /*@null@*/ /*@out@*/ int_32 * type,
1401 /*@null@*/ /*@out@*/ const void ** p,
1402 /*@null@*/ /*@out@*/ int_32 *c,
1404 /*@modifies *type, *p, *c @*/
1406 struct indexEntry * entry;
1409 /* First find the tag */
1410 /*@-mods@*/ /*@ FIX: h modified by sort. */
1411 entry = findEntry(h, tag, RPM_NULL_TYPE);
1413 if (entry == NULL) {
1420 switch (entry->info.type) {
1421 case RPM_I18NSTRING_TYPE:
1423 if (type) *type = RPM_STRING_TYPE;
1425 /*@-dependenttrans@*/
1426 if (p) *p = headerFindI18NString(h, entry);
1427 /*@=dependenttrans@*/
1430 rc = copyEntry(entry, type, p, c, minMem);
1434 /* XXX 1 on success */
1435 return ((rc == 1) ? 1 : 0);
1438 int headerGetEntryMinMemory(Header h, int_32 tag, int_32 *type, const void **p,
1441 return intGetEntry(h, tag, type, p, c, 1);
1444 int headerGetEntry(Header h, int_32 tag, int_32 * type, void **p, int_32 * c)
1446 return intGetEntry(h, tag, type, (const void **)p, c, 0);
1451 Header h = xcalloc(1, sizeof(*h));
1453 h->indexAlloced = INDEX_MALLOC_SIZE;
1455 h->region_allocated = 0;
1460 h->index = (h->indexAlloced
1461 ? xcalloc(h->indexAlloced, sizeof(*h->index))
1467 Header headerFree(Header h)
1469 if (h == NULL || --h->nrefs > 0)
1470 return NULL; /* XXX return previous header? */
1473 struct indexEntry * entry = h->index;
1475 for (i = 0; i < h->indexUsed; i++, entry++) {
1476 if (h->region_allocated && ENTRY_IS_REGION(entry)) {
1477 if (entry->length > 0) {
1478 int_32 * ei = entry->data;
1479 ei -= 2; /* XXX HACK: adjust to beginning of header. */
1482 } else if (!ENTRY_IN_REGION(entry)) {
1483 entry->data = _free(entry->data);
1487 h->index = _free(h->index);
1490 /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
1494 Header headerLink(Header h)
1497 /*@-refcounttrans@*/ return h; /*@=refcounttrans@*/
1500 int headerUsageCount(Header h)
1505 unsigned int headerSizeof(Header h, enum hMagic magicp)
1507 struct indexEntry * entry;
1508 unsigned int size = 0;
1509 unsigned int pad = 0;
1518 case HEADER_MAGIC_YES:
1519 size += sizeof(header_magic);
1521 case HEADER_MAGIC_NO:
1525 size += 2 * sizeof(int_32); /* count of index entries */
1527 for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
1531 /* Regions go in as is ... */
1532 if (ENTRY_IS_REGION(entry)) {
1533 size += entry->length;
1534 /* XXX Legacy regions do not include the region tag and data. */
1535 if (i == 0 && h->legacy)
1536 size += sizeof(struct entryInfo) + entry->info.count;
1540 /* ... and region elements are skipped. */
1541 if (entry->info.offset < 0)
1545 type = entry->info.type;
1546 if (typeSizes[type] > 1) {
1547 diff = typeSizes[type] - (size % typeSizes[type]);
1548 if (diff != typeSizes[type]) {
1554 size += sizeof(struct entryInfo) + entry->length;
1562 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
1563 int_32 c, int dataLength)
1564 /*@modifies *dstPtr @*/
1571 case RPM_STRING_ARRAY_TYPE:
1572 case RPM_I18NSTRING_TYPE:
1573 /* Otherwise, p is char** */
1575 src = (const char **) srcPtr;
1579 int len = strlen(*src) + 1;
1580 memcpy(dst, *src, len);
1588 /*@-mayaliasunique@*/
1589 memcpy(dstPtr, srcPtr, dataLength);
1590 /*@=mayaliasunique@*/
1596 * Return (malloc'ed) copy of entry data.
1597 * @param type entry data type
1598 * @param p entry data
1599 * @param c entry item count
1600 * @retval lengthPtr no. bytes in returned data
1601 * @return (malloc'ed) copy of entry data
1603 static void * grabData(int_32 type, const void * p, int_32 c,
1604 /*@out@*/ int * lengthPtr)
1605 /*@modifies *lengthPtr @*/
1607 int length = dataLength(type, p, c, 0);
1608 void * data = xmalloc(length);
1610 copyData(type, data, p, c, length);
1613 *lengthPtr = length;
1617 int headerAddEntry(Header h, int_32 tag, int_32 type, const void *p, int_32 c)
1619 struct indexEntry *entry;
1621 /* Count must always be >= 1 for headerAddEntry. */
1625 /* Allocate more index space if necessary */
1626 if (h->indexUsed == h->indexAlloced) {
1627 h->indexAlloced += INDEX_MALLOC_SIZE;
1628 h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
1631 /* Fill in the index */
1632 entry = h->index + h->indexUsed;
1633 entry->info.tag = tag;
1634 entry->info.type = type;
1635 entry->info.count = c;
1636 entry->info.offset = 0;
1637 entry->data = grabData(type, p, c, &entry->length);
1639 if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
1647 headerGetLangs(Header h)
1649 char **s, *e, **table;
1652 if (!headerGetRawEntry(h, HEADER_I18NTABLE, &type, (const void **)&s, &count))
1655 /* XXX xcalloc never returns NULL. */
1656 if ((table = (char **)xcalloc((count+1), sizeof(char *))) == NULL)
1659 for (i = 0, e = *s; i < count > 0; i++, e += strlen(e)+1)
1661 table[count] = NULL;
1663 /*@-nullret@*/ return table; /*@=nullret@*/ /* LCL: double indirection? */
1666 int headerAddI18NString(Header h, int_32 tag, const char * string, const char * lang)
1668 struct indexEntry * table, * entry;
1669 const char ** strArray;
1675 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
1676 entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
1678 if (!table && entry)
1679 return 0; /* this shouldn't ever happen!! */
1681 if (!table && !entry) {
1682 const char * charArray[2];
1684 if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
1685 /*@-observertrans -readonlytrans@*/
1686 charArray[count++] = "C";
1687 /*@=observertrans =readonlytrans@*/
1689 /*@-observertrans -readonlytrans@*/
1690 charArray[count++] = "C";
1691 /*@=observertrans =readonlytrans@*/
1692 charArray[count++] = lang;
1694 if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
1697 table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
1702 if (!lang) lang = "C";
1704 { const char * l = table->data;
1705 for (langNum = 0; langNum < table->info.count; langNum++) {
1706 if (!strcmp(l, lang)) break;
1711 if (langNum >= table->info.count) {
1712 length = strlen(lang) + 1;
1713 if (ENTRY_IN_REGION(table)) {
1714 char * t = xmalloc(table->length + length);
1715 memcpy(t, table->data, table->length);
1717 table->info.offset = 0;
1719 table->data = xrealloc(table->data, table->length + length);
1720 /*@-mayaliasunique@*/
1721 memcpy(((char *)table->data) + table->length, lang, length);
1722 /*@=mayaliasunique@*/
1723 table->length += length;
1724 table->info.count++;
1728 strArray = alloca(sizeof(*strArray) * (langNum + 1));
1729 for (i = 0; i < langNum; i++)
1731 strArray[langNum] = string;
1732 return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
1734 } else if (langNum >= entry->info.count) {
1735 ghosts = langNum - entry->info.count;
1737 length = strlen(string) + 1 + ghosts;
1738 if (ENTRY_IN_REGION(entry)) {
1739 char * t = xmalloc(entry->length + length);
1740 memcpy(t, entry->data, entry->length);
1742 entry->info.offset = 0;
1744 entry->data = xrealloc(entry->data, entry->length + length);
1746 memset(((char *)entry->data) + entry->length, '\0', ghosts);
1747 /*@-mayaliasunique@*/
1748 strcpy(((char *)entry->data) + entry->length + ghosts, string);
1749 /*@=mayaliasunique@*/
1751 entry->length += length;
1752 entry->info.count = langNum + 1;
1754 char *b, *be, *e, *ee, *t;
1757 /* Set beginning/end pointers to previous data */
1758 b = be = e = ee = entry->data;
1759 for (i = 0; i < table->info.count; i++) {
1762 ee += strlen(ee) + 1;
1767 /* Get storage for new buffer */
1769 sn = strlen(string) + 1;
1771 length = bn + sn + en;
1772 t = buf = xmalloc(length);
1774 /* Copy values into new storage */
1777 memcpy(t, string, sn);
1782 /* Replace I18N string array */
1783 entry->length -= strlen(be) + 1;
1784 entry->length += sn;
1786 if (ENTRY_IN_REGION(entry)) {
1787 entry->info.offset = 0;
1789 entry->data = _free(entry->data);
1790 /*@-dependenttrans@*/
1792 /*@=dependenttrans@*/
1798 int headerModifyEntry(Header h, int_32 tag, int_32 type,
1799 const void * p, int_32 c)
1801 struct indexEntry *entry;
1804 /* First find the tag */
1805 entry = findEntry(h, tag, type);
1809 /* make sure entry points to the first occurence of this tag */
1810 while (entry > h->index && (entry - 1)->info.tag == tag)
1813 /* free after we've grabbed the new data in case the two are intertwined;
1814 that's a bad idea but at least we won't break */
1815 oldData = entry->data;
1817 entry->info.count = c;
1818 entry->info.type = type;
1819 entry->data = grabData(type, p, c, &entry->length);
1821 if (ENTRY_IN_REGION(entry)) {
1822 entry->info.offset = 0;
1824 oldData = _free(oldData);
1829 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
1830 const void * p, int_32 c)
1832 return (findEntry(h, tag, type)
1833 ? headerAppendEntry(h, tag, type, p, c)
1834 : headerAddEntry(h, tag, type, p, c));
1837 int headerAppendEntry(Header h, int_32 tag, int_32 type,
1838 const void * p, int_32 c)
1840 struct indexEntry *entry;
1843 /* First find the tag */
1844 entry = findEntry(h, tag, type);
1848 if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
1849 /* we can't do this */
1853 length = dataLength(type, p, c, 0);
1855 if (ENTRY_IN_REGION(entry)) {
1856 char * t = xmalloc(entry->length + length);
1857 memcpy(t, entry->data, entry->length);
1859 entry->info.offset = 0;
1861 entry->data = xrealloc(entry->data, entry->length + length);
1863 copyData(type, ((char *) entry->data) + entry->length, p, c, length);
1865 entry->length += length;
1867 entry->info.count += c;
1872 int headerRemoveEntry(Header h, int_32 tag)
1874 struct indexEntry * last = h->index + h->indexUsed;
1875 struct indexEntry * entry, * first;
1878 entry = findEntry(h, tag, RPM_NULL_TYPE);
1879 if (!entry) return 1;
1881 /* Make sure entry points to the first occurence of this tag. */
1882 while (entry > h->index && (entry - 1)->info.tag == tag)
1885 /* Free data for tags being removed. */
1886 for (first = entry; first < last; first++) {
1888 if (first->info.tag != tag)
1893 if (ENTRY_IN_REGION(first))
1898 ne = (first - entry);
1903 memmove(entry, first, (ne * sizeof(*entry)));
1911 static char escapedChar(const char ch) /*@*/
1914 case 'a': return '\a';
1915 case 'b': return '\b';
1916 case 'f': return '\f';
1917 case 'n': return '\n';
1918 case 'r': return '\r';
1919 case 't': return '\t';
1920 case 'v': return '\v';
1927 static /*@null@*/ struct sprintfToken *
1928 freeFormat( /*@only@*/ /*@null@*/ struct sprintfToken * format, int num)
1929 /*@modifies *format @*/
1933 if (format == NULL) return NULL;
1934 for (i = 0; i < num; i++) {
1935 switch (format[i].type) {
1937 format[i].u.array.format =
1938 freeFormat(format[i].u.array.format,
1939 format[i].u.array.numTokens);
1942 format[i].u.cond.ifFormat =
1943 freeFormat(format[i].u.cond.ifFormat,
1944 format[i].u.cond.numIfTokens);
1945 format[i].u.cond.elseFormat =
1946 freeFormat(format[i].u.cond.elseFormat,
1947 format[i].u.cond.numElseTokens);
1956 format = _free(format);
1962 static void findTag(char * name, const struct headerTagTableEntry * tags,
1963 const struct headerSprintfExtension * extensions,
1964 /*@out@*/const struct headerTagTableEntry ** tagMatch,
1965 /*@out@*/const struct headerSprintfExtension ** extMatch)
1966 /*@modifies *tagMatch, *extMatch @*/
1968 const struct headerTagTableEntry * entry;
1969 const struct headerSprintfExtension * ext;
1970 const char * tagname;
1975 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
1976 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
1977 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
1983 /* Search extensions first to permit overriding header tags. */
1985 while (ext->type != HEADER_EXT_LAST) {
1986 if (ext->name != NULL && ext->type == HEADER_EXT_TAG
1987 && !xstrcasecmp(ext->name, tagname))
1990 if (ext->type == HEADER_EXT_MORE)
1996 if (ext->type == HEADER_EXT_TAG) {
2001 /* Search header tags. */
2002 for (entry = tags; entry->name; entry++)
2003 if (entry->name && !xstrcasecmp(entry->name, tagname))
2013 static int parseExpression(struct sprintfToken * token, char * str,
2014 const struct headerTagTableEntry * tags,
2015 const struct headerSprintfExtension * extensions,
2016 /*@out@*/char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
2017 /*@modifies str, *str, *token, *endPtr, *errmsg @*/;
2021 static int parseFormat(char * str, const struct headerTagTableEntry * tags,
2022 const struct headerSprintfExtension * extensions,
2023 /*@out@*/struct sprintfToken ** formatPtr, /*@out@*/int * numTokensPtr,
2024 /*@null@*/ /*@out@*/char ** endPtr, int state,
2025 /*@null@*/ /*@out@*/errmsg_t * errmsg)
2026 /*@modifies str, *str, *formatPtr, *numTokensPtr, *endPtr, *errmsg @*/
2028 char * chptr, * start, * next, * dst;
2029 struct sprintfToken * format;
2032 const struct headerTagTableEntry * tag;
2033 const struct headerSprintfExtension * ext;
2037 /* upper limit on number of individual formats */
2039 for (chptr = str; *chptr != '\0'; chptr++)
2040 if (*chptr == '%') numTokens++;
2041 numTokens = numTokens * 2 + 1;
2043 format = xcalloc(numTokens, sizeof(*format));
2044 if (endPtr) *endPtr = NULL;
2049 while (*start != '\0') {
2053 if (*(start + 1) == '%') {
2054 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
2056 format[currToken].type = PTOK_STRING;
2058 dst = format[currToken].u.string.string = start;
2066 break; /* out of switch */
2073 if (*start == '|') {
2077 if (parseExpression(format + currToken, start, tags,
2078 extensions, &newEnd, errmsg)) {
2079 format = freeFormat(format, numTokens);
2083 break; /* out of switch */
2086 format[currToken].u.tag.format = start;
2087 format[currToken].u.tag.pad = 0;
2088 format[currToken].u.tag.justOne = 0;
2089 format[currToken].u.tag.arrayCount = 0;
2092 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
2093 if (!*chptr || *chptr == '%') {
2094 /*@-observertrans -readonlytrans@*/
2095 if (errmsg) *errmsg = _("missing { after %");
2096 /*@=observertrans =readonlytrans@*/
2097 format = freeFormat(format, numTokens);
2103 while (start < chptr) {
2104 if (xisdigit(*start)) {
2105 i = strtoul(start, &start, 10);
2106 format[currToken].u.tag.pad += i;
2112 if (*start == '=') {
2113 format[currToken].u.tag.justOne = 1;
2115 } else if (*start == '#') {
2116 format[currToken].u.tag.justOne = 1;
2117 format[currToken].u.tag.arrayCount = 1;
2122 while (*next && *next != '}') next++;
2124 /*@-observertrans -readonlytrans@*/
2125 if (errmsg) *errmsg = _("missing } after %{");
2126 /*@=observertrans =readonlytrans@*/
2127 format = freeFormat(format, numTokens);
2133 while (*chptr && *chptr != ':') chptr++;
2135 if (*chptr != '\0') {
2138 /*@-observertrans -readonlytrans@*/
2139 if (errmsg) *errmsg = _("empty tag format");
2140 /*@=observertrans =readonlytrans@*/
2141 format = freeFormat(format, numTokens);
2144 format[currToken].u.tag.type = chptr;
2146 format[currToken].u.tag.type = NULL;
2150 /*@-observertrans -readonlytrans@*/
2151 if (errmsg) *errmsg = _("empty tag name");
2152 /*@=observertrans =readonlytrans@*/
2153 format = freeFormat(format, numTokens);
2158 findTag(start, tags, extensions, &tag, &ext);
2161 format[currToken].u.tag.ext = NULL;
2162 format[currToken].u.tag.tag = tag->val;
2164 format[currToken].u.tag.ext = ext->u.tagFunction;
2165 format[currToken].u.tag.extNum = ext - extensions;
2167 /*@-observertrans -readonlytrans@*/
2168 if (errmsg) *errmsg = _("unknown tag");
2169 /*@=observertrans =readonlytrans@*/
2170 format = freeFormat(format, numTokens);
2174 format[currToken].type = PTOK_TAG;
2185 if (parseFormat(start, tags, extensions,
2186 &format[currToken].u.array.format,
2187 &format[currToken].u.array.numTokens,
2188 &start, PARSER_IN_ARRAY, errmsg)) {
2189 format = freeFormat(format, numTokens);
2194 /*@-observertrans -readonlytrans@*/
2195 if (errmsg) *errmsg = _("] expected at end of array");
2196 /*@=observertrans =readonlytrans@*/
2197 format = freeFormat(format, numTokens);
2203 format[currToken].type = PTOK_ARRAY;
2209 if ((*start == ']' && state != PARSER_IN_ARRAY) ||
2210 (*start == '}' && state != PARSER_IN_EXPR)) {
2211 if (*start == ']') {
2212 /*@-observertrans -readonlytrans@*/
2213 if (errmsg) *errmsg = _("unexpected ]");
2214 /*@=observertrans =readonlytrans@*/
2216 /*@-observertrans -readonlytrans@*/
2217 if (errmsg) *errmsg = _("unexpected }");
2218 /*@=observertrans =readonlytrans@*/
2220 format = freeFormat(format, numTokens);
2224 if (endPtr) *endPtr = start;
2229 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
2231 format[currToken].type = PTOK_STRING;
2233 dst = format[currToken].u.string.string = start;
2237 if (*start == '\\') {
2239 *dst++ = escapedChar(*start++);
2253 for (i = 0; i < currToken; i++) {
2254 if (format[i].type == PTOK_STRING)
2255 format[i].u.string.len = strlen(format[i].u.string.string);
2258 *numTokensPtr = currToken;
2259 *formatPtr = format;
2266 static int parseExpression(struct sprintfToken * token, char * str,
2267 const struct headerTagTableEntry * tags,
2268 const struct headerSprintfExtension * extensions,
2269 /*@out@*/ char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
2271 const struct headerTagTableEntry * tag;
2272 const struct headerSprintfExtension * ext;
2276 if (errmsg) *errmsg = NULL;
2278 while (*chptr && *chptr != '?') chptr++;
2280 if (*chptr != '?') {
2281 /*@-observertrans -readonlytrans@*/
2282 if (errmsg) *errmsg = _("? expected in expression");
2283 /*@=observertrans =readonlytrans@*/
2289 if (*chptr != '{') {
2290 /*@-observertrans -readonlytrans@*/
2291 if (errmsg) *errmsg = _("{ expected after ? in expression");
2292 /*@=observertrans =readonlytrans@*/
2298 if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
2299 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
2303 /*@-observertrans -readonlytrans@*/
2304 if (errmsg) *errmsg = _("} expected in expression");
2305 /*@=observertrans =readonlytrans@*/
2306 token->u.cond.ifFormat =
2307 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2312 if (*chptr != ':' && *chptr != '|') {
2313 /*@-observertrans -readonlytrans@*/
2314 if (errmsg) *errmsg = _(": expected following ? subexpression");
2315 /*@=observertrans =readonlytrans@*/
2316 token->u.cond.ifFormat =
2317 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2321 if (*chptr == '|') {
2322 (void) parseFormat(xstrdup(""), tags, extensions,
2323 &token->u.cond.elseFormat,
2324 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
2329 if (*chptr != '{') {
2330 /*@-observertrans -readonlytrans@*/
2331 if (errmsg) *errmsg = _("{ expected after : in expression");
2332 /*@=observertrans =readonlytrans@*/
2333 token->u.cond.ifFormat =
2334 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2340 if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
2341 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
2345 /*@-observertrans -readonlytrans@*/
2346 if (errmsg) *errmsg = _("} expected in expression");
2347 /*@=observertrans =readonlytrans@*/
2348 token->u.cond.ifFormat =
2349 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2354 if (*chptr != '|') {
2355 /*@-observertrans -readonlytrans@*/
2356 if (errmsg) *errmsg = _("| expected at end of expression");
2357 /*@=observertrans =readonlytrans@*/
2358 token->u.cond.ifFormat =
2359 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
2360 token->u.cond.elseFormat =
2361 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
2370 findTag(str, tags, extensions, &tag, &ext);
2373 token->u.cond.tag.ext = NULL;
2374 token->u.cond.tag.tag = tag->val;
2376 token->u.cond.tag.ext = ext->u.tagFunction;
2377 token->u.cond.tag.extNum = ext - extensions;
2379 token->u.cond.tag.ext = NULL;
2380 token->u.cond.tag.tag = -1;
2383 token->type = PTOK_COND;
2390 static int getExtension(Header h, headerTagTagFunction fn,
2391 /*@out@*/ int_32 * typeptr, /*@out@*/ const void ** data,
2392 /*@out@*/ int_32 * countptr, struct extensionCache * ext)
2393 /*@modifies *typeptr, *data, *countptr, ext->avail @*/
2396 if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
2401 *typeptr = ext->type;
2403 *countptr = ext->count;
2410 static char * formatValue(struct sprintfTag * tag, Header h,
2411 const struct headerSprintfExtension * extensions,
2412 struct extensionCache * extCache, int element)
2413 /*@modifies extCache->avail @*/
2419 unsigned int intVal;
2421 const char ** strarray;
2424 headerTagFormatFunction tagtype = NULL;
2425 const struct headerSprintfExtension * ext;
2428 if (getExtension(h, tag->ext, &type, &data, &count,
2429 extCache + tag->extNum)) {
2431 type = RPM_STRING_TYPE;
2432 data = "(none)"; /* XXX i18n? NO!, sez; gafton */
2435 if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)){
2437 type = RPM_STRING_TYPE;
2438 data = "(none)"; /* XXX i18n? NO!, sez; gafton */
2444 if (tag->arrayCount) {
2445 /*@-observertrans -modobserver@*/
2446 data = headerFreeData(data, type);
2447 /*@=observertrans =modobserver@*/
2452 type = RPM_INT32_TYPE;
2455 (void) stpcpy( stpcpy(buf, "%"), tag->format);
2459 while (ext->type != HEADER_EXT_LAST) {
2460 if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
2461 && !strcmp(ext->name, tag->type))
2463 tagtype = ext->u.formatFunction;
2467 if (ext->type == HEADER_EXT_MORE)
2475 case RPM_STRING_ARRAY_TYPE:
2476 strarray = (const char **)data;
2479 val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
2484 len = strlen(strarray[element]) + tag->pad + 20;
2486 sprintf(val, buf, strarray[element]);
2489 /*@-observertrans -modobserver@*/
2490 if (mayfree) data = _free(data);
2491 /*@=observertrans =modobserver@*/
2495 case RPM_STRING_TYPE:
2497 val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad, 0);
2502 len = strlen(data) + tag->pad + 20;
2504 sprintf(val, buf, data);
2510 case RPM_INT16_TYPE:
2511 case RPM_INT32_TYPE:
2514 case RPM_INT8_TYPE: intVal = *(((int_8 *) data) + element); break;
2515 case RPM_INT16_TYPE: intVal = *(((uint_16 *) data) + element); break;
2516 default: /* keep -Wall quiet */
2517 case RPM_INT32_TYPE: intVal = *(((int_32 *) data) + element); break;
2521 val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
2525 len = 10 + tag->pad + 20;
2527 sprintf(val, buf, intVal);
2532 val = xstrdup(_("(unknown type)"));
2541 static const char * singleSprintf(Header h, struct sprintfToken * token,
2542 const struct headerSprintfExtension * extensions,
2543 struct extensionCache * extCache, int element)
2544 /*@modifies h, extCache->avail @*/
2547 const char * thisItem;
2553 struct sprintfToken * condFormat;
2556 /* we assume the token and header have been validated already! */
2558 switch (token->type) {
2563 val = xmalloc(token->u.string.len + 1);
2564 strcpy(val, token->u.string.string);
2568 val = formatValue(&token->u.tag, h, extensions, extCache,
2569 token->u.tag.justOne ? 0 : element);
2573 if (token->u.cond.tag.ext ||
2574 headerIsEntry(h, token->u.cond.tag.tag)) {
2575 condFormat = token->u.cond.ifFormat;
2576 condNumFormats = token->u.cond.numIfTokens;
2578 condFormat = token->u.cond.elseFormat;
2579 condNumFormats = token->u.cond.numElseTokens;
2582 alloced = condNumFormats * 20;
2583 val = xmalloc(alloced ? alloced : 1);
2588 for (i = 0; i < condNumFormats; i++) {
2589 thisItem = singleSprintf(h, condFormat + i,
2590 extensions, extCache, element);
2591 thisItemLen = strlen(thisItem);
2592 if ((thisItemLen + len) >= alloced) {
2593 alloced = (thisItemLen + len) + 200;
2594 val = xrealloc(val, alloced);
2596 strcat(val, thisItem);
2598 thisItem = _free(thisItem);
2605 for (i = 0; i < token->u.array.numTokens; i++) {
2606 if (token->u.array.format[i].type != PTOK_TAG ||
2607 token->u.array.format[i].u.tag.arrayCount ||
2608 token->u.array.format[i].u.tag.justOne) continue;
2610 if (token->u.array.format[i].u.tag.ext) {
2612 if (getExtension(h, token->u.array.format[i].u.tag.ext,
2613 &type, &data, &numElements,
2615 token->u.array.format[i].u.tag.extNum))
2618 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
2619 &type, (void **) &val, &numElements))
2621 val = headerFreeData(val, type);
2623 /*@loopbreak@*/ break;
2626 if (numElements == -1) {
2627 val = xstrdup("(none)"); /* XXX i18n? NO!, sez; gafton */
2629 alloced = numElements * token->u.array.numTokens * 20;
2630 val = xmalloc(alloced);
2634 for (j = 0; j < numElements; j++) {
2635 for (i = 0; i < token->u.array.numTokens; i++) {
2636 thisItem = singleSprintf(h, token->u.array.format + i,
2637 extensions, extCache, j);
2638 thisItemLen = strlen(thisItem);
2639 if ((thisItemLen + len) >= alloced) {
2640 alloced = (thisItemLen + len) + 200;
2641 val = xrealloc(val, alloced);
2643 strcat(val, thisItem);
2645 thisItem = _free(thisItem);
2658 static struct extensionCache * allocateExtensionCache(
2659 const struct headerSprintfExtension * extensions)
2662 const struct headerSprintfExtension * ext = extensions;
2665 while (ext->type != HEADER_EXT_LAST) {
2667 if (ext->type == HEADER_EXT_MORE)
2673 return xcalloc(i, sizeof(struct extensionCache));
2678 static void freeExtensionCache(const struct headerSprintfExtension * extensions,
2679 /*@only@*/struct extensionCache * cache)
2681 const struct headerSprintfExtension * ext = extensions;
2684 while (ext->type != HEADER_EXT_LAST) {
2685 if (cache[i].freeit) cache[i].data = _free(cache[i].data);
2688 if (ext->type == HEADER_EXT_MORE)
2694 cache = _free(cache);
2697 char * headerSprintf(Header h, const char * fmt,
2698 const struct headerTagTableEntry * tags,
2699 const struct headerSprintfExtension * extensions,
2703 struct sprintfToken * format;
2709 struct extensionCache * extCache;
2711 /*fmtString = escapeString(fmt);*/
2712 fmtString = xstrdup(fmt);
2714 if (parseFormat(fmtString, tags, extensions, &format, &numTokens,
2715 NULL, PARSER_BEGIN, errmsg)) {
2716 fmtString = _free(fmtString);
2720 extCache = allocateExtensionCache(extensions);
2722 answerAlloced = 1024;
2724 answer = xmalloc(answerAlloced);
2727 for (i = 0; i < numTokens; i++) {
2732 piece = singleSprintf(h, format + i, extensions, extCache, 0);
2735 pieceLength = strlen(piece);
2736 if ((answerLength + pieceLength) >= answerAlloced) {
2737 while ((answerLength + pieceLength) >= answerAlloced)
2738 answerAlloced += 1024;
2739 answer = xrealloc(answer, answerAlloced);
2742 strcat(answer, piece);
2743 answerLength += pieceLength;
2744 piece = _free(piece);
2748 fmtString = _free(fmtString);
2749 freeExtensionCache(extensions, extCache);
2750 format = _free(format);
2757 static char * octalFormat(int_32 type, const void * data,
2758 char * formatPrefix, int padding, /*@unused@*/int element)
2759 /*@modifies formatPrefix @*/
2763 if (type != RPM_INT32_TYPE) {
2764 val = xstrdup(_("(not a number)"));
2766 val = xmalloc(20 + padding);
2767 strcat(formatPrefix, "o");
2768 sprintf(val, formatPrefix, *((int_32 *) data));
2776 static char * hexFormat(int_32 type, const void * data,
2777 char * formatPrefix, int padding, /*@unused@*/int element)
2778 /*@modifies formatPrefix @*/
2782 if (type != RPM_INT32_TYPE) {
2783 val = xstrdup(_("(not a number)"));
2785 val = xmalloc(20 + padding);
2786 strcat(formatPrefix, "x");
2787 sprintf(val, formatPrefix, *((int_32 *) data));
2795 static char * realDateFormat(int_32 type, const void * data,
2796 char * formatPrefix, int padding, /*@unused@*/int element,
2797 const char * strftimeFormat)
2798 /*@modifies formatPrefix @*/
2802 if (type != RPM_INT32_TYPE) {
2803 val = xstrdup(_("(not a number)"));
2805 struct tm * tstruct;
2808 val = xmalloc(50 + padding);
2809 strcat(formatPrefix, "s");
2811 /* this is important if sizeof(int_32) ! sizeof(time_t) */
2812 { time_t dateint = *((int_32 *) data);
2813 tstruct = localtime(&dateint);
2817 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
2818 sprintf(val, formatPrefix, buf);
2826 static char * dateFormat(int_32 type, const void * data,
2827 char * formatPrefix, int padding, int element)
2828 /*@modifies formatPrefix @*/
2830 return realDateFormat(type, data, formatPrefix, padding, element, "%c");
2835 static char * dayFormat(int_32 type, const void * data,
2836 char * formatPrefix, int padding, int element)
2837 /*@modifies formatPrefix @*/
2839 return realDateFormat(type, data, formatPrefix, padding, element,
2845 static char * shescapeFormat(int_32 type, const void * data,
2846 char * formatPrefix, int padding, /*@unused@*/int element)
2847 /*@modifies formatPrefix @*/
2849 char * result, * dst, * src, * buf;
2851 if (type == RPM_INT32_TYPE) {
2852 result = xmalloc(padding + 20);
2853 strcat(formatPrefix, "d");
2854 sprintf(result, formatPrefix, *((int_32 *) data));
2856 buf = alloca(strlen(data) + padding + 2);
2857 strcat(formatPrefix, "s");
2858 sprintf(buf, formatPrefix, data);
2860 result = dst = xmalloc(strlen(buf) * 4 + 3);
2862 for (src = buf; *src != '\0'; src++) {
2880 const struct headerSprintfExtension headerDefaultFormats[] = {
2881 { HEADER_EXT_FORMAT, "octal", { octalFormat } },
2882 { HEADER_EXT_FORMAT, "hex", { hexFormat } },
2883 { HEADER_EXT_FORMAT, "date", { dateFormat } },
2884 { HEADER_EXT_FORMAT, "day", { dayFormat } },
2885 { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
2886 { HEADER_EXT_LAST, NULL, { NULL } }
2889 void headerCopyTags(Header headerFrom, Header headerTo, int_32 * tagstocopy)
2893 if (headerFrom == headerTo)
2896 for (p = tagstocopy; *p != 0; p++) {
2900 if (headerIsEntry(headerTo, *p))
2902 if (!headerGetEntryMinMemory(headerFrom, *p, &type,
2903 (const void **) &s, &count))
2905 (void) headerAddEntry(headerTo, *p, type, s, count);
2906 s = headerFreeData(s, type);