rpmdb/header.c

Go to the documentation of this file.
00001 
00005 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
00006 
00007 /* Data written to file descriptors is in network byte order.    */
00008 /* Data read from file descriptors is expected to be in          */
00009 /* network byte order and is converted on the fly to host order. */
00010 
00011 #include "system.h"
00012 
00013 #define __HEADER_PROTOTYPES__
00014 
00015 #include <rpmio_internal.h>     /* XXX for fdGetOPath() */
00016 #include <header_internal.h>
00017 #include <rpmmacro.h>
00018 
00019 #include "debug.h"
00020 
00021 /*@unchecked@*/
00022 int _hdr_debug = 0;
00023 
00024 /*@unchecked@*/
00025 int _tagcache = 1;              /* XXX Cache tag data persistently? */
00026 
00027 /*@access entryInfo @*/
00028 /*@access indexEntry @*/
00029 
00030 /*@access sprintfTag @*/
00031 /*@access sprintfToken @*/
00032 /*@access HV_t @*/
00033 
00034 #define PARSER_BEGIN    0
00035 #define PARSER_IN_ARRAY 1
00036 #define PARSER_IN_EXPR  2
00037 
00040 /*@observer@*/ /*@unchecked@*/
00041 static unsigned char header_magic[8] = {
00042         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00043 };
00044 
00048 /*@observer@*/ /*@unchecked@*/
00049 static int typeAlign[16] =  {
00050     1,  
00051     1,  
00052     1,  
00053     2,  
00054     4,  
00055     8,  
00056     1,  
00057     1,  
00058     1,  
00059     1,  
00060     1,  
00061     1,  
00062     0,
00063     0,
00064     0,
00065     0
00066 };
00067 
00071 /*@observer@*/ /*@unchecked@*/
00072 static int typeSizes[16] =  { 
00073     0,  
00074     1,  
00075     1,  
00076     2,  
00077     4,  
00078     8,  
00079     -1, 
00080     1,  
00081     -1, 
00082     -1, 
00083     1,  
00084     1,  
00085     0,
00086     0,
00087     0,
00088     0
00089 };
00090 
00094 /*@unchecked@*/
00095 static size_t headerMaxbytes = (32*1024*1024);
00096 
00101 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00102 
00106 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00107 
00112 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00113 
00117 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00118 
00122 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00123 
00124 /*@observer@*/ /*@unchecked@*/
00125 HV_t hdrVec;    /* forward reference */
00126 
00133 static /*@null@*/
00134 void * headerGetStats(/*@unused@*/ Header h, /*@unused@*/ int opx)
00135         /*@*/
00136 {
00137     rpmop op = NULL;
00138     return op;
00139 }
00140 
00146 static
00147 Header headerLink(Header h)
00148         /*@modifies h @*/
00149 {
00150 /*@-nullret@*/
00151     if (h == NULL) return NULL;
00152 /*@=nullret@*/
00153 
00154     h->nrefs++;
00155 /*@-modfilesys@*/
00156 if (_hdr_debug)
00157 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00158 /*@=modfilesys@*/
00159 
00160     /*@-refcounttrans @*/
00161     return h;
00162     /*@=refcounttrans @*/
00163 }
00164 
00170 static /*@null@*/
00171 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00172         /*@modifies h @*/
00173 {
00174     if (h == NULL) return NULL;
00175 /*@-modfilesys@*/
00176 if (_hdr_debug)
00177 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00178 /*@=modfilesys@*/
00179     h->nrefs--;
00180     return NULL;
00181 }
00182 
00188 static /*@null@*/
00189 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00190         /*@modifies h @*/
00191 {
00192     (void) headerUnlink(h);
00193 
00194     /*@-usereleased@*/
00195     if (h == NULL || h->nrefs > 0)
00196         return NULL;    /* XXX return previous header? */
00197 
00198     if (h->index) {
00199         indexEntry entry = h->index;
00200         int i;
00201         for (i = 0; i < h->indexUsed; i++, entry++) {
00202             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00203                 if (entry->length > 0) {
00204                     int_32 * ei = entry->data;
00205                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00206                     entry->data = NULL;
00207                 }
00208             } else if (!ENTRY_IN_REGION(entry)) {
00209                 entry->data = _free(entry->data);
00210             }
00211             entry->data = NULL;
00212         }
00213         h->index = _free(h->index);
00214     }
00215     h->origin = _free(h->origin);
00216     h->baseurl = _free(h->baseurl);
00217     h->digest = _free(h->digest);
00218 
00219     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00220     return h;
00221     /*@=usereleased@*/
00222 }
00223 
00228 static
00229 Header headerNew(void)
00230         /*@*/
00231 {
00232     Header h = xcalloc(1, sizeof(*h));
00233 
00234     /*@-assignexpose@*/
00235     h->hv = *hdrVec;            /* structure assignment */
00236     /*@=assignexpose@*/
00237     h->blob = NULL;
00238     h->origin = NULL;
00239     h->baseurl = NULL;
00240     h->digest = NULL;
00241     h->instance = 0;
00242     h->indexAlloced = INDEX_MALLOC_SIZE;
00243     h->indexUsed = 0;
00244     h->flags |= HEADERFLAG_SORTED;
00245 
00246     h->index = (h->indexAlloced
00247         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00248         : NULL);
00249 
00250     h->nrefs = 0;
00251     /*@-globstate -observertrans @*/
00252     return headerLink(h);
00253     /*@=globstate =observertrans @*/
00254 }
00255 
00258 static int indexCmp(const void * avp, const void * bvp)
00259         /*@*/
00260 {
00261     /*@-castexpose@*/
00262     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00263     /*@=castexpose@*/
00264     return (ap->info.tag - bp->info.tag);
00265 }
00266 
00271 static
00272 void headerSort(Header h)
00273         /*@modifies h @*/
00274 {
00275     if (!(h->flags & HEADERFLAG_SORTED)) {
00276         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00277         h->flags |= HEADERFLAG_SORTED;
00278     }
00279 }
00280 
00283 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00284 {
00285     /*@-castexpose@*/
00286     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00287     /*@=castexpose@*/
00288     int rc = (ap->info.offset - bp->info.offset);
00289 
00290     if (rc == 0) {
00291         /* Within a region, entries sort by address. Added drips sort by tag. */
00292         if (ap->info.offset < 0)
00293             rc = (((char *)ap->data) - ((char *)bp->data));
00294         else
00295             rc = (ap->info.tag - bp->info.tag);
00296     }
00297     return rc;
00298 }
00299 
00304 static
00305 void headerUnsort(Header h)
00306         /*@modifies h @*/
00307 {
00308     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00309 }
00310 
00317 static
00318 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00319         /*@modifies h @*/
00320 {
00321     indexEntry entry;
00322     unsigned int size = 0;
00323     unsigned int pad = 0;
00324     int i;
00325 
00326     if (h == NULL)
00327         return size;
00328 
00329     headerSort(h);
00330 
00331     switch (magicp) {
00332     case HEADER_MAGIC_YES:
00333         size += sizeof(header_magic);
00334         break;
00335     case HEADER_MAGIC_NO:
00336         break;
00337     }
00338 
00339     /*@-sizeoftype@*/
00340     size += 2 * sizeof(int_32); /* count of index entries */
00341     /*@=sizeoftype@*/
00342 
00343     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00344         unsigned diff;
00345         rpmTagType type;
00346 
00347         /* Regions go in as is ... */
00348         if (ENTRY_IS_REGION(entry)) {
00349             size += entry->length;
00350             /* XXX Legacy regions do not include the region tag and data. */
00351             /*@-sizeoftype@*/
00352             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00353                 size += sizeof(struct entryInfo_s) + entry->info.count;
00354             /*@=sizeoftype@*/
00355             continue;
00356         }
00357 
00358         /* ... and region elements are skipped. */
00359         if (entry->info.offset < 0)
00360             continue;
00361 
00362         /* Alignment */
00363         type = entry->info.type;
00364         if (typeSizes[type] > 1) {
00365             diff = typeSizes[type] - (size % typeSizes[type]);
00366             if (diff != typeSizes[type]) {
00367                 size += diff;
00368                 pad += diff;
00369             }
00370         }
00371 
00372         /*@-sizeoftype@*/
00373         size += sizeof(struct entryInfo_s) + entry->length;
00374         /*@=sizeoftype@*/
00375     }
00376 
00377     return size;
00378 }
00379 
00389 static int dataLength(rpmTagType type, rpmTagData * p, rpmTagCount count,
00390                 int onDisk, /*@null@*/ rpmTagData * pend)
00391         /*@*/
00392 {
00393     const unsigned char * s = (*p).ui8p;
00394     const unsigned char * se = (pend ? (*pend).ui8p : NULL);
00395     int length = 0;
00396 
00397     switch (type) {
00398     case RPM_STRING_TYPE:
00399         if (count != 1)
00400             return -1;
00401         while (*s++) {
00402             if (se && s > se)
00403                 return -1;
00404             length++;
00405         }
00406         length++;       /* count nul terminator too. */
00407         break;
00408         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00409         /* Compute sum of length of all strings, including nul terminators */
00410     case RPM_I18NSTRING_TYPE:
00411     case RPM_STRING_ARRAY_TYPE:
00412         if (onDisk) {
00413             while (count--) {
00414                 length++;       /* count nul terminator too */
00415                while (*s++) {
00416                     if (se && s > se)
00417                         return -1;      /* XXX change errret, use size_t */
00418                     length++;
00419                 }
00420             }
00421         } else {
00422             const char ** av = (*p).argv;
00423             while (count--) {
00424                 /* add one for null termination */
00425                 length += strlen(*av++) + 1;
00426             }
00427         }
00428         break;
00429     default:
00430         if (typeSizes[type] == -1)
00431             return -1;          /* XXX change errret, use size_t */
00432         length = typeSizes[(type & 0xf)] * count;
00433         if (length < 0 || (se && (s + length) > se))
00434             return -1;          /* XXX change errret, use size_t */
00435         break;
00436     }
00437 
00438     return length;
00439 }
00440 
00467 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00468                 entryInfo pe,
00469                 unsigned char * dataStart,
00470                 /*@null@*/ const unsigned char * dataEnd,
00471                 int regionid)
00472         /*@modifies *entry, *dataStart @*/
00473 {
00474     rpmTagData p;
00475     rpmTagData pend;
00476     unsigned char * tprev = NULL;
00477     unsigned char * t = NULL;
00478     int tdel = 0;
00479     int tl = dl;
00480     struct indexEntry_s ieprev;
00481 
00482     memset(&ieprev, 0, sizeof(ieprev));
00483     for (; il > 0; il--, pe++) {
00484         struct indexEntry_s ie;
00485         rpmTagType type;
00486 
00487         ie.info.tag = ntohl(pe->tag);
00488         ie.info.type = ntohl(pe->type);
00489         ie.info.count = ntohl(pe->count);
00490         ie.info.offset = ntohl(pe->offset);
00491 
00492         if (hdrchkType(ie.info.type))
00493             return -1;
00494         if (hdrchkData(ie.info.count))
00495             return -1;
00496         if (hdrchkData(ie.info.offset))
00497             return -1;
00498         if (hdrchkAlign(ie.info.type, ie.info.offset))
00499             return -1;
00500 
00501         ie.data = t = dataStart + ie.info.offset;
00502         if (dataEnd && t >= dataEnd)
00503             return -1;
00504 
00505         p.ptr = ie.data;
00506         pend.ui8p = (unsigned char *) dataEnd;
00507         ie.length = dataLength(ie.info.type, &p, ie.info.count, 1, &pend);
00508         if (ie.length < 0 || hdrchkData(ie.length))
00509             return -1;
00510 
00511         ie.rdlen = 0;
00512 
00513         if (entry) {
00514             ie.info.offset = regionid;
00515             *entry = ie;        /* structure assignment */
00516             entry++;
00517         }
00518 
00519         /* Alignment */
00520         type = ie.info.type;
00521         if (typeSizes[type] > 1) {
00522             unsigned diff;
00523             diff = typeSizes[type] - (dl % typeSizes[type]);
00524             if (diff != typeSizes[type]) {
00525                 dl += diff;
00526                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00527                     ieprev.length += diff;
00528             }
00529         }
00530         tdel = (tprev ? (t - tprev) : 0);
00531         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00532             tdel = ieprev.length;
00533 
00534         if (ie.info.tag >= HEADER_I18NTABLE) {
00535             tprev = t;
00536         } else {
00537             tprev = dataStart;
00538             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00539             /*@-sizeoftype@*/
00540             if (ie.info.tag == HEADER_IMAGE)
00541                 tprev -= REGION_TAG_COUNT;
00542             /*@=sizeoftype@*/
00543         }
00544 
00545         /* Perform endian conversions */
00546         switch (ntohl(pe->type)) {
00547         case RPM_INT64_TYPE:
00548         {   int_64 * it = (int_64 *)t;
00549             int_32 b[2];
00550             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00551                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00552                     return -1;
00553                 b[1] = htonl(((int_32 *)it)[0]);
00554                 b[0] = htonl(((int_32 *)it)[1]);
00555                 if (b[1] != ((int_32 *)it)[0])
00556                     memcpy(it, b, sizeof(b));
00557             }
00558             t = (unsigned char *) it;
00559         }   /*@switchbreak@*/ break;
00560         case RPM_INT32_TYPE:
00561         {   int_32 * it = (int_32 *)t;
00562             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00563                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00564                     return -1;
00565                 *it = htonl(*it);
00566             }
00567             t = (unsigned char *) it;
00568         }   /*@switchbreak@*/ break;
00569         case RPM_INT16_TYPE:
00570         {   int_16 * it = (int_16 *) t;
00571             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00572                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00573                     return -1;
00574                 *it = htons(*it);
00575             }
00576             t = (unsigned char *) it;
00577         }   /*@switchbreak@*/ break;
00578         default:
00579             t += ie.length;
00580             /*@switchbreak@*/ break;
00581         }
00582 
00583         dl += ie.length;
00584         if (dataEnd && (dataStart + dl) > dataEnd) return -1;
00585         tl += tdel;
00586         ieprev = ie;    /* structure assignment */
00587 
00588     }
00589     tdel = (tprev ? (t - tprev) : 0);
00590     tl += tdel;
00591 
00592     /* XXX
00593      * There are two hacks here:
00594      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00595      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00596      */
00597     /*@-sizeoftype@*/
00598     if (tl+REGION_TAG_COUNT == dl)
00599         tl += REGION_TAG_COUNT;
00600     /*@=sizeoftype@*/
00601 
00602     return dl;
00603 }
00604 
00610 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00611                 /*@out@*/ size_t * lenp)
00612         /*@modifies h, *lenp @*/
00613         /*@requires maxSet(lenp) >= 0 @*/
00614         /*@ensures maxRead(result) == (*lenp) @*/
00615 {
00616     void * sw;
00617     int_32 * ei = NULL;
00618     entryInfo pe;
00619     unsigned char * dataStart;
00620     unsigned char * te;
00621     unsigned pad;
00622     unsigned len = 0;
00623     int_32 il = 0;
00624     int_32 dl = 0;
00625     indexEntry entry; 
00626     rpmTagType type;
00627     int i;
00628     int drlen, ndribbles;
00629     int driplen, ndrips;
00630     int legacy = 0;
00631 
00632     if ((sw = headerGetStats(h, 18)) != NULL)   /* RPMTS_OP_HDRLOAD */
00633         (void) rpmswEnter(sw, 0);
00634 
00635     /* Sort entries by (offset,tag). */
00636     headerUnsort(h);
00637 
00638     /* Compute (il,dl) for all tags, including those deleted in region. */
00639     pad = 0;
00640     drlen = ndribbles = driplen = ndrips = 0;
00641     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00642         if (ENTRY_IS_REGION(entry)) {
00643             int_32 rdl = -entry->info.offset;   /* negative offset */
00644             int_32 ril = rdl/sizeof(*pe);
00645             int rid = entry->info.offset;
00646 
00647             il += ril;
00648             dl += entry->rdlen + entry->info.count;
00649             /* XXX Legacy regions do not include the region tag and data. */
00650             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00651                 il += 1;
00652 
00653             /* Skip rest of entries in region, but account for dribbles. */
00654             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00655                 if (entry->info.offset <= rid)
00656                     /*@innercontinue@*/ continue;
00657 
00658                 /* Alignment */
00659                 type = entry->info.type;
00660                 if (typeSizes[type] > 1) {
00661                     unsigned diff;
00662                     diff = typeSizes[type] - (dl % typeSizes[type]);
00663                     if (diff != typeSizes[type]) {
00664                         drlen += diff;
00665                         pad += diff;
00666                         dl += diff;
00667                     }
00668                 }
00669 
00670                 ndribbles++;
00671                 il++;
00672                 drlen += entry->length;
00673                 dl += entry->length;
00674             }
00675             i--;
00676             entry--;
00677             continue;
00678         }
00679 
00680         /* Ignore deleted drips. */
00681         if (entry->data == NULL || entry->length <= 0)
00682             continue;
00683 
00684         /* Alignment */
00685         type = entry->info.type;
00686         if (typeSizes[type] > 1) {
00687             unsigned diff;
00688             diff = typeSizes[type] - (dl % typeSizes[type]);
00689             if (diff != typeSizes[type]) {
00690                 driplen += diff;
00691                 pad += diff;
00692                 dl += diff;
00693             } else
00694                 diff = 0;
00695         }
00696 
00697         ndrips++;
00698         il++;
00699         driplen += entry->length;
00700         dl += entry->length;
00701     }
00702 
00703     /* Sanity checks on header intro. */
00704     if (hdrchkTags(il) || hdrchkData(dl))
00705         goto errxit;
00706 
00707     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00708 
00709     ei = xmalloc(len);
00710     ei[0] = htonl(il);
00711     ei[1] = htonl(dl);
00712 
00713     pe = (entryInfo) &ei[2];
00714     dataStart = te = (unsigned char *) (pe + il);
00715 
00716     pad = 0;
00717     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00718         const char * src;
00719         unsigned char *t;
00720         int count;
00721         int rdlen;
00722 
00723         if (entry->data == NULL || entry->length <= 0)
00724             continue;
00725 
00726         t = te;
00727         pe->tag = htonl(entry->info.tag);
00728         pe->type = htonl(entry->info.type);
00729         pe->count = htonl(entry->info.count);
00730 
00731         if (ENTRY_IS_REGION(entry)) {
00732             int_32 rdl = -entry->info.offset;   /* negative offset */
00733             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00734             int rid = entry->info.offset;
00735 
00736             src = (char *)entry->data;
00737             rdlen = entry->rdlen;
00738 
00739             /* XXX Legacy regions do not include the region tag and data. */
00740             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00741                 int_32 stei[4];
00742 
00743                 legacy = 1;
00744                 memcpy(pe+1, src, rdl);
00745                 memcpy(te, src + rdl, rdlen);
00746                 te += rdlen;
00747 
00748                 pe->offset = htonl(te - dataStart);
00749                 stei[0] = pe->tag;
00750                 stei[1] = pe->type;
00751                 stei[2] = htonl(-rdl-entry->info.count);
00752                 stei[3] = pe->count;
00753                 memcpy(te, stei, entry->info.count);
00754                 te += entry->info.count;
00755                 ril++;
00756                 rdlen += entry->info.count;
00757 
00758                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00759                 if (count != rdlen)
00760                     goto errxit;
00761 
00762             } else {
00763 
00764                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00765                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00766                 te += rdlen;
00767                 {   /*@-castexpose@*/
00768                     entryInfo se = (entryInfo)src;
00769                     /*@=castexpose@*/
00770                     int off = ntohl(se->offset);
00771                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00772                 }
00773                 te += entry->info.count + drlen;
00774 
00775                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00776                 if (count != (rdlen + entry->info.count + drlen))
00777                     goto errxit;
00778             }
00779 
00780             /* Skip rest of entries in region. */
00781             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00782                 i++;
00783                 entry++;
00784             }
00785             i--;
00786             entry--;
00787             pe += ril;
00788             continue;
00789         }
00790 
00791         /* Ignore deleted drips. */
00792         if (entry->data == NULL || entry->length <= 0)
00793             continue;
00794 
00795         /* Alignment */
00796         type = entry->info.type;
00797         if (typeSizes[type] > 1) {
00798             unsigned diff;
00799             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00800             if (diff != typeSizes[type]) {
00801                 memset(te, 0, diff);
00802                 te += diff;
00803                 pad += diff;
00804             }
00805         }
00806 
00807         pe->offset = htonl(te - dataStart);
00808 
00809         /* copy data w/ endian conversions */
00810         switch (entry->info.type) {
00811         case RPM_INT64_TYPE:
00812         {   int_32 b[2];
00813             count = entry->info.count;
00814             src = entry->data;
00815             while (count--) {
00816                 b[1] = htonl(((int_32 *)src)[0]);
00817                 b[0] = htonl(((int_32 *)src)[1]);
00818                 if (b[1] == ((int_32 *)src)[0])
00819                     memcpy(te, src, sizeof(b));
00820                 else
00821                     memcpy(te, b, sizeof(b));
00822                 te += sizeof(b);
00823                 src += sizeof(b);
00824             }
00825         }   /*@switchbreak@*/ break;
00826 
00827         case RPM_INT32_TYPE:
00828             count = entry->info.count;
00829             src = entry->data;
00830             while (count--) {
00831                 *((int_32 *)te) = htonl(*((int_32 *)src));
00832                 /*@-sizeoftype@*/
00833                 te += sizeof(int_32);
00834                 src += sizeof(int_32);
00835                 /*@=sizeoftype@*/
00836             }
00837             /*@switchbreak@*/ break;
00838 
00839         case RPM_INT16_TYPE:
00840             count = entry->info.count;
00841             src = entry->data;
00842             while (count--) {
00843                 *((int_16 *)te) = htons(*((int_16 *)src));
00844                 /*@-sizeoftype@*/
00845                 te += sizeof(int_16);
00846                 src += sizeof(int_16);
00847                 /*@=sizeoftype@*/
00848             }
00849             /*@switchbreak@*/ break;
00850 
00851         default:
00852             memcpy(te, entry->data, entry->length);
00853             te += entry->length;
00854             /*@switchbreak@*/ break;
00855         }
00856         pe++;
00857     }
00858    
00859     /* Insure that there are no memcpy underruns/overruns. */
00860     if (((unsigned char *)pe) != dataStart)
00861         goto errxit;
00862     if ((((unsigned char *)ei)+len) != te)
00863         goto errxit;
00864 
00865     if (lenp)
00866         *lenp = len;
00867 
00868     h->flags &= ~HEADERFLAG_SORTED;
00869     headerSort(h);
00870 
00871     if (sw != NULL)     (void) rpmswExit(sw, len);
00872 
00873     return (void *) ei;
00874 
00875 errxit:
00876     if (sw != NULL)     (void) rpmswExit(sw, len);
00877     /*@-usereleased@*/
00878     ei = _free(ei);
00879     /*@=usereleased@*/
00880     return (void *) ei;
00881 }
00882 
00888 static /*@only@*/ /*@null@*/
00889 void * headerUnload(Header h)
00890         /*@modifies h @*/
00891 {
00892     size_t length;
00893     void * uh = doHeaderUnload(h, &length);
00894     return uh;
00895 }
00896 
00904 static /*@null@*/
00905 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, rpmTagType type)
00906         /*@modifies h @*/
00907 {
00908     indexEntry entry, entry2, last;
00909     struct indexEntry_s key;
00910 
00911     if (h == NULL) return NULL;
00912     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00913 
00914     key.info.tag = tag;
00915 
00916     entry2 = entry = 
00917         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00918     if (entry == NULL)
00919         return NULL;
00920 
00921     if (type == RPM_NULL_TYPE)
00922         return entry;
00923 
00924     /* look backwards */
00925     while (entry->info.tag == tag && entry->info.type != type &&
00926            entry > h->index) entry--;
00927 
00928     if (entry->info.tag == tag && entry->info.type == type)
00929         return entry;
00930 
00931     last = h->index + h->indexUsed;
00932     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00933     while (entry2->info.tag == tag && entry2->info.type != type &&
00934            entry2 < last) entry2++;
00935     /*@=usereleased@*/
00936 
00937     if (entry->info.tag == tag && entry->info.type == type)
00938         return entry;
00939 
00940     return NULL;
00941 }
00942 
00952 static
00953 int headerRemoveEntry(Header h, int_32 tag)
00954         /*@modifies h @*/
00955 {
00956     indexEntry last = h->index + h->indexUsed;
00957     indexEntry entry, first;
00958     int ne;
00959 
00960     entry = findEntry(h, tag, RPM_NULL_TYPE);
00961     if (!entry) return 1;
00962 
00963     /* Make sure entry points to the first occurence of this tag. */
00964     while (entry > h->index && (entry - 1)->info.tag == tag)  
00965         entry--;
00966 
00967     /* Free data for tags being removed. */
00968     for (first = entry; first < last; first++) {
00969         void * data;
00970         if (first->info.tag != tag)
00971             break;
00972         data = first->data;
00973         first->data = NULL;
00974         first->length = 0;
00975         if (ENTRY_IN_REGION(first))
00976             continue;
00977         data = _free(data);
00978     }
00979 
00980     ne = (first - entry);
00981     if (ne > 0) {
00982         h->indexUsed -= ne;
00983         ne = last - first;
00984         if (ne > 0)
00985             memmove(entry, first, (ne * sizeof(*entry)));
00986     }
00987 
00988     return 0;
00989 }
00990 
00996 static /*@null@*/
00997 Header headerLoad(/*@kept@*/ void * uh)
00998         /*@modifies uh @*/
00999 {
01000     void * sw = NULL;
01001     int_32 * ei = (int_32 *) uh;
01002     int_32 il = ntohl(ei[0]);           /* index length */
01003     int_32 dl = ntohl(ei[1]);           /* data length */
01004     /*@-sizeoftype@*/
01005     size_t pvlen = sizeof(il) + sizeof(dl) +
01006                (il * sizeof(struct entryInfo_s)) + dl;
01007     /*@=sizeoftype@*/
01008     void * pv = uh;
01009     Header h = NULL;
01010     entryInfo pe;
01011     unsigned char * dataStart;
01012     unsigned char * dataEnd;
01013     indexEntry entry; 
01014     int rdlen;
01015     int i;
01016 
01017     /* Sanity checks on header intro. */
01018     if (hdrchkTags(il) || hdrchkData(dl))
01019         goto errxit;
01020 
01021     ei = (int_32 *) pv;
01022     /*@-castexpose@*/
01023     pe = (entryInfo) &ei[2];
01024     /*@=castexpose@*/
01025     dataStart = (unsigned char *) (pe + il);
01026     dataEnd = dataStart + dl;
01027 
01028     h = xcalloc(1, sizeof(*h));
01029     if ((sw = headerGetStats(h, 18)) != NULL)   /* RPMTS_OP_HDRLOAD */
01030         (void) rpmswEnter(sw, 0);
01031     /*@-assignexpose@*/
01032     h->hv = *hdrVec;            /* structure assignment */
01033     /*@=assignexpose@*/
01034     /*@-assignexpose -kepttrans@*/
01035     h->blob = uh;
01036     /*@=assignexpose =kepttrans@*/
01037     h->indexAlloced = il + 1;
01038     h->indexUsed = il;
01039     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01040     h->flags |= HEADERFLAG_SORTED;
01041     h->nrefs = 0;
01042     h = headerLink(h);
01043 
01044     entry = h->index;
01045     i = 0;
01046     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01047         h->flags |= HEADERFLAG_LEGACY;
01048         entry->info.type = REGION_TAG_TYPE;
01049         entry->info.tag = HEADER_IMAGE;
01050         /*@-sizeoftype@*/
01051         entry->info.count = REGION_TAG_COUNT;
01052         /*@=sizeoftype@*/
01053         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01054 
01055         /*@-assignexpose@*/
01056         entry->data = pe;
01057         /*@=assignexpose@*/
01058         entry->length = pvlen - sizeof(il) - sizeof(dl);
01059         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01060 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01061         if (rdlen != dl)
01062             goto errxit;
01063 #endif
01064         entry->rdlen = rdlen;
01065         entry++;
01066         h->indexUsed++;
01067     } else {
01068         int_32 rdl;
01069         int_32 ril;
01070 
01071         h->flags &= ~HEADERFLAG_LEGACY;
01072 
01073         entry->info.type = htonl(pe->type);
01074         entry->info.count = htonl(pe->count);
01075 
01076         if (hdrchkType(entry->info.type))
01077             goto errxit;
01078         if (hdrchkTags(entry->info.count))
01079             goto errxit;
01080 
01081         {   int off = ntohl(pe->offset);
01082 
01083             if (hdrchkData(off))
01084                 goto errxit;
01085             if (off) {
01086 /*@-sizeoftype@*/
01087                 size_t nb = REGION_TAG_COUNT;
01088 /*@=sizeoftype@*/
01089                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01090                 rdl = -ntohl(stei[2]);  /* negative offset */
01091                 ril = rdl/sizeof(*pe);
01092                 if (hdrchkTags(ril) || hdrchkData(rdl))
01093                     goto errxit;
01094                 entry->info.tag = htonl(pe->tag);
01095             } else {
01096                 ril = il;
01097                 /*@-sizeoftype@*/
01098                 rdl = (ril * sizeof(struct entryInfo_s));
01099                 /*@=sizeoftype@*/
01100                 entry->info.tag = HEADER_IMAGE;
01101             }
01102         }
01103         entry->info.offset = -rdl;      /* negative offset */
01104 
01105         /*@-assignexpose@*/
01106         entry->data = pe;
01107         /*@=assignexpose@*/
01108         entry->length = pvlen - sizeof(il) - sizeof(dl);
01109         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01110         if (rdlen < 0)
01111             goto errxit;
01112         entry->rdlen = rdlen;
01113 
01114         if (ril < h->indexUsed) {
01115             indexEntry newEntry = entry + ril;
01116             int ne = (h->indexUsed - ril);
01117             int rid = entry->info.offset+1;
01118             int rc;
01119 
01120             /* Load dribble entries from region. */
01121             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01122             if (rc < 0)
01123                 goto errxit;
01124             rdlen += rc;
01125 
01126           { indexEntry firstEntry = newEntry;
01127             int save = h->indexUsed;
01128             int j;
01129 
01130             /* Dribble entries replace duplicate region entries. */
01131             h->indexUsed -= ne;
01132             for (j = 0; j < ne; j++, newEntry++) {
01133                 (void) headerRemoveEntry(h, newEntry->info.tag);
01134                 if (newEntry->info.tag == HEADER_BASENAMES)
01135                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01136             }
01137 
01138             /* If any duplicate entries were replaced, move new entries down. */
01139             if (h->indexUsed < (save - ne)) {
01140                 memmove(h->index + h->indexUsed, firstEntry,
01141                         (ne * sizeof(*entry)));
01142             }
01143             h->indexUsed += ne;
01144           }
01145         }
01146     }
01147 
01148     h->flags &= ~HEADERFLAG_SORTED;
01149     headerSort(h);
01150 
01151     if (sw != NULL)     (void) rpmswExit(sw, pvlen);
01152 
01153     /*@-globstate -observertrans @*/
01154     return h;
01155     /*@=globstate =observertrans @*/
01156 
01157 errxit:
01158     if (sw != NULL)     (void) rpmswExit(sw, pvlen);
01159     /*@-usereleased@*/
01160     if (h) {
01161         h->index = _free(h->index);
01162         /*@-refcounttrans@*/
01163         h = _free(h);
01164         /*@=refcounttrans@*/
01165     }
01166     /*@=usereleased@*/
01167     /*@-refcounttrans -globstate@*/
01168     return h;
01169     /*@=refcounttrans =globstate@*/
01170 }
01171 
01177 static /*@observer@*/ /*@null@*/
01178 const char * headerGetOrigin(/*@null@*/ Header h)
01179         /*@*/
01180 {
01181     return (h != NULL ? h->origin : NULL);
01182 }
01183 
01190 static
01191 int headerSetOrigin(/*@null@*/ Header h, const char * origin)
01192         /*@modifies h @*/
01193 {
01194     if (h != NULL) {
01195         h->origin = _free(h->origin);
01196         h->origin = xstrdup(origin);
01197     }
01198     return 0;
01199 }
01200 
01201 const char * headerGetBaseURL(Header h);        /* XXX keep GCC quiet */
01202 const char * headerGetBaseURL(Header h)
01203 {
01204     return (h != NULL ? h->baseurl : NULL);
01205 }
01206 
01207 int headerSetBaseURL(Header h, const char * baseurl);   /* XXX keep GCC quiet */
01208 int headerSetBaseURL(Header h, const char * baseurl)
01209 {
01210     if (h != NULL) {
01211         h->baseurl = _free(h->baseurl);
01212         h->baseurl = xstrdup(baseurl);
01213     }
01214     return 0;
01215 }
01216 
01217 struct stat * headerGetStatbuf(Header h);       /* XXX keep GCC quiet */
01218 struct stat * headerGetStatbuf(Header h)
01219 {
01220     return &h->sb;
01221 }
01222 
01223 int headerSetStatbuf(Header h, struct stat * st);       /* XXX keep GCC quiet */
01224 int headerSetStatbuf(Header h, struct stat * st)
01225 {
01226     if (h != NULL && st != NULL)
01227         memcpy(&h->sb, st, sizeof(h->sb));
01228     return 0;
01229 }
01230 
01231 const char * headerGetDigest(Header h);         /* XXX keep GCC quiet. */
01232 const char * headerGetDigest(Header h)
01233 {
01234     return (h != NULL ? h->digest : NULL);
01235 }
01236 
01237 int headerSetDigest(Header h, const char * digest);     /* XXX keep GCC quiet */
01238 int headerSetDigest(Header h, const char * digest)
01239 {
01240     if (h != NULL) {
01241         h->digest = _free(h->digest);
01242         h->digest = xstrdup(digest);
01243     }
01244     return 0;
01245 }
01246 
01247 static
01248 uint32_t headerGetInstance(/*@null@*/ Header h)
01249         /*@*/
01250 {
01251     return (h != NULL ? h->instance : 0);
01252 }
01253 
01254 static
01255 uint32_t headerSetInstance(/*@null@*/ Header h, uint32_t instance)
01256         /*@modifies h @*/
01257 {
01258     if (h != NULL)
01259         h->instance = instance;
01260     return 0;
01261 }
01262 
01263 uint32_t headerGetStartOff(Header h);   /* XXX keep GCC quiet */
01264 uint32_t headerGetStartOff(Header h)
01265 {
01266     return (h != NULL ? h->startoff : 0);
01267 }
01268 
01269 uint32_t headerSetStartOff(Header h, uint32_t startoff);        /* XXX keep GCC quiet */
01270 uint32_t headerSetStartOff(Header h, uint32_t startoff)
01271 {
01272     if (h != NULL)
01273         h->startoff = startoff;
01274     return 0;
01275 }
01276 
01277 uint32_t headerGetEndOff(Header h);     /* XXX keep GCC quiet */
01278 uint32_t headerGetEndOff(Header h)
01279 {
01280     return (h != NULL ? h->endoff : 0);
01281 }
01282 
01283 uint32_t headerSetEndOff(Header h, uint32_t endoff);    /* XXX keep GCC quiet. */
01284 uint32_t headerSetEndOff(Header h, uint32_t endoff)
01285 {
01286     if (h != NULL)
01287         h->endoff = endoff;
01288     return 0;
01289 }
01290 
01298 static /*@null@*/
01299 Header headerReload(/*@only@*/ Header h, int tag)
01300         /*@modifies h @*/
01301 {
01302     Header nh;
01303     size_t length;
01304     void * uh;
01305     const char * origin = (h->origin != NULL ? xstrdup(h->origin) : NULL);
01306     const char * baseurl = (h->baseurl != NULL ? xstrdup(h->baseurl) : NULL);
01307     const char * digest = (h->digest != NULL ? xstrdup(h->digest) : NULL);
01308     struct stat sb = h->sb;     /* structure assignment */
01309     int_32 instance = h->instance;
01310     int xx;
01311 
01312 /*@-onlytrans@*/
01313     uh = doHeaderUnload(h, &length);
01314     h = headerFree(h);
01315 /*@=onlytrans@*/
01316     if (uh == NULL)
01317         return NULL;
01318     nh = headerLoad(uh);
01319     if (nh == NULL) {
01320         uh = _free(uh);
01321         return NULL;
01322     }
01323     if (nh->flags & HEADERFLAG_ALLOCATED)
01324         uh = _free(uh);
01325     nh->flags |= HEADERFLAG_ALLOCATED;
01326     if (ENTRY_IS_REGION(nh->index)) {
01327         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01328             nh->index[0].info.tag = tag;
01329     }
01330     if (origin != NULL) {
01331         xx = headerSetOrigin(nh, origin);
01332         origin = _free(origin);
01333     }
01334     if (baseurl != NULL) {
01335         xx = headerSetBaseURL(nh, baseurl);
01336         baseurl = _free(baseurl);
01337     }
01338     if (digest != NULL) {
01339         xx = headerSetDigest(nh, digest);
01340         digest = _free(digest);
01341     }
01342     nh->sb = sb;        /* structure assignment */
01343     xx = headerSetInstance(nh, instance);
01344     return nh;
01345 }
01346 
01352 static /*@null@*/
01353 Header headerCopyLoad(const void * uh)
01354         /*@*/
01355 {
01356     int_32 * ei = (int_32 *) uh;
01357     int_32 il = ntohl(ei[0]);           /* index length */
01358     int_32 dl = ntohl(ei[1]);           /* data length */
01359     /*@-sizeoftype@*/
01360     size_t pvlen = sizeof(il) + sizeof(dl) +
01361                         (il * sizeof(struct entryInfo_s)) + dl;
01362     /*@=sizeoftype@*/
01363     void * nuh = NULL;
01364     Header h = NULL;
01365 
01366     /* Sanity checks on header intro. */
01367     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01368         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01369         if ((h = headerLoad(nuh)) != NULL)
01370             h->flags |= HEADERFLAG_ALLOCATED;
01371     }
01372     if (h == NULL)
01373         nuh = _free(nuh);
01374     return h;
01375 }
01376 
01383 static /*@null@*/
01384 Header headerRead(void * _fd, enum hMagic magicp)
01385         /*@modifies _fd @*/
01386 {
01387     FD_t fd = _fd;
01388     int_32 block[4];
01389     int_32 reserved;
01390     int_32 * ei = NULL;
01391     int_32 il;
01392     int_32 dl;
01393     int_32 magic;
01394     Header h = NULL;
01395     size_t len;
01396     int i;
01397 
01398     memset(block, 0, sizeof(block));
01399     i = 2;
01400     if (magicp == HEADER_MAGIC_YES)
01401         i += 2;
01402 
01403     /*@-type@*/ /* FIX: cast? */
01404     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01405         goto exit;
01406     /*@=type@*/
01407 
01408     i = 0;
01409 
01410     if (magicp == HEADER_MAGIC_YES) {
01411         magic = block[i++];
01412         if (memcmp(&magic, header_magic, sizeof(magic)))
01413             goto exit;
01414         reserved = block[i++];
01415     }
01416     
01417     il = ntohl(block[i]);       i++;
01418     dl = ntohl(block[i]);       i++;
01419 
01420     /*@-sizeoftype@*/
01421     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01422     /*@=sizeoftype@*/
01423 
01424     /* Sanity checks on header intro. */
01425     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01426         goto exit;
01427 
01428     ei = xmalloc(len);
01429     ei[0] = htonl(il);
01430     ei[1] = htonl(dl);
01431     len -= sizeof(il) + sizeof(dl);
01432 
01433     /*@-type@*/ /* FIX: cast? */
01434     if (timedRead(fd, (char *)&ei[2], len) != len)
01435         goto exit;
01436     /*@=type@*/
01437     
01438     h = headerLoad(ei);
01439 
01440     {   const char * origin = fdGetOPath(fd);
01441         if (origin != NULL)
01442             (void) headerSetOrigin(h, origin);
01443     }
01444 
01445 exit:
01446     if (h) {
01447         if (h->flags & HEADERFLAG_ALLOCATED)
01448             ei = _free(ei);
01449         h->flags |= HEADERFLAG_ALLOCATED;
01450     } else if (ei)
01451         ei = _free(ei);
01452     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01453     return h;
01454     /*@-mustmod@*/
01455 }
01456 
01464 static
01465 int headerWrite(void * _fd, /*@null@*/ Header h, enum hMagic magicp)
01466         /*@globals fileSystem @*/
01467         /*@modifies fd, h, fileSystem @*/
01468 {
01469     FD_t fd = _fd;
01470     ssize_t nb;
01471     size_t length;
01472     const void * uh;
01473 
01474     if (h == NULL)
01475         return 1;
01476     uh = doHeaderUnload(h, &length);
01477     if (uh == NULL)
01478         return 1;
01479     switch (magicp) {
01480     case HEADER_MAGIC_YES:
01481         /*@-sizeoftype@*/
01482         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01483         /*@=sizeoftype@*/
01484         if (nb != sizeof(header_magic))
01485             goto exit;
01486         break;
01487     case HEADER_MAGIC_NO:
01488         break;
01489     }
01490 
01491     /*@-sizeoftype@*/
01492     nb = Fwrite(uh, sizeof(char), length, fd);
01493     /*@=sizeoftype@*/
01494 
01495 exit:
01496     uh = _free(uh);
01497     return (nb == length ? 0 : 1);
01498 }
01499 
01506 static
01507 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01508         /*@*/
01509 {
01510     /*@-mods@*/         /*@ FIX: h modified by sort. */
01511     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01512     /*@=mods@*/ 
01513 }
01514 
01525 static int copyEntry(const indexEntry entry,
01526                 /*@null@*/ /*@out@*/ rpmTagType * type,
01527                 /*@null@*/ /*@out@*/ rpmTagData * p,
01528                 /*@null@*/ /*@out@*/ rpmTagCount * c,
01529                 int minMem)
01530         /*@modifies *type, *p, *c @*/
01531         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01532 {
01533     rpmTagCount count = entry->info.count;
01534     int rc = 1;         /* XXX 1 on success. */
01535 
01536     if (p)
01537     switch (entry->info.type) {
01538     case RPM_BIN_TYPE:
01539         /*
01540          * XXX This only works for
01541          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01542          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01543          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01544          */
01545         if (ENTRY_IS_REGION(entry)) {
01546             int_32 * ei = ((int_32 *)entry->data) - 2;
01547             /*@-castexpose@*/
01548             entryInfo pe = (entryInfo) (ei + 2);
01549             /*@=castexpose@*/
01550             unsigned char * dataStart = (unsigned char *) (pe + ntohl(ei[0]));
01551             unsigned char * dataEnd;
01552             int_32 rdl = -entry->info.offset;   /* negative offset */
01553             int_32 ril = rdl/sizeof(*pe);
01554 
01555             /*@-sizeoftype@*/
01556             rdl = entry->rdlen;
01557             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01558             if (entry->info.tag == HEADER_IMAGE) {
01559                 ril -= 1;
01560                 pe += 1;
01561             } else {
01562                 count += REGION_TAG_COUNT;
01563                 rdl += REGION_TAG_COUNT;
01564             }
01565 
01566             (*p).i32p = ei = xmalloc(count);
01567             ei[0] = htonl(ril);
01568             ei[1] = htonl(rdl);
01569 
01570             /*@-castexpose@*/
01571             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01572             /*@=castexpose@*/
01573 
01574             dataStart = (unsigned char *) memcpy(pe + ril, dataStart, rdl);
01575             dataEnd = dataStart + rdl;
01576             /*@=sizeoftype@*/
01577 
01578             rc = regionSwab(NULL, ril, 0, pe, dataStart, dataEnd, 0);
01579             /* XXX 1 on success. */
01580             rc = (rc < 0) ? 0 : 1;
01581         } else {
01582             count = entry->length;
01583             (*p).ptr = (!minMem
01584                 ? memcpy(xmalloc(count), entry->data, count)
01585                 : entry->data);
01586         }
01587         break;
01588     case RPM_STRING_TYPE:
01589         if (count == 1) {
01590             (*p).str = entry->data;
01591             break;
01592         }
01593         /*@fallthrough@*/
01594     case RPM_I18NSTRING_TYPE:
01595     case RPM_STRING_ARRAY_TYPE:
01596     {   const char ** argv;
01597         size_t nb = count * sizeof(*argv);
01598         char * t;
01599         int i;
01600 
01601         /*@-mods@*/
01602         if (minMem) {
01603             (*p).argv = argv = xmalloc(nb);
01604             t = entry->data;
01605         } else {
01606             (*p).argv = argv = xmalloc(nb + entry->length);
01607             t = (char *) &argv[count];
01608             memcpy(t, entry->data, entry->length);
01609         }
01610         /*@=mods@*/
01611         for (i = 0; i < count; i++) {
01612             argv[i] = t;
01613             t = strchr(t, 0);
01614             t++;
01615         }
01616     }   break;
01617 
01618     case RPM_OPENPGP_TYPE:      /* XXX W2DO? */
01619     case RPM_ASN1_TYPE:         /* XXX W2DO? */
01620     default:
01621         (*p).ptr = entry->data;
01622         break;
01623     }
01624     if (type) *type = entry->info.type;
01625     if (c) *c = count;
01626     return rc;
01627 }
01628 
01647 static int headerMatchLocale(const char *td, const char *l, const char *le)
01648         /*@*/
01649 {
01650     const char *fe;
01651 
01652 
01653 #if 0
01654   { const char *s, *ll, *CC, *EE, *dd;
01655     char *lbuf, *t.
01656 
01657     /* Copy the buffer and parse out components on the fly. */
01658     lbuf = alloca(le - l + 1);
01659     for (s = l, ll = t = lbuf; *s; s++, t++) {
01660         switch (*s) {
01661         case '_':
01662             *t = '\0';
01663             CC = t + 1;
01664             break;
01665         case '.':
01666             *t = '\0';
01667             EE = t + 1;
01668             break;
01669         case '@':
01670             *t = '\0';
01671             dd = t + 1;
01672             break;
01673         default:
01674             *t = *s;
01675             break;
01676         }
01677     }
01678 
01679     if (ll)     /* ISO language should be lower case */
01680         for (t = ll; *t; t++)   *t = tolower(*t);
01681     if (CC)     /* ISO country code should be upper case */
01682         for (t = CC; *t; t++)   *t = toupper(*t);
01683 
01684     /* There are a total of 16 cases to attempt to match. */
01685   }
01686 #endif
01687 
01688     /* First try a complete match. */
01689     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01690         return 1;
01691 
01692     /* Next, try stripping optional dialect and matching.  */
01693     for (fe = l; fe < le && *fe != '@'; fe++)
01694         {};
01695     if (fe < le && !strncmp(td, l, (fe - l)))
01696         return 1;
01697 
01698     /* Next, try stripping optional codeset and matching.  */
01699     for (fe = l; fe < le && *fe != '.'; fe++)
01700         {};
01701     if (fe < le && !strncmp(td, l, (fe - l)))
01702         return 1;
01703 
01704     /* Finally, try stripping optional country code and matching. */
01705     for (fe = l; fe < le && *fe != '_'; fe++)
01706         {};
01707     if (fe < le && !strncmp(td, l, (fe - l)))
01708         return 1;
01709 
01710     return 0;
01711 }
01712 
01719 /*@dependent@*/ /*@exposed@*/ static char *
01720 headerFindI18NString(Header h, indexEntry entry)
01721         /*@*/
01722 {
01723     const char *lang, *l, *le;
01724     indexEntry table;
01725 
01726     /* XXX Drepper sez' this is the order. */
01727     if ((lang = getenv("LANGUAGE")) == NULL &&
01728         (lang = getenv("LC_ALL")) == NULL &&
01729         (lang = getenv("LC_MESSAGES")) == NULL &&
01730         (lang = getenv("LANG")) == NULL)
01731             return entry->data;
01732     
01733     /*@-mods@*/
01734     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01735         return entry->data;
01736     /*@=mods@*/
01737 
01738     for (l = lang; *l != '\0'; l = le) {
01739         const char *td;
01740         char *ed;
01741         int langNum;
01742 
01743         while (*l && *l == ':')                 /* skip leading colons */
01744             l++;
01745         if (*l == '\0')
01746             break;
01747         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01748             {};
01749 
01750         /* For each entry in the header ... */
01751         for (langNum = 0, td = table->data, ed = entry->data;
01752              langNum < entry->info.count;
01753              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01754 
01755                 if (headerMatchLocale(td, l, le))
01756                     return ed;
01757 
01758         }
01759     }
01760 
01761 /* when everything fail, try gettext */
01762     return ((entry->data != NULL) && *(char*)(entry->data)) ? _(entry->data) : entry->data;
01763 }
01764 
01775 static int intGetEntry(Header h, int_32 tag,
01776                 /*@null@*/ /*@out@*/ rpmTagType * type,
01777                 /*@null@*/ /*@out@*/ rpmTagData * p,
01778                 /*@null@*/ /*@out@*/ rpmTagCount * c,
01779                 int minMem)
01780         /*@modifies *type, *p, *c @*/
01781         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01782 {
01783     indexEntry entry;
01784     int rc;
01785 
01786     /* First find the tag */
01787 /*@-mods@*/             /*@ FIX: h modified by sort. */
01788     entry = findEntry(h, tag, RPM_NULL_TYPE);
01789 /*@=mods@*/
01790     if (entry == NULL) {
01791         if (type) type = 0;
01792         if (p) (*p).ptr = NULL;
01793         if (c) *c = 0;
01794         return 0;
01795     }
01796 
01797     switch (entry->info.type) {
01798     case RPM_I18NSTRING_TYPE:
01799         rc = 1;
01800         if (type) *type = RPM_STRING_TYPE;
01801         if (c) *c = 1;
01802         /*@-dependenttrans@*/
01803         if (p) (*p).str = headerFindI18NString(h, entry);
01804         /*@=dependenttrans@*/
01805         break;
01806     default:
01807         rc = copyEntry(entry, type, p, c, minMem);
01808         break;
01809     }
01810 
01811     /* XXX 1 on success */
01812     return ((rc == 1) ? 1 : 0);
01813 }
01814 
01822 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01823                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01824         /*@modifies data @*/
01825 {
01826     if (data) {
01827         if (type == -1 ||
01828             type == RPM_STRING_ARRAY_TYPE ||
01829             type == RPM_I18NSTRING_TYPE ||
01830             type == RPM_BIN_TYPE ||
01831             type == RPM_ASN1_TYPE ||
01832             type == RPM_OPENPGP_TYPE)
01833                 data = _free(data);
01834     }
01835     return NULL;
01836 }
01837 
01851 static
01852 int headerGetEntry(Header h, int_32 tag,
01853                         /*@null@*/ /*@out@*/ hTYP_t type,
01854                         /*@null@*/ /*@out@*/ void * p,
01855                         /*@null@*/ /*@out@*/ hCNT_t c)
01856         /*@modifies *type, *p, *c @*/
01857         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01858 {
01859     void * sw;
01860     int rc;
01861 
01862     if ((sw = headerGetStats(h, 19)) != NULL)   /* RPMTS_OP_HDRGET */
01863         (void) rpmswEnter(sw, 0);
01864     rc = intGetEntry(h, tag, (rpmTagType *)type, (rpmTagData *)p, (rpmTagCount *)c, 0);
01865     if (sw != NULL)     (void) rpmswExit(sw, 0);
01866     return rc;
01867 }
01868 
01881 static
01882 int headerGetEntryMinMemory(Header h, int_32 tag,
01883                         /*@null@*/ /*@out@*/ hTYP_t type,
01884                         /*@null@*/ /*@out@*/ void * p,
01885                         /*@null@*/ /*@out@*/ hCNT_t c)
01886         /*@modifies *type, *p, *c @*/
01887         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01888 {
01889     void * sw;
01890     int rc;
01891 
01892     if ((sw = headerGetStats(h, 19)) != NULL)   /* RPMTS_OP_HDRGET */
01893         (void) rpmswEnter(sw, 0);
01894     rc = intGetEntry(h, tag, (rpmTagType *)type, (rpmTagData *)p, (rpmTagCount *)c, 1);
01895     if (sw != NULL)     (void) rpmswExit(sw, 0);
01896     return rc;
01897 }
01898 
01899 int headerGetRawEntry(Header h, int_32 tag, rpmTagType * type, void * p, rpmTagCount * c)
01900 {
01901     indexEntry entry;
01902     int rc;
01903 
01904     if (p == NULL) return headerIsEntry(h, tag);
01905 
01906     /* First find the tag */
01907     /*@-mods@*/         /*@ FIX: h modified by sort. */
01908     entry = findEntry(h, tag, RPM_NULL_TYPE);
01909     /*@=mods@*/
01910     if (!entry) {
01911         if (p) *(void **)p = NULL;
01912         if (c) *c = 0;
01913         return 0;
01914     }
01915 
01916     rc = copyEntry(entry, type, p, c, 0);
01917 
01918     /* XXX 1 on success */
01919     return ((rc == 1) ? 1 : 0);
01920 }
01921 
01924 static void copyData(rpmTagType type, rpmTagData * dest, rpmTagData * src,
01925                 rpmTagCount cnt, size_t len)
01926         /*@modifies *dest @*/
01927 {
01928     switch (type) {
01929     case RPM_I18NSTRING_TYPE:
01930     case RPM_STRING_ARRAY_TYPE:
01931     {   const char ** av = (*src).argv;
01932         char * t = (char *) (*dest).str;
01933 
01934         while (cnt-- > 0 && len > 0) {
01935             const char * s;
01936             if ((s = *av++) == NULL)
01937                 continue;
01938             do {
01939                 *t++ = *s++;
01940             } while (s[-1] && --len > 0);
01941         }
01942     }   break;
01943     default:
01944         memmove((*dest).ptr, (*src).ptr, len);
01945         break;
01946     }
01947 }
01948 
01957 /*@null@*/
01958 static void *
01959 grabData(rpmTagType type, rpmTagData * p, rpmTagCount c, /*@out@*/ int * lenp)
01960         /*@modifies *lenp @*/
01961         /*@requires maxSet(lengthPtr) >= 0 @*/
01962 {
01963     rpmTagData data = { .ptr = NULL };
01964     int length;
01965 
01966     length = dataLength(type, p, c, 0, NULL);
01967     if (length > 0) {
01968         data.ptr = xmalloc(length);
01969         copyData(type, &data, p, c, length);
01970     }
01971 
01972     if (lenp)
01973         *lenp = length;
01974     return data.ptr;
01975 }
01976 
01991 static
01992 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01993         /*@modifies h @*/
01994 {
01995     indexEntry entry;
01996     rpmTagData q = { .ptr = (void *) p };
01997     rpmTagData data;
01998     int length;
01999 
02000     /* Count must always be >= 1 for headerAddEntry. */
02001     if (c <= 0)
02002         return 0;
02003 
02004     if (hdrchkType(type))
02005         return 0;
02006     if (hdrchkData(c))
02007         return 0;
02008 
02009     length = 0;
02010     data.ptr = grabData(type, &q, c, &length);
02011     if (data.ptr == NULL || length <= 0)
02012         return 0;
02013 
02014     /* Allocate more index space if necessary */
02015     if (h->indexUsed == h->indexAlloced) {
02016         h->indexAlloced += INDEX_MALLOC_SIZE;
02017         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
02018     }
02019 
02020     /* Fill in the index */
02021     entry = h->index + h->indexUsed;
02022     entry->info.tag = tag;
02023     entry->info.type = type;
02024     entry->info.count = c;
02025     entry->info.offset = 0;
02026     entry->data = data.ptr;
02027     entry->length = length;
02028 
02029     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
02030         h->flags &= ~HEADERFLAG_SORTED;
02031     h->indexUsed++;
02032 
02033     return 1;
02034 }
02035 
02050 static
02051 int headerAppendEntry(Header h, int_32 tag, int_32 type,
02052                 const void * p, int_32 c)
02053         /*@modifies h @*/
02054 {
02055     rpmTagData src = { .ptr = (void *) p };
02056     rpmTagData dest = { .ptr = NULL };
02057     indexEntry entry;
02058     int length;
02059 
02060     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
02061         /* we can't do this */
02062         return 0;
02063     }
02064 
02065     /* Find the tag entry in the header. */
02066     entry = findEntry(h, tag, type);
02067     if (!entry)
02068         return 0;
02069 
02070     length = dataLength(type, &src, c, 0, NULL);
02071     if (length < 0)
02072         return 0;
02073 
02074     if (ENTRY_IN_REGION(entry)) {
02075         char * t = xmalloc(entry->length + length);
02076         memcpy(t, entry->data, entry->length);
02077         entry->data = t;
02078         entry->info.offset = 0;
02079     } else
02080         entry->data = xrealloc(entry->data, entry->length + length);
02081 
02082     dest.ptr = ((char *) entry->data) + entry->length;
02083     copyData(type, &dest, &src, c, length);
02084 
02085     entry->length += length;
02086 
02087     entry->info.count += c;
02088 
02089     return 1;
02090 }
02091 
02101 static
02102 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02103                 const void * p, int_32 c)
02104         /*@modifies h @*/
02105 {
02106     return (findEntry(h, tag, type)
02107         ? headerAppendEntry(h, tag, type, p, c)
02108         : headerAddEntry(h, tag, type, p, c));
02109 }
02110 
02131 static
02132 int headerAddI18NString(Header h, int_32 tag, const char * string,
02133                 const char * lang)
02134         /*@modifies h @*/
02135 {
02136     indexEntry table, entry;
02137     rpmTagData p;
02138     int length;
02139     int ghosts;
02140     int i, langNum;
02141     char * buf;
02142 
02143     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02144     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02145 
02146     if (!table && entry)
02147         return 0;               /* this shouldn't ever happen!! */
02148 
02149     if (!table && !entry) {
02150         const char * argv[2];
02151         int count = 0;
02152         p.argv = argv;
02153         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02154             /*@-observertrans -readonlytrans@*/
02155             p.argv[count++] = "C";
02156             /*@=observertrans =readonlytrans@*/
02157         } else {
02158             /*@-observertrans -readonlytrans@*/
02159             p.argv[count++] = "C";
02160             /*@=observertrans =readonlytrans@*/
02161             p.argv[count++] = lang;
02162         }
02163         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
02164                         p.ptr, count))
02165             return 0;
02166         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02167     }
02168 
02169     if (!table)
02170         return 0;
02171     if (!lang) lang = "C";
02172 
02173     {   const char * l = table->data;
02174         for (langNum = 0; langNum < table->info.count; langNum++) {
02175             if (!strcmp(l, lang)) break;
02176             l += strlen(l) + 1;
02177         }
02178     }
02179 
02180     if (langNum >= table->info.count) {
02181         length = strlen(lang) + 1;
02182         if (ENTRY_IN_REGION(table)) {
02183             char * t = xmalloc(table->length + length);
02184             memcpy(t, table->data, table->length);
02185             table->data = t;
02186             table->info.offset = 0;
02187         } else
02188             table->data = xrealloc(table->data, table->length + length);
02189         memmove(((char *)table->data) + table->length, lang, length);
02190         table->length += length;
02191         table->info.count++;
02192     }
02193 
02194     if (!entry) {
02195         p.argv = alloca(sizeof(*p.argv) * (langNum + 1));
02196         for (i = 0; i < langNum; i++)
02197             p.argv[i] = "";
02198         p.argv[langNum] = string;
02199         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, p.ptr, langNum + 1);
02200     } else if (langNum >= entry->info.count) {
02201         ghosts = langNum - entry->info.count;
02202         
02203         length = strlen(string) + 1 + ghosts;
02204         if (ENTRY_IN_REGION(entry)) {
02205             char * t = xmalloc(entry->length + length);
02206             memcpy(t, entry->data, entry->length);
02207             entry->data = t;
02208             entry->info.offset = 0;
02209         } else
02210             entry->data = xrealloc(entry->data, entry->length + length);
02211 
02212         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02213         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02214 
02215         entry->length += length;
02216         entry->info.count = langNum + 1;
02217     } else {
02218         char *b, *be, *e, *ee, *t;
02219         size_t bn, sn, en;
02220 
02221         /* Set beginning/end pointers to previous data */
02222         b = be = e = ee = entry->data;
02223         for (i = 0; i < table->info.count; i++) {
02224             if (i == langNum)
02225                 be = ee;
02226             ee += strlen(ee) + 1;
02227             if (i == langNum)
02228                 e  = ee;
02229         }
02230 
02231         /* Get storage for new buffer */
02232         bn = (be-b);
02233         sn = strlen(string) + 1;
02234         en = (ee-e);
02235         length = bn + sn + en;
02236         t = buf = xmalloc(length);
02237 
02238         /* Copy values into new storage */
02239         memcpy(t, b, bn);
02240         t += bn;
02241 /*@-mayaliasunique@*/
02242         memcpy(t, string, sn);
02243         t += sn;
02244         memcpy(t, e, en);
02245         t += en;
02246 /*@=mayaliasunique@*/
02247 
02248         /* Replace i18N string array */
02249         entry->length -= strlen(be) + 1;
02250         entry->length += sn;
02251         
02252         if (ENTRY_IN_REGION(entry)) {
02253             entry->info.offset = 0;
02254         } else
02255             entry->data = _free(entry->data);
02256         /*@-dependenttrans@*/
02257         entry->data = buf;
02258         /*@=dependenttrans@*/
02259     }
02260 
02261     return 0;
02262 }
02263 
02274 static
02275 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02276                         const void * p, int_32 c)
02277         /*@modifies h @*/
02278 {
02279     indexEntry entry;
02280     rpmTagData q = { .ptr = (void *) p };
02281     rpmTagData oldData;
02282     rpmTagData newData;
02283     int length;
02284 
02285     /* First find the tag */
02286     entry = findEntry(h, tag, type);
02287     if (!entry)
02288         return 0;
02289 
02290     length = 0;
02291     newData.ptr = grabData(type, &q, c, &length);
02292     if (newData.ptr == NULL || length <= 0)
02293         return 0;
02294 
02295     /* make sure entry points to the first occurence of this tag */
02296     while (entry > h->index && (entry - 1)->info.tag == tag)  
02297         entry--;
02298 
02299     /* free after we've grabbed the new data in case the two are intertwined;
02300        that's a bad idea but at least we won't break */
02301     oldData.ptr = entry->data;
02302 
02303     entry->info.count = c;
02304     entry->info.type = type;
02305     entry->data = newData.ptr;
02306     entry->length = length;
02307 
02308     if (ENTRY_IN_REGION(entry)) {
02309         entry->info.offset = 0;
02310     } else
02311         oldData.ptr = _free(oldData.ptr);
02312 
02313     return 1;
02314 }
02315 
02318 static char escapedChar(const char ch)  /*@*/
02319 {
02320 /*@-modfilesys@*/
02321 if (_hdr_debug)
02322 fprintf(stderr, "\t\t\\%c\n", ch);
02323 /*@=modfilesys@*/
02324     switch (ch) {
02325     case 'a':   return '\a';
02326     case 'b':   return '\b';
02327     case 'f':   return '\f';
02328     case 'n':   return '\n';
02329     case 'r':   return '\r';
02330     case 't':   return '\t';
02331     case 'v':   return '\v';
02332     default:    return ch;
02333     }
02334 }
02335 
02340 static HE_t rpmheMark(/*@null@*/ HE_t he)
02341         /*@modifies he @*/
02342 {
02343     /* Set he->freeData as appropriate for headerGetEntry() . */
02344     if (he)
02345     switch (he->t) {
02346     default:
02347         he->freeData = 0;
02348         break;
02349     case RPM_I18NSTRING_TYPE:
02350     case RPM_STRING_ARRAY_TYPE:
02351     case RPM_BIN_TYPE:
02352         he->freeData = 1;
02353         break;
02354     }
02355     return he;
02356 }
02357 
02362 static HE_t rpmheClean(/*@null@*/ HE_t he)
02363         /*@modifies he @*/
02364 {
02365     if (he) {
02366         if (he->freeData && he->p.ptr != NULL)
02367             he->p.ptr = _free(he->p.ptr);
02368         memset(he, 0, sizeof(*he));
02369     }
02370     return he;
02371 }
02372 
02379 static /*@null@*/ sprintfToken
02380 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02381         /*@modifies *format @*/
02382 {
02383     int i;
02384 
02385     if (format == NULL) return NULL;
02386 
02387     for (i = 0; i < num; i++) {
02388         switch (format[i].type) {
02389         case PTOK_TAG:
02390             if (_tagcache)
02391                 (void) rpmheClean(&format[i].u.tag.he);
02392             format[i].u.tag.av = argvFree(format[i].u.tag.av);
02393             format[i].u.tag.params = argvFree(format[i].u.tag.params);
02394             format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs);
02395             /*@switchbreak@*/ break;
02396         case PTOK_ARRAY:
02397             format[i].u.array.format =
02398                 freeFormat(format[i].u.array.format,
02399                         format[i].u.array.numTokens);
02400             /*@switchbreak@*/ break;
02401         case PTOK_COND:
02402             format[i].u.cond.ifFormat =
02403                 freeFormat(format[i].u.cond.ifFormat, 
02404                         format[i].u.cond.numIfTokens);
02405             format[i].u.cond.elseFormat =
02406                 freeFormat(format[i].u.cond.elseFormat, 
02407                         format[i].u.cond.numElseTokens);
02408             if (_tagcache)
02409                 (void) rpmheClean(&format[i].u.cond.tag.he);
02410             format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av);
02411             format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params);
02412             format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs);
02413             /*@switchbreak@*/ break;
02414         case PTOK_NONE:
02415         case PTOK_STRING:
02416         default:
02417             /*@switchbreak@*/ break;
02418         }
02419     }
02420     format = _free(format);
02421     return NULL;
02422 }
02423 
02427 struct headerIterator_s {
02428 /*@unused@*/
02429     Header h;           
02430 /*@unused@*/
02431     int next_index;     
02432 };
02433 
02439 static /*@null@*/
02440 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
02441         /*@modifies hi @*/
02442 {
02443     if (hi != NULL) {
02444         hi->h = headerFree(hi->h);
02445         hi = _free(hi);
02446     }
02447     return hi;
02448 }
02449 
02455 static
02456 HeaderIterator headerInitIterator(Header h)
02457         /*@modifies h */
02458 {
02459     HeaderIterator hi = xmalloc(sizeof(*hi));
02460 
02461     headerSort(h);
02462 
02463     hi->h = headerLink(h);
02464     hi->next_index = 0;
02465     return hi;
02466 }
02467 
02477 static
02478 int headerNextIterator(HeaderIterator hi,
02479                 /*@null@*/ /*@out@*/ hTAG_t tag,
02480                 /*@null@*/ /*@out@*/ hTYP_t type,
02481                 /*@null@*/ /*@out@*/ hPTR_t * p,
02482                 /*@null@*/ /*@out@*/ hCNT_t c)
02483         /*@modifies hi, *tag, *type, *p, *c @*/
02484         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
02485                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
02486 {
02487     void * sw;
02488     Header h = hi->h;
02489     int slot = hi->next_index;
02490     indexEntry entry = NULL;
02491     int rc;
02492 
02493     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02494         entry = h->index + slot;
02495         if (!ENTRY_IS_REGION(entry))
02496             break;
02497     }
02498     hi->next_index = slot;
02499     if (entry == NULL || slot >= h->indexUsed)
02500         return 0;
02501 
02502     /*@-noeffect@*/     /* LCL: no clue */
02503     hi->next_index++;
02504     /*@=noeffect@*/
02505 
02506     if ((sw = headerGetStats(h, 19)) != NULL)   /* RPMTS_OP_HDRGET */
02507         (void) rpmswEnter(sw, 0);
02508 
02509     if (tag)
02510         *tag = entry->info.tag;
02511 
02512     rc = copyEntry(entry, (rpmTagType *)type, (rpmTagData *)p, (rpmTagCount *)c, 0);
02513 
02514     if (sw != NULL)     (void) rpmswExit(sw, 0);
02515 
02516     /* XXX 1 on success */
02517     return ((rc == 1) ? 1 : 0);
02518 }
02519 
02525 static /*@null@*/
02526 Header headerCopy(Header h)
02527         /*@modifies h @*/
02528 {
02529     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02530     Header nh = headerNew();
02531     HeaderIterator hi;
02532    
02533     for (hi = headerInitIterator(h);
02534         headerNextIterator(hi, &he->tag, (hTYP_t)&he->t, (hPTR_t *)&he->p, &he->c);
02535         he->p.ptr = headerFreeData(he->p.ptr, he->t))
02536     {
02537         if (he->p.ptr) (void) headerAddEntry(nh, he->tag, he->t, he->p.ptr, he->c);
02538     }
02539     hi = headerFreeIterator(hi);
02540 
02541     return headerReload(nh, HEADER_IMAGE);
02542 }
02543 
02546 typedef struct headerSprintfArgs_s {
02547     Header h;
02548     char * fmt;
02549 /*@temp@*/
02550     headerTagTableEntry tags;
02551 /*@temp@*/
02552     headerSprintfExtension exts;
02553 /*@observer@*/ /*@null@*/
02554     const char * errmsg;
02555     HE_t ec;                    
02556     int nec;                    
02557     sprintfToken format;
02558 /*@relnull@*/
02559     HeaderIterator hi;
02560 /*@owned@*/
02561     char * val;
02562     size_t vallen;
02563     size_t alloced;
02564     int numTokens;
02565     int i;
02566 } * headerSprintfArgs;
02567 
02573 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
02574         /*@modifies hsa */
02575 {
02576     sprintfTag tag =
02577         (hsa->format->type == PTOK_TAG
02578             ? &hsa->format->u.tag :
02579         (hsa->format->type == PTOK_ARRAY
02580             ? &hsa->format->u.array.format->u.tag :
02581         NULL));
02582 
02583     if (hsa != NULL) {
02584         hsa->i = 0;
02585         if (tag != NULL && tag->tagno == -2)
02586             hsa->hi = headerInitIterator(hsa->h);
02587     }
02588 /*@-nullret@*/
02589     return hsa;
02590 /*@=nullret@*/
02591 }
02592 
02598 /*@null@*/
02599 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
02600         /*@modifies hsa */
02601 {
02602     sprintfToken fmt = NULL;
02603     sprintfTag tag =
02604         (hsa->format->type == PTOK_TAG
02605             ? &hsa->format->u.tag :
02606         (hsa->format->type == PTOK_ARRAY
02607             ? &hsa->format->u.array.format->u.tag :
02608         NULL));
02609 
02610     if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02611         fmt = hsa->format + hsa->i;
02612         if (hsa->hi == NULL) {
02613             hsa->i++;
02614         } else {
02615             HE_t he = rpmheClean(&tag->he);
02616             if (!headerNextIterator(hsa->hi, &he->tag, (hTAG_t)&he->t, (hPTR_t *)&he->p.ptr, &he->c))
02617             {
02618                 tag->tagno = 0;
02619                 return NULL;
02620             }
02621             he = rpmheMark(he);
02622             he->avail = 1;
02623             tag->tagno = he->tag;
02624         }
02625     }
02626 
02627 /*@-dependenttrans -onlytrans@*/
02628     return fmt;
02629 /*@=dependenttrans =onlytrans@*/
02630 }
02631 
02637 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02638         /*@modifies hsa */
02639 {
02640     if (hsa != NULL) {
02641         hsa->hi = headerFreeIterator(hsa->hi);
02642         hsa->i = 0;
02643     }
02644 /*@-nullret@*/
02645     return hsa;
02646 /*@=nullret@*/
02647 }
02648 
02655 /*@dependent@*/ /*@exposed@*/
02656 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02657         /*@modifies hsa */
02658 {
02659     if ((hsa->vallen + need) >= hsa->alloced) {
02660         if (hsa->alloced <= need)
02661             hsa->alloced += need;
02662         hsa->alloced <<= 1;
02663         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02664     }
02665     return hsa->val + hsa->vallen;
02666 }
02667 
02676 /*@observer@*/ /*@null@*/
02677 static const char * myTagName(headerTagTableEntry tbl, int val,
02678                 /*@null@*/ int *typep)
02679         /*@modifies *typep @*/
02680 {
02681     static char name[128];
02682     const char * s;
02683     char *t;
02684 
02685     for (; tbl->name != NULL; tbl++) {
02686         if (tbl->val == val)
02687             break;
02688     }
02689     if ((s = tbl->name) == NULL)
02690         return NULL;
02691     s += sizeof("RPMTAG_") - 1;
02692     t = name;
02693     *t++ = *s++;
02694     while (*s != '\0')
02695         *t++ = xtolower(*s++);
02696     *t = '\0';
02697     if (typep)
02698         *typep = tbl->type;
02699     return name;
02700 }
02701 
02702 /*@observer@*/ /*@null@*/
02703 static int myTagType(headerTagTableEntry tbl, int val)
02704 {
02705     for (; tbl->name != NULL; tbl++) {
02706         if (tbl->val == val)
02707             break;
02708     }
02709     return (tbl->name != NULL ? tbl->type : 0);
02710 }
02711 
02719 static int myTagValue(headerTagTableEntry tbl, const char * name)
02720         /*@*/
02721 {
02722     for (; tbl->name != NULL; tbl++) {
02723         if (!xstrcasecmp(tbl->name, name))
02724             return tbl->val;
02725     }
02726     return 0;
02727 }
02728 
02736 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02737         /*@modifies token @*/
02738 {
02739     headerSprintfExtension exts = hsa->exts;
02740     headerSprintfExtension ext;
02741     sprintfTag stag = (token->type == PTOK_COND
02742         ? &token->u.cond.tag : &token->u.tag);
02743     int extNum;
02744 
02745     stag->fmtfuncs = NULL;
02746     stag->ext = NULL;
02747     stag->extNum = 0;
02748     stag->tagno = -1;
02749 
02750     if (!strcmp(name, "*")) {
02751         stag->tagno = -2;
02752         goto bingo;
02753     }
02754 
02755     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02756         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02757         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02758         name = t;
02759     }
02760 
02761     /* Search extensions for specific tag override. */
02762     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
02763         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1), extNum++)
02764     {
02765         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02766             continue;
02767         if (!xstrcasecmp(ext->name, name)) {
02768             stag->ext = ext->u.tagFunction;
02769             stag->extNum = extNum;
02770             goto bingo;
02771         }
02772     }
02773 
02774     /* Search tag names. */
02775     stag->tagno = myTagValue(hsa->tags, name);
02776     if (stag->tagno != 0)
02777         goto bingo;
02778 
02779     return 1;
02780 
02781 bingo:
02782     /* Search extensions for specific format. */
02783     if (stag->av != NULL) {
02784         int i;
02785         stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs));
02786         for (i = 0; stag->av[i] != NULL; i++) {
02787             for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02788                     ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02789             {
02790                 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02791                     continue;
02792                 if (strcmp(ext->name, stag->av[i]+1))
02793                     continue;
02794                 stag->fmtfuncs[i] = ext->u.fmtFunction;
02795                 break;
02796             }
02797         }
02798     }
02799     return 0;
02800 }
02801 
02809 char * intFormat(HE_t he, /*@null@*/ const char ** av, const char * fmt)
02810 {
02811     int ix = (he->ix > 0 ? he->ix : 0);
02812     int_64 ival = 0;
02813     const char * istr = NULL;
02814     char * b;
02815     size_t nb = 0;
02816 
02817     if (fmt == NULL || *fmt == '\0')
02818         fmt = "d";
02819 
02820     switch (he->t) {
02821     default:
02822         return xstrdup(_("(not a number)"));
02823         break;
02824     case RPM_CHAR_TYPE: 
02825     case RPM_INT8_TYPE:
02826         ival = he->p.i8p[ix];
02827         break;
02828     case RPM_INT16_TYPE:
02829         ival = he->p.ui16p[ix]; /* XXX note unsigned. */
02830         break;
02831     case RPM_INT32_TYPE:
02832         ival = he->p.i32p[ix];
02833         break;
02834     case RPM_INT64_TYPE:
02835         ival = he->p.i64p[ix];
02836         break;
02837     case RPM_STRING_TYPE:
02838         istr = he->p.str;
02839         break;
02840     case RPM_STRING_ARRAY_TYPE:
02841         istr = he->p.argv[ix];
02842         break;
02843     case RPM_OPENPGP_TYPE:      /* XXX W2DO? */
02844     case RPM_ASN1_TYPE:         /* XXX W2DO? */
02845     case RPM_BIN_TYPE:
02846         {   static char hex[] = "0123456789abcdef";
02847             const char * s = he->p.str;
02848             int c = he->c;
02849             char * t;
02850 
02851             nb = 2 * c + 1;
02852             t = b = alloca(nb+1);
02853             while (c-- > 0) {
02854                 unsigned int i;
02855                 i = *s++;
02856                 *t++ = hex[ (i >> 4) & 0xf ];
02857                 *t++ = hex[ (i     ) & 0xf ];
02858             }
02859             *t = '\0';
02860         }   break;
02861     }
02862 
02863     if (istr) {         /* string */
02864         b = (char *)istr;       /* NOCAST */
02865     } else
02866     if (nb == 0) {      /* number */
02867         char myfmt[] = "%llX";
02868         myfmt[3] = *fmt;
02869         nb = 64;
02870         b = alloca(nb);
02871         snprintf(b, nb, myfmt, ival);
02872         b[nb-1] = '\0';
02873     }
02874 
02875     return xstrdup(b);
02876 }
02877 
02884 static char * octFormat(HE_t he, /*@null@*/ const char ** av)
02885         /*@*/
02886 {
02887     return intFormat(he, NULL, "o");
02888 }
02889 
02896 static char * hexFormat(HE_t he, /*@null@*/ const char ** av)
02897         /*@*/
02898 {
02899     return intFormat(he, NULL, "x");
02900 }
02901 
02908 static char * decFormat(HE_t he, /*@null@*/ const char ** av)
02909         /*@*/
02910 {
02911     return intFormat(he, NULL, "d");
02912 }
02913 
02921 static char * realDateFormat(HE_t he, /*@null@*/ const char ** av, const char * strftimeFormat)
02922         /*@*/
02923 {
02924     rpmTagData data = { .ptr = he->p.ptr };
02925     char * val;
02926 
02927     if (he->t != RPM_INT64_TYPE) {
02928         val = xstrdup(_("(not a number)"));
02929     } else {
02930         struct tm * tstruct;
02931         char buf[50];
02932 
02933         /* this is important if sizeof(int_64) ! sizeof(time_t) */
02934         {   time_t dateint = data.ui64p[0];
02935             tstruct = localtime(&dateint);
02936         }
02937         buf[0] = '\0';
02938         if (tstruct)
02939             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
02940         buf[sizeof(buf) - 1] = '\0';
02941         val = xstrdup(buf);
02942     }
02943 
02944     return val;
02945 }
02946 
02953 static char * dateFormat(HE_t he, /*@null@*/ const char ** av)
02954         /*@*/
02955 {
02956     return realDateFormat(he, NULL, _("%c"));
02957 }
02958 
02965 static char * dayFormat(HE_t he, /*@null@*/ const char ** av)
02966         /*@*/
02967 {
02968     return realDateFormat(he, NULL, _("%a %b %d %Y"));
02969 }
02970 
02977 static char * shescapeFormat(HE_t he, /*@null@*/ const char ** av)
02978         /*@*/
02979 {
02980     rpmTagData data = { .ptr = he->p.ptr };
02981     char * val;
02982     size_t nb;
02983 
02984     /* XXX one of these integer types is unnecessary. */
02985     if (he->t == RPM_INT32_TYPE) {
02986         nb = 20;
02987         val = xmalloc(nb);
02988         snprintf(val, nb, "%d", data.i32p[0]);
02989         val[nb-1] = '\0';
02990     } else if (he->t == RPM_INT64_TYPE) {
02991         nb = 40;
02992         val = xmalloc(40);
02993         snprintf(val, nb, "%lld", data.i64p[0]);
02994         val[nb-1] = '\0';
02995     } else if (he->t == RPM_STRING_TYPE) {
02996         const char * s = data.str;
02997         char * t;
02998         int c;
02999 
03000         nb = strlen(data.str) + 1;
03001         /* XXX count no. of escapes instead. */
03002         t = xmalloc(4 * nb + 3);
03003         *t++ = '\'';
03004         while ((c = *s++) != 0) {
03005             if (c == '\'') {
03006                 *t++ = '\'';
03007                 *t++ = '\\';
03008                 *t++ = '\'';
03009             }
03010             *t++ = c;
03011         }
03012         *t++ = '\'';
03013         *t = '\0';
03014         nb = strlen(t) + 1;
03015         val = xrealloc(t, nb);
03016     } else
03017         val = xstrdup(_("invalid type"));
03018 
03019     return val;
03020 }
03021 
03022 /*@-type@*/ /* FIX: cast? */
03023 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03024     { HEADER_EXT_FORMAT, "octal",
03025         { .fmtFunction = octFormat } },
03026     { HEADER_EXT_FORMAT, "oct",
03027         { .fmtFunction = octFormat } },
03028     { HEADER_EXT_FORMAT, "hex",
03029         { .fmtFunction = hexFormat } },
03030     { HEADER_EXT_FORMAT, "decimal",
03031         { .fmtFunction = decFormat } },
03032     { HEADER_EXT_FORMAT, "dec",
03033         { .fmtFunction = decFormat } },
03034     { HEADER_EXT_FORMAT, "date",
03035         { .fmtFunction = dateFormat } },
03036     { HEADER_EXT_FORMAT, "day",
03037         { .fmtFunction = dayFormat } },
03038     { HEADER_EXT_FORMAT, "shescape",
03039         { .fmtFunction = shescapeFormat } },
03040     { HEADER_EXT_LAST, NULL, { NULL } }
03041 };
03042 /*@=type@*/
03043 
03044 /* forward ref */
03053 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
03054                 char * str, /*@out@*/char ** endPtr)
03055         /*@modifies hsa, str, token, *endPtr @*/
03056         /*@requires maxSet(endPtr) >= 0 @*/;
03057 
03068 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
03069                 /*@out@*/ sprintfToken * formatPtr,
03070                 /*@out@*/ int * numTokensPtr,
03071                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
03072         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
03073         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
03074                 /\ maxSet(endPtr) >= 0 @*/
03075 {
03076 /*@observer@*/
03077 static const char *pstates[] = {
03078 "NORMAL", "ARRAY", "EXPR", "WTF?"
03079 };
03080     char * chptr, * start, * next, * dst;
03081     sprintfToken format;
03082     sprintfToken token;
03083     unsigned numTokens;
03084     unsigned i;
03085     int done = 0;
03086     int xx;
03087 
03088 /*@-modfilesys@*/
03089 if (_hdr_debug)
03090 fprintf(stderr, "-->     parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]);
03091 /*@=modfilesys@*/
03092 
03093     /* upper limit on number of individual formats */
03094     numTokens = 0;
03095     if (str != NULL)
03096     for (chptr = str; *chptr != '\0'; chptr++)
03097         if (*chptr == '%') numTokens++;
03098     numTokens = numTokens * 2 + 1;
03099 
03100     format = xcalloc(numTokens, sizeof(*format));
03101     if (endPtr) *endPtr = NULL;
03102 
03103 /*@-infloops@*/ /* LCL: can't detect done termination */
03104     dst = start = str;
03105     numTokens = 0;
03106     token = NULL;
03107     if (start != NULL)
03108     while (*start != '\0') {
03109         switch (*start) {
03110         case '%':
03111             /* handle %% */
03112             if (*(start + 1) == '%') {
03113                 if (token == NULL || token->type != PTOK_STRING) {
03114                     token = format + numTokens++;
03115                     token->type = PTOK_STRING;
03116                     /*@-temptrans -assignexpose@*/
03117                     dst = token->u.string.string = start;
03118                     /*@=temptrans =assignexpose@*/
03119                 }
03120                 start++;
03121                 *dst++ = *start++;
03122                 /*@switchbreak@*/ break;
03123             } 
03124 
03125             token = format + numTokens++;
03126             *dst++ = '\0';
03127             start++;
03128 
03129             if (*start == '|') {
03130                 char * newEnd;
03131 
03132                 start++;
03133                 if (parseExpression(hsa, token, start, &newEnd))
03134                 {
03135                     format = freeFormat(format, numTokens);
03136                     return 1;
03137                 }
03138                 start = newEnd;
03139                 /*@switchbreak@*/ break;
03140             }
03141 
03142             /*@-assignexpose@*/
03143             token->u.tag.format = start;
03144             /*@=assignexpose@*/
03145             token->u.tag.pad = 0;
03146             token->u.tag.justOne = 0;
03147             token->u.tag.arrayCount = 0;
03148 
03149             chptr = start;
03150             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
03151             if (!*chptr || *chptr == '%') {
03152                 hsa->errmsg = _("missing { after %");
03153                 format = freeFormat(format, numTokens);
03154                 return 1;
03155             }
03156 
03157 /*@-modfilesys@*/
03158 if (_hdr_debug)
03159 fprintf(stderr, "\tchptr *%p = NUL\n", chptr);
03160 /*@=modfilesys@*/
03161             *chptr++ = '\0';
03162 
03163             while (start < chptr) {
03164                 if (xisdigit((int)*start)) {
03165                     i = strtoul(start, &start, 10);
03166                     token->u.tag.pad += i;
03167                     start = chptr;
03168                     /*@innerbreak@*/ break;
03169                 } else {
03170                     start++;
03171                 }
03172             }
03173 
03174             if (*start == '=') {
03175                 token->u.tag.justOne = 1;
03176                 start++;
03177             } else if (*start == '#') {
03178                 token->u.tag.justOne = 1;
03179                 token->u.tag.arrayCount = 1;
03180                 start++;
03181             }
03182 
03183             next = start;
03184             while (*next && *next != '}') next++;
03185             if (!*next) {
03186                 hsa->errmsg = _("missing } after %{");
03187                 format = freeFormat(format, numTokens);
03188                 return 1;
03189             }
03190 /*@-modfilesys@*/
03191 if (_hdr_debug)
03192 fprintf(stderr, "\tnext *%p = NUL\n", next);
03193 /*@=modfilesys@*/
03194             *next++ = '\0';
03195 
03196 #define isSEP(_c)       ((_c) == ':' || (_c) == '|')
03197             chptr = start;
03198             while (!(*chptr == '\0' || isSEP(*chptr))) chptr++;
03199             /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */
03200             while (isSEP(*chptr)) {
03201                 if (chptr[1] == '\0' || isSEP(chptr[1])) {
03202                     hsa->errmsg = _("empty tag format");
03203                     format = freeFormat(format, numTokens);
03204                     return 1;
03205                 }
03206                 /* Parse the formatter parameter list. */
03207                 {   char * te = chptr + 1;
03208                     char * t = strchr(te, '(');
03209                     char c;
03210 
03211                     while (!(*te == '\0' || isSEP(*te))) {
03212 #ifdef  NOTYET  /* XXX some means of escaping is needed */
03213                         if (te[0] == '\\' && te[1] != '\0') te++;
03214 #endif
03215                         te++;
03216                     }
03217                     c = *te; *te = '\0';
03218                     /* Parse (a,b,c) parameter list. */
03219                     if (t != NULL) {
03220                         *t++ = '\0';
03221                         if (te <= t || te[-1] != ')') {
03222                             hsa->errmsg = _("malformed parameter list");
03223                             format = freeFormat(format, numTokens);
03224                             return 1;
03225                         }
03226                         te[-1] = '\0';
03227                         xx = argvAdd(&token->u.tag.params, t);
03228                     } else
03229                         xx = argvAdd(&token->u.tag.params, "");
03230 /*@-modfilesys@*/
03231 if (_hdr_debug)
03232 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : ""));
03233 /*@=modfilesys@*/
03234                     xx = argvAdd(&token->u.tag.av, chptr);
03235                     *te = c;
03236                     *chptr = '\0';
03237                     chptr = te;
03238                 }
03239             }
03240 #undef  isSEP
03241             
03242             if (*start == '\0') {
03243                 hsa->errmsg = _("empty tag name");
03244                 format = freeFormat(format, numTokens);
03245                 return 1;
03246             }
03247 
03248             i = 0;
03249             token->type = PTOK_TAG;
03250 
03251             if (findTag(hsa, token, start)) {
03252                 hsa->errmsg = _("unknown tag");
03253                 format = freeFormat(format, numTokens);
03254                 return 1;
03255             }
03256 
03257             dst = start = next;
03258 /*@-modfilesys@*/
03259 if (_hdr_debug)
03260 fprintf(stderr, "\tdst = start = next %p\n", dst);
03261 /*@=modfilesys@*/
03262             /*@switchbreak@*/ break;
03263 
03264         case '[':
03265 /*@-modfilesys@*/
03266 if (_hdr_debug)
03267 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start);
03268 /*@=modfilesys@*/
03269             *start++ = '\0';
03270             token = format + numTokens++;
03271 
03272             if (parseFormat(hsa, start,
03273                             &token->u.array.format,
03274                             &token->u.array.numTokens,
03275                             &start, PARSER_IN_ARRAY))
03276             {
03277                 format = freeFormat(format, numTokens);
03278                 return 1;
03279             }
03280 
03281             if (!start) {
03282                 hsa->errmsg = _("] expected at end of array");
03283                 format = freeFormat(format, numTokens);
03284                 return 1;
03285             }
03286 
03287             dst = start;
03288 /*@-modfilesys@*/
03289 if (_hdr_debug)
03290 fprintf(stderr, "\tdst = start %p\n", dst);
03291 /*@=modfilesys@*/
03292 
03293             token->type = PTOK_ARRAY;
03294 
03295             /*@switchbreak@*/ break;
03296 
03297         case ']':
03298             if (state != PARSER_IN_ARRAY) {
03299                 hsa->errmsg = _("unexpected ]");
03300                 format = freeFormat(format, numTokens);
03301                 return 1;
03302             }
03303             *start++ = '\0';
03304 /*@-modfilesys@*/
03305 if (_hdr_debug)
03306 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
03307 /*@=modfilesys@*/
03308             if (endPtr) *endPtr = start;
03309             done = 1;
03310             /*@switchbreak@*/ break;
03311 
03312         case '}':
03313             if (state != PARSER_IN_EXPR) {
03314                 hsa->errmsg = _("unexpected }");
03315                 format = freeFormat(format, numTokens);
03316                 return 1;
03317             }
03318             *start++ = '\0';
03319 /*@-modfilesys@*/
03320 if (_hdr_debug)
03321 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
03322 /*@=modfilesys@*/
03323             if (endPtr) *endPtr = start;
03324             done = 1;
03325             /*@switchbreak@*/ break;
03326 
03327         default:
03328             if (token == NULL || token->type != PTOK_STRING) {
03329                 token = format + numTokens++;
03330                 token->type = PTOK_STRING;
03331                 /*@-temptrans -assignexpose@*/
03332                 dst = token->u.string.string = start;
03333                 /*@=temptrans =assignexpose@*/
03334             }
03335 
03336 /*@-modfilesys@*/
03337 if (_hdr_debug)
03338 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start);
03339 /*@=modfilesys@*/
03340             if (start[0] == '\\' && start[1] != '\0') {
03341                 start++;
03342                 *dst++ = escapedChar(*start);
03343                 *start++ = '\0';
03344             } else {
03345                 *dst++ = *start++;
03346             }
03347             if (dst < start) *dst = '\0';
03348             /*@switchbreak@*/ break;
03349         }
03350         if (done)
03351             break;
03352     }
03353 /*@=infloops@*/
03354 
03355     if (dst != NULL)
03356         *dst = '\0';
03357 
03358     for (i = 0; i < (unsigned) numTokens; i++) {
03359         token = format + i;
03360         switch(token->type) {
03361         default:
03362             /*@switchbreak@*/ break;
03363         case PTOK_STRING:
03364             token->u.string.len = strlen(token->u.string.string);
03365             /*@switchbreak@*/ break;
03366         }
03367     }
03368 
03369     if (numTokensPtr != NULL)
03370         *numTokensPtr = numTokens;
03371     if (formatPtr != NULL)
03372         *formatPtr = format;
03373 
03374     return 0;
03375 }
03376 
03377 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
03378                 char * str, /*@out@*/ char ** endPtr)
03379 {
03380     char * chptr;
03381     char * end;
03382 
03383 /*@-modfilesys@*/
03384 if (_hdr_debug)
03385 fprintf(stderr, "-->   parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr);
03386 /*@=modfilesys@*/
03387 
03388     hsa->errmsg = NULL;
03389     chptr = str;
03390     while (*chptr && *chptr != '?') chptr++;
03391 
03392     if (*chptr != '?') {
03393         hsa->errmsg = _("? expected in expression");
03394         return 1;
03395     }
03396 
03397     *chptr++ = '\0';
03398 
03399     if (*chptr != '{') {
03400         hsa->errmsg = _("{ expected after ? in expression");
03401         return 1;
03402     }
03403 
03404     chptr++;
03405 
03406     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
03407                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
03408         return 1;
03409 
03410     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
03411     if (!(end && *end)) {
03412         hsa->errmsg = _("} expected in expression");
03413         token->u.cond.ifFormat =
03414                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03415         return 1;
03416     }
03417 
03418     chptr = end;
03419     if (*chptr != ':' && *chptr != '|') {
03420         hsa->errmsg = _(": expected following ? subexpression");
03421         token->u.cond.ifFormat =
03422                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03423         return 1;
03424     }
03425 
03426     if (*chptr == '|') {
03427         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
03428                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
03429         {
03430             token->u.cond.ifFormat =
03431                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03432             return 1;
03433         }
03434     } else {
03435         chptr++;
03436 
03437         if (*chptr != '{') {
03438             hsa->errmsg = _("{ expected after : in expression");
03439             token->u.cond.ifFormat =
03440                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03441             return 1;
03442         }
03443 
03444         chptr++;
03445 
03446         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
03447                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
03448             return 1;
03449 
03450         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
03451         if (!(end && *end)) {
03452             hsa->errmsg = _("} expected in expression");
03453             token->u.cond.ifFormat =
03454                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03455             return 1;
03456         }
03457 
03458         chptr = end;
03459         if (*chptr != '|') {
03460             hsa->errmsg = _("| expected at end of expression");
03461             token->u.cond.ifFormat =
03462                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
03463             token->u.cond.elseFormat =
03464                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
03465             return 1;
03466         }
03467     }
03468         
03469     chptr++;
03470 
03471     *endPtr = chptr;
03472 
03473     token->type = PTOK_COND;
03474 
03475     (void) findTag(hsa, token, str);
03476 
03477     return 0;
03478 }
03479 
03488 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03489                 HE_t he, HE_t ec)
03490         /*@modifies he, ec @*/
03491 {
03492     int rc = 0;
03493     if (!ec->avail) {
03494         he = rpmheClean(he);
03495         rc = fn(hsa->h, he);
03496         *ec = *he;      /* structure copy. */
03497         if (!rc)
03498             ec->avail = 1;
03499     } else
03500         *he = *ec;      /* structure copy. */
03501     he->freeData = 0;
03502     return rc;
03503 }
03504 
03512 /*@observer@*/ /*@null@*/
03513 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03514         /*@modifies hsa @*/
03515 {
03516     HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
03517     HE_t he = &tag->he;
03518     char * val = NULL;
03519     size_t need = 0;
03520     char * t, * te;
03521     int_64 ival = 0;
03522     rpmTagCount countBuf;
03523     int xx;
03524 
03525     if (!he->avail) {
03526         if (tag->ext) {
03527             xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
03528         } else {
03529             he->tag = tag->tagno;
03530 #ifdef  NOTYET
03531             if (_usehge) {
03532                 xx = headerGetExtension(hsa->h, he->tag, &he->t, &he->p, &he->c);
03533                 if (xx)         /* XXX 1 on success */
03534                     he->freeData = 1;
03535             } else
03536 #endif
03537             {
03538                 xx = headerGetEntry(hsa->h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
03539                 if (xx)         /* XXX 1 on success */
03540                     he = rpmheMark(he);
03541             }
03542             xx = (xx == 0);     /* XXX invert headerGetEntry return. */
03543         }
03544         if (xx) {
03545             (void) rpmheClean(he);
03546             he->t = RPM_STRING_TYPE;    
03547             he->p.str = "(none)";
03548             he->c = 1;
03549         }
03550         he->avail = 1;
03551     }
03552 
03553     if (tag->arrayCount) {
03554         countBuf = he->c;
03555         he = rpmheClean(he);
03556         he->t = RPM_INT32_TYPE;
03557         he->p.i32p = &countBuf;
03558         he->c = 1;
03559         he->freeData = 0;
03560     }
03561 
03562     if (he->p.ptr)
03563     switch (he->t) {
03564     default:
03565         val = xstrdup("(unknown type)");
03566         need = strlen(val) + 1;
03567         goto exit;
03568         /*@notreached@*/ break;
03569     case RPM_I18NSTRING_TYPE:
03570     case RPM_STRING_ARRAY_TYPE:
03571         vhe->t = RPM_STRING_TYPE;
03572         vhe->p.str = he->p.argv[element];
03573         vhe->c = he->c;
03574         vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1);
03575         break;
03576     case RPM_STRING_TYPE:
03577         vhe->p.str = he->p.str;
03578         vhe->t = RPM_STRING_TYPE;
03579         vhe->c = 0;
03580         vhe->ix = -1;
03581         break;
03582     case RPM_CHAR_TYPE:
03583     case RPM_INT8_TYPE:
03584     case RPM_INT16_TYPE:
03585     case RPM_INT32_TYPE:
03586     case RPM_INT64_TYPE:
03587         switch (he->t) {
03588         default:
03589 assert(0);      /* XXX keep gcc quiet. */
03590             break;
03591         case RPM_CHAR_TYPE:     
03592         case RPM_INT8_TYPE:
03593             ival = he->p.i8p[element];
03594             break;
03595         case RPM_INT16_TYPE:
03596             ival = he->p.ui16p[element];        /* XXX note unsigned. */
03597             break;
03598         case RPM_INT32_TYPE:
03599             ival = he->p.i32p[element];
03600             break;
03601         case RPM_INT64_TYPE:
03602             ival = he->p.i64p[element];
03603             break;
03604         }
03605         vhe->t = RPM_INT64_TYPE;
03606         vhe->p.i64p = &ival;
03607         vhe->c = he->c;
03608         vhe->ix = (he->c > 1 ? 0 : -1);
03609         if ((myTagType(hsa->tags, he->tag) & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03610             vhe->ix = 0;
03611         break;
03612 
03613     case RPM_OPENPGP_TYPE:      /* XXX W2DO? */
03614     case RPM_ASN1_TYPE:         /* XXX W2DO? */
03615     case RPM_BIN_TYPE:
03616         vhe->t = RPM_BIN_TYPE;
03617         vhe->p.ptr = he->p.ptr;
03618         vhe->c = he->c;
03619         vhe->ix = -1;
03620         break;
03621     }
03622 
03623 /*@-compmempass@*/      /* vhe->p.ui64p is stack, not owned */
03624     if (tag->fmtfuncs) {
03625         char * nval;
03626         int i;
03627         for (i = 0; tag->av[i] != NULL; i++) {
03628             headerTagFormatFunction fmt;
03629             ARGV_t av;
03630             if ((fmt = tag->fmtfuncs[i]) == NULL)
03631                 continue;
03632             /* If !1st formatter, and transformer, not extractor, save val. */
03633             if (val != NULL && *tag->av[i] == '|') {
03634                 int ix = vhe->ix;
03635                 vhe = rpmheClean(vhe);
03636                 vhe->tag = he->tag;
03637                 vhe->t = RPM_STRING_TYPE;
03638                 vhe->p.str = xstrdup(val);
03639                 vhe->c = he->c;
03640                 vhe->ix = ix;
03641                 vhe->freeData = 1;
03642             }
03643             av = NULL;
03644             if (tag->params && tag->params[i] && *tag->params[i] != '\0')
03645                 xx = argvSplit(&av, tag->params[i], ",");
03646 
03647             nval = fmt(vhe, av);
03648 
03649 /*@-modfilesys@*/
03650 if (_hdr_debug)
03651 fprintf(stderr, "\t%s(%s) %p(%p,%p) ret \"%s\"\n", tag->av[i], tag->params[i], fmt, vhe, (av ? av : NULL), val);
03652 /*@=modfilesys@*/
03653 
03654             /* Accumulate (by appending) next formmatter's return string. */
03655             if (val == NULL)
03656                 val = xstrdup((nval ? nval : ""));
03657             else {
03658                 char * oval = val;
03659                 /* XXX using ... | ... as separator is feeble. */
03660                 val = rpmExpand(val, (*val ? " | " : ""), nval, NULL);
03661                 oval = _free(oval);
03662             }
03663             nval = _free(nval);
03664             av = argvFree(av);
03665         }
03666     }
03667     if (val == NULL)
03668         val = intFormat(vhe, NULL, NULL);
03669 /*@=compmempass@*/
03670 assert(val != NULL);
03671     if (val)
03672         need = strlen(val) + 1;
03673 
03674 exit:
03675     if (!_tagcache)
03676         he = rpmheClean(he);
03677 
03678     if (val && need > 0) {
03679         if (tag->format && *tag->format && tag->pad) {
03680             size_t nb;
03681             nb = strlen(tag->format) + sizeof("%s");
03682             t = alloca(nb);
03683             (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s");
03684             nb = tag->pad + strlen(val) + 1;
03685             te = xmalloc(nb);
03686             (void) snprintf(te, nb, t, val);
03687             te[nb-1] = '\0';
03688             val = _free(val);
03689             val = te;
03690             need += tag->pad;
03691         }
03692         t = hsaReserve(hsa, need);
03693         te = stpcpy(t, val);
03694         hsa->vallen += (te - t);
03695         val = _free(val);
03696     }
03697 
03698     return (hsa->val + hsa->vallen);
03699 }
03700 
03708 /*@observer@*/
03709 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03710                 int element)
03711         /*@modifies hsa @*/
03712 {
03713     char numbuf[64];    /* XXX big enuf for "Tag_0x01234567" */
03714     char * t, * te;
03715     int i, j;
03716     int numElements;
03717     sprintfToken spft;
03718     sprintfTag tag = NULL;
03719     HE_t he = NULL;
03720     int condNumFormats;
03721     size_t need;
03722     int xx;
03723 
03724     /* we assume the token and header have been validated already! */
03725 
03726     switch (token->type) {
03727     case PTOK_NONE:
03728         break;
03729 
03730     case PTOK_STRING:
03731         need = token->u.string.len;
03732         if (need == 0) break;
03733         t = hsaReserve(hsa, need);
03734         te = stpcpy(t, token->u.string.string);
03735         hsa->vallen += (te - t);
03736         break;
03737 
03738     case PTOK_TAG:
03739         t = hsa->val + hsa->vallen;
03740         te = formatValue(hsa, &token->u.tag,
03741                         (token->u.tag.justOne ? 0 : element));
03742         if (te == NULL)
03743             return NULL;
03744         break;
03745 
03746     case PTOK_COND:
03747         if (token->u.cond.tag.ext
03748          || headerIsEntry(hsa->h, token->u.cond.tag.tagno))
03749         {
03750             spft = token->u.cond.ifFormat;
03751             condNumFormats = token->u.cond.numIfTokens;
03752         } else {
03753             spft = token->u.cond.elseFormat;
03754             condNumFormats = token->u.cond.numElseTokens;
03755         }
03756 
03757         need = condNumFormats * 20;
03758         if (spft == NULL || need == 0) break;
03759 
03760         t = hsaReserve(hsa, need);
03761         for (i = 0; i < condNumFormats; i++, spft++) {
03762             te = singleSprintf(hsa, spft, element);
03763             if (te == NULL)
03764                 return NULL;
03765         }
03766         break;
03767 
03768     case PTOK_ARRAY:
03769         numElements = -1;
03770         spft = token->u.array.format;
03771         for (i = 0; i < token->u.array.numTokens; i++, spft++)
03772         {
03773             tag = &spft->u.tag;
03774             if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne)
03775                 continue;
03776             he = &tag->he;
03777             if (!he->avail) {
03778                 he->tag = tag->tagno;
03779                 if (tag->ext)
03780                     xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
03781                 else {
03782 #ifdef  NOTYET
03783                     if (_usehge) {
03784                         xx = headerGetExtension(hsa->h, he->tag, &he->t, &he->p, &he->c);
03785                         if (xx)
03786                             he->freeData = 1;
03787                     } else
03788 #endif
03789                     {
03790                         xx = headerGetEntry(hsa->h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
03791                         if (xx) /* XXX 1 on success */
03792                             rpmheMark(he);
03793                     }
03794                     xx = (xx == 0);     /* XXX invert headerGetEntry return. */
03795                 }
03796                 if (xx) {
03797                     (void) rpmheClean(he);
03798                     continue;
03799                 }
03800                 he->avail = 1;
03801             }
03802 
03803             /* Check iteration arrays are same dimension (or scalar). */
03804             switch (he->t) {
03805             default:
03806                 if (numElements == -1) {
03807                     numElements = he->c;
03808                     /*@switchbreak@*/ break;
03809                 }
03810                 if (he->c == numElements)
03811                     /*@switchbreak@*/ break;
03812                 hsa->errmsg =
03813                         _("array iterator used with different sized arrays");
03814                 he = rpmheClean(he);
03815                 return NULL;
03816                 /*@notreached@*/ /*@switchbreak@*/ break;
03817             case RPM_OPENPGP_TYPE:
03818             case RPM_ASN1_TYPE:
03819             case RPM_BIN_TYPE:
03820             case RPM_STRING_TYPE:
03821                 if (numElements == -1)
03822                     numElements = 1;
03823                 /*@switchbreak@*/ break;
03824             }
03825             if (!_tagcache)
03826                 he = rpmheClean(he);
03827         }
03828         spft = token->u.array.format;
03829 
03830         if (numElements == -1) {
03831 #ifdef  DYING   /* XXX lots of pugly "(none)" lines with --conflicts. */
03832             need = sizeof("(none)\n") - 1;
03833             t = hsaReserve(hsa, need);
03834             te = stpcpy(t, "(none)\n");
03835             hsa->vallen += (te - t);
03836 #endif
03837         } else {
03838             int isxml;
03839             int isyaml;
03840 
03841             need = numElements * token->u.array.numTokens;
03842             if (need == 0) break;
03843 
03844             tag = &spft->u.tag;
03845 
03846             /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
03847             isxml = (spft->type == PTOK_TAG && tag->av != NULL &&
03848                 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"));
03849             isyaml = (spft->type == PTOK_TAG && tag->av != NULL &&
03850                 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"));
03851 
03852             if (isxml) {
03853                 const char * tagN = myTagName(hsa->tags, tag->tagno, NULL);
03854                 /* XXX display "Tag_0x01234567" for unknown tags. */
03855                 if (tagN == NULL) {
03856                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03857                                 tag->tagno);
03858                     numbuf[sizeof(numbuf)-1] = '\0';
03859                     tagN = numbuf;
03860                 }
03861                 need = sizeof("  <rpmTag name=\"\">\n") + strlen(tagN);
03862                 te = t = hsaReserve(hsa, need);
03863                 te = stpcpy( stpcpy( stpcpy(te, "  <rpmTag name=\""), tagN), "\">\n");
03864                 hsa->vallen += (te - t);
03865             }
03866             if (isyaml) {
03867                 int tagT = -1;
03868                 const char * tagN = myTagName(hsa->tags, tag->tagno, &tagT);
03869                 /* XXX display "Tag_0x01234567" for unknown tags. */
03870                 if (tagN == NULL) {
03871                     (void) snprintf(numbuf, sizeof(numbuf), "Tag_0x%08x",
03872                                 tag->tagno);
03873                     numbuf[sizeof(numbuf)-1] = '\0';
03874                     tagN = numbuf;
03875                     tagT = numElements > 1
03876                         ?  RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
03877                 }
03878                 need = sizeof("  :     - ") + strlen(tagN);
03879                 te = t = hsaReserve(hsa, need);
03880                 *te++ = ' ';
03881                 *te++ = ' ';
03882                 te = stpcpy(te, tagN);
03883                 *te++ = ':';
03884                 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
03885                         ? '\n' : ' ');
03886                 *te = '\0';
03887                 hsa->vallen += (te - t);
03888             }
03889 
03890             need = numElements * token->u.array.numTokens * 10;
03891             t = hsaReserve(hsa, need);
03892             for (j = 0; j < numElements; j++) {
03893                 spft = token->u.array.format;
03894                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03895                     te = singleSprintf(hsa, spft, j);
03896                     if (te == NULL)
03897                         return NULL;
03898                 }
03899             }
03900 
03901             if (isxml) {
03902                 need = sizeof("  </rpmTag>\n") - 1;
03903                 te = t = hsaReserve(hsa, need);
03904                 te = stpcpy(te, "  </rpmTag>\n");
03905                 hsa->vallen += (te - t);
03906             }
03907             if (isyaml) {
03908 #if 0
03909                 need = sizeof("\n") - 1;
03910                 te = t = hsaReserve(hsa, need);
03911                 te = stpcpy(te, "\n");
03912                 hsa->vallen += (te - t);
03913 #endif
03914             }
03915 
03916         }
03917         break;
03918     }
03919 
03920     return (hsa->val + hsa->vallen);
03921 }
03922 
03929 static /*@only@*/ HE_t
03930 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp)
03931         /*@*/
03932 {
03933     headerSprintfExtension ext;
03934     HE_t ec;
03935     int extNum = 0;
03936 
03937     if (exts != NULL)
03938     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
03939         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1), extNum++)
03940     {
03941         ;
03942     }
03943     if (necp)
03944         *necp = extNum;
03945     ec = xcalloc(extNum+1, sizeof(*ec));        /* XXX +1 unnecessary */
03946     return ec;
03947 }
03948 
03955 static /*@null@*/ HE_t
03956 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec)
03957         /*@modifies ec @*/
03958 {
03959     headerSprintfExtension ext;
03960     int extNum;
03961 
03962     for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
03963         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1), extNum++)
03964     {
03965         (void) rpmheClean(&ec[extNum]);
03966     }
03967 
03968     ec = _free(ec);
03969     return NULL;
03970 }
03971 
03972 extern const struct headerTagTableEntry_s * rpmTagTable;
03973 
03985 static /*@only@*/ /*@null@*/
03986 char * headerSprintf(Header h, const char * fmt,
03987                      const struct headerTagTableEntry_s * tags,
03988                      const struct headerSprintfExtension_s * exts,
03989                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03990         /*@modifies h, *errmsg @*/
03991         /*@requires maxSet(errmsg) >= 0 @*/
03992 {
03993     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03994     sprintfToken nextfmt;
03995     sprintfTag tag;
03996     char * t, * te;
03997     int isxml;
03998     int isyaml;
03999     int need;
04000  
04001 /*@-modfilesys@*/
04002 if (_hdr_debug)
04003 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg);
04004 /*@=modfilesys@*/
04005 
04006     /* Set some reasonable defaults */
04007     if (tags == NULL)
04008         tags = rpmTagTable;
04009 
04010     hsa->h = headerLink(h);
04011     hsa->fmt = xstrdup(fmt);
04012 /*@-castexpose@*/       /* FIX: legacy API shouldn't change. */
04013     hsa->exts = (headerSprintfExtension) exts;
04014     hsa->tags = (headerTagTableEntry) tags;
04015 /*@=castexpose@*/
04016     hsa->errmsg = NULL;
04017 
04018     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
04019         goto exit;
04020 
04021     hsa->nec = 0;
04022     hsa->ec = rpmecNew(hsa->exts, &hsa->nec);
04023     hsa->val = xstrdup("");
04024 
04025     tag =
04026         (hsa->format->type == PTOK_TAG
04027             ? &hsa->format->u.tag :
04028         (hsa->format->type == PTOK_ARRAY
04029             ? &hsa->format->u.array.format->u.tag :
04030         NULL));
04031     /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
04032     isxml = (tag != NULL && tag->tagno == -2 && tag->av != NULL
04033                 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"));
04034     isyaml = (tag != NULL && tag->tagno == -2 && tag->av != NULL
04035                 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"));
04036 
04037     if (isxml) {
04038         need = sizeof("<rpmHeader>\n") - 1;
04039         t = hsaReserve(hsa, need);
04040         te = stpcpy(t, "<rpmHeader>\n");
04041         hsa->vallen += (te - t);
04042     }
04043     if (isyaml) {
04044         need = sizeof("- !!omap\n") - 1;
04045         t = hsaReserve(hsa, need);
04046         te = stpcpy(t, "- !!omap\n");
04047         hsa->vallen += (te - t);
04048     }
04049 
04050     hsa = hsaInit(hsa);
04051     while ((nextfmt = hsaNext(hsa)) != NULL) {
04052         te = singleSprintf(hsa, nextfmt, 0);
04053         if (te == NULL) {
04054             hsa->val = _free(hsa->val);
04055             break;
04056         }
04057     }
04058     hsa = hsaFini(hsa);
04059 
04060     if (isxml) {
04061         need = sizeof("</rpmHeader>\n") - 1;
04062         t = hsaReserve(hsa, need);
04063         te = stpcpy(t, "</rpmHeader>\n");
04064         hsa->vallen += (te - t);
04065     }
04066     if (isyaml) {
04067         need = sizeof("\n") - 1;
04068         t = hsaReserve(hsa, need);
04069         te = stpcpy(t, "\n");
04070         hsa->vallen += (te - t);
04071     }
04072 
04073     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
04074         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
04075 
04076     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
04077     hsa->nec = 0;
04078     hsa->format = freeFormat(hsa->format, hsa->numTokens);
04079 
04080 exit:
04081 /*@-dependenttrans -observertrans @*/
04082     if (errmsg)
04083         *errmsg = hsa->errmsg;
04084 /*@=dependenttrans =observertrans @*/
04085     hsa->h = headerFree(hsa->h);
04086     hsa->fmt = _free(hsa->fmt);
04087     return hsa->val;
04088 }
04089 
04096 static
04097 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
04098         /*@modifies headerTo @*/
04099 {
04100     int * tagno;
04101 
04102     if (headerFrom == headerTo)
04103         return;
04104 
04105     for (tagno = tagstocopy; *tagno != 0; tagno++) {
04106         rpmTagType t;
04107         rpmTagData p = { .ptr = NULL };
04108         rpmTagCount c;
04109         if (headerIsEntry(headerTo, *tagno))
04110             continue;
04111         if (!headerGetEntryMinMemory(headerFrom, *tagno, (hTYP_t)&t, &p, &c))
04112             continue;
04113         (void) headerAddEntry(headerTo, *tagno, t, p.ptr, c);
04114         p.ptr = headerFreeData(p.ptr, t);
04115     }
04116 }
04117 
04118 /*@observer@*/ /*@unchecked@*/
04119 static struct HV_s hdrVec1 = {
04120     headerLink,
04121     headerUnlink,
04122     headerFree,
04123     headerNew,
04124     headerSort,
04125     headerUnsort,
04126     headerSizeof,
04127     headerUnload,
04128     headerReload,
04129     headerCopy,
04130     headerLoad,
04131     headerCopyLoad,
04132     headerRead,
04133     headerWrite,
04134     headerIsEntry,
04135     headerFreeTag,
04136     headerGetEntry,
04137     headerGetEntryMinMemory,
04138     headerAddEntry,
04139     headerAppendEntry,
04140     headerAddOrAppendEntry,
04141     headerAddI18NString,
04142     headerModifyEntry,
04143     headerRemoveEntry,
04144     headerSprintf,
04145     headerCopyTags,
04146     headerFreeIterator,
04147     headerInitIterator,
04148     headerNextIterator,
04149     headerGetOrigin,
04150     headerSetOrigin,
04151     headerGetInstance,
04152     headerSetInstance,
04153     NULL, NULL,
04154     1
04155 };
04156 
04157 /*@-compmempass -redef@*/
04158 /*@observer@*/ /*@unchecked@*/
04159 HV_t hdrVec = &hdrVec1;
04160 /*@=compmempass =redef@*/

Generated on Wed Oct 29 03:28:19 2008 for rpm by  doxygen 1.5.1