rpmdb/header.c

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

Generated on Thu Feb 23 17:00:15 2012 for rpm by  doxygen 1.4.7