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     if (regionid > 0)
00497        return -1;
00498 /*@-boundswrite@*/
00499     memset(&ieprev, 0, sizeof(ieprev));
00500 /*@=boundswrite@*/
00501     for (; il > 0; il--, pe++) {
00502         struct indexEntry_s ie;
00503         int_32 type;
00504 
00505         ie.info.tag = ntohl(pe->tag);
00506         ie.info.type = ntohl(pe->type);
00507         ie.info.count = ntohl(pe->count);
00508         ie.info.offset = ntohl(pe->offset);
00509 
00510         if (hdrchkType(ie.info.type))
00511             return -1;
00512         if (hdrchkData(ie.info.count))
00513             return -1;
00514         if (hdrchkData(ie.info.offset))
00515             return -1;
00516 /*@-boundsread@*/
00517         if (hdrchkAlign(ie.info.type, ie.info.offset))
00518             return -1;
00519 /*@=boundsread@*/
00520 
00521         ie.data = t = dataStart + ie.info.offset;
00522         if (dataEnd && t >= dataEnd)
00523             return -1;
00524 
00525         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00526         if (ie.length < 0 || hdrchkData(ie.length))
00527             return -1;
00528 
00529         ie.rdlen = 0;
00530 
00531         if (entry) {
00532             ie.info.offset = regionid;
00533 /*@-boundswrite@*/
00534             *entry = ie;        /* structure assignment */
00535 /*@=boundswrite@*/
00536             entry++;
00537         }
00538 
00539         /* Alignment */
00540         type = ie.info.type;
00541 /*@-boundsread@*/
00542         if (typeSizes[type] > 1) {
00543             unsigned diff;
00544             diff = typeSizes[type] - (dl % typeSizes[type]);
00545             if (diff != typeSizes[type]) {
00546                 dl += diff;
00547                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00548                     ieprev.length += diff;
00549             }
00550         }
00551 /*@=boundsread@*/
00552         tdel = (tprev ? (t - tprev) : 0);
00553         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00554             tdel = ieprev.length;
00555 
00556         if (ie.info.tag >= HEADER_I18NTABLE) {
00557             tprev = t;
00558         } else {
00559             tprev = dataStart;
00560             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00561             /*@-sizeoftype@*/
00562             if (ie.info.tag == HEADER_IMAGE)
00563                 tprev -= REGION_TAG_COUNT;
00564             /*@=sizeoftype@*/
00565         }
00566 
00567         /* Perform endian conversions */
00568         switch (ntohl(pe->type)) {
00569 /*@-bounds@*/
00570         case RPM_INT32_TYPE:
00571         {   int_32 * it = (int_32 *)t;
00572             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00573                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00574                     return -1;
00575                 *it = htonl(*it);
00576             }
00577             t = (char *) it;
00578         }   /*@switchbreak@*/ break;
00579         case RPM_INT16_TYPE:
00580         {   int_16 * it = (int_16 *) t;
00581             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00582                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00583                     return -1;
00584                 *it = htons(*it);
00585             }
00586             t = (char *) it;
00587         }   /*@switchbreak@*/ break;
00588 /*@=bounds@*/
00589         default:
00590             t += ie.length;
00591             /*@switchbreak@*/ break;
00592         }
00593 
00594         dl += ie.length;
00595         tl += tdel;
00596         ieprev = ie;    /* structure assignment */
00597 
00598     }
00599     tdel = (tprev ? (t - tprev) : 0);
00600     tl += tdel;
00601 
00602     /* XXX
00603      * There are two hacks here:
00604      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00605      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00606      */
00607     /*@-sizeoftype@*/
00608     if (tl+REGION_TAG_COUNT == dl)
00609         tl += REGION_TAG_COUNT;
00610     /*@=sizeoftype@*/
00611 
00612     return dl;
00613 }
00614 
00620 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00621                 /*@out@*/ int * lengthPtr)
00622         /*@modifies h, *lengthPtr @*/
00623         /*@requires maxSet(lengthPtr) >= 0 @*/
00624         /*@ensures maxRead(result) == (*lengthPtr) @*/
00625 {
00626     int_32 * ei = NULL;
00627     entryInfo pe;
00628     char * dataStart;
00629     char * te;
00630     unsigned pad;
00631     unsigned len;
00632     int_32 il = 0;
00633     int_32 dl = 0;
00634     indexEntry entry; 
00635     int_32 type;
00636     int i;
00637     int drlen, ndribbles;
00638     int driplen, ndrips;
00639     int legacy = 0;
00640 
00641     /* Sort entries by (offset,tag). */
00642     headerUnsort(h);
00643 
00644     /* Compute (il,dl) for all tags, including those deleted in region. */
00645     pad = 0;
00646     drlen = ndribbles = driplen = ndrips = 0;
00647     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00648         if (ENTRY_IS_REGION(entry)) {
00649             int_32 rdl = -entry->info.offset;   /* negative offset */
00650             int_32 ril = rdl/sizeof(*pe);
00651             int rid = entry->info.offset;
00652 
00653             il += ril;
00654             dl += entry->rdlen + entry->info.count;
00655             /* XXX Legacy regions do not include the region tag and data. */
00656             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00657                 il += 1;
00658 
00659             /* Skip rest of entries in region, but account for dribbles. */
00660             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00661                 if (entry->info.offset <= rid)
00662                     /*@innercontinue@*/ continue;
00663 
00664                 /* Alignment */
00665                 type = entry->info.type;
00666                 if (typeSizes[type] > 1) {
00667                     unsigned diff;
00668                     diff = typeSizes[type] - (dl % typeSizes[type]);
00669                     if (diff != typeSizes[type]) {
00670                         drlen += diff;
00671                         pad += diff;
00672                         dl += diff;
00673                     }
00674                 }
00675 
00676                 ndribbles++;
00677                 il++;
00678                 drlen += entry->length;
00679                 dl += entry->length;
00680             }
00681             i--;
00682             entry--;
00683             continue;
00684         }
00685 
00686         /* Ignore deleted drips. */
00687         if (entry->data == NULL || entry->length <= 0)
00688             continue;
00689 
00690         /* Alignment */
00691         type = entry->info.type;
00692         if (typeSizes[type] > 1) {
00693             unsigned diff;
00694             diff = typeSizes[type] - (dl % typeSizes[type]);
00695             if (diff != typeSizes[type]) {
00696                 driplen += diff;
00697                 pad += diff;
00698                 dl += diff;
00699             } else
00700                 diff = 0;
00701         }
00702 
00703         ndrips++;
00704         il++;
00705         driplen += entry->length;
00706         dl += entry->length;
00707     }
00708 
00709     /* Sanity checks on header intro. */
00710     if (hdrchkTags(il) || hdrchkData(dl))
00711         goto errxit;
00712 
00713     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00714 
00715 /*@-boundswrite@*/
00716     ei = xmalloc(len);
00717     ei[0] = htonl(il);
00718     ei[1] = htonl(dl);
00719 /*@=boundswrite@*/
00720 
00721     pe = (entryInfo) &ei[2];
00722     dataStart = te = (char *) (pe + il);
00723 
00724     pad = 0;
00725     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00726         const char * src;
00727 char *t;
00728         int count;
00729         int rdlen;
00730 
00731         if (entry->data == NULL || entry->length <= 0)
00732             continue;
00733 
00734 t = te;
00735         pe->tag = htonl(entry->info.tag);
00736         pe->type = htonl(entry->info.type);
00737         pe->count = htonl(entry->info.count);
00738 
00739         if (ENTRY_IS_REGION(entry)) {
00740             int_32 rdl = -entry->info.offset;   /* negative offset */
00741             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00742             int rid = entry->info.offset;
00743 
00744             src = (char *)entry->data;
00745             rdlen = entry->rdlen;
00746 
00747             /* XXX Legacy regions do not include the region tag and data. */
00748             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00749                 int_32 stei[4];
00750 
00751                 legacy = 1;
00752 /*@-boundswrite@*/
00753                 memcpy(pe+1, src, rdl);
00754                 memcpy(te, src + rdl, rdlen);
00755 /*@=boundswrite@*/
00756                 te += rdlen;
00757 
00758                 pe->offset = htonl(te - dataStart);
00759                 stei[0] = pe->tag;
00760                 stei[1] = pe->type;
00761                 stei[2] = htonl(-rdl-entry->info.count);
00762                 stei[3] = pe->count;
00763 /*@-boundswrite@*/
00764                 memcpy(te, stei, entry->info.count);
00765 /*@=boundswrite@*/
00766                 te += entry->info.count;
00767                 ril++;
00768                 rdlen += entry->info.count;
00769 
00770                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00771                 if (count != rdlen)
00772                     goto errxit;
00773 
00774             } else {
00775 
00776 /*@-boundswrite@*/
00777                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00778                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00779 /*@=boundswrite@*/
00780                 te += rdlen;
00781                 {   /*@-castexpose@*/
00782                     entryInfo se = (entryInfo)src;
00783                     /*@=castexpose@*/
00784                     int off = ntohl(se->offset);
00785                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00786                 }
00787                 te += entry->info.count + drlen;
00788 
00789                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00790                 if (count != (rdlen + entry->info.count + drlen))
00791                     goto errxit;
00792             }
00793 
00794             /* Skip rest of entries in region. */
00795             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00796                 i++;
00797                 entry++;
00798             }
00799             i--;
00800             entry--;
00801             pe += ril;
00802             continue;
00803         }
00804 
00805         /* Ignore deleted drips. */
00806         if (entry->data == NULL || entry->length <= 0)
00807             continue;
00808 
00809         /* Alignment */
00810         type = entry->info.type;
00811         if (typeSizes[type] > 1) {
00812             unsigned diff;
00813             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00814             if (diff != typeSizes[type]) {
00815 /*@-boundswrite@*/
00816                 memset(te, 0, diff);
00817 /*@=boundswrite@*/
00818                 te += diff;
00819                 pad += diff;
00820             }
00821         }
00822 
00823         pe->offset = htonl(te - dataStart);
00824 
00825         /* copy data w/ endian conversions */
00826 /*@-boundswrite@*/
00827         switch (entry->info.type) {
00828         case RPM_INT32_TYPE:
00829             count = entry->info.count;
00830             src = entry->data;
00831             while (count--) {
00832                 *((int_32 *)te) = htonl(*((int_32 *)src));
00833                 /*@-sizeoftype@*/
00834                 te += sizeof(int_32);
00835                 src += sizeof(int_32);
00836                 /*@=sizeoftype@*/
00837             }
00838             /*@switchbreak@*/ break;
00839 
00840         case RPM_INT16_TYPE:
00841             count = entry->info.count;
00842             src = entry->data;
00843             while (count--) {
00844                 *((int_16 *)te) = htons(*((int_16 *)src));
00845                 /*@-sizeoftype@*/
00846                 te += sizeof(int_16);
00847                 src += sizeof(int_16);
00848                 /*@=sizeoftype@*/
00849             }
00850             /*@switchbreak@*/ break;
00851 
00852         default:
00853             memcpy(te, entry->data, entry->length);
00854             te += entry->length;
00855             /*@switchbreak@*/ break;
00856         }
00857 /*@=boundswrite@*/
00858         pe++;
00859     }
00860    
00861     /* Insure that there are no memcpy underruns/overruns. */
00862     if (((char *)pe) != dataStart)
00863         goto errxit;
00864     if ((((char *)ei)+len) != te)
00865         goto errxit;
00866 
00867     if (lengthPtr)
00868         *lengthPtr = len;
00869 
00870     h->flags &= ~HEADERFLAG_SORTED;
00871     headerSort(h);
00872 
00873     return (void *) ei;
00874 
00875 errxit:
00876     /*@-usereleased@*/
00877     ei = _free(ei);
00878     /*@=usereleased@*/
00879     return (void *) ei;
00880 }
00881 
00887 static /*@only@*/ /*@null@*/
00888 void * headerUnload(Header h)
00889         /*@modifies h @*/
00890 {
00891     int length;
00892 /*@-boundswrite@*/
00893     void * uh = doHeaderUnload(h, &length);
00894 /*@=boundswrite@*/
00895     return uh;
00896 }
00897 
00905 static /*@null@*/
00906 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00907         /*@modifies h @*/
00908 {
00909     indexEntry entry, entry2, last;
00910     struct indexEntry_s key;
00911 
00912     if (h == NULL) return NULL;
00913     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00914 
00915     key.info.tag = tag;
00916 
00917 /*@-boundswrite@*/
00918     entry2 = entry = 
00919         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00920 /*@=boundswrite@*/
00921     if (entry == NULL)
00922         return NULL;
00923 
00924     if (type == RPM_NULL_TYPE)
00925         return entry;
00926 
00927     /* look backwards */
00928     while (entry->info.tag == tag && entry->info.type != type &&
00929            entry > h->index) entry--;
00930 
00931     if (entry->info.tag == tag && entry->info.type == type)
00932         return entry;
00933 
00934     last = h->index + h->indexUsed;
00935     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00936     while (entry2->info.tag == tag && entry2->info.type != type &&
00937            entry2 < last) entry2++;
00938     /*@=usereleased@*/
00939 
00940     if (entry->info.tag == tag && entry->info.type == type)
00941         return entry;
00942 
00943     return NULL;
00944 }
00945 
00955 static
00956 int headerRemoveEntry(Header h, int_32 tag)
00957         /*@modifies h @*/
00958 {
00959     indexEntry last = h->index + h->indexUsed;
00960     indexEntry entry, first;
00961     int ne;
00962 
00963     entry = findEntry(h, tag, RPM_NULL_TYPE);
00964     if (!entry) return 1;
00965 
00966     /* Make sure entry points to the first occurence of this tag. */
00967     while (entry > h->index && (entry - 1)->info.tag == tag)  
00968         entry--;
00969 
00970     /* Free data for tags being removed. */
00971     for (first = entry; first < last; first++) {
00972         void * data;
00973         if (first->info.tag != tag)
00974             break;
00975         data = first->data;
00976         first->data = NULL;
00977         first->length = 0;
00978         if (ENTRY_IN_REGION(first))
00979             continue;
00980         data = _free(data);
00981     }
00982 
00983     ne = (first - entry);
00984     if (ne > 0) {
00985         h->indexUsed -= ne;
00986         ne = last - first;
00987 /*@-boundswrite@*/
00988         if (ne > 0)
00989             memmove(entry, first, (ne * sizeof(*entry)));
00990 /*@=boundswrite@*/
00991     }
00992 
00993     return 0;
00994 }
00995 
01001 static /*@null@*/
01002 Header headerLoad(/*@kept@*/ void * uh)
01003         /*@modifies uh @*/
01004 {
01005     int_32 * ei = (int_32 *) uh;
01006     int_32 il = ntohl(ei[0]);           /* index length */
01007     int_32 dl = ntohl(ei[1]);           /* data length */
01008     /*@-sizeoftype@*/
01009     size_t pvlen = sizeof(il) + sizeof(dl) +
01010                (il * sizeof(struct entryInfo_s)) + dl;
01011     /*@=sizeoftype@*/
01012     void * pv = uh;
01013     Header h = NULL;
01014     entryInfo pe;
01015     unsigned char * dataStart;
01016     unsigned char * dataEnd;
01017     indexEntry entry; 
01018     int rdlen;
01019     int i;
01020 
01021     /* Sanity checks on header intro. */
01022     if (hdrchkTags(il) || hdrchkData(dl))
01023         goto errxit;
01024 
01025     ei = (int_32 *) pv;
01026     /*@-castexpose@*/
01027     pe = (entryInfo) &ei[2];
01028     /*@=castexpose@*/
01029     dataStart = (unsigned char *) (pe + il);
01030     dataEnd = dataStart + dl;
01031 
01032     h = xcalloc(1, sizeof(*h));
01033     /*@-assignexpose@*/
01034     h->hv = *hdrVec;            /* structure assignment */
01035     /*@=assignexpose@*/
01036     /*@-assignexpose -kepttrans@*/
01037     h->blob = uh;
01038     /*@=assignexpose =kepttrans@*/
01039     h->indexAlloced = il + 1;
01040     h->indexUsed = il;
01041     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01042     h->flags |= HEADERFLAG_SORTED;
01043     h->nrefs = 0;
01044     h = headerLink(h);
01045 
01046     /*
01047      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
01048      * %verifyscript tag that needs to be diddled.
01049      */
01050     if (ntohl(pe->tag) == 15 &&
01051         ntohl(pe->type) == RPM_STRING_TYPE &&
01052         ntohl(pe->count) == 1)
01053     {
01054         pe->tag = htonl(1079);
01055     }
01056 
01057     entry = h->index;
01058     i = 0;
01059     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01060         h->flags |= HEADERFLAG_LEGACY;
01061         entry->info.type = REGION_TAG_TYPE;
01062         entry->info.tag = HEADER_IMAGE;
01063         /*@-sizeoftype@*/
01064         entry->info.count = REGION_TAG_COUNT;
01065         /*@=sizeoftype@*/
01066         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01067 
01068         /*@-assignexpose@*/
01069         entry->data = pe;
01070         /*@=assignexpose@*/
01071         entry->length = pvlen - sizeof(il) - sizeof(dl);
01072         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01073 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01074         if (rdlen != dl)
01075             goto errxit;
01076 #endif
01077         entry->rdlen = rdlen;
01078         entry++;
01079         h->indexUsed++;
01080     } else {
01081         int_32 rdl;
01082         int_32 ril;
01083 
01084         h->flags &= ~HEADERFLAG_LEGACY;
01085 
01086         entry->info.type = htonl(pe->type);
01087         entry->info.count = htonl(pe->count);
01088 
01089         if (hdrchkType(entry->info.type))
01090             goto errxit;
01091         if (hdrchkTags(entry->info.count))
01092             goto errxit;
01093 
01094         {   int off = ntohl(pe->offset);
01095 
01096             if (hdrchkData(off))
01097                 goto errxit;
01098             if (off) {
01099 /*@-sizeoftype@*/
01100                 size_t nb = REGION_TAG_COUNT;
01101 /*@=sizeoftype@*/
01102                 int_32 * stei;
01103                 if (dataStart + off + nb > dataEnd)
01104                     goto errxit;
01105                 stei = memcpy(alloca(nb), dataStart + off, nb);
01106                 rdl = -ntohl(stei[2]);  /* negative offset */
01107                 ril = rdl/sizeof(*pe);
01108                 if (hdrchkTags(ril) || hdrchkData(rdl))
01109                     goto errxit;
01110                 entry->info.tag = htonl(pe->tag);
01111             } else {
01112                 ril = il;
01113                 /*@-sizeoftype@*/
01114                 rdl = (ril * sizeof(struct entryInfo_s));
01115                 /*@=sizeoftype@*/
01116                 entry->info.tag = HEADER_IMAGE;
01117             }
01118         }
01119         entry->info.offset = -rdl;      /* negative offset */
01120 
01121         /*@-assignexpose@*/
01122         entry->data = pe;
01123         /*@=assignexpose@*/
01124         entry->length = pvlen - sizeof(il) - sizeof(dl);
01125         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01126         if (rdlen < 0)
01127             goto errxit;
01128         entry->rdlen = rdlen;
01129 
01130         if (ril < h->indexUsed) {
01131             indexEntry newEntry = entry + ril;
01132             int ne = (h->indexUsed - ril);
01133             int rid = entry->info.offset+1;
01134             int rc;
01135 
01136             /* Load dribble entries from region. */
01137             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01138             if (rc < 0)
01139                 goto errxit;
01140             rdlen += rc;
01141 
01142           { indexEntry firstEntry = newEntry;
01143             int save = h->indexUsed;
01144             int j;
01145 
01146             /* Dribble entries replace duplicate region entries. */
01147             h->indexUsed -= ne;
01148             for (j = 0; j < ne; j++, newEntry++) {
01149                 (void) headerRemoveEntry(h, newEntry->info.tag);
01150                 if (newEntry->info.tag == HEADER_BASENAMES)
01151                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01152             }
01153 
01154             /* If any duplicate entries were replaced, move new entries down. */
01155 /*@-boundswrite@*/
01156             if (h->indexUsed < (save - ne)) {
01157                 memmove(h->index + h->indexUsed, firstEntry,
01158                         (ne * sizeof(*entry)));
01159             }
01160 /*@=boundswrite@*/
01161             h->indexUsed += ne;
01162           }
01163         }
01164     }
01165 
01166     h->flags &= ~HEADERFLAG_SORTED;
01167     headerSort(h);
01168 
01169     /*@-globstate -observertrans @*/
01170     return h;
01171     /*@=globstate =observertrans @*/
01172 
01173 errxit:
01174     /*@-usereleased@*/
01175     if (h) {
01176         h->index = _free(h->index);
01177         /*@-refcounttrans@*/
01178         h = _free(h);
01179         /*@=refcounttrans@*/
01180     }
01181     /*@=usereleased@*/
01182     /*@-refcounttrans -globstate@*/
01183     return h;
01184     /*@=refcounttrans =globstate@*/
01185 }
01186 
01194 static /*@null@*/
01195 Header headerReload(/*@only@*/ Header h, int tag)
01196         /*@modifies h @*/
01197 {
01198     Header nh;
01199     int length;
01200     /*@-onlytrans@*/
01201 /*@-boundswrite@*/
01202     void * uh = doHeaderUnload(h, &length);
01203 /*@=boundswrite@*/
01204 
01205     h = headerFree(h);
01206     /*@=onlytrans@*/
01207     if (uh == NULL)
01208         return NULL;
01209     nh = headerLoad(uh);
01210     if (nh == NULL) {
01211         uh = _free(uh);
01212         return NULL;
01213     }
01214     if (nh->flags & HEADERFLAG_ALLOCATED)
01215         uh = _free(uh);
01216     nh->flags |= HEADERFLAG_ALLOCATED;
01217     if (ENTRY_IS_REGION(nh->index)) {
01218 /*@-boundswrite@*/
01219         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01220             nh->index[0].info.tag = tag;
01221 /*@=boundswrite@*/
01222     }
01223     return nh;
01224 }
01225 
01231 static /*@null@*/
01232 Header headerCopyLoad(const void * uh)
01233         /*@*/
01234 {
01235     int_32 * ei = (int_32 *) uh;
01236 /*@-boundsread@*/
01237     int_32 il = ntohl(ei[0]);           /* index length */
01238     int_32 dl = ntohl(ei[1]);           /* data length */
01239 /*@=boundsread@*/
01240     /*@-sizeoftype@*/
01241     size_t pvlen = sizeof(il) + sizeof(dl) +
01242                         (il * sizeof(struct entryInfo_s)) + dl;
01243     /*@=sizeoftype@*/
01244     void * nuh = NULL;
01245     Header h = NULL;
01246 
01247     /* Sanity checks on header intro. */
01248     /*@-branchstate@*/
01249     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01250 /*@-boundsread@*/
01251         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01252 /*@=boundsread@*/
01253         if ((h = headerLoad(nuh)) != NULL)
01254             h->flags |= HEADERFLAG_ALLOCATED;
01255     }
01256     /*@=branchstate@*/
01257     /*@-branchstate@*/
01258     if (h == NULL)
01259         nuh = _free(nuh);
01260     /*@=branchstate@*/
01261     return h;
01262 }
01263 
01270 static /*@null@*/
01271 Header headerRead(FD_t fd, enum hMagic magicp)
01272         /*@modifies fd @*/
01273 {
01274     int_32 block[4];
01275     int_32 reserved;
01276     int_32 * ei = NULL;
01277     int_32 il;
01278     int_32 dl;
01279     int_32 magic;
01280     Header h = NULL;
01281     size_t len;
01282     int i;
01283 
01284     memset(block, 0, sizeof(block));
01285     i = 2;
01286     if (magicp == HEADER_MAGIC_YES)
01287         i += 2;
01288 
01289     /*@-type@*/ /* FIX: cast? */
01290     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01291         goto exit;
01292     /*@=type@*/
01293 
01294     i = 0;
01295 
01296 /*@-boundsread@*/
01297     if (magicp == HEADER_MAGIC_YES) {
01298         magic = block[i++];
01299         if (memcmp(&magic, header_magic, sizeof(magic)))
01300             goto exit;
01301         reserved = block[i++];
01302     }
01303     
01304     il = ntohl(block[i]);       i++;
01305     dl = ntohl(block[i]);       i++;
01306 /*@=boundsread@*/
01307 
01308     /*@-sizeoftype@*/
01309     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01310     /*@=sizeoftype@*/
01311 
01312     /* Sanity checks on header intro. */
01313     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01314         goto exit;
01315 
01316 /*@-boundswrite@*/
01317     ei = xmalloc(len);
01318     ei[0] = htonl(il);
01319     ei[1] = htonl(dl);
01320     len -= sizeof(il) + sizeof(dl);
01321 /*@=boundswrite@*/
01322 
01323 /*@-boundsread@*/
01324     /*@-type@*/ /* FIX: cast? */
01325     if (timedRead(fd, (char *)&ei[2], len) != len)
01326         goto exit;
01327     /*@=type@*/
01328 /*@=boundsread@*/
01329     
01330     h = headerLoad(ei);
01331 
01332 exit:
01333     if (h) {
01334         if (h->flags & HEADERFLAG_ALLOCATED)
01335             ei = _free(ei);
01336         h->flags |= HEADERFLAG_ALLOCATED;
01337     } else if (ei)
01338         ei = _free(ei);
01339     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01340     return h;
01341     /*@-mustmod@*/
01342 }
01343 
01351 static
01352 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
01353         /*@globals fileSystem @*/
01354         /*@modifies fd, h, fileSystem @*/
01355 {
01356     ssize_t nb;
01357     int length;
01358     const void * uh;
01359 
01360     if (h == NULL)
01361         return 1;
01362 /*@-boundswrite@*/
01363     uh = doHeaderUnload(h, &length);
01364 /*@=boundswrite@*/
01365     if (uh == NULL)
01366         return 1;
01367     switch (magicp) {
01368     case HEADER_MAGIC_YES:
01369 /*@-boundsread@*/
01370         /*@-sizeoftype@*/
01371         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01372         /*@=sizeoftype@*/
01373 /*@=boundsread@*/
01374         if (nb != sizeof(header_magic))
01375             goto exit;
01376         break;
01377     case HEADER_MAGIC_NO:
01378         break;
01379     }
01380 
01381     /*@-sizeoftype@*/
01382     nb = Fwrite(uh, sizeof(char), length, fd);
01383     /*@=sizeoftype@*/
01384 
01385 exit:
01386     uh = _free(uh);
01387     return (nb == length ? 0 : 1);
01388 }
01389 
01396 static
01397 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01398         /*@*/
01399 {
01400     /*@-mods@*/         /*@ FIX: h modified by sort. */
01401     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01402     /*@=mods@*/ 
01403 }
01404 
01415 static int copyEntry(const indexEntry entry,
01416                 /*@null@*/ /*@out@*/ hTYP_t type,
01417                 /*@null@*/ /*@out@*/ hPTR_t * p,
01418                 /*@null@*/ /*@out@*/ hCNT_t c,
01419                 int minMem)
01420         /*@modifies *type, *p, *c @*/
01421         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01422 {
01423     int_32 count = entry->info.count;
01424     int rc = 1;         /* XXX 1 on success. */
01425 
01426     if (p)
01427     switch (entry->info.type) {
01428     case RPM_BIN_TYPE:
01429         /*
01430          * XXX This only works for
01431          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01432          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01433          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01434          */
01435         if (ENTRY_IS_REGION(entry)) {
01436             int_32 * ei = ((int_32 *)entry->data) - 2;
01437             /*@-castexpose@*/
01438             entryInfo pe = (entryInfo) (ei + 2);
01439             /*@=castexpose@*/
01440 /*@-boundsread@*/
01441             char * dataStart = (char *) (pe + ntohl(ei[0]));
01442 /*@=boundsread@*/
01443             int_32 rdl = -entry->info.offset;   /* negative offset */
01444             int_32 ril = rdl/sizeof(*pe);
01445 
01446             /*@-sizeoftype@*/
01447             rdl = entry->rdlen;
01448             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01449             if (entry->info.tag == HEADER_IMAGE) {
01450                 ril -= 1;
01451                 pe += 1;
01452             } else {
01453                 count += REGION_TAG_COUNT;
01454                 rdl += REGION_TAG_COUNT;
01455             }
01456 
01457 /*@-bounds@*/
01458             *p = xmalloc(count);
01459             ei = (int_32 *) *p;
01460             ei[0] = htonl(ril);
01461             ei[1] = htonl(rdl);
01462 
01463             /*@-castexpose@*/
01464             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01465             /*@=castexpose@*/
01466 
01467             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01468             /*@=sizeoftype@*/
01469 /*@=bounds@*/
01470 
01471             rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01472             /* XXX 1 on success. */
01473             rc = (rc < 0) ? 0 : 1;
01474         } else {
01475             count = entry->length;
01476             *p = (!minMem
01477                 ? memcpy(xmalloc(count), entry->data, count)
01478                 : entry->data);
01479         }
01480         break;
01481     case RPM_STRING_TYPE:
01482         if (count == 1) {
01483             *p = entry->data;
01484             break;
01485         }
01486         /*@fallthrough@*/
01487     case RPM_STRING_ARRAY_TYPE:
01488     case RPM_I18NSTRING_TYPE:
01489     {   const char ** ptrEntry;
01490         /*@-sizeoftype@*/
01491         int tableSize = count * sizeof(char *);
01492         /*@=sizeoftype@*/
01493         char * t;
01494         int i;
01495 
01496 /*@-bounds@*/
01497         /*@-mods@*/
01498         if (minMem) {
01499             *p = xmalloc(tableSize);
01500             ptrEntry = (const char **) *p;
01501             t = entry->data;
01502         } else {
01503             t = xmalloc(tableSize + entry->length);
01504             *p = (void *)t;
01505             ptrEntry = (const char **) *p;
01506             t += tableSize;
01507             memcpy(t, entry->data, entry->length);
01508         }
01509         /*@=mods@*/
01510 /*@=bounds@*/
01511         for (i = 0; i < count; i++) {
01512 /*@-boundswrite@*/
01513             *ptrEntry++ = t;
01514 /*@=boundswrite@*/
01515             t = strchr(t, 0);
01516             t++;
01517         }
01518     }   break;
01519 
01520     default:
01521         *p = entry->data;
01522         break;
01523     }
01524     if (type) *type = entry->info.type;
01525     if (c) *c = count;
01526     return rc;
01527 }
01528 
01547 static int headerMatchLocale(const char *td, const char *l, const char *le)
01548         /*@*/
01549 {
01550     const char *fe;
01551 
01552 
01553 #if 0
01554   { const char *s, *ll, *CC, *EE, *dd;
01555     char *lbuf, *t.
01556 
01557     /* Copy the buffer and parse out components on the fly. */
01558     lbuf = alloca(le - l + 1);
01559     for (s = l, ll = t = lbuf; *s; s++, t++) {
01560         switch (*s) {
01561         case '_':
01562             *t = '\0';
01563             CC = t + 1;
01564             break;
01565         case '.':
01566             *t = '\0';
01567             EE = t + 1;
01568             break;
01569         case '@':
01570             *t = '\0';
01571             dd = t + 1;
01572             break;
01573         default:
01574             *t = *s;
01575             break;
01576         }
01577     }
01578 
01579     if (ll)     /* ISO language should be lower case */
01580         for (t = ll; *t; t++)   *t = tolower(*t);
01581     if (CC)     /* ISO country code should be upper case */
01582         for (t = CC; *t; t++)   *t = toupper(*t);
01583 
01584     /* There are a total of 16 cases to attempt to match. */
01585   }
01586 #endif
01587 
01588     /* First try a complete match. */
01589     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01590         return 1;
01591 
01592     /* Next, try stripping optional dialect and matching.  */
01593     for (fe = l; fe < le && *fe != '@'; fe++)
01594         {};
01595     if (fe < le && !strncmp(td, l, (fe - l)))
01596         return 1;
01597 
01598     /* Next, try stripping optional codeset and matching.  */
01599     for (fe = l; fe < le && *fe != '.'; fe++)
01600         {};
01601     if (fe < le && !strncmp(td, l, (fe - l)))
01602         return 1;
01603 
01604     /* Finally, try stripping optional country code and matching. */
01605     for (fe = l; fe < le && *fe != '_'; fe++)
01606         {};
01607     if (fe < le && !strncmp(td, l, (fe - l)))
01608         return 1;
01609 
01610     return 0;
01611 }
01612 
01619 /*@dependent@*/ /*@exposed@*/ static char *
01620 headerFindI18NString(Header h, indexEntry entry)
01621         /*@*/
01622 {
01623     const char *lang, *l, *le;
01624     indexEntry table;
01625 
01626     /* XXX Drepper sez' this is the order. */
01627     if ((lang = getenv("LANGUAGE")) == NULL &&
01628         (lang = getenv("LC_ALL")) == NULL &&
01629         (lang = getenv("LC_MESSAGES")) == NULL &&
01630         (lang = getenv("LANG")) == NULL)
01631             return entry->data;
01632     
01633     /*@-mods@*/
01634     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01635         return entry->data;
01636     /*@=mods@*/
01637 
01638 /*@-boundsread@*/
01639     for (l = lang; *l != '\0'; l = le) {
01640         const char *td;
01641         char *ed;
01642         int langNum;
01643 
01644         while (*l && *l == ':')                 /* skip leading colons */
01645             l++;
01646         if (*l == '\0')
01647             break;
01648         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01649             {};
01650 
01651         /* For each entry in the header ... */
01652         for (langNum = 0, td = table->data, ed = entry->data;
01653              langNum < entry->info.count;
01654              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01655 
01656                 if (headerMatchLocale(td, l, le))
01657                     return ed;
01658 
01659         }
01660     }
01661 /*@=boundsread@*/
01662 
01663     return entry->data;
01664 }
01665 
01676 static int intGetEntry(Header h, int_32 tag,
01677                 /*@null@*/ /*@out@*/ hTAG_t type,
01678                 /*@null@*/ /*@out@*/ hPTR_t * p,
01679                 /*@null@*/ /*@out@*/ hCNT_t c,
01680                 int minMem)
01681         /*@modifies *type, *p, *c @*/
01682         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01683 {
01684     indexEntry entry;
01685     int rc;
01686 
01687     /* First find the tag */
01688     /*@-mods@*/         /*@ FIX: h modified by sort. */
01689     entry = findEntry(h, tag, RPM_NULL_TYPE);
01690     /*@mods@*/
01691     if (entry == NULL) {
01692         if (type) type = 0;
01693         if (p) *p = NULL;
01694         if (c) *c = 0;
01695         return 0;
01696     }
01697 
01698     switch (entry->info.type) {
01699     case RPM_I18NSTRING_TYPE:
01700         rc = 1;
01701         if (type) *type = RPM_STRING_TYPE;
01702         if (c) *c = 1;
01703         /*@-dependenttrans@*/
01704         if (p) *p = headerFindI18NString(h, entry);
01705         /*@=dependenttrans@*/
01706         break;
01707     default:
01708         rc = copyEntry(entry, type, p, c, minMem);
01709         break;
01710     }
01711 
01712     /* XXX 1 on success */
01713     return ((rc == 1) ? 1 : 0);
01714 }
01715 
01723 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01724                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01725         /*@modifies data @*/
01726 {
01727     if (data) {
01728         /*@-branchstate@*/
01729         if (type == -1 ||
01730             type == RPM_STRING_ARRAY_TYPE ||
01731             type == RPM_I18NSTRING_TYPE ||
01732             type == RPM_BIN_TYPE)
01733                 data = _free(data);
01734         /*@=branchstate@*/
01735     }
01736     return NULL;
01737 }
01738 
01752 static
01753 int headerGetEntry(Header h, int_32 tag,
01754                         /*@null@*/ /*@out@*/ hTYP_t type,
01755                         /*@null@*/ /*@out@*/ void ** p,
01756                         /*@null@*/ /*@out@*/ hCNT_t c)
01757         /*@modifies *type, *p, *c @*/
01758         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01759 {
01760     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01761 }
01762 
01775 static
01776 int headerGetEntryMinMemory(Header h, int_32 tag,
01777                         /*@null@*/ /*@out@*/ hTYP_t type,
01778                         /*@null@*/ /*@out@*/ hPTR_t * p,
01779                         /*@null@*/ /*@out@*/ hCNT_t c)
01780         /*@modifies *type, *p, *c @*/
01781         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01782 {
01783     return intGetEntry(h, tag, type, p, c, 1);
01784 }
01785 
01786 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01787                 int_32 * c)
01788 {
01789     indexEntry entry;
01790     int rc;
01791 
01792     if (p == NULL) return headerIsEntry(h, tag);
01793 
01794     /* First find the tag */
01795     /*@-mods@*/         /*@ FIX: h modified by sort. */
01796     entry = findEntry(h, tag, RPM_NULL_TYPE);
01797     /*@=mods@*/
01798     if (!entry) {
01799         if (p) *p = NULL;
01800         if (c) *c = 0;
01801         return 0;
01802     }
01803 
01804     rc = copyEntry(entry, type, p, c, 0);
01805 
01806     /* XXX 1 on success */
01807     return ((rc == 1) ? 1 : 0);
01808 }
01809 
01812 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01813                 int_32 cnt, int dataLength)
01814         /*@modifies *dstPtr @*/
01815 {
01816     switch (type) {
01817     case RPM_STRING_ARRAY_TYPE:
01818     case RPM_I18NSTRING_TYPE:
01819     {   const char ** av = (const char **) srcPtr;
01820         char * t = dstPtr;
01821 
01822 /*@-bounds@*/
01823         while (cnt-- > 0 && dataLength > 0) {
01824             const char * s;
01825             if ((s = *av++) == NULL)
01826                 continue;
01827             do {
01828                 *t++ = *s++;
01829             } while (s[-1] && --dataLength > 0);
01830         }
01831 /*@=bounds@*/
01832     }   break;
01833 
01834     default:
01835 /*@-boundswrite@*/
01836         memmove(dstPtr, srcPtr, dataLength);
01837 /*@=boundswrite@*/
01838         break;
01839     }
01840 }
01841 
01850 /*@null@*/
01851 static void *
01852 grabData(int_32 type, hPTR_t p, int_32 c, /*@out@*/ int * lengthPtr)
01853         /*@modifies *lengthPtr @*/
01854         /*@requires maxSet(lengthPtr) >= 0 @*/
01855 {
01856     void * data = NULL;
01857     int length;
01858 
01859     length = dataLength(type, p, c, 0, NULL);
01860 /*@-branchstate@*/
01861     if (length > 0) {
01862         data = xmalloc(length);
01863         copyData(type, data, p, c, length);
01864     }
01865 /*@=branchstate@*/
01866 
01867     if (lengthPtr)
01868         *lengthPtr = length;
01869     return data;
01870 }
01871 
01886 static
01887 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01888         /*@modifies h @*/
01889 {
01890     indexEntry entry;
01891     void * data;
01892     int length;
01893 
01894     /* Count must always be >= 1 for headerAddEntry. */
01895     if (c <= 0)
01896         return 0;
01897 
01898     if (hdrchkType(type))
01899         return 0;
01900     if (hdrchkData(c))
01901         return 0;
01902 
01903     length = 0;
01904 /*@-boundswrite@*/
01905     data = grabData(type, p, c, &length);
01906 /*@=boundswrite@*/
01907     if (data == NULL || length <= 0)
01908         return 0;
01909 
01910     /* Allocate more index space if necessary */
01911     if (h->indexUsed == h->indexAlloced) {
01912         h->indexAlloced += INDEX_MALLOC_SIZE;
01913         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01914     }
01915 
01916     /* Fill in the index */
01917     entry = h->index + h->indexUsed;
01918     entry->info.tag = tag;
01919     entry->info.type = type;
01920     entry->info.count = c;
01921     entry->info.offset = 0;
01922     entry->data = data;
01923     entry->length = length;
01924 
01925 /*@-boundsread@*/
01926     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01927         h->flags &= ~HEADERFLAG_SORTED;
01928 /*@=boundsread@*/
01929     h->indexUsed++;
01930 
01931     return 1;
01932 }
01933 
01948 static
01949 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01950                 const void * p, int_32 c)
01951         /*@modifies h @*/
01952 {
01953     indexEntry entry;
01954     int length;
01955 
01956     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01957         /* we can't do this */
01958         return 0;
01959     }
01960 
01961     /* Find the tag entry in the header. */
01962     entry = findEntry(h, tag, type);
01963     if (!entry)
01964         return 0;
01965 
01966     length = dataLength(type, p, c, 0, NULL);
01967     if (length < 0)
01968         return 0;
01969 
01970     if (ENTRY_IN_REGION(entry)) {
01971         char * t = xmalloc(entry->length + length);
01972 /*@-bounds@*/
01973         memcpy(t, entry->data, entry->length);
01974 /*@=bounds@*/
01975         entry->data = t;
01976         entry->info.offset = 0;
01977     } else
01978         entry->data = xrealloc(entry->data, entry->length + length);
01979 
01980     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01981 
01982     entry->length += length;
01983 
01984     entry->info.count += c;
01985 
01986     return 1;
01987 }
01988 
01999 static
02000 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
02001                 const void * p, int_32 c)
02002         /*@modifies h @*/
02003 {
02004     return (findEntry(h, tag, type)
02005         ? headerAppendEntry(h, tag, type, p, c)
02006         : headerAddEntry(h, tag, type, p, c));
02007 }
02008 
02029 static
02030 int headerAddI18NString(Header h, int_32 tag, const char * string,
02031                 const char * lang)
02032         /*@modifies h @*/
02033 {
02034     indexEntry table, entry;
02035     const char ** strArray;
02036     int length;
02037     int ghosts;
02038     int i, langNum;
02039     char * buf;
02040 
02041     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02042     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02043 
02044     if (!table && entry)
02045         return 0;               /* this shouldn't ever happen!! */
02046 
02047     if (!table && !entry) {
02048         const char * charArray[2];
02049         int count = 0;
02050         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02051             /*@-observertrans -readonlytrans@*/
02052             charArray[count++] = "C";
02053             /*@=observertrans =readonlytrans@*/
02054         } else {
02055             /*@-observertrans -readonlytrans@*/
02056             charArray[count++] = "C";
02057             /*@=observertrans =readonlytrans@*/
02058             charArray[count++] = lang;
02059         }
02060         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
02061                         &charArray, count))
02062             return 0;
02063         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02064     }
02065 
02066     if (!table)
02067         return 0;
02068     /*@-branchstate@*/
02069     if (!lang) lang = "C";
02070     /*@=branchstate@*/
02071 
02072     {   const char * l = table->data;
02073         for (langNum = 0; langNum < table->info.count; langNum++) {
02074             if (!strcmp(l, lang)) break;
02075             l += strlen(l) + 1;
02076         }
02077     }
02078 
02079     if (langNum >= table->info.count) {
02080         length = strlen(lang) + 1;
02081         if (ENTRY_IN_REGION(table)) {
02082             char * t = xmalloc(table->length + length);
02083             memcpy(t, table->data, table->length);
02084             table->data = t;
02085             table->info.offset = 0;
02086         } else
02087             table->data = xrealloc(table->data, table->length + length);
02088         memmove(((char *)table->data) + table->length, lang, length);
02089         table->length += length;
02090         table->info.count++;
02091     }
02092 
02093     if (!entry) {
02094         strArray = alloca(sizeof(*strArray) * (langNum + 1));
02095         for (i = 0; i < langNum; i++)
02096             strArray[i] = "";
02097         strArray[langNum] = string;
02098         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
02099                                 langNum + 1);
02100     } else if (langNum >= entry->info.count) {
02101         ghosts = langNum - entry->info.count;
02102         
02103         length = strlen(string) + 1 + ghosts;
02104         if (ENTRY_IN_REGION(entry)) {
02105             char * t = xmalloc(entry->length + length);
02106             memcpy(t, entry->data, entry->length);
02107             entry->data = t;
02108             entry->info.offset = 0;
02109         } else
02110             entry->data = xrealloc(entry->data, entry->length + length);
02111 
02112         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02113         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02114 
02115         entry->length += length;
02116         entry->info.count = langNum + 1;
02117     } else {
02118         char *b, *be, *e, *ee, *t;
02119         size_t bn, sn, en;
02120 
02121         /* Set beginning/end pointers to previous data */
02122         b = be = e = ee = entry->data;
02123         for (i = 0; i < table->info.count; i++) {
02124             if (i == langNum)
02125                 be = ee;
02126             ee += strlen(ee) + 1;
02127             if (i == langNum)
02128                 e  = ee;
02129         }
02130 
02131         /* Get storage for new buffer */
02132         bn = (be-b);
02133         sn = strlen(string) + 1;
02134         en = (ee-e);
02135         length = bn + sn + en;
02136         t = buf = xmalloc(length);
02137 
02138         /* Copy values into new storage */
02139         memcpy(t, b, bn);
02140         t += bn;
02141 /*@-mayaliasunique@*/
02142         memcpy(t, string, sn);
02143         t += sn;
02144         memcpy(t, e, en);
02145         t += en;
02146 /*@=mayaliasunique@*/
02147 
02148         /* Replace i18N string array */
02149         entry->length -= strlen(be) + 1;
02150         entry->length += sn;
02151         
02152         if (ENTRY_IN_REGION(entry)) {
02153             entry->info.offset = 0;
02154         } else
02155             entry->data = _free(entry->data);
02156         /*@-dependenttrans@*/
02157         entry->data = buf;
02158         /*@=dependenttrans@*/
02159     }
02160 
02161     return 0;
02162 }
02163 
02174 static
02175 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02176                         const void * p, int_32 c)
02177         /*@modifies h @*/
02178 {
02179     indexEntry entry;
02180     void * oldData;
02181     void * data;
02182     int length;
02183 
02184     /* First find the tag */
02185     entry = findEntry(h, tag, type);
02186     if (!entry)
02187         return 0;
02188 
02189     length = 0;
02190     data = grabData(type, p, c, &length);
02191     if (data == NULL || length <= 0)
02192         return 0;
02193 
02194     /* make sure entry points to the first occurence of this tag */
02195     while (entry > h->index && (entry - 1)->info.tag == tag)  
02196         entry--;
02197 
02198     /* free after we've grabbed the new data in case the two are intertwined;
02199        that's a bad idea but at least we won't break */
02200     oldData = entry->data;
02201 
02202     entry->info.count = c;
02203     entry->info.type = type;
02204     entry->data = data;
02205     entry->length = length;
02206 
02207     /*@-branchstate@*/
02208     if (ENTRY_IN_REGION(entry)) {
02209         entry->info.offset = 0;
02210     } else
02211         oldData = _free(oldData);
02212     /*@=branchstate@*/
02213 
02214     return 1;
02215 }
02216 
02219 static char escapedChar(const char ch)  /*@*/
02220 {
02221     switch (ch) {
02222     case 'a':   return '\a';
02223     case 'b':   return '\b';
02224     case 'f':   return '\f';
02225     case 'n':   return '\n';
02226     case 'r':   return '\r';
02227     case 't':   return '\t';
02228     case 'v':   return '\v';
02229     default:    return ch;
02230     }
02231 }
02232 
02239 static /*@null@*/ sprintfToken
02240 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02241         /*@modifies *format @*/
02242 {
02243     int i;
02244 
02245     if (format == NULL) return NULL;
02246 
02247     for (i = 0; i < num; i++) {
02248         switch (format[i].type) {
02249         case PTOK_ARRAY:
02250 /*@-boundswrite@*/
02251             format[i].u.array.format =
02252                 freeFormat(format[i].u.array.format,
02253                         format[i].u.array.numTokens);
02254 /*@=boundswrite@*/
02255             /*@switchbreak@*/ break;
02256         case PTOK_COND:
02257 /*@-boundswrite@*/
02258             format[i].u.cond.ifFormat =
02259                 freeFormat(format[i].u.cond.ifFormat, 
02260                         format[i].u.cond.numIfTokens);
02261             format[i].u.cond.elseFormat =
02262                 freeFormat(format[i].u.cond.elseFormat, 
02263                         format[i].u.cond.numElseTokens);
02264 /*@=boundswrite@*/
02265             /*@switchbreak@*/ break;
02266         case PTOK_NONE:
02267         case PTOK_TAG:
02268         case PTOK_STRING:
02269         default:
02270             /*@switchbreak@*/ break;
02271         }
02272     }
02273     format = _free(format);
02274     return NULL;
02275 }
02276 
02280 struct headerIterator_s {
02281 /*@unused@*/
02282     Header h;           
02283 /*@unused@*/
02284     int next_index;     
02285 };
02286 
02292 static /*@null@*/
02293 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
02294         /*@modifies hi @*/
02295 {
02296     if (hi != NULL) {
02297         hi->h = headerFree(hi->h);
02298         hi = _free(hi);
02299     }
02300     return hi;
02301 }
02302 
02308 static
02309 HeaderIterator headerInitIterator(Header h)
02310         /*@modifies h */
02311 {
02312     HeaderIterator hi = xmalloc(sizeof(*hi));
02313 
02314     headerSort(h);
02315 
02316     hi->h = headerLink(h);
02317     hi->next_index = 0;
02318     return hi;
02319 }
02320 
02330 static
02331 int headerNextIterator(HeaderIterator hi,
02332                 /*@null@*/ /*@out@*/ hTAG_t tag,
02333                 /*@null@*/ /*@out@*/ hTYP_t type,
02334                 /*@null@*/ /*@out@*/ hPTR_t * p,
02335                 /*@null@*/ /*@out@*/ hCNT_t c)
02336         /*@modifies hi, *tag, *type, *p, *c @*/
02337         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
02338                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
02339 {
02340     Header h = hi->h;
02341     int slot = hi->next_index;
02342     indexEntry entry = NULL;
02343     int rc;
02344 
02345     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02346         entry = h->index + slot;
02347         if (!ENTRY_IS_REGION(entry))
02348             break;
02349     }
02350     hi->next_index = slot;
02351     if (entry == NULL || slot >= h->indexUsed)
02352         return 0;
02353 
02354     /*@-noeffect@*/     /* LCL: no clue */
02355     hi->next_index++;
02356     /*@=noeffect@*/
02357 
02358     if (tag)
02359         *tag = entry->info.tag;
02360 
02361     rc = copyEntry(entry, type, p, c, 0);
02362 
02363     /* XXX 1 on success */
02364     return ((rc == 1) ? 1 : 0);
02365 }
02366 
02372 static /*@null@*/
02373 Header headerCopy(Header h)
02374         /*@modifies h @*/
02375 {
02376     Header nh = headerNew();
02377     HeaderIterator hi;
02378     int_32 tag, type, count;
02379     hPTR_t ptr;
02380    
02381     /*@-branchstate@*/
02382     for (hi = headerInitIterator(h);
02383         headerNextIterator(hi, &tag, &type, &ptr, &count);
02384         ptr = headerFreeData((void *)ptr, type))
02385     {
02386         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02387     }
02388     hi = headerFreeIterator(hi);
02389     /*@=branchstate@*/
02390 
02391     return headerReload(nh, HEADER_IMAGE);
02392 }
02393 
02396 typedef struct headerSprintfArgs_s {
02397     Header h;
02398     char * fmt;
02399 /*@temp@*/
02400     headerTagTableEntry tags;
02401 /*@temp@*/
02402     headerSprintfExtension exts;
02403 /*@observer@*/ /*@null@*/
02404     const char * errmsg;
02405     rpmec ec;
02406     sprintfToken format;
02407 /*@relnull@*/
02408     HeaderIterator hi;
02409 /*@owned@*/
02410     char * val;
02411     size_t vallen;
02412     size_t alloced;
02413     int numTokens;
02414     int i;
02415 } * headerSprintfArgs;
02416 
02422 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
02423         /*@modifies hsa */
02424 {
02425     sprintfTag tag =
02426         (hsa->format->type == PTOK_TAG
02427             ? &hsa->format->u.tag :
02428         (hsa->format->type == PTOK_ARRAY
02429             ? &hsa->format->u.array.format->u.tag :
02430         NULL));
02431 
02432     if (hsa != NULL) {
02433         hsa->i = 0;
02434         if (tag != NULL && tag->tag == -2)
02435             hsa->hi = headerInitIterator(hsa->h);
02436     }
02437 /*@-nullret@*/
02438     return hsa;
02439 /*@=nullret@*/
02440 }
02441 
02447 /*@null@*/
02448 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
02449         /*@modifies hsa */
02450 {
02451     sprintfToken fmt = NULL;
02452     sprintfTag tag =
02453         (hsa->format->type == PTOK_TAG
02454             ? &hsa->format->u.tag :
02455         (hsa->format->type == PTOK_ARRAY
02456             ? &hsa->format->u.array.format->u.tag :
02457         NULL));
02458 
02459     if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02460         fmt = hsa->format + hsa->i;
02461         if (hsa->hi == NULL) {
02462             hsa->i++;
02463         } else {
02464             int_32 tagno;
02465             int_32 type;
02466             int_32 count;
02467 
02468 /*@-boundswrite@*/
02469             if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02470                 fmt = NULL;
02471             tag->tag = tagno;
02472 /*@=boundswrite@*/
02473         }
02474     }
02475 
02476 /*@-dependenttrans -onlytrans@*/
02477     return fmt;
02478 /*@=dependenttrans =onlytrans@*/
02479 }
02480 
02486 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02487         /*@modifies hsa */
02488 {
02489     if (hsa != NULL) {
02490         hsa->hi = headerFreeIterator(hsa->hi);
02491         hsa->i = 0;
02492     }
02493 /*@-nullret@*/
02494     return hsa;
02495 /*@=nullret@*/
02496 }
02497 
02504 /*@dependent@*/ /*@exposed@*/
02505 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02506         /*@modifies hsa */
02507 {
02508     if ((hsa->vallen + need) >= hsa->alloced) {
02509         if (hsa->alloced <= need)
02510             hsa->alloced += need;
02511         hsa->alloced <<= 1;
02512         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02513     }
02514     return hsa->val + hsa->vallen;
02515 }
02516 
02523 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02524         /*@modifies token @*/
02525 {
02526     headerTagTableEntry tag;
02527     headerSprintfExtension ext;
02528     sprintfTag stag = (token->type == PTOK_COND
02529         ? &token->u.cond.tag : &token->u.tag);
02530 
02531     stag->fmt = NULL;
02532     stag->ext = NULL;
02533     stag->extNum = 0;
02534     stag->tag = -1;
02535 
02536     if (!strcmp(name, "*")) {
02537         stag->tag = -2;
02538         goto bingo;
02539     }
02540 
02541 /*@-branchstate@*/
02542     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02543 /*@-boundswrite@*/
02544         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02545         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02546         name = t;
02547 /*@=boundswrite@*/
02548     }
02549 /*@=branchstate@*/
02550 
02551     /* Search extensions for specific tag override. */
02552     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02553         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02554     {
02555         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02556             continue;
02557         if (!xstrcasecmp(ext->name, name)) {
02558             stag->ext = ext->u.tagFunction;
02559             stag->extNum = ext - hsa->exts;
02560             goto bingo;
02561         }
02562     }
02563 
02564     /* Search tag names. */
02565     for (tag = hsa->tags; tag->name != NULL; tag++) {
02566         if (!xstrcasecmp(tag->name, name)) {
02567             stag->tag = tag->val;
02568             goto bingo;
02569         }
02570     }
02571 
02572     return 1;
02573 
02574 bingo:
02575     /* Search extensions for specific format. */
02576     if (stag->type != NULL)
02577     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02578             ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02579     {
02580         if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02581             continue;
02582         if (!strcmp(ext->name, stag->type)) {
02583             stag->fmt = ext->u.formatFunction;
02584             break;
02585         }
02586     }
02587     return 0;
02588 }
02589 
02590 /* forward ref */
02598 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02599                 char * str, /*@out@*/char ** endPtr)
02600         /*@modifies hsa, str, token, *endPtr @*/
02601         /*@requires maxSet(endPtr) >= 0 @*/;
02602 
02612 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
02613                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02614                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
02615         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
02616         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02617                 /\ maxSet(endPtr) >= 0 @*/
02618 {
02619     char * chptr, * start, * next, * dst;
02620     sprintfToken format;
02621     sprintfToken token;
02622     int numTokens;
02623     int i;
02624     int done = 0;
02625 
02626     /* upper limit on number of individual formats */
02627     numTokens = 0;
02628     if (str != NULL)
02629     for (chptr = str; *chptr != '\0'; chptr++)
02630         if (*chptr == '%') numTokens++;
02631     numTokens = numTokens * 2 + 1;
02632 
02633     format = xcalloc(numTokens, sizeof(*format));
02634     if (endPtr) *endPtr = NULL;
02635 
02636     /*@-infloops@*/ /* LCL: can't detect done termination */
02637     dst = start = str;
02638     numTokens = 0;
02639     token = NULL;
02640     if (start != NULL)
02641     while (*start != '\0') {
02642         switch (*start) {
02643         case '%':
02644             /* handle %% */
02645             if (*(start + 1) == '%') {
02646                 if (token == NULL || token->type != PTOK_STRING) {
02647                     token = format + numTokens++;
02648                     token->type = PTOK_STRING;
02649                     /*@-temptrans -assignexpose@*/
02650                     dst = token->u.string.string = start;
02651                     /*@=temptrans =assignexpose@*/
02652                 }
02653                 start++;
02654 /*@-boundswrite@*/
02655                 *dst++ = *start++;
02656 /*@=boundswrite@*/
02657                 /*@switchbreak@*/ break;
02658             } 
02659 
02660             token = format + numTokens++;
02661 /*@-boundswrite@*/
02662             *dst++ = '\0';
02663 /*@=boundswrite@*/
02664             start++;
02665 
02666             if (*start == '|') {
02667                 char * newEnd;
02668 
02669                 start++;
02670 /*@-boundswrite@*/
02671                 if (parseExpression(hsa, token, start, &newEnd))
02672                 {
02673                     format = freeFormat(format, numTokens);
02674                     return 1;
02675                 }
02676 /*@=boundswrite@*/
02677                 start = newEnd;
02678                 /*@switchbreak@*/ break;
02679             }
02680 
02681             /*@-assignexpose@*/
02682             token->u.tag.format = start;
02683             /*@=assignexpose@*/
02684             token->u.tag.pad = 0;
02685             token->u.tag.justOne = 0;
02686             token->u.tag.arrayCount = 0;
02687 
02688             chptr = start;
02689             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02690             if (!*chptr || *chptr == '%') {
02691                 hsa->errmsg = _("missing { after %");
02692                 format = freeFormat(format, numTokens);
02693                 return 1;
02694             }
02695 
02696 /*@-boundswrite@*/
02697             *chptr++ = '\0';
02698 /*@=boundswrite@*/
02699 
02700             while (start < chptr) {
02701                 if (xisdigit(*start)) {
02702                     i = strtoul(start, &start, 10);
02703                     token->u.tag.pad += i;
02704                 } else {
02705                     start++;
02706                 }
02707             }
02708 
02709             if (*start == '=') {
02710                 token->u.tag.justOne = 1;
02711                 start++;
02712             } else if (*start == '#') {
02713                 token->u.tag.justOne = 1;
02714                 token->u.tag.arrayCount = 1;
02715                 start++;
02716             }
02717 
02718             next = start;
02719             while (*next && *next != '}') next++;
02720             if (!*next) {
02721                 hsa->errmsg = _("missing } after %{");
02722                 format = freeFormat(format, numTokens);
02723                 return 1;
02724             }
02725 /*@-boundswrite@*/
02726             *next++ = '\0';
02727 /*@=boundswrite@*/
02728 
02729             chptr = start;
02730             while (*chptr && *chptr != ':') chptr++;
02731 
02732             if (*chptr != '\0') {
02733 /*@-boundswrite@*/
02734                 *chptr++ = '\0';
02735 /*@=boundswrite@*/
02736                 if (!*chptr) {
02737                     hsa->errmsg = _("empty tag format");
02738                     format = freeFormat(format, numTokens);
02739                     return 1;
02740                 }
02741                 /*@-assignexpose@*/
02742                 token->u.tag.type = chptr;
02743                 /*@=assignexpose@*/
02744             } else {
02745                 token->u.tag.type = NULL;
02746             }
02747             
02748             if (!*start) {
02749                 hsa->errmsg = _("empty tag name");
02750                 format = freeFormat(format, numTokens);
02751                 return 1;
02752             }
02753 
02754             i = 0;
02755             token->type = PTOK_TAG;
02756 
02757             if (findTag(hsa, token, start)) {
02758                 hsa->errmsg = _("unknown tag");
02759                 format = freeFormat(format, numTokens);
02760                 return 1;
02761             }
02762 
02763             start = next;
02764             /*@switchbreak@*/ break;
02765 
02766         case '[':
02767 /*@-boundswrite@*/
02768             *dst++ = '\0';
02769             *start++ = '\0';
02770 /*@=boundswrite@*/
02771             token = format + numTokens++;
02772 
02773 /*@-boundswrite@*/
02774             if (parseFormat(hsa, start,
02775                             &token->u.array.format,
02776                             &token->u.array.numTokens,
02777                             &start, PARSER_IN_ARRAY))
02778             {
02779                 format = freeFormat(format, numTokens);
02780                 return 1;
02781             }
02782 /*@=boundswrite@*/
02783 
02784             if (!start) {
02785                 hsa->errmsg = _("] expected at end of array");
02786                 format = freeFormat(format, numTokens);
02787                 return 1;
02788             }
02789 
02790             dst = start;
02791 
02792             token->type = PTOK_ARRAY;
02793 
02794             /*@switchbreak@*/ break;
02795 
02796         case ']':
02797             if (state != PARSER_IN_ARRAY) {
02798                 hsa->errmsg = _("unexpected ]");
02799                 format = freeFormat(format, numTokens);
02800                 return 1;
02801             }
02802 /*@-boundswrite@*/
02803             *start++ = '\0';
02804 /*@=boundswrite@*/
02805             if (endPtr) *endPtr = start;
02806             done = 1;
02807             /*@switchbreak@*/ break;
02808 
02809         case '}':
02810             if (state != PARSER_IN_EXPR) {
02811                 hsa->errmsg = _("unexpected }");
02812                 format = freeFormat(format, numTokens);
02813                 return 1;
02814             }
02815 /*@-boundswrite@*/
02816             *start++ = '\0';
02817 /*@=boundswrite@*/
02818             if (endPtr) *endPtr = start;
02819             done = 1;
02820             /*@switchbreak@*/ break;
02821 
02822         default:
02823             if (token == NULL || token->type != PTOK_STRING) {
02824                 token = format + numTokens++;
02825                 token->type = PTOK_STRING;
02826                 /*@-temptrans -assignexpose@*/
02827                 dst = token->u.string.string = start;
02828                 /*@=temptrans =assignexpose@*/
02829             }
02830 
02831 /*@-boundswrite@*/
02832             if (*start == '\\') {
02833                 start++;
02834                 *dst++ = escapedChar(*start++);
02835             } else {
02836                 *dst++ = *start++;
02837             }
02838 /*@=boundswrite@*/
02839             /*@switchbreak@*/ break;
02840         }
02841         if (done)
02842             break;
02843     }
02844     /*@=infloops@*/
02845 
02846 /*@-boundswrite@*/
02847     if (dst != NULL)
02848         *dst = '\0';
02849 /*@=boundswrite@*/
02850 
02851     for (i = 0; i < numTokens; i++) {
02852         token = format + i;
02853         if (token->type == PTOK_STRING)
02854             token->u.string.len = strlen(token->u.string.string);
02855     }
02856 
02857     *numTokensPtr = numTokens;
02858     *formatPtr = format;
02859 
02860     return 0;
02861 }
02862 
02863 /*@-boundswrite@*/
02864 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02865                 char * str, /*@out@*/ char ** endPtr)
02866 {
02867     char * chptr;
02868     char * end;
02869 
02870     hsa->errmsg = NULL;
02871     chptr = str;
02872     while (*chptr && *chptr != '?') chptr++;
02873 
02874     if (*chptr != '?') {
02875         hsa->errmsg = _("? expected in expression");
02876         return 1;
02877     }
02878 
02879     *chptr++ = '\0';;
02880 
02881     if (*chptr != '{') {
02882         hsa->errmsg = _("{ expected after ? in expression");
02883         return 1;
02884     }
02885 
02886     chptr++;
02887 
02888     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
02889                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
02890         return 1;
02891 
02892     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
02893     if (!(end && *end)) {
02894         hsa->errmsg = _("} expected in expression");
02895         token->u.cond.ifFormat =
02896                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02897         return 1;
02898     }
02899 
02900     chptr = end;
02901     if (*chptr != ':' && *chptr != '|') {
02902         hsa->errmsg = _(": expected following ? subexpression");
02903         token->u.cond.ifFormat =
02904                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02905         return 1;
02906     }
02907 
02908     if (*chptr == '|') {
02909         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
02910                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02911         {
02912             token->u.cond.ifFormat =
02913                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02914             return 1;
02915         }
02916     } else {
02917         chptr++;
02918 
02919         if (*chptr != '{') {
02920             hsa->errmsg = _("{ expected after : in expression");
02921             token->u.cond.ifFormat =
02922                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02923             return 1;
02924         }
02925 
02926         chptr++;
02927 
02928         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
02929                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
02930             return 1;
02931 
02932         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
02933         if (!(end && *end)) {
02934             hsa->errmsg = _("} expected in expression");
02935             token->u.cond.ifFormat =
02936                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02937             return 1;
02938         }
02939 
02940         chptr = end;
02941         if (*chptr != '|') {
02942             hsa->errmsg = _("| expected at end of expression");
02943             token->u.cond.ifFormat =
02944                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02945             token->u.cond.elseFormat =
02946                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02947             return 1;
02948         }
02949     }
02950         
02951     chptr++;
02952 
02953     *endPtr = chptr;
02954 
02955     token->type = PTOK_COND;
02956 
02957     (void) findTag(hsa, token, str);
02958 
02959     return 0;
02960 }
02961 /*@=boundswrite@*/
02962 
02973 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
02974                 /*@out@*/ hTYP_t typeptr,
02975                 /*@out@*/ hPTR_t * data,
02976                 /*@out@*/ hCNT_t countptr,
02977                 rpmec ec)
02978         /*@modifies *typeptr, *data, *countptr, ec @*/
02979         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
02980                 /\ maxSet(countptr) >= 0 @*/
02981 {
02982     if (!ec->avail) {
02983         if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
02984             return 1;
02985         ec->avail = 1;
02986     }
02987 
02988     if (typeptr) *typeptr = ec->type;
02989     if (data) *data = ec->data;
02990     if (countptr) *countptr = ec->count;
02991 
02992     return 0;
02993 }
02994 
03001 /*@observer@*/ /*@null@*/
03002 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03003         /*@modifies hsa @*/
03004 {
03005     char * val = NULL;
03006     size_t need = 0;
03007     char * t, * te;
03008     char buf[20];
03009     int_32 count, type;
03010     hPTR_t data;
03011     unsigned int intVal;
03012     const char ** strarray;
03013     int datafree = 0;
03014     int countBuf;
03015 
03016     memset(buf, 0, sizeof(buf));
03017     if (tag->ext) {
03018 /*@-boundswrite -branchstate @*/
03019         if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03020         {
03021             count = 1;
03022             type = RPM_STRING_TYPE;     
03023             data = "(none)";
03024         }
03025 /*@=boundswrite =branchstate @*/
03026     } else {
03027 /*@-boundswrite -branchstate @*/
03028         if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03029             count = 1;
03030             type = RPM_STRING_TYPE;     
03031             data = "(none)";
03032         }
03033 /*@=boundswrite =branchstate @*/
03034 
03035         /* XXX this test is unnecessary, array sizes are checked */
03036         switch (type) {
03037         default:
03038             if (element >= count) {
03039                 /*@-modobserver -observertrans@*/
03040                 data = headerFreeData(data, type);
03041                 /*@=modobserver =observertrans@*/
03042 
03043                 hsa->errmsg = _("(index out of range)");
03044                 return NULL;
03045             }
03046             break;
03047         case RPM_BIN_TYPE:
03048         case RPM_STRING_TYPE:
03049             break;
03050         }
03051         datafree = 1;
03052     }
03053 
03054     if (tag->arrayCount) {
03055         /*@-branchstate -observertrans -modobserver@*/
03056         if (datafree)
03057             data = headerFreeData(data, type);
03058         /*@=branchstate =observertrans =modobserver@*/
03059 
03060         countBuf = count;
03061         data = &countBuf;
03062         count = 1;
03063         type = RPM_INT32_TYPE;
03064     }
03065 
03066 /*@-boundswrite@*/
03067     (void) stpcpy( stpcpy(buf, "%"), tag->format);
03068 /*@=boundswrite@*/
03069 
03070     /*@-branchstate@*/
03071     if (data)
03072     switch (type) {
03073     case RPM_STRING_ARRAY_TYPE:
03074         strarray = (const char **)data;
03075 
03076         if (tag->fmt)
03077             val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03078 
03079         if (val) {
03080             need = strlen(val);
03081         } else {
03082             need = strlen(strarray[element]) + tag->pad + 20;
03083             val = xmalloc(need+1);
03084             strcat(buf, "s");
03085             /*@-formatconst@*/
03086             sprintf(val, buf, strarray[element]);
03087             /*@=formatconst@*/
03088         }
03089 
03090         break;
03091 
03092     case RPM_STRING_TYPE:
03093         if (tag->fmt)
03094             val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad,  0);
03095 
03096         if (val) {
03097             need = strlen(val);
03098         } else {
03099             need = strlen(data) + tag->pad + 20;
03100             val = xmalloc(need+1);
03101             strcat(buf, "s");
03102             /*@-formatconst@*/
03103             sprintf(val, buf, data);
03104             /*@=formatconst@*/
03105         }
03106         break;
03107 
03108     case RPM_CHAR_TYPE:
03109     case RPM_INT8_TYPE:
03110     case RPM_INT16_TYPE:
03111     case RPM_INT32_TYPE:
03112         switch (type) {
03113         case RPM_CHAR_TYPE:     
03114         case RPM_INT8_TYPE:
03115             intVal = *(((int_8 *) data) + element);
03116             /*@innerbreak@*/ break;
03117         case RPM_INT16_TYPE:
03118             intVal = *(((uint_16 *) data) + element);
03119             /*@innerbreak@*/ break;
03120         default:                /* keep -Wall quiet */
03121         case RPM_INT32_TYPE:
03122             intVal = *(((int_32 *) data) + element);
03123             /*@innerbreak@*/ break;
03124         }
03125 
03126         if (tag->fmt)
03127             val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03128 
03129         if (val) {
03130             need = strlen(val);
03131         } else {
03132             need = 10 + tag->pad + 20;
03133             val = xmalloc(need+1);
03134             strcat(buf, "d");
03135             /*@-formatconst@*/
03136             sprintf(val, buf, intVal);
03137             /*@=formatconst@*/
03138         }
03139         break;
03140 
03141     case RPM_BIN_TYPE:
03142         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
03143         if (tag->fmt)
03144             val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03145 
03146         if (val) {
03147             need = strlen(val);
03148         } else {
03149 #ifdef  NOTYET
03150             val = memcpy(xmalloc(count), data, count);
03151 #else
03152             /* XXX format string not used */
03153             static char hex[] = "0123456789abcdef";
03154             const char * s = data;
03155 
03156 /*@-boundswrite@*/
03157             need = 2*count + tag->pad;
03158             val = t = xmalloc(need+1);
03159             while (count-- > 0) {
03160                 unsigned int i;
03161                 i = *s++;
03162                 *t++ = hex[ (i >> 4) & 0xf ];
03163                 *t++ = hex[ (i     ) & 0xf ];
03164             }
03165             *t = '\0';
03166 /*@=boundswrite@*/
03167 #endif
03168         }
03169         break;
03170 
03171     default:
03172         need = sizeof("(unknown type)") - 1;
03173         val = xstrdup("(unknown type)");
03174         break;
03175     }
03176     /*@=branchstate@*/
03177 
03178     /*@-branchstate -observertrans -modobserver@*/
03179     if (datafree)
03180         data = headerFreeData(data, type);
03181     /*@=branchstate =observertrans =modobserver@*/
03182 
03183     /*@-branchstate@*/
03184     if (val && need > 0) {
03185         t = hsaReserve(hsa, need);
03186 /*@-boundswrite@*/
03187         te = stpcpy(t, val);
03188 /*@=boundswrite@*/
03189         hsa->vallen += (te - t);
03190         val = _free(val);
03191     }
03192     /*@=branchstate@*/
03193 
03194     return (hsa->val + hsa->vallen);
03195 }
03196 
03203 /*@observer@*/
03204 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03205                 int element)
03206         /*@modifies hsa @*/
03207 {
03208     char * t, * te;
03209     int i, j;
03210     int numElements;
03211     int_32 type;
03212     int_32 count;
03213     sprintfToken spft;
03214     int condNumFormats;
03215     size_t need;
03216 
03217     /* we assume the token and header have been validated already! */
03218 
03219     switch (token->type) {
03220     case PTOK_NONE:
03221         break;
03222 
03223     case PTOK_STRING:
03224         need = token->u.string.len;
03225         if (need == 0) break;
03226         t = hsaReserve(hsa, need);
03227 /*@-boundswrite@*/
03228         te = stpcpy(t, token->u.string.string);
03229 /*@=boundswrite@*/
03230         hsa->vallen += (te - t);
03231         break;
03232 
03233     case PTOK_TAG:
03234         t = hsa->val + hsa->vallen;
03235         te = formatValue(hsa, &token->u.tag,
03236                         (token->u.tag.justOne ? 0 : element));
03237         if (te == NULL)
03238             return NULL;
03239         break;
03240 
03241     case PTOK_COND:
03242         if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03243             spft = token->u.cond.ifFormat;
03244             condNumFormats = token->u.cond.numIfTokens;
03245         } else {
03246             spft = token->u.cond.elseFormat;
03247             condNumFormats = token->u.cond.numElseTokens;
03248         }
03249 
03250         need = condNumFormats * 20;
03251         if (spft == NULL || need == 0) break;
03252 
03253         t = hsaReserve(hsa, need);
03254         for (i = 0; i < condNumFormats; i++, spft++) {
03255             te = singleSprintf(hsa, spft, element);
03256             if (te == NULL)
03257                 return NULL;
03258         }
03259         break;
03260 
03261     case PTOK_ARRAY:
03262         numElements = -1;
03263         spft = token->u.array.format;
03264         for (i = 0; i < token->u.array.numTokens; i++, spft++)
03265         {
03266             if (spft->type != PTOK_TAG ||
03267                 spft->u.tag.arrayCount ||
03268                 spft->u.tag.justOne) continue;
03269 
03270             if (spft->u.tag.ext) {
03271 /*@-boundswrite@*/
03272                 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count, 
03273                                  hsa->ec + spft->u.tag.extNum))
03274                      continue;
03275 /*@=boundswrite@*/
03276             } else {
03277 /*@-boundswrite@*/
03278                 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03279                     continue;
03280 /*@=boundswrite@*/
03281             } 
03282 
03283             if (type == RPM_BIN_TYPE)
03284                 count = 1;      /* XXX count abused as no. of bytes. */
03285 
03286             if (numElements > 1 && count != numElements)
03287             switch (type) {
03288             default:
03289                 hsa->errmsg =
03290                         _("array iterator used with different sized arrays");
03291                 return NULL;
03292                 /*@notreached@*/ /*@switchbreak@*/ break;
03293             case RPM_BIN_TYPE:
03294             case RPM_STRING_TYPE:
03295                 /*@switchbreak@*/ break;
03296             }
03297             if (count > numElements)
03298                 numElements = count;
03299         }
03300 
03301         if (numElements == -1) {
03302             need = sizeof("(none)") - 1;
03303             t = hsaReserve(hsa, need);
03304 /*@-boundswrite@*/
03305             te = stpcpy(t, "(none)");
03306 /*@=boundswrite@*/
03307             hsa->vallen += (te - t);
03308         } else {
03309             int isxml;
03310 
03311             need = numElements * token->u.array.numTokens * 10;
03312             if (need == 0) break;
03313 
03314             spft = token->u.array.format;
03315             isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03316                 !strcmp(spft->u.tag.type, "xml"));
03317 
03318             if (isxml) {
03319                 const char * tagN = tagName(spft->u.tag.tag);
03320 
03321                 need = strlen(tagN) + sizeof("  <rpmTag name=\"\">\n") - 1;
03322                 t = hsaReserve(hsa, need);
03323 /*@-boundswrite@*/
03324                 te = stpcpy(t, "  <rpmTag name=\"");
03325                 te = stpcpy(te, tagN);
03326                 te = stpcpy(te, "\">\n");
03327 /*@=boundswrite@*/
03328                 hsa->vallen += (te - t);
03329             }
03330 
03331             t = hsaReserve(hsa, need);
03332             for (j = 0; j < numElements; j++) {
03333                 spft = token->u.array.format;
03334                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03335                     te = singleSprintf(hsa, spft, j);
03336                     if (te == NULL)
03337                         return NULL;
03338                 }
03339             }
03340 
03341             if (isxml) {
03342                 need = sizeof("  </rpmTag>\n") - 1;
03343                 t = hsaReserve(hsa, need);
03344 /*@-boundswrite@*/
03345                 te = stpcpy(t, "  </rpmTag>\n");
03346 /*@=boundswrite@*/
03347                 hsa->vallen += (te - t);
03348             }
03349 
03350         }
03351         break;
03352     }
03353 
03354     return (hsa->val + hsa->vallen);
03355 }
03356 
03362 static /*@only@*/ rpmec
03363 rpmecNew(const headerSprintfExtension exts)
03364         /*@*/
03365 {
03366     headerSprintfExtension ext;
03367     rpmec ec;
03368     int i = 0;
03369 
03370     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03371         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03372     {
03373         i++;
03374     }
03375 
03376     ec = xcalloc(i, sizeof(*ec));
03377     return ec;
03378 }
03379 
03386 static /*@null@*/ rpmec
03387 rpmecFree(const headerSprintfExtension exts, /*@only@*/ rpmec ec)
03388         /*@modifies ec @*/
03389 {
03390     headerSprintfExtension ext;
03391     int i = 0;
03392 
03393     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03394         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03395     {
03396 /*@-boundswrite@*/
03397         if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03398 /*@=boundswrite@*/
03399         i++;
03400     }
03401 
03402     ec = _free(ec);
03403     return NULL;
03404 }
03405 
03417 static /*@only@*/ /*@null@*/
03418 char * headerSprintf(Header h, const char * fmt,
03419                      const struct headerTagTableEntry_s * tbltags,
03420                      const struct headerSprintfExtension_s * extensions,
03421                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03422         /*@modifies h, *errmsg @*/
03423         /*@requires maxSet(errmsg) >= 0 @*/
03424 {
03425     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03426     sprintfToken nextfmt;
03427     sprintfTag tag;
03428     char * t, * te;
03429     int isxml;
03430     int need;
03431  
03432     hsa->h = headerLink(h);
03433     hsa->fmt = xstrdup(fmt);
03434 /*@-castexpose@*/       /* FIX: legacy API shouldn't change. */
03435     hsa->exts = (headerSprintfExtension) extensions;
03436     hsa->tags = (headerTagTableEntry) tbltags;
03437 /*@=castexpose@*/
03438     hsa->errmsg = NULL;
03439 
03440 /*@-boundswrite@*/
03441     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03442         goto exit;
03443 /*@=boundswrite@*/
03444 
03445     hsa->ec = rpmecNew(hsa->exts);
03446     hsa->val = xstrdup("");
03447 
03448     tag =
03449         (hsa->format->type == PTOK_TAG
03450             ? &hsa->format->u.tag :
03451         (hsa->format->type == PTOK_ARRAY
03452             ? &hsa->format->u.array.format->u.tag :
03453         NULL));
03454     isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03455 
03456     if (isxml) {
03457         need = sizeof("<rpmHeader>\n") - 1;
03458         t = hsaReserve(hsa, need);
03459 /*@-boundswrite@*/
03460         te = stpcpy(t, "<rpmHeader>\n");
03461 /*@=boundswrite@*/
03462         hsa->vallen += (te - t);
03463     }
03464 
03465     hsa = hsaInit(hsa);
03466     while ((nextfmt = hsaNext(hsa)) != NULL) {
03467         te = singleSprintf(hsa, nextfmt, 0);
03468         if (te == NULL) {
03469             hsa->val = _free(hsa->val);
03470             break;
03471         }
03472     }
03473     hsa = hsaFini(hsa);
03474 
03475     if (isxml) {
03476         need = sizeof("</rpmHeader>\n") - 1;
03477         t = hsaReserve(hsa, need);
03478 /*@-boundswrite@*/
03479         te = stpcpy(t, "</rpmHeader>\n");
03480 /*@=boundswrite@*/
03481         hsa->vallen += (te - t);
03482     }
03483 
03484     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03485         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
03486 
03487     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03488     hsa->format = freeFormat(hsa->format, hsa->numTokens);
03489 
03490 exit:
03491 /*@-dependenttrans -observertrans @*/
03492     if (errmsg)
03493         *errmsg = hsa->errmsg;
03494 /*@=dependenttrans =observertrans @*/
03495     hsa->h = headerFree(hsa->h);
03496     hsa->fmt = _free(hsa->fmt);
03497     return hsa->val;
03498 }
03499 
03508 static char * octalFormat(int_32 type, hPTR_t data, 
03509                 char * formatPrefix, int padding, /*@unused@*/int element)
03510         /*@modifies formatPrefix @*/
03511 {
03512     char * val;
03513 
03514     if (type != RPM_INT32_TYPE) {
03515         val = xstrdup(_("(not a number)"));
03516     } else {
03517         val = xmalloc(20 + padding);
03518 /*@-boundswrite@*/
03519         strcat(formatPrefix, "o");
03520 /*@=boundswrite@*/
03521         /*@-formatconst@*/
03522         sprintf(val, formatPrefix, *((int_32 *) data));
03523         /*@=formatconst@*/
03524     }
03525 
03526     return val;
03527 }
03528 
03537 static char * hexFormat(int_32 type, hPTR_t data, 
03538                 char * formatPrefix, int padding, /*@unused@*/int element)
03539         /*@modifies formatPrefix @*/
03540 {
03541     char * val;
03542 
03543     if (type != RPM_INT32_TYPE) {
03544         val = xstrdup(_("(not a number)"));
03545     } else {
03546         val = xmalloc(20 + padding);
03547 /*@-boundswrite@*/
03548         strcat(formatPrefix, "x");
03549 /*@=boundswrite@*/
03550         /*@-formatconst@*/
03551         sprintf(val, formatPrefix, *((int_32 *) data));
03552         /*@=formatconst@*/
03553     }
03554 
03555     return val;
03556 }
03557 
03560 static char * realDateFormat(int_32 type, hPTR_t data, 
03561                 char * formatPrefix, int padding, /*@unused@*/int element,
03562                 const char * strftimeFormat)
03563         /*@modifies formatPrefix @*/
03564 {
03565     char * val;
03566 
03567     if (type != RPM_INT32_TYPE) {
03568         val = xstrdup(_("(not a number)"));
03569     } else {
03570         struct tm * tstruct;
03571         char buf[50];
03572 
03573         val = xmalloc(50 + padding);
03574 /*@-boundswrite@*/
03575         strcat(formatPrefix, "s");
03576 /*@=boundswrite@*/
03577 
03578         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03579         {   time_t dateint = *((int_32 *) data);
03580             tstruct = localtime(&dateint);
03581         }
03582         buf[0] = '\0';
03583         if (tstruct)
03584             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03585         /*@-formatconst@*/
03586         sprintf(val, formatPrefix, buf);
03587         /*@=formatconst@*/
03588     }
03589 
03590     return val;
03591 }
03592 
03601 static char * dateFormat(int_32 type, hPTR_t data, 
03602                          char * formatPrefix, int padding, int element)
03603         /*@modifies formatPrefix @*/
03604 {
03605     return realDateFormat(type, data, formatPrefix, padding, element,
03606                         _("%c"));
03607 }
03608 
03617 static char * dayFormat(int_32 type, hPTR_t data, 
03618                          char * formatPrefix, int padding, int element)
03619         /*@modifies formatPrefix @*/
03620 {
03621     return realDateFormat(type, data, formatPrefix, padding, element, 
03622                           _("%a %b %d %Y"));
03623 }
03624 
03633 static char * shescapeFormat(int_32 type, hPTR_t data, 
03634                 char * formatPrefix, int padding, /*@unused@*/int element)
03635         /*@modifies formatPrefix @*/
03636 {
03637     char * result, * dst, * src, * buf;
03638 
03639     if (type == RPM_INT32_TYPE) {
03640         result = xmalloc(padding + 20);
03641 /*@-boundswrite@*/
03642         strcat(formatPrefix, "d");
03643 /*@=boundswrite@*/
03644         /*@-formatconst@*/
03645         sprintf(result, formatPrefix, *((int_32 *) data));
03646         /*@=formatconst@*/
03647     } else {
03648         buf = alloca(strlen(data) + padding + 2);
03649 /*@-boundswrite@*/
03650         strcat(formatPrefix, "s");
03651 /*@=boundswrite@*/
03652         /*@-formatconst@*/
03653         sprintf(buf, formatPrefix, data);
03654         /*@=formatconst@*/
03655 
03656 /*@-boundswrite@*/
03657         result = dst = xmalloc(strlen(buf) * 4 + 3);
03658         *dst++ = '\'';
03659         for (src = buf; *src != '\0'; src++) {
03660             if (*src == '\'') {
03661                 *dst++ = '\'';
03662                 *dst++ = '\\';
03663                 *dst++ = '\'';
03664                 *dst++ = '\'';
03665             } else {
03666                 *dst++ = *src;
03667             }
03668         }
03669         *dst++ = '\'';
03670         *dst = '\0';
03671 /*@=boundswrite@*/
03672 
03673     }
03674 
03675     return result;
03676 }
03677 
03678 /*@-type@*/ /* FIX: cast? */
03679 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03680     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03681     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03682     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03683     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03684     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03685     { HEADER_EXT_LAST, NULL, { NULL } }
03686 };
03687 /*@=type@*/
03688 
03695 static
03696 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03697         /*@modifies headerTo @*/
03698 {
03699     int * p;
03700 
03701     if (headerFrom == headerTo)
03702         return;
03703 
03704     for (p = tagstocopy; *p != 0; p++) {
03705         char *s;
03706         int_32 type;
03707         int_32 count;
03708         if (headerIsEntry(headerTo, *p))
03709             continue;
03710 /*@-boundswrite@*/
03711         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03712                                 (hPTR_t *) &s, &count))
03713             continue;
03714 /*@=boundswrite@*/
03715         (void) headerAddEntry(headerTo, *p, type, s, count);
03716         s = headerFreeData(s, type);
03717     }
03718 }
03719 
03720 /*@observer@*/ /*@unchecked@*/
03721 static struct HV_s hdrVec1 = {
03722     headerLink,
03723     headerUnlink,
03724     headerFree,
03725     headerNew,
03726     headerSort,
03727     headerUnsort,
03728     headerSizeof,
03729     headerUnload,
03730     headerReload,
03731     headerCopy,
03732     headerLoad,
03733     headerCopyLoad,
03734     headerRead,
03735     headerWrite,
03736     headerIsEntry,
03737     headerFreeTag,
03738     headerGetEntry,
03739     headerGetEntryMinMemory,
03740     headerAddEntry,
03741     headerAppendEntry,
03742     headerAddOrAppendEntry,
03743     headerAddI18NString,
03744     headerModifyEntry,
03745     headerRemoveEntry,
03746     headerSprintf,
03747     headerCopyTags,
03748     headerFreeIterator,
03749     headerInitIterator,
03750     headerNextIterator,
03751     NULL, NULL,
03752     1
03753 };
03754 
03755 /*@-compmempass -redef@*/
03756 /*@observer@*/ /*@unchecked@*/
03757 HV_t hdrVec = &hdrVec1;
03758 /*@=compmempass =redef@*/

Generated on Mon Oct 3 16:57:49 2011 for rpm by  doxygen 1.3.9.1