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

Generated on Sun Oct 26 13:02:02 2003 for rpm by doxygen1.2.18