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@*/