rpmdb/header.c

Go to the documentation of this file.
00001 
00005 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
00006 
00007 /* Data written to file descriptors is in network byte order.    */
00008 /* Data read from file descriptors is expected to be in          */
00009 /* network byte order and is converted on the fly to host order. */
00010 
00011 #include "system.h"
00012 
00013 #define __HEADER_PROTOTYPES__
00014 
00015 #include <header_internal.h>
00016 
00017 #include "debug.h"
00018 
00019 /*@unchecked@*/
00020 int _hdr_debug = 0;
00021 
00022 /*@access entryInfo @*/
00023 /*@access indexEntry @*/
00024 
00025 /*@access rpmec @*/
00026 /*@access sprintfTag @*/
00027 /*@access sprintfToken @*/
00028 /*@access HV_t @*/
00029 
00030 #define PARSER_BEGIN    0
00031 #define PARSER_IN_ARRAY 1
00032 #define PARSER_IN_EXPR  2
00033 
00036 /*@observer@*/ /*@unchecked@*/
00037 static unsigned char header_magic[8] = {
00038         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00039 };
00040 
00044 /*@observer@*/ /*@unchecked@*/
00045 static int typeAlign[16] =  {
00046     1,  
00047     1,  
00048     1,  
00049     2,  
00050     4,  
00051     8,  
00052     1,  
00053     1,  
00054     1,  
00055     1,  
00056     0,
00057     0,
00058     0,
00059     0,
00060     0,
00061     0
00062 };
00063 
00067 /*@observer@*/ /*@unchecked@*/
00068 static int typeSizes[16] =  { 
00069     0,  
00070     1,  
00071     1,  
00072     2,  
00073     4,  
00074     -1, 
00075     -1, 
00076     1,  
00077     -1, 
00078     -1, 
00079     0,
00080     0,
00081     0,
00082     0,
00083     0,
00084     0
00085 };
00086 
00090 /*@unchecked@*/
00091 static size_t headerMaxbytes = (32*1024*1024);
00092 
00097 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00098 
00102 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00103 
00108 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00109 
00113 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00114 
00118 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00119 
00120 /*@observer@*/ /*@unchecked@*/
00121 HV_t hdrVec;    /* forward reference */
00122 
00128 /*@unused@*/ static inline /*@null@*/ void *
00129 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
00130 {
00131     if (p != NULL)      free((void *)p);
00132     return NULL;
00133 }
00134 
00140 static
00141 Header headerLink(Header h)
00142         /*@modifies h @*/
00143 {
00144 /*@-nullret@*/
00145     if (h == NULL) return NULL;
00146 /*@=nullret@*/
00147 
00148     h->nrefs++;
00149 /*@-modfilesys@*/
00150 if (_hdr_debug)
00151 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00152 /*@=modfilesys@*/
00153 
00154     /*@-refcounttrans @*/
00155     return h;
00156     /*@=refcounttrans @*/
00157 }
00158 
00164 static /*@null@*/
00165 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00166         /*@modifies h @*/
00167 {
00168     if (h == NULL) return NULL;
00169 /*@-modfilesys@*/
00170 if (_hdr_debug)
00171 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00172 /*@=modfilesys@*/
00173     h->nrefs--;
00174     return NULL;
00175 }
00176 
00182 static /*@null@*/
00183 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00184         /*@modifies h @*/
00185 {
00186     (void) headerUnlink(h);
00187 
00188     /*@-usereleased@*/
00189     if (h == NULL || h->nrefs > 0)
00190         return NULL;    /* XXX return previous header? */
00191 
00192     if (h->index) {
00193         indexEntry entry = h->index;
00194         int i;
00195         for (i = 0; i < h->indexUsed; i++, entry++) {
00196             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00197                 if (entry->length > 0) {
00198                     int_32 * ei = entry->data;
00199                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00200                     entry->data = NULL;
00201                 }
00202             } else if (!ENTRY_IN_REGION(entry)) {
00203                 entry->data = _free(entry->data);
00204             }
00205             entry->data = NULL;
00206         }
00207         h->index = _free(h->index);
00208     }
00209 
00210     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00211     return h;
00212     /*@=usereleased@*/
00213 }
00214 
00219 static
00220 Header headerNew(void)
00221         /*@*/
00222 {
00223     Header h = xcalloc(1, sizeof(*h));
00224 
00225 /*@-boundsread@*/
00226     /*@-assignexpose@*/
00227     h->hv = *hdrVec;            /* structure assignment */
00228     /*@=assignexpose@*/
00229 /*@=boundsread@*/
00230     h->blob = NULL;
00231     h->indexAlloced = INDEX_MALLOC_SIZE;
00232     h->indexUsed = 0;
00233     h->flags |= HEADERFLAG_SORTED;
00234 
00235     h->index = (h->indexAlloced
00236         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00237         : NULL);
00238 
00239     h->nrefs = 0;
00240     /*@-globstate -observertrans @*/
00241     return headerLink(h);
00242     /*@=globstate =observertrans @*/
00243 }
00244 
00247 static int indexCmp(const void * avp, const void * bvp)
00248         /*@*/
00249 {
00250     /*@-castexpose@*/
00251     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00252     /*@=castexpose@*/
00253     return (ap->info.tag - bp->info.tag);
00254 }
00255 
00260 static
00261 void headerSort(Header h)
00262         /*@modifies h @*/
00263 {
00264     if (!(h->flags & HEADERFLAG_SORTED)) {
00265 /*@-boundsread@*/
00266         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00267 /*@=boundsread@*/
00268         h->flags |= HEADERFLAG_SORTED;
00269     }
00270 }
00271 
00274 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00275 {
00276     /*@-castexpose@*/
00277     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00278     /*@=castexpose@*/
00279     int rc = (ap->info.offset - bp->info.offset);
00280 
00281     if (rc == 0) {
00282         /* Within a region, entries sort by address. Added drips sort by tag. */
00283         if (ap->info.offset < 0)
00284             rc = (((char *)ap->data) - ((char *)bp->data));
00285         else
00286             rc = (ap->info.tag - bp->info.tag);
00287     }
00288     return rc;
00289 }
00290 
00295 static
00296 void headerUnsort(Header h)
00297         /*@modifies h @*/
00298 {
00299 /*@-boundsread@*/
00300     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00301 /*@=boundsread@*/
00302 }
00303 
00310 static
00311 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00312         /*@modifies h @*/
00313 {
00314     indexEntry entry;
00315     unsigned int size = 0;
00316     unsigned int pad = 0;
00317     int i;
00318 
00319     if (h == NULL)
00320         return size;
00321 
00322     headerSort(h);
00323 
00324     switch (magicp) {
00325     case HEADER_MAGIC_YES:
00326         size += sizeof(header_magic);
00327         break;
00328     case HEADER_MAGIC_NO:
00329         break;
00330     }
00331 
00332     /*@-sizeoftype@*/
00333     size += 2 * sizeof(int_32); /* count of index entries */
00334     /*@=sizeoftype@*/
00335 
00336     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00337         unsigned diff;
00338         int_32 type;
00339 
00340         /* Regions go in as is ... */
00341         if (ENTRY_IS_REGION(entry)) {
00342             size += entry->length;
00343             /* XXX Legacy regions do not include the region tag and data. */
00344             /*@-sizeoftype@*/
00345             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00346                 size += sizeof(struct entryInfo_s) + entry->info.count;
00347             /*@=sizeoftype@*/
00348             continue;
00349         }
00350 
00351         /* ... and region elements are skipped. */
00352         if (entry->info.offset < 0)
00353             continue;
00354 
00355         /* Alignment */
00356         type = entry->info.type;
00357 /*@-boundsread@*/
00358         if (typeSizes[type] > 1) {
00359             diff = typeSizes[type] - (size % typeSizes[type]);
00360             if (diff != typeSizes[type]) {
00361                 size += diff;
00362                 pad += diff;
00363             }
00364         }
00365 /*@=boundsread@*/
00366 
00367         /*@-sizeoftype@*/
00368         size += sizeof(struct entryInfo_s) + entry->length;
00369         /*@=sizeoftype@*/
00370     }
00371 
00372     return size;
00373 }
00374 
00384 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00385                 /*@null@*/ hPTR_t pend)
00386         /*@*/
00387 {
00388     const unsigned char * s = p;
00389     const unsigned char * se = pend;
00390     int length = 0;
00391 
00392     switch (type) {
00393     case RPM_STRING_TYPE:
00394         if (count != 1)
00395             return -1;
00396 /*@-boundsread@*/
00397         while (*s++) {
00398             if (se && s > se)
00399                 return -1;
00400             length++;
00401         }
00402 /*@=boundsread@*/
00403         length++;       /* count nul terminator too. */
00404         break;
00405 
00406     case RPM_STRING_ARRAY_TYPE:
00407     case RPM_I18NSTRING_TYPE:
00408         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00409         /* Compute sum of length of all strings, including nul terminators */
00410 
00411         if (onDisk) {
00412             while (count--) {
00413                 length++;       /* count nul terminator too */
00414 /*@-boundsread@*/
00415                while (*s++) {
00416                     if (se && s > se)
00417                         return -1;
00418                     length++;
00419                 }
00420 /*@=boundsread@*/
00421             }
00422         } else {
00423             const char ** av = (const char **)p;
00424 /*@-boundsread@*/
00425             while (count--) {
00426                 /* add one for null termination */
00427                 length += strlen(*av++) + 1;
00428             }
00429 /*@=boundsread@*/
00430         }
00431         break;
00432 
00433     default:
00434 /*@-boundsread@*/
00435         if (typeSizes[type] == -1)
00436             return -1;
00437         length = typeSizes[(type & 0xf)] * count;
00438 /*@=boundsread@*/
00439         if (length < 0 || (se && (s + length) > se))
00440             return -1;
00441         break;
00442     }
00443 
00444     return length;
00445 }
00446 
00473 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00474                 entryInfo pe,
00475                 unsigned char * dataStart,
00476                 /*@null@*/ const unsigned char * dataEnd,
00477                 int regionid)
00478         /*@modifies *entry, *dataStart @*/
00479 {
00480     unsigned char * tprev = NULL;
00481     unsigned char * t = NULL;
00482     int tdel = 0;
00483     int tl = dl;
00484     struct indexEntry_s ieprev;
00485 
00486 /*@-boundswrite@*/
00487     memset(&ieprev, 0, sizeof(ieprev));
00488 /*@=boundswrite@*/
00489     for (; il > 0; il--, pe++) {
00490         struct indexEntry_s ie;
00491         int_32 type;
00492 
00493         ie.info.tag = ntohl(pe->tag);
00494         ie.info.type = ntohl(pe->type);
00495         ie.info.count = ntohl(pe->count);
00496         ie.info.offset = ntohl(pe->offset);
00497 
00498         if (hdrchkType(ie.info.type))
00499             return -1;
00500         if (hdrchkData(ie.info.count))
00501             return -1;
00502         if (hdrchkData(ie.info.offset))
00503             return -1;
00504 /*@-boundsread@*/
00505         if (hdrchkAlign(ie.info.type, ie.info.offset))
00506             return -1;
00507 /*@=boundsread@*/
00508 
00509         ie.data = t = dataStart + ie.info.offset;
00510         if (dataEnd && t >= dataEnd)
00511             return -1;
00512 
00513         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00514         if (ie.length < 0 || hdrchkData(ie.length))
00515             return -1;
00516 
00517         ie.rdlen = 0;
00518 
00519         if (entry) {
00520             ie.info.offset = regionid;
00521 /*@-boundswrite@*/
00522             *entry = ie;        /* structure assignment */
00523 /*@=boundswrite@*/
00524             entry++;
00525         }
00526 
00527         /* Alignment */
00528         type = ie.info.type;
00529 /*@-boundsread@*/
00530         if (typeSizes[type] > 1) {
00531             unsigned diff;
00532             diff = typeSizes[type] - (dl % typeSizes[type]);
00533             if (diff != typeSizes[type]) {
00534                 dl += diff;
00535                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00536                     ieprev.length += diff;
00537             }
00538         }
00539 /*@=boundsread@*/
00540         tdel = (tprev ? (t - tprev) : 0);
00541         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00542             tdel = ieprev.length;
00543 
00544         if (ie.info.tag >= HEADER_I18NTABLE) {
00545             tprev = t;
00546         } else {
00547             tprev = dataStart;
00548             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00549             /*@-sizeoftype@*/
00550             if (ie.info.tag == HEADER_IMAGE)
00551                 tprev -= REGION_TAG_COUNT;
00552             /*@=sizeoftype@*/
00553         }
00554 
00555         /* Perform endian conversions */
00556         switch (ntohl(pe->type)) {
00557 /*@-bounds@*/
00558         case RPM_INT32_TYPE:
00559         {   int_32 * it = (int_32 *)t;
00560             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00561                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00562                     return -1;
00563                 *it = htonl(*it);
00564             }
00565             t = (char *) it;
00566         }   /*@switchbreak@*/ break;
00567         case RPM_INT16_TYPE:
00568         {   int_16 * it = (int_16 *) t;
00569             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00570                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00571                     return -1;
00572                 *it = htons(*it);
00573             }
00574             t = (char *) it;
00575         }   /*@switchbreak@*/ break;
00576 /*@=bounds@*/
00577         default:
00578             t += ie.length;
00579             /*@switchbreak@*/ break;
00580         }
00581 
00582         dl += ie.length;
00583         tl += tdel;
00584         ieprev = ie;    /* structure assignment */
00585 
00586     }
00587     tdel = (tprev ? (t - tprev) : 0);
00588     tl += tdel;
00589 
00590     /* XXX
00591      * There are two hacks here:
00592      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00593      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00594      */
00595     /*@-sizeoftype@*/
00596     if (tl+REGION_TAG_COUNT == dl)
00597         tl += REGION_TAG_COUNT;
00598     /*@=sizeoftype@*/
00599 
00600     return dl;
00601 }
00602 
00608 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00609                 /*@out@*/ int * lengthPtr)
00610         /*@modifies h, *lengthPtr @*/
00611         /*@requires maxSet(lengthPtr) >= 0 @*/
00612         /*@ensures maxRead(result) == (*lengthPtr) @*/
00613 {
00614     int_32 * ei = NULL;
00615     entryInfo pe;
00616     char * dataStart;
00617     char * te;
00618     unsigned pad;
00619     unsigned len;
00620     int_32 il = 0;
00621     int_32 dl = 0;
00622     indexEntry entry; 
00623     int_32 type;
00624     int i;
00625     int drlen, ndribbles;
00626     int driplen, ndrips;
00627     int legacy = 0;
00628 
00629     /* Sort entries by (offset,tag). */
00630     headerUnsort(h);
00631 
00632     /* Compute (il,dl) for all tags, including those deleted in region. */
00633     pad = 0;
00634     drlen = ndribbles = driplen = ndrips = 0;
00635     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00636         if (ENTRY_IS_REGION(entry)) {
00637             int_32 rdl = -entry->info.offset;   /* negative offset */
00638             int_32 ril = rdl/sizeof(*pe);
00639             int rid = entry->info.offset;
00640 
00641             il += ril;
00642             dl += entry->rdlen + entry->info.count;
00643             /* XXX Legacy regions do not include the region tag and data. */
00644             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00645                 il += 1;
00646 
00647             /* Skip rest of entries in region, but account for dribbles. */
00648             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00649                 if (entry->info.offset <= rid)
00650                     /*@innercontinue@*/ continue;
00651 
00652                 /* Alignment */
00653                 type = entry->info.type;
00654                 if (typeSizes[type] > 1) {
00655                     unsigned diff;
00656                     diff = typeSizes[type] - (dl % typeSizes[type]);
00657                     if (diff != typeSizes[type]) {
00658                         drlen += diff;
00659                         pad += diff;
00660                         dl += diff;
00661                     }
00662                 }
00663 
00664                 ndribbles++;
00665                 il++;
00666                 drlen += entry->length;
00667                 dl += entry->length;
00668             }
00669             i--;
00670             entry--;
00671             continue;
00672         }
00673 
00674         /* Ignore deleted drips. */
00675         if (entry->data == NULL || entry->length <= 0)
00676             continue;
00677 
00678         /* Alignment */
00679         type = entry->info.type;
00680         if (typeSizes[type] > 1) {
00681             unsigned diff;
00682             diff = typeSizes[type] - (dl % typeSizes[type]);
00683             if (diff != typeSizes[type]) {
00684                 driplen += diff;
00685                 pad += diff;
00686                 dl += diff;
00687             } else
00688                 diff = 0;
00689         }
00690 
00691         ndrips++;
00692         il++;
00693         driplen += entry->length;
00694         dl += entry->length;
00695     }
00696 
00697     /* Sanity checks on header intro. */
00698     if (hdrchkTags(il) || hdrchkData(dl))
00699         goto errxit;
00700 
00701     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00702 
00703 /*@-boundswrite@*/
00704     ei = xmalloc(len);
00705     ei[0] = htonl(il);
00706     ei[1] = htonl(dl);
00707 /*@=boundswrite@*/
00708 
00709     pe = (entryInfo) &ei[2];
00710     dataStart = te = (char *) (pe + il);
00711 
00712     pad = 0;
00713     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00714         const char * src;
00715 char *t;
00716         int count;
00717         int rdlen;
00718 
00719         if (entry->data == NULL || entry->length <= 0)
00720             continue;
00721 
00722 t = te;
00723         pe->tag = htonl(entry->info.tag);
00724         pe->type = htonl(entry->info.type);
00725         pe->count = htonl(entry->info.count);
00726 
00727         if (ENTRY_IS_REGION(entry)) {
00728             int_32 rdl = -entry->info.offset;   /* negative offset */
00729             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00730             int rid = entry->info.offset;
00731 
00732             src = (char *)entry->data;
00733             rdlen = entry->rdlen;
00734 
00735             /* XXX Legacy regions do not include the region tag and data. */
00736             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00737                 int_32 stei[4];
00738 
00739                 legacy = 1;
00740 /*@-boundswrite@*/
00741                 memcpy(pe+1, src, rdl);
00742                 memcpy(te, src + rdl, rdlen);
00743 /*@=boundswrite@*/
00744                 te += rdlen;
00745 
00746                 pe->offset = htonl(te - dataStart);
00747                 stei[0] = pe->tag;
00748                 stei[1] = pe->type;
00749                 stei[2] = htonl(-rdl-entry->info.count);
00750                 stei[3] = pe->count;
00751 /*@-boundswrite@*/
00752                 memcpy(te, stei, entry->info.count);
00753 /*@=boundswrite@*/
00754                 te += entry->info.count;
00755                 ril++;
00756                 rdlen += entry->info.count;
00757 
00758                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00759                 if (count != rdlen)
00760                     goto errxit;
00761 
00762             } else {
00763 
00764 /*@-boundswrite@*/
00765                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00766                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00767 /*@=boundswrite@*/
00768                 te += rdlen;
00769                 {   /*@-castexpose@*/
00770                     entryInfo se = (entryInfo)src;
00771                     /*@=castexpose@*/
00772                     int off = ntohl(se->offset);
00773                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00774                 }
00775                 te += entry->info.count + drlen;
00776 
00777                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00778                 if (count != (rdlen + entry->info.count + drlen))
00779                     goto errxit;
00780             }
00781 
00782             /* Skip rest of entries in region. */
00783             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00784                 i++;
00785                 entry++;
00786             }
00787             i--;
00788             entry--;
00789             pe += ril;
00790             continue;
00791         }
00792 
00793         /* Ignore deleted drips. */
00794         if (entry->data == NULL || entry->length <= 0)
00795             continue;
00796 
00797         /* Alignment */
00798         type = entry->info.type;
00799         if (typeSizes[type] > 1) {
00800             unsigned diff;
00801             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00802             if (diff != typeSizes[type]) {
00803 /*@-boundswrite@*/
00804                 memset(te, 0, diff);
00805 /*@=boundswrite@*/
00806                 te += diff;
00807                 pad += diff;
00808             }
00809         }
00810 
00811         pe->offset = htonl(te - dataStart);
00812 
00813         /* copy data w/ endian conversions */
00814 /*@-boundswrite@*/
00815         switch (entry->info.type) {
00816         case RPM_INT32_TYPE:
00817             count = entry->info.count;
00818             src = entry->data;
00819             while (count--) {
00820                 *((int_32 *)te) = htonl(*((int_32 *)src));
00821                 /*@-sizeoftype@*/
00822                 te += sizeof(int_32);
00823                 src += sizeof(int_32);
00824                 /*@=sizeoftype@*/
00825             }
00826             /*@switchbreak@*/ break;
00827 
00828         case RPM_INT16_TYPE:
00829             count = entry->info.count;
00830             src = entry->data;
00831             while (count--) {
00832                 *((int_16 *)te) = htons(*((int_16 *)src));
00833                 /*@-sizeoftype@*/
00834                 te += sizeof(int_16);
00835                 src += sizeof(int_16);
00836                 /*@=sizeoftype@*/
00837             }
00838             /*@switchbreak@*/ break;
00839 
00840         default:
00841             memcpy(te, entry->data, entry->length);
00842             te += entry->length;
00843             /*@switchbreak@*/ break;
00844         }
00845 /*@=boundswrite@*/
00846         pe++;
00847     }
00848    
00849     /* Insure that there are no memcpy underruns/overruns. */
00850     if (((char *)pe) != dataStart)
00851         goto errxit;
00852     if ((((char *)ei)+len) != te)
00853         goto errxit;
00854 
00855     if (lengthPtr)
00856         *lengthPtr = len;
00857 
00858     h->flags &= ~HEADERFLAG_SORTED;
00859     headerSort(h);
00860 
00861     return (void *) ei;
00862 
00863 errxit:
00864     /*@-usereleased@*/
00865     ei = _free(ei);
00866     /*@=usereleased@*/
00867     return (void *) ei;
00868 }
00869 
00875 static /*@only@*/ /*@null@*/
00876 void * headerUnload(Header h)
00877         /*@modifies h @*/
00878 {
00879     int length;
00880 /*@-boundswrite@*/
00881     void * uh = doHeaderUnload(h, &length);
00882 /*@=boundswrite@*/
00883     return uh;
00884 }
00885 
00893 static /*@null@*/
00894 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00895         /*@modifies h @*/
00896 {
00897     indexEntry entry, entry2, last;
00898     struct indexEntry_s key;
00899 
00900     if (h == NULL) return NULL;
00901     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00902 
00903     key.info.tag = tag;
00904 
00905 /*@-boundswrite@*/
00906     entry2 = entry = 
00907         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00908 /*@=boundswrite@*/
00909     if (entry == NULL)
00910         return NULL;
00911 
00912     if (type == RPM_NULL_TYPE)
00913         return entry;
00914 
00915     /* look backwards */
00916     while (entry->info.tag == tag && entry->info.type != type &&
00917            entry > h->index) entry--;
00918 
00919     if (entry->info.tag == tag && entry->info.type == type)
00920         return entry;
00921 
00922     last = h->index + h->indexUsed;
00923     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00924     while (entry2->info.tag == tag && entry2->info.type != type &&
00925            entry2 < last) entry2++;
00926     /*@=usereleased@*/
00927 
00928     if (entry->info.tag == tag && entry->info.type == type)
00929         return entry;
00930 
00931     return NULL;
00932 }
00933 
00943 static
00944 int headerRemoveEntry(Header h, int_32 tag)
00945         /*@modifies h @*/
00946 {
00947     indexEntry last = h->index + h->indexUsed;
00948     indexEntry entry, first;
00949     int ne;
00950 
00951     entry = findEntry(h, tag, RPM_NULL_TYPE);
00952     if (!entry) return 1;
00953 
00954     /* Make sure entry points to the first occurence of this tag. */
00955     while (entry > h->index && (entry - 1)->info.tag == tag)  
00956         entry--;
00957 
00958     /* Free data for tags being removed. */
00959     for (first = entry; first < last; first++) {
00960         void * data;
00961         if (first->info.tag != tag)
00962             break;
00963         data = first->data;
00964         first->data = NULL;
00965         first->length = 0;
00966         if (ENTRY_IN_REGION(first))
00967             continue;
00968         data = _free(data);
00969     }
00970 
00971     ne = (first - entry);
00972     if (ne > 0) {
00973         h->indexUsed -= ne;
00974         ne = last - first;
00975 /*@-boundswrite@*/
00976         if (ne > 0)
00977             memmove(entry, first, (ne * sizeof(*entry)));
00978 /*@=boundswrite@*/
00979     }
00980 
00981     return 0;
00982 }
00983 
00989 static /*@null@*/
00990 Header headerLoad(/*@kept@*/ void * uh)
00991         /*@modifies uh @*/
00992 {
00993     int_32 * ei = (int_32 *) uh;
00994     int_32 il = ntohl(ei[0]);           /* index length */
00995     int_32 dl = ntohl(ei[1]);           /* data length */
00996     /*@-sizeoftype@*/
00997     size_t pvlen = sizeof(il) + sizeof(dl) +
00998                (il * sizeof(struct entryInfo_s)) + dl;
00999     /*@=sizeoftype@*/
01000     void * pv = uh;
01001     Header h = NULL;
01002     entryInfo pe;
01003     unsigned char * dataStart;
01004     unsigned char * dataEnd;
01005     indexEntry entry; 
01006     int rdlen;
01007     int i;
01008 
01009     /* Sanity checks on header intro. */
01010     if (hdrchkTags(il) || hdrchkData(dl))
01011         goto errxit;
01012 
01013     ei = (int_32 *) pv;
01014     /*@-castexpose@*/
01015     pe = (entryInfo) &ei[2];
01016     /*@=castexpose@*/
01017     dataStart = (unsigned char *) (pe + il);
01018     dataEnd = dataStart + dl;
01019 
01020     h = xcalloc(1, sizeof(*h));
01021     /*@-assignexpose@*/
01022     h->hv = *hdrVec;            /* structure assignment */
01023     /*@=assignexpose@*/
01024     /*@-assignexpose -kepttrans@*/
01025     h->blob = uh;
01026     /*@=assignexpose =kepttrans@*/
01027     h->indexAlloced = il + 1;
01028     h->indexUsed = il;
01029     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
01030     h->flags |= HEADERFLAG_SORTED;
01031     h->nrefs = 0;
01032     h = headerLink(h);
01033 
01034     /*
01035      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
01036      * %verifyscript tag that needs to be diddled.
01037      */
01038     if (ntohl(pe->tag) == 15 &&
01039         ntohl(pe->type) == RPM_STRING_TYPE &&
01040         ntohl(pe->count) == 1)
01041     {
01042         pe->tag = htonl(1079);
01043     }
01044 
01045     entry = h->index;
01046     i = 0;
01047     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
01048         h->flags |= HEADERFLAG_LEGACY;
01049         entry->info.type = REGION_TAG_TYPE;
01050         entry->info.tag = HEADER_IMAGE;
01051         /*@-sizeoftype@*/
01052         entry->info.count = REGION_TAG_COUNT;
01053         /*@=sizeoftype@*/
01054         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
01055 
01056         /*@-assignexpose@*/
01057         entry->data = pe;
01058         /*@=assignexpose@*/
01059         entry->length = pvlen - sizeof(il) - sizeof(dl);
01060         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01061 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01062         if (rdlen != dl)
01063             goto errxit;
01064 #endif
01065         entry->rdlen = rdlen;
01066         entry++;
01067         h->indexUsed++;
01068     } else {
01069         int_32 rdl;
01070         int_32 ril;
01071 
01072         h->flags &= ~HEADERFLAG_LEGACY;
01073 
01074         entry->info.type = htonl(pe->type);
01075         entry->info.count = htonl(pe->count);
01076 
01077         if (hdrchkType(entry->info.type))
01078             goto errxit;
01079         if (hdrchkTags(entry->info.count))
01080             goto errxit;
01081 
01082         {   int off = ntohl(pe->offset);
01083 
01084             if (hdrchkData(off))
01085                 goto errxit;
01086             if (off) {
01087 /*@-sizeoftype@*/
01088                 size_t nb = REGION_TAG_COUNT;
01089 /*@=sizeoftype@*/
01090                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01091                 rdl = -ntohl(stei[2]);  /* negative offset */
01092                 ril = rdl/sizeof(*pe);
01093                 if (hdrchkTags(ril) || hdrchkData(rdl))
01094                     goto errxit;
01095                 entry->info.tag = htonl(pe->tag);
01096             } else {
01097                 ril = il;
01098                 /*@-sizeoftype@*/
01099                 rdl = (ril * sizeof(struct entryInfo_s));
01100                 /*@=sizeoftype@*/
01101                 entry->info.tag = HEADER_IMAGE;
01102             }
01103         }
01104         entry->info.offset = -rdl;      /* negative offset */
01105 
01106         /*@-assignexpose@*/
01107         entry->data = pe;
01108         /*@=assignexpose@*/
01109         entry->length = pvlen - sizeof(il) - sizeof(dl);
01110         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01111         if (rdlen < 0)
01112             goto errxit;
01113         entry->rdlen = rdlen;
01114 
01115         if (ril < h->indexUsed) {
01116             indexEntry newEntry = entry + ril;
01117             int ne = (h->indexUsed - ril);
01118             int rid = entry->info.offset+1;
01119             int rc;
01120 
01121             /* Load dribble entries from region. */
01122             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01123             if (rc < 0)
01124                 goto errxit;
01125             rdlen += rc;
01126 
01127           { indexEntry firstEntry = newEntry;
01128             int save = h->indexUsed;
01129             int j;
01130 
01131             /* Dribble entries replace duplicate region entries. */
01132             h->indexUsed -= ne;
01133             for (j = 0; j < ne; j++, newEntry++) {
01134                 (void) headerRemoveEntry(h, newEntry->info.tag);
01135                 if (newEntry->info.tag == HEADER_BASENAMES)
01136                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01137             }
01138 
01139             /* If any duplicate entries were replaced, move new entries down. */
01140 /*@-boundswrite@*/
01141             if (h->indexUsed < (save - ne)) {
01142                 memmove(h->index + h->indexUsed, firstEntry,
01143                         (ne * sizeof(*entry)));
01144             }
01145 /*@=boundswrite@*/
01146             h->indexUsed += ne;
01147           }
01148         }
01149     }
01150 
01151     h->flags &= ~HEADERFLAG_SORTED;
01152     headerSort(h);
01153 
01154     /*@-globstate -observertrans @*/
01155     return h;
01156     /*@=globstate =observertrans @*/
01157 
01158 errxit:
01159     /*@-usereleased@*/
01160     if (h) {
01161         h->index = _free(h->index);
01162         /*@-refcounttrans@*/
01163         h = _free(h);
01164         /*@=refcounttrans@*/
01165     }
01166     /*@=usereleased@*/
01167     /*@-refcounttrans -globstate@*/
01168     return h;
01169     /*@=refcounttrans =globstate@*/
01170 }
01171 
01179 static /*@null@*/
01180 Header headerReload(/*@only@*/ Header h, int tag)
01181         /*@modifies h @*/
01182 {
01183     Header nh;
01184     int length;
01185     /*@-onlytrans@*/
01186 /*@-boundswrite@*/
01187     void * uh = doHeaderUnload(h, &length);
01188 /*@=boundswrite@*/
01189 
01190     h = headerFree(h);
01191     /*@=onlytrans@*/
01192     if (uh == NULL)
01193         return NULL;
01194     nh = headerLoad(uh);
01195     if (nh == NULL) {
01196         uh = _free(uh);
01197         return NULL;
01198     }
01199     if (nh->flags & HEADERFLAG_ALLOCATED)
01200         uh = _free(uh);
01201     nh->flags |= HEADERFLAG_ALLOCATED;
01202     if (ENTRY_IS_REGION(nh->index)) {
01203 /*@-boundswrite@*/
01204         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01205             nh->index[0].info.tag = tag;
01206 /*@=boundswrite@*/
01207     }
01208     return nh;
01209 }
01210 
01216 static /*@null@*/
01217 Header headerCopyLoad(const void * uh)
01218         /*@*/
01219 {
01220     int_32 * ei = (int_32 *) uh;
01221 /*@-boundsread@*/
01222     int_32 il = ntohl(ei[0]);           /* index length */
01223     int_32 dl = ntohl(ei[1]);           /* data length */
01224 /*@=boundsread@*/
01225     /*@-sizeoftype@*/
01226     size_t pvlen = sizeof(il) + sizeof(dl) +
01227                         (il * sizeof(struct entryInfo_s)) + dl;
01228     /*@=sizeoftype@*/
01229     void * nuh = NULL;
01230     Header h = NULL;
01231 
01232     /* Sanity checks on header intro. */
01233     /*@-branchstate@*/
01234     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01235 /*@-boundsread@*/
01236         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01237 /*@=boundsread@*/
01238         if ((h = headerLoad(nuh)) != NULL)
01239             h->flags |= HEADERFLAG_ALLOCATED;
01240     }
01241     /*@=branchstate@*/
01242     /*@-branchstate@*/
01243     if (h == NULL)
01244         nuh = _free(nuh);
01245     /*@=branchstate@*/
01246     return h;
01247 }
01248 
01255 static /*@null@*/
01256 Header headerRead(FD_t fd, enum hMagic magicp)
01257         /*@modifies fd @*/
01258 {
01259     int_32 block[4];
01260     int_32 reserved;
01261     int_32 * ei = NULL;
01262     int_32 il;
01263     int_32 dl;
01264     int_32 magic;
01265     Header h = NULL;
01266     size_t len;
01267     int i;
01268 
01269     memset(block, 0, sizeof(block));
01270     i = 2;
01271     if (magicp == HEADER_MAGIC_YES)
01272         i += 2;
01273 
01274     /*@-type@*/ /* FIX: cast? */
01275     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01276         goto exit;
01277     /*@=type@*/
01278 
01279     i = 0;
01280 
01281 /*@-boundsread@*/
01282     if (magicp == HEADER_MAGIC_YES) {
01283         magic = block[i++];
01284         if (memcmp(&magic, header_magic, sizeof(magic)))
01285             goto exit;
01286         reserved = block[i++];
01287     }
01288     
01289     il = ntohl(block[i]);       i++;
01290     dl = ntohl(block[i]);       i++;
01291 /*@=boundsread@*/
01292 
01293     /*@-sizeoftype@*/
01294     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01295     /*@=sizeoftype@*/
01296 
01297     /* Sanity checks on header intro. */
01298     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01299         goto exit;
01300 
01301 /*@-boundswrite@*/
01302     ei = xmalloc(len);
01303     ei[0] = htonl(il);
01304     ei[1] = htonl(dl);
01305     len -= sizeof(il) + sizeof(dl);
01306 /*@=boundswrite@*/
01307 
01308 /*@-boundsread@*/
01309     /*@-type@*/ /* FIX: cast? */
01310     if (timedRead(fd, (char *)&ei[2], len) != len)
01311         goto exit;
01312     /*@=type@*/
01313 /*@=boundsread@*/
01314     
01315     h = headerLoad(ei);
01316 
01317 exit:
01318     if (h) {
01319         if (h->flags & HEADERFLAG_ALLOCATED)
01320             ei = _free(ei);
01321         h->flags |= HEADERFLAG_ALLOCATED;
01322     } else if (ei)
01323         ei = _free(ei);
01324     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01325     return h;
01326     /*@-mustmod@*/
01327 }
01328 
01336 static
01337 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
01338         /*@globals fileSystem @*/
01339         /*@modifies fd, h, fileSystem @*/
01340 {
01341     ssize_t nb;
01342     int length;
01343     const void * uh;
01344 
01345     if (h == NULL)
01346         return 1;
01347 /*@-boundswrite@*/
01348     uh = doHeaderUnload(h, &length);
01349 /*@=boundswrite@*/
01350     if (uh == NULL)
01351         return 1;
01352     switch (magicp) {
01353     case HEADER_MAGIC_YES:
01354 /*@-boundsread@*/
01355         /*@-sizeoftype@*/
01356         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01357         /*@=sizeoftype@*/
01358 /*@=boundsread@*/
01359         if (nb != sizeof(header_magic))
01360             goto exit;
01361         break;
01362     case HEADER_MAGIC_NO:
01363         break;
01364     }
01365 
01366     /*@-sizeoftype@*/
01367     nb = Fwrite(uh, sizeof(char), length, fd);
01368     /*@=sizeoftype@*/
01369 
01370 exit:
01371     uh = _free(uh);
01372     return (nb == length ? 0 : 1);
01373 }
01374 
01381 static
01382 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01383         /*@*/
01384 {
01385     /*@-mods@*/         /*@ FIX: h modified by sort. */
01386     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01387     /*@=mods@*/ 
01388 }
01389 
01400 static int copyEntry(const indexEntry entry,
01401                 /*@null@*/ /*@out@*/ hTYP_t type,
01402                 /*@null@*/ /*@out@*/ hPTR_t * p,
01403                 /*@null@*/ /*@out@*/ hCNT_t c,
01404                 int minMem)
01405         /*@modifies *type, *p, *c @*/
01406         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01407 {
01408     int_32 count = entry->info.count;
01409     int rc = 1;         /* XXX 1 on success. */
01410 
01411     if (p)
01412     switch (entry->info.type) {
01413     case RPM_BIN_TYPE:
01414         /*
01415          * XXX This only works for
01416          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01417          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01418          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01419          */
01420         if (ENTRY_IS_REGION(entry)) {
01421             int_32 * ei = ((int_32 *)entry->data) - 2;
01422             /*@-castexpose@*/
01423             entryInfo pe = (entryInfo) (ei + 2);
01424             /*@=castexpose@*/
01425 /*@-boundsread@*/
01426             char * dataStart = (char *) (pe + ntohl(ei[0]));
01427 /*@=boundsread@*/
01428             int_32 rdl = -entry->info.offset;   /* negative offset */
01429             int_32 ril = rdl/sizeof(*pe);
01430 
01431             /*@-sizeoftype@*/
01432             rdl = entry->rdlen;
01433             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01434             if (entry->info.tag == HEADER_IMAGE) {
01435                 ril -= 1;
01436                 pe += 1;
01437             } else {
01438                 count += REGION_TAG_COUNT;
01439                 rdl += REGION_TAG_COUNT;
01440             }
01441 
01442 /*@-bounds@*/
01443             *p = xmalloc(count);
01444             ei = (int_32 *) *p;
01445             ei[0] = htonl(ril);
01446             ei[1] = htonl(rdl);
01447 
01448             /*@-castexpose@*/
01449             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01450             /*@=castexpose@*/
01451 
01452             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01453             /*@=sizeoftype@*/
01454 /*@=bounds@*/
01455 
01456             rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01457             /* XXX 1 on success. */
01458             rc = (rc < 0) ? 0 : 1;
01459         } else {
01460             count = entry->length;
01461             *p = (!minMem
01462                 ? memcpy(xmalloc(count), entry->data, count)
01463                 : entry->data);
01464         }
01465         break;
01466     case RPM_STRING_TYPE:
01467         if (count == 1) {
01468             *p = entry->data;
01469             break;
01470         }
01471         /*@fallthrough@*/
01472     case RPM_STRING_ARRAY_TYPE:
01473     case RPM_I18NSTRING_TYPE:
01474     {   const char ** ptrEntry;
01475         /*@-sizeoftype@*/
01476         int tableSize = count * sizeof(char *);
01477         /*@=sizeoftype@*/
01478         char * t;
01479         int i;
01480 
01481 /*@-bounds@*/
01482         /*@-mods@*/
01483         if (minMem) {
01484             *p = xmalloc(tableSize);
01485             ptrEntry = (const char **) *p;
01486             t = entry->data;
01487         } else {
01488             t = xmalloc(tableSize + entry->length);
01489             *p = (void *)t;
01490             ptrEntry = (const char **) *p;
01491             t += tableSize;
01492             memcpy(t, entry->data, entry->length);
01493         }
01494         /*@=mods@*/
01495 /*@=bounds@*/
01496         for (i = 0; i < count; i++) {
01497 /*@-boundswrite@*/
01498             *ptrEntry++ = t;
01499 /*@=boundswrite@*/
01500             t = strchr(t, 0);
01501             t++;
01502         }
01503     }   break;
01504 
01505     default:
01506         *p = entry->data;
01507         break;
01508     }
01509     if (type) *type = entry->info.type;
01510     if (c) *c = count;
01511     return rc;
01512 }
01513 
01532 static int headerMatchLocale(const char *td, const char *l, const char *le)
01533         /*@*/
01534 {
01535     const char *fe;
01536 
01537 
01538 #if 0
01539   { const char *s, *ll, *CC, *EE, *dd;
01540     char *lbuf, *t.
01541 
01542     /* Copy the buffer and parse out components on the fly. */
01543     lbuf = alloca(le - l + 1);
01544     for (s = l, ll = t = lbuf; *s; s++, t++) {
01545         switch (*s) {
01546         case '_':
01547             *t = '\0';
01548             CC = t + 1;
01549             break;
01550         case '.':
01551             *t = '\0';
01552             EE = t + 1;
01553             break;
01554         case '@':
01555             *t = '\0';
01556             dd = t + 1;
01557             break;
01558         default:
01559             *t = *s;
01560             break;
01561         }
01562     }
01563 
01564     if (ll)     /* ISO language should be lower case */
01565         for (t = ll; *t; t++)   *t = tolower(*t);
01566     if (CC)     /* ISO country code should be upper case */
01567         for (t = CC; *t; t++)   *t = toupper(*t);
01568 
01569     /* There are a total of 16 cases to attempt to match. */
01570   }
01571 #endif
01572 
01573     /* First try a complete match. */
01574     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01575         return 1;
01576 
01577     /* Next, try stripping optional dialect and matching.  */
01578     for (fe = l; fe < le && *fe != '@'; fe++)
01579         {};
01580     if (fe < le && !strncmp(td, l, (fe - l)))
01581         return 1;
01582 
01583     /* Next, try stripping optional codeset and matching.  */
01584     for (fe = l; fe < le && *fe != '.'; fe++)
01585         {};
01586     if (fe < le && !strncmp(td, l, (fe - l)))
01587         return 1;
01588 
01589     /* Finally, try stripping optional country code and matching. */
01590     for (fe = l; fe < le && *fe != '_'; fe++)
01591         {};
01592     if (fe < le && !strncmp(td, l, (fe - l)))
01593         return 1;
01594 
01595     return 0;
01596 }
01597 
01604 /*@dependent@*/ /*@exposed@*/ static char *
01605 headerFindI18NString(Header h, indexEntry entry)
01606         /*@*/
01607 {
01608     const char *lang, *l, *le;
01609     indexEntry table;
01610 
01611     /* XXX Drepper sez' this is the order. */
01612     if ((lang = getenv("LANGUAGE")) == NULL &&
01613         (lang = getenv("LC_ALL")) == NULL &&
01614         (lang = getenv("LC_MESSAGES")) == NULL &&
01615         (lang = getenv("LANG")) == NULL)
01616             return entry->data;
01617     
01618     /*@-mods@*/
01619     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01620         return entry->data;
01621     /*@=mods@*/
01622 
01623 /*@-boundsread@*/
01624     for (l = lang; *l != '\0'; l = le) {
01625         const char *td;
01626         char *ed;
01627         int langNum;
01628 
01629         while (*l && *l == ':')                 /* skip leading colons */
01630             l++;
01631         if (*l == '\0')
01632             break;
01633         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01634             {};
01635 
01636         /* For each entry in the header ... */
01637         for (langNum = 0, td = table->data, ed = entry->data;
01638              langNum < entry->info.count;
01639              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01640 
01641                 if (headerMatchLocale(td, l, le))
01642                     return ed;
01643 
01644         }
01645     }
01646 /*@=boundsread@*/
01647 
01648     return entry->data;
01649 }
01650 
01661 static int intGetEntry(Header h, int_32 tag,
01662                 /*@null@*/ /*@out@*/ hTAG_t type,
01663                 /*@null@*/ /*@out@*/ hPTR_t * p,
01664                 /*@null@*/ /*@out@*/ hCNT_t c,
01665                 int minMem)
01666         /*@modifies *type, *p, *c @*/
01667         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01668 {
01669     indexEntry entry;
01670     int rc;
01671 
01672     /* First find the tag */
01673     /*@-mods@*/         /*@ FIX: h modified by sort. */
01674     entry = findEntry(h, tag, RPM_NULL_TYPE);
01675     /*@mods@*/
01676     if (entry == NULL) {
01677         if (type) type = 0;
01678         if (p) *p = NULL;
01679         if (c) *c = 0;
01680         return 0;
01681     }
01682 
01683     switch (entry->info.type) {
01684     case RPM_I18NSTRING_TYPE:
01685         rc = 1;
01686         if (type) *type = RPM_STRING_TYPE;
01687         if (c) *c = 1;
01688         /*@-dependenttrans@*/
01689         if (p) *p = headerFindI18NString(h, entry);
01690         /*@=dependenttrans@*/
01691         break;
01692     default:
01693         rc = copyEntry(entry, type, p, c, minMem);
01694         break;
01695     }
01696 
01697     /* XXX 1 on success */
01698     return ((rc == 1) ? 1 : 0);
01699 }
01700 
01708 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01709                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01710         /*@modifies data @*/
01711 {
01712     if (data) {
01713         /*@-branchstate@*/
01714         if (type == -1 ||
01715             type == RPM_STRING_ARRAY_TYPE ||
01716             type == RPM_I18NSTRING_TYPE ||
01717             type == RPM_BIN_TYPE)
01718                 data = _free(data);
01719         /*@=branchstate@*/
01720     }
01721     return NULL;
01722 }
01723 
01737 static
01738 int headerGetEntry(Header h, int_32 tag,
01739                         /*@null@*/ /*@out@*/ hTYP_t type,
01740                         /*@null@*/ /*@out@*/ void ** p,
01741                         /*@null@*/ /*@out@*/ hCNT_t c)
01742         /*@modifies *type, *p, *c @*/
01743         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01744 {
01745     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01746 }
01747 
01760 static
01761 int headerGetEntryMinMemory(Header h, int_32 tag,
01762                         /*@null@*/ /*@out@*/ hTYP_t type,
01763                         /*@null@*/ /*@out@*/ hPTR_t * p,
01764                         /*@null@*/ /*@out@*/ hCNT_t c)
01765         /*@modifies *type, *p, *c @*/
01766         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01767 {
01768     return intGetEntry(h, tag, type, p, c, 1);
01769 }
01770 
01771 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01772                 int_32 * c)
01773 {
01774     indexEntry entry;
01775     int rc;
01776 
01777     if (p == NULL) return headerIsEntry(h, tag);
01778 
01779     /* First find the tag */
01780     /*@-mods@*/         /*@ FIX: h modified by sort. */
01781     entry = findEntry(h, tag, RPM_NULL_TYPE);
01782     /*@=mods@*/
01783     if (!entry) {
01784         if (p) *p = NULL;
01785         if (c) *c = 0;
01786         return 0;
01787     }
01788 
01789     rc = copyEntry(entry, type, p, c, 0);
01790 
01791     /* XXX 1 on success */
01792     return ((rc == 1) ? 1 : 0);
01793 }
01794 
01797 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01798                 int_32 cnt, int dataLength)
01799         /*@modifies *dstPtr @*/
01800 {
01801     switch (type) {
01802     case RPM_STRING_ARRAY_TYPE:
01803     case RPM_I18NSTRING_TYPE:
01804     {   const char ** av = (const char **) srcPtr;
01805         char * t = dstPtr;
01806 
01807 /*@-bounds@*/
01808         while (cnt-- > 0 && dataLength > 0) {
01809             const char * s;
01810             if ((s = *av++) == NULL)
01811                 continue;
01812             do {
01813                 *t++ = *s++;
01814             } while (s[-1] && --dataLength > 0);
01815         }
01816 /*@=bounds@*/
01817     }   break;
01818 
01819     default:
01820 /*@-boundswrite@*/
01821         memmove(dstPtr, srcPtr, dataLength);
01822 /*@=boundswrite@*/
01823         break;
01824     }
01825 }
01826 
01835 /*@null@*/
01836 static void *
01837 grabData(int_32 type, hPTR_t p, int_32 c, /*@out@*/ int * lengthPtr)
01838         /*@modifies *lengthPtr @*/
01839         /*@requires maxSet(lengthPtr) >= 0 @*/
01840 {
01841     void * data = NULL;
01842     int length;
01843 
01844     length = dataLength(type, p, c, 0, NULL);
01845 /*@-branchstate@*/
01846     if (length > 0) {
01847         data = xmalloc(length);
01848         copyData(type, data, p, c, length);
01849     }
01850 /*@=branchstate@*/
01851 
01852     if (lengthPtr)
01853         *lengthPtr = length;
01854     return data;
01855 }
01856 
01871 static
01872 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01873         /*@modifies h @*/
01874 {
01875     indexEntry entry;
01876     void * data;
01877     int length;
01878 
01879     /* Count must always be >= 1 for headerAddEntry. */
01880     if (c <= 0)
01881         return 0;
01882 
01883     if (hdrchkType(type))
01884         return 0;
01885     if (hdrchkData(c))
01886         return 0;
01887 
01888     length = 0;
01889 /*@-boundswrite@*/
01890     data = grabData(type, p, c, &length);
01891 /*@=boundswrite@*/
01892     if (data == NULL || length <= 0)
01893         return 0;
01894 
01895     /* Allocate more index space if necessary */
01896     if (h->indexUsed == h->indexAlloced) {
01897         h->indexAlloced += INDEX_MALLOC_SIZE;
01898         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01899     }
01900 
01901     /* Fill in the index */
01902     entry = h->index + h->indexUsed;
01903     entry->info.tag = tag;
01904     entry->info.type = type;
01905     entry->info.count = c;
01906     entry->info.offset = 0;
01907     entry->data = data;
01908     entry->length = length;
01909 
01910 /*@-boundsread@*/
01911     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01912         h->flags &= ~HEADERFLAG_SORTED;
01913 /*@=boundsread@*/
01914     h->indexUsed++;
01915 
01916     return 1;
01917 }
01918 
01933 static
01934 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01935                 const void * p, int_32 c)
01936         /*@modifies h @*/
01937 {
01938     indexEntry entry;
01939     int length;
01940 
01941     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01942         /* we can't do this */
01943         return 0;
01944     }
01945 
01946     /* Find the tag entry in the header. */
01947     entry = findEntry(h, tag, type);
01948     if (!entry)
01949         return 0;
01950 
01951     length = dataLength(type, p, c, 0, NULL);
01952     if (length < 0)
01953         return 0;
01954 
01955     if (ENTRY_IN_REGION(entry)) {
01956         char * t = xmalloc(entry->length + length);
01957 /*@-bounds@*/
01958         memcpy(t, entry->data, entry->length);
01959 /*@=bounds@*/
01960         entry->data = t;
01961         entry->info.offset = 0;
01962     } else
01963         entry->data = xrealloc(entry->data, entry->length + length);
01964 
01965     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01966 
01967     entry->length += length;
01968 
01969     entry->info.count += c;
01970 
01971     return 1;
01972 }
01973 
01984 static
01985 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01986                 const void * p, int_32 c)
01987         /*@modifies h @*/
01988 {
01989     return (findEntry(h, tag, type)
01990         ? headerAppendEntry(h, tag, type, p, c)
01991         : headerAddEntry(h, tag, type, p, c));
01992 }
01993 
02014 static
02015 int headerAddI18NString(Header h, int_32 tag, const char * string,
02016                 const char * lang)
02017         /*@modifies h @*/
02018 {
02019     indexEntry table, entry;
02020     const char ** strArray;
02021     int length;
02022     int ghosts;
02023     int i, langNum;
02024     char * buf;
02025 
02026     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02027     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
02028 
02029     if (!table && entry)
02030         return 0;               /* this shouldn't ever happen!! */
02031 
02032     if (!table && !entry) {
02033         const char * charArray[2];
02034         int count = 0;
02035         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
02036             /*@-observertrans -readonlytrans@*/
02037             charArray[count++] = "C";
02038             /*@=observertrans =readonlytrans@*/
02039         } else {
02040             /*@-observertrans -readonlytrans@*/
02041             charArray[count++] = "C";
02042             /*@=observertrans =readonlytrans@*/
02043             charArray[count++] = lang;
02044         }
02045         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
02046                         &charArray, count))
02047             return 0;
02048         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
02049     }
02050 
02051     if (!table)
02052         return 0;
02053     /*@-branchstate@*/
02054     if (!lang) lang = "C";
02055     /*@=branchstate@*/
02056 
02057     {   const char * l = table->data;
02058         for (langNum = 0; langNum < table->info.count; langNum++) {
02059             if (!strcmp(l, lang)) break;
02060             l += strlen(l) + 1;
02061         }
02062     }
02063 
02064     if (langNum >= table->info.count) {
02065         length = strlen(lang) + 1;
02066         if (ENTRY_IN_REGION(table)) {
02067             char * t = xmalloc(table->length + length);
02068             memcpy(t, table->data, table->length);
02069             table->data = t;
02070             table->info.offset = 0;
02071         } else
02072             table->data = xrealloc(table->data, table->length + length);
02073         memmove(((char *)table->data) + table->length, lang, length);
02074         table->length += length;
02075         table->info.count++;
02076     }
02077 
02078     if (!entry) {
02079         strArray = alloca(sizeof(*strArray) * (langNum + 1));
02080         for (i = 0; i < langNum; i++)
02081             strArray[i] = "";
02082         strArray[langNum] = string;
02083         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
02084                                 langNum + 1);
02085     } else if (langNum >= entry->info.count) {
02086         ghosts = langNum - entry->info.count;
02087         
02088         length = strlen(string) + 1 + ghosts;
02089         if (ENTRY_IN_REGION(entry)) {
02090             char * t = xmalloc(entry->length + length);
02091             memcpy(t, entry->data, entry->length);
02092             entry->data = t;
02093             entry->info.offset = 0;
02094         } else
02095             entry->data = xrealloc(entry->data, entry->length + length);
02096 
02097         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02098         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02099 
02100         entry->length += length;
02101         entry->info.count = langNum + 1;
02102     } else {
02103         char *b, *be, *e, *ee, *t;
02104         size_t bn, sn, en;
02105 
02106         /* Set beginning/end pointers to previous data */
02107         b = be = e = ee = entry->data;
02108         for (i = 0; i < table->info.count; i++) {
02109             if (i == langNum)
02110                 be = ee;
02111             ee += strlen(ee) + 1;
02112             if (i == langNum)
02113                 e  = ee;
02114         }
02115 
02116         /* Get storage for new buffer */
02117         bn = (be-b);
02118         sn = strlen(string) + 1;
02119         en = (ee-e);
02120         length = bn + sn + en;
02121         t = buf = xmalloc(length);
02122 
02123         /* Copy values into new storage */
02124         memcpy(t, b, bn);
02125         t += bn;
02126 /*@-mayaliasunique@*/
02127         memcpy(t, string, sn);
02128         t += sn;
02129         memcpy(t, e, en);
02130         t += en;
02131 /*@=mayaliasunique@*/
02132 
02133         /* Replace i18N string array */
02134         entry->length -= strlen(be) + 1;
02135         entry->length += sn;
02136         
02137         if (ENTRY_IN_REGION(entry)) {
02138             entry->info.offset = 0;
02139         } else
02140             entry->data = _free(entry->data);
02141         /*@-dependenttrans@*/
02142         entry->data = buf;
02143         /*@=dependenttrans@*/
02144     }
02145 
02146     return 0;
02147 }
02148 
02159 static
02160 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02161                         const void * p, int_32 c)
02162         /*@modifies h @*/
02163 {
02164     indexEntry entry;
02165     void * oldData;
02166     void * data;
02167     int length;
02168 
02169     /* First find the tag */
02170     entry = findEntry(h, tag, type);
02171     if (!entry)
02172         return 0;
02173 
02174     length = 0;
02175     data = grabData(type, p, c, &length);
02176     if (data == NULL || length <= 0)
02177         return 0;
02178 
02179     /* make sure entry points to the first occurence of this tag */
02180     while (entry > h->index && (entry - 1)->info.tag == tag)  
02181         entry--;
02182 
02183     /* free after we've grabbed the new data in case the two are intertwined;
02184        that's a bad idea but at least we won't break */
02185     oldData = entry->data;
02186 
02187     entry->info.count = c;
02188     entry->info.type = type;
02189     entry->data = data;
02190     entry->length = length;
02191 
02192     /*@-branchstate@*/
02193     if (ENTRY_IN_REGION(entry)) {
02194         entry->info.offset = 0;
02195     } else
02196         oldData = _free(oldData);
02197     /*@=branchstate@*/
02198 
02199     return 1;
02200 }
02201 
02204 static char escapedChar(const char ch)  /*@*/
02205 {
02206     switch (ch) {
02207     case 'a':   return '\a';
02208     case 'b':   return '\b';
02209     case 'f':   return '\f';
02210     case 'n':   return '\n';
02211     case 'r':   return '\r';
02212     case 't':   return '\t';
02213     case 'v':   return '\v';
02214     default:    return ch;
02215     }
02216 }
02217 
02224 static /*@null@*/ sprintfToken
02225 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02226         /*@modifies *format @*/
02227 {
02228     int i;
02229 
02230     if (format == NULL) return NULL;
02231 
02232     for (i = 0; i < num; i++) {
02233         switch (format[i].type) {
02234         case PTOK_ARRAY:
02235 /*@-boundswrite@*/
02236             format[i].u.array.format =
02237                 freeFormat(format[i].u.array.format,
02238                         format[i].u.array.numTokens);
02239 /*@=boundswrite@*/
02240             /*@switchbreak@*/ break;
02241         case PTOK_COND:
02242 /*@-boundswrite@*/
02243             format[i].u.cond.ifFormat =
02244                 freeFormat(format[i].u.cond.ifFormat, 
02245                         format[i].u.cond.numIfTokens);
02246             format[i].u.cond.elseFormat =
02247                 freeFormat(format[i].u.cond.elseFormat, 
02248                         format[i].u.cond.numElseTokens);
02249 /*@=boundswrite@*/
02250             /*@switchbreak@*/ break;
02251         case PTOK_NONE:
02252         case PTOK_TAG:
02253         case PTOK_STRING:
02254         default:
02255             /*@switchbreak@*/ break;
02256         }
02257     }
02258     format = _free(format);
02259     return NULL;
02260 }
02261 
02265 struct headerIterator_s {
02266 /*@unused@*/
02267     Header h;           
02268 /*@unused@*/
02269     int next_index;     
02270 };
02271 
02277 static /*@null@*/
02278 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
02279         /*@modifies hi @*/
02280 {
02281     if (hi != NULL) {
02282         hi->h = headerFree(hi->h);
02283         hi = _free(hi);
02284     }
02285     return hi;
02286 }
02287 
02293 static
02294 HeaderIterator headerInitIterator(Header h)
02295         /*@modifies h */
02296 {
02297     HeaderIterator hi = xmalloc(sizeof(*hi));
02298 
02299     headerSort(h);
02300 
02301     hi->h = headerLink(h);
02302     hi->next_index = 0;
02303     return hi;
02304 }
02305 
02315 static
02316 int headerNextIterator(HeaderIterator hi,
02317                 /*@null@*/ /*@out@*/ hTAG_t tag,
02318                 /*@null@*/ /*@out@*/ hTYP_t type,
02319                 /*@null@*/ /*@out@*/ hPTR_t * p,
02320                 /*@null@*/ /*@out@*/ hCNT_t c)
02321         /*@modifies hi, *tag, *type, *p, *c @*/
02322         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
02323                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
02324 {
02325     Header h = hi->h;
02326     int slot = hi->next_index;
02327     indexEntry entry = NULL;
02328     int rc;
02329 
02330     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
02331         entry = h->index + slot;
02332         if (!ENTRY_IS_REGION(entry))
02333             break;
02334     }
02335     hi->next_index = slot;
02336     if (entry == NULL || slot >= h->indexUsed)
02337         return 0;
02338 
02339     /*@-noeffect@*/     /* LCL: no clue */
02340     hi->next_index++;
02341     /*@=noeffect@*/
02342 
02343     if (tag)
02344         *tag = entry->info.tag;
02345 
02346     rc = copyEntry(entry, type, p, c, 0);
02347 
02348     /* XXX 1 on success */
02349     return ((rc == 1) ? 1 : 0);
02350 }
02351 
02357 static /*@null@*/
02358 Header headerCopy(Header h)
02359         /*@modifies h @*/
02360 {
02361     Header nh = headerNew();
02362     HeaderIterator hi;
02363     int_32 tag, type, count;
02364     hPTR_t ptr;
02365    
02366     /*@-branchstate@*/
02367     for (hi = headerInitIterator(h);
02368         headerNextIterator(hi, &tag, &type, &ptr, &count);
02369         ptr = headerFreeData((void *)ptr, type))
02370     {
02371         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
02372     }
02373     hi = headerFreeIterator(hi);
02374     /*@=branchstate@*/
02375 
02376     return headerReload(nh, HEADER_IMAGE);
02377 }
02378 
02381 typedef struct headerSprintfArgs_s {
02382     Header h;
02383     char * fmt;
02384 /*@temp@*/
02385     headerTagTableEntry tags;
02386 /*@temp@*/
02387     headerSprintfExtension exts;
02388 /*@observer@*/ /*@null@*/
02389     const char * errmsg;
02390     rpmec ec;
02391     sprintfToken format;
02392 /*@relnull@*/
02393     HeaderIterator hi;
02394 /*@owned@*/
02395     char * val;
02396     size_t vallen;
02397     size_t alloced;
02398     int numTokens;
02399     int i;
02400 } * headerSprintfArgs;
02401 
02407 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
02408         /*@modifies hsa */
02409 {
02410     sprintfTag tag =
02411         (hsa->format->type == PTOK_TAG
02412             ? &hsa->format->u.tag :
02413         (hsa->format->type == PTOK_ARRAY
02414             ? &hsa->format->u.array.format->u.tag :
02415         NULL));
02416 
02417     if (hsa != NULL) {
02418         hsa->i = 0;
02419         if (tag != NULL && tag->tag == -2)
02420             hsa->hi = headerInitIterator(hsa->h);
02421     }
02422 /*@-nullret@*/
02423     return hsa;
02424 /*@=nullret@*/
02425 }
02426 
02432 /*@null@*/
02433 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
02434         /*@modifies hsa */
02435 {
02436     sprintfToken fmt = NULL;
02437     sprintfTag tag =
02438         (hsa->format->type == PTOK_TAG
02439             ? &hsa->format->u.tag :
02440         (hsa->format->type == PTOK_ARRAY
02441             ? &hsa->format->u.array.format->u.tag :
02442         NULL));
02443 
02444     if (hsa != NULL && hsa->i >= 0 && hsa->i < hsa->numTokens) {
02445         fmt = hsa->format + hsa->i;
02446         if (hsa->hi == NULL) {
02447             hsa->i++;
02448         } else {
02449             int_32 tagno;
02450             int_32 type;
02451             int_32 count;
02452 
02453 /*@-boundswrite@*/
02454             if (!headerNextIterator(hsa->hi, &tagno, &type, NULL, &count))
02455                 fmt = NULL;
02456             tag->tag = tagno;
02457 /*@=boundswrite@*/
02458         }
02459     }
02460 
02461 /*@-dependenttrans -onlytrans@*/
02462     return fmt;
02463 /*@=dependenttrans =onlytrans@*/
02464 }
02465 
02471 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
02472         /*@modifies hsa */
02473 {
02474     if (hsa != NULL) {
02475         hsa->hi = headerFreeIterator(hsa->hi);
02476         hsa->i = 0;
02477     }
02478 /*@-nullret@*/
02479     return hsa;
02480 /*@=nullret@*/
02481 }
02482 
02489 /*@dependent@*/ /*@exposed@*/
02490 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
02491         /*@modifies hsa */
02492 {
02493     if ((hsa->vallen + need) >= hsa->alloced) {
02494         if (hsa->alloced <= need)
02495             hsa->alloced += need;
02496         hsa->alloced <<= 1;
02497         hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
02498     }
02499     return hsa->val + hsa->vallen;
02500 }
02501 
02509 /*@observer@*/ /*@null@*/
02510 static const char * myTagName(headerTagTableEntry tbl, int val)
02511         /*@*/
02512 {
02513     static char name[128];
02514     const char * s;
02515     char *t;
02516 
02517     for (; tbl->name != NULL; tbl++) {
02518         if (tbl->val == val)
02519             break;
02520     }
02521     if ((s = tbl->name) == NULL)
02522         return NULL;
02523     s += sizeof("RPMTAG_") - 1;
02524     t = name;
02525     *t++ = *s++;
02526     while (*s != '\0')
02527         *t++ = xtolower(*s++);
02528     *t = '\0';
02529     return name;
02530 }
02531 
02539 static int myTagValue(headerTagTableEntry tbl, const char * name)
02540         /*@*/
02541 {
02542     for (; tbl->name != NULL; tbl++) {
02543         if (!xstrcasecmp(tbl->name, name))
02544             return tbl->val;
02545     }
02546     return 0;
02547 }
02548 
02555 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
02556         /*@modifies token @*/
02557 {
02558     headerSprintfExtension ext;
02559     sprintfTag stag = (token->type == PTOK_COND
02560         ? &token->u.cond.tag : &token->u.tag);
02561 
02562     stag->fmt = NULL;
02563     stag->ext = NULL;
02564     stag->extNum = 0;
02565     stag->tag = -1;
02566 
02567     if (!strcmp(name, "*")) {
02568         stag->tag = -2;
02569         goto bingo;
02570     }
02571 
02572 /*@-branchstate@*/
02573     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02574 /*@-boundswrite@*/
02575         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02576         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02577         name = t;
02578 /*@=boundswrite@*/
02579     }
02580 /*@=branchstate@*/
02581 
02582     /* Search extensions for specific tag override. */
02583     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02584         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02585     {
02586         if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
02587             continue;
02588         if (!xstrcasecmp(ext->name, name)) {
02589             stag->ext = ext->u.tagFunction;
02590             stag->extNum = ext - hsa->exts;
02591             goto bingo;
02592         }
02593     }
02594 
02595     /* Search tag names. */
02596     stag->tag = myTagValue(hsa->tags, name);
02597     if (stag->tag != 0)
02598         goto bingo;
02599 
02600     return 1;
02601 
02602 bingo:
02603     /* Search extensions for specific format. */
02604     if (stag->type != NULL)
02605     for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
02606             ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
02607     {
02608         if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
02609             continue;
02610         if (!strcmp(ext->name, stag->type)) {
02611             stag->fmt = ext->u.formatFunction;
02612             break;
02613         }
02614     }
02615     return 0;
02616 }
02617 
02618 /* forward ref */
02626 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02627                 char * str, /*@out@*/char ** endPtr)
02628         /*@modifies hsa, str, token, *endPtr @*/
02629         /*@requires maxSet(endPtr) >= 0 @*/;
02630 
02640 static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
02641                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02642                 /*@null@*/ /*@out@*/ char ** endPtr, int state)
02643         /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
02644         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02645                 /\ maxSet(endPtr) >= 0 @*/
02646 {
02647     char * chptr, * start, * next, * dst;
02648     sprintfToken format;
02649     sprintfToken token;
02650     int numTokens;
02651     int i;
02652     int done = 0;
02653 
02654     /* upper limit on number of individual formats */
02655     numTokens = 0;
02656     if (str != NULL)
02657     for (chptr = str; *chptr != '\0'; chptr++)
02658         if (*chptr == '%') numTokens++;
02659     numTokens = numTokens * 2 + 1;
02660 
02661     format = xcalloc(numTokens, sizeof(*format));
02662     if (endPtr) *endPtr = NULL;
02663 
02664     /*@-infloops@*/ /* LCL: can't detect done termination */
02665     dst = start = str;
02666     numTokens = 0;
02667     token = NULL;
02668     if (start != NULL)
02669     while (*start != '\0') {
02670         switch (*start) {
02671         case '%':
02672             /* handle %% */
02673             if (*(start + 1) == '%') {
02674                 if (token == NULL || token->type != PTOK_STRING) {
02675                     token = format + numTokens++;
02676                     token->type = PTOK_STRING;
02677                     /*@-temptrans -assignexpose@*/
02678                     dst = token->u.string.string = start;
02679                     /*@=temptrans =assignexpose@*/
02680                 }
02681                 start++;
02682 /*@-boundswrite@*/
02683                 *dst++ = *start++;
02684 /*@=boundswrite@*/
02685                 /*@switchbreak@*/ break;
02686             } 
02687 
02688             token = format + numTokens++;
02689 /*@-boundswrite@*/
02690             *dst++ = '\0';
02691 /*@=boundswrite@*/
02692             start++;
02693 
02694             if (*start == '|') {
02695                 char * newEnd;
02696 
02697                 start++;
02698 /*@-boundswrite@*/
02699                 if (parseExpression(hsa, token, start, &newEnd))
02700                 {
02701                     format = freeFormat(format, numTokens);
02702                     return 1;
02703                 }
02704 /*@=boundswrite@*/
02705                 start = newEnd;
02706                 /*@switchbreak@*/ break;
02707             }
02708 
02709             /*@-assignexpose@*/
02710             token->u.tag.format = start;
02711             /*@=assignexpose@*/
02712             token->u.tag.pad = 0;
02713             token->u.tag.justOne = 0;
02714             token->u.tag.arrayCount = 0;
02715 
02716             chptr = start;
02717             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02718             if (!*chptr || *chptr == '%') {
02719                 hsa->errmsg = _("missing { after %");
02720                 format = freeFormat(format, numTokens);
02721                 return 1;
02722             }
02723 
02724 /*@-boundswrite@*/
02725             *chptr++ = '\0';
02726 /*@=boundswrite@*/
02727 
02728             while (start < chptr) {
02729                 if (xisdigit(*start)) {
02730                     i = strtoul(start, &start, 10);
02731                     token->u.tag.pad += i;
02732                 } else {
02733                     start++;
02734                 }
02735             }
02736 
02737             if (*start == '=') {
02738                 token->u.tag.justOne = 1;
02739                 start++;
02740             } else if (*start == '#') {
02741                 token->u.tag.justOne = 1;
02742                 token->u.tag.arrayCount = 1;
02743                 start++;
02744             }
02745 
02746             next = start;
02747             while (*next && *next != '}') next++;
02748             if (!*next) {
02749                 hsa->errmsg = _("missing } after %{");
02750                 format = freeFormat(format, numTokens);
02751                 return 1;
02752             }
02753 /*@-boundswrite@*/
02754             *next++ = '\0';
02755 /*@=boundswrite@*/
02756 
02757             chptr = start;
02758             while (*chptr && *chptr != ':') chptr++;
02759 
02760             if (*chptr != '\0') {
02761 /*@-boundswrite@*/
02762                 *chptr++ = '\0';
02763 /*@=boundswrite@*/
02764                 if (!*chptr) {
02765                     hsa->errmsg = _("empty tag format");
02766                     format = freeFormat(format, numTokens);
02767                     return 1;
02768                 }
02769                 /*@-assignexpose@*/
02770                 token->u.tag.type = chptr;
02771                 /*@=assignexpose@*/
02772             } else {
02773                 token->u.tag.type = NULL;
02774             }
02775             
02776             if (!*start) {
02777                 hsa->errmsg = _("empty tag name");
02778                 format = freeFormat(format, numTokens);
02779                 return 1;
02780             }
02781 
02782             i = 0;
02783             token->type = PTOK_TAG;
02784 
02785             if (findTag(hsa, token, start)) {
02786                 hsa->errmsg = _("unknown tag");
02787                 format = freeFormat(format, numTokens);
02788                 return 1;
02789             }
02790 
02791             start = next;
02792             /*@switchbreak@*/ break;
02793 
02794         case '[':
02795 /*@-boundswrite@*/
02796             *dst++ = '\0';
02797             *start++ = '\0';
02798 /*@=boundswrite@*/
02799             token = format + numTokens++;
02800 
02801 /*@-boundswrite@*/
02802             if (parseFormat(hsa, start,
02803                             &token->u.array.format,
02804                             &token->u.array.numTokens,
02805                             &start, PARSER_IN_ARRAY))
02806             {
02807                 format = freeFormat(format, numTokens);
02808                 return 1;
02809             }
02810 /*@=boundswrite@*/
02811 
02812             if (!start) {
02813                 hsa->errmsg = _("] expected at end of array");
02814                 format = freeFormat(format, numTokens);
02815                 return 1;
02816             }
02817 
02818             dst = start;
02819 
02820             token->type = PTOK_ARRAY;
02821 
02822             /*@switchbreak@*/ break;
02823 
02824         case ']':
02825             if (state != PARSER_IN_ARRAY) {
02826                 hsa->errmsg = _("unexpected ]");
02827                 format = freeFormat(format, numTokens);
02828                 return 1;
02829             }
02830 /*@-boundswrite@*/
02831             *start++ = '\0';
02832 /*@=boundswrite@*/
02833             if (endPtr) *endPtr = start;
02834             done = 1;
02835             /*@switchbreak@*/ break;
02836 
02837         case '}':
02838             if (state != PARSER_IN_EXPR) {
02839                 hsa->errmsg = _("unexpected }");
02840                 format = freeFormat(format, numTokens);
02841                 return 1;
02842             }
02843 /*@-boundswrite@*/
02844             *start++ = '\0';
02845 /*@=boundswrite@*/
02846             if (endPtr) *endPtr = start;
02847             done = 1;
02848             /*@switchbreak@*/ break;
02849 
02850         default:
02851             if (token == NULL || token->type != PTOK_STRING) {
02852                 token = format + numTokens++;
02853                 token->type = PTOK_STRING;
02854                 /*@-temptrans -assignexpose@*/
02855                 dst = token->u.string.string = start;
02856                 /*@=temptrans =assignexpose@*/
02857             }
02858 
02859 /*@-boundswrite@*/
02860             if (*start == '\\') {
02861                 start++;
02862                 *dst++ = escapedChar(*start++);
02863             } else {
02864                 *dst++ = *start++;
02865             }
02866 /*@=boundswrite@*/
02867             /*@switchbreak@*/ break;
02868         }
02869         if (done)
02870             break;
02871     }
02872     /*@=infloops@*/
02873 
02874 /*@-boundswrite@*/
02875     if (dst != NULL)
02876         *dst = '\0';
02877 /*@=boundswrite@*/
02878 
02879     for (i = 0; i < numTokens; i++) {
02880         token = format + i;
02881         if (token->type == PTOK_STRING)
02882             token->u.string.len = strlen(token->u.string.string);
02883     }
02884 
02885     *numTokensPtr = numTokens;
02886     *formatPtr = format;
02887 
02888     return 0;
02889 }
02890 
02891 /*@-boundswrite@*/
02892 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
02893                 char * str, /*@out@*/ char ** endPtr)
02894 {
02895     char * chptr;
02896     char * end;
02897 
02898     hsa->errmsg = NULL;
02899     chptr = str;
02900     while (*chptr && *chptr != '?') chptr++;
02901 
02902     if (*chptr != '?') {
02903         hsa->errmsg = _("? expected in expression");
02904         return 1;
02905     }
02906 
02907     *chptr++ = '\0';;
02908 
02909     if (*chptr != '{') {
02910         hsa->errmsg = _("{ expected after ? in expression");
02911         return 1;
02912     }
02913 
02914     chptr++;
02915 
02916     if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
02917                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
02918         return 1;
02919 
02920     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
02921     if (!(end && *end)) {
02922         hsa->errmsg = _("} expected in expression");
02923         token->u.cond.ifFormat =
02924                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02925         return 1;
02926     }
02927 
02928     chptr = end;
02929     if (*chptr != ':' && *chptr != '|') {
02930         hsa->errmsg = _(": expected following ? subexpression");
02931         token->u.cond.ifFormat =
02932                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02933         return 1;
02934     }
02935 
02936     if (*chptr == '|') {
02937         if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
02938                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
02939         {
02940             token->u.cond.ifFormat =
02941                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02942             return 1;
02943         }
02944     } else {
02945         chptr++;
02946 
02947         if (*chptr != '{') {
02948             hsa->errmsg = _("{ expected after : in expression");
02949             token->u.cond.ifFormat =
02950                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02951             return 1;
02952         }
02953 
02954         chptr++;
02955 
02956         if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
02957                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
02958             return 1;
02959 
02960         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
02961         if (!(end && *end)) {
02962             hsa->errmsg = _("} expected in expression");
02963             token->u.cond.ifFormat =
02964                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02965             return 1;
02966         }
02967 
02968         chptr = end;
02969         if (*chptr != '|') {
02970             hsa->errmsg = _("| expected at end of expression");
02971             token->u.cond.ifFormat =
02972                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02973             token->u.cond.elseFormat =
02974                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02975             return 1;
02976         }
02977     }
02978         
02979     chptr++;
02980 
02981     *endPtr = chptr;
02982 
02983     token->type = PTOK_COND;
02984 
02985     (void) findTag(hsa, token, str);
02986 
02987     return 0;
02988 }
02989 /*@=boundswrite@*/
02990 
03001 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
03002                 /*@out@*/ hTYP_t typeptr,
03003                 /*@out@*/ hPTR_t * data,
03004                 /*@out@*/ hCNT_t countptr,
03005                 rpmec ec)
03006         /*@modifies *typeptr, *data, *countptr, ec @*/
03007         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
03008                 /\ maxSet(countptr) >= 0 @*/
03009 {
03010     if (!ec->avail) {
03011         if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
03012             return 1;
03013         ec->avail = 1;
03014     }
03015 
03016     if (typeptr) *typeptr = ec->type;
03017     if (data) *data = ec->data;
03018     if (countptr) *countptr = ec->count;
03019 
03020     return 0;
03021 }
03022 
03029 /*@observer@*/ /*@null@*/
03030 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
03031         /*@modifies hsa @*/
03032 {
03033     char * val = NULL;
03034     size_t need = 0;
03035     char * t, * te;
03036     char buf[20];
03037     int_32 count, type;
03038     hPTR_t data;
03039     unsigned int intVal;
03040     const char ** strarray;
03041     int datafree = 0;
03042     int countBuf;
03043 
03044     memset(buf, 0, sizeof(buf));
03045     if (tag->ext) {
03046 /*@-boundswrite -branchstate @*/
03047         if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
03048         {
03049             count = 1;
03050             type = RPM_STRING_TYPE;     
03051             data = "(none)";
03052         }
03053 /*@=boundswrite =branchstate @*/
03054     } else {
03055 /*@-boundswrite -branchstate @*/
03056         if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
03057             count = 1;
03058             type = RPM_STRING_TYPE;     
03059             data = "(none)";
03060         }
03061 /*@=boundswrite =branchstate @*/
03062 
03063         /* XXX this test is unnecessary, array sizes are checked */
03064         switch (type) {
03065         default:
03066             if (element >= count) {
03067                 /*@-modobserver -observertrans@*/
03068                 data = headerFreeData(data, type);
03069                 /*@=modobserver =observertrans@*/
03070 
03071                 hsa->errmsg = _("(index out of range)");
03072                 return NULL;
03073             }
03074             break;
03075         case RPM_BIN_TYPE:
03076         case RPM_STRING_TYPE:
03077             break;
03078         }
03079         datafree = 1;
03080     }
03081 
03082     if (tag->arrayCount) {
03083         /*@-branchstate -observertrans -modobserver@*/
03084         if (datafree)
03085             data = headerFreeData(data, type);
03086         /*@=branchstate =observertrans =modobserver@*/
03087 
03088         countBuf = count;
03089         data = &countBuf;
03090         count = 1;
03091         type = RPM_INT32_TYPE;
03092     }
03093 
03094 /*@-boundswrite@*/
03095     (void) stpcpy( stpcpy(buf, "%"), tag->format);
03096 /*@=boundswrite@*/
03097 
03098     /*@-branchstate@*/
03099     if (data)
03100     switch (type) {
03101     case RPM_STRING_ARRAY_TYPE:
03102         strarray = (const char **)data;
03103 
03104         if (tag->fmt)
03105             val = tag->fmt(RPM_STRING_TYPE, strarray[element], buf, tag->pad, element);
03106 
03107         if (val) {
03108             need = strlen(val);
03109         } else {
03110             need = strlen(strarray[element]) + tag->pad + 20;
03111             val = xmalloc(need+1);
03112             strcat(buf, "s");
03113             /*@-formatconst@*/
03114             sprintf(val, buf, strarray[element]);
03115             /*@=formatconst@*/
03116         }
03117 
03118         break;
03119 
03120     case RPM_STRING_TYPE:
03121         if (tag->fmt)
03122             val = tag->fmt(RPM_STRING_TYPE, data, buf, tag->pad,  0);
03123 
03124         if (val) {
03125             need = strlen(val);
03126         } else {
03127             need = strlen(data) + tag->pad + 20;
03128             val = xmalloc(need+1);
03129             strcat(buf, "s");
03130             /*@-formatconst@*/
03131             sprintf(val, buf, data);
03132             /*@=formatconst@*/
03133         }
03134         break;
03135 
03136     case RPM_CHAR_TYPE:
03137     case RPM_INT8_TYPE:
03138     case RPM_INT16_TYPE:
03139     case RPM_INT32_TYPE:
03140         switch (type) {
03141         case RPM_CHAR_TYPE:     
03142         case RPM_INT8_TYPE:
03143             intVal = *(((int_8 *) data) + element);
03144             /*@innerbreak@*/ break;
03145         case RPM_INT16_TYPE:
03146             intVal = *(((uint_16 *) data) + element);
03147             /*@innerbreak@*/ break;
03148         default:                /* keep -Wall quiet */
03149         case RPM_INT32_TYPE:
03150             intVal = *(((int_32 *) data) + element);
03151             /*@innerbreak@*/ break;
03152         }
03153 
03154         if (tag->fmt)
03155             val = tag->fmt(RPM_INT32_TYPE, &intVal, buf, tag->pad, element);
03156 
03157         if (val) {
03158             need = strlen(val);
03159         } else {
03160             need = 10 + tag->pad + 20;
03161             val = xmalloc(need+1);
03162             strcat(buf, "d");
03163             /*@-formatconst@*/
03164             sprintf(val, buf, intVal);
03165             /*@=formatconst@*/
03166         }
03167         break;
03168 
03169     case RPM_BIN_TYPE:
03170         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
03171         if (tag->fmt)
03172             val = tag->fmt(RPM_BIN_TYPE, data, buf, tag->pad, count);
03173 
03174         if (val) {
03175             need = strlen(val);
03176         } else {
03177             val = bin2hex(data, count);
03178             need = strlen(val) + tag->pad;
03179         }
03180         break;
03181 
03182     default:
03183         need = sizeof("(unknown type)") - 1;
03184         val = xstrdup("(unknown type)");
03185         break;
03186     }
03187     /*@=branchstate@*/
03188 
03189     /*@-branchstate -observertrans -modobserver@*/
03190     if (datafree)
03191         data = headerFreeData(data, type);
03192     /*@=branchstate =observertrans =modobserver@*/
03193 
03194     /*@-branchstate@*/
03195     if (val && need > 0) {
03196         t = hsaReserve(hsa, need);
03197 /*@-boundswrite@*/
03198         te = stpcpy(t, val);
03199 /*@=boundswrite@*/
03200         hsa->vallen += (te - t);
03201         val = _free(val);
03202     }
03203     /*@=branchstate@*/
03204 
03205     return (hsa->val + hsa->vallen);
03206 }
03207 
03214 /*@observer@*/
03215 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
03216                 int element)
03217         /*@modifies hsa @*/
03218 {
03219     char * t, * te;
03220     int i, j;
03221     int numElements;
03222     int_32 type;
03223     int_32 count;
03224     sprintfToken spft;
03225     int condNumFormats;
03226     size_t need;
03227 
03228     /* we assume the token and header have been validated already! */
03229 
03230     switch (token->type) {
03231     case PTOK_NONE:
03232         break;
03233 
03234     case PTOK_STRING:
03235         need = token->u.string.len;
03236         if (need == 0) break;
03237         t = hsaReserve(hsa, need);
03238 /*@-boundswrite@*/
03239         te = stpcpy(t, token->u.string.string);
03240 /*@=boundswrite@*/
03241         hsa->vallen += (te - t);
03242         break;
03243 
03244     case PTOK_TAG:
03245         t = hsa->val + hsa->vallen;
03246         te = formatValue(hsa, &token->u.tag,
03247                         (token->u.tag.justOne ? 0 : element));
03248         if (te == NULL)
03249             return NULL;
03250         break;
03251 
03252     case PTOK_COND:
03253         if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
03254             spft = token->u.cond.ifFormat;
03255             condNumFormats = token->u.cond.numIfTokens;
03256         } else {
03257             spft = token->u.cond.elseFormat;
03258             condNumFormats = token->u.cond.numElseTokens;
03259         }
03260 
03261         need = condNumFormats * 20;
03262         if (spft == NULL || need == 0) break;
03263 
03264         t = hsaReserve(hsa, need);
03265         for (i = 0; i < condNumFormats; i++, spft++) {
03266             te = singleSprintf(hsa, spft, element);
03267             if (te == NULL)
03268                 return NULL;
03269         }
03270         break;
03271 
03272     case PTOK_ARRAY:
03273         numElements = -1;
03274         spft = token->u.array.format;
03275         for (i = 0; i < token->u.array.numTokens; i++, spft++)
03276         {
03277             if (spft->type != PTOK_TAG ||
03278                 spft->u.tag.arrayCount ||
03279                 spft->u.tag.justOne) continue;
03280 
03281             if (spft->u.tag.ext) {
03282 /*@-boundswrite@*/
03283                 if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count, 
03284                                  hsa->ec + spft->u.tag.extNum))
03285                      continue;
03286 /*@=boundswrite@*/
03287             } else {
03288 /*@-boundswrite@*/
03289                 if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
03290                     continue;
03291 /*@=boundswrite@*/
03292             } 
03293 
03294             if (type == RPM_BIN_TYPE)
03295                 count = 1;      /* XXX count abused as no. of bytes. */
03296 
03297             if (numElements > 1 && count != numElements)
03298             switch (type) {
03299             default:
03300                 hsa->errmsg =
03301                         _("array iterator used with different sized arrays");
03302                 return NULL;
03303                 /*@notreached@*/ /*@switchbreak@*/ break;
03304             case RPM_BIN_TYPE:
03305             case RPM_STRING_TYPE:
03306                 /*@switchbreak@*/ break;
03307             }
03308             if (count > numElements)
03309                 numElements = count;
03310         }
03311 
03312         if (numElements == -1) {
03313             need = sizeof("(none)") - 1;
03314             t = hsaReserve(hsa, need);
03315 /*@-boundswrite@*/
03316             te = stpcpy(t, "(none)");
03317 /*@=boundswrite@*/
03318             hsa->vallen += (te - t);
03319         } else {
03320             int isxml;
03321 
03322             need = numElements * token->u.array.numTokens * 10;
03323             if (need == 0) break;
03324 
03325             spft = token->u.array.format;
03326             isxml = (spft->type == PTOK_TAG && spft->u.tag.type != NULL &&
03327                 !strcmp(spft->u.tag.type, "xml"));
03328 
03329             if (isxml) {
03330                 const char * tagN = myTagName(hsa->tags, spft->u.tag.tag);
03331 
03332                 need = sizeof("  <rpmTag name=\"\">\n") - 1;
03333                 if (tagN != NULL)
03334                     need += strlen(tagN);
03335                 t = hsaReserve(hsa, need);
03336 /*@-boundswrite@*/
03337                 te = stpcpy(t, "  <rpmTag name=\"");
03338                 if (tagN != NULL)
03339                     te = stpcpy(te, tagN);
03340                 te = stpcpy(te, "\">\n");
03341 /*@=boundswrite@*/
03342                 hsa->vallen += (te - t);
03343             }
03344 
03345             t = hsaReserve(hsa, need);
03346             for (j = 0; j < numElements; j++) {
03347                 spft = token->u.array.format;
03348                 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
03349                     te = singleSprintf(hsa, spft, j);
03350                     if (te == NULL)
03351                         return NULL;
03352                 }
03353             }
03354 
03355             if (isxml) {
03356                 need = sizeof("  </rpmTag>\n") - 1;
03357                 t = hsaReserve(hsa, need);
03358 /*@-boundswrite@*/
03359                 te = stpcpy(t, "  </rpmTag>\n");
03360 /*@=boundswrite@*/
03361                 hsa->vallen += (te - t);
03362             }
03363 
03364         }
03365         break;
03366     }
03367 
03368     return (hsa->val + hsa->vallen);
03369 }
03370 
03376 static /*@only@*/ rpmec
03377 rpmecNew(const headerSprintfExtension exts)
03378         /*@*/
03379 {
03380     headerSprintfExtension ext;
03381     rpmec ec;
03382     int i = 0;
03383 
03384     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03385         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03386     {
03387         i++;
03388     }
03389 
03390     ec = xcalloc(i, sizeof(*ec));
03391     return ec;
03392 }
03393 
03400 static /*@null@*/ rpmec
03401 rpmecFree(const headerSprintfExtension exts, /*@only@*/ rpmec ec)
03402         /*@modifies ec @*/
03403 {
03404     headerSprintfExtension ext;
03405     int i = 0;
03406 
03407     for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
03408         ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
03409     {
03410 /*@-boundswrite@*/
03411         if (ec[i].freeit) ec[i].data = _free(ec[i].data);
03412 /*@=boundswrite@*/
03413         i++;
03414     }
03415 
03416     ec = _free(ec);
03417     return NULL;
03418 }
03419 
03431 static /*@only@*/ /*@null@*/
03432 char * headerSprintf(Header h, const char * fmt,
03433                      const struct headerTagTableEntry_s * tbltags,
03434                      const struct headerSprintfExtension_s * extensions,
03435                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03436         /*@modifies h, *errmsg @*/
03437         /*@requires maxSet(errmsg) >= 0 @*/
03438 {
03439     headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
03440     sprintfToken nextfmt;
03441     sprintfTag tag;
03442     char * t, * te;
03443     int isxml;
03444     int need;
03445  
03446     hsa->h = headerLink(h);
03447     hsa->fmt = xstrdup(fmt);
03448 /*@-castexpose@*/       /* FIX: legacy API shouldn't change. */
03449     hsa->exts = (headerSprintfExtension) extensions;
03450     hsa->tags = (headerTagTableEntry) tbltags;
03451 /*@=castexpose@*/
03452     hsa->errmsg = NULL;
03453 
03454 /*@-boundswrite@*/
03455     if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
03456         goto exit;
03457 /*@=boundswrite@*/
03458 
03459     hsa->ec = rpmecNew(hsa->exts);
03460     hsa->val = xstrdup("");
03461 
03462     tag =
03463         (hsa->format->type == PTOK_TAG
03464             ? &hsa->format->u.tag :
03465         (hsa->format->type == PTOK_ARRAY
03466             ? &hsa->format->u.array.format->u.tag :
03467         NULL));
03468     isxml = (tag != NULL && tag->tag == -2 && tag->type != NULL && !strcmp(tag->type, "xml"));
03469 
03470     if (isxml) {
03471         need = sizeof("<rpmHeader>\n") - 1;
03472         t = hsaReserve(hsa, need);
03473 /*@-boundswrite@*/
03474         te = stpcpy(t, "<rpmHeader>\n");
03475 /*@=boundswrite@*/
03476         hsa->vallen += (te - t);
03477     }
03478 
03479     hsa = hsaInit(hsa);
03480     while ((nextfmt = hsaNext(hsa)) != NULL) {
03481         te = singleSprintf(hsa, nextfmt, 0);
03482         if (te == NULL) {
03483             hsa->val = _free(hsa->val);
03484             break;
03485         }
03486     }
03487     hsa = hsaFini(hsa);
03488 
03489     if (isxml) {
03490         need = sizeof("</rpmHeader>\n") - 1;
03491         t = hsaReserve(hsa, need);
03492 /*@-boundswrite@*/
03493         te = stpcpy(t, "</rpmHeader>\n");
03494 /*@=boundswrite@*/
03495         hsa->vallen += (te - t);
03496     }
03497 
03498     if (hsa->val != NULL && hsa->vallen < hsa->alloced)
03499         hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
03500 
03501     hsa->ec = rpmecFree(hsa->exts, hsa->ec);
03502     hsa->format = freeFormat(hsa->format, hsa->numTokens);
03503 
03504 exit:
03505 /*@-dependenttrans -observertrans @*/
03506     if (errmsg)
03507         *errmsg = hsa->errmsg;
03508 /*@=dependenttrans =observertrans @*/
03509     hsa->h = headerFree(hsa->h);
03510     hsa->fmt = _free(hsa->fmt);
03511     return hsa->val;
03512 }
03513 
03522 static char * octalFormat(int_32 type, hPTR_t data, 
03523                 char * formatPrefix, int padding, /*@unused@*/int element)
03524         /*@modifies formatPrefix @*/
03525 {
03526     char * val;
03527 
03528     if (type != RPM_INT32_TYPE) {
03529         val = xstrdup(_("(not a number)"));
03530     } else {
03531         val = xmalloc(20 + padding);
03532 /*@-boundswrite@*/
03533         strcat(formatPrefix, "o");
03534 /*@=boundswrite@*/
03535         /*@-formatconst@*/
03536         sprintf(val, formatPrefix, *((int_32 *) data));
03537         /*@=formatconst@*/
03538     }
03539 
03540     return val;
03541 }
03542 
03551 static char * hexFormat(int_32 type, hPTR_t data, 
03552                 char * formatPrefix, int padding, /*@unused@*/int element)
03553         /*@modifies formatPrefix @*/
03554 {
03555     char * val;
03556 
03557     if (type != RPM_INT32_TYPE) {
03558         val = xstrdup(_("(not a number)"));
03559     } else {
03560         val = xmalloc(20 + padding);
03561 /*@-boundswrite@*/
03562         strcat(formatPrefix, "x");
03563 /*@=boundswrite@*/
03564         /*@-formatconst@*/
03565         sprintf(val, formatPrefix, *((int_32 *) data));
03566         /*@=formatconst@*/
03567     }
03568 
03569     return val;
03570 }
03571 
03574 static char * realDateFormat(int_32 type, hPTR_t data, 
03575                 char * formatPrefix, int padding, /*@unused@*/int element,
03576                 const char * strftimeFormat)
03577         /*@modifies formatPrefix @*/
03578 {
03579     char * val;
03580 
03581     if (type != RPM_INT32_TYPE) {
03582         val = xstrdup(_("(not a number)"));
03583     } else {
03584         struct tm * tstruct;
03585         char buf[50];
03586 
03587         val = xmalloc(50 + padding);
03588 /*@-boundswrite@*/
03589         strcat(formatPrefix, "s");
03590 /*@=boundswrite@*/
03591 
03592         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03593         {   time_t dateint = *((int_32 *) data);
03594             tstruct = localtime(&dateint);
03595         }
03596         buf[0] = '\0';
03597         if (tstruct)
03598             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03599         /*@-formatconst@*/
03600         sprintf(val, formatPrefix, buf);
03601         /*@=formatconst@*/
03602     }
03603 
03604     return val;
03605 }
03606 
03615 static char * dateFormat(int_32 type, hPTR_t data, 
03616                          char * formatPrefix, int padding, int element)
03617         /*@modifies formatPrefix @*/
03618 {
03619     return realDateFormat(type, data, formatPrefix, padding, element,
03620                         _("%c"));
03621 }
03622 
03631 static char * dayFormat(int_32 type, hPTR_t data, 
03632                          char * formatPrefix, int padding, int element)
03633         /*@modifies formatPrefix @*/
03634 {
03635     return realDateFormat(type, data, formatPrefix, padding, element, 
03636                           _("%a %b %d %Y"));
03637 }
03638 
03647 static char * shescapeFormat(int_32 type, hPTR_t data, 
03648                 char * formatPrefix, int padding, /*@unused@*/int element)
03649         /*@modifies formatPrefix @*/
03650 {
03651     char * result, * dst, * src, * buf;
03652 
03653     if (type == RPM_INT32_TYPE) {
03654         result = xmalloc(padding + 20);
03655 /*@-boundswrite@*/
03656         strcat(formatPrefix, "d");
03657 /*@=boundswrite@*/
03658         /*@-formatconst@*/
03659         sprintf(result, formatPrefix, *((int_32 *) data));
03660         /*@=formatconst@*/
03661     } else {
03662         buf = alloca(strlen(data) + padding + 2);
03663 /*@-boundswrite@*/
03664         strcat(formatPrefix, "s");
03665 /*@=boundswrite@*/
03666         /*@-formatconst@*/
03667         sprintf(buf, formatPrefix, data);
03668         /*@=formatconst@*/
03669 
03670 /*@-boundswrite@*/
03671         result = dst = xmalloc(strlen(buf) * 4 + 3);
03672         *dst++ = '\'';
03673         for (src = buf; *src != '\0'; src++) {
03674             if (*src == '\'') {
03675                 *dst++ = '\'';
03676                 *dst++ = '\\';
03677                 *dst++ = '\'';
03678                 *dst++ = '\'';
03679             } else {
03680                 *dst++ = *src;
03681             }
03682         }
03683         *dst++ = '\'';
03684         *dst = '\0';
03685 /*@=boundswrite@*/
03686 
03687     }
03688 
03689     return result;
03690 }
03691 
03692 /*@-type@*/ /* FIX: cast? */
03693 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03694     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03695     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03696     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03697     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03698     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03699     { HEADER_EXT_LAST, NULL, { NULL } }
03700 };
03701 /*@=type@*/
03702 
03709 static
03710 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03711         /*@modifies headerTo @*/
03712 {
03713     int * p;
03714 
03715     if (headerFrom == headerTo)
03716         return;
03717 
03718     for (p = tagstocopy; *p != 0; p++) {
03719         char *s;
03720         int_32 type;
03721         int_32 count;
03722         if (headerIsEntry(headerTo, *p))
03723             continue;
03724 /*@-boundswrite@*/
03725         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03726                                 (hPTR_t *) &s, &count))
03727             continue;
03728 /*@=boundswrite@*/
03729         (void) headerAddEntry(headerTo, *p, type, s, count);
03730         s = headerFreeData(s, type);
03731     }
03732 }
03733 
03734 /*@observer@*/ /*@unchecked@*/
03735 static struct HV_s hdrVec1 = {
03736     headerLink,
03737     headerUnlink,
03738     headerFree,
03739     headerNew,
03740     headerSort,
03741     headerUnsort,
03742     headerSizeof,
03743     headerUnload,
03744     headerReload,
03745     headerCopy,
03746     headerLoad,
03747     headerCopyLoad,
03748     headerRead,
03749     headerWrite,
03750     headerIsEntry,
03751     headerFreeTag,
03752     headerGetEntry,
03753     headerGetEntryMinMemory,
03754     headerAddEntry,
03755     headerAppendEntry,
03756     headerAddOrAppendEntry,
03757     headerAddI18NString,
03758     headerModifyEntry,
03759     headerRemoveEntry,
03760     headerSprintf,
03761     headerCopyTags,
03762     headerFreeIterator,
03763     headerInitIterator,
03764     headerNextIterator,
03765     NULL, NULL,
03766     1
03767 };
03768 
03769 /*@-compmempass -redef@*/
03770 /*@observer@*/ /*@unchecked@*/
03771 HV_t hdrVec = &hdrVec1;
03772 /*@=compmempass =redef@*/

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2