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

rpmdb/header.c

Go to the documentation of this file.
00001 
00005 /* RPM - Copyright (C) 1995-2002 Red Hat Software */
00006 
00007 /* Data written to file descriptors is in network byte order.    */
00008 /* Data read from file descriptors is expected to be in          */
00009 /* network byte order and is converted on the fly to host order. */
00010 
00011 #include "system.h"
00012 
00013 #define __HEADER_PROTOTYPES__
00014 
00015 #include <header_internal.h>
00016 
00017 #include "debug.h"
00018 
00019 /*@unchecked@*/
00020 int _hdr_debug = 0;
00021 
00022 /*@-redecl@*/   /* FIX: avoid rpmlib.h, need for debugging. */
00023 /*@observer@*/ const char *const tagName(int tag)       /*@*/;
00024 /*@=redecl@*/
00025 
00026 /*@access entryInfo @*/
00027 /*@access indexEntry @*/
00028 
00029 /*@access extensionCache @*/
00030 /*@access sprintfTag @*/
00031 /*@access sprintfToken @*/
00032 /*@access HV_t @*/
00033 
00034 #define PARSER_BEGIN    0
00035 #define PARSER_IN_ARRAY 1
00036 #define PARSER_IN_EXPR  2
00037 
00040 /*@observer@*/ /*@unchecked@*/
00041 static unsigned char header_magic[8] = {
00042         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
00043 };
00044 
00048 /*@unchecked@*/
00049 static size_t headerMaxbytes = (32*1024*1024);
00050 
00055 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
00056 
00061 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
00062 
00066 /*@observer@*/ /*@unchecked@*/
00067 static int typeSizes[] =  { 
00068         0,      
00069         1,      
00070         1,      
00071         2,      
00072         4,      
00073         -1,     
00074         -1,     
00075         1,      
00076         -1,     
00077         -1      
00078 };
00079 
00080 /*@observer@*/ /*@unchecked@*/
00081 HV_t hdrVec;    /* forward reference */
00082 
00088 /*@unused@*/ static inline /*@null@*/ void *
00089 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
00090 {
00091     if (p != NULL)      free((void *)p);
00092     return NULL;
00093 }
00094 
00100 static
00101 Header headerLink(Header h)
00102         /*@modifies h @*/
00103 {
00104 /*@-nullret@*/
00105     if (h == NULL) return NULL;
00106 /*@=nullret@*/
00107 
00108     h->nrefs++;
00109 /*@-modfilesys@*/
00110 if (_hdr_debug)
00111 fprintf(stderr, "--> h  %p ++ %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00112 /*@=modfilesys@*/
00113 
00114     /*@-refcounttrans @*/
00115     return h;
00116     /*@=refcounttrans @*/
00117 }
00118 
00124 static /*@null@*/
00125 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
00126         /*@modifies h @*/
00127 {
00128     if (h == NULL) return NULL;
00129 /*@-modfilesys@*/
00130 if (_hdr_debug)
00131 fprintf(stderr, "--> h  %p -- %d at %s:%u\n", h, h->nrefs, __FILE__, __LINE__);
00132 /*@=modfilesys@*/
00133     h->nrefs--;
00134     return NULL;
00135 }
00136 
00142 static /*@null@*/
00143 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
00144         /*@modifies h @*/
00145 {
00146     (void) headerUnlink(h);
00147 
00148     /*@-usereleased@*/
00149     if (h == NULL || h->nrefs > 0)
00150         return NULL;    /* XXX return previous header? */
00151 
00152     if (h->index) {
00153         indexEntry entry = h->index;
00154         int i;
00155         for (i = 0; i < h->indexUsed; i++, entry++) {
00156             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
00157                 if (entry->length > 0) {
00158                     int_32 * ei = entry->data;
00159                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
00160                     entry->data = NULL;
00161                 }
00162             } else if (!ENTRY_IN_REGION(entry)) {
00163                 entry->data = _free(entry->data);
00164             }
00165             entry->data = NULL;
00166         }
00167         h->index = _free(h->index);
00168     }
00169 
00170     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
00171     return h;
00172     /*@=usereleased@*/
00173 }
00174 
00179 static
00180 Header headerNew(void)
00181         /*@*/
00182 {
00183     Header h = xcalloc(1, sizeof(*h));
00184 
00185 /*@-boundsread@*/
00186     /*@-assignexpose@*/
00187     h->hv = *hdrVec;            /* structure assignment */
00188     /*@=assignexpose@*/
00189 /*@=boundsread@*/
00190     h->blob = NULL;
00191     h->indexAlloced = INDEX_MALLOC_SIZE;
00192     h->indexUsed = 0;
00193     h->flags |= HEADERFLAG_SORTED;
00194 
00195     h->index = (h->indexAlloced
00196         ? xcalloc(h->indexAlloced, sizeof(*h->index))
00197         : NULL);
00198 
00199     h->nrefs = 0;
00200     /*@-globstate -observertrans @*/
00201     return headerLink(h);
00202     /*@=globstate =observertrans @*/
00203 }
00204 
00207 static int indexCmp(const void * avp, const void * bvp)
00208         /*@*/
00209 {
00210     /*@-castexpose@*/
00211     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00212     /*@=castexpose@*/
00213     return (ap->info.tag - bp->info.tag);
00214 }
00215 
00220 static
00221 void headerSort(Header h)
00222         /*@modifies h @*/
00223 {
00224     if (!(h->flags & HEADERFLAG_SORTED)) {
00225 /*@-boundsread@*/
00226         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00227 /*@=boundsread@*/
00228         h->flags |= HEADERFLAG_SORTED;
00229     }
00230 }
00231 
00234 static int offsetCmp(const void * avp, const void * bvp) /*@*/
00235 {
00236     /*@-castexpose@*/
00237     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
00238     /*@=castexpose@*/
00239     int rc = (ap->info.offset - bp->info.offset);
00240 
00241     if (rc == 0) {
00242         /* Within a region, entries sort by address. Added drips sort by tag. */
00243         if (ap->info.offset < 0)
00244             rc = (((char *)ap->data) - ((char *)bp->data));
00245         else
00246             rc = (ap->info.tag - bp->info.tag);
00247     }
00248     return rc;
00249 }
00250 
00255 static
00256 void headerUnsort(Header h)
00257         /*@modifies h @*/
00258 {
00259 /*@-boundsread@*/
00260     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
00261 /*@=boundsread@*/
00262 }
00263 
00270 static
00271 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
00272         /*@modifies h @*/
00273 {
00274     indexEntry entry;
00275     unsigned int size = 0;
00276     unsigned int pad = 0;
00277     int i;
00278 
00279     if (h == NULL)
00280         return size;
00281 
00282     headerSort(h);
00283 
00284     switch (magicp) {
00285     case HEADER_MAGIC_YES:
00286         size += sizeof(header_magic);
00287         break;
00288     case HEADER_MAGIC_NO:
00289         break;
00290     }
00291 
00292     /*@-sizeoftype@*/
00293     size += 2 * sizeof(int_32); /* count of index entries */
00294     /*@=sizeoftype@*/
00295 
00296     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00297         unsigned diff;
00298         int_32 type;
00299 
00300         /* Regions go in as is ... */
00301         if (ENTRY_IS_REGION(entry)) {
00302             size += entry->length;
00303             /* XXX Legacy regions do not include the region tag and data. */
00304             /*@-sizeoftype@*/
00305             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00306                 size += sizeof(struct entryInfo_s) + entry->info.count;
00307             /*@=sizeoftype@*/
00308             continue;
00309         }
00310 
00311         /* ... and region elements are skipped. */
00312         if (entry->info.offset < 0)
00313             continue;
00314 
00315         /* Alignment */
00316         type = entry->info.type;
00317 /*@-boundsread@*/
00318         if (typeSizes[type] > 1) {
00319             diff = typeSizes[type] - (size % typeSizes[type]);
00320             if (diff != typeSizes[type]) {
00321                 size += diff;
00322                 pad += diff;
00323             }
00324         }
00325 /*@=boundsread@*/
00326 
00327         /*@-sizeoftype@*/
00328         size += sizeof(struct entryInfo_s) + entry->length;
00329         /*@=sizeoftype@*/
00330     }
00331 
00332     return size;
00333 }
00334 
00344 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk,
00345                 /*@null@*/ hPTR_t pend)
00346         /*@*/
00347 {
00348     const unsigned char * s = p;
00349     const unsigned char * se = pend;
00350     int length = 0;
00351 
00352     switch (type) {
00353     case RPM_STRING_TYPE:
00354         if (count != 1)
00355             return -1;
00356         while (*s++) {
00357             if (se && s > se)
00358                 return -1;
00359             length++;
00360         }
00361         length++;       /* count nul terminator too. */
00362         break;
00363 
00364     case RPM_STRING_ARRAY_TYPE:
00365     case RPM_I18NSTRING_TYPE:
00366         /* These are like RPM_STRING_TYPE, except they're *always* an array */
00367         /* Compute sum of length of all strings, including nul terminators */
00368 
00369         if (onDisk) {
00370             while (count--) {
00371                 length++;       /* count nul terminator too */
00372                while (*s++) {
00373                     if (se && s > se)
00374                         return -1;
00375                     length++;
00376                 }
00377             }
00378         } else {
00379             const char ** av = (const char **)p;
00380 /*@-boundsread@*/
00381             while (count--) {
00382                 /* add one for null termination */
00383                 length += strlen(*av++) + 1;
00384             }
00385 /*@=boundsread@*/
00386         }
00387         break;
00388 
00389     default:
00390 /*@-boundsread@*/
00391         if (typeSizes[type] == -1)
00392             return -1;
00393         length = typeSizes[(type & 0xf)] * count;
00394 /*@=boundsread@*/
00395         if (length < 0 || (se && (s + length) > se))
00396             return -1;
00397         break;
00398     }
00399 
00400     return length;
00401 }
00402 
00429 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
00430                 entryInfo pe,
00431                 unsigned char * dataStart,
00432                 /*@null@*/ const unsigned char * dataEnd,
00433                 int regionid)
00434         /*@modifies *entry, *dataStart @*/
00435 {
00436     unsigned char * tprev = NULL;
00437     unsigned char * t = NULL;
00438     int tdel, tl = dl;
00439     struct indexEntry_s ieprev;
00440 
00441 /*@-boundswrite@*/
00442     memset(&ieprev, 0, sizeof(ieprev));
00443 /*@=boundswrite@*/
00444     for (; il > 0; il--, pe++) {
00445         struct indexEntry_s ie;
00446         int_32 type;
00447 
00448         ie.info.tag = ntohl(pe->tag);
00449         ie.info.type = ntohl(pe->type);
00450         if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
00451             return -1;
00452         ie.info.count = ntohl(pe->count);
00453         ie.info.offset = ntohl(pe->offset);
00454 
00455         ie.data = t = dataStart + ie.info.offset;
00456         if (dataEnd && t >= dataEnd)
00457             return -1;
00458 
00459         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1, dataEnd);
00460         if (ie.length < 0 || hdrchkData(ie.length))
00461             return -1;
00462 
00463         ie.rdlen = 0;
00464 
00465         if (entry) {
00466             ie.info.offset = regionid;
00467 /*@-boundswrite@*/
00468             *entry = ie;        /* structure assignment */
00469 /*@=boundswrite@*/
00470             entry++;
00471         }
00472 
00473         /* Alignment */
00474         type = ie.info.type;
00475 /*@-boundsread@*/
00476         if (typeSizes[type] > 1) {
00477             unsigned diff;
00478             diff = typeSizes[type] - (dl % typeSizes[type]);
00479             if (diff != typeSizes[type]) {
00480                 dl += diff;
00481                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00482                     ieprev.length += diff;
00483             }
00484         }
00485 /*@=boundsread@*/
00486         tdel = (tprev ? (t - tprev) : 0);
00487         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
00488             tdel = ieprev.length;
00489 
00490         if (ie.info.tag >= HEADER_I18NTABLE) {
00491             tprev = t;
00492         } else {
00493             tprev = dataStart;
00494             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
00495             /*@-sizeoftype@*/
00496             if (ie.info.tag == HEADER_IMAGE)
00497                 tprev -= REGION_TAG_COUNT;
00498             /*@=sizeoftype@*/
00499         }
00500 
00501         /* Perform endian conversions */
00502         switch (ntohl(pe->type)) {
00503 /*@-bounds@*/
00504         case RPM_INT32_TYPE:
00505         {   int_32 * it = (int_32 *)t;
00506             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00507                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00508                     return -1;
00509                 *it = htonl(*it);
00510             }
00511             t = (char *) it;
00512         }   /*@switchbreak@*/ break;
00513         case RPM_INT16_TYPE:
00514         {   int_16 * it = (int_16 *) t;
00515             for (; ie.info.count > 0; ie.info.count--, it += 1) {
00516                 if (dataEnd && ((unsigned char *)it) >= dataEnd)
00517                     return -1;
00518                 *it = htons(*it);
00519             }
00520             t = (char *) it;
00521         }   /*@switchbreak@*/ break;
00522 /*@=bounds@*/
00523         default:
00524             t += ie.length;
00525             /*@switchbreak@*/ break;
00526         }
00527 
00528         dl += ie.length;
00529         tl += tdel;
00530         ieprev = ie;    /* structure assignment */
00531 
00532     }
00533     tdel = (tprev ? (t - tprev) : 0);
00534     tl += tdel;
00535 
00536     /* XXX
00537      * There are two hacks here:
00538      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
00539      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
00540      */
00541     /*@-sizeoftype@*/
00542     if (tl+REGION_TAG_COUNT == dl)
00543         tl += REGION_TAG_COUNT;
00544     /*@=sizeoftype@*/
00545 
00546     return dl;
00547 }
00548 
00551 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
00552                 /*@out@*/ int * lengthPtr)
00553         /*@modifies h, *lengthPtr @*/
00554         /*@requires maxSet(lengthPtr) >= 0 @*/
00555         /*@ensures maxRead(result) == (*lengthPtr) @*/
00556 {
00557     int_32 * ei = NULL;
00558     entryInfo pe;
00559     char * dataStart;
00560     char * te;
00561     unsigned pad;
00562     unsigned len;
00563     int_32 il = 0;
00564     int_32 dl = 0;
00565     indexEntry entry; 
00566     int_32 type;
00567     int i;
00568     int drlen, ndribbles;
00569     int driplen, ndrips;
00570     int legacy = 0;
00571 
00572     /* Sort entries by (offset,tag). */
00573     headerUnsort(h);
00574 
00575     /* Compute (il,dl) for all tags, including those deleted in region. */
00576     pad = 0;
00577     drlen = ndribbles = driplen = ndrips = 0;
00578     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00579         if (ENTRY_IS_REGION(entry)) {
00580             int_32 rdl = -entry->info.offset;   /* negative offset */
00581             int_32 ril = rdl/sizeof(*pe);
00582             int rid = entry->info.offset;
00583 
00584             il += ril;
00585             dl += entry->rdlen + entry->info.count;
00586             /* XXX Legacy regions do not include the region tag and data. */
00587             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
00588                 il += 1;
00589 
00590             /* Skip rest of entries in region, but account for dribbles. */
00591             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
00592                 if (entry->info.offset <= rid)
00593                     /*@innercontinue@*/ continue;
00594 
00595                 /* Alignment */
00596                 type = entry->info.type;
00597                 if (typeSizes[type] > 1) {
00598                     unsigned diff;
00599                     diff = typeSizes[type] - (dl % typeSizes[type]);
00600                     if (diff != typeSizes[type]) {
00601                         drlen += diff;
00602                         pad += diff;
00603                         dl += diff;
00604                     }
00605                 }
00606 
00607                 ndribbles++;
00608                 il++;
00609                 drlen += entry->length;
00610                 dl += entry->length;
00611             }
00612             i--;
00613             entry--;
00614             continue;
00615         }
00616 
00617         /* Ignore deleted drips. */
00618         if (entry->data == NULL || entry->length <= 0)
00619             continue;
00620 
00621         /* Alignment */
00622         type = entry->info.type;
00623         if (typeSizes[type] > 1) {
00624             unsigned diff;
00625             diff = typeSizes[type] - (dl % typeSizes[type]);
00626             if (diff != typeSizes[type]) {
00627                 driplen += diff;
00628                 pad += diff;
00629                 dl += diff;
00630             } else
00631                 diff = 0;
00632         }
00633 
00634         ndrips++;
00635         il++;
00636         driplen += entry->length;
00637         dl += entry->length;
00638     }
00639 
00640     /* Sanity checks on header intro. */
00641     if (hdrchkTags(il) || hdrchkData(dl))
00642         goto errxit;
00643 
00644     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
00645 
00646 /*@-boundswrite@*/
00647     ei = xmalloc(len);
00648     ei[0] = htonl(il);
00649     ei[1] = htonl(dl);
00650 /*@=boundswrite@*/
00651 
00652     pe = (entryInfo) &ei[2];
00653     dataStart = te = (char *) (pe + il);
00654 
00655     pad = 0;
00656     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
00657         const char * src;
00658 char *t;
00659         int count;
00660         int rdlen;
00661 
00662         if (entry->data == NULL || entry->length <= 0)
00663             continue;
00664 
00665 t = te;
00666         pe->tag = htonl(entry->info.tag);
00667         pe->type = htonl(entry->info.type);
00668         pe->count = htonl(entry->info.count);
00669 
00670         if (ENTRY_IS_REGION(entry)) {
00671             int_32 rdl = -entry->info.offset;   /* negative offset */
00672             int_32 ril = rdl/sizeof(*pe) + ndribbles;
00673             int rid = entry->info.offset;
00674 
00675             src = (char *)entry->data;
00676             rdlen = entry->rdlen;
00677 
00678             /* XXX Legacy regions do not include the region tag and data. */
00679             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
00680                 int_32 stei[4];
00681 
00682                 legacy = 1;
00683 /*@-boundswrite@*/
00684                 memcpy(pe+1, src, rdl);
00685                 memcpy(te, src + rdl, rdlen);
00686 /*@=boundswrite@*/
00687                 te += rdlen;
00688 
00689                 pe->offset = htonl(te - dataStart);
00690                 stei[0] = pe->tag;
00691                 stei[1] = pe->type;
00692                 stei[2] = htonl(-rdl-entry->info.count);
00693                 stei[3] = pe->count;
00694 /*@-boundswrite@*/
00695                 memcpy(te, stei, entry->info.count);
00696 /*@=boundswrite@*/
00697                 te += entry->info.count;
00698                 ril++;
00699                 rdlen += entry->info.count;
00700 
00701                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00702                 if (count != rdlen)
00703                     goto errxit;
00704 
00705             } else {
00706 
00707 /*@-boundswrite@*/
00708                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
00709                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
00710 /*@=boundswrite@*/
00711                 te += rdlen;
00712                 {   /*@-castexpose@*/
00713                     entryInfo se = (entryInfo)src;
00714                     /*@=castexpose@*/
00715                     int off = ntohl(se->offset);
00716                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
00717                 }
00718                 te += entry->info.count + drlen;
00719 
00720                 count = regionSwab(NULL, ril, 0, pe, t, NULL, 0);
00721                 if (count != (rdlen + entry->info.count + drlen))
00722                     goto errxit;
00723             }
00724 
00725             /* Skip rest of entries in region. */
00726             while (i < h->indexUsed && entry->info.offset <= rid+1) {
00727                 i++;
00728                 entry++;
00729             }
00730             i--;
00731             entry--;
00732             pe += ril;
00733             continue;
00734         }
00735 
00736         /* Ignore deleted drips. */
00737         if (entry->data == NULL || entry->length <= 0)
00738             continue;
00739 
00740         /* Alignment */
00741         type = entry->info.type;
00742         if (typeSizes[type] > 1) {
00743             unsigned diff;
00744             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
00745             if (diff != typeSizes[type]) {
00746 /*@-boundswrite@*/
00747                 memset(te, 0, diff);
00748 /*@=boundswrite@*/
00749                 te += diff;
00750                 pad += diff;
00751             }
00752         }
00753 
00754         pe->offset = htonl(te - dataStart);
00755 
00756         /* copy data w/ endian conversions */
00757 /*@-boundswrite@*/
00758         switch (entry->info.type) {
00759         case RPM_INT32_TYPE:
00760             count = entry->info.count;
00761             src = entry->data;
00762             while (count--) {
00763                 *((int_32 *)te) = htonl(*((int_32 *)src));
00764                 /*@-sizeoftype@*/
00765                 te += sizeof(int_32);
00766                 src += sizeof(int_32);
00767                 /*@=sizeoftype@*/
00768             }
00769             /*@switchbreak@*/ break;
00770 
00771         case RPM_INT16_TYPE:
00772             count = entry->info.count;
00773             src = entry->data;
00774             while (count--) {
00775                 *((int_16 *)te) = htons(*((int_16 *)src));
00776                 /*@-sizeoftype@*/
00777                 te += sizeof(int_16);
00778                 src += sizeof(int_16);
00779                 /*@=sizeoftype@*/
00780             }
00781             /*@switchbreak@*/ break;
00782 
00783         default:
00784             memcpy(te, entry->data, entry->length);
00785             te += entry->length;
00786             /*@switchbreak@*/ break;
00787         }
00788 /*@=boundswrite@*/
00789         pe++;
00790     }
00791    
00792     /* Insure that there are no memcpy underruns/overruns. */
00793     if (((char *)pe) != dataStart)
00794         goto errxit;
00795     if ((((char *)ei)+len) != te)
00796         goto errxit;
00797 
00798     if (lengthPtr)
00799         *lengthPtr = len;
00800 
00801     h->flags &= ~HEADERFLAG_SORTED;
00802     headerSort(h);
00803 
00804     return (void *) ei;
00805 
00806 errxit:
00807     /*@-usereleased@*/
00808     ei = _free(ei);
00809     /*@=usereleased@*/
00810     return (void *) ei;
00811 }
00812 
00818 static /*@only@*/ /*@null@*/
00819 void * headerUnload(Header h)
00820         /*@modifies h @*/
00821 {
00822     int length;
00823 /*@-boundswrite@*/
00824     void * uh = doHeaderUnload(h, &length);
00825 /*@=boundswrite@*/
00826     return uh;
00827 }
00828 
00836 static /*@null@*/
00837 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
00838         /*@modifies h @*/
00839 {
00840     indexEntry entry, entry2, last;
00841     struct indexEntry_s key;
00842 
00843     if (h == NULL) return NULL;
00844     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
00845 
00846     key.info.tag = tag;
00847 
00848 /*@-boundswrite@*/
00849     entry2 = entry = 
00850         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
00851 /*@=boundswrite@*/
00852     if (entry == NULL)
00853         return NULL;
00854 
00855     if (type == RPM_NULL_TYPE)
00856         return entry;
00857 
00858     /* look backwards */
00859     while (entry->info.tag == tag && entry->info.type != type &&
00860            entry > h->index) entry--;
00861 
00862     if (entry->info.tag == tag && entry->info.type == type)
00863         return entry;
00864 
00865     last = h->index + h->indexUsed;
00866     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
00867     while (entry2->info.tag == tag && entry2->info.type != type &&
00868            entry2 < last) entry2++;
00869     /*@=usereleased@*/
00870 
00871     if (entry->info.tag == tag && entry->info.type == type)
00872         return entry;
00873 
00874     return NULL;
00875 }
00876 
00886 static
00887 int headerRemoveEntry(Header h, int_32 tag)
00888         /*@modifies h @*/
00889 {
00890     indexEntry last = h->index + h->indexUsed;
00891     indexEntry entry, first;
00892     int ne;
00893 
00894     entry = findEntry(h, tag, RPM_NULL_TYPE);
00895     if (!entry) return 1;
00896 
00897     /* Make sure entry points to the first occurence of this tag. */
00898     while (entry > h->index && (entry - 1)->info.tag == tag)  
00899         entry--;
00900 
00901     /* Free data for tags being removed. */
00902     for (first = entry; first < last; first++) {
00903         void * data;
00904         if (first->info.tag != tag)
00905             break;
00906         data = first->data;
00907         first->data = NULL;
00908         first->length = 0;
00909         if (ENTRY_IN_REGION(first))
00910             continue;
00911         data = _free(data);
00912     }
00913 
00914     ne = (first - entry);
00915     if (ne > 0) {
00916         h->indexUsed -= ne;
00917         ne = last - first;
00918 /*@-boundswrite@*/
00919         if (ne > 0)
00920             memmove(entry, first, (ne * sizeof(*entry)));
00921 /*@=boundswrite@*/
00922     }
00923 
00924     return 0;
00925 }
00926 
00932 static /*@null@*/
00933 Header headerLoad(/*@kept@*/ void * uh)
00934         /*@modifies uh @*/
00935 {
00936     int_32 * ei = (int_32 *) uh;
00937     int_32 il = ntohl(ei[0]);           /* index length */
00938     int_32 dl = ntohl(ei[1]);           /* data length */
00939     /*@-sizeoftype@*/
00940     size_t pvlen = sizeof(il) + sizeof(dl) +
00941                (il * sizeof(struct entryInfo_s)) + dl;
00942     /*@=sizeoftype@*/
00943     void * pv = uh;
00944     Header h = NULL;
00945     entryInfo pe;
00946     unsigned char * dataStart;
00947     unsigned char * dataEnd;
00948     indexEntry entry; 
00949     int rdlen;
00950     int i;
00951 
00952     /* Sanity checks on header intro. */
00953     if (hdrchkTags(il) || hdrchkData(dl))
00954         goto errxit;
00955 
00956     ei = (int_32 *) pv;
00957     /*@-castexpose@*/
00958     pe = (entryInfo) &ei[2];
00959     /*@=castexpose@*/
00960     dataStart = (unsigned char *) (pe + il);
00961     dataEnd = dataStart + dl;
00962 
00963     h = xcalloc(1, sizeof(*h));
00964     /*@-assignexpose@*/
00965     h->hv = *hdrVec;            /* structure assignment */
00966     /*@=assignexpose@*/
00967     /*@-assignexpose -kepttrans@*/
00968     h->blob = uh;
00969     /*@=assignexpose =kepttrans@*/
00970     h->indexAlloced = il + 1;
00971     h->indexUsed = il;
00972     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
00973     h->flags |= HEADERFLAG_SORTED;
00974     h->nrefs = 0;
00975     h = headerLink(h);
00976 
00977     /*
00978      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
00979      * %verifyscript tag that needs to be diddled.
00980      */
00981     if (ntohl(pe->tag) == 15 &&
00982         ntohl(pe->type) == RPM_STRING_TYPE &&
00983         ntohl(pe->count) == 1)
00984     {
00985         pe->tag = htonl(1079);
00986     }
00987 
00988     entry = h->index;
00989     i = 0;
00990     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
00991         h->flags |= HEADERFLAG_LEGACY;
00992         entry->info.type = REGION_TAG_TYPE;
00993         entry->info.tag = HEADER_IMAGE;
00994         /*@-sizeoftype@*/
00995         entry->info.count = REGION_TAG_COUNT;
00996         /*@=sizeoftype@*/
00997         entry->info.offset = ((unsigned char *)pe - dataStart); /* negative offset */
00998 
00999         /*@-assignexpose@*/
01000         entry->data = pe;
01001         /*@=assignexpose@*/
01002         entry->length = pvlen - sizeof(il) - sizeof(dl);
01003         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, dataEnd, entry->info.offset);
01004 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
01005         if (rdlen != dl)
01006             goto errxit;
01007 #endif
01008         entry->rdlen = rdlen;
01009         entry++;
01010         h->indexUsed++;
01011     } else {
01012         int_32 rdl;
01013         int_32 ril;
01014 
01015         h->flags &= ~HEADERFLAG_LEGACY;
01016 
01017         entry->info.type = htonl(pe->type);
01018         if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
01019             goto errxit;
01020         entry->info.count = htonl(pe->count);
01021 
01022         if (hdrchkTags(entry->info.count))
01023             goto errxit;
01024 
01025         {   int off = ntohl(pe->offset);
01026 
01027             if (hdrchkData(off))
01028                 goto errxit;
01029             if (off) {
01030                 size_t nb = REGION_TAG_COUNT;
01031                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
01032                 rdl = -ntohl(stei[2]);  /* negative offset */
01033                 ril = rdl/sizeof(*pe);
01034                 if (hdrchkTags(ril) || hdrchkData(rdl))
01035                     goto errxit;
01036                 entry->info.tag = htonl(pe->tag);
01037             } else {
01038                 ril = il;
01039                 /*@-sizeoftype@*/
01040                 rdl = (ril * sizeof(struct entryInfo_s));
01041                 /*@=sizeoftype@*/
01042                 entry->info.tag = HEADER_IMAGE;
01043             }
01044         }
01045         entry->info.offset = -rdl;      /* negative offset */
01046 
01047         /*@-assignexpose@*/
01048         entry->data = pe;
01049         /*@=assignexpose@*/
01050         entry->length = pvlen - sizeof(il) - sizeof(dl);
01051         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, dataEnd, entry->info.offset);
01052         if (rdlen < 0)
01053             goto errxit;
01054         entry->rdlen = rdlen;
01055 
01056         if (ril < h->indexUsed) {
01057             indexEntry newEntry = entry + ril;
01058             int ne = (h->indexUsed - ril);
01059             int rid = entry->info.offset+1;
01060             int rc;
01061 
01062             /* Load dribble entries from region. */
01063             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, dataEnd, rid);
01064             if (rc < 0)
01065                 goto errxit;
01066             rdlen += rc;
01067 
01068           { indexEntry firstEntry = newEntry;
01069             int save = h->indexUsed;
01070             int j;
01071 
01072             /* Dribble entries replace duplicate region entries. */
01073             h->indexUsed -= ne;
01074             for (j = 0; j < ne; j++, newEntry++) {
01075                 (void) headerRemoveEntry(h, newEntry->info.tag);
01076                 if (newEntry->info.tag == HEADER_BASENAMES)
01077                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
01078             }
01079 
01080             /* If any duplicate entries were replaced, move new entries down. */
01081 /*@-boundswrite@*/
01082             if (h->indexUsed < (save - ne)) {
01083                 memmove(h->index + h->indexUsed, firstEntry,
01084                         (ne * sizeof(*entry)));
01085             }
01086 /*@=boundswrite@*/
01087             h->indexUsed += ne;
01088           }
01089         }
01090     }
01091 
01092     h->flags &= ~HEADERFLAG_SORTED;
01093     headerSort(h);
01094 
01095     /*@-globstate -observertrans @*/
01096     return h;
01097     /*@=globstate =observertrans @*/
01098 
01099 errxit:
01100     /*@-usereleased@*/
01101     if (h) {
01102         h->index = _free(h->index);
01103         /*@-refcounttrans@*/
01104         h = _free(h);
01105         /*@=refcounttrans@*/
01106     }
01107     /*@=usereleased@*/
01108     /*@-refcounttrans -globstate@*/
01109     return h;
01110     /*@=refcounttrans =globstate@*/
01111 }
01112 
01120 static /*@null@*/
01121 Header headerReload(/*@only@*/ Header h, int tag)
01122         /*@modifies h @*/
01123 {
01124     Header nh;
01125     int length;
01126     /*@-onlytrans@*/
01127 /*@-boundswrite@*/
01128     void * uh = doHeaderUnload(h, &length);
01129 /*@=boundswrite@*/
01130 
01131     h = headerFree(h);
01132     /*@=onlytrans@*/
01133     if (uh == NULL)
01134         return NULL;
01135     nh = headerLoad(uh);
01136     if (nh == NULL) {
01137         uh = _free(uh);
01138         return NULL;
01139     }
01140     if (nh->flags & HEADERFLAG_ALLOCATED)
01141         uh = _free(uh);
01142     nh->flags |= HEADERFLAG_ALLOCATED;
01143     if (ENTRY_IS_REGION(nh->index)) {
01144 /*@-boundswrite@*/
01145         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
01146             nh->index[0].info.tag = tag;
01147 /*@=boundswrite@*/
01148     }
01149     return nh;
01150 }
01151 
01157 static /*@null@*/
01158 Header headerCopyLoad(const void * uh)
01159         /*@*/
01160 {
01161     int_32 * ei = (int_32 *) uh;
01162 /*@-boundsread@*/
01163     int_32 il = ntohl(ei[0]);           /* index length */
01164     int_32 dl = ntohl(ei[1]);           /* data length */
01165 /*@=boundsread@*/
01166     /*@-sizeoftype@*/
01167     size_t pvlen = sizeof(il) + sizeof(dl) +
01168                         (il * sizeof(struct entryInfo_s)) + dl;
01169     /*@=sizeoftype@*/
01170     void * nuh = NULL;
01171     Header h = NULL;
01172 
01173     /* Sanity checks on header intro. */
01174     /*@-branchstate@*/
01175     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
01176 /*@-boundsread@*/
01177         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
01178 /*@=boundsread@*/
01179         if ((h = headerLoad(nuh)) != NULL)
01180             h->flags |= HEADERFLAG_ALLOCATED;
01181     }
01182     /*@=branchstate@*/
01183     /*@-branchstate@*/
01184     if (h == NULL)
01185         nuh = _free(nuh);
01186     /*@=branchstate@*/
01187     return h;
01188 }
01189 
01196 static /*@null@*/
01197 Header headerRead(FD_t fd, enum hMagic magicp)
01198         /*@modifies fd @*/
01199 {
01200     int_32 block[4];
01201     int_32 reserved;
01202     int_32 * ei = NULL;
01203     int_32 il;
01204     int_32 dl;
01205     int_32 magic;
01206     Header h = NULL;
01207     size_t len;
01208     int i;
01209 
01210     memset(block, 0, sizeof(block));
01211     i = 2;
01212     if (magicp == HEADER_MAGIC_YES)
01213         i += 2;
01214 
01215     /*@-type@*/ /* FIX: cast? */
01216     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
01217         goto exit;
01218     /*@=type@*/
01219 
01220     i = 0;
01221 
01222 /*@-boundsread@*/
01223     if (magicp == HEADER_MAGIC_YES) {
01224         magic = block[i++];
01225         if (memcmp(&magic, header_magic, sizeof(magic)))
01226             goto exit;
01227         reserved = block[i++];
01228     }
01229     
01230     il = ntohl(block[i]);       i++;
01231     dl = ntohl(block[i]);       i++;
01232 /*@=boundsread@*/
01233 
01234     /*@-sizeoftype@*/
01235     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo_s)) + dl;
01236     /*@=sizeoftype@*/
01237 
01238     /* Sanity checks on header intro. */
01239     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
01240         goto exit;
01241 
01242 /*@-boundswrite@*/
01243     ei = xmalloc(len);
01244     ei[0] = htonl(il);
01245     ei[1] = htonl(dl);
01246     len -= sizeof(il) + sizeof(dl);
01247 /*@=boundswrite@*/
01248 
01249 /*@-boundsread@*/
01250     /*@-type@*/ /* FIX: cast? */
01251     if (timedRead(fd, (char *)&ei[2], len) != len)
01252         goto exit;
01253     /*@=type@*/
01254 /*@=boundsread@*/
01255     
01256     h = headerLoad(ei);
01257 
01258 exit:
01259     if (h) {
01260         if (h->flags & HEADERFLAG_ALLOCATED)
01261             ei = _free(ei);
01262         h->flags |= HEADERFLAG_ALLOCATED;
01263     } else if (ei)
01264         ei = _free(ei);
01265     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
01266     return h;
01267     /*@-mustmod@*/
01268 }
01269 
01277 static
01278 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
01279         /*@globals fileSystem @*/
01280         /*@modifies fd, h, fileSystem @*/
01281 {
01282     ssize_t nb;
01283     int length;
01284     const void * uh;
01285 
01286     if (h == NULL)
01287         return 1;
01288 /*@-boundswrite@*/
01289     uh = doHeaderUnload(h, &length);
01290 /*@=boundswrite@*/
01291     if (uh == NULL)
01292         return 1;
01293     switch (magicp) {
01294     case HEADER_MAGIC_YES:
01295 /*@-boundsread@*/
01296         /*@-sizeoftype@*/
01297         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
01298         /*@=sizeoftype@*/
01299 /*@=boundsread@*/
01300         if (nb != sizeof(header_magic))
01301             goto exit;
01302         break;
01303     case HEADER_MAGIC_NO:
01304         break;
01305     }
01306 
01307     /*@-sizeoftype@*/
01308     nb = Fwrite(uh, sizeof(char), length, fd);
01309     /*@=sizeoftype@*/
01310 
01311 exit:
01312     uh = _free(uh);
01313     return (nb == length ? 0 : 1);
01314 }
01315 
01322 static
01323 int headerIsEntry(/*@null@*/Header h, int_32 tag)
01324         /*@*/
01325 {
01326     /*@-mods@*/         /*@ FIX: h modified by sort. */
01327     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
01328     /*@=mods@*/ 
01329 }
01330 
01341 static int copyEntry(const indexEntry entry,
01342                 /*@null@*/ /*@out@*/ hTYP_t type,
01343                 /*@null@*/ /*@out@*/ hPTR_t * p,
01344                 /*@null@*/ /*@out@*/ hCNT_t c,
01345                 int minMem)
01346         /*@modifies *type, *p, *c @*/
01347         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01348 {
01349     int_32 count = entry->info.count;
01350     int rc = 1;         /* XXX 1 on success. */
01351 
01352     if (p)
01353     switch (entry->info.type) {
01354     case RPM_BIN_TYPE:
01355         /*
01356          * XXX This only works for
01357          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
01358          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
01359          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
01360          */
01361         if (ENTRY_IS_REGION(entry)) {
01362             int_32 * ei = ((int_32 *)entry->data) - 2;
01363             /*@-castexpose@*/
01364             entryInfo pe = (entryInfo) (ei + 2);
01365             /*@=castexpose@*/
01366 /*@-boundsread@*/
01367             char * dataStart = (char *) (pe + ntohl(ei[0]));
01368 /*@=boundsread@*/
01369             int_32 rdl = -entry->info.offset;   /* negative offset */
01370             int_32 ril = rdl/sizeof(*pe);
01371 
01372             /*@-sizeoftype@*/
01373             rdl = entry->rdlen;
01374             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
01375             if (entry->info.tag == HEADER_IMAGE) {
01376                 ril -= 1;
01377                 pe += 1;
01378             } else {
01379                 count += REGION_TAG_COUNT;
01380                 rdl += REGION_TAG_COUNT;
01381             }
01382 
01383 /*@-bounds@*/
01384             *p = xmalloc(count);
01385             ei = (int_32 *) *p;
01386             ei[0] = htonl(ril);
01387             ei[1] = htonl(rdl);
01388 
01389             /*@-castexpose@*/
01390             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
01391             /*@=castexpose@*/
01392 
01393             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
01394             /*@=sizeoftype@*/
01395 /*@=bounds@*/
01396 
01397             rc = regionSwab(NULL, ril, 0, pe, dataStart, NULL, 0);
01398             /* XXX 1 on success. */
01399             rc = (rc < 0) ? 0 : 1;
01400         } else {
01401             count = entry->length;
01402             *p = (!minMem
01403                 ? memcpy(xmalloc(count), entry->data, count)
01404                 : entry->data);
01405         }
01406         break;
01407     case RPM_STRING_TYPE:
01408         if (count == 1) {
01409             *p = entry->data;
01410             break;
01411         }
01412         /*@fallthrough@*/
01413     case RPM_STRING_ARRAY_TYPE:
01414     case RPM_I18NSTRING_TYPE:
01415     {   const char ** ptrEntry;
01416         /*@-sizeoftype@*/
01417         int tableSize = count * sizeof(char *);
01418         /*@=sizeoftype@*/
01419         char * t;
01420         int i;
01421 
01422 /*@-bounds@*/
01423         /*@-mods@*/
01424         if (minMem) {
01425             *p = xmalloc(tableSize);
01426             ptrEntry = (const char **) *p;
01427             t = entry->data;
01428         } else {
01429             t = xmalloc(tableSize + entry->length);
01430             *p = (void *)t;
01431             ptrEntry = (const char **) *p;
01432             t += tableSize;
01433             memcpy(t, entry->data, entry->length);
01434         }
01435         /*@=mods@*/
01436 /*@=bounds@*/
01437         for (i = 0; i < count; i++) {
01438 /*@-boundswrite@*/
01439             *ptrEntry++ = t;
01440 /*@=boundswrite@*/
01441             t = strchr(t, 0);
01442             t++;
01443         }
01444     }   break;
01445 
01446     default:
01447         *p = entry->data;
01448         break;
01449     }
01450     if (type) *type = entry->info.type;
01451     if (c) *c = count;
01452     return rc;
01453 }
01454 
01473 static int headerMatchLocale(const char *td, const char *l, const char *le)
01474         /*@*/
01475 {
01476     const char *fe;
01477 
01478 
01479 #if 0
01480   { const char *s, *ll, *CC, *EE, *dd;
01481     char *lbuf, *t.
01482 
01483     /* Copy the buffer and parse out components on the fly. */
01484     lbuf = alloca(le - l + 1);
01485     for (s = l, ll = t = lbuf; *s; s++, t++) {
01486         switch (*s) {
01487         case '_':
01488             *t = '\0';
01489             CC = t + 1;
01490             break;
01491         case '.':
01492             *t = '\0';
01493             EE = t + 1;
01494             break;
01495         case '@':
01496             *t = '\0';
01497             dd = t + 1;
01498             break;
01499         default:
01500             *t = *s;
01501             break;
01502         }
01503     }
01504 
01505     if (ll)     /* ISO language should be lower case */
01506         for (t = ll; *t; t++)   *t = tolower(*t);
01507     if (CC)     /* ISO country code should be upper case */
01508         for (t = CC; *t; t++)   *t = toupper(*t);
01509 
01510     /* There are a total of 16 cases to attempt to match. */
01511   }
01512 #endif
01513 
01514     /* First try a complete match. */
01515     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
01516         return 1;
01517 
01518     /* Next, try stripping optional dialect and matching.  */
01519     for (fe = l; fe < le && *fe != '@'; fe++)
01520         {};
01521     if (fe < le && !strncmp(td, l, (fe - l)))
01522         return 1;
01523 
01524     /* Next, try stripping optional codeset and matching.  */
01525     for (fe = l; fe < le && *fe != '.'; fe++)
01526         {};
01527     if (fe < le && !strncmp(td, l, (fe - l)))
01528         return 1;
01529 
01530     /* Finally, try stripping optional country code and matching. */
01531     for (fe = l; fe < le && *fe != '_'; fe++)
01532         {};
01533     if (fe < le && !strncmp(td, l, (fe - l)))
01534         return 1;
01535 
01536     return 0;
01537 }
01538 
01545 /*@dependent@*/ /*@exposed@*/ static char *
01546 headerFindI18NString(Header h, indexEntry entry)
01547         /*@*/
01548 {
01549     const char *lang, *l, *le;
01550     indexEntry table;
01551 
01552     /* XXX Drepper sez' this is the order. */
01553     if ((lang = getenv("LANGUAGE")) == NULL &&
01554         (lang = getenv("LC_ALL")) == NULL &&
01555         (lang = getenv("LC_MESSAGES")) == NULL &&
01556         (lang = getenv("LANG")) == NULL)
01557             return entry->data;
01558     
01559     /*@-mods@*/
01560     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
01561         return entry->data;
01562     /*@=mods@*/
01563 
01564 /*@-boundsread@*/
01565     for (l = lang; *l != '\0'; l = le) {
01566         const char *td;
01567         char *ed;
01568         int langNum;
01569 
01570         while (*l && *l == ':')                 /* skip leading colons */
01571             l++;
01572         if (*l == '\0')
01573             break;
01574         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
01575             {};
01576 
01577         /* For each entry in the header ... */
01578         for (langNum = 0, td = table->data, ed = entry->data;
01579              langNum < entry->info.count;
01580              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
01581 
01582                 if (headerMatchLocale(td, l, le))
01583                     return ed;
01584 
01585         }
01586     }
01587 /*@=boundsread@*/
01588 
01589     return entry->data;
01590 }
01591 
01602 static int intGetEntry(Header h, int_32 tag,
01603                 /*@null@*/ /*@out@*/ hTAG_t type,
01604                 /*@null@*/ /*@out@*/ hPTR_t * p,
01605                 /*@null@*/ /*@out@*/ hCNT_t c,
01606                 int minMem)
01607         /*@modifies *type, *p, *c @*/
01608         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01609 {
01610     indexEntry entry;
01611     int rc;
01612 
01613     /* First find the tag */
01614     /*@-mods@*/         /*@ FIX: h modified by sort. */
01615     entry = findEntry(h, tag, RPM_NULL_TYPE);
01616     /*@mods@*/
01617     if (entry == NULL) {
01618         if (type) type = 0;
01619         if (p) *p = NULL;
01620         if (c) *c = 0;
01621         return 0;
01622     }
01623 
01624     switch (entry->info.type) {
01625     case RPM_I18NSTRING_TYPE:
01626         rc = 1;
01627         if (type) *type = RPM_STRING_TYPE;
01628         if (c) *c = 1;
01629         /*@-dependenttrans@*/
01630         if (p) *p = headerFindI18NString(h, entry);
01631         /*@=dependenttrans@*/
01632         break;
01633     default:
01634         rc = copyEntry(entry, type, p, c, minMem);
01635         break;
01636     }
01637 
01638     /* XXX 1 on success */
01639     return ((rc == 1) ? 1 : 0);
01640 }
01641 
01649 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
01650                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
01651         /*@modifies data @*/
01652 {
01653     if (data) {
01654         /*@-branchstate@*/
01655         if (type == -1 ||
01656             type == RPM_STRING_ARRAY_TYPE ||
01657             type == RPM_I18NSTRING_TYPE ||
01658             type == RPM_BIN_TYPE)
01659                 data = _free(data);
01660         /*@=branchstate@*/
01661     }
01662     return NULL;
01663 }
01664 
01678 static
01679 int headerGetEntry(Header h, int_32 tag,
01680                         /*@null@*/ /*@out@*/ hTYP_t type,
01681                         /*@null@*/ /*@out@*/ void ** p,
01682                         /*@null@*/ /*@out@*/ hCNT_t c)
01683         /*@modifies *type, *p, *c @*/
01684         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01685 {
01686     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
01687 }
01688 
01701 static
01702 int headerGetEntryMinMemory(Header h, int_32 tag,
01703                         /*@null@*/ /*@out@*/ hTYP_t type,
01704                         /*@null@*/ /*@out@*/ hPTR_t * p,
01705                         /*@null@*/ /*@out@*/ hCNT_t c)
01706         /*@modifies *type, *p, *c @*/
01707         /*@requires maxSet(type) >= 0 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
01708 {
01709     return intGetEntry(h, tag, type, p, c, 1);
01710 }
01711 
01712 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
01713                 int_32 * c)
01714 {
01715     indexEntry entry;
01716     int rc;
01717 
01718     if (p == NULL) return headerIsEntry(h, tag);
01719 
01720     /* First find the tag */
01721     /*@-mods@*/         /*@ FIX: h modified by sort. */
01722     entry = findEntry(h, tag, RPM_NULL_TYPE);
01723     /*@=mods@*/
01724     if (!entry) {
01725         if (p) *p = NULL;
01726         if (c) *c = 0;
01727         return 0;
01728     }
01729 
01730     rc = copyEntry(entry, type, p, c, 0);
01731 
01732     /* XXX 1 on success */
01733     return ((rc == 1) ? 1 : 0);
01734 }
01735 
01738 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
01739                 int_32 cnt, int dataLength)
01740         /*@modifies *dstPtr @*/
01741 {
01742     switch (type) {
01743     case RPM_STRING_ARRAY_TYPE:
01744     case RPM_I18NSTRING_TYPE:
01745     {   const char ** av = (const char **) srcPtr;
01746         char * t = dstPtr;
01747 
01748 /*@-bounds@*/
01749         while (cnt-- > 0 && dataLength > 0) {
01750             const char * s;
01751             if ((s = *av++) == NULL)
01752                 continue;
01753             do {
01754                 *t++ = *s++;
01755             } while (s[-1] && --dataLength > 0);
01756         }
01757 /*@=bounds@*/
01758     }   break;
01759 
01760     default:
01761 /*@-boundswrite@*/
01762         memmove(dstPtr, srcPtr, dataLength);
01763 /*@=boundswrite@*/
01764         break;
01765     }
01766 }
01767 
01776 /*@null@*/
01777 static void *
01778 grabData(int_32 type, hPTR_t p, int_32 c, /*@out@*/ int * lengthPtr)
01779         /*@modifies *lengthPtr @*/
01780         /*@requires maxSet(lengthPtr) >= 0 @*/
01781 {
01782     void * data = NULL;
01783     int length;
01784 
01785     length = dataLength(type, p, c, 0, NULL);
01786     if (length > 0) {
01787         data = xmalloc(length);
01788         copyData(type, data, p, c, length);
01789     }
01790 
01791     if (lengthPtr)
01792         *lengthPtr = length;
01793     return data;
01794 }
01795 
01810 static
01811 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
01812         /*@modifies h @*/
01813 {
01814     indexEntry entry;
01815     void * data;
01816     int length;
01817 
01818     /* Count must always be >= 1 for headerAddEntry. */
01819     if (c <= 0)
01820         return 0;
01821 
01822     length = 0;
01823 /*@-boundswrite@*/
01824     data = grabData(type, p, c, &length);
01825 /*@=boundswrite@*/
01826     if (data == NULL || length <= 0)
01827         return 0;
01828 
01829     /* Allocate more index space if necessary */
01830     if (h->indexUsed == h->indexAlloced) {
01831         h->indexAlloced += INDEX_MALLOC_SIZE;
01832         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
01833     }
01834 
01835     /* Fill in the index */
01836     entry = h->index + h->indexUsed;
01837     entry->info.tag = tag;
01838     entry->info.type = type;
01839     entry->info.count = c;
01840     entry->info.offset = 0;
01841     entry->data = data;
01842     entry->length = length;
01843 
01844 /*@-boundsread@*/
01845     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
01846         h->flags &= ~HEADERFLAG_SORTED;
01847 /*@=boundsread@*/
01848     h->indexUsed++;
01849 
01850     return 1;
01851 }
01852 
01867 static
01868 int headerAppendEntry(Header h, int_32 tag, int_32 type,
01869                 const void * p, int_32 c)
01870         /*@modifies h @*/
01871 {
01872     indexEntry entry;
01873     int length;
01874 
01875     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
01876         /* we can't do this */
01877         return 0;
01878     }
01879 
01880     /* Find the tag entry in the header. */
01881     entry = findEntry(h, tag, type);
01882     if (!entry)
01883         return 0;
01884 
01885     length = dataLength(type, p, c, 0, NULL);
01886     if (length < 0)
01887         return 0;
01888 
01889     if (ENTRY_IN_REGION(entry)) {
01890         char * t = xmalloc(entry->length + length);
01891 /*@-bounds@*/
01892         memcpy(t, entry->data, entry->length);
01893 /*@=bounds@*/
01894         entry->data = t;
01895         entry->info.offset = 0;
01896     } else
01897         entry->data = xrealloc(entry->data, entry->length + length);
01898 
01899     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
01900 
01901     entry->length += length;
01902 
01903     entry->info.count += c;
01904 
01905     return 1;
01906 }
01907 
01918 static
01919 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
01920                 const void * p, int_32 c)
01921         /*@modifies h @*/
01922 {
01923     return (findEntry(h, tag, type)
01924         ? headerAppendEntry(h, tag, type, p, c)
01925         : headerAddEntry(h, tag, type, p, c));
01926 }
01927 
01948 static
01949 int headerAddI18NString(Header h, int_32 tag, const char * string,
01950                 const char * lang)
01951         /*@modifies h @*/
01952 {
01953     indexEntry table, entry;
01954     const char ** strArray;
01955     int length;
01956     int ghosts;
01957     int i, langNum;
01958     char * buf;
01959 
01960     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01961     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
01962 
01963     if (!table && entry)
01964         return 0;               /* this shouldn't ever happen!! */
01965 
01966     if (!table && !entry) {
01967         const char * charArray[2];
01968         int count = 0;
01969         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
01970             /*@-observertrans -readonlytrans@*/
01971             charArray[count++] = "C";
01972             /*@=observertrans =readonlytrans@*/
01973         } else {
01974             /*@-observertrans -readonlytrans@*/
01975             charArray[count++] = "C";
01976             /*@=observertrans =readonlytrans@*/
01977             charArray[count++] = lang;
01978         }
01979         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE, 
01980                         &charArray, count))
01981             return 0;
01982         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
01983     }
01984 
01985     if (!table)
01986         return 0;
01987     /*@-branchstate@*/
01988     if (!lang) lang = "C";
01989     /*@=branchstate@*/
01990 
01991     {   const char * l = table->data;
01992         for (langNum = 0; langNum < table->info.count; langNum++) {
01993             if (!strcmp(l, lang)) break;
01994             l += strlen(l) + 1;
01995         }
01996     }
01997 
01998     if (langNum >= table->info.count) {
01999         length = strlen(lang) + 1;
02000         if (ENTRY_IN_REGION(table)) {
02001             char * t = xmalloc(table->length + length);
02002             memcpy(t, table->data, table->length);
02003             table->data = t;
02004             table->info.offset = 0;
02005         } else
02006             table->data = xrealloc(table->data, table->length + length);
02007         memmove(((char *)table->data) + table->length, lang, length);
02008         table->length += length;
02009         table->info.count++;
02010     }
02011 
02012     if (!entry) {
02013         strArray = alloca(sizeof(*strArray) * (langNum + 1));
02014         for (i = 0; i < langNum; i++)
02015             strArray[i] = "";
02016         strArray[langNum] = string;
02017         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray, 
02018                                 langNum + 1);
02019     } else if (langNum >= entry->info.count) {
02020         ghosts = langNum - entry->info.count;
02021         
02022         length = strlen(string) + 1 + ghosts;
02023         if (ENTRY_IN_REGION(entry)) {
02024             char * t = xmalloc(entry->length + length);
02025             memcpy(t, entry->data, entry->length);
02026             entry->data = t;
02027             entry->info.offset = 0;
02028         } else
02029             entry->data = xrealloc(entry->data, entry->length + length);
02030 
02031         memset(((char *)entry->data) + entry->length, '\0', ghosts);
02032         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
02033 
02034         entry->length += length;
02035         entry->info.count = langNum + 1;
02036     } else {
02037         char *b, *be, *e, *ee, *t;
02038         size_t bn, sn, en;
02039 
02040         /* Set beginning/end pointers to previous data */
02041         b = be = e = ee = entry->data;
02042         for (i = 0; i < table->info.count; i++) {
02043             if (i == langNum)
02044                 be = ee;
02045             ee += strlen(ee) + 1;
02046             if (i == langNum)
02047                 e  = ee;
02048         }
02049 
02050         /* Get storage for new buffer */
02051         bn = (be-b);
02052         sn = strlen(string) + 1;
02053         en = (ee-e);
02054         length = bn + sn + en;
02055         t = buf = xmalloc(length);
02056 
02057         /* Copy values into new storage */
02058         memcpy(t, b, bn);
02059         t += bn;
02060 /*@-mayaliasunique@*/
02061         memcpy(t, string, sn);
02062         t += sn;
02063         memcpy(t, e, en);
02064         t += en;
02065 /*@=mayaliasunique@*/
02066 
02067         /* Replace i18N string array */
02068         entry->length -= strlen(be) + 1;
02069         entry->length += sn;
02070         
02071         if (ENTRY_IN_REGION(entry)) {
02072             entry->info.offset = 0;
02073         } else
02074             entry->data = _free(entry->data);
02075         /*@-dependenttrans@*/
02076         entry->data = buf;
02077         /*@=dependenttrans@*/
02078     }
02079 
02080     return 0;
02081 }
02082 
02093 static
02094 int headerModifyEntry(Header h, int_32 tag, int_32 type,
02095                         const void * p, int_32 c)
02096         /*@modifies h @*/
02097 {
02098     indexEntry entry;
02099     void * oldData;
02100     void * data;
02101     int length;
02102 
02103     /* First find the tag */
02104     entry = findEntry(h, tag, type);
02105     if (!entry)
02106         return 0;
02107 
02108     length = 0;
02109     data = grabData(type, p, c, &length);
02110     if (data == NULL || length <= 0)
02111         return 0;
02112 
02113     /* make sure entry points to the first occurence of this tag */
02114     while (entry > h->index && (entry - 1)->info.tag == tag)  
02115         entry--;
02116 
02117     /* free after we've grabbed the new data in case the two are intertwined;
02118        that's a bad idea but at least we won't break */
02119     oldData = entry->data;
02120 
02121     entry->info.count = c;
02122     entry->info.type = type;
02123     entry->data = data;
02124     entry->length = length;
02125 
02126     /*@-branchstate@*/
02127     if (ENTRY_IN_REGION(entry)) {
02128         entry->info.offset = 0;
02129     } else
02130         oldData = _free(oldData);
02131     /*@=branchstate@*/
02132 
02133     return 1;
02134 }
02135 
02138 static char escapedChar(const char ch)  /*@*/
02139 {
02140     switch (ch) {
02141     case 'a':   return '\a';
02142     case 'b':   return '\b';
02143     case 'f':   return '\f';
02144     case 'n':   return '\n';
02145     case 'r':   return '\r';
02146     case 't':   return '\t';
02147     case 'v':   return '\v';
02148     default:    return ch;
02149     }
02150 }
02151 
02158 static /*@null@*/ sprintfToken
02159 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
02160         /*@modifies *format @*/
02161 {
02162     int i;
02163 
02164     if (format == NULL) return NULL;
02165     for (i = 0; i < num; i++) {
02166         switch (format[i].type) {
02167         case PTOK_ARRAY:
02168 /*@-boundswrite@*/
02169             format[i].u.array.format =
02170                 freeFormat(format[i].u.array.format,
02171                         format[i].u.array.numTokens);
02172 /*@=boundswrite@*/
02173             /*@switchbreak@*/ break;
02174         case PTOK_COND:
02175 /*@-boundswrite@*/
02176             format[i].u.cond.ifFormat =
02177                 freeFormat(format[i].u.cond.ifFormat, 
02178                         format[i].u.cond.numIfTokens);
02179             format[i].u.cond.elseFormat =
02180                 freeFormat(format[i].u.cond.elseFormat, 
02181                         format[i].u.cond.numElseTokens);
02182 /*@=boundswrite@*/
02183             /*@switchbreak@*/ break;
02184         case PTOK_NONE:
02185         case PTOK_TAG:
02186         case PTOK_STRING:
02187         default:
02188             /*@switchbreak@*/ break;
02189         }
02190     }
02191     format = _free(format);
02192     return NULL;
02193 }
02194 
02197 static void findTag(char * name, const headerTagTableEntry tags, 
02198                     const headerSprintfExtension extensions,
02199                     /*@out@*/ headerTagTableEntry * tagMatch,
02200                     /*@out@*/ headerSprintfExtension * extMatch)
02201         /*@modifies *tagMatch, *extMatch @*/
02202         /*@requires maxSet(tagMatch) >= 0 /\ maxSet(extMatch) >= 0 @*/
02203 {
02204     headerTagTableEntry entry;
02205     headerSprintfExtension ext;
02206     const char * tagname;
02207 
02208     *tagMatch = NULL;
02209     *extMatch = NULL;
02210 
02211     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
02212 /*@-boundswrite@*/
02213         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
02214         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
02215         tagname = t;
02216 /*@=boundswrite@*/
02217     } else {
02218         tagname = name;
02219     }
02220 
02221     /* Search extensions first to permit overriding header tags. */
02222     ext = extensions;
02223     while (ext->type != HEADER_EXT_LAST) {
02224         if (ext->name != NULL && ext->type == HEADER_EXT_TAG
02225         && !xstrcasecmp(ext->name, tagname))
02226             break;
02227 
02228         if (ext->type == HEADER_EXT_MORE)
02229             ext = ext->u.more;
02230         else
02231             ext++;
02232     }
02233 
02234     if (ext->type == HEADER_EXT_TAG) {
02235         *extMatch = ext;
02236         return;
02237     }
02238 
02239     /* Search header tags. */
02240     for (entry = tags; entry->name; entry++)
02241         if (entry->name && !xstrcasecmp(entry->name, tagname))
02242             break;
02243 
02244     if (entry->name) {
02245         *tagMatch = entry;
02246         return;
02247     }
02248 }
02249 
02250 /* forward ref */
02251 static int parseExpression(sprintfToken token, char * str, 
02252                 const headerTagTableEntry tags, 
02253                 const headerSprintfExtension extensions,
02254                 /*@out@*/char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
02255         /*@modifies str, *str, *token, *endPtr, *errmsg @*/
02256         /*@requires maxSet(endPtr) >= 0 /\ maxSet(errmsg) >= 0 @*/;
02257 
02260 /*@-boundswrite@*/
02261 static int parseFormat(/*@null@*/ char * str, const headerTagTableEntry tags,
02262                 const headerSprintfExtension extensions,
02263                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
02264                 /*@null@*/ /*@out@*/ char ** endPtr, int state,
02265                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
02266         /*@modifies str, *str, *formatPtr, *numTokensPtr, *endPtr, *errmsg @*/
02267         /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
02268                 /\ maxSet(endPtr) >= 0 /\ maxSet(errmsg) >= 0 @*/
02269 {
02270     char * chptr, * start, * next, * dst;
02271     sprintfToken format;
02272     int numTokens;
02273     int currToken;
02274     headerTagTableEntry tag;
02275     headerSprintfExtension ext;
02276     int i;
02277     int done = 0;
02278 
02279     /* upper limit on number of individual formats */
02280     numTokens = 0;
02281     if (str != NULL)
02282     for (chptr = str; *chptr != '\0'; chptr++)
02283         if (*chptr == '%') numTokens++;
02284     numTokens = numTokens * 2 + 1;
02285 
02286     format = xcalloc(numTokens, sizeof(*format));
02287     if (endPtr) *endPtr = NULL;
02288 
02289     /*@-infloops@*/ /* LCL: can't detect done termination */
02290     dst = start = str;
02291     currToken = -1;
02292     if (start != NULL)
02293     while (*start != '\0') {
02294         switch (*start) {
02295         case '%':
02296             /* handle %% */
02297             if (*(start + 1) == '%') {
02298                 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02299                     currToken++;
02300                     format[currToken].type = PTOK_STRING;
02301                     /*@-temptrans -assignexpose@*/
02302                     dst = format[currToken].u.string.string = start;
02303                     /*@=temptrans =assignexpose@*/
02304                 }
02305 
02306                 start++;
02307 
02308                 *dst++ = *start++;
02309 
02310                 /*@switchbreak@*/ break;
02311             } 
02312 
02313             currToken++;
02314             *dst++ = '\0';
02315             start++;
02316 
02317             if (*start == '|') {
02318                 char * newEnd;
02319 
02320                 start++;
02321                 if (parseExpression(format + currToken, start, tags, 
02322                                     extensions, &newEnd, errmsg))
02323                 {
02324                     format = freeFormat(format, numTokens);
02325                     return 1;
02326                 }
02327                 start = newEnd;
02328                 /*@switchbreak@*/ break;
02329             }
02330 
02331             /*@-assignexpose@*/
02332             format[currToken].u.tag.format = start;
02333             /*@=assignexpose@*/
02334             format[currToken].u.tag.pad = 0;
02335             format[currToken].u.tag.justOne = 0;
02336             format[currToken].u.tag.arrayCount = 0;
02337 
02338             chptr = start;
02339             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
02340             if (!*chptr || *chptr == '%') {
02341                 /*@-observertrans -readonlytrans@*/
02342                 if (errmsg) *errmsg = _("missing { after %");
02343                 /*@=observertrans =readonlytrans@*/
02344                 format = freeFormat(format, numTokens);
02345                 return 1;
02346             }
02347 
02348             *chptr++ = '\0';
02349 
02350             while (start < chptr) {
02351                 if (xisdigit(*start)) {
02352                     i = strtoul(start, &start, 10);
02353                     format[currToken].u.tag.pad += i;
02354                 } else {
02355                     start++;
02356                 }
02357             }
02358 
02359             if (*start == '=') {
02360                 format[currToken].u.tag.justOne = 1;
02361                 start++;
02362             } else if (*start == '#') {
02363                 format[currToken].u.tag.justOne = 1;
02364                 format[currToken].u.tag.arrayCount = 1;
02365                 start++;
02366             }
02367 
02368             next = start;
02369             while (*next && *next != '}') next++;
02370             if (!*next) {
02371                 /*@-observertrans -readonlytrans@*/
02372                 if (errmsg) *errmsg = _("missing } after %{");
02373                 /*@=observertrans =readonlytrans@*/
02374                 format = freeFormat(format, numTokens);
02375                 return 1;
02376             }
02377             *next++ = '\0';
02378 
02379             chptr = start;
02380             while (*chptr && *chptr != ':') chptr++;
02381 
02382             if (*chptr != '\0') {
02383                 *chptr++ = '\0';
02384                 if (!*chptr) {
02385                     /*@-observertrans -readonlytrans@*/
02386                     if (errmsg) *errmsg = _("empty tag format");
02387                     /*@=observertrans =readonlytrans@*/
02388                     format = freeFormat(format, numTokens);
02389                     return 1;
02390                 }
02391                 /*@-assignexpose@*/
02392                 format[currToken].u.tag.type = chptr;
02393                 /*@=assignexpose@*/
02394             } else {
02395                 format[currToken].u.tag.type = NULL;
02396             }
02397             
02398             if (!*start) {
02399                 /*@-observertrans -readonlytrans@*/
02400                 if (errmsg) *errmsg = _("empty tag name");
02401                 /*@=observertrans =readonlytrans@*/
02402                 format = freeFormat(format, numTokens);
02403                 return 1;
02404             }
02405 
02406             i = 0;
02407             findTag(start, tags, extensions, &tag, &ext);
02408 
02409             if (tag) {
02410                 format[currToken].u.tag.ext = NULL;
02411                 format[currToken].u.tag.tag = tag->val;
02412             } else if (ext) {
02413                 format[currToken].u.tag.ext = ext->u.tagFunction;
02414                 format[currToken].u.tag.extNum = ext - extensions;
02415             } else {
02416                 /*@-observertrans -readonlytrans@*/
02417                 if (errmsg) *errmsg = _("unknown tag");
02418                 /*@=observertrans =readonlytrans@*/
02419                 format = freeFormat(format, numTokens);
02420                 return 1;
02421             }
02422 
02423             format[currToken].type = PTOK_TAG;
02424 
02425             start = next;
02426 
02427             /*@switchbreak@*/ break;
02428 
02429         case '[':
02430             *dst++ = '\0';
02431             *start++ = '\0';
02432             currToken++;
02433 
02434             if (parseFormat(start, tags, extensions, 
02435                             &format[currToken].u.array.format,
02436                             &format[currToken].u.array.numTokens,
02437                             &start, PARSER_IN_ARRAY, errmsg)) {
02438                 format = freeFormat(format, numTokens);
02439                 return 1;
02440             }
02441 
02442             if (!start) {
02443                 /*@-observertrans -readonlytrans@*/
02444                 if (errmsg) *errmsg = _("] expected at end of array");
02445                 /*@=observertrans =readonlytrans@*/
02446                 format = freeFormat(format, numTokens);
02447                 return 1;
02448             }
02449 
02450             dst = start;
02451 
02452             format[currToken].type = PTOK_ARRAY;
02453 
02454             /*@switchbreak@*/ break;
02455 
02456         case ']':
02457         case '}':
02458             if ((*start == ']' && state != PARSER_IN_ARRAY) ||
02459                 (*start == '}' && state != PARSER_IN_EXPR)) {
02460                 if (*start == ']') {
02461                     /*@-observertrans -readonlytrans@*/
02462                     if (errmsg) *errmsg = _("unexpected ]");
02463                     /*@=observertrans =readonlytrans@*/
02464                 } else {
02465                     /*@-observertrans -readonlytrans@*/
02466                     if (errmsg) *errmsg = _("unexpected }");
02467                     /*@=observertrans =readonlytrans@*/
02468                 }
02469                 format = freeFormat(format, numTokens);
02470                 return 1;
02471             }
02472             *start++ = '\0';
02473             if (endPtr) *endPtr = start;
02474             done = 1;
02475             /*@switchbreak@*/ break;
02476 
02477         default:
02478             if (currToken < 0 || format[currToken].type != PTOK_STRING) {
02479                 currToken++;
02480                 format[currToken].type = PTOK_STRING;
02481                 /*@-temptrans -assignexpose@*/
02482                 dst = format[currToken].u.string.string = start;
02483                 /*@=temptrans =assignexpose@*/
02484             }
02485 
02486             if (*start == '\\') {
02487                 start++;
02488                 *dst++ = escapedChar(*start++);
02489             } else {
02490                 *dst++ = *start++;
02491             }
02492             /*@switchbreak@*/ break;
02493         }
02494         if (done)
02495             break;
02496     }
02497     /*@=infloops@*/
02498 
02499     if (dst != NULL)
02500         *dst = '\0';
02501 
02502     currToken++;
02503     for (i = 0; i < currToken; i++) {
02504         if (format[i].type == PTOK_STRING)
02505             format[i].u.string.len = strlen(format[i].u.string.string);
02506     }
02507 
02508     *numTokensPtr = currToken;
02509     *formatPtr = format;
02510 
02511     return 0;
02512 }
02513 /*@=boundswrite@*/
02514 
02517 /*@-boundswrite@*/
02518 static int parseExpression(sprintfToken token, char * str, 
02519                 const headerTagTableEntry tags, 
02520                 const headerSprintfExtension extensions,
02521                 /*@out@*/ char ** endPtr,
02522                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
02523 {
02524     headerTagTableEntry tag;
02525     headerSprintfExtension ext;
02526     char * chptr;
02527     char * end;
02528 
02529     if (errmsg) *errmsg = NULL;
02530     chptr = str;
02531     while (*chptr && *chptr != '?') chptr++;
02532 
02533     if (*chptr != '?') {
02534         /*@-observertrans -readonlytrans@*/
02535         if (errmsg) *errmsg = _("? expected in expression");
02536         /*@=observertrans =readonlytrans@*/
02537         return 1;
02538     }
02539 
02540     *chptr++ = '\0';;
02541 
02542     if (*chptr != '{') {
02543         /*@-observertrans -readonlytrans@*/
02544         if (errmsg) *errmsg = _("{ expected after ? in expression");
02545         /*@=observertrans =readonlytrans@*/
02546         return 1;
02547     }
02548 
02549     chptr++;
02550 
02551     if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat, 
02552                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg)) 
02553         return 1;
02554 
02555     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
02556     if (!(end && *end)) {
02557         /*@-observertrans -readonlytrans@*/
02558         if (errmsg) *errmsg = _("} expected in expression");
02559         /*@=observertrans =readonlytrans@*/
02560         token->u.cond.ifFormat =
02561                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02562         return 1;
02563     }
02564 
02565     chptr = end;
02566     if (*chptr != ':' && *chptr != '|') {
02567         /*@-observertrans -readonlytrans@*/
02568         if (errmsg) *errmsg = _(": expected following ? subexpression");
02569         /*@=observertrans =readonlytrans@*/
02570         token->u.cond.ifFormat =
02571                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02572         return 1;
02573     }
02574 
02575     if (*chptr == '|') {
02576         if (parseFormat(NULL, tags, extensions, &token->u.cond.elseFormat, 
02577                 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, errmsg))
02578         {
02579             token->u.cond.ifFormat =
02580                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02581             return 1;
02582         }
02583     } else {
02584         chptr++;
02585 
02586         if (*chptr != '{') {
02587             /*@-observertrans -readonlytrans@*/
02588             if (errmsg) *errmsg = _("{ expected after : in expression");
02589             /*@=observertrans =readonlytrans@*/
02590             token->u.cond.ifFormat =
02591                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02592             return 1;
02593         }
02594 
02595         chptr++;
02596 
02597         if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat, 
02598                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, 
02599                         errmsg)) 
02600             return 1;
02601 
02602         /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
02603         if (!(end && *end)) {
02604             /*@-observertrans -readonlytrans@*/
02605             if (errmsg) *errmsg = _("} expected in expression");
02606             /*@=observertrans =readonlytrans@*/
02607             token->u.cond.ifFormat =
02608                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02609             return 1;
02610         }
02611 
02612         chptr = end;
02613         if (*chptr != '|') {
02614             /*@-observertrans -readonlytrans@*/
02615             if (errmsg) *errmsg = _("| expected at end of expression");
02616             /*@=observertrans =readonlytrans@*/
02617             token->u.cond.ifFormat =
02618                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
02619             token->u.cond.elseFormat =
02620                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
02621             return 1;
02622         }
02623     }
02624         
02625     chptr++;
02626 
02627     *endPtr = chptr;
02628 
02629     findTag(str, tags, extensions, &tag, &ext);
02630 
02631     if (tag) {
02632         token->u.cond.tag.ext = NULL;
02633         token->u.cond.tag.tag = tag->val;
02634     } else if (ext) {
02635         token->u.cond.tag.ext = ext->u.tagFunction;
02636         token->u.cond.tag.extNum = ext - extensions;
02637     } else {
02638         token->u.cond.tag.ext = NULL;
02639         token->u.cond.tag.tag = -1;
02640     }
02641         
02642     token->type = PTOK_COND;
02643 
02644     return 0;
02645 }
02646 /*@=boundswrite@*/
02647 
02657 static int getExtension(Header h, headerTagTagFunction fn,
02658                 /*@out@*/ hTYP_t typeptr,
02659                 /*@out@*/ hPTR_t * data,
02660                 /*@out@*/ hCNT_t countptr,
02661                 extensionCache ext)
02662         /*@modifies *typeptr, *data, *countptr, ext @*/
02663         /*@requires maxSet(typeptr) >= 0 /\ maxSet(data) >= 0
02664                 /\ maxSet(countptr) >= 0 @*/
02665 {
02666     if (!ext->avail) {
02667         if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
02668             return 1;
02669         ext->avail = 1;
02670     }
02671 
02672     if (typeptr) *typeptr = ext->type;
02673     if (data) *data = ext->data;
02674     if (countptr) *countptr = ext->count;
02675 
02676     return 0;
02677 }
02678 
02681 /*@observer@*/
02682 static char * formatValue(sprintfTag tag, Header h, 
02683                 const headerSprintfExtension extensions,
02684                 extensionCache extCache, int element,
02685                 char ** valp, int * vallenp, int * allocedp)
02686         /*@modifies extCache, *valp, *vallenp, *allocedp @*/
02687         /*@requires maxSet(valp) >= 0 /\ maxSet(vallenp) >= 0
02688                 /\ maxSet(allocedp) >= 0 @*/
02689 {
02690     char * val = NULL;
02691     int need = 0;
02692     char * t, * te;
02693     char buf[20];
02694     int_32 count, type;
02695     hPTR_t data;
02696     unsigned int intVal;
02697     const char ** strarray;
02698     int datafree = 0;
02699     int countBuf;
02700     headerTagFormatFunction tagtype = NULL;
02701     headerSprintfExtension ext;
02702 
02703     memset(buf, 0, sizeof(buf));
02704     /*@-branchstate@*/
02705     if (tag->ext) {
02706 /*@-boundswrite@*/
02707         if (getExtension(h, tag->ext, &type, &data, &count, 
02708                          extCache + tag->extNum))
02709         {
02710             count = 1;
02711             type = RPM_STRING_TYPE;     
02712             data = "(none)";
02713         }
02714 /*@=boundswrite@*/
02715     } else {
02716 /*@-boundswrite@*/
02717         if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
02718             count = 1;
02719             type = RPM_STRING_TYPE;     
02720             data = "(none)";
02721         }
02722 /*@=boundswrite@*/
02723 
02724         datafree = 1;
02725     }
02726     /*@=branchstate@*/
02727 
02728     if (tag->arrayCount) {
02729         /*@-branchstate -observertrans -modobserver@*/
02730         if (datafree)
02731             data = headerFreeData(data, type);
02732         /*@=branchstate =observertrans =modobserver@*/
02733 
02734         countBuf = count;
02735         data = &countBuf;
02736         count = 1;
02737         type = RPM_INT32_TYPE;
02738     }
02739 
02740 /*@-boundswrite@*/
02741     (void) stpcpy( stpcpy(buf, "%"), tag->format);
02742 /*@=boundswrite@*/
02743 
02744     if (tag->type) {
02745         ext = extensions;
02746         while (ext->type != HEADER_EXT_LAST) {
02747             if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
02748             && !strcmp(ext->name, tag->type))
02749             {
02750                 tagtype = ext->u.formatFunction;
02751                 break;
02752             }
02753 
02754             if (ext->type == HEADER_EXT_MORE)
02755                 ext = ext->u.more;
02756             else
02757                 ext++;
02758         }
02759     }
02760     
02761     /*@-branchstate@*/
02762     switch (type) {
02763     case RPM_STRING_ARRAY_TYPE:
02764         strarray = (const char **)data;
02765 
02766         if (tagtype)
02767             val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
02768 
02769         if (val) {
02770             need = strlen(val);
02771         } else {
02772             need = strlen(strarray[element]) + tag->pad + 20;
02773             val = xmalloc(need+1);
02774             strcat(buf, "s");
02775             /*@-formatconst@*/
02776             sprintf(val, buf, strarray[element]);
02777             /*@=formatconst@*/
02778         }
02779 
02780         /*@-observertrans -modobserver@*/
02781         if (datafree) data = _free(data);
02782         /*@=observertrans =modobserver@*/
02783 
02784         break;
02785 
02786     case RPM_STRING_TYPE:
02787         if (tagtype)
02788             val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad,  0);
02789 
02790         if (val) {
02791             need = strlen(val);
02792         } else {
02793             need = strlen(data) + tag->pad + 20;
02794             val = xmalloc(need+1);
02795             strcat(buf, "s");
02796             /*@-formatconst@*/
02797             sprintf(val, buf, data);
02798             /*@=formatconst@*/
02799         }
02800         break;
02801 
02802     case RPM_CHAR_TYPE:
02803     case RPM_INT8_TYPE:
02804     case RPM_INT16_TYPE:
02805     case RPM_INT32_TYPE:
02806         switch (type) {
02807         case RPM_CHAR_TYPE:     
02808         case RPM_INT8_TYPE:
02809             intVal = *(((int_8 *) data) + element);
02810             /*@innerbreak@*/ break;
02811         case RPM_INT16_TYPE:
02812             intVal = *(((uint_16 *) data) + element);
02813             /*@innerbreak@*/ break;
02814         default:                /* keep -Wall quiet */
02815         case RPM_INT32_TYPE:
02816             intVal = *(((int_32 *) data) + element);
02817             /*@innerbreak@*/ break;
02818         }
02819 
02820         if (tagtype)
02821             val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad,  element);
02822 
02823         if (val) {
02824             need = strlen(val);
02825         } else {
02826             need = 10 + tag->pad + 20;
02827             val = xmalloc(need+1);
02828             strcat(buf, "d");
02829             /*@-formatconst@*/
02830             sprintf(val, buf, intVal);
02831             /*@=formatconst@*/
02832         }
02833         break;
02834 
02835     case RPM_BIN_TYPE:
02836         if (tagtype)
02837             val = tagtype(RPM_BIN_TYPE, data, buf, tag->pad, count);
02838 
02839         if (val) {
02840             need = count;       /* XXX broken iff RPM_BIN_TYPE extension */
02841         } else {
02842 #ifdef  NOTYET
02843             val = memcpy(xmalloc(count), data, count);
02844 #else
02845             /* XXX format string not used */
02846             static char hex[] = "0123456789abcdef";
02847             const char * s = data;
02848 
02849 /*@-boundswrite@*/
02850             need = 2*count + tag->pad;
02851             val = t = xmalloc(need+1);
02852             while (count-- > 0) {
02853                 unsigned int i;
02854                 i = *s++;
02855                 *t++ = hex[ (i >> 4) & 0xf ];
02856                 *t++ = hex[ (i     ) & 0xf ];
02857             }
02858             *t = '\0';
02859 /*@=boundswrite@*/
02860 #endif
02861         }
02862         break;
02863 
02864     default:
02865         need = sizeof("(unknown type)") - 1;
02866         val = xstrdup("(unknown type)");
02867         break;
02868     }
02869     /*@=branchstate@*/
02870 
02871     /*@-branchstate@*/
02872     if (val && need > 0) {
02873         if (((*vallenp) + need) >= (*allocedp)) {
02874             if ((*allocedp) <= need)
02875                 (*allocedp) += need;
02876 /*@-shiftimplementation@*/
02877             (*allocedp) <<= 1;
02878 /*@=shiftimplementation@*/
02879 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
02880             (*valp) = xrealloc((*valp), (*allocedp)+1); 
02881 /*@=unqualifiedtrans@*/
02882         }
02883         t = (*valp) + (*vallenp);
02884 /*@-boundswrite@*/
02885         te = stpcpy(t, val);
02886 /*@=boundswrite@*/
02887         (*vallenp) += (te - t);
02888         val = _free(val);
02889     }
02890     /*@=branchstate@*/
02891 
02892     return ((*valp) + (*vallenp));
02893 }
02894 
02897 /*@observer@*/
02898 static char * singleSprintf(Header h, sprintfToken token,
02899                 const headerSprintfExtension extensions,
02900                 extensionCache extCache, int element,
02901                 char ** valp, int * vallenp, int * allocedp)
02902         /*@modifies h, extCache, *valp, *vallenp, *allocedp @*/
02903         /*@requires maxSet(valp) >= 0 /\ maxSet(vallenp) >= 0
02904                 /\ maxSet(allocedp) >= 0 @*/
02905 {
02906     char * t, * te;
02907     int i, j;
02908     int numElements;
02909     int type;
02910     sprintfToken condFormat;
02911     int condNumFormats;
02912     int need;
02913 
02914     /* we assume the token and header have been validated already! */
02915 
02916     switch (token->type) {
02917     case PTOK_NONE:
02918         break;
02919 
02920     case PTOK_STRING:
02921         need = token->u.string.len;
02922         if (need <= 0) break;
02923         if (((*vallenp) + need) >= (*allocedp)) {
02924             if ((*allocedp) <= need)
02925                 (*allocedp) += need;
02926 /*@-shiftimplementation@*/
02927             (*allocedp) <<= 1;
02928 /*@=shiftimplementation@*/
02929 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
02930             (*valp) = xrealloc((*valp), (*allocedp)+1); 
02931 /*@=unqualifiedtrans@*/
02932         }
02933         t = (*valp) + (*vallenp);
02934 /*@-boundswrite@*/
02935         te = stpcpy(t, token->u.string.string);
02936 /*@=boundswrite@*/
02937         (*vallenp) += (te - t);
02938         break;
02939 
02940     case PTOK_TAG:
02941         t = (*valp) + (*vallenp);
02942         te = formatValue(&token->u.tag, h, extensions, extCache,
02943                         (token->u.tag.justOne ? 0 : element),
02944                         valp, vallenp, allocedp);
02945         break;
02946 
02947     case PTOK_COND:
02948         if (token->u.cond.tag.ext ||
02949             headerIsEntry(h, token->u.cond.tag.tag)) {
02950             condFormat = token->u.cond.ifFormat;
02951             condNumFormats = token->u.cond.numIfTokens;
02952         } else {
02953             condFormat = token->u.cond.elseFormat;
02954             condNumFormats = token->u.cond.numElseTokens;
02955         }
02956 
02957         need = condNumFormats * 20;
02958         if (condFormat == NULL || need <= 0) break;
02959         if (((*vallenp) + need) >= (*allocedp)) {
02960             if ((*allocedp) <= need)
02961                 (*allocedp) += need;
02962 /*@-shiftimplementation@*/
02963             (*allocedp) <<= 1;
02964 /*@=shiftimplementation@*/
02965 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
02966             (*valp) = xrealloc((*valp), (*allocedp)+1); 
02967 /*@=unqualifiedtrans@*/
02968         }
02969 
02970         t = (*valp) + (*vallenp);
02971         for (i = 0; i < condNumFormats; i++)
02972             te = singleSprintf(h, condFormat + i, extensions, extCache,
02973                                 element, valp, vallenp, allocedp);
02974         break;
02975 
02976     case PTOK_ARRAY:
02977         numElements = -1;
02978         for (i = 0; i < token->u.array.numTokens; i++) {
02979             if (token->u.array.format[i].type != PTOK_TAG ||
02980                 token->u.array.format[i].u.tag.arrayCount ||
02981                 token->u.array.format[i].u.tag.justOne) continue;
02982 
02983             if (token->u.array.format[i].u.tag.ext) {
02984                 const void * data;
02985 /*@-boundswrite@*/
02986                 if (getExtension(h, token->u.array.format[i].u.tag.ext,
02987                                  &type, &data, &numElements, 
02988                                  extCache + 
02989                                    token->u.array.format[i].u.tag.extNum))
02990                      continue;
02991 /*@=boundswrite@*/
02992             } else {
02993 /*@-boundswrite@*/
02994                 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag, 
02995                                     &type, NULL, &numElements))
02996                     continue;
02997 /*@=boundswrite@*/
02998             } 
02999             /*@loopbreak@*/ break;
03000         }
03001 
03002         if (numElements == -1) {
03003             need = sizeof("(none)") - 1;
03004             if (((*vallenp) + need) >= (*allocedp)) {
03005                 if ((*allocedp) <= need)
03006                     (*allocedp) += need;
03007 /*@-shiftimplementation@*/
03008                 (*allocedp) <<= 1;
03009 /*@=shiftimplementation@*/
03010 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
03011                 (*valp) = xrealloc((*valp), (*allocedp)+1);     
03012 /*@=unqualifiedtrans@*/
03013             }
03014             t = (*valp) + (*vallenp);
03015 /*@-boundswrite@*/
03016             te = stpcpy(t, "(none)");
03017 /*@=boundswrite@*/
03018             (*vallenp) += (te - t);
03019         } else {
03020             need = numElements * token->u.array.numTokens * 10;
03021             if (need <= 0) break;
03022             if (((*vallenp) + need) >= (*allocedp)) {
03023                 if ((*allocedp) <= need)
03024                     (*allocedp) += need;
03025 /*@-shiftimplementation@*/
03026                 (*allocedp) <<= 1;
03027 /*@=shiftimplementation@*/
03028 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
03029                 (*valp) = xrealloc((*valp), (*allocedp)+1);     
03030 /*@=unqualifiedtrans@*/
03031             }
03032 
03033             t = (*valp) + (*vallenp);
03034             for (j = 0; j < numElements; j++) {
03035                 for (i = 0; i < token->u.array.numTokens; i++)
03036                     te = singleSprintf(h, token->u.array.format + i, 
03037                                         extensions, extCache, j,
03038                                         valp, vallenp, allocedp);
03039             }
03040         }
03041         break;
03042     }
03043 
03044     return ((*valp) + (*vallenp));
03045 }
03046 
03049 static /*@only@*/ extensionCache
03050 allocateExtensionCache(const headerSprintfExtension extensions)
03051         /*@*/
03052 {
03053     headerSprintfExtension ext = extensions;
03054     int i = 0;
03055 
03056     while (ext->type != HEADER_EXT_LAST) {
03057         i++;
03058         if (ext->type == HEADER_EXT_MORE)
03059             ext = ext->u.more;
03060         else
03061             ext++;
03062     }
03063 
03064     /*@-sizeoftype@*/
03065     return xcalloc(i, sizeof(struct extensionCache_s));
03066     /*@=sizeoftype@*/
03067 }
03068 
03072 static /*@null@*/ extensionCache
03073 freeExtensionCache(const headerSprintfExtension extensions,
03074                         /*@only@*/ extensionCache cache)
03075         /*@*/
03076 {
03077     headerSprintfExtension ext = extensions;
03078     int i = 0;
03079 
03080     while (ext->type != HEADER_EXT_LAST) {
03081 /*@-boundswrite@*/
03082         if (cache[i].freeit) cache[i].data = _free(cache[i].data);
03083 /*@=boundswrite@*/
03084 
03085         i++;
03086         if (ext->type == HEADER_EXT_MORE)
03087             ext = ext->u.more;
03088         else
03089             ext++;
03090     }
03091 
03092     cache = _free(cache);
03093     return NULL;
03094 }
03095 
03107 static /*@only@*/ /*@null@*/
03108 char * headerSprintf(Header h, const char * fmt,
03109                      const struct headerTagTableEntry_s * tbltags,
03110                      const struct headerSprintfExtension_s * extensions,
03111                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
03112         /*@modifies *errmsg @*/
03113 {
03114     /*@-castexpose@*/   /* FIX: legacy API shouldn't change. */
03115     headerSprintfExtension exts = (headerSprintfExtension) extensions;
03116     headerTagTableEntry tags = (headerTagTableEntry) tbltags;
03117     /*@=castexpose@*/
03118     char * t;
03119     char * fmtString;
03120     sprintfToken format;
03121     int numTokens;
03122     char * val = NULL;
03123     int vallen = 0;
03124     int alloced = 0;
03125     int i;
03126     extensionCache extCache;
03127  
03128     /*fmtString = escapeString(fmt);*/
03129     fmtString = xstrdup(fmt);
03130    
03131 /*@-boundswrite@*/
03132     if (parseFormat(fmtString, tags, exts, &format, &numTokens, 
03133                     NULL, PARSER_BEGIN, errmsg)) {
03134         fmtString = _free(fmtString);
03135         return NULL;
03136     }
03137 /*@=boundswrite@*/
03138 
03139     extCache = allocateExtensionCache(exts);
03140 
03141     val = xstrdup("");
03142     for (i = 0; i < numTokens; i++) {
03143 /*@-boundswrite@*/
03144         /*@-mods@*/
03145         t = singleSprintf(h, format + i, exts, extCache, 0,
03146                 &val, &vallen, &alloced);
03147         /*@=mods@*/
03148 /*@=boundswrite@*/
03149     }
03150 
03151     if (val != NULL && vallen < alloced)
03152         val = xrealloc(val, vallen+1);  
03153 
03154     fmtString = _free(fmtString);
03155     extCache = freeExtensionCache(exts, extCache);
03156     format = freeFormat(format, numTokens);
03157 
03158     return val;
03159 }
03160 
03163 static char * octalFormat(int_32 type, hPTR_t data, 
03164                 char * formatPrefix, int padding, /*@unused@*/int element)
03165         /*@modifies formatPrefix @*/
03166 {
03167     char * val;
03168 
03169     if (type != RPM_INT32_TYPE) {
03170         val = xstrdup(_("(not a number)"));
03171     } else {
03172         val = xmalloc(20 + padding);
03173 /*@-boundswrite@*/
03174         strcat(formatPrefix, "o");
03175 /*@=boundswrite@*/
03176         /*@-formatconst@*/
03177         sprintf(val, formatPrefix, *((int_32 *) data));
03178         /*@=formatconst@*/
03179     }
03180 
03181     return val;
03182 }
03183 
03186 static char * hexFormat(int_32 type, hPTR_t data, 
03187                 char * formatPrefix, int padding, /*@unused@*/int element)
03188         /*@modifies formatPrefix @*/
03189 {
03190     char * val;
03191 
03192     if (type != RPM_INT32_TYPE) {
03193         val = xstrdup(_("(not a number)"));
03194     } else {
03195         val = xmalloc(20 + padding);
03196 /*@-boundswrite@*/
03197         strcat(formatPrefix, "x");
03198 /*@=boundswrite@*/
03199         /*@-formatconst@*/
03200         sprintf(val, formatPrefix, *((int_32 *) data));
03201         /*@=formatconst@*/
03202     }
03203 
03204     return val;
03205 }
03206 
03209 static char * realDateFormat(int_32 type, hPTR_t data, 
03210                 char * formatPrefix, int padding, /*@unused@*/int element,
03211                 const char * strftimeFormat)
03212         /*@modifies formatPrefix @*/
03213 {
03214     char * val;
03215 
03216     if (type != RPM_INT32_TYPE) {
03217         val = xstrdup(_("(not a number)"));
03218     } else {
03219         struct tm * tstruct;
03220         char buf[50];
03221 
03222         val = xmalloc(50 + padding);
03223 /*@-boundswrite@*/
03224         strcat(formatPrefix, "s");
03225 /*@=boundswrite@*/
03226 
03227         /* this is important if sizeof(int_32) ! sizeof(time_t) */
03228         {   time_t dateint = *((int_32 *) data);
03229             tstruct = localtime(&dateint);
03230         }
03231         buf[0] = '\0';
03232         if (tstruct)
03233             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
03234         /*@-formatconst@*/
03235         sprintf(val, formatPrefix, buf);
03236         /*@=formatconst@*/
03237     }
03238 
03239     return val;
03240 }
03241 
03244 static char * dateFormat(int_32 type, hPTR_t data, 
03245                          char * formatPrefix, int padding, int element)
03246         /*@modifies formatPrefix @*/
03247 {
03248     return realDateFormat(type, data, formatPrefix, padding, element, "%c");
03249 }
03250 
03253 static char * dayFormat(int_32 type, hPTR_t data, 
03254                          char * formatPrefix, int padding, int element)
03255         /*@modifies formatPrefix @*/
03256 {
03257     return realDateFormat(type, data, formatPrefix, padding, element, 
03258                           "%a %b %d %Y");
03259 }
03260 
03263 static char * shescapeFormat(int_32 type, hPTR_t data, 
03264                 char * formatPrefix, int padding, /*@unused@*/int element)
03265         /*@modifies formatPrefix @*/
03266 {
03267     char * result, * dst, * src, * buf;
03268 
03269     if (type == RPM_INT32_TYPE) {
03270         result = xmalloc(padding + 20);
03271 /*@-boundswrite@*/
03272         strcat(formatPrefix, "d");
03273 /*@=boundswrite@*/
03274         /*@-formatconst@*/
03275         sprintf(result, formatPrefix, *((int_32 *) data));
03276         /*@=formatconst@*/
03277     } else {
03278         buf = alloca(strlen(data) + padding + 2);
03279 /*@-boundswrite@*/
03280         strcat(formatPrefix, "s");
03281 /*@=boundswrite@*/
03282         /*@-formatconst@*/
03283         sprintf(buf, formatPrefix, data);
03284         /*@=formatconst@*/
03285 
03286 /*@-boundswrite@*/
03287         result = dst = xmalloc(strlen(buf) * 4 + 3);
03288         *dst++ = '\'';
03289         for (src = buf; *src != '\0'; src++) {
03290             if (*src == '\'') {
03291                 *dst++ = '\'';
03292                 *dst++ = '\\';
03293                 *dst++ = '\'';
03294                 *dst++ = '\'';
03295             } else {
03296                 *dst++ = *src;
03297             }
03298         }
03299         *dst++ = '\'';
03300         *dst = '\0';
03301 /*@=boundswrite@*/
03302 
03303     }
03304 
03305     return result;
03306 }
03307 
03308 /*@-type@*/ /* FIX: cast? */
03309 const struct headerSprintfExtension_s headerDefaultFormats[] = {
03310     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
03311     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
03312     { HEADER_EXT_FORMAT, "date", { dateFormat } },
03313     { HEADER_EXT_FORMAT, "day", { dayFormat } },
03314     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
03315     { HEADER_EXT_LAST, NULL, { NULL } }
03316 };
03317 /*@=type@*/
03318 
03325 static
03326 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
03327         /*@modifies headerTo @*/
03328 {
03329     int * p;
03330 
03331     if (headerFrom == headerTo)
03332         return;
03333 
03334     for (p = tagstocopy; *p != 0; p++) {
03335         char *s;
03336         int_32 type;
03337         int_32 count;
03338         if (headerIsEntry(headerTo, *p))
03339             continue;
03340 /*@-boundswrite@*/
03341         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
03342                                 (hPTR_t *) &s, &count))
03343             continue;
03344 /*@=boundswrite@*/
03345         (void) headerAddEntry(headerTo, *p, type, s, count);
03346         s = headerFreeData(s, type);
03347     }
03348 }
03349 
03353 struct headerIteratorS {
03354 /*@unused@*/ Header h;          
03355 /*@unused@*/ int next_index;    
03356 };
03357 
03363 static /*@null@*/
03364 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
03365         /*@modifies hi @*/
03366 {
03367     hi->h = headerFree(hi->h);
03368     hi = _free(hi);
03369     return hi;
03370 }
03371 
03377 static
03378 HeaderIterator headerInitIterator(Header h)
03379         /*@modifies h */
03380 {
03381     HeaderIterator hi = xmalloc(sizeof(*hi));
03382 
03383     headerSort(h);
03384 
03385     hi->h = headerLink(h);
03386     hi->next_index = 0;
03387     return hi;
03388 }
03389 
03399 static
03400 int headerNextIterator(HeaderIterator hi,
03401                 /*@null@*/ /*@out@*/ hTAG_t tag,
03402                 /*@null@*/ /*@out@*/ hTYP_t type,
03403                 /*@null@*/ /*@out@*/ hPTR_t * p,
03404                 /*@null@*/ /*@out@*/ hCNT_t c)
03405         /*@modifies hi, *tag, *type, *p, *c @*/
03406         /*@requires maxSet(tag) >= 0 /\ maxSet(type) >= 0
03407                 /\ maxSet(p) >= 0 /\ maxSet(c) >= 0 @*/
03408 {
03409     Header h = hi->h;
03410     int slot = hi->next_index;
03411     indexEntry entry = NULL;
03412     int rc;
03413 
03414     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
03415         entry = h->index + slot;
03416         if (!ENTRY_IS_REGION(entry))
03417             break;
03418     }
03419     hi->next_index = slot;
03420     if (entry == NULL || slot >= h->indexUsed)
03421         return 0;
03422     /*@-noeffect@*/     /* LCL: no clue */
03423     hi->next_index++;
03424     /*@=noeffect@*/
03425 
03426     if (tag)
03427         *tag = entry->info.tag;
03428 
03429     rc = copyEntry(entry, type, p, c, 0);
03430 
03431     /* XXX 1 on success */
03432     return ((rc == 1) ? 1 : 0);
03433 }
03434 
03440 static /*@null@*/
03441 Header headerCopy(Header h)
03442         /*@modifies h @*/
03443 {
03444     Header nh = headerNew();
03445     HeaderIterator hi;
03446     int_32 tag, type, count;
03447     hPTR_t ptr;
03448    
03449     /*@-branchstate@*/
03450     for (hi = headerInitIterator(h);
03451         headerNextIterator(hi, &tag, &type, &ptr, &count);
03452         ptr = headerFreeData((void *)ptr, type))
03453     {
03454         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
03455     }
03456     hi = headerFreeIterator(hi);
03457     /*@=branchstate@*/
03458 
03459     return headerReload(nh, HEADER_IMAGE);
03460 }
03461 
03462 /*@observer@*/ /*@unchecked@*/
03463 static struct HV_s hdrVec1 = {
03464     headerLink,
03465     headerUnlink,
03466     headerFree,
03467     headerNew,
03468     headerSort,
03469     headerUnsort,
03470     headerSizeof,
03471     headerUnload,
03472     headerReload,
03473     headerCopy,
03474     headerLoad,
03475     headerCopyLoad,
03476     headerRead,
03477     headerWrite,
03478     headerIsEntry,
03479     headerFreeTag,
03480     headerGetEntry,
03481     headerGetEntryMinMemory,
03482     headerAddEntry,
03483     headerAppendEntry,
03484     headerAddOrAppendEntry,
03485     headerAddI18NString,
03486     headerModifyEntry,
03487     headerRemoveEntry,
03488     headerSprintf,
03489     headerCopyTags,
03490     headerFreeIterator,
03491     headerInitIterator,
03492     headerNextIterator,
03493     NULL, NULL,
03494     1
03495 };
03496 
03497 /*@-compmempass -redef@*/
03498 /*@observer@*/ /*@unchecked@*/
03499 HV_t hdrVec = &hdrVec1;
03500 /*@=compmempass =redef@*/

Generated on Wed Sep 4 12:49:55 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002