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

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 /*@-redecl@*/   /* FIX: avoid rpmlib.h, need for debugging. */
00023 /*@observer@*/ const char *const tagName(int tag)       /*@*/;
00024 /*@=redecl@*/
00025 
00026 /*@access entryInfo @*/
00027 /*@access indexEntry @*/
00028 
00029 /*@access extensionCache @*/
00030 /*@access sprintfTag @*/
00031 /*@access sprintfToken @*/
00032 /*@access HV_t @*/
00033 
00034 #define PARSER_BEGIN    0
00035 #define PARSER_IN_ARRAY 1
00036 #define PARSER_IN_EXPR  2
00037 
00040 /*@observer@*/ /*@unchecked@*/
00041 static unsigned char header_magic[8] = {
00042         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00043 };
00044 
00048 /*@observer@*/ /*@unchecked@*/
00049 static int typeAlign[16] =  {
00050     1,  
00051     1,  
00052     1,  
00053     2,  
00054     4,  
00055     8,  
00056     1,  
00057     1,  
00058     1,  
00059     1,  
00060     0,
00061     0,
00062     0,
00063     0,
00064     0,
00065     0
00066 };
00067 
00071 /*@observer@*/ /*@unchecked@*/
00072 static int typeSizes[16] =  { 
00073     0,  
00074     1,  
00075     1,  
00076     2,  
00077     4,  
00078     -1, 
00079     -1, 
00080     1,  
00081     -1, 
00082     -1, 
00083     0,
00084     0,
00085     0,
00086     0,
00087     0,
00088     0
00089 };
00090 
00094 /*@unchecked@*/
00095 static size_t headerMaxbytes = (32*1024*1024);
00096 
00101 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00102 
00106 #define hdrchkType(_type) ((_type) < RPM_MIN_TYPE || (_type) > RPM_MAX_TYPE)
00107 
00112 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00113 
00117 #define hdrchkAlign(_type, _off)        ((_off) & (typeAlign[_type]-1))
00118 
00122 #define hdrchkRange(_dl, _off)          ((_off) < 0 || (_off) > (_dl))
00123 
00124 /*@observer@*/ /*@unchecked@*/
00125 HV_t hdrVec;    /* forward reference */
00126 
00132 /*@unused@*/ static inline /*@null@*/ void *
00133 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
00134 {
00135     if (p != NULL)      free((void *)p);
00136     return NULL;
00137 }
00138 
00144 static
00145 Header headerLink(Header h)
00146         /*@modifies h @*/
00147 {
00148 /*@-nullret@*/
00149     if (h == NULL) return NULL;
00150 /*@=nullret@*/
00151 
00152     h->nrefs++;
00153 /*@-modfilesys@*/
00154 if (_hdr_debug)
00155 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00156 /*@=modfilesys@*/
00157 
00158     /*@-refcounttrans @*/
00159     return h;
00160     /*@=refcounttrans @*/
00161 }
00162 
00168 static /*@null@*/
00169 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00170         /*@modifies h @*/
00171 {
00172     if (h == NULL) return NULL;
00173 /*@-modfilesys@*/
00174 if (_hdr_debug)
00175 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00176 /*@=modfilesys@*/
00177     h->nrefs--;
00178     return NULL;
00179 }
00180 
00186 static /*@null@*/
00187 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00188         /*@modifies h @*/
00189 {
00190     (void) headerUnlink(h);
00191 
00192     /*@-usereleased@*/
00193     if (h == NULL || h->nrefs > 0)
00194         return NULL;    /* XXX return previous header? */
00195 
00196     if (h->index) {
00197         indexEntry entry = h->index;
00198         int i;
00199         for (i = 0; i < h->indexUsed; i++, entry++) {
00200             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00201                 if (entry->length > 0) {
00202                     int_32 * ei = entry->data;
00203                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00204                     entry->data = NULL;
00205                 }
00206             } else if (!ENTRY_IN_REGION(entry)) {
00207                 entry->data = _free(entry->data);
00208             }
00209             entry->data = NULL;
00210         }
00211         h->index = _free(h->index);
00212     }
00213 
00214     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00215     return h;
00216     /*@=usereleased@*/
00217 }
00218 
00223 static
00224 Header headerNew(void)
00225         /*@*/
00226 {
00227     Header h = xcalloc(1, sizeof(*h));
00228 
00229 /*@-boundsread@*/
00230     /*@-assignexpose@*/
00231     h->hv = *hdrVec;            /* structure assignment */
00232     /*@=assignexpose@*/
00233 /*@=boundsread@*/
00234     h->blob = NULL;
00235     h->indexAlloced = INDEX_MALLOC_SIZE;
00236     h->indexUsed = 0;
00237     h->flags |= HEADERFLAG_SORTED;
00238 
00239     h->index = (h->indexAlloced
00240         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00241         : NULL);
00242 
00243     h->nrefs = 0;
00244     /*@-globstate -observertrans @*/
00245     return headerLink(h);
00246     /*@=globstate =observertrans @*/
00247 }
00248 
00251 static int indexCmp(const void * avp, const void * bvp)
00252         /*@*/
00253 {
00254     /*@-castexpose@*/
00255     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00256     /*@=castexpose@*/
00257     return (ap->info.tag - bp->info.tag);
00258 }
00259 
00264 static
00265 void headerSort(Header h)
00266         /*@modifies h @*/
00267 {
00268     if (!(h->flags & HEADERFLAG_SORTED)) {
00269 /*@-boundsread@*/
00270         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00271 /*@=boundsread@*/
00272         h->flags |= HEADERFLAG_SORTED;
00273     }
00274 }
00275 
00278 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00279 {
00280     /*@-castexpose@*/
00281     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00282     /*@=castexpose@*/
00283     int rc = (ap->info.offset - bp->info.offset);
00284 
00285     if (rc == 0) {
00286         /* Within a region, entries sort by address. Added drips sort by tag. */
00287         if (ap->info.offset < 0)
00288             rc = (((char *)ap->data) - ((char *)bp->data));
00289         else
00290             rc = (ap->info.tag - bp->info.tag);
00291     }
00292     return rc;
00293 }
00294 
00299 static
00300 void headerUnsort(Header h)
00301         /*@modifies h @*/
00302 {
00303 /*@-boundsread@*/
00304     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00305 /*@=boundsread@*/
00306 }
00307 
00314 static
00315 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00316         /*@modifies h @*/
00317 {
00318     indexEntry entry;
00319     unsigned int size = 0;
00320     unsigned int pad = 0;
00321     int i;
00322 
00323     if (h == NULL)
00324         return size;
00325 
00326     headerSort(h);
00327 
00328     switch (magicp) {
00329     case HEADER_MAGIC_YES:
00330         size += sizeof(header_magic);
00331         break;
00332     case HEADER_MAGIC_NO:
00333         break;
00334     }
00335 
00336     /*@-sizeoftype@*/
00337     size += 2 * sizeof(int_32); /* count of index entries */
00338     /*@=sizeoftype@*/
00339 
00340     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00341         unsigned diff;
00342         int_32 type;
00343 
00344         /* Regions go in as is ... */
00345         if (ENTRY_IS_REGION(entry)) {
00346             size += entry->length;
00347             /* XXX Legacy regions do not include the region tag and data. */
00348             /*@-sizeoftype@*/
00349             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00350                 size += sizeof(struct entryInfo_s) + entry->info.count;
00351             /*@=sizeoftype@*/
00352             continue;
00353         }
00354 
00355         /* ... and region elements are skipped. */
00356         if (entry->info.offset < 0)
00357             continue;
00358 
00359         /* Alignment */
00360         type = entry->info.type;
00361 /*@-boundsread@*/
00362         if (typeSizes[type] > 1) {
00363             diff = typeSizes[type] - (size % typeSizes[type]);
00364             if (diff != typeSizes[type]) {
00365                 size += diff;
00366                 pad += diff;
00367             }
00368         }
00369 /*@=boundsread@*/
00370 
00371         /*@-sizeoftype@*/
00372         size += sizeof(struct entryInfo_s) + entry->length;
00373         /*@=sizeoftype@*/
00374     }
00375 
00376     return size;
00377 }
00378 
00388 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00389                 /*@null@*/ hPTR_t pend)
00390         /*@*/
00391 {
00392     const unsigned char * s = p;
00393     const unsigned char * se = pend;
00394     int length = 0;
00395 
00396     switch (type) {
00397     case RPM_STRING_TYPE:
00398         if (count != 1)
00399             return -1;
00400 /*@-boundsread@*/
00401         while (*s++) {
00402             if (se && s > se)
00403                 return -1;
00404             length++;
00405         }
00406 /*@=boundsread@*/
00407         length++;       /* count nul terminator too. */
00408         break;
00409 
00410     case RPM_STRING_ARRAY_TYPE:
00411     case RPM_I18NSTRING_TYPE:
00412         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00413         /* Compute sum of length of all strings, including nul terminators */
00414 
00415         if (onDisk) {
00416             while (count--) {
00417                 length++;       /* count nul terminator too */
00418 /*@-boundsread@*/
00419                while (*s++) {
00420                     if (se && s > se)
00421                         return -1;
00422                     length++;
00423                 }
00424 /*@=boundsread@*/
00425             }
00426         } else {
00427             const char ** av = (const char **)p;
00428 /*@-boundsread@*/
00429             while (count--) {
00430                 /* add one for null termination */
00431                 length += strlen(*av++) + 1;
00432             }
00433 /*@=boundsread@*/
00434         }
00435         break;
00436 
00437     default:
00438 /*@-boundsread@*/
00439         if (typeSizes[type] == -1)
00440             return -1;
00441         length = typeSizes[(type & 0xf)] * count;
00442 /*@=boundsread@*/
00443         if (length < 0 || (se && (s + length) > se))
00444             return -1;
00445         break;
00446     }
00447 
00448     return length;
00449 }
00450 
00477 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00478                 entryInfo pe,
00479                 unsigned char * dataStart,
00480                 /*@null@*/ const unsigned char * dataEnd,
00481                 int regionid)
00482         /*@modifies *entry, *dataStart @*/
00483 {
00484     unsigned char * tprev = NULL;
00485     unsigned char * t = NULL;
00486     int tdel, tl = dl;
00487     struct indexEntry_s ieprev;
00488 
00489 /*@-boundswrite@*/
00490     memset(&ieprev, 0, sizeof(ieprev));
00491 /*@=boundswrite@*/
00492     for (; il > 0; il--, pe++) {
00493         struct indexEntry_s ie;
00494         int_32 type;
00495 
00496         ie.info.tag = ntohl(pe->tag);
00497         ie.info.type = ntohl(pe->type);
00498         ie.info.count = ntohl(pe->count);
00499         ie.info.offset = ntohl(pe->offset);
00500 
00501         if (hdrchkType(ie.info.type))
00502             return -1;
00503         if (hdrchkData(ie.info.count))
00504             return -1;
00505         if (hdrchkData(ie.info.offset))
00506             return -1;
00507 /*@-boundsread@*/
00508         if (hdrchkAlign(ie.info.type, ie.info.offset))
00509             return -1;
00510 /*@=boundsread@*/
00511 
00512         ie.data = t = dataStart + ie.info.offset;
00513         if (dataEnd && t >= dataEnd)
00514             return -1;
00515 
00516         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00517         if (ie.length < 0 || hdrchkData(ie.length))
00518             return -1;
00519 
00520         ie.rdlen = 0;
00521 
00522         if (entry) {
00523             ie.info.offset = regionid;
00524 /*@-boundswrite@*/
00525             *entry = ie;        /* structure assignment */
00526 /*@=boundswrite@*/
00527             entry++;
00528         }
00529 
00530         /* Alignment */
00531         type = ie.info.type;
00532 /*@-boundsread@*/
00533         if (typeSizes[type] > 1) {
00534             unsigned diff;
00535             diff = typeSizes[type] - (dl % typeSizes[type]);
00536             if (diff != typeSizes[type]) {
00537                 dl += diff;
00538                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00539                     ieprev.length += diff;
00540             }
00541         }
00542 /*@=boundsread@*/
00543         tdel = (tprev ? (t - tprev) : 0);
00544         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00545             tdel = ieprev.length;
00546 
00547         if (ie.info.tag >= HEADER_I18NTABLE) {
00548             tprev = t;
00549         } else {
00550             tprev = dataStart;
00551             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00552             /*@-sizeoftype@*/
00553             if (ie.info.tag == HEADER_IMAGE)
00554                 tprev -= REGION_TAG_COUNT;
00555             /*@=sizeoftype@*/
00556         }
00557 
00558         /* Perform endian conversions */
00559         switch (ntohl(pe->type)) {
00560 /*@-bounds@*/
00561         case RPM_INT32_TYPE:
00562         {   int_32 * it = (int_32 *)t;
00563             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00564                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00565                     return -1;
00566                 *it = htonl(*it);
00567             }
00568             t = (char *) it;
00569         }   /*@switchbreak@*/ break;
00570         case RPM_INT16_TYPE:
00571         {   int_16 * it = (int_16 *) t;
00572             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00573                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00574                     return -1;
00575                 *it = htons(*it);
00576             }
00577             t = (char *) it;
00578         }   /*@switchbreak@*/ break;
00579 /*@=bounds@*/
00580         default:
00581             t += ie.length;
00582             /*@switchbreak@*/ break;
00583         }
00584 
00585         dl += ie.length;
00586         tl += tdel;
00587         ieprev = ie;    /* structure assignment */
00588 
00589     }
00590     tdel = (tprev ? (t - tprev) : 0);
00591     tl += tdel;
00592 
00593     /* XXX
00594      * There are two hacks here:
00595      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00596      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00597      */
00598     /*@-sizeoftype@*/
00599     if (tl+REGION_TAG_COUNT == dl)
00600         tl += REGION_TAG_COUNT;
00601     /*@=sizeoftype@*/
00602 
00603     return dl;
00604 }
00605 
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     for (i = 0; i < num; i++) {
02232         switch (format[i].type) {
02233         case PTOK_ARRAY:
02234 /*@-boundswrite@*/
02235             format[i].u.array.format =
02236                 freeFormat(format[i].u.array.format,
02237                         format[i].u.array.numTokens);
02238 /*@=boundswrite@*/
02239             /*@switchbreak@*/ break;
02240         case PTOK_COND:
02241 /*@-boundswrite@*/
02242             format[i].u.cond.ifFormat =
02243                 freeFormat(format[i].u.cond.ifFormat, 
02244                         format[i].u.cond.numIfTokens);
02245             format[i].u.cond.elseFormat =
02246                 freeFormat(format[i].u.cond.elseFormat, 
02247                         format[i].u.cond.numElseTokens);
02248 /*@=boundswrite@*/
02249             /*@switchbreak@*/ break;
02250         case PTOK_NONE:
02251         case PTOK_TAG:
02252         case PTOK_STRING:
02253         default:
02254             /*@switchbreak@*/ break;
02255         }
02256     }
02257     format = _free(format);
02258     return NULL;
02259 }
02260 
02263 static void findTag(char * name, const headerTagTableEntry tags, 
02264                     const headerSprintfExtension extensions,
02265                     /*@out@*/ headerTagTableEntry * tagMatch,
02266                     /*@out@*/ headerSprintfExtension * extMatch)
02267         /*@modifies *tagMatch, *extMatch @*/
02268         /*@requires maxSet(tagMatch) >= 0 /\ maxSet(extMatch) >= 0 @*/
02269 {
02270     headerTagTableEntry entry;
02271     headerSprintfExtension ext;
02272     const char * tagname;
02273 
02274     *tagMatch = NULL;
02275     *extMatch = NULL;
02276 
02277     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02278 /*@-boundswrite@*/
02279         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02280         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02281         tagname = t;
02282 /*@=boundswrite@*/
02283     } else {
02284         tagname = name;
02285     }
02286 
02287     /* Search extensions first to permit overriding header tags. */
02288     ext = extensions;
02289     while (ext->type != HEADER_EXT_LAST) {
02290         if (ext->name != NULL && ext->type == HEADER_EXT_TAG
02291         && !xstrcasecmp(ext->name, tagname))
02292             break;
02293 
02294         if (ext->type == HEADER_EXT_MORE)
02295             ext = ext->u.more;
02296         else
02297             ext++;
02298     }
02299 
02300     if (ext->type == HEADER_EXT_TAG) {
02301         *extMatch = ext;
02302         return;
02303     }
02304 
02305     /* Search header tags. */
02306     for (entry = tags; entry->name; entry++)
02307         if (entry->name && !xstrcasecmp(entry->name, tagname))
02308             break;
02309 
02310     if (entry->name) {
02311         *tagMatch = entry;
02312         return;
02313     }
02314 }
02315 
02316 /* forward ref */
02317 static int parseExpression(sprintfToken token, char * str, 
02318                 const headerTagTableEntry tags, 
02319                 const headerSprintfExtension extensions,
02320                 /*@out@*/char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
02321         /*@modifies str, *str, *token, *endPtr, *errmsg @*/
02322         /*@requires maxSet(endPtr) >= 0 /\ maxSet(errmsg) >= 0 @*/;
02323 
02326 /*@-boundswrite@*/
02327 static int parseFormat(/*@null@*/ char * str, const headerTagTableEntry tags,
02328                 const headerSprintfExtension extensions,
02329                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02330                 /*@null@*/ /*@out@*/ char ** endPtr, int state,
02331                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
02332         /*@modifies str, *str, *formatPtr, *numTokensPtr, *endPtr, *errmsg @*/
02333         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02334                 /\ maxSet(endPtr) >= 0 /\ maxSet(errmsg) >= 0 @*/
02335 {
02336     char * chptr, * start, * next, * dst;
02337     sprintfToken format;
02338     int numTokens;
02339     int currToken;
02340     headerTagTableEntry tag;
02341     headerSprintfExtension ext;
02342     int i;
02343     int done = 0;
02344 
02345     /* upper limit on number of individual formats */
02346     numTokens = 0;
02347     if (str != NULL)
02348     for (chptr = str; *chptr != '\0'; chptr++)
02349         if (*chptr == '%') numTokens++;
02350     numTokens = numTokens * 2 + 1;
02351 
02352     format = xcalloc(numTokens, sizeof(*format));
02353     if (endPtr) *endPtr = NULL;
02354 
02355     /*@-infloops@*/ /* LCL: can't detect done termination */
02356     dst = start = str;
02357     currToken = -1;
02358     if (start != NULL)
02359     while (*start != '\0') {
02360         switch (*start) {
02361         case '%':
02362             /* handle %% */
02363             if (*(start + 1) == '%') {
02364                 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02365                     currToken++;
02366                     format[currToken].type = PTOK_STRING;
02367                     /*@-temptrans -assignexpose@*/
02368                     dst = format[currToken].u.string.string = start;
02369                     /*@=temptrans =assignexpose@*/
02370                 }
02371 
02372                 start++;
02373 
02374                 *dst++ = *start++;
02375 
02376                 /*@switchbreak@*/ break;
02377             } 
02378 
02379             currToken++;
02380             *dst++ = '\0';
02381             start++;
02382 
02383             if (*start == '|') {
02384                 char * newEnd;
02385 
02386                 start++;
02387                 if (parseExpression(format + currToken, start, tags, 
02388                                     extensions, &newEnd, errmsg))
02389                 {
02390                     format = freeFormat(format, numTokens);
02391                     return 1;
02392                 }
02393                 start = newEnd;
02394                 /*@switchbreak@*/ break;
02395             }
02396 
02397             /*@-assignexpose@*/
02398             format[currToken].u.tag.format = start;
02399             /*@=assignexpose@*/
02400             format[currToken].u.tag.pad = 0;
02401             format[currToken].u.tag.justOne = 0;
02402             format[currToken].u.tag.arrayCount = 0;
02403 
02404             chptr = start;
02405             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02406             if (!*chptr || *chptr == '%') {
02407                 /*@-observertrans -readonlytrans@*/
02408                 if (errmsg) *errmsg = _("missing { after %");
02409                 /*@=observertrans =readonlytrans@*/
02410                 format = freeFormat(format, numTokens);
02411                 return 1;
02412             }
02413 
02414             *chptr++ = '\0';
02415 
02416             while (start < chptr) {
02417                 if (xisdigit(*start)) {
02418                     i = strtoul(start, &start, 10);
02419                     format[currToken].u.tag.pad += i;
02420                 } else {
02421                     start++;
02422                 }
02423             }
02424 
02425             if (*start == '=') {
02426                 format[currToken].u.tag.justOne = 1;
02427                 start++;
02428             } else if (*start == '#') {
02429                 format[currToken].u.tag.justOne = 1;
02430                 format[currToken].u.tag.arrayCount = 1;
02431                 start++;
02432             }
02433 
02434             next = start;
02435             while (*next && *next != '}') next++;
02436             if (!*next) {
02437                 /*@-observertrans -readonlytrans@*/
02438                 if (errmsg) *errmsg = _("missing } after %{");
02439                 /*@=observertrans =readonlytrans@*/
02440                 format = freeFormat(format, numTokens);
02441                 return 1;
02442             }
02443             *next++ = '\0';
02444 
02445             chptr = start;
02446             while (*chptr && *chptr != ':') chptr++;
02447 
02448             if (*chptr != '\0') {
02449                 *chptr++ = '\0';
02450                 if (!*chptr) {
02451                     /*@-observertrans -readonlytrans@*/
02452                     if (errmsg) *errmsg = _("empty tag format");
02453                     /*@=observertrans =readonlytrans@*/
02454                     format = freeFormat(format, numTokens);
02455                     return 1;
02456                 }
02457                 /*@-assignexpose@*/
02458                 format[currToken].u.tag.type = chptr;
02459                 /*@=assignexpose@*/
02460             } else {
02461                 format[currToken].u.tag.type = NULL;
02462             }
02463             
02464             if (!*start) {
02465                 /*@-observertrans -readonlytrans@*/
02466                 if (errmsg) *errmsg = _("empty tag name");
02467                 /*@=observertrans =readonlytrans@*/
02468                 format = freeFormat(format, numTokens);
02469                 return 1;
02470             }
02471 
02472             i = 0;
02473             findTag(start, tags, extensions, &tag, &ext);
02474 
02475             if (tag) {
02476                 format[currToken].u.tag.ext = NULL;
02477                 format[currToken].u.tag.tag = tag->val;
02478             } else if (ext) {
02479                 format[currToken].u.tag.ext = ext->u.tagFunction;
02480                 format[currToken].u.tag.extNum = ext - extensions;
02481             } else {
02482                 /*@-observertrans -readonlytrans@*/
02483                 if (errmsg) *errmsg = _("unknown tag");
02484                 /*@=observertrans =readonlytrans@*/
02485                 format = freeFormat(format, numTokens);
02486                 return 1;
02487             }
02488 
02489             format[currToken].type = PTOK_TAG;
02490 
02491             start = next;
02492 
02493             /*@switchbreak@*/ break;
02494 
02495         case '[':
02496             *dst++ = '\0';
02497             *start++ = '\0';
02498             currToken++;
02499 
02500             if (parseFormat(start, tags, extensions, 
02501                             &format[currToken].u.array.format,
02502                             &format[currToken].u.array.numTokens,
02503                             &start, PARSER_IN_ARRAY, errmsg)) {
02504                 format = freeFormat(format, numTokens);
02505                 return 1;
02506             }
02507 
02508             if (!start) {
02509                 /*@-observertrans -readonlytrans@*/
02510                 if (errmsg) *errmsg = _("] expected at end of array");
02511                 /*@=observertrans =readonlytrans@*/
02512                 format = freeFormat(format, numTokens);
02513                 return 1;
02514             }
02515 
02516             dst = start;
02517 
02518             format[currToken].type = PTOK_ARRAY;
02519 
02520             /*@switchbreak@*/ break;
02521 
02522         case ']':
02523         case '}':
02524             if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02525                 (*start == '}' && state != PARSER_IN_EXPR)) {
02526                 if (*start == ']') {
02527                     /*@-observertrans -readonlytrans@*/
02528                     if (errmsg) *errmsg = _("unexpected ]");
02529                     /*@=observertrans =readonlytrans@*/
02530                 } else {
02531                     /*@-observertrans -readonlytrans@*/
02532                     if (errmsg) *errmsg = _("unexpected }");
02533                     /*@=observertrans =readonlytrans@*/
02534                 }
02535                 format = freeFormat(format, numTokens);
02536                 return 1;
02537             }
02538             *start++ = '\0';
02539             if (endPtr) *endPtr = start;
02540             done = 1;
02541             /*@switchbreak@*/ break;
02542 
02543         default:
02544             if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02545                 currToken++;
02546                 format[currToken].type = PTOK_STRING;
02547                 /*@-temptrans -assignexpose@*/
02548                 dst = format[currToken].u.string.string = start;
02549                 /*@=temptrans =assignexpose@*/
02550             }
02551 
02552             if (*start == '\\') {
02553                 start++;
02554                 *dst++ = escapedChar(*start++);
02555             } else {
02556                 *dst++ = *start++;
02557             }
02558             /*@switchbreak@*/ break;
02559         }
02560         if (done)
02561             break;
02562     }
02563     /*@=infloops@*/
02564 
02565     if (dst != NULL)
02566         *dst = '\0';
02567 
02568     currToken++;
02569     for (i = 0; i < currToken; i++) {
02570         if (format[i].type == PTOK_STRING)
02571             format[i].u.string.len = strlen(format[i].u.string.string);
02572     }
02573 
02574     *numTokensPtr = currToken;
02575     *formatPtr = format;
02576 
02577     return 0;
02578 }
02579 /*@=boundswrite@*/
02580 
02583 /*@-boundswrite@*/
02584 static int parseExpression(sprintfToken token, char * str, 
02585                 const headerTagTableEntry tags, 
02586                 const headerSprintfExtension extensions,
02587                 /*@out@*/ char ** endPtr,
02588                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
02589 {
02590     headerTagTableEntry tag;
02591     headerSprintfExtension ext;
02592     char * chptr;
02593     char * end;
02594 
02595     if (errmsg) *errmsg = NULL;
02596     chptr = str;
02597     while (*chptr && *chptr != '?') chptr++;
02598 
02599     if (*chptr != '?') {
02600         /*@-observertrans -readonlytrans@*/
02601         if (errmsg) *errmsg = _("? expected in expression");
02602         /*@=observertrans =readonlytrans@*/
02603         return 1;
02604     }
02605 
02606     *chptr++ = '\0';;
02607 
02608     if (*chptr != '{') {
02609         /*@-observertrans -readonlytrans@*/
02610         if (errmsg) *errmsg = _("{ expected after ? in expression");
02611         /*@=observertrans =readonlytrans@*/
02612         return 1;
02613     }
02614 
02615     chptr++;
02616 
02617     if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat, 
02618                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg)) 
02619         return 1;
02620 
02621     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
02622     if (!(end && *end)) {
02623         /*@-observertrans -readonlytrans@*/
02624         if (errmsg) *errmsg = _("} expected in expression");
02625         /*@=observertrans =readonlytrans@*/
02626         token->u.cond.ifFormat =
02627                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02628         return 1;
02629     }
02630 
02631     chptr = end;
02632     if (*chptr != ':' && *chptr != '|') {
02633         /*@-observertrans -readonlytrans@*/
02634         if (errmsg) *errmsg = _(": expected following ? subexpression");
02635         /*@=observertrans =readonlytrans@*/
02636         token->u.cond.ifFormat =
02637                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02638         return 1;
02639     }
02640 
02641     if (*chptr == '|') {
02642         if (parseFormat(NULL, tags, extensions, &token->u.cond.elseFormat, 
02643                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, errmsg))
02644         {
02645             token->u.cond.ifFormat =
02646                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02647             return 1;
02648         }
02649     } else {
02650         chptr++;
02651 
02652         if (*chptr != '{') {
02653             /*@-observertrans -readonlytrans@*/
02654             if (errmsg) *errmsg = _("{ expected after : in expression");
02655             /*@=observertrans =readonlytrans@*/
02656             token->u.cond.ifFormat =
02657                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02658             return 1;
02659         }
02660 
02661         chptr++;
02662 
02663         if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat, 
02664                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, 
02665                         errmsg)) 
02666             return 1;
02667 
02668         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
02669         if (!(end && *end)) {
02670             /*@-observertrans -readonlytrans@*/
02671             if (errmsg) *errmsg = _("} expected in expression");
02672             /*@=observertrans =readonlytrans@*/
02673             token->u.cond.ifFormat =
02674                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02675             return 1;
02676         }
02677 
02678         chptr = end;
02679         if (*chptr != '|') {
02680             /*@-observertrans -readonlytrans@*/
02681             if (errmsg) *errmsg = _("| expected at end of expression");
02682             /*@=observertrans =readonlytrans@*/
02683             token->u.cond.ifFormat =
02684                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02685             token->u.cond.elseFormat =
02686                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02687             return 1;
02688         }
02689     }
02690         
02691     chptr++;
02692 
02693     *endPtr = chptr;
02694 
02695     findTag(str, tags, extensions, &tag, &ext);
02696 
02697     if (tag) {
02698         token->u.cond.tag.ext = NULL;
02699         token->u.cond.tag.tag = tag->val;
02700     } else if (ext) {
02701         token->u.cond.tag.ext = ext->u.tagFunction;
02702         token->u.cond.tag.extNum = ext - extensions;
02703     } else {
02704         token->u.cond.tag.ext = NULL;
02705         token->u.cond.tag.tag = -1;
02706     }
02707         
02708     token->type = PTOK_COND;
02709 
02710     return 0;
02711 }
02712 /*@=boundswrite@*/
02713 
02723 static int getExtension(Header h, headerTagTagFunction fn,
02724                 /*@out@*/ hTYP_t typeptr,
02725                 /*@out@*/ hPTR_t * data,
02726                 /*@out@*/ hCNT_t countptr,
02727                 extensionCache ext)
02728         /*@modifies *typeptr, *data, *countptr, ext @*/
02729         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
02730                 /\ maxSet(countptr) >= 0 @*/
02731 {
02732     if (!ext->avail) {
02733         if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02734             return 1;
02735         ext->avail = 1;
02736     }
02737 
02738     if (typeptr) *typeptr = ext->type;
02739     if (data) *data = ext->data;
02740     if (countptr) *countptr = ext->count;
02741 
02742     return 0;
02743 }
02744 
02747 /*@observer@*/
02748 static char * formatValue(sprintfTag tag, Header h, 
02749                 const headerSprintfExtension extensions,
02750                 extensionCache extCache, int element,
02751                 char ** valp, int * vallenp, int * allocedp)
02752         /*@modifies extCache, *valp, *vallenp, *allocedp @*/
02753         /*@requires maxSet(valp) >= 0 /\ maxSet(vallenp) >= 0
02754                 /\ maxSet(allocedp) >= 0 @*/
02755 {
02756     char * val = NULL;
02757     int need = 0;
02758     char * t, * te;
02759     char buf[20];
02760     int_32 count, type;
02761     hPTR_t data;
02762     unsigned int intVal;
02763     const char ** strarray;
02764     int datafree = 0;
02765     int countBuf;
02766     headerTagFormatFunction tagtype = NULL;
02767     headerSprintfExtension ext;
02768 
02769     memset(buf, 0, sizeof(buf));
02770     /*@-branchstate@*/
02771     if (tag->ext) {
02772 /*@-boundswrite@*/
02773         if (getExtension(h, tag->ext, &type, &data, &count, 
02774                          extCache + tag->extNum))
02775         {
02776             count = 1;
02777             type = RPM_STRING_TYPE;     
02778             data = "(none)";
02779         }
02780 /*@=boundswrite@*/
02781     } else {
02782 /*@-boundswrite@*/
02783         if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02784             count = 1;
02785             type = RPM_STRING_TYPE;     
02786             data = "(none)";
02787         }
02788 /*@=boundswrite@*/
02789 
02790         datafree = 1;
02791     }
02792     /*@=branchstate@*/
02793 
02794     if (tag->arrayCount) {
02795         /*@-branchstate -observertrans -modobserver@*/
02796         if (datafree)
02797             data = headerFreeData(data, type);
02798         /*@=branchstate =observertrans =modobserver@*/
02799 
02800         countBuf = count;
02801         data = &countBuf;
02802         count = 1;
02803         type = RPM_INT32_TYPE;
02804     }
02805 
02806 /*@-boundswrite@*/
02807     (void) stpcpy( stpcpy(buf, "%"), tag->format);
02808 /*@=boundswrite@*/
02809 
02810     if (tag->type) {
02811         ext = extensions;
02812         while (ext->type != HEADER_EXT_LAST) {
02813             if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02814             && !strcmp(ext->name, tag->type))
02815             {
02816                 tagtype = ext->u.formatFunction;
02817                 break;
02818             }
02819 
02820             if (ext->type == HEADER_EXT_MORE)
02821                 ext = ext->u.more;
02822             else
02823                 ext++;
02824         }
02825     }
02826     
02827     /*@-branchstate@*/
02828     switch (type) {
02829     case RPM_STRING_ARRAY_TYPE:
02830         strarray = (const char **)data;
02831 
02832         if (tagtype)
02833             val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02834 
02835         if (val) {
02836             need = strlen(val);
02837         } else {
02838             need = strlen(strarray[element]) + tag->pad + 20;
02839             val = xmalloc(need+1);
02840             strcat(buf, "s");
02841             /*@-formatconst@*/
02842             sprintf(val, buf, strarray[element]);
02843             /*@=formatconst@*/
02844         }
02845 
02846         /*@-observertrans -modobserver@*/
02847         if (datafree) data = _free(data);
02848         /*@=observertrans =modobserver@*/
02849 
02850         break;
02851 
02852     case RPM_STRING_TYPE:
02853         if (tagtype)
02854             val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad,  0);
02855 
02856         if (val) {
02857             need = strlen(val);
02858         } else {
02859             need = strlen(data) + tag->pad + 20;
02860             val = xmalloc(need+1);
02861             strcat(buf, "s");
02862             /*@-formatconst@*/
02863             sprintf(val, buf, data);
02864             /*@=formatconst@*/
02865         }
02866         break;
02867 
02868     case RPM_CHAR_TYPE:
02869     case RPM_INT8_TYPE:
02870     case RPM_INT16_TYPE:
02871     case RPM_INT32_TYPE:
02872         switch (type) {
02873         case RPM_CHAR_TYPE:     
02874         case RPM_INT8_TYPE:
02875             intVal = *(((int_8 *) data) + element);
02876             /*@innerbreak@*/ break;
02877         case RPM_INT16_TYPE:
02878             intVal = *(((uint_16 *) data) + element);
02879             /*@innerbreak@*/ break;
02880         default:                /* keep -Wall quiet */
02881         case RPM_INT32_TYPE:
02882             intVal = *(((int_32 *) data) + element);
02883             /*@innerbreak@*/ break;
02884         }
02885 
02886         if (tagtype)
02887             val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad,  element);
02888 
02889         if (val) {
02890             need = strlen(val);
02891         } else {
02892             need = 10 + tag->pad + 20;
02893             val = xmalloc(need+1);
02894             strcat(buf, "d");
02895             /*@-formatconst@*/
02896             sprintf(val, buf, intVal);
02897             /*@=formatconst@*/
02898         }
02899         break;
02900 
02901     case RPM_BIN_TYPE:
02902         if (tagtype)
02903             val = tagtype(RPM_BIN_TYPE, data, buf, tag->pad, count);
02904 
02905         if (val) {
02906             need = count;       /* XXX broken iff RPM_BIN_TYPE extension */
02907         } else {
02908 #ifdef  NOTYET
02909             val = memcpy(xmalloc(count), data, count);
02910 #else
02911             /* XXX format string not used */
02912             static char hex[] = "0123456789abcdef";
02913             const char * s = data;
02914 
02915 /*@-boundswrite@*/
02916             need = 2*count + tag->pad;
02917             val = t = xmalloc(need+1);
02918             while (count-- > 0) {
02919                 unsigned int i;
02920                 i = *s++;
02921                 *t++ = hex[ (i >> 4) & 0xf ];
02922                 *t++ = hex[ (i     ) & 0xf ];
02923             }
02924             *t = '\0';
02925 /*@=boundswrite@*/
02926 #endif
02927         }
02928         break;
02929 
02930     default:
02931         need = sizeof("(unknown type)") - 1;
02932         val = xstrdup("(unknown type)");
02933         break;
02934     }
02935     /*@=branchstate@*/
02936 
02937     /*@-branchstate@*/
02938     if (val && need > 0) {
02939         if (((*vallenp) + need) >= (*allocedp)) {
02940             if ((*allocedp) <= need)
02941                 (*allocedp) += need;
02942 /*@-shiftimplementation@*/
02943             (*allocedp) <<= 1;
02944 /*@=shiftimplementation@*/
02945 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
02946             (*valp) = xrealloc((*valp), (*allocedp)+1); 
02947 /*@=unqualifiedtrans@*/
02948         }
02949         t = (*valp) + (*vallenp);
02950 /*@-boundswrite@*/
02951         te = stpcpy(t, val);
02952 /*@=boundswrite@*/
02953         (*vallenp) += (te - t);
02954         val = _free(val);
02955     }
02956     /*@=branchstate@*/
02957 
02958     return ((*valp) + (*vallenp));
02959 }
02960 
02963 /*@observer@*/
02964 static char * singleSprintf(Header h, sprintfToken token,
02965                 const headerSprintfExtension extensions,
02966                 extensionCache extCache, int element,
02967                 char ** valp, int * vallenp, int * allocedp)
02968         /*@modifies h, extCache, *valp, *vallenp, *allocedp @*/
02969         /*@requires maxSet(valp) >= 0 /\ maxSet(vallenp) >= 0
02970                 /\ maxSet(allocedp) >= 0 @*/
02971 {
02972     char * t, * te;
02973     int i, j;
02974     int numElements;
02975     int type;
02976     sprintfToken condFormat;
02977     int condNumFormats;
02978     int need;
02979 
02980     /* we assume the token and header have been validated already! */
02981 
02982     switch (token->type) {
02983     case PTOK_NONE:
02984         break;
02985 
02986     case PTOK_STRING:
02987         need = token->u.string.len;
02988         if (need <= 0) break;
02989         if (((*vallenp) + need) >= (*allocedp)) {
02990             if ((*allocedp) <= need)
02991                 (*allocedp) += need;
02992 /*@-shiftimplementation@*/
02993             (*allocedp) <<= 1;
02994 /*@=shiftimplementation@*/
02995 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
02996             (*valp) = xrealloc((*valp), (*allocedp)+1); 
02997 /*@=unqualifiedtrans@*/
02998         }
02999         t = (*valp) + (*vallenp);
03000 /*@-boundswrite@*/
03001         te = stpcpy(t, token->u.string.string);
03002 /*@=boundswrite@*/
03003         (*vallenp) += (te - t);
03004         break;
03005 
03006     case PTOK_TAG:
03007         t = (*valp) + (*vallenp);
03008         te = formatValue(&token->u.tag, h, extensions, extCache,
03009                         (token->u.tag.justOne ? 0 : element),
03010                         valp, vallenp, allocedp);
03011         break;
03012 
03013     case PTOK_COND:
03014         if (token->u.cond.tag.ext ||
03015             headerIsEntry(h, token->u.cond.tag.tag)) {
03016             condFormat = token->u.cond.ifFormat;
03017             condNumFormats = token->u.cond.numIfTokens;
03018         } else {
03019             condFormat = token->u.cond.elseFormat;
03020             condNumFormats = token->u.cond.numElseTokens;
03021         }
03022 
03023         need = condNumFormats * 20;
03024         if (condFormat == NULL || need <= 0) break;
03025         if (((*vallenp) + need) >= (*allocedp)) {
03026             if ((*allocedp) <= need)
03027                 (*allocedp) += need;
03028 /*@-shiftimplementation@*/
03029             (*allocedp) <<= 1;
03030 /*@=shiftimplementation@*/
03031 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
03032             (*valp) = xrealloc((*valp), (*allocedp)+1); 
03033 /*@=unqualifiedtrans@*/
03034         }
03035 
03036         t = (*valp) + (*vallenp);
03037         for (i = 0; i < condNumFormats; i++)
03038             te = singleSprintf(h, condFormat + i, extensions, extCache,
03039                                 element, valp, vallenp, allocedp);
03040         break;
03041 
03042     case PTOK_ARRAY:
03043         numElements = -1;
03044         for (i = 0; i < token->u.array.numTokens; i++) {
03045             if (token->u.array.format[i].type != PTOK_TAG ||
03046                 token->u.array.format[i].u.tag.arrayCount ||
03047                 token->u.array.format[i].u.tag.justOne) continue;
03048 
03049             if (token->u.array.format[i].u.tag.ext) {
03050                 const void * data;
03051 /*@-boundswrite@*/
03052                 if (getExtension(h, token->u.array.format[i].u.tag.ext,
03053                                  &type, &data, &numElements, 
03054                                  extCache + 
03055                                    token->u.array.format[i].u.tag.extNum))
03056                      continue;
03057 /*@=boundswrite@*/
03058             } else {
03059 /*@-boundswrite@*/
03060                 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag, 
03061                                     &type, NULL, &numElements))
03062                     continue;
03063 /*@=boundswrite@*/
03064             } 
03065             /*@loopbreak@*/ break;
03066         }
03067 
03068         if (numElements == -1) {
03069             need = sizeof("(none)") - 1;
03070             if (((*vallenp) + need) >= (*allocedp)) {
03071                 if ((*allocedp) <= need)
03072                     (*allocedp) += need;
03073 /*@-shiftimplementation@*/
03074                 (*allocedp) <<= 1;
03075 /*@=shiftimplementation@*/
03076 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
03077                 (*valp) = xrealloc((*valp), (*allocedp)+1);     
03078 /*@=unqualifiedtrans@*/
03079             }
03080             t = (*valp) + (*vallenp);
03081 /*@-boundswrite@*/
03082             te = stpcpy(t, "(none)");
03083 /*@=boundswrite@*/
03084             (*vallenp) += (te - t);
03085         } else {
03086             need = numElements * token->u.array.numTokens * 10;
03087             if (need <= 0) break;
03088             if (((*vallenp) + need) >= (*allocedp)) {
03089                 if ((*allocedp) <= need)
03090                     (*allocedp) += need;
03091 /*@-shiftimplementation@*/
03092                 (*allocedp) <<= 1;
03093 /*@=shiftimplementation@*/
03094 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
03095                 (*valp) = xrealloc((*valp), (*allocedp)+1);     
03096 /*@=unqualifiedtrans@*/
03097             }
03098 
03099             t = (*valp) + (*vallenp);
03100             for (j = 0; j < numElements; j++) {
03101                 for (i = 0; i < token->u.array.numTokens; i++)
03102                     te = singleSprintf(h, token->u.array.format + i, 
03103                                         extensions, extCache, j,
03104                                         valp, vallenp, allocedp);
03105             }
03106         }
03107         break;
03108     }
03109 
03110     return ((*valp) + (*vallenp));
03111 }
03112 
03115 static /*@only@*/ extensionCache
03116 allocateExtensionCache(const headerSprintfExtension extensions)
03117         /*@*/
03118 {
03119     headerSprintfExtension ext = extensions;
03120     int i = 0;
03121 
03122     while (ext->type != HEADER_EXT_LAST) {
03123         i++;
03124         if (ext->type == HEADER_EXT_MORE)
03125             ext = ext->u.more;
03126         else
03127             ext++;
03128     }
03129 
03130     /*@-sizeoftype@*/
03131     return xcalloc(i, sizeof(struct extensionCache_s));
03132     /*@=sizeoftype@*/
03133 }
03134 
03138 static /*@null@*/ extensionCache
03139 freeExtensionCache(const headerSprintfExtension extensions,
03140                         /*@only@*/ extensionCache cache)
03141         /*@*/
03142 {
03143     headerSprintfExtension ext = extensions;
03144     int i = 0;
03145 
03146     while (ext->type != HEADER_EXT_LAST) {
03147 /*@-boundswrite@*/
03148         if (cache[i].freeit) cache[i].data = _free(cache[i].data);
03149 /*@=boundswrite@*/
03150 
03151         i++;
03152         if (ext->type == HEADER_EXT_MORE)
03153             ext = ext->u.more;
03154         else
03155             ext++;
03156     }
03157 
03158     cache = _free(cache);
03159     return NULL;
03160 }
03161 
03173 static /*@only@*/ /*@null@*/
03174 char * headerSprintf(Header h, const char * fmt,
03175                      const struct headerTagTableEntry_s * tbltags,
03176                      const struct headerSprintfExtension_s * extensions,
03177                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03178         /*@modifies *errmsg @*/
03179 {
03180     /*@-castexpose@*/   /* FIX: legacy API shouldn't change. */
03181     headerSprintfExtension exts = (headerSprintfExtension) extensions;
03182     headerTagTableEntry tags = (headerTagTableEntry) tbltags;
03183     /*@=castexpose@*/
03184     char * t;
03185     char * fmtString;
03186     sprintfToken format;
03187     int numTokens;
03188     char * val = NULL;
03189     int vallen = 0;
03190     int alloced = 0;
03191     int i;
03192     extensionCache extCache;
03193  
03194     /*fmtString = escapeString(fmt);*/
03195     fmtString = xstrdup(fmt);
03196    
03197 /*@-boundswrite@*/
03198     if (parseFormat(fmtString, tags, exts, &format, &numTokens, 
03199                     NULL, PARSER_BEGIN, errmsg)) {
03200         fmtString = _free(fmtString);
03201         return NULL;
03202     }
03203 /*@=boundswrite@*/
03204 
03205     extCache = allocateExtensionCache(exts);
03206 
03207     val = xstrdup("");
03208     for (i = 0; i < numTokens; i++) {
03209 /*@-boundswrite@*/
03210         /*@-mods@*/
03211         t = singleSprintf(h, format + i, exts, extCache, 0,
03212                 &val, &vallen, &alloced);
03213         /*@=mods@*/
03214 /*@=boundswrite@*/
03215     }
03216 
03217     if (val != NULL && vallen < alloced)
03218         val = xrealloc(val, vallen+1);  
03219 
03220     fmtString = _free(fmtString);
03221     extCache = freeExtensionCache(exts, extCache);
03222     format = freeFormat(format, numTokens);
03223 
03224     return val;
03225 }
03226 
03229 static char * octalFormat(int_32 type, hPTR_t data, 
03230                 char * formatPrefix, int padding, /*@unused@*/int element)
03231         /*@modifies formatPrefix @*/
03232 {
03233     char * val;
03234 
03235     if (type != RPM_INT32_TYPE) {
03236         val = xstrdup(_("(not a number)"));
03237     } else {
03238         val = xmalloc(20 + padding);
03239 /*@-boundswrite@*/
03240         strcat(formatPrefix, "o");
03241 /*@=boundswrite@*/
03242         /*@-formatconst@*/
03243         sprintf(val, formatPrefix, *((int_32 *) data));
03244         /*@=formatconst@*/
03245     }
03246 
03247     return val;
03248 }
03249 
03252 static char * hexFormat(int_32 type, hPTR_t data, 
03253                 char * formatPrefix, int padding, /*@unused@*/int element)
03254         /*@modifies formatPrefix @*/
03255 {
03256     char * val;
03257 
03258     if (type != RPM_INT32_TYPE) {
03259         val = xstrdup(_("(not a number)"));
03260     } else {
03261         val = xmalloc(20 + padding);
03262 /*@-boundswrite@*/
03263         strcat(formatPrefix, "x");
03264 /*@=boundswrite@*/
03265         /*@-formatconst@*/
03266         sprintf(val, formatPrefix, *((int_32 *) data));
03267         /*@=formatconst@*/
03268     }
03269 
03270     return val;
03271 }
03272 
03275 static char * realDateFormat(int_32 type, hPTR_t data, 
03276                 char * formatPrefix, int padding, /*@unused@*/int element,
03277                 const char * strftimeFormat)
03278         /*@modifies formatPrefix @*/
03279 {
03280     char * val;
03281 
03282     if (type != RPM_INT32_TYPE) {
03283         val = xstrdup(_("(not a number)"));
03284     } else {
03285         struct tm * tstruct;
03286         char buf[50];
03287 
03288         val = xmalloc(50 + padding);
03289 /*@-boundswrite@*/
03290         strcat(formatPrefix, "s");
03291 /*@=boundswrite@*/
03292 
03293         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03294         {   time_t dateint = *((int_32 *) data);
03295             tstruct = localtime(&dateint);
03296         }
03297         buf[0] = '\0';
03298         if (tstruct)
03299             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03300         /*@-formatconst@*/
03301         sprintf(val, formatPrefix, buf);
03302         /*@=formatconst@*/
03303     }
03304 
03305     return val;
03306 }
03307 
03310 static char * dateFormat(int_32 type, hPTR_t data, 
03311                          char * formatPrefix, int padding, int element)
03312         /*@modifies formatPrefix @*/
03313 {
03314     return realDateFormat(type, data, formatPrefix, padding, element, "%c");
03315 }
03316 
03319 static char * dayFormat(int_32 type, hPTR_t data, 
03320                          char * formatPrefix, int padding, int element)
03321         /*@modifies formatPrefix @*/
03322 {
03323     return realDateFormat(type, data, formatPrefix, padding, element, 
03324                           "%a %b %d %Y");
03325 }
03326 
03329 static char * shescapeFormat(int_32 type, hPTR_t data, 
03330                 char * formatPrefix, int padding, /*@unused@*/int element)
03331         /*@modifies formatPrefix @*/
03332 {
03333     char * result, * dst, * src, * buf;
03334 
03335     if (type == RPM_INT32_TYPE) {
03336         result = xmalloc(padding + 20);
03337 /*@-boundswrite@*/
03338         strcat(formatPrefix, "d");
03339 /*@=boundswrite@*/
03340         /*@-formatconst@*/
03341         sprintf(result, formatPrefix, *((int_32 *) data));
03342         /*@=formatconst@*/
03343     } else {
03344         buf = alloca(strlen(data) + padding + 2);
03345 /*@-boundswrite@*/
03346         strcat(formatPrefix, "s");
03347 /*@=boundswrite@*/
03348         /*@-formatconst@*/
03349         sprintf(buf, formatPrefix, data);
03350         /*@=formatconst@*/
03351 
03352 /*@-boundswrite@*/
03353         result = dst = xmalloc(strlen(buf) * 4 + 3);
03354         *dst++ = '\'';
03355         for (src = buf; *src != '\0'; src++) {
03356             if (*src == '\'') {
03357                 *dst++ = '\'';
03358                 *dst++ = '\\';
03359                 *dst++ = '\'';
03360                 *dst++ = '\'';
03361             } else {
03362                 *dst++ = *src;
03363             }
03364         }
03365         *dst++ = '\'';
03366         *dst = '\0';
03367 /*@=boundswrite@*/
03368 
03369     }
03370 
03371     return result;
03372 }
03373 
03374 /*@-type@*/ /* FIX: cast? */
03375 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03376     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03377     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03378     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03379     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03380     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03381     { HEADER_EXT_LAST, NULL, { NULL } }
03382 };
03383 /*@=type@*/
03384 
03391 static
03392 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03393         /*@modifies headerTo @*/
03394 {
03395     int * p;
03396 
03397     if (headerFrom == headerTo)
03398         return;
03399 
03400     for (p = tagstocopy; *p != 0; p++) {
03401         char *s;
03402         int_32 type;
03403         int_32 count;
03404         if (headerIsEntry(headerTo, *p))
03405             continue;
03406 /*@-boundswrite@*/
03407         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03408                                 (hPTR_t *) &s, &count))
03409             continue;
03410 /*@=boundswrite@*/
03411         (void) headerAddEntry(headerTo, *p, type, s, count);
03412         s = headerFreeData(s, type);
03413     }
03414 }
03415 
03419 struct headerIteratorS {
03420 /*@unused@*/ Header h;          
03421 /*@unused@*/ int next_index;    
03422 };
03423 
03429 static /*@null@*/
03430 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
03431         /*@modifies hi @*/
03432 {
03433     hi->h = headerFree(hi->h);
03434     hi = _free(hi);
03435     return hi;
03436 }
03437 
03443 static
03444 HeaderIterator headerInitIterator(Header h)
03445         /*@modifies h */
03446 {
03447     HeaderIterator hi = xmalloc(sizeof(*hi));
03448 
03449     headerSort(h);
03450 
03451     hi->h = headerLink(h);
03452     hi->next_index = 0;
03453     return hi;
03454 }
03455 
03465 static
03466 int headerNextIterator(HeaderIterator hi,
03467                 /*@null@*/ /*@out@*/ hTAG_t tag,
03468                 /*@null@*/ /*@out@*/ hTYP_t type,
03469                 /*@null@*/ /*@out@*/ hPTR_t * p,
03470                 /*@null@*/ /*@out@*/ hCNT_t c)
03471         /*@modifies hi, *tag, *type, *p, *c @*/
03472         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
03473                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
03474 {
03475     Header h = hi->h;
03476     int slot = hi->next_index;
03477     indexEntry entry = NULL;
03478     int rc;
03479 
03480     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
03481         entry = h->index + slot;
03482         if (!ENTRY_IS_REGION(entry))
03483             break;
03484     }
03485     hi->next_index = slot;
03486     if (entry == NULL || slot >= h->indexUsed)
03487         return 0;
03488 
03489     /*@-noeffect@*/     /* LCL: no clue */
03490     hi->next_index++;
03491     /*@=noeffect@*/
03492 
03493     if (tag)
03494         *tag = entry->info.tag;
03495 
03496     rc = copyEntry(entry, type, p, c, 0);
03497 
03498     /* XXX 1 on success */
03499     return ((rc == 1) ? 1 : 0);
03500 }
03501 
03507 static /*@null@*/
03508 Header headerCopy(Header h)
03509         /*@modifies h @*/
03510 {
03511     Header nh = headerNew();
03512     HeaderIterator hi;
03513     int_32 tag, type, count;
03514     hPTR_t ptr;
03515    
03516     /*@-branchstate@*/
03517     for (hi = headerInitIterator(h);
03518         headerNextIterator(hi, &tag, &type, &ptr, &count);
03519         ptr = headerFreeData((void *)ptr, type))
03520     {
03521         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
03522     }
03523     hi = headerFreeIterator(hi);
03524     /*@=branchstate@*/
03525 
03526     return headerReload(nh, HEADER_IMAGE);
03527 }
03528 
03529 /*@observer@*/ /*@unchecked@*/
03530 static struct HV_s hdrVec1 = {
03531     headerLink,
03532     headerUnlink,
03533     headerFree,
03534     headerNew,
03535     headerSort,
03536     headerUnsort,
03537     headerSizeof,
03538     headerUnload,
03539     headerReload,
03540     headerCopy,
03541     headerLoad,
03542     headerCopyLoad,
03543     headerRead,
03544     headerWrite,
03545     headerIsEntry,
03546     headerFreeTag,
03547     headerGetEntry,
03548     headerGetEntryMinMemory,
03549     headerAddEntry,
03550     headerAppendEntry,
03551     headerAddOrAppendEntry,
03552     headerAddI18NString,
03553     headerModifyEntry,
03554     headerRemoveEntry,
03555     headerSprintf,
03556     headerCopyTags,
03557     headerFreeIterator,
03558     headerInitIterator,
03559     headerNextIterator,
03560     NULL, NULL,
03561     1
03562 };
03563 
03564 /*@-compmempass -redef@*/
03565 /*@observer@*/ /*@unchecked@*/
03566 HV_t hdrVec = &hdrVec1;
03567 /*@=compmempass =redef@*/

Generated on Tue Sep 17 15:56:44 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002