Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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 <header_internal.h>
00016 
00017 #include "debug.h"
00018 
00019 /*@unchecked@*/
00020 int _hdr_debug = 0;
00021 
00022 /*@-redecl@*/   /* FIX: avoid rpmlib.h, need for debugging. */
00023 /*@observer@*/ const char *const tagName(int tag)       /*@*/;
00024 /*@=redecl@*/
00025 
00026 /*@access entryInfo @*/
00027 /*@access indexEntry @*/
00028 
00029 /*@access rpmec @*/
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 
00038 /* XXX for xml support */
00039 /*@-redecl@*/
00040 /*@observer@*/ extern const char *const tagName(int tag)
00041         /*@*/;
00042 /*@=redecl@*/
00043 
00046 /*@observer@*/ /*@unchecked@*/
00047 static unsigned char header_magic[8] = {
00048         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00049 };
00050 
00054 /*@observer@*/ /*@unchecked@*/
00055 static int typeAlign[16] =  {
00056     1,  
00057     1,  
00058     1,  
00059     2,  
00060     4,  
00061     8,  
00062     1,  
00063     1,  
00064     1,  
00065     1,  
00066     0,
00067     0,
00068     0,
00069     0,
00070     0,
00071     0
00072 };
00073 
00077 /*@observer@*/ /*@unchecked@*/
00078 static int typeSizes[16] =  { 
00079     0,  
00080     1,  
00081     1,  
00082     2,  
00083     4,  
00084     -1, 
00085     -1, 
00086     1,  
00087     -1, 
00088     -1, 
00089     0,
00090     0,
00091     0,
00092     0,
00093     0,
00094     0
00095 };
00096 
00100 /*@unchecked@*/
00101 static size_t headerMaxbytes = (32*1024*1024);
00102 
00107 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00108 
00112 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00113 
00118 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00119 
00123 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00124 
00128 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00129 
00130 /*@observer@*/ /*@unchecked@*/
00131 HV_t hdrVec;    /* forward reference */
00132 
00138 /*@unused@*/ static inline /*@null@*/ void *
00139 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
00140 {
00141     if (p != NULL)      free((void *)p);
00142     return NULL;
00143 }
00144 
00150 static
00151 Header headerLink(Header h)
00152         /*@modifies h @*/
00153 {
00154 /*@-nullret@*/
00155     if (h == NULL) return NULL;
00156 /*@=nullret@*/
00157 
00158     h->nrefs++;
00159 /*@-modfilesys@*/
00160 if (_hdr_debug)
00161 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00162 /*@=modfilesys@*/
00163 
00164     /*@-refcounttrans @*/
00165     return h;
00166     /*@=refcounttrans @*/
00167 }
00168 
00174 static /*@null@*/
00175 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00176         /*@modifies h @*/
00177 {
00178     if (h == NULL) return NULL;
00179 /*@-modfilesys@*/
00180 if (_hdr_debug)
00181 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00182 /*@=modfilesys@*/
00183     h->nrefs--;
00184     return NULL;
00185 }
00186 
00192 static /*@null@*/
00193 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00194         /*@modifies h @*/
00195 {
00196     (void) headerUnlink(h);
00197 
00198     /*@-usereleased@*/
00199     if (h == NULL || h->nrefs > 0)
00200         return NULL;    /* XXX return previous header? */
00201 
00202     if (h->index) {
00203         indexEntry entry = h->index;
00204         int i;
00205         for (i = 0; i < h->indexUsed; i++, entry++) {
00206             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00207                 if (entry->length > 0) {
00208                     int_32 * ei = entry->data;
00209                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00210                     entry->data = NULL;
00211                 }
00212             } else if (!ENTRY_IN_REGION(entry)) {
00213                 entry->data = _free(entry->data);
00214             }
00215             entry->data = NULL;
00216         }
00217         h->index = _free(h->index);
00218     }
00219 
00220     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00221     return h;
00222     /*@=usereleased@*/
00223 }
00224 
00229 static
00230 Header headerNew(void)
00231         /*@*/
00232 {
00233     Header h = xcalloc(1, sizeof(*h));
00234 
00235 /*@-boundsread@*/
00236     /*@-assignexpose@*/
00237     h->hv = *hdrVec;            /* structure assignment */
00238     /*@=assignexpose@*/
00239 /*@=boundsread@*/
00240     h->blob = NULL;
00241     h->indexAlloced = INDEX_MALLOC_SIZE;
00242     h->indexUsed = 0;
00243     h->flags |= HEADERFLAG_SORTED;
00244 
00245     h->index = (h->indexAlloced
00246         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00247         : NULL);
00248 
00249     h->nrefs = 0;
00250     /*@-globstate -observertrans @*/
00251     return headerLink(h);
00252     /*@=globstate =observertrans @*/
00253 }
00254 
00257 static int indexCmp(const void * avp, const void * bvp)
00258         /*@*/
00259 {
00260     /*@-castexpose@*/
00261     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00262     /*@=castexpose@*/
00263     return (ap->info.tag - bp->info.tag);
00264 }
00265 
00270 static
00271 void headerSort(Header h)
00272         /*@modifies h @*/
00273 {
00274     if (!(h->flags & HEADERFLAG_SORTED)) {
00275 /*@-boundsread@*/
00276         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00277 /*@=boundsread@*/
00278         h->flags |= HEADERFLAG_SORTED;
00279     }
00280 }
00281 
00284 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00285 {
00286     /*@-castexpose@*/
00287     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00288     /*@=castexpose@*/
00289     int rc = (ap->info.offset - bp->info.offset);
00290 
00291     if (rc == 0) {
00292         /* Within a region, entries sort by address. Added drips sort by tag. */
00293         if (ap->info.offset < 0)
00294             rc = (((char *)ap->data) - ((char *)bp->data));
00295         else
00296             rc = (ap->info.tag - bp->info.tag);
00297     }
00298     return rc;
00299 }
00300 
00305 static
00306 void headerUnsort(Header h)
00307         /*@modifies h @*/
00308 {
00309 /*@-boundsread@*/
00310     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00311 /*@=boundsread@*/
00312 }
00313 
00320 static
00321 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00322         /*@modifies h @*/
00323 {
00324     indexEntry entry;
00325     unsigned int size = 0;
00326     unsigned int pad = 0;
00327     int i;
00328 
00329     if (h == NULL)
00330         return size;
00331 
00332     headerSort(h);
00333 
00334     switch (magicp) {
00335     case HEADER_MAGIC_YES:
00336         size += sizeof(header_magic);
00337         break;
00338     case HEADER_MAGIC_NO:
00339         break;
00340     }
00341 
00342     /*@-sizeoftype@*/
00343     size += 2 * sizeof(int_32); /* count of index entries */
00344     /*@=sizeoftype@*/
00345 
00346     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00347         unsigned diff;
00348         int_32 type;
00349 
00350         /* Regions go in as is ... */
00351         if (ENTRY_IS_REGION(entry)) {
00352             size += entry->length;
00353             /* XXX Legacy regions do not include the region tag and data. */
00354             /*@-sizeoftype@*/
00355             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00356                 size += sizeof(struct entryInfo_s) + entry->info.count;
00357             /*@=sizeoftype@*/
00358             continue;
00359         }
00360 
00361         /* ... and region elements are skipped. */
00362         if (entry->info.offset < 0)
00363             continue;
00364 
00365         /* Alignment */
00366         type = entry->info.type;
00367 /*@-boundsread@*/
00368         if (typeSizes[type] > 1) {
00369             diff = typeSizes[type] - (size % typeSizes[type]);
00370             if (diff != typeSizes[type]) {
00371                 size += diff;
00372                 pad += diff;
00373             }
00374         }
00375 /*@=boundsread@*/
00376 
00377         /*@-sizeoftype@*/
00378         size += sizeof(struct entryInfo_s) + entry->length;
00379         /*@=sizeoftype@*/
00380     }
00381 
00382     return size;
00383 }
00384 
00394 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00395                 /*@null@*/ hPTR_t pend)
00396         /*@*/
00397 {
00398     const unsigned char * s = p;
00399     const unsigned char * se = pend;
00400     int length = 0;
00401 
00402     switch (type) {
00403     case RPM_STRING_TYPE:
00404         if (count != 1)
00405             return -1;
00406 /*@-boundsread@*/
00407         while (*s++) {
00408             if (se && s > se)
00409                 return -1;
00410             length++;
00411         }
00412 /*@=boundsread@*/
00413         length++;       /* count nul terminator too. */
00414         break;
00415 
00416     case RPM_STRING_ARRAY_TYPE:
00417     case RPM_I18NSTRING_TYPE:
00418         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00419         /* Compute sum of length of all strings, including nul terminators */
00420 
00421         if (onDisk) {
00422             while (count--) {
00423                 length++;       /* count nul terminator too */
00424 /*@-boundsread@*/
00425                while (*s++) {
00426                     if (se && s > se)
00427                         return -1;
00428                     length++;
00429                 }
00430 /*@=boundsread@*/
00431             }
00432         } else {
00433             const char ** av = (const char **)p;
00434 /*@-boundsread@*/
00435             while (count--) {
00436                 /* add one for null termination */
00437                 length += strlen(*av++) + 1;
00438             }
00439 /*@=boundsread@*/
00440         }
00441         break;
00442 
00443     default:
00444 /*@-boundsread@*/
00445         if (typeSizes[type] == -1)
00446             return -1;
00447         length = typeSizes[(type & 0xf)] * count;
00448 /*@=boundsread@*/
00449         if (length < 0 || (se && (s + length) > se))
00450             return -1;
00451         break;
00452     }
00453 
00454     return length;
00455 }
00456 
00483 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00484                 entryInfo pe,
00485                 unsigned char * dataStart,
00486                 /*@null@*/ const unsigned char * dataEnd,
00487                 int regionid)
00488         /*@modifies *entry, *dataStart @*/
00489 {
00490     unsigned char * tprev = NULL;
00491     unsigned char * t = NULL;
00492     int tdel = 0;
00493     int tl = dl;
00494     struct indexEntry_s ieprev;
00495 
00496 /*@-boundswrite@*/
00497     memset(&ieprev, 0, sizeof(ieprev));
00498 /*@=boundswrite@*/
00499     for (; il > 0; il--, pe++) {
00500         struct indexEntry_s ie;
00501         int_32 type;
00502 
00503         ie.info.tag = ntohl(pe->tag);
00504         ie.info.type = ntohl(pe->type);
00505         ie.info.count = ntohl(pe->count);
00506         ie.info.offset = ntohl(pe->offset);
00507 
00508         if (hdrchkType(ie.info.type))
00509             return -1;
00510         if (hdrchkData(ie.info.count))
00511             return -1;
00512         if (hdrchkData(ie.info.offset))
00513             return -1;
00514 /*@-boundsread@*/
00515         if (hdrchkAlign(ie.info.type, ie.info.offset))
00516             return -1;
00517 /*@=boundsread@*/
00518 
00519         ie.data = t = dataStart + ie.info.offset;
00520         if (dataEnd && t >= dataEnd)
00521             return -1;
00522 
00523         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00524         if (ie.length < 0 || hdrchkData(ie.length))
00525             return -1;
00526 
00527         ie.rdlen = 0;
00528 
00529         if (entry) {
00530             ie.info.offset = regionid;
00531 /*@-boundswrite@*/
00532             *entry = ie;        /* structure assignment */
00533 /*@=boundswrite@*/
00534             entry++;
00535         }
00536 
00537         /* Alignment */
00538         type = ie.info.type;
00539 /*@-boundsread@*/
00540         if (typeSizes[type] > 1) {
00541             unsigned diff;
00542             diff = typeSizes[type] - (dl % typeSizes[type]);
00543             if (diff != typeSizes[type]) {
00544                 dl += diff;
00545                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00546                     ieprev.length += diff;
00547             }
00548         }
00549 /*@=boundsread@*/
00550         tdel = (tprev ? (t - tprev) : 0);
00551         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00552             tdel = ieprev.length;
00553 
00554         if (ie.info.tag >= HEADER_I18NTABLE) {
00555             tprev = t;
00556         } else {
00557             tprev = dataStart;
00558             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00559             /*@-sizeoftype@*/
00560             if (ie.info.tag == HEADER_IMAGE)
00561                 tprev -= REGION_TAG_COUNT;
00562             /*@=sizeoftype@*/
00563         }
00564 
00565         /* Perform endian conversions */
00566         switch (ntohl(pe->type)) {
00567 /*@-bounds@*/
00568         case RPM_INT32_TYPE:
00569         {   int_32 * it = (int_32 *)t;
00570             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00571                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00572                     return -1;
00573                 *it = htonl(*it);
00574             }
00575             t = (char *) it;
00576         }   /*@switchbreak@*/ break;
00577         case RPM_INT16_TYPE:
00578         {   int_16 * it = (int_16 *) t;
00579             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00580                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00581                     return -1;
00582                 *it = htons(*it);
00583             }
00584             t = (char *) it;
00585         }   /*@switchbreak@*/ break;
00586 /*@=bounds@*/
00587         default:
00588             t += ie.length;
00589             /*@switchbreak@*/ break;
00590         }
00591 
00592         dl += ie.length;
00593         tl += tdel;
00594         ieprev = ie;    /* structure assignment */
00595 
00596     }
00597     tdel = (tprev ? (t - tprev) : 0);
00598     tl += tdel;
00599 
00600     /* XXX
00601      * There are two hacks here:
00602      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00603      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00604      */
00605     /*@-sizeoftype@*/
00606     if (tl+REGION_TAG_COUNT == dl)
00607         tl += REGION_TAG_COUNT;
00608     /*@=sizeoftype@*/
00609 
00610     return dl;
00611 }
00612 
00618 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00619                 /*@out@*/ int * lengthPtr)
00620         /*@modifies h, *lengthPtr @*/
00621         /*@requires maxSet(lengthPtr) >= 0 @*/
00622         /*@ensures maxRead(result) == (*lengthPtr) @*/
00623 {
00624     int_32 * ei = NULL;
00625     entryInfo pe;
00626     char * dataStart;
00627     char * te;
00628     unsigned pad;
00629     unsigned len;
00630     int_32 il = 0;
00631     int_32 dl = 0;
00632     indexEntry entry; 
00633     int_32 type;
00634     int i;
00635     int drlen, ndribbles;
00636     int driplen, ndrips;
00637     int legacy = 0;
00638 
00639     /* Sort entries by (offset,tag). */
00640     headerUnsort(h);
00641 
00642     /* Compute (il,dl) for all tags, including those deleted in region. */
00643     pad = 0;
00644     drlen = ndribbles = driplen = ndrips = 0;
00645     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00646         if (ENTRY_IS_REGION(entry)) {
00647             int_32 rdl = -entry->info.offset;   /* negative offset */
00648             int_32 ril = rdl/sizeof(*pe);
00649             int rid = entry->info.offset;
00650 
00651             il += ril;
00652             dl += entry->rdlen + entry->info.count;
00653             /* XXX Legacy regions do not include the region tag and data. */
00654             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00655                 il += 1;
00656 
00657             /* Skip rest of entries in region, but account for dribbles. */
00658             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00659                 if (entry->info.offset <= rid)
00660                     /*@innercontinue@*/ continue;
00661 
00662                 /* Alignment */
00663                 type = entry->info.type;
00664                 if (typeSizes[type] > 1) {
00665                     unsigned diff;
00666                     diff = typeSizes[type] - (dl % typeSizes[type]);
00667                     if (diff != typeSizes[type]) {
00668                         drlen += diff;
00669                         pad += diff;
00670                         dl += diff;
00671                     }
00672                 }
00673 
00674                 ndribbles++;
00675                 il++;
00676                 drlen += entry->length;
00677                 dl += entry->length;
00678             }
00679             i--;
00680             entry--;
00681             continue;
00682         }
00683 
00684         /* Ignore deleted drips. */
00685         if (entry->data == NULL || entry->length <= 0)
00686             continue;
00687 
00688         /* Alignment */
00689         type = entry->info.type;
00690         if (typeSizes[type] > 1) {
00691             unsigned diff;
00692             diff = typeSizes[type] - (dl % typeSizes[type]);
00693             if (diff != typeSizes[type]) {
00694                 driplen += diff;
00695                 pad += diff;
00696                 dl += diff;
00697             } else
00698                 diff = 0;
00699         }
00700 
00701         ndrips++;
00702         il++;
00703         driplen += entry->length;
00704         dl += entry->length;
00705     }
00706 
00707     /* Sanity checks on header intro. */
00708     if (hdrchkTags(il) || hdrchkData(dl))
00709         goto errxit;
00710 
00711     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00712 
00713 /*@-boundswrite@*/
00714     ei = xmalloc(len);
00715     ei[0] = htonl(il);
00716     ei[1] = htonl(dl);
00717 /*@=boundswrite@*/
00718 
00719     pe = (entryInfo) &ei[2];
00720     dataStart = te = (char *) (pe + il);
00721 
00722     pad = 0;
00723     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00724         const char * src;
00725 char *t;
00726         int count;
00727         int rdlen;
00728 
00729         if (entry->data == NULL || entry->length <= 0)
00730             continue;
00731 
00732 t = te;
00733         pe->tag = htonl(entry->info.tag);
00734         pe->type = htonl(entry->info.type);
00735         pe->count = htonl(entry->info.count);
00736 
00737         if (ENTRY_IS_REGION(entry)) {
00738             int_32 rdl = -entry->info.offset;   /* negative offset */
00739             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00740             int rid = entry->info.offset;
00741 
00742             src = (char *)entry->data;
00743             rdlen = entry->rdlen;
00744 
00745             /* XXX Legacy regions do not include the region tag and data. */
00746             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00747                 int_32 stei[4];
00748 
00749                 legacy = 1;
00750 /*@-boundswrite@*/
00751                 memcpy(pe+1, src, rdl);
00752                 memcpy(te, src + rdl, rdlen);
00753 /*@=boundswrite@*/
00754                 te += rdlen;
00755 
00756                 pe->offset = htonl(te - dataStart);
00757                 stei[0] = pe->tag;
00758                 stei[1] = pe->type;
00759                 stei[2] = htonl(-rdl-entry->info.count);
00760                 stei[3] = pe->count;
00761 /*@-boundswrite@*/
00762                 memcpy(te, stei, entry->info.count);
00763 /*@=boundswrite@*/
00764                 te += entry->info.count;
00765                 ril++;
00766                 rdlen += entry->info.count;
00767 
00768                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00769                 if (count != rdlen)
00770                     goto errxit;
00771 
00772             } else {
00773 
00774 /*@-boundswrite@*/
00775                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00776                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00777 /*@=boundswrite@*/
00778                 te += rdlen;
00779                 {   /*@-castexpose@*/
00780                     entryInfo se = (entryInfo)src;
00781                     /*@=castexpose@*/
00782                     int off = ntohl(se->offset);
00783                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00784                 }
00785                 te += entry->info.count + drlen;
00786 
00787                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00788                 if (count != (rdlen + entry->info.count + drlen))
00789                     goto errxit;
00790             }
00791 
00792             /* Skip rest of entries in region. */
00793             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00794                 i++;
00795                 entry++;
00796             }
00797             i--;
00798             entry--;
00799             pe += ril;
00800             continue;
00801         }
00802 
00803         /* Ignore deleted drips. */
00804         if (entry->data == NULL || entry->length <= 0)
00805             continue;
00806 
00807         /* Alignment */
00808         type = entry->info.type;
00809         if (typeSizes[type] > 1) {
00810             unsigned diff;
00811             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00812             if (diff != typeSizes[type]) {
00813 /*@-boundswrite@*/
00814                 memset(te, 0, diff);
00815 /*@=boundswrite@*/
00816                 te += diff;
00817                 pad += diff;
00818             }
00819         }
00820 
00821         pe->offset = htonl(te - dataStart);
00822 
00823         /* copy data w/ endian conversions */
00824 /*@-boundswrite@*/
00825         switch (entry->info.type) {
00826         case RPM_INT32_TYPE:
00827             count = entry->info.count;
00828             src = entry->data;
00829             while (count--) {
00830                 *((int_32 *)te) = htonl(*((int_32 *)src));
00831                 /*@-sizeoftype@*/
00832                 te += sizeof(int_32);
00833                 src += sizeof(int_32);
00834                 /*@=sizeoftype@*/
00835             }
00836             /*@switchbreak@*/ break;
00837 
00838         case RPM_INT16_TYPE:
00839             count = entry->info.count;
00840             src = entry->data;
00841             while (count--) {
00842                 *((int_16 *)te) = htons(*((int_16 *)src));
00843                 /*@-sizeoftype@*/
00844                 te += sizeof(int_16);
00845                 src += sizeof(int_16);
00846                 /*@=sizeoftype@*/
00847             }
00848             /*@switchbreak@*/ break;
00849 
00850         default:
00851             memcpy(te, entry->data, entry->length);
00852             te += entry->length;
00853             /*@switchbreak@*/ break;
00854         }
00855 /*@=boundswrite@*/
00856         pe++;
00857     }
00858    
00859     /* Insure that there are no memcpy underruns/overruns. */
00860     if (((char *)pe) != dataStart)
00861         goto errxit;
00862     if ((((char *)ei)+len) != te)
00863         goto errxit;
00864 
00865     if (lengthPtr)
00866         *lengthPtr = len;
00867 
00868     h->flags &= ~HEADERFLAG_SORTED;
00869     headerSort(h);
00870 
00871     return (void *) ei;
00872 
00873 errxit:
00874     /*@-usereleased@*/
00875     ei = _free(ei);
00876     /*@=usereleased@*/
00877     return (void *) ei;
00878 }
00879 
00885 static /*@only@*/ /*@null@*/
00886 void * headerUnload(Header h)
00887         /*@modifies h @*/
00888 {
00889     int length;
00890 /*@-boundswrite@*/
00891     void * uh = doHeaderUnload(h, &length);
00892 /*@=boundswrite@*/
00893     return uh;
00894 }
00895 
00903 static /*@null@*/
00904 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00905         /*@modifies h @*/
00906 {
00907     indexEntry entry, entry2, last;
00908     struct indexEntry_s key;
00909 
00910     if (h == NULL) return NULL;
00911     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00912 
00913     key.info.tag = tag;
00914 
00915 /*@-boundswrite@*/
00916     entry2 = entry = 
00917         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00918 /*@=boundswrite@*/
00919     if (entry == NULL)
00920         return NULL;
00921 
00922     if (type == RPM_NULL_TYPE)
00923         return entry;
00924 
00925     /* look backwards */
00926     while (entry->info.tag == tag && entry->info.type != type &&
00927            entry > h->index) entry--;
00928 
00929     if (entry->info.tag == tag && entry->info.type == type)
00930         return entry;
00931 
00932     last = h->index + h->indexUsed;
00933     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00934     while (entry2->info.tag == tag && entry2->info.type != type &&
00935            entry2 < last) entry2++;
00936     /*@=usereleased@*/
00937 
00938     if (entry->info.tag == tag && entry->info.type == type)
00939         return entry;
00940 
00941     return NULL;
00942 }
00943 
00953 static
00954 int headerRemoveEntry(Header h, int_32 tag)
00955         /*@modifies h @*/
00956 {
00957     indexEntry last = h->index + h->indexUsed;
00958     indexEntry entry, first;
00959     int ne;
00960 
00961     entry = findEntry(h, tag, RPM_NULL_TYPE);
00962     if (!entry) return 1;
00963 
00964     /* Make sure entry points to the first occurence of this tag. */
00965     while (entry > h->index && (entry - 1)->info.tag == tag)  
00966         entry--;
00967 
00968     /* Free data for tags being removed. */
00969     for (first = entry; first < last; first++) {
00970         void * data;
00971         if (first->info.tag != tag)
00972             break;
00973         data = first->data;
00974         first->data = NULL;
00975         first->length = 0;
00976         if (ENTRY_IN_REGION(first))
00977             continue;
00978         data = _free(data);
00979     }
00980 
00981     ne = (first - entry);
00982     if (ne > 0) {
00983         h->indexUsed -= ne;
00984         ne = last - first;
00985 /*@-boundswrite@*/
00986         if (ne > 0)
00987             memmove(entry, first, (ne * sizeof(*entry)));
00988 /*@=boundswrite@*/
00989     }
00990 
00991     return 0;
00992 }
00993 
00999 static /*@null@*/
01000 Header headerLoad(/*@kept@*/ void * uh)
01001         /*@modifies uh @*/
01002 {
01003     int_32 * ei = (int_32 *) uh;
01004     int_32 il = ntohl(ei[0]);           /* index length */
01005     int_32 dl = ntohl(ei[1]);           /* data length */
01006     /*@-sizeoftype@*/
01007     size_t pvlen = sizeof(il) + sizeof(dl) +
01008                (il * sizeof(struct entryInfo_s)) + dl;
01009     /*@=sizeoftype@*/
01010     void * pv = uh;
01011     Header h = NULL;
01012     entryInfo pe;
01013     unsigned char * dataStart;
01014     unsigned char * dataEnd;
01015     indexEntry entry; 
01016     int rdlen;
01017     int i;
01018 
01019     /* Sanity checks on header intro. */
01020     if (hdrchkTags(il) || hdrchkData(dl))
01021         goto errxit;
01022 
01023     ei = (int_32 *) pv;
01024     /*@-castexpose@*/
01025     pe = (entryInfo) &ei[2];
01026     /*@=castexpose@*/
01027     dataStart = (unsigned char *) (pe + il);
01028     dataEnd = dataStart + dl;
01029 
01030     h = xcalloc(1, sizeof(*h));
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     /*
01045      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
01046      * %verifyscript tag that needs to be diddled.
01047      */
01048     if (ntohl(pe->tag) == 15 &&
01049         ntohl(pe->type) == RPM_STRING_TYPE &&
01050         ntohl(pe->count) == 1)
01051     {
01052         pe->tag = htonl(1079);
01053     }
01054 
01055     entry = h->index;
01056     i = 0;
01057     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01058         h->flags |= HEADERFLAG_LEGACY;
01059         entry->info.type = REGION_TAG_TYPE;
01060         entry->info.tag = HEADER_IMAGE;
01061         /*@-sizeoftype@*/
01062         entry->info.count = REGION_TAG_COUNT;
01063         /*@=sizeoftype@*/
01064         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01065 
01066         /*@-assignexpose@*/
01067         entry->data = pe;
01068         /*@=assignexpose@*/
01069         entry->length = pvlen - sizeof(il) - sizeof(dl);
01070         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01071 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01072         if (rdlen != dl)
01073             goto errxit;
01074 #endif
01075         entry->rdlen = rdlen;
01076         entry++;
01077         h->indexUsed++;
01078     } else {
01079         int_32 rdl;
01080         int_32 ril;
01081 
01082         h->flags &= ~HEADERFLAG_LEGACY;
01083 
01084         entry->info.type = htonl(pe->type);
01085         entry->info.count = htonl(pe->count);
01086 
01087         if (hdrchkType(entry->info.type))
01088             goto errxit;
01089         if (hdrchkTags(entry->info.count))
01090             goto errxit;
01091 
01092         {   int off = ntohl(pe->offset);
01093 
01094             if (hdrchkData(off))
01095                 goto errxit;
01096             if (off) {
01097 /*@-sizeoftype@*/
01098                 size_t nb = REGION_TAG_COUNT;
01099 /*@=sizeoftype@*/
01100                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01101                 rdl = -ntohl(stei[2]);  /* negative offset */
01102                 ril = rdl/sizeof(*pe);
01103                 if (hdrchkTags(ril) || hdrchkData(rdl))
01104                     goto errxit;
01105                 entry->info.tag = htonl(pe->tag);
01106             } else {
01107                 ril = il;
01108                 /*@-sizeoftype@*/
01109                 rdl = (ril * sizeof(struct entryInfo_s));
01110                 /*@=sizeoftype@*/
01111                 entry->info.tag = HEADER_IMAGE;
01112             }
01113         }
01114         entry->info.offset = -rdl;      /* negative offset */
01115 
01116         /*@-assignexpose@*/
01117         entry->data = pe;
01118         /*@=assignexpose@*/
01119         entry->length = pvlen - sizeof(il) - sizeof(dl);
01120         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01121         if (rdlen < 0)
01122             goto errxit;
01123         entry->rdlen = rdlen;
01124 
01125         if (ril < h->indexUsed) {
01126             indexEntry newEntry = entry + ril;
01127             int ne = (h->indexUsed - ril);
01128             int rid = entry->info.offset+1;
01129             int rc;
01130 
01131             /* Load dribble entries from region. */
01132             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01133             if (rc < 0)
01134                 goto errxit;
01135             rdlen += rc;
01136 
01137           { indexEntry firstEntry = newEntry;
01138             int save = h->indexUsed;
01139             int j;
01140 
01141             /* Dribble entries replace duplicate region entries. */
01142             h->indexUsed -= ne;
01143             for (j = 0; j < ne; j++, newEntry++) {
01144                 (void) headerRemoveEntry(h, newEntry->info.tag);
01145                 if (newEntry->info.tag == HEADER_BASENAMES)
01146                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01147             }
01148 
01149             /* If any duplicate entries were replaced, move new entries down. */
01150 /*@-boundswrite@*/
01151             if (h->indexUsed < (save - ne)) {
01152                 memmove(h->index + h->indexUsed, firstEntry,
01153                         (ne * sizeof(*entry)));
01154             }
01155 /*@=boundswrite@*/
01156             h->indexUsed += ne;
01157           }
01158         }
01159     }
01160 
01161     h->flags &= ~HEADERFLAG_SORTED;
01162     headerSort(h);
01163 
01164     /*@-globstate -observertrans @*/
01165     return h;
01166     /*@=globstate =observertrans @*/
01167 
01168 errxit:
01169     /*@-usereleased@*/
01170     if (h) {
01171         h->index = _free(h->index);
01172         /*@-refcounttrans@*/
01173         h = _free(h);
01174         /*@=refcounttrans@*/
01175     }
01176     /*@=usereleased@*/
01177     /*@-refcounttrans -globstate@*/
01178     return h;
01179     /*@=refcounttrans =globstate@*/
01180 }
01181 
01189 static /*@null@*/
01190 Header headerReload(/*@only@*/ Header h, int tag)
01191         /*@modifies h @*/
01192 {
01193     Header nh;
01194     int length;
01195     /*@-onlytrans@*/
01196 /*@-boundswrite@*/
01197     void * uh = doHeaderUnload(h, &length);
01198 /*@=boundswrite@*/
01199 
01200     h = headerFree(h);
01201     /*@=onlytrans@*/
01202     if (uh == NULL)
01203         return NULL;
01204     nh = headerLoad(uh);
01205     if (nh == NULL) {
01206         uh = _free(uh);
01207         return NULL;
01208     }
01209     if (nh->flags & HEADERFLAG_ALLOCATED)
01210         uh = _free(uh);
01211     nh->flags |= HEADERFLAG_ALLOCATED;
01212     if (ENTRY_IS_REGION(nh->index)) {
01213 /*@-boundswrite@*/
01214         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01215             nh->index[0].info.tag = tag;
01216 /*@=boundswrite@*/
01217     }
01218     return nh;
01219 }
01220 
01226 static /*@null@*/
01227 Header headerCopyLoad(const void * uh)
01228         /*@*/
01229 {
01230     int_32 * ei = (int_32 *) uh;
01231 /*@-boundsread@*/
01232     int_32 il = ntohl(ei[0]);           /* index length */
01233     int_32 dl = ntohl(ei[1]);           /* data length */
01234 /*@=boundsread@*/
01235     /*@-sizeoftype@*/
01236     size_t pvlen = sizeof(il) + sizeof(dl) +
01237                         (il * sizeof(struct entryInfo_s)) + dl;
01238     /*@=sizeoftype@*/
01239     void * nuh = NULL;
01240     Header h = NULL;
01241 
01242     /* Sanity checks on header intro. */
01243     /*@-branchstate@*/
01244     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01245 /*@-boundsread@*/
01246         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01247 /*@=boundsread@*/
01248         if ((h = headerLoad(nuh)) != NULL)
01249             h->flags |= HEADERFLAG_ALLOCATED;
01250     }
01251     /*@=branchstate@*/
01252     /*@-branchstate@*/
01253     if (h == NULL)
01254         nuh = _free(nuh);
01255     /*@=branchstate@*/
01256     return h;
01257 }
01258 
01265 static /*@null@*/
01266 Header headerRead(FD_t fd, enum hMagic magicp)
01267         /*@modifies fd @*/
01268 {
01269     int_32 block[4];
01270     int_32 reserved;
01271     int_32 * ei = NULL;
01272     int_32 il;
01273     int_32 dl;
01274     int_32 magic;
01275     Header h = NULL;
01276     size_t len;
01277     int i;
01278 
01279     memset(block, 0, sizeof(block));
01280     i = 2;
01281     if (magicp == HEADER_MAGIC_YES)
01282         i += 2;
01283 
01284     /*@-type@*/ /* FIX: cast? */
01285     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01286         goto exit;
01287     /*@=type@*/
01288 
01289     i = 0;
01290 
01291 /*@-boundsread@*/
01292     if (magicp == HEADER_MAGIC_YES) {
01293         magic = block[i++];
01294         if (memcmp(&magic, header_magic, sizeof(magic)))
01295             goto exit;
01296         reserved = block[i++];
01297     }
01298     
01299     il = ntohl(block[i]);       i++;
01300     dl = ntohl(block[i]);       i++;
01301 /*@=boundsread@*/
01302 
01303     /*@-sizeoftype@*/
01304     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01305     /*@=sizeoftype@*/
01306 
01307     /* Sanity checks on header intro. */
01308     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01309         goto exit;
01310 
01311 /*@-boundswrite@*/
01312     ei = xmalloc(len);
01313     ei[0] = htonl(il);
01314     ei[1] = htonl(dl);
01315     len -= sizeof(il) + sizeof(dl);
01316 /*@=boundswrite@*/
01317 
01318 /*@-boundsread@*/
01319     /*@-type@*/ /* FIX: cast? */
01320     if (timedRead(fd, (char *)&ei[2], len) != len)
01321         goto exit;
01322     /*@=type@*/
01323 /*@=boundsread@*/
01324     
01325     h = headerLoad(ei);
01326 
01327 exit:
01328     if (h) {
01329         if (h->flags & HEADERFLAG_ALLOCATED)
01330             ei = _free(ei);
01331         h->flags |= HEADERFLAG_ALLOCATED;
01332     } else if (ei)
01333         ei = _free(ei);
01334     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01335     return h;
01336     /*@-mustmod@*/
01337 }
01338 
01346 static
01347 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
01348         /*@globals fileSystem @*/
01349         /*@modifies fd, h, fileSystem @*/
01350 {
01351     ssize_t nb;
01352     int length;
01353     const void * uh;
01354 
01355     if (h == NULL)
01356         return 1;
01357 /*@-boundswrite@*/
01358     uh = doHeaderUnload(h, &length);
01359 /*@=boundswrite@*/
01360     if (uh == NULL)
01361         return 1;
01362     switch (magicp) {
01363     case HEADER_MAGIC_YES:
01364 /*@-boundsread@*/
01365         /*@-sizeoftype@*/
01366         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01367         /*@=sizeoftype@*/
01368 /*@=boundsread@*/
01369         if (nb != sizeof(header_magic))
01370             goto exit;
01371         break;
01372     case HEADER_MAGIC_NO:
01373         break;
01374     }
01375 
01376     /*@-sizeoftype@*/
01377     nb = Fwrite(uh, sizeof(char), length, fd);
01378     /*@=sizeoftype@*/
01379 
01380 exit:
01381     uh = _free(uh);
01382     return (nb == length ? 0 : 1);
01383 }
01384 
01391 static
01392 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01393         /*@*/
01394 {
01395     /*@-mods@*/         /*@ FIX: h modified by sort. */
01396     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01397     /*@=mods@*/ 
01398 }
01399 
01410 static int copyEntry(const indexEntry entry,
01411                 /*@null@*/ /*@out@*/ hTYP_t type,
01412                 /*@null@*/ /*@out@*/ hPTR_t * p,
01413                 /*@null@*/ /*@out@*/ hCNT_t c,
01414                 int minMem)
01415         /*@modifies *type, *p, *c @*/
01416         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01417 {
01418     int_32 count = entry->info.count;
01419     int rc = 1;         /* XXX 1 on success. */
01420 
01421     if (p)
01422     switch (entry->info.type) {
01423     case RPM_BIN_TYPE:
01424         /*
01425          * XXX This only works for
01426          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01427          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01428          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01429          */
01430         if (ENTRY_IS_REGION(entry)) {
01431             int_32 * ei = ((int_32 *)entry->data) - 2;
01432             /*@-castexpose@*/
01433             entryInfo pe = (entryInfo) (ei + 2);
01434             /*@=castexpose@*/
01435 /*@-boundsread@*/
01436             char * dataStart = (char *) (pe + ntohl(ei[0]));
01437 /*@=boundsread@*/
01438             int_32 rdl = -entry->info.offset;   /* negative offset */
01439             int_32 ril = rdl/sizeof(*pe);
01440 
01441             /*@-sizeoftype@*/
01442             rdl = entry->rdlen;
01443             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01444             if (entry->info.tag == HEADER_IMAGE) {
01445                 ril -= 1;
01446                 pe += 1;
01447             } else {
01448                 count += REGION_TAG_COUNT;
01449                 rdl += REGION_TAG_COUNT;
01450             }
01451 
01452 /*@-bounds@*/
01453             *p = xmalloc(count);
01454             ei = (int_32 *) *p;
01455             ei[0] = htonl(ril);
01456             ei[1] = htonl(rdl);
01457 
01458             /*@-castexpose@*/
01459             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01460             /*@=castexpose@*/
01461 
01462             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01463             /*@=sizeoftype@*/
01464 /*@=bounds@*/
01465 
01466             rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01467             /* XXX 1 on success. */
01468             rc = (rc < 0) ? 0 : 1;
01469         } else {
01470             count = entry->length;
01471             *p = (!minMem
01472                 ? memcpy(xmalloc(count), entry->data, count)
01473                 : entry->data);
01474         }
01475         break;
01476     case RPM_STRING_TYPE:
01477         if (count == 1) {
01478             *p = entry->data;
01479             break;
01480         }
01481         /*@fallthrough@*/
01482     case RPM_STRING_ARRAY_TYPE:
01483     case RPM_I18NSTRING_TYPE:
01484     {   const char ** ptrEntry;
01485         /*@-sizeoftype@*/
01486         int tableSize = count * sizeof(char *);
01487         /*@=sizeoftype@*/
01488         char * t;
01489         int i;
01490 
01491 /*@-bounds@*/
01492         /*@-mods@*/
01493         if (minMem) {
01494             *p = xmalloc(tableSize);
01495             ptrEntry = (const char **) *p;
01496             t = entry->data;
01497         } else {
01498             t = xmalloc(tableSize + entry->length);
01499             *p = (void *)t;
01500             ptrEntry = (const char **) *p;
01501             t += tableSize;
01502             memcpy(t, entry->data, entry->length);
01503         }
01504         /*@=mods@*/
01505 /*@=bounds@*/
01506         for (i = 0; i < count; i++) {
01507 /*@-boundswrite@*/
01508             *ptrEntry++ = t;
01509 /*@=boundswrite@*/
01510             t = strchr(t, 0);
01511             t++;
01512         }
01513     }   break;
01514 
01515     default:
01516         *p = entry->data;
01517         break;
01518     }
01519     if (type) *type = entry->info.type;
01520     if (c) *c = count;
01521     return rc;
01522 }
01523 
01542 static int headerMatchLocale(const char *td, const char *l, const char *le)
01543         /*@*/
01544 {
01545     const char *fe;
01546 
01547 
01548 #if 0
01549   { const char *s, *ll, *CC, *EE, *dd;
01550     char *lbuf, *t.
01551 
01552     /* Copy the buffer and parse out components on the fly. */
01553     lbuf = alloca(le - l + 1);
01554     for (s = l, ll = t = lbuf; *s; s++, t++) {
01555         switch (*s) {
01556         case '_':
01557             *t = '\0';
01558             CC = t + 1;
01559             break;
01560         case '.':
01561             *t = '\0';
01562             EE = t + 1;
01563             break;
01564         case '@':
01565             *t = '\0';
01566             dd = t + 1;
01567             break;
01568         default:
01569             *t = *s;
01570             break;
01571         }
01572     }
01573 
01574     if (ll)     /* ISO language should be lower case */
01575         for (t = ll; *t; t++)   *t = tolower(*t);
01576     if (CC)     /* ISO country code should be upper case */
01577         for (t = CC; *t; t++)   *t = toupper(*t);
01578 
01579     /* There are a total of 16 cases to attempt to match. */
01580   }
01581 #endif
01582 
01583     /* First try a complete match. */
01584     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01585         return 1;
01586 
01587     /* Next, try stripping optional dialect and matching.  */
01588     for (fe = l; fe < le && *fe != '@'; fe++)
01589         {};
01590     if (fe < le && !strncmp(td, l, (fe - l)))
01591         return 1;
01592 
01593     /* Next, try stripping optional codeset and matching.  */
01594     for (fe = l; fe < le && *fe != '.'; fe++)
01595         {};
01596     if (fe < le && !strncmp(td, l, (fe - l)))
01597         return 1;
01598 
01599     /* Finally, try stripping optional country code and matching. */
01600     for (fe = l; fe < le && *fe != '_'; fe++)
01601         {};
01602     if (fe < le && !strncmp(td, l, (fe - l)))
01603         return 1;
01604 
01605     return 0;
01606 }
01607 
01614 /*@dependent@*/ /*@exposed@*/ static char *
01615 headerFindI18NString(Header h, indexEntry entry)
01616         /*@*/
01617 {
01618     const char *lang, *l, *le;
01619     indexEntry table;
01620 
01621     /* XXX Drepper sez' this is the order. */
01622     if ((lang = getenv("LANGUAGE")) == NULL &&
01623         (lang = getenv("LC_ALL")) == NULL &&
01624         (lang = getenv("LC_MESSAGES")) == NULL &&
01625         (lang = getenv("LANG")) == NULL)
01626             return entry->data;
01627     
01628     /*@-mods@*/
01629     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01630         return entry->data;
01631     /*@=mods@*/
01632 
01633 /*@-boundsread@*/
01634     for (l = lang; *l != '\0'; l = le) {
01635         const char *td;
01636         char *ed;
01637         int langNum;
01638 
01639         while (*l && *l == ':')                 /* skip leading colons */
01640             l++;
01641         if (*l == '\0')
01642             break;
01643         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01644             {};
01645 
01646         /* For each entry in the header ... */
01647         for (langNum = 0, td = table->data, ed = entry->data;
01648              langNum < entry->info.count;
01649              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01650 
01651                 if (headerMatchLocale(td, l, le))
01652                     return ed;
01653 
01654         }
01655     }
01656 /*@=boundsread@*/
01657 
01658     return entry->data;
01659 }
01660 
01671 static int intGetEntry(Header h, int_32 tag,
01672                 /*@null@*/ /*@out@*/ hTAG_t type,
01673                 /*@null@*/ /*@out@*/ hPTR_t * p,
01674                 /*@null@*/ /*@out@*/ hCNT_t c,
01675                 int minMem)
01676         /*@modifies *type, *p, *c @*/
01677         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01678 {
01679     indexEntry entry;
01680     int rc;
01681 
01682     /* First find the tag */
01683     /*@-mods@*/         /*@ FIX: h modified by sort. */
01684     entry = findEntry(h, tag, RPM_NULL_TYPE);
01685     /*@mods@*/
01686     if (entry == NULL) {
01687         if (type) type = 0;
01688         if (p) *p = NULL;
01689         if (c) *c = 0;
01690         return 0;
01691     }
01692 
01693     switch (entry->info.type) {
01694     case RPM_I18NSTRING_TYPE:
01695         rc = 1;
01696         if (type) *type = RPM_STRING_TYPE;
01697         if (c) *c = 1;
01698         /*@-dependenttrans@*/
01699         if (p) *p = headerFindI18NString(h, entry);
01700         /*@=dependenttrans@*/
01701         break;
01702     default:
01703         rc = copyEntry(entry, type, p, c, minMem);
01704         break;
01705     }
01706 
01707     /* XXX 1 on success */
01708     return ((rc == 1) ? 1 : 0);
01709 }
01710 
01718 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01719                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01720         /*@modifies data @*/
01721 {
01722     if (data) {
01723         /*@-branchstate@*/
01724         if (type == -1 ||
01725             type == RPM_STRING_ARRAY_TYPE ||
01726             type == RPM_I18NSTRING_TYPE ||
01727             type == RPM_BIN_TYPE)
01728                 data = _free(data);
01729         /*@=branchstate@*/
01730     }
01731     return NULL;
01732 }
01733 
01747 static
01748 int headerGetEntry(Header h, int_32 tag,
01749                         /*@null@*/ /*@out@*/ hTYP_t type,
01750                         /*@null@*/ /*@out@*/ void ** p,
01751                         /*@null@*/ /*@out@*/ hCNT_t c)
01752         /*@modifies *type, *p, *c @*/
01753         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01754 {
01755     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01756 }
01757 
01770 static
01771 int headerGetEntryMinMemory(Header h, int_32 tag,
01772                         /*@null@*/ /*@out@*/ hTYP_t type,
01773                         /*@null@*/ /*@out@*/ hPTR_t * p,
01774                         /*@null@*/ /*@out@*/ hCNT_t c)
01775         /*@modifies *type, *p, *c @*/
01776         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01777 {
01778     return intGetEntry(h, tag, type, p, c, 1);
01779 }
01780 
01781 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01782                 int_32 * c)
01783 {
01784     indexEntry entry;
01785     int rc;
01786 
01787     if (p == NULL) return headerIsEntry(h, tag);
01788 
01789     /* First find the tag */
01790     /*@-mods@*/         /*@ FIX: h modified by sort. */
01791     entry = findEntry(h, tag, RPM_NULL_TYPE);
01792     /*@=mods@*/
01793     if (!entry) {
01794         if (p) *p = NULL;
01795         if (c) *c = 0;
01796         return 0;
01797     }
01798 
01799     rc = copyEntry(entry, type, p, c, 0);
01800 
01801     /* XXX 1 on success */
01802     return ((rc == 1) ? 1 : 0);
01803 }
01804 
01807 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01808                 int_32 cnt, int dataLength)
01809         /*@modifies *dstPtr @*/
01810 {
01811     switch (type) {
01812     case RPM_STRING_ARRAY_TYPE:
01813     case RPM_I18NSTRING_TYPE:
01814     {   const char ** av = (const char **) srcPtr;
01815         char * t = dstPtr;
01816 
01817 /*@-bounds@*/
01818         while (cnt-- > 0 && dataLength > 0) {
01819             const char * s;
01820             if ((s = *av++) == NULL)
01821                 continue;
01822             do {
01823                 *t++ = *s++;
01824             } while (s[-1] && --dataLength > 0);
01825         }
01826 /*@=bounds@*/
01827     }   break;
01828 
01829     default:
01830 /*@-boundswrite@*/
01831         memmove(dstPtr, srcPtr, dataLength);
01832 /*@=boundswrite@*/
01833         break;
01834     }
01835 }
01836 
01845 /*@null@*/
01846 static void *
01847 grabData(int_32 type, hPTR_t p, int_32 c, /*@out@*/ int * lengthPtr)
01848         /*@modifies *lengthPtr @*/
01849         /*@requires maxSet(lengthPtr) >= 0 @*/
01850 {
01851     void * data = NULL;
01852     int length;
01853 
01854     length = dataLength(type, p, c, 0, NULL);
01855 /*@-branchstate@*/
01856     if (length > 0) {
01857         data = xmalloc(length);
01858         copyData(type, data, p, c, length);
01859     }
01860 /*@=branchstate@*/
01861 
01862     if (lengthPtr)
01863         *lengthPtr = length;
01864     return data;
01865 }
01866 
01881 static
01882 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01883         /*@modifies h @*/
01884 {
01885     indexEntry entry;
01886     void * data;
01887     int length;
01888 
01889     /* Count must always be >= 1 for headerAddEntry. */
01890     if (c <= 0)
01891         return 0;
01892 
01893     if (hdrchkType(type))
01894         return 0;
01895     if (hdrchkData(c))
01896         return 0;
01897 
01898     length = 0;
01899 /*@-boundswrite@*/
01900     data = grabData(type, p, c, &length);
01901 /*@=boundswrite@*/
01902     if (data == NULL || length <= 0)
01903         return 0;
01904 
01905     /* Allocate more index space if necessary */
01906     if (h->indexUsed == h->indexAlloced) {
01907         h->indexAlloced += INDEX_MALLOC_SIZE;
01908         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01909     }
01910 
01911     /* Fill in the index */
01912     entry = h->index + h->indexUsed;
01913     entry->info.tag = tag;
01914     entry->info.type = type;
01915     entry->info.count = c;
01916     entry->info.offset = 0;
01917     entry->data = data;
01918     entry->length = length;
01919 
01920 /*@-boundsread@*/
01921     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01922         h->flags &= ~HEADERFLAG_SORTED;
01923 /*@=boundsread@*/
01924     h->indexUsed++;
01925 
01926     return 1;
01927 }
01928 
01943 static
01944 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01945                 const void * p, int_32 c)
01946         /*@modifies h @*/
01947 {
01948     indexEntry entry;
01949     int length;
01950 
01951     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01952         /* we can't do this */
01953         return 0;
01954     }
01955 
01956     /* Find the tag entry in the header. */
01957     entry = findEntry(h, tag, type);
01958     if (!entry)
01959         return 0;
01960 
01961     length = dataLength(type, p, c, 0, NULL);
01962     if (length < 0)
01963         return 0;
01964 
01965     if (ENTRY_IN_REGION(entry)) {
01966         char * t = xmalloc(entry->length + length);
01967 /*@-bounds@*/
01968         memcpy(t, entry->data, entry->length);
01969 /*@=bounds@*/
01970         entry->data = t;
01971         entry->info.offset = 0;
01972     } else
01973         entry->data = xrealloc(entry->data, entry->length + length);
01974 
01975     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01976 
01977     entry->length += length;
01978 
01979     entry->info.count += c;
01980 
01981     return 1;
01982 }
01983 
01994 static
01995 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01996                 const void * p, int_32 c)
01997         /*@modifies h @*/
01998 {
01999     return (findEntry(h, tag, type)
02000         ? headerAppendEntry(h, tag, type, p, c)
02001         : headerAddEntry(h, tag, type, p, c));
02002 }
02003 
02024 static
02025 int headerAddI18NString(Header h, int_32 tag, const char * string,
02026                 const char * lang)
02027         /*@modifies h @*/
02028 {
02029     indexEntry table, entry;
02030     const char ** strArray;
02031     int length;
02032     int ghosts;
02033     int i, langNum;
02034     char * buf;
02035 
02036     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02037     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02038 
02039     if (!table && entry)
02040         return 0;               /* this shouldn't ever happen!! */
02041 
02042     if (!table && !entry) {
02043         const char * charArray[2];
02044         int count = 0;
02045         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02046             /*@-observertrans -readonlytrans@*/
02047             charArray[count++] = "C";
02048             /*@=observertrans =readonlytrans@*/
02049         } else {
02050             /*@-observertrans -readonlytrans@*/
02051             charArray[count++] = "C";
02052             /*@=observertrans =readonlytrans@*/
02053             charArray[count++] = lang;
02054         }
02055         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
02056                         &charArray, count))
02057             return 0;
02058         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02059     }
02060 
02061     if (!table)
02062         return 0;
02063     /*@-branchstate@*/
02064     if (!lang) lang = "C";
02065     /*@=branchstate@*/
02066 
02067     {   const char * l = table->data;
02068         for (langNum = 0; langNum < table->info.count; langNum++) {
02069             if (!strcmp(l, lang)) break;
02070             l += strlen(l) + 1;
02071         }
02072     }
02073 
02074     if (langNum >= table->info.count) {
02075         length = strlen(lang) + 1;
02076         if (ENTRY_IN_REGION(table)) {
02077             char * t = xmalloc(table->length + length);
02078             memcpy(t, table->data, table->length);
02079             table->data = t;
02080             table->info.offset = 0;
02081         } else
02082             table->data = xrealloc(table->data, table->length + length);
02083         memmove(((char *)table->data) + table->length, lang, length);
02084         table->length += length;
02085         table->info.count++;
02086     }
02087 
02088     if (!entry) {
02089         strArray = alloca(sizeof(*strArray) * (langNum + 1));
02090         for (i = 0; i < langNum; i++)
02091             strArray[i] = "";
02092         strArray[langNum] = string;
02093         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
02094                                 langNum + 1);
02095     } else if (langNum >= entry->info.count) {
02096         ghosts = langNum - entry->info.count;
02097         
02098         length = strlen(string) + 1 + ghosts;
02099         if (ENTRY_IN_REGION(entry)) {
02100             char * t = xmalloc(entry->length + length);
02101             memcpy(t, entry->data, entry->length);
02102             entry->data = t;
02103             entry->info.offset = 0;
02104         } else
02105             entry->data = xrealloc(entry->data, entry->length + length);
02106 
02107         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02108         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02109 
02110         entry->length += length;
02111         entry->info.count = langNum + 1;
02112     } else {
02113         char *b, *be, *e, *ee, *t;
02114         size_t bn, sn, en;
02115 
02116         /* Set beginning/end pointers to previous data */
02117         b = be = e = ee = entry->data;
02118         for (i = 0; i < table->info.count; i++) {
02119             if (i == langNum)
02120                 be = ee;
02121             ee += strlen(ee) + 1;
02122             if (i == langNum)
02123                 e  = ee;
02124         }
02125 
02126         /* Get storage for new buffer */
02127         bn = (be-b);
02128         sn = strlen(string) + 1;
02129         en = (ee-e);
02130         length = bn + sn + en;
02131         t = buf = xmalloc(length);
02132 
02133         /* Copy values into new storage */
02134         memcpy(t, b, bn);
02135         t += bn;
02136 /*@-mayaliasunique@*/
02137         memcpy(t, string, sn);
02138         t += sn;
02139         memcpy(t, e, en);
02140         t += en;
02141 /*@=mayaliasunique@*/
02142 
02143         /* Replace i18N string array */
02144         entry->length -= strlen(be) + 1;
02145         entry->length += sn;
02146         
02147         if (ENTRY_IN_REGION(entry)) {
02148             entry->info.offset = 0;
02149         } else
02150             entry->data = _free(entry->data);
02151         /*@-dependenttrans@*/
02152         entry->data = buf;
02153         /*@=dependenttrans@*/
02154     }
02155 
02156     return 0;
02157 }
02158 
02169 static
02170 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02171                         const void * p, int_32 c)
02172         /*@modifies h @*/
02173 {
02174     indexEntry entry;
02175     void * oldData;
02176     void * data;
02177     int length;
02178 
02179     /* First find the tag */
02180     entry = findEntry(h, tag, type);
02181     if (!entry)
02182         return 0;
02183 
02184     length = 0;
02185     data = grabData(type, p, c, &length);
02186     if (data == NULL || length <= 0)
02187         return 0;
02188 
02189     /* make sure entry points to the first occurence of this tag */
02190     while (entry > h->index && (entry - 1)->info.tag == tag)  
02191         entry--;
02192 
02193     /* free after we've grabbed the new data in case the two are intertwined;
02194        that's a bad idea but at least we won't break */
02195     oldData = entry->data;
02196 
02197     entry->info.count = c;
02198     entry->info.type = type;
02199     entry->data = data;
02200     entry->length = length;
02201 
02202     /*@-branchstate@*/
02203     if (ENTRY_IN_REGION(entry)) {
02204         entry->info.offset = 0;
02205     } else
02206         oldData = _free(oldData);
02207     /*@=branchstate@*/
02208 
02209     return 1;
02210 }
02211 
02214 static char escapedChar(const char ch)  /*@*/
02215 {
02216     switch (ch) {
02217     case 'a':   return '\a';
02218     case 'b':   return '\b';
02219     case 'f':   return '\f';
02220     case 'n':   return '\n';
02221     case 'r':   return '\r';
02222     case 't':   return '\t';
02223     case 'v':   return '\v';
02224     default:    return ch;
02225     }
02226 }
02227 
02234 static /*@null@*/ sprintfToken
02235 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02236         /*@modifies *format @*/
02237 {
02238     int i;
02239 
02240     if (format == NULL) return NULL;
02241 
02242     for (i = 0; i < num; i++) {
02243         switch (format[i].type) {
02244         case PTOK_ARRAY:
02245 /*@-boundswrite@*/
02246             format[i].u.array.format =
02247                 freeFormat(format[i].u.array.format,
02248                         format[i].u.array.numTokens);
02249 /*@=boundswrite@*/
02250             /*@switchbreak@*/ break;
02251         case PTOK_COND:
02252 /*@-boundswrite@*/
02253             format[i].u.cond.ifFormat =
02254                 freeFormat(format[i].u.cond.ifFormat, 
02255                         format[i].u.cond.numIfTokens);
02256             format[i].u.cond.elseFormat =
02257                 freeFormat(format[i].u.cond.elseFormat, 
02258                         format[i].u.cond.numElseTokens);
02259 /*@=boundswrite@*/
02260             /*@switchbreak@*/ break;
02261         case PTOK_NONE:
02262         case PTOK_TAG:
02263         case PTOK_STRING:
02264         default:
02265             /*@switchbreak@*/ break;
02266         }
02267     }
02268     format = _free(format);
02269     return NULL;
02270 }
02271 
02275 struct headerIterator_s {
02276 /*@unused@*/
02277     Header h;           
02278 /*@unused@*/
02279     int next_index;     
02280 };
02281 
02287 static /*@null@*/
02288 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
02289         /*@modifies hi @*/
02290 {
02291     if (hi != NULL) {
02292         hi->h = headerFree(hi->h);
02293         hi = _free(hi);
02294     }
02295     return hi;
02296 }
02297 
02303 static
02304 HeaderIterator headerInitIterator(Header h)
02305         /*@modifies h */
02306 {
02307     HeaderIterator hi = xmalloc(sizeof(*hi));
02308 
02309     headerSort(h);
02310 
02311     hi->h = headerLink(h);
02312     hi->next_index = 0;
02313     return hi;
02314 }
02315 
02325 static
02326 int headerNextIterator(HeaderIterator hi,
02327                 /*@null@*/ /*@out@*/ hTAG_t tag,
02328                 /*@null@*/ /*@out@*/ hTYP_t type,
02329                 /*@null@*/ /*@out@*/ hPTR_t * p,
02330                 /*@null@*/ /*@out@*/ hCNT_t c)
02331         /*@modifies hi, *tag, *type, *p, *c @*/
02332         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
02333                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
02334 {
02335     Header h = hi->h;
02336     int slot = hi->next_index;
02337     indexEntry entry = NULL;
02338     int rc;
02339 
02340     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02341         entry = h->index + slot;
02342         if (!ENTRY_IS_REGION(entry))
02343             break;
02344     }
02345     hi->next_index = slot;
02346     if (entry == NULL || slot >= h->indexUsed)
02347         return 0;
02348 
02349     /*@-noeffect@*/     /* LCL: no clue */
02350     hi->next_index++;
02351     /*@=noeffect@*/
02352 
02353     if (tag)
02354         *tag = entry->info.tag;
02355 
02356     rc = copyEntry(entry, type, p, c, 0);
02357 
02358     /* XXX 1 on success */
02359     return ((rc == 1) ? 1 : 0);
02360 }
02361 
02367 static /*@null@*/
02368 Header headerCopy(Header h)
02369         /*@modifies h @*/
02370 {
02371     Header nh = headerNew();
02372     HeaderIterator hi;
02373     int_32 tag, type, count;
02374     hPTR_t ptr;
02375    
02376     /*@-branchstate@*/
02377     for (hi = headerInitIterator(h);
02378         headerNextIterator(hi, &tag, &type, &ptr, &count);
02379         ptr = headerFreeData((void *)ptr, type))
02380     {
02381         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02382     }
02383     hi = headerFreeIterator(hi);
02384     /*@=branchstate@*/
02385 
02386     return headerReload(nh, HEADER_IMAGE);
02387 }
02388 
02391 typedef struct headerSprintfArgs_s {
02392     Header h;
02393     char * fmt;
02394 /*@temp@*/
02395     headerTagTableEntry tags;
02396 /*@temp@*/
02397     headerSprintfExtension exts;
02398 /*@observer@*/ /*@null@*/
02399     const char * errmsg;
02400     rpmec ec;
02401     sprintfToken format;
02402 /*@relnull@*/
02403     HeaderIterator hi;
02404 /*@owned@*/
02405     char * val;
02406     size_t vallen;
02407     size_t alloced;
02408     int numTokens;
02409     int i;
02410 } * headerSprintfArgs;
02411 
02417 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
02418         /*@modifies hsa */
02419 {
02420     sprintfTag tag =
02421         (hsa->format->type == PTOK_TAG
02422             ? &hsa->format->u.tag :
02423         (hsa->format->type == PTOK_ARRAY
02424             ? &hsa->format->u.array.format->u.tag :
02425         NULL));
02426 
02427     if (hsa != NULL) {
02428         hsa->i = 0;
02429         if (tag != NULL && tag->tag == -2)
02430             hsa->hi = headerInitIterator(hsa->h);
02431     }
02432 /*@-nullret@*/
02433     return hsa;
02434 /*@=nullret@*/
02435 }
02436 
02442 /*@null@*/
02443 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
02444         /*@modifies hsa */
02445 {
02446     sprintfToken fmt = NULL;
02447     sprintfTag tag =
02448         (hsa->format->type == PTOK_TAG
02449             ? &hsa->format->u.tag :
02450         (hsa->format->type == PTOK_ARRAY
02451             ? &hsa->format->u.array.format->u.tag :
02452         NULL));
02453 
02454     if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02455         fmt = hsa->format + hsa->i;
02456         if (hsa->hi == NULL) {
02457             hsa->i++;
02458         } else {
02459             int_32 tagno;
02460             int_32 type;
02461             int_32 count;
02462 
02463 /*@-boundswrite@*/
02464             if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02465                 fmt = NULL;
02466             tag->tag = tagno;
02467 /*@=boundswrite@*/
02468         }
02469     }
02470 
02471 /*@-dependenttrans -onlytrans@*/
02472     return fmt;
02473 /*@=dependenttrans =onlytrans@*/
02474 }
02475 
02481 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02482         /*@modifies hsa */
02483 {
02484     if (hsa != NULL) {
02485         hsa->hi = headerFreeIterator(hsa->hi);
02486         hsa->i = 0;
02487     }
02488 /*@-nullret@*/
02489     return hsa;
02490 /*@=nullret@*/
02491 }
02492 
02499 /*@dependent@*/ /*@exposed@*/
02500 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02501         /*@modifies hsa */
02502 {
02503     if ((hsa->vallen + need) >= hsa->alloced) {
02504         if (hsa->alloced <= need)
02505             hsa->alloced += need;
02506         hsa->alloced <<= 1;
02507         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02508     }
02509     return hsa->val + hsa->vallen;
02510 }
02511 
02518 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02519         /*@modifies token @*/
02520 {
02521     headerTagTableEntry tag;
02522     headerSprintfExtension ext;
02523     sprintfTag stag = (token->type == PTOK_COND
02524         ? &token->u.cond.tag : &token->u.tag);
02525 
02526     stag->fmt = NULL;
02527     stag->ext = NULL;
02528     stag->extNum = 0;
02529     stag->tag = -1;
02530 
02531     if (!strcmp(name, "*")) {
02532         stag->tag = -2;
02533         goto bingo;
02534     }
02535 
02536 /*@-branchstate@*/
02537     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02538 /*@-boundswrite@*/
02539         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02540         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02541         name = t;
02542 /*@=boundswrite@*/
02543     }
02544 /*@=branchstate@*/
02545 
02546     /* Search extensions for specific tag override. */
02547     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02548         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02549     {
02550         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02551             continue;
02552         if (!xstrcasecmp(ext->name, name)) {
02553             stag->ext = ext->u.tagFunction;
02554             stag->extNum = ext - hsa->exts;
02555             goto bingo;
02556         }
02557     }
02558 
02559     /* Search tag names. */
02560     for (tag = hsa->tags; tag->name != NULL; tag++) {
02561         if (!xstrcasecmp(tag->name, name)) {
02562             stag->tag = tag->val;
02563             goto bingo;
02564         }
02565     }
02566 
02567     return 1;
02568 
02569 bingo:
02570     /* Search extensions for specific format. */
02571     if (stag->type != NULL)
02572     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02573             ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02574     {
02575         if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02576             continue;
02577         if (!strcmp(ext->name, stag->type)) {
02578             stag->fmt = ext->u.formatFunction;
02579             break;
02580         }
02581     }
02582     return 0;
02583 }
02584 
02585 /* forward ref */
02593 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02594                 char * str, /*@out@*/char ** endPtr)
02595         /*@modifies hsa, str, token, *endPtr @*/
02596         /*@requires maxSet(endPtr) >= 0 @*/;
02597 
02607 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
02608                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02609                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
02610         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
02611         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02612                 /\ maxSet(endPtr) >= 0 @*/
02613 {
02614     char * chptr, * start, * next, * dst;
02615     sprintfToken format;
02616     sprintfToken token;
02617     int numTokens;
02618     int i;
02619     int done = 0;
02620 
02621     /* upper limit on number of individual formats */
02622     numTokens = 0;
02623     if (str != NULL)
02624     for (chptr = str; *chptr != '\0'; chptr++)
02625         if (*chptr == '%') numTokens++;
02626     numTokens = numTokens * 2 + 1;
02627 
02628     format = xcalloc(numTokens, sizeof(*format));
02629     if (endPtr) *endPtr = NULL;
02630 
02631     /*@-infloops@*/ /* LCL: can't detect done termination */
02632     dst = start = str;
02633     numTokens = 0;
02634     token = NULL;
02635     if (start != NULL)
02636     while (*start != '\0') {
02637         switch (*start) {
02638         case '%':
02639             /* handle %% */
02640             if (*(start + 1) == '%') {
02641                 if (token == NULL || token->type != PTOK_STRING) {
02642                     token = format + numTokens++;
02643                     token->type = PTOK_STRING;
02644                     /*@-temptrans -assignexpose@*/
02645                     dst = token->u.string.string = start;
02646                     /*@=temptrans =assignexpose@*/
02647                 }
02648                 start++;
02649 /*@-boundswrite@*/
02650                 *dst++ = *start++;
02651 /*@=boundswrite@*/
02652                 /*@switchbreak@*/ break;
02653             } 
02654 
02655             token = format + numTokens++;
02656 /*@-boundswrite@*/
02657             *dst++ = '\0';
02658 /*@=boundswrite@*/
02659             start++;
02660 
02661             if (*start == '|') {
02662                 char * newEnd;
02663 
02664                 start++;
02665 /*@-boundswrite@*/
02666                 if (parseExpression(hsa, token, start, &newEnd))
02667                 {
02668                     format = freeFormat(format, numTokens);
02669                     return 1;
02670                 }
02671 /*@=boundswrite@*/
02672                 start = newEnd;
02673                 /*@switchbreak@*/ break;
02674             }
02675 
02676             /*@-assignexpose@*/
02677             token->u.tag.format = start;
02678             /*@=assignexpose@*/
02679             token->u.tag.pad = 0;
02680             token->u.tag.justOne = 0;
02681             token->u.tag.arrayCount = 0;
02682 
02683             chptr = start;
02684             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02685             if (!*chptr || *chptr == '%') {
02686                 hsa->errmsg = _("missing { after %");
02687                 format = freeFormat(format, numTokens);
02688                 return 1;
02689             }
02690 
02691 /*@-boundswrite@*/
02692             *chptr++ = '\0';
02693 /*@=boundswrite@*/
02694 
02695             while (start < chptr) {
02696                 if (xisdigit(*start)) {
02697                     i = strtoul(start, &start, 10);
02698                     token->u.tag.pad += i;
02699                 } else {
02700                     start++;
02701                 }
02702             }
02703 
02704             if (*start == '=') {
02705                 token->u.tag.justOne = 1;
02706                 start++;
02707             } else if (*start == '#') {
02708                 token->u.tag.justOne = 1;
02709                 token->u.tag.arrayCount = 1;
02710                 start++;
02711             }
02712 
02713             next = start;
02714             while (*next && *next != '}') next++;
02715             if (!*next) {
02716                 hsa->errmsg = _("missing } after %{");
02717                 format = freeFormat(format, numTokens);
02718                 return 1;
02719             }
02720 /*@-boundswrite@*/
02721             *next++ = '\0';
02722 /*@=boundswrite@*/
02723 
02724             chptr = start;
02725             while (*chptr && *chptr != ':') chptr++;
02726 
02727             if (*chptr != '\0') {
02728 /*@-boundswrite@*/
02729                 *chptr++ = '\0';
02730 /*@=boundswrite@*/
02731                 if (!*chptr) {
02732                     hsa->errmsg = _("empty tag format");
02733                     format = freeFormat(format, numTokens);
02734                     return 1;
02735                 }
02736                 /*@-assignexpose@*/
02737                 token->u.tag.type = chptr;
02738                 /*@=assignexpose@*/
02739             } else {
02740                 token->u.tag.type = NULL;
02741             }
02742             
02743             if (!*start) {
02744                 hsa->errmsg = _("empty tag name");
02745                 format = freeFormat(format, numTokens);
02746                 return 1;
02747             }
02748 
02749             i = 0;
02750             token->type = PTOK_TAG;
02751 
02752             if (findTag(hsa, token, start)) {
02753                 hsa->errmsg = _("unknown tag");
02754                 format = freeFormat(format, numTokens);
02755                 return 1;
02756             }
02757 
02758             start = next;
02759             /*@switchbreak@*/ break;
02760 
02761         case '[':
02762 /*@-boundswrite@*/
02763             *dst++ = '\0';
02764             *start++ = '\0';
02765 /*@=boundswrite@*/
02766             token = format + numTokens++;
02767 
02768 /*@-boundswrite@*/
02769             if (parseFormat(hsa, start,
02770                             &token->u.array.format,
02771                             &token->u.array.numTokens,
02772                             &start, PARSER_IN_ARRAY))
02773             {
02774                 format = freeFormat(format, numTokens);
02775                 return 1;
02776             }
02777 /*@=boundswrite@*/
02778 
02779             if (!start) {
02780                 hsa->errmsg = _("] expected at end of array");
02781                 format = freeFormat(format, numTokens);
02782                 return 1;
02783             }
02784 
02785             dst = start;
02786 
02787             token->type = PTOK_ARRAY;
02788 
02789             /*@switchbreak@*/ break;
02790 
02791         case ']':
02792             if (state != PARSER_IN_ARRAY) {
02793                 hsa->errmsg = _("unexpected ]");
02794                 format = freeFormat(format, numTokens);
02795                 return 1;
02796             }
02797 /*@-boundswrite@*/
02798             *start++ = '\0';
02799 /*@=boundswrite@*/
02800             if (endPtr) *endPtr = start;
02801             done = 1;
02802             /*@switchbreak@*/ break;
02803 
02804         case '}':
02805             if (state != PARSER_IN_EXPR) {
02806                 hsa->errmsg = _("unexpected }");
02807                 format = freeFormat(format, numTokens);
02808                 return 1;
02809             }
02810 /*@-boundswrite@*/
02811             *start++ = '\0';
02812 /*@=boundswrite@*/
02813             if (endPtr) *endPtr = start;
02814             done = 1;
02815             /*@switchbreak@*/ break;
02816 
02817         default:
02818             if (token == NULL || token->type != PTOK_STRING) {
02819                 token = format + numTokens++;
02820                 token->type = PTOK_STRING;
02821                 /*@-temptrans -assignexpose@*/
02822                 dst = token->u.string.string = start;
02823                 /*@=temptrans =assignexpose@*/
02824             }
02825 
02826 /*@-boundswrite@*/
02827             if (*start == '\\') {
02828                 start++;
02829                 *dst++ = escapedChar(*start++);
02830             } else {
02831                 *dst++ = *start++;
02832             }
02833 /*@=boundswrite@*/
02834             /*@switchbreak@*/ break;
02835         }
02836         if (done)
02837             break;
02838     }
02839     /*@=infloops@*/
02840 
02841 /*@-boundswrite@*/
02842     if (dst != NULL)
02843         *dst = '\0';
02844 /*@=boundswrite@*/
02845 
02846     for (i = 0; i < numTokens; i++) {
02847         token = format + i;
02848         if (token->type == PTOK_STRING)
02849             token->u.string.len = strlen(token->u.string.string);
02850     }
02851 
02852     *numTokensPtr = numTokens;
02853     *formatPtr = format;
02854 
02855     return 0;
02856 }
02857 
02858 /*@-boundswrite@*/
02859 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02860                 char * str, /*@out@*/ char ** endPtr)
02861 {
02862     char * chptr;
02863     char * end;
02864 
02865     hsa->errmsg = NULL;
02866     chptr = str;
02867     while (*chptr && *chptr != '?') chptr++;
02868 
02869     if (*chptr != '?') {
02870         hsa->errmsg = _("? expected in expression");
02871         return 1;
02872     }
02873 
02874     *chptr++ = '\0';;
02875 
02876     if (*chptr != '{') {
02877         hsa->errmsg = _("{ expected after ? in expression");
02878         return 1;
02879     }
02880 
02881     chptr++;
02882 
02883     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
02884                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
02885         return 1;
02886 
02887     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
02888     if (!(end && *end)) {
02889         hsa->errmsg = _("} expected in expression");
02890         token->u.cond.ifFormat =
02891                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02892         return 1;
02893     }
02894 
02895     chptr = end;
02896     if (*chptr != ':' && *chptr != '|') {
02897         hsa->errmsg = _(": expected following ? subexpression");
02898         token->u.cond.ifFormat =
02899                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02900         return 1;
02901     }
02902 
02903     if (*chptr == '|') {
02904         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
02905                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02906         {
02907             token->u.cond.ifFormat =
02908                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02909             return 1;
02910         }
02911     } else {
02912         chptr++;
02913 
02914         if (*chptr != '{') {
02915             hsa->errmsg = _("{ expected after : in expression");
02916             token->u.cond.ifFormat =
02917                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02918             return 1;
02919         }
02920 
02921         chptr++;
02922 
02923         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
02924                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
02925             return 1;
02926 
02927         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
02928         if (!(end && *end)) {
02929             hsa->errmsg = _("} expected in expression");
02930             token->u.cond.ifFormat =
02931                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02932             return 1;
02933         }
02934 
02935         chptr = end;
02936         if (*chptr != '|') {
02937             hsa->errmsg = _("| expected at end of expression");
02938             token->u.cond.ifFormat =
02939                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02940             token->u.cond.elseFormat =
02941                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02942             return 1;
02943         }
02944     }
02945         
02946     chptr++;
02947 
02948     *endPtr = chptr;
02949 
02950     token->type = PTOK_COND;
02951 
02952     (void) findTag(hsa, token, str);
02953 
02954     return 0;
02955 }
02956 /*@=boundswrite@*/
02957 
02968 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
02969                 /*@out@*/ hTYP_t typeptr,
02970                 /*@out@*/ hPTR_t * data,
02971                 /*@out@*/ hCNT_t countptr,
02972                 rpmec ec)
02973         /*@modifies *typeptr, *data, *countptr, ec @*/
02974         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
02975                 /\ maxSet(countptr) >= 0 @*/
02976 {
02977     if (!ec->avail) {
02978         if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
02979             return 1;
02980         ec->avail = 1;
02981     }
02982 
02983     if (typeptr) *typeptr = ec->type;
02984     if (data) *data = ec->data;
02985     if (countptr) *countptr = ec->count;
02986 
02987     return 0;
02988 }
02989 
02996 /*@observer@*/ /*@null@*/
02997 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
02998         /*@modifies hsa @*/
02999 {
03000     char * val = NULL;
03001     size_t need = 0;
03002     char * t, * te;
03003     char buf[20];
03004     int_32 count, type;
03005     hPTR_t data;
03006     unsigned int intVal;
03007     const char ** strarray;
03008     int datafree = 0;
03009     int countBuf;
03010 
03011     memset(buf, 0, sizeof(buf));
03012     if (tag->ext) {
03013 /*@-boundswrite -branchstate @*/
03014         if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03015         {
03016             count = 1;
03017             type = RPM_STRING_TYPE;     
03018             data = "(none)";
03019         }
03020 /*@=boundswrite =branchstate @*/
03021     } else {
03022 /*@-boundswrite -branchstate @*/
03023         if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03024             count = 1;
03025             type = RPM_STRING_TYPE;     
03026             data = "(none)";
03027         }
03028 /*@=boundswrite =branchstate @*/
03029 
03030         /* XXX this test is unnecessary, array sizes are checked */
03031         switch (type) {
03032         default:
03033             if (element >= count) {
03034                 /*@-modobserver -observertrans@*/
03035                 data = headerFreeData(data, type);
03036                 /*@=modobserver =observertrans@*/
03037 
03038                 hsa->errmsg = _("(index out of range)");
03039                 return NULL;
03040             }
03041             break;
03042         case RPM_BIN_TYPE:
03043         case RPM_STRING_TYPE:
03044             break;
03045         }
03046         datafree = 1;
03047     }
03048 
03049     if (tag->arrayCount) {
03050         /*@-branchstate -observertrans -modobserver@*/
03051         if (datafree)
03052             data = headerFreeData(data, type);
03053         /*@=branchstate =observertrans =modobserver@*/
03054 
03055         countBuf = count;
03056         data = &countBuf;
03057         count = 1;
03058         type = RPM_INT32_TYPE;
03059     }
03060 
03061 /*@-boundswrite@*/
03062     (void) stpcpy( stpcpy(buf, "%"), tag->format);
03063 /*@=boundswrite@*/
03064 
03065     /*@-branchstate@*/
03066     if (data)
03067     switch (type) {
03068     case RPM_STRING_ARRAY_TYPE:
03069         strarray = (const char **)data;
03070 
03071         if (tag->fmt)
03072             val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03073 
03074         if (val) {
03075             need = strlen(val);
03076         } else {
03077             need = strlen(strarray[element]) + tag->pad + 20;
03078             val = xmalloc(need+1);
03079             strcat(buf, "s");
03080             /*@-formatconst@*/
03081             sprintf(val, buf, strarray[element]);
03082             /*@=formatconst@*/
03083         }
03084 
03085         break;
03086 
03087     case RPM_STRING_TYPE:
03088         if (tag->fmt)
03089             val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad,  0);
03090 
03091         if (val) {
03092             need = strlen(val);
03093         } else {
03094             need = strlen(data) + tag->pad + 20;
03095             val = xmalloc(need+1);
03096             strcat(buf, "s");
03097             /*@-formatconst@*/
03098             sprintf(val, buf, data);
03099             /*@=formatconst@*/
03100         }
03101         break;
03102 
03103     case RPM_CHAR_TYPE:
03104     case RPM_INT8_TYPE:
03105     case RPM_INT16_TYPE:
03106     case RPM_INT32_TYPE:
03107         switch (type) {
03108         case RPM_CHAR_TYPE:     
03109         case RPM_INT8_TYPE:
03110             intVal = *(((int_8 *) data) + element);
03111             /*@innerbreak@*/ break;
03112         case RPM_INT16_TYPE:
03113             intVal = *(((uint_16 *) data) + element);
03114             /*@innerbreak@*/ break;
03115         default:                /* keep -Wall quiet */
03116         case RPM_INT32_TYPE:
03117             intVal = *(((int_32 *) data) + element);
03118             /*@innerbreak@*/ break;
03119         }
03120 
03121         if (tag->fmt)
03122             val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03123 
03124         if (val) {
03125             need = strlen(val);
03126         } else {
03127             need = 10 + tag->pad + 20;
03128             val = xmalloc(need+1);
03129             strcat(buf, "d");
03130             /*@-formatconst@*/
03131             sprintf(val, buf, intVal);
03132             /*@=formatconst@*/
03133         }
03134         break;
03135 
03136     case RPM_BIN_TYPE:
03137         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
03138         if (tag->fmt)
03139             val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03140 
03141         if (val) {
03142             need = strlen(val);
03143         } else {
03144 #ifdef  NOTYET
03145             val = memcpy(xmalloc(count), data, count);
03146 #else
03147             /* XXX format string not used */
03148             static char hex[] = "0123456789abcdef";
03149             const char * s = data;
03150 
03151 /*@-boundswrite@*/
03152             need = 2*count + tag->pad;
03153             val = t = xmalloc(need+1);
03154             while (count-- > 0) {
03155                 unsigned int i;
03156                 i = *s++;
03157                 *t++ = hex[ (i >> 4) & 0xf ];
03158                 *t++ = hex[ (i     ) & 0xf ];
03159             }
03160             *t = '\0';
03161 /*@=boundswrite@*/
03162 #endif
03163         }
03164         break;
03165 
03166     default:
03167         need = sizeof("(unknown type)") - 1;
03168         val = xstrdup("(unknown type)");
03169         break;
03170     }
03171     /*@=branchstate@*/
03172 
03173     /*@-branchstate -observertrans -modobserver@*/
03174     if (datafree)
03175         data = headerFreeData(data, type);
03176     /*@=branchstate =observertrans =modobserver@*/
03177 
03178     /*@-branchstate@*/
03179     if (val && need > 0) {
03180         t = hsaReserve(hsa, need);
03181 /*@-boundswrite@*/
03182         te = stpcpy(t, val);
03183 /*@=boundswrite@*/
03184         hsa->vallen += (te - t);
03185         val = _free(val);
03186     }
03187     /*@=branchstate@*/
03188 
03189     return (hsa->val + hsa->vallen);
03190 }
03191 
03198 /*@observer@*/
03199 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03200                 int element)
03201         /*@modifies hsa @*/
03202 {
03203     char * t, * te;
03204     int i, j;
03205     int numElements;
03206     int_32 type;
03207     int_32 count;
03208     sprintfToken spft;
03209     int condNumFormats;
03210     size_t need;
03211 
03212     /* we assume the token and header have been validated already! */
03213 
03214     switch (token->type) {
03215     case PTOK_NONE:
03216         break;
03217 
03218     case PTOK_STRING:
03219         need = token->u.string.len;
03220         if (need == 0) break;
03221         t = hsaReserve(hsa, need);
03222 /*@-boundswrite@*/
03223         te = stpcpy(t, token->u.string.string);
03224 /*@=boundswrite@*/
03225         hsa->vallen += (te - t);
03226         break;
03227 
03228     case PTOK_TAG:
03229         t = hsa->val + hsa->vallen;
03230         te = formatValue(hsa, &token->u.tag,
03231                         (token->u.tag.justOne ? 0 : element));
03232         if (te == NULL)
03233             return NULL;
03234         break;
03235 
03236     case PTOK_COND:
03237         if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03238             spft = token->u.cond.ifFormat;
03239             condNumFormats = token->u.cond.numIfTokens;
03240         } else {
03241             spft = token->u.cond.elseFormat;
03242             condNumFormats = token->u.cond.numElseTokens;
03243         }
03244 
03245         need = condNumFormats * 20;
03246         if (spft == NULL || need == 0) break;
03247 
03248         t = hsaReserve(hsa, need);
03249         for (i = 0; i < condNumFormats; i++, spft++) {
03250             te = singleSprintf(hsa, spft, element);
03251             if (te == NULL)
03252                 return NULL;
03253         }
03254         break;
03255 
03256     case PTOK_ARRAY:
03257         numElements = -1;
03258         spft = token->u.array.format;
03259         for (i = 0; i < token->u.array.numTokens; i++, spft++)
03260         {
03261             if (spft->type != PTOK_TAG ||
03262                 spft->u.tag.arrayCount ||
03263                 spft->u.tag.justOne) continue;
03264 
03265             if (spft->u.tag.ext) {
03266 /*@-boundswrite@*/
03267                 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count, 
03268                                  hsa->ec + spft->u.tag.extNum))
03269                      continue;
03270 /*@=boundswrite@*/
03271             } else {
03272 /*@-boundswrite@*/
03273                 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03274                     continue;
03275 /*@=boundswrite@*/
03276             } 
03277 
03278             if (type == RPM_BIN_TYPE)
03279                 count = 1;      /* XXX count abused as no. of bytes. */
03280 
03281             if (numElements > 1 && count != numElements)
03282             switch (type) {
03283             default:
03284                 hsa->errmsg =
03285                         _("array iterator used with different sized arrays");
03286                 return NULL;
03287                 /*@notreached@*/ /*@switchbreak@*/ break;
03288             case RPM_BIN_TYPE:
03289             case RPM_STRING_TYPE:
03290                 /*@switchbreak@*/ break;
03291             }
03292             if (count > numElements)
03293                 numElements = count;
03294         }
03295 
03296         if (numElements == -1) {
03297             need = sizeof("(none)") - 1;
03298             t = hsaReserve(hsa, need);
03299 /*@-boundswrite@*/
03300             te = stpcpy(t, "(none)");
03301 /*@=boundswrite@*/
03302             hsa->vallen += (te - t);
03303         } else {
03304             int isxml;
03305 
03306             need = numElements * token->u.array.numTokens * 10;
03307             if (need == 0) break;
03308 
03309             spft = token->u.array.format;
03310             isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03311                 !strcmp(spft->u.tag.type, "xml"));
03312 
03313             if (isxml) {
03314                 const char * tagN = tagName(spft->u.tag.tag);
03315 
03316                 need = strlen(tagN) + sizeof("  <rpmTag name=\"\">\n") - 1;
03317                 t = hsaReserve(hsa, need);
03318 /*@-boundswrite@*/
03319                 te = stpcpy(t, "  <rpmTag name=\"");
03320                 te = stpcpy(te, tagN);
03321                 te = stpcpy(te, "\">\n");
03322 /*@=boundswrite@*/
03323                 hsa->vallen += (te - t);
03324             }
03325 
03326             t = hsaReserve(hsa, need);
03327             for (j = 0; j < numElements; j++) {
03328                 spft = token->u.array.format;
03329                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03330                     te = singleSprintf(hsa, spft, j);
03331                     if (te == NULL)
03332                         return NULL;
03333                 }
03334             }
03335 
03336             if (isxml) {
03337                 need = sizeof("  </rpmTag>\n") - 1;
03338                 t = hsaReserve(hsa, need);
03339 /*@-boundswrite@*/
03340                 te = stpcpy(t, "  </rpmTag>\n");
03341 /*@=boundswrite@*/
03342                 hsa->vallen += (te - t);
03343             }
03344 
03345         }
03346         break;
03347     }
03348 
03349     return (hsa->val + hsa->vallen);
03350 }
03351 
03357 static /*@only@*/ rpmec
03358 rpmecNew(const headerSprintfExtension exts)
03359         /*@*/
03360 {
03361     headerSprintfExtension ext;
03362     rpmec ec;
03363     int i = 0;
03364 
03365     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03366         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03367     {
03368         i++;
03369     }
03370 
03371     ec = xcalloc(i, sizeof(*ec));
03372     return ec;
03373 }
03374 
03381 static /*@null@*/ rpmec
03382 rpmecFree(const headerSprintfExtension exts, /*@only@*/ rpmec ec)
03383         /*@modifies ec @*/
03384 {
03385     headerSprintfExtension ext;
03386     int i = 0;
03387 
03388     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03389         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03390     {
03391 /*@-boundswrite@*/
03392         if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03393 /*@=boundswrite@*/
03394         i++;
03395     }
03396 
03397     ec = _free(ec);
03398     return NULL;
03399 }
03400 
03412 static /*@only@*/ /*@null@*/
03413 char * headerSprintf(Header h, const char * fmt,
03414                      const struct headerTagTableEntry_s * tbltags,
03415                      const struct headerSprintfExtension_s * extensions,
03416                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03417         /*@modifies h, *errmsg @*/
03418         /*@requires maxSet(errmsg) >= 0 @*/
03419 {
03420     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03421     sprintfToken nextfmt;
03422     sprintfTag tag;
03423     char * t, * te;
03424     int isxml;
03425     int need;
03426  
03427     hsa->h = headerLink(h);
03428     hsa->fmt = xstrdup(fmt);
03429 /*@-castexpose@*/       /* FIX: legacy API shouldn't change. */
03430     hsa->exts = (headerSprintfExtension) extensions;
03431     hsa->tags = (headerTagTableEntry) tbltags;
03432 /*@=castexpose@*/
03433     hsa->errmsg = NULL;
03434 
03435 /*@-boundswrite@*/
03436     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03437         goto exit;
03438 /*@=boundswrite@*/
03439 
03440     hsa->ec = rpmecNew(hsa->exts);
03441     hsa->val = xstrdup("");
03442 
03443     tag =
03444         (hsa->format->type == PTOK_TAG
03445             ? &hsa->format->u.tag :
03446         (hsa->format->type == PTOK_ARRAY
03447             ? &hsa->format->u.array.format->u.tag :
03448         NULL));
03449     isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03450 
03451     if (isxml) {
03452         need = sizeof("<rpmHeader>\n") - 1;
03453         t = hsaReserve(hsa, need);
03454 /*@-boundswrite@*/
03455         te = stpcpy(t, "<rpmHeader>\n");
03456 /*@=boundswrite@*/
03457         hsa->vallen += (te - t);
03458     }
03459 
03460     hsa = hsaInit(hsa);
03461     while ((nextfmt = hsaNext(hsa)) != NULL) {
03462         te = singleSprintf(hsa, nextfmt, 0);
03463         if (te == NULL) {
03464             hsa->val = _free(hsa->val);
03465             break;
03466         }
03467     }
03468     hsa = hsaFini(hsa);
03469 
03470     if (isxml) {
03471         need = sizeof("</rpmHeader>\n") - 1;
03472         t = hsaReserve(hsa, need);
03473 /*@-boundswrite@*/
03474         te = stpcpy(t, "</rpmHeader>\n");
03475 /*@=boundswrite@*/
03476         hsa->vallen += (te - t);
03477     }
03478 
03479     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03480         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
03481 
03482     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03483     hsa->format = freeFormat(hsa->format, hsa->numTokens);
03484 
03485 exit:
03486 /*@-dependenttrans -observertrans @*/
03487     if (errmsg)
03488         *errmsg = hsa->errmsg;
03489 /*@=dependenttrans =observertrans @*/
03490     hsa->h = headerFree(hsa->h);
03491     hsa->fmt = _free(hsa->fmt);
03492     return hsa->val;
03493 }
03494 
03503 static char * octalFormat(int_32 type, hPTR_t data, 
03504                 char * formatPrefix, int padding, /*@unused@*/int element)
03505         /*@modifies formatPrefix @*/
03506 {
03507     char * val;
03508 
03509     if (type != RPM_INT32_TYPE) {
03510         val = xstrdup(_("(not a number)"));
03511     } else {
03512         val = xmalloc(20 + padding);
03513 /*@-boundswrite@*/
03514         strcat(formatPrefix, "o");
03515 /*@=boundswrite@*/
03516         /*@-formatconst@*/
03517         sprintf(val, formatPrefix, *((int_32 *) data));
03518         /*@=formatconst@*/
03519     }
03520 
03521     return val;
03522 }
03523 
03532 static char * hexFormat(int_32 type, hPTR_t data, 
03533                 char * formatPrefix, int padding, /*@unused@*/int element)
03534         /*@modifies formatPrefix @*/
03535 {
03536     char * val;
03537 
03538     if (type != RPM_INT32_TYPE) {
03539         val = xstrdup(_("(not a number)"));
03540     } else {
03541         val = xmalloc(20 + padding);
03542 /*@-boundswrite@*/
03543         strcat(formatPrefix, "x");
03544 /*@=boundswrite@*/
03545         /*@-formatconst@*/
03546         sprintf(val, formatPrefix, *((int_32 *) data));
03547         /*@=formatconst@*/
03548     }
03549 
03550     return val;
03551 }
03552 
03555 static char * realDateFormat(int_32 type, hPTR_t data, 
03556                 char * formatPrefix, int padding, /*@unused@*/int element,
03557                 const char * strftimeFormat)
03558         /*@modifies formatPrefix @*/
03559 {
03560     char * val;
03561 
03562     if (type != RPM_INT32_TYPE) {
03563         val = xstrdup(_("(not a number)"));
03564     } else {
03565         struct tm * tstruct;
03566         char buf[50];
03567 
03568         val = xmalloc(50 + padding);
03569 /*@-boundswrite@*/
03570         strcat(formatPrefix, "s");
03571 /*@=boundswrite@*/
03572 
03573         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03574         {   time_t dateint = *((int_32 *) data);
03575             tstruct = localtime(&dateint);
03576         }
03577         buf[0] = '\0';
03578         if (tstruct)
03579             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03580         /*@-formatconst@*/
03581         sprintf(val, formatPrefix, buf);
03582         /*@=formatconst@*/
03583     }
03584 
03585     return val;
03586 }
03587 
03596 static char * dateFormat(int_32 type, hPTR_t data, 
03597                          char * formatPrefix, int padding, int element)
03598         /*@modifies formatPrefix @*/
03599 {
03600     return realDateFormat(type, data, formatPrefix, padding, element,
03601                         _("%c"));
03602 }
03603 
03612 static char * dayFormat(int_32 type, hPTR_t data, 
03613                          char * formatPrefix, int padding, int element)
03614         /*@modifies formatPrefix @*/
03615 {
03616     return realDateFormat(type, data, formatPrefix, padding, element, 
03617                           _("%a %b %d %Y"));
03618 }
03619 
03628 static char * shescapeFormat(int_32 type, hPTR_t data, 
03629                 char * formatPrefix, int padding, /*@unused@*/int element)
03630         /*@modifies formatPrefix @*/
03631 {
03632     char * result, * dst, * src, * buf;
03633 
03634     if (type == RPM_INT32_TYPE) {
03635         result = xmalloc(padding + 20);
03636 /*@-boundswrite@*/
03637         strcat(formatPrefix, "d");
03638 /*@=boundswrite@*/
03639         /*@-formatconst@*/
03640         sprintf(result, formatPrefix, *((int_32 *) data));
03641         /*@=formatconst@*/
03642     } else {
03643         buf = alloca(strlen(data) + padding + 2);
03644 /*@-boundswrite@*/
03645         strcat(formatPrefix, "s");
03646 /*@=boundswrite@*/
03647         /*@-formatconst@*/
03648         sprintf(buf, formatPrefix, data);
03649         /*@=formatconst@*/
03650 
03651 /*@-boundswrite@*/
03652         result = dst = xmalloc(strlen(buf) * 4 + 3);
03653         *dst++ = '\'';
03654         for (src = buf; *src != '\0'; src++) {
03655             if (*src == '\'') {
03656                 *dst++ = '\'';
03657                 *dst++ = '\\';
03658                 *dst++ = '\'';
03659                 *dst++ = '\'';
03660             } else {
03661                 *dst++ = *src;
03662             }
03663         }
03664         *dst++ = '\'';
03665         *dst = '\0';
03666 /*@=boundswrite@*/
03667 
03668     }
03669 
03670     return result;
03671 }
03672 
03673 /*@-type@*/ /* FIX: cast? */
03674 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03675     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03676     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03677     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03678     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03679     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03680     { HEADER_EXT_LAST, NULL, { NULL } }
03681 };
03682 /*@=type@*/
03683 
03690 static
03691 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03692         /*@modifies headerTo @*/
03693 {
03694     int * p;
03695 
03696     if (headerFrom == headerTo)
03697         return;
03698 
03699     for (p = tagstocopy; *p != 0; p++) {
03700         char *s;
03701         int_32 type;
03702         int_32 count;
03703         if (headerIsEntry(headerTo, *p))
03704             continue;
03705 /*@-boundswrite@*/
03706         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03707                                 (hPTR_t *) &s, &count))
03708             continue;
03709 /*@=boundswrite@*/
03710         (void) headerAddEntry(headerTo, *p, type, s, count);
03711         s = headerFreeData(s, type);
03712     }
03713 }
03714 
03715 /*@observer@*/ /*@unchecked@*/
03716 static struct HV_s hdrVec1 = {
03717     headerLink,
03718     headerUnlink,
03719     headerFree,
03720     headerNew,
03721     headerSort,
03722     headerUnsort,
03723     headerSizeof,
03724     headerUnload,
03725     headerReload,
03726     headerCopy,
03727     headerLoad,
03728     headerCopyLoad,
03729     headerRead,
03730     headerWrite,
03731     headerIsEntry,
03732     headerFreeTag,
03733     headerGetEntry,
03734     headerGetEntryMinMemory,
03735     headerAddEntry,
03736     headerAppendEntry,
03737     headerAddOrAppendEntry,
03738     headerAddI18NString,
03739     headerModifyEntry,
03740     headerRemoveEntry,
03741     headerSprintf,
03742     headerCopyTags,
03743     headerFreeIterator,
03744     headerInitIterator,
03745     headerNextIterator,
03746     NULL, NULL,
03747     1
03748 };
03749 
03750 /*@-compmempass -redef@*/
03751 /*@observer@*/ /*@unchecked@*/
03752 HV_t hdrVec = &hdrVec1;
03753 /*@=compmempass =redef@*/

Generated on Sun Aug 20 07:15:07 2006 for rpm by  doxygen 1.3.9.1