- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# lib/header.c

Go to the documentation of this file.

    00001
    00005 /* RPM - Copyright (C) 1995-2000 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 /*@-redecl@*/   /* FIX: avoid rpmlib.h, need for debugging. */
    00020 /*@observer@*/ const char *const tagName(int tag)       /*@*/;
    00021 /*@=redecl@*/
    00022
    00023 /*@access entryInfo @*/
    00024 /*@access indexEntry @*/
    00025
    00026 /*@access extensionCache @*/
    00027 /*@access sprintfTag @*/
    00028 /*@access sprintfToken @*/
    00029 /*@access HV_t @*/
    00030
    00031 #define PARSER_BEGIN    0
    00032 #define PARSER_IN_ARRAY 1
    00033 #define PARSER_IN_EXPR  2
    00034
    00037 /*@observer@*/ /*@unchecked@*/
    00038 static unsigned char header_magic[8] = {
    00039         0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
    00040 };
    00041
    00045 /*@unchecked@*/
    00046 static size_t headerMaxbytes = (32*1024*1024);
    00047
    00052 #define hdrchkTags(_ntags)      ((_ntags) & 0xffff0000)
    00053
    00058 #define hdrchkData(_nbytes)     ((_nbytes) & 0xff000000)
    00059
    00063 /*@observer@*/ /*@unchecked@*/
    00064 static int typeSizes[] =  {
    00065         0,
    00066         1,
    00067         1,
    00068         2,
    00069         4,
    00070         -1,
    00071         -1,
    00072         1,
    00073         -1,
    00074         -1
    00075 };
    00076
    00077 /*@observer@*/ /*@unchecked@*/
    00078 HV_t hdrVec;    /* forward reference */
    00079
    00085 /*@unused@*/ static inline /*@null@*/ void *
    00086 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies *p @*/
    00087 {
    00088     if (p != NULL)      free((void *)p);
    00089     return NULL;
    00090 }
    00091
    00097 static
    00098 Header headerLink(Header h)
    00099         /*@modifies h @*/
    00100 {
    00101     if (h != NULL) h->nrefs++;
    00102     /*@-refcounttrans -nullret @*/
    00103     return h;
    00104     /*@=refcounttrans =nullret @*/
    00105 }
    00106
    00112 static /*@null@*/
    00113 Header headerUnlink(/*@killref@*/ /*@null@*/ Header h)
    00114         /*@modifies h @*/
    00115 {
    00116     if (h != NULL) h->nrefs--;
    00117     return NULL;
    00118 }
    00119
    00125 static /*@null@*/
    00126 Header headerFree(/*@killref@*/ /*@null@*/ Header h)
    00127         /*@modifies h @*/
    00128 {
    00129     (void) headerUnlink(h);
    00130
    00131     /*@-usereleased@*/
    00132     if (h == NULL || h->nrefs > 0)
    00133         return NULL;    /* XXX return previous header? */
    00134
    00135     if (h->index) {
    00136         indexEntry entry = h->index;
    00137         int i;
    00138         for (i = 0; i < h->indexUsed; i++, entry++) {
    00139             if ((h->flags & HEADERFLAG_ALLOCATED) && ENTRY_IS_REGION(entry)) {
    00140                 if (entry->length > 0) {
    00141                     int_32 * ei = entry->data;
    00142                     if ((ei - 2) == h->blob) h->blob = _free(h->blob);
    00143                     entry->data = NULL;
    00144                 }
    00145             } else if (!ENTRY_IN_REGION(entry)) {
    00146                 entry->data = _free(entry->data);
    00147             }
    00148             entry->data = NULL;
    00149         }
    00150         h->index = _free(h->index);
    00151     }
    00152
    00153     /*@-refcounttrans@*/ h = _free(h); /*@=refcounttrans@*/
    00154     return h;
    00155     /*@=usereleased@*/
    00156 }
    00157
    00162 static
    00163 Header headerNew(void)
    00164         /*@*/
    00165 {
    00166     Header h = xcalloc(1, sizeof(*h));
    00167
    00168     /*@-assignexpose@*/
    00169     h->hv = *hdrVec;            /* structure assignment */
    00170     /*@=assignexpose@*/
    00171     h->blob = NULL;
    00172     h->indexAlloced = INDEX_MALLOC_SIZE;
    00173     h->indexUsed = 0;
    00174     h->flags = HEADERFLAG_SORTED;
    00175
    00176     h->index = (h->indexAlloced
    00177         ? xcalloc(h->indexAlloced, sizeof(*h->index))
    00178         : NULL);
    00179
    00180     /*@-globstate -observertrans @*/
    00181     h->nrefs = 0;
    00182     return headerLink(h);
    00183     /*@=globstate =observertrans @*/
    00184 }
    00185
    00188 static int indexCmp(const void * avp, const void * bvp) /*@*/
    00189 {
    00190     /*@-castexpose@*/
    00191     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
    00192     /*@=castexpose@*/
    00193     return (ap->info.tag - bp->info.tag);
    00194 }
    00195
    00200 static
    00201 void headerSort(Header h)
    00202         /*@modifies h @*/
    00203 {
    00204     if (!(h->flags & HEADERFLAG_SORTED)) {
    00205         qsort(h->index, h->indexUsed, sizeof(*h->index), indexCmp);
    00206         h->flags |= HEADERFLAG_SORTED;
    00207     }
    00208 }
    00209
    00212 static int offsetCmp(const void * avp, const void * bvp) /*@*/
    00213 {
    00214     /*@-castexpose@*/
    00215     indexEntry ap = (indexEntry) avp, bp = (indexEntry) bvp;
    00216     /*@=castexpose@*/
    00217     int rc = (ap->info.offset - bp->info.offset);
    00218
    00219     if (rc == 0) {
    00220         /* Within a region, entries sort by address. Added drips sort by tag. */
    00221         if (ap->info.offset < 0)
    00222             rc = (((char *)ap->data) - ((char *)bp->data));
    00223         else
    00224             rc = (ap->info.tag - bp->info.tag);
    00225     }
    00226     return rc;
    00227 }
    00228
    00233 static
    00234 void headerUnsort(Header h)
    00235         /*@modifies h @*/
    00236 {
    00237     qsort(h->index, h->indexUsed, sizeof(*h->index), offsetCmp);
    00238 }
    00239
    00246 static
    00247 unsigned int headerSizeof(/*@null@*/ Header h, enum hMagic magicp)
    00248         /*@modifies h @*/
    00249 {
    00250     indexEntry entry;
    00251     unsigned int size = 0;
    00252     unsigned int pad = 0;
    00253     int i;
    00254
    00255     if (h == NULL)
    00256         return size;
    00257
    00258     headerSort(h);
    00259
    00260     switch (magicp) {
    00261     case HEADER_MAGIC_YES:
    00262         size += sizeof(header_magic);
    00263         break;
    00264     case HEADER_MAGIC_NO:
    00265         break;
    00266     }
    00267
    00268     /*@-sizeoftype@*/
    00269     size += 2 * sizeof(int_32); /* count of index entries */
    00270     /*@=sizeoftype@*/
    00271
    00272     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
    00273         unsigned diff;
    00274         int_32 type;
    00275
    00276         /* Regions go in as is ... */
    00277         if (ENTRY_IS_REGION(entry)) {
    00278             size += entry->length;
    00279             /* XXX Legacy regions do not include the region tag and data. */
    00280             /*@-sizeoftype@*/
    00281             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
    00282                 size += sizeof(struct entryInfo) + entry->info.count;
    00283             /*@=sizeoftype@*/
    00284             continue;
    00285         }
    00286
    00287         /* ... and region elements are skipped. */
    00288         if (entry->info.offset < 0)
    00289             continue;
    00290
    00291         /* Alignment */
    00292         type = entry->info.type;
    00293         if (typeSizes[type] > 1) {
    00294             diff = typeSizes[type] - (size % typeSizes[type]);
    00295             if (diff != typeSizes[type]) {
    00296                 size += diff;
    00297                 pad += diff;
    00298             }
    00299         }
    00300
    00301         /*@-sizeoftype@*/
    00302         size += sizeof(struct entryInfo) + entry->length;
    00303         /*@=sizeoftype@*/
    00304     }
    00305
    00306     return size;
    00307 }
    00308
    00318 /*@mayexit@*/
    00319 static int dataLength(int_32 type, hPTR_t p, int_32 count, int onDisk)
    00320         /*@*/
    00321 {
    00322     int length = 0;
    00323
    00324     switch (type) {
    00325     case RPM_STRING_TYPE:
    00326         if (count == 1) {       /* Special case -- p is just the string */
    00327             length = strlen(p) + 1;
    00328             break;
    00329         }
    00330         /* This should not be allowed */
    00331         /*@-modfilesys@*/
    00332         fprintf(stderr, _("dataLength() RPM_STRING_TYPE count must be 1.\n"));
    00333         /*@=modfilesys@*/
    00334         exit(EXIT_FAILURE);
    00335         /*@notreached@*/ break;
    00336
    00337     case RPM_STRING_ARRAY_TYPE:
    00338     case RPM_I18NSTRING_TYPE:
    00339     {   int i;
    00340
    00341         /* This is like RPM_STRING_TYPE, except it's *always* an array */
    00342         /* Compute sum of length of all strings, including null terminators */
    00343         i = count;
    00344
    00345         if (onDisk) {
    00346             const char * chptr = p;
    00347             int thisLen;
    00348
    00349             while (i--) {
    00350                 thisLen = strlen(chptr) + 1;
    00351                 length += thisLen;
    00352                 chptr += thisLen;
    00353             }
    00354         } else {
    00355             const char ** src = (const char **)p;
    00356             while (i--) {
    00357                 /* add one for null termination */
    00358                 length += strlen(*src++) + 1;
    00359             }
    00360         }
    00361     }   break;
    00362
    00363     default:
    00364         if (typeSizes[type] != -1) {
    00365             length = typeSizes[type] * count;
    00366             break;
    00367         }
    00368         /*@-modfilesys@*/
    00369         fprintf(stderr, _("Data type %d not supported\n"), (int) type);
    00370         /*@=modfilesys@*/
    00371         exit(EXIT_FAILURE);
    00372         /*@notreached@*/ break;
    00373     }
    00374
    00375     return length;
    00376 }
    00377
    00403 static int regionSwab(/*@null@*/ indexEntry entry, int il, int dl,
    00404                 entryInfo pe, char * dataStart, int regionid)
    00405         /*@modifies *entry, *dataStart @*/
    00406 {
    00407     char * tprev = NULL;
    00408     char * t = NULL;
    00409     int tdel, tl = dl;
    00410     struct indexEntry ieprev;
    00411
    00412     memset(&ieprev, 0, sizeof(ieprev));
    00413     for (; il > 0; il--, pe++) {
    00414         struct indexEntry ie;
    00415         int_32 type;
    00416
    00417         ie.info.tag = ntohl(pe->tag);
    00418         ie.info.type = ntohl(pe->type);
    00419         if (ie.info.type < RPM_MIN_TYPE || ie.info.type > RPM_MAX_TYPE)
    00420             return -1;
    00421         ie.info.count = ntohl(pe->count);
    00422         ie.info.offset = ntohl(pe->offset);
    00423         ie.data = t = dataStart + ie.info.offset;
    00424         ie.length = dataLength(ie.info.type, ie.data, ie.info.count, 1);
    00425         ie.rdlen = 0;
    00426
    00427         if (entry) {
    00428             ie.info.offset = regionid;
    00429             *entry = ie;        /* structure assignment */
    00430             entry++;
    00431         }
    00432
    00433         /* Alignment */
    00434         type = ie.info.type;
    00435         if (typeSizes[type] > 1) {
    00436             unsigned diff;
    00437             diff = typeSizes[type] - (dl % typeSizes[type]);
    00438             if (diff != typeSizes[type]) {
    00439                 dl += diff;
    00440                 if (ieprev.info.type == RPM_I18NSTRING_TYPE)
    00441                     ieprev.length += diff;
    00442             }
    00443         }
    00444         tdel = (tprev ? (t - tprev) : 0);
    00445         if (ieprev.info.type == RPM_I18NSTRING_TYPE)
    00446             tdel = ieprev.length;
    00447
    00448         if (ie.info.tag >= HEADER_I18NTABLE) {
    00449             tprev = t;
    00450         } else {
    00451             tprev = dataStart;
    00452             /* XXX HEADER_IMAGE tags don't include region sub-tag. */
    00453             /*@-sizeoftype@*/
    00454             if (ie.info.tag == HEADER_IMAGE)
    00455                 tprev -= REGION_TAG_COUNT;
    00456             /*@=sizeoftype@*/
    00457         }
    00458
    00459         /* Perform endian conversions */
    00460         switch (ntohl(pe->type)) {
    00461         case RPM_INT32_TYPE:
    00462         {   int_32 * it = (int_32 *)t;
    00463             for (; ie.info.count > 0; ie.info.count--, it += 1)
    00464                 *it = htonl(*it);
    00465             t = (char *) it;
    00466         }   /*@switchbreak@*/ break;
    00467         case RPM_INT16_TYPE:
    00468         {   int_16 * it = (int_16 *) t;
    00469             for (; ie.info.count > 0; ie.info.count--, it += 1)
    00470                 *it = htons(*it);
    00471             t = (char *) it;
    00472         }   /*@switchbreak@*/ break;
    00473         default:
    00474             t += ie.length;
    00475             /*@switchbreak@*/ break;
    00476         }
    00477
    00478         dl += ie.length;
    00479         tl += tdel;
    00480         ieprev = ie;    /* structure assignment */
    00481
    00482     }
    00483     tdel = (tprev ? (t - tprev) : 0);
    00484     tl += tdel;
    00485
    00486     /* XXX
    00487      * There are two hacks here:
    00488      *  1) tl is 16b (i.e. REGION_TAG_COUNT) short while doing headerReload().
    00489      *  2) the 8/98 rpm bug with inserting i18n tags needs to use tl, not dl.
    00490      */
    00491     /*@-sizeoftype@*/
    00492     if (tl+REGION_TAG_COUNT == dl)
    00493         tl += REGION_TAG_COUNT;
    00494     /*@=sizeoftype@*/
    00495
    00496     return dl;
    00497 }
    00498
    00501 static /*@only@*/ /*@null@*/ void * doHeaderUnload(Header h,
    00502                 /*@out@*/ int * lengthPtr)
    00503         /*@modifies h, *lengthPtr @*/
    00504 {
    00505     int_32 * ei = NULL;
    00506     entryInfo pe;
    00507     char * dataStart;
    00508     char * te;
    00509     unsigned pad;
    00510     unsigned len;
    00511     int_32 il = 0;
    00512     int_32 dl = 0;
    00513     indexEntry entry;
    00514     int_32 type;
    00515     int i;
    00516     int drlen, ndribbles;
    00517     int driplen, ndrips;
    00518     int legacy = 0;
    00519
    00520     /* Sort entries by (offset,tag). */
    00521     headerUnsort(h);
    00522
    00523     /* Compute (il,dl) for all tags, including those deleted in region. */
    00524     pad = 0;
    00525     drlen = ndribbles = driplen = ndrips = 0;
    00526     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
    00527         if (ENTRY_IS_REGION(entry)) {
    00528             int_32 rdl = -entry->info.offset;   /* negative offset */
    00529             int_32 ril = rdl/sizeof(*pe);
    00530             int rid = entry->info.offset;
    00531
    00532             il += ril;
    00533             dl += entry->rdlen + entry->info.count;
    00534             /* XXX Legacy regions do not include the region tag and data. */
    00535             if (i == 0 && (h->flags & HEADERFLAG_LEGACY))
    00536                 il += 1;
    00537
    00538             /* Skip rest of entries in region, but account for dribbles. */
    00539             for (; i < h->indexUsed && entry->info.offset <= rid+1; i++, entry++) {
    00540                 if (entry->info.offset <= rid)
    00541                     /*@innercontinue@*/ continue;
    00542
    00543                 /* Alignment */
    00544                 type = entry->info.type;
    00545                 if (typeSizes[type] > 1) {
    00546                     unsigned diff;
    00547                     diff = typeSizes[type] - (dl % typeSizes[type]);
    00548                     if (diff != typeSizes[type]) {
    00549                         drlen += diff;
    00550                         pad += diff;
    00551                         dl += diff;
    00552                     }
    00553                 }
    00554
    00555                 ndribbles++;
    00556                 il++;
    00557                 drlen += entry->length;
    00558                 dl += entry->length;
    00559             }
    00560             i--;
    00561             entry--;
    00562             continue;
    00563         }
    00564
    00565         /* Ignore deleted drips. */
    00566         if (entry->data == NULL || entry->length <= 0)
    00567             continue;
    00568
    00569         /* Alignment */
    00570         type = entry->info.type;
    00571         if (typeSizes[type] > 1) {
    00572             unsigned diff;
    00573             diff = typeSizes[type] - (dl % typeSizes[type]);
    00574             if (diff != typeSizes[type]) {
    00575                 driplen += diff;
    00576                 pad += diff;
    00577                 dl += diff;
    00578             } else
    00579                 diff = 0;
    00580         }
    00581
    00582         ndrips++;
    00583         il++;
    00584         driplen += entry->length;
    00585         dl += entry->length;
    00586     }
    00587
    00588     /* Sanity checks on header intro. */
    00589     if (hdrchkTags(il) || hdrchkData(dl))
    00590         goto errxit;
    00591
    00592     len = sizeof(il) + sizeof(dl) + (il * sizeof(*pe)) + dl;
    00593
    00594     ei = xmalloc(len);
    00595     ei[0] = htonl(il);
    00596     ei[1] = htonl(dl);
    00597
    00598     pe = (entryInfo) &ei[2];
    00599     dataStart = te = (char *) (pe + il);
    00600
    00601     pad = 0;
    00602     for (i = 0, entry = h->index; i < h->indexUsed; i++, entry++) {
    00603         const char * src;
    00604 char *t;
    00605         int count;
    00606         int rdlen;
    00607
    00608         if (entry->data == NULL || entry->length <= 0)
    00609             continue;
    00610
    00611 t = te;
    00612         pe->tag = htonl(entry->info.tag);
    00613         pe->type = htonl(entry->info.type);
    00614         pe->count = htonl(entry->info.count);
    00615
    00616         if (ENTRY_IS_REGION(entry)) {
    00617             int_32 rdl = -entry->info.offset;   /* negative offset */
    00618             int_32 ril = rdl/sizeof(*pe) + ndribbles;
    00619             int rid = entry->info.offset;
    00620
    00621             src = (char *)entry->data;
    00622             rdlen = entry->rdlen;
    00623
    00624             /* XXX Legacy regions do not include the region tag and data. */
    00625             if (i == 0 && (h->flags & HEADERFLAG_LEGACY)) {
    00626                 int_32 stei[4];
    00627
    00628                 legacy = 1;
    00629                 memcpy(pe+1, src, rdl);
    00630                 memcpy(te, src + rdl, rdlen);
    00631                 te += rdlen;
    00632
    00633                 pe->offset = htonl(te - dataStart);
    00634                 stei[0] = pe->tag;
    00635                 stei[1] = pe->type;
    00636                 stei[2] = htonl(-rdl-entry->info.count);
    00637                 stei[3] = pe->count;
    00638                 memcpy(te, stei, entry->info.count);
    00639                 te += entry->info.count;
    00640                 ril++;
    00641                 rdlen += entry->info.count;
    00642
    00643                 count = regionSwab(NULL, ril, 0, pe, t, 0);
    00644                 if (count != rdlen)
    00645                     goto errxit;
    00646
    00647             } else {
    00648
    00649                 memcpy(pe+1, src + sizeof(*pe), ((ril-1) * sizeof(*pe)));
    00650                 memcpy(te, src + (ril * sizeof(*pe)), rdlen+entry->info.count+drlen);
    00651                 te += rdlen;
    00652                 {   /*@-castexpose@*/
    00653                     entryInfo se = (entryInfo)src;
    00654                     /*@=castexpose@*/
    00655                     int off = ntohl(se->offset);
    00656                     pe->offset = (off) ? htonl(te - dataStart) : htonl(off);
    00657                 }
    00658                 te += entry->info.count + drlen;
    00659
    00660                 count = regionSwab(NULL, ril, 0, pe, t, 0);
    00661                 if (count != (rdlen + entry->info.count + drlen))
    00662                     goto errxit;
    00663             }
    00664
    00665             /* Skip rest of entries in region. */
    00666             while (i < h->indexUsed && entry->info.offset <= rid+1) {
    00667                 i++;
    00668                 entry++;
    00669             }
    00670             i--;
    00671             entry--;
    00672             pe += ril;
    00673             continue;
    00674         }
    00675
    00676         /* Ignore deleted drips. */
    00677         if (entry->data == NULL || entry->length <= 0)
    00678             continue;
    00679
    00680         /* Alignment */
    00681         type = entry->info.type;
    00682         if (typeSizes[type] > 1) {
    00683             unsigned diff;
    00684             diff = typeSizes[type] - ((te - dataStart) % typeSizes[type]);
    00685             if (diff != typeSizes[type]) {
    00686                 memset(te, 0, diff);
    00687                 te += diff;
    00688                 pad += diff;
    00689             }
    00690         }
    00691
    00692         pe->offset = htonl(te - dataStart);
    00693
    00694         /* copy data w/ endian conversions */
    00695         switch (entry->info.type) {
    00696         case RPM_INT32_TYPE:
    00697             count = entry->info.count;
    00698             src = entry->data;
    00699             while (count--) {
    00700                 *((int_32 *)te) = htonl(*((int_32 *)src));
    00701                 /*@-sizeoftype@*/
    00702                 te += sizeof(int_32);
    00703                 src += sizeof(int_32);
    00704                 /*@=sizeoftype@*/
    00705             }
    00706             /*@switchbreak@*/ break;
    00707
    00708         case RPM_INT16_TYPE:
    00709             count = entry->info.count;
    00710             src = entry->data;
    00711             while (count--) {
    00712                 *((int_16 *)te) = htons(*((int_16 *)src));
    00713                 /*@-sizeoftype@*/
    00714                 te += sizeof(int_16);
    00715                 src += sizeof(int_16);
    00716                 /*@=sizeoftype@*/
    00717             }
    00718             /*@switchbreak@*/ break;
    00719
    00720         default:
    00721             memcpy(te, entry->data, entry->length);
    00722             te += entry->length;
    00723             /*@switchbreak@*/ break;
    00724         }
    00725         pe++;
    00726     }
    00727
    00728     /* Insure that there are no memcpy underruns/overruns. */
    00729     if (((char *)pe) != dataStart)
    00730         goto errxit;
    00731     if ((((char *)ei)+len) != te)
    00732         goto errxit;
    00733
    00734     if (lengthPtr)
    00735         *lengthPtr = len;
    00736
    00737     h->flags &= ~HEADERFLAG_SORTED;
    00738     headerSort(h);
    00739
    00740     return (void *) ei;
    00741
    00742 errxit:
    00743     /*@-usereleased@*/
    00744     ei = _free(ei);
    00745     /*@=usereleased@*/
    00746     return (void *) ei;
    00747 }
    00748
    00754 static /*@only@*/ /*@null@*/
    00755 void * headerUnload(Header h)
    00756         /*@modifies h @*/
    00757 {
    00758     int length;
    00759     void * uh = doHeaderUnload(h, &length);
    00760     return uh;
    00761 }
    00762
    00770 static /*@null@*/
    00771 indexEntry findEntry(/*@null@*/ Header h, int_32 tag, int_32 type)
    00772         /*@modifies h @*/
    00773 {
    00774     indexEntry entry, entry2, last;
    00775     struct indexEntry key;
    00776
    00777     if (h == NULL) return NULL;
    00778     if (!(h->flags & HEADERFLAG_SORTED)) headerSort(h);
    00779
    00780     key.info.tag = tag;
    00781
    00782     entry2 = entry =
    00783         bsearch(&key, h->index, h->indexUsed, sizeof(*h->index), indexCmp);
    00784     if (entry == NULL)
    00785         return NULL;
    00786
    00787     if (type == RPM_NULL_TYPE)
    00788         return entry;
    00789
    00790     /* look backwards */
    00791     while (entry->info.tag == tag && entry->info.type != type &&
    00792            entry > h->index) entry--;
    00793
    00794     if (entry->info.tag == tag && entry->info.type == type)
    00795         return entry;
    00796
    00797     last = h->index + h->indexUsed;
    00798     /*@-usereleased@*/ /* FIX: entry2 = entry. Code looks bogus as well. */
    00799     while (entry2->info.tag == tag && entry2->info.type != type &&
    00800            entry2 < last) entry2++;
    00801     /*@=usereleased@*/
    00802
    00803     if (entry->info.tag == tag && entry->info.type == type)
    00804         return entry;
    00805
    00806     return NULL;
    00807 }
    00808
    00818 static
    00819 int headerRemoveEntry(Header h, int_32 tag)
    00820         /*@modifies h @*/
    00821 {
    00822     indexEntry last = h->index + h->indexUsed;
    00823     indexEntry entry, first;
    00824     int ne;
    00825
    00826     entry = findEntry(h, tag, RPM_NULL_TYPE);
    00827     if (!entry) return 1;
    00828
    00829     /* Make sure entry points to the first occurence of this tag. */
    00830     while (entry > h->index && (entry - 1)->info.tag == tag)
    00831         entry--;
    00832
    00833     /* Free data for tags being removed. */
    00834     for (first = entry; first < last; first++) {
    00835         void * data;
    00836         if (first->info.tag != tag)
    00837             break;
    00838         data = first->data;
    00839         first->data = NULL;
    00840         first->length = 0;
    00841         if (ENTRY_IN_REGION(first))
    00842             continue;
    00843         data = _free(data);
    00844     }
    00845
    00846     ne = (first - entry);
    00847     if (ne > 0) {
    00848         h->indexUsed -= ne;
    00849         ne = last - first;
    00850         if (ne > 0)
    00851             memmove(entry, first, (ne * sizeof(*entry)));
    00852     }
    00853
    00854     return 0;
    00855 }
    00856
    00862 static /*@null@*/
    00863 Header headerLoad(/*@kept@*/ void * uh)
    00864         /*@modifies uh @*/
    00865 {
    00866     int_32 * ei = (int_32 *) uh;
    00867     int_32 il = ntohl(ei[0]);           /* index length */
    00868     int_32 dl = ntohl(ei[1]);           /* data length */
    00869     /*@-sizeoftype@*/
    00870     size_t pvlen = sizeof(il) + sizeof(dl) +
    00871                (il * sizeof(struct entryInfo)) + dl;
    00872     /*@=sizeoftype@*/
    00873     void * pv = uh;
    00874     Header h = NULL;
    00875     entryInfo pe;
    00876     char * dataStart;
    00877     indexEntry entry;
    00878     int rdlen;
    00879     int i;
    00880
    00881     /* Sanity checks on header intro. */
    00882     if (hdrchkTags(il) || hdrchkData(dl))
    00883         goto errxit;
    00884
    00885     ei = (int_32 *) pv;
    00886     /*@-castexpose@*/
    00887     pe = (entryInfo) &ei[2];
    00888     /*@=castexpose@*/
    00889     dataStart = (char *) (pe + il);
    00890
    00891     h = xcalloc(1, sizeof(*h));
    00892     /*@-assignexpose@*/
    00893     h->hv = *hdrVec;            /* structure assignment */
    00894     /*@=assignexpose@*/
    00895     /*@-assignexpose -kepttrans@*/
    00896     h->blob = uh;
    00897     /*@=assignexpose =kepttrans@*/
    00898     h->indexAlloced = il + 1;
    00899     h->indexUsed = il;
    00900     h->index = xcalloc(h->indexAlloced, sizeof(*h->index));
    00901     h->flags = HEADERFLAG_SORTED;
    00902     h->nrefs = 0;
    00903     h = headerLink(h);
    00904
    00905     /*
    00906      * XXX XFree86-libs, ash, and pdksh from Red Hat 5.2 have bogus
    00907      * %verifyscript tag that needs to be diddled.
    00908      */
    00909     if (ntohl(pe->tag) == 15 &&
    00910         ntohl(pe->type) == RPM_STRING_TYPE &&
    00911         ntohl(pe->count) == 1)
    00912     {
    00913         pe->tag = htonl(1079);
    00914     }
    00915
    00916     entry = h->index;
    00917     i = 0;
    00918     if (!(htonl(pe->tag) < HEADER_I18NTABLE)) {
    00919         h->flags |= HEADERFLAG_LEGACY;
    00920         entry->info.type = REGION_TAG_TYPE;
    00921         entry->info.tag = HEADER_IMAGE;
    00922         /*@-sizeoftype@*/
    00923         entry->info.count = REGION_TAG_COUNT;
    00924         /*@=sizeoftype@*/
    00925         entry->info.offset = ((char *)pe - dataStart); /* negative offset */
    00926
    00927         /*@-assignexpose@*/
    00928         entry->data = pe;
    00929         /*@=assignexpose@*/
    00930         entry->length = pvlen - sizeof(il) - sizeof(dl);
    00931         rdlen = regionSwab(entry+1, il, 0, pe, dataStart, entry->info.offset);
    00932 #if 0   /* XXX don't check, the 8/98 i18n bug fails here. */
    00933         if (rdlen != dl)
    00934             goto errxit;
    00935 #endif
    00936         entry->rdlen = rdlen;
    00937         entry++;
    00938         h->indexUsed++;
    00939     } else {
    00940         int nb = ntohl(pe->count);
    00941         int_32 rdl;
    00942         int_32 ril;
    00943
    00944         h->flags &= ~HEADERFLAG_LEGACY;
    00945
    00946         entry->info.type = htonl(pe->type);
    00947         if (entry->info.type < RPM_MIN_TYPE || entry->info.type > RPM_MAX_TYPE)
    00948             goto errxit;
    00949         entry->info.count = htonl(pe->count);
    00950
    00951         if (hdrchkTags(entry->info.count))
    00952             goto errxit;
    00953
    00954         {   int off = ntohl(pe->offset);
    00955
    00956             if (hdrchkData(off))
    00957                 goto errxit;
    00958             if (off) {
    00959                 int_32 * stei = memcpy(alloca(nb), dataStart + off, nb);
    00960                 rdl = -ntohl(stei[2]);  /* negative offset */
    00961                 ril = rdl/sizeof(*pe);
    00962                 if (hdrchkTags(ril) || hdrchkData(rdl))
    00963                     goto errxit;
    00964                 entry->info.tag = htonl(pe->tag);
    00965             } else {
    00966                 ril = il;
    00967                 /*@-sizeoftype@*/
    00968                 rdl = (ril * sizeof(struct entryInfo));
    00969                 /*@=sizeoftype@*/
    00970                 entry->info.tag = HEADER_IMAGE;
    00971             }
    00972         }
    00973         entry->info.offset = -rdl;      /* negative offset */
    00974
    00975         /*@-assignexpose@*/
    00976         entry->data = pe;
    00977         /*@=assignexpose@*/
    00978         entry->length = pvlen - sizeof(il) - sizeof(dl);
    00979         rdlen = regionSwab(entry+1, ril-1, 0, pe+1, dataStart, entry->info.offset);
    00980         if (rdlen < 0)
    00981             goto errxit;
    00982         entry->rdlen = rdlen;
    00983
    00984         if (ril < h->indexUsed) {
    00985             indexEntry newEntry = entry + ril;
    00986             int ne = (h->indexUsed - ril);
    00987             int rid = entry->info.offset+1;
    00988             int rc;
    00989
    00990             /* Load dribble entries from region. */
    00991             rc = regionSwab(newEntry, ne, 0, pe+ril, dataStart, rid);
    00992             if (rc < 0)
    00993                 goto errxit;
    00994             rdlen += rc;
    00995
    00996           { indexEntry firstEntry = newEntry;
    00997             int save = h->indexUsed;
    00998             int j;
    00999
    01000             /* Dribble entries replace duplicate region entries. */
    01001             h->indexUsed -= ne;
    01002             for (j = 0; j < ne; j++, newEntry++) {
    01003                 (void) headerRemoveEntry(h, newEntry->info.tag);
    01004                 if (newEntry->info.tag == HEADER_BASENAMES)
    01005                     (void) headerRemoveEntry(h, HEADER_OLDFILENAMES);
    01006             }
    01007
    01008             /* If any duplicate entries were replaced, move new entries down. */
    01009             if (h->indexUsed < (save - ne)) {
    01010                 memmove(h->index + h->indexUsed, firstEntry,
    01011                         (ne * sizeof(*entry)));
    01012             }
    01013             h->indexUsed += ne;
    01014           }
    01015         }
    01016     }
    01017
    01018     h->flags &= ~HEADERFLAG_SORTED;
    01019     headerSort(h);
    01020
    01021     /*@-globstate -observertrans @*/
    01022     return h;
    01023     /*@=globstate =observertrans @*/
    01024
    01025 errxit:
    01026     /*@-usereleased@*/
    01027     if (h) {
    01028         h->index = _free(h->index);
    01029         /*@-refcounttrans@*/
    01030         h = _free(h);
    01031         /*@=refcounttrans@*/
    01032     }
    01033     /*@=usereleased@*/
    01034     /*@-refcounttrans -globstate@*/
    01035     return h;
    01036     /*@=refcounttrans =globstate@*/
    01037 }
    01038
    01046 static /*@null@*/
    01047 Header headerReload(/*@only@*/ Header h, int tag)
    01048         /*@modifies h @*/
    01049 {
    01050     Header nh;
    01051     int length;
    01052     /*@-onlytrans@*/
    01053     void * uh = doHeaderUnload(h, &length);
    01054
    01055     h = headerFree(h);
    01056     /*@=onlytrans@*/
    01057     if (uh == NULL)
    01058         return NULL;
    01059     nh = headerLoad(uh);
    01060     if (nh == NULL) {
    01061         uh = _free(uh);
    01062         return NULL;
    01063     }
    01064     if (nh->flags & HEADERFLAG_ALLOCATED)
    01065         uh = _free(uh);
    01066     nh->flags |= HEADERFLAG_ALLOCATED;
    01067     if (ENTRY_IS_REGION(nh->index)) {
    01068         if (tag == HEADER_SIGNATURES || tag == HEADER_IMMUTABLE)
    01069             nh->index[0].info.tag = tag;
    01070     }
    01071     return nh;
    01072 }
    01073
    01079 static /*@null@*/
    01080 Header headerCopyLoad(const void * uh)
    01081         /*@*/
    01082 {
    01083     int_32 * ei = (int_32 *) uh;
    01084     int_32 il = ntohl(ei[0]);           /* index length */
    01085     int_32 dl = ntohl(ei[1]);           /* data length */
    01086     /*@-sizeoftype@*/
    01087     size_t pvlen = sizeof(il) + sizeof(dl) +
    01088                         (il * sizeof(struct entryInfo)) + dl;
    01089     /*@=sizeoftype@*/
    01090     void * nuh = NULL;
    01091     Header h = NULL;
    01092
    01093     /* Sanity checks on header intro. */
    01094     /*@-branchstate@*/
    01095     if (!(hdrchkTags(il) || hdrchkData(dl)) && pvlen < headerMaxbytes) {
    01096         nuh = memcpy(xmalloc(pvlen), uh, pvlen);
    01097         if ((h = headerLoad(nuh)) != NULL)
    01098             h->flags |= HEADERFLAG_ALLOCATED;
    01099     }
    01100     /*@=branchstate@*/
    01101     /*@-branchstate@*/
    01102     if (h == NULL)
    01103         nuh = _free(nuh);
    01104     /*@=branchstate@*/
    01105     return h;
    01106 }
    01107
    01114 static /*@null@*/
    01115 Header headerRead(FD_t fd, enum hMagic magicp)
    01116         /*@modifies fd @*/
    01117 {
    01118     int_32 block[4];
    01119     int_32 reserved;
    01120     int_32 * ei = NULL;
    01121     int_32 il;
    01122     int_32 dl;
    01123     int_32 magic;
    01124     Header h = NULL;
    01125     size_t len;
    01126     int i;
    01127
    01128     memset(block, 0, sizeof(block));
    01129     i = 2;
    01130     if (magicp == HEADER_MAGIC_YES)
    01131         i += 2;
    01132
    01133     /*@-type@*/ /* FIX: cast? */
    01134     if (timedRead(fd, (char *)block, i*sizeof(*block)) != (i * sizeof(*block)))
    01135         goto exit;
    01136     /*@=type@*/
    01137
    01138     i = 0;
    01139
    01140     if (magicp == HEADER_MAGIC_YES) {
    01141         magic = block[i++];
    01142         if (memcmp(&magic, header_magic, sizeof(magic)))
    01143             goto exit;
    01144         reserved = block[i++];
    01145     }
    01146
    01147     il = ntohl(block[i]);       i++;
    01148     dl = ntohl(block[i]);       i++;
    01149
    01150     /*@-sizeoftype@*/
    01151     len = sizeof(il) + sizeof(dl) + (il * sizeof(struct entryInfo)) + dl;
    01152     /*@=sizeoftype@*/
    01153
    01154     /* Sanity checks on header intro. */
    01155     if (hdrchkTags(il) || hdrchkData(dl) || len > headerMaxbytes)
    01156         goto exit;
    01157
    01158     ei = xmalloc(len);
    01159     ei[0] = htonl(il);
    01160     ei[1] = htonl(dl);
    01161     len -= sizeof(il) + sizeof(dl);
    01162
    01163     /*@-type@*/ /* FIX: cast? */
    01164     if (timedRead(fd, (char *)&ei[2], len) != len)
    01165         goto exit;
    01166     /*@=type@*/
    01167
    01168     h = headerLoad(ei);
    01169
    01170 exit:
    01171     if (h) {
    01172         if (h->flags & HEADERFLAG_ALLOCATED)
    01173             ei = _free(ei);
    01174         h->flags |= HEADERFLAG_ALLOCATED;
    01175     } else if (ei)
    01176         ei = _free(ei);
    01177     /*@-mustmod@*/      /* FIX: timedRead macro obscures annotation */
    01178     return h;
    01179     /*@-mustmod@*/
    01180 }
    01181
    01189 static
    01190 int headerWrite(FD_t fd, /*@null@*/ Header h, enum hMagic magicp)
    01191         /*@globals fileSystem @*/
    01192         /*@modifies fd, h, fileSystem @*/
    01193 {
    01194     ssize_t nb;
    01195     int length;
    01196     const void * uh;
    01197
    01198     if (h == NULL)
    01199         return 1;
    01200     uh = doHeaderUnload(h, &length);
    01201     if (uh == NULL)
    01202         return 1;
    01203     switch (magicp) {
    01204     case HEADER_MAGIC_YES:
    01205         /*@-sizeoftype@*/
    01206         nb = Fwrite(header_magic, sizeof(char), sizeof(header_magic), fd);
    01207         /*@=sizeoftype@*/
    01208         if (nb != sizeof(header_magic))
    01209             goto exit;
    01210         break;
    01211     case HEADER_MAGIC_NO:
    01212         break;
    01213     }
    01214
    01215     /*@-sizeoftype@*/
    01216     nb = Fwrite(uh, sizeof(char), length, fd);
    01217     /*@=sizeoftype@*/
    01218
    01219 exit:
    01220     uh = _free(uh);
    01221     return (nb == length ? 0 : 1);
    01222 }
    01223
    01230 static
    01231 int headerIsEntry(/*@null@*/Header h, int_32 tag)
    01232         /*@*/
    01233 {
    01234     /*@-mods@*/         /*@ FIX: h modified by sort. */
    01235     return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);
    01236     /*@=mods@*/
    01237 }
    01238
    01249 static int copyEntry(const indexEntry entry,
    01250                 /*@null@*/ /*@out@*/ hTYP_t type,
    01251                 /*@null@*/ /*@out@*/ hPTR_t * p,
    01252                 /*@null@*/ /*@out@*/ hCNT_t c,
    01253                 int minMem)
    01254         /*@modifies *type, *p, *c @*/
    01255 {
    01256     int_32 count = entry->info.count;
    01257     int rc = 1;         /* XXX 1 on success. */
    01258
    01259     if (p)
    01260     switch (entry->info.type) {
    01261     case RPM_BIN_TYPE:
    01262         /*
    01263          * XXX This only works for
    01264          * XXX  "sealed" HEADER_IMMUTABLE/HEADER_SIGNATURES/HEADER_IMAGE.
    01265          * XXX This will *not* work for unsealed legacy HEADER_IMAGE (i.e.
    01266          * XXX a legacy header freshly read, but not yet unloaded to the rpmdb).
    01267          */
    01268         if (ENTRY_IS_REGION(entry)) {
    01269             int_32 * ei = ((int_32 *)entry->data) - 2;
    01270             /*@-castexpose@*/
    01271             entryInfo pe = (entryInfo) (ei + 2);
    01272             /*@=castexpose@*/
    01273             char * dataStart = (char *) (pe + ntohl(ei[0]));
    01274             int_32 rdl = -entry->info.offset;   /* negative offset */
    01275             int_32 ril = rdl/sizeof(*pe);
    01276
    01277             /*@-sizeoftype@*/
    01278             rdl = entry->rdlen;
    01279             count = 2 * sizeof(*ei) + (ril * sizeof(*pe)) + rdl;
    01280             if (entry->info.tag == HEADER_IMAGE) {
    01281                 ril -= 1;
    01282                 pe += 1;
    01283             } else {
    01284                 count += REGION_TAG_COUNT;
    01285                 rdl += REGION_TAG_COUNT;
    01286             }
    01287
    01288             *p = xmalloc(count);
    01289             ei = (int_32 *) *p;
    01290             ei[0] = htonl(ril);
    01291             ei[1] = htonl(rdl);
    01292
    01293             /*@-castexpose@*/
    01294             pe = (entryInfo) memcpy(ei + 2, pe, (ril * sizeof(*pe)));
    01295             /*@=castexpose@*/
    01296
    01297             dataStart = (char *) memcpy(pe + ril, dataStart, rdl);
    01298             /*@=sizeoftype@*/
    01299
    01300             rc = regionSwab(NULL, ril, 0, pe, dataStart, 0);
    01301             /* XXX 1 on success. */
    01302             rc = (rc < 0) ? 0 : 1;
    01303         } else {
    01304             count = entry->length;
    01305             *p = (!minMem
    01306                 ? memcpy(xmalloc(count), entry->data, count)
    01307                 : entry->data);
    01308         }
    01309         break;
    01310     case RPM_STRING_TYPE:
    01311         if (count == 1) {
    01312             *p = entry->data;
    01313             break;
    01314         }
    01315         /*@fallthrough@*/
    01316     case RPM_STRING_ARRAY_TYPE:
    01317     case RPM_I18NSTRING_TYPE:
    01318     {   const char ** ptrEntry;
    01319         /*@-sizeoftype@*/
    01320         int tableSize = count * sizeof(char *);
    01321         /*@=sizeoftype@*/
    01322         char * t;
    01323         int i;
    01324
    01325         /*@-mods@*/
    01326         if (minMem) {
    01327             *p = xmalloc(tableSize);
    01328             ptrEntry = (const char **) *p;
    01329             t = entry->data;
    01330         } else {
    01331             t = xmalloc(tableSize + entry->length);
    01332             *p = (void *)t;
    01333             ptrEntry = (const char **) *p;
    01334             t += tableSize;
    01335             memcpy(t, entry->data, entry->length);
    01336         }
    01337         /*@=mods@*/
    01338         for (i = 0; i < count; i++) {
    01339             *ptrEntry++ = t;
    01340             t = strchr(t, 0);
    01341             t++;
    01342         }
    01343     }   break;
    01344
    01345     default:
    01346         *p = entry->data;
    01347         break;
    01348     }
    01349     if (type) *type = entry->info.type;
    01350     if (c) *c = count;
    01351     return rc;
    01352 }
    01353
    01372 static int headerMatchLocale(const char *td, const char *l, const char *le)
    01373         /*@*/
    01374 {
    01375     const char *fe;
    01376
    01377
    01378 #if 0
    01379   { const char *s, *ll, *CC, *EE, *dd;
    01380     char *lbuf, *t.
    01381
    01382     /* Copy the buffer and parse out components on the fly. */
    01383     lbuf = alloca(le - l + 1);
    01384     for (s = l, ll = t = lbuf; *s; s++, t++) {
    01385         switch (*s) {
    01386         case '_':
    01387             *t = '\0';
    01388             CC = t + 1;
    01389             break;
    01390         case '.':
    01391             *t = '\0';
    01392             EE = t + 1;
    01393             break;
    01394         case '@':
    01395             *t = '\0';
    01396             dd = t + 1;
    01397             break;
    01398         default:
    01399             *t = *s;
    01400             break;
    01401         }
    01402     }
    01403
    01404     if (ll)     /* ISO language should be lower case */
    01405         for (t = ll; *t; t++)   *t = tolower(*t);
    01406     if (CC)     /* ISO country code should be upper case */
    01407         for (t = CC; *t; t++)   *t = toupper(*t);
    01408
    01409     /* There are a total of 16 cases to attempt to match. */
    01410   }
    01411 #endif
    01412
    01413     /* First try a complete match. */
    01414     if (strlen(td) == (le-l) && !strncmp(td, l, (le - l)))
    01415         return 1;
    01416
    01417     /* Next, try stripping optional dialect and matching.  */
    01418     for (fe = l; fe < le && *fe != '@'; fe++)
    01419         {};
    01420     if (fe < le && !strncmp(td, l, (fe - l)))
    01421         return 1;
    01422
    01423     /* Next, try stripping optional codeset and matching.  */
    01424     for (fe = l; fe < le && *fe != '.'; fe++)
    01425         {};
    01426     if (fe < le && !strncmp(td, l, (fe - l)))
    01427         return 1;
    01428
    01429     /* Finally, try stripping optional country code and matching. */
    01430     for (fe = l; fe < le && *fe != '_'; fe++)
    01431         {};
    01432     if (fe < le && !strncmp(td, l, (fe - l)))
    01433         return 1;
    01434
    01435     return 0;
    01436 }
    01437
    01444 /*@dependent@*/ /*@exposed@*/ static char *
    01445 headerFindI18NString(Header h, indexEntry entry)
    01446         /*@*/
    01447 {
    01448     const char *lang, *l, *le;
    01449     indexEntry table;
    01450
    01451     /* XXX Drepper sez' this is the order. */
    01452     if ((lang = getenv("LANGUAGE")) == NULL &&
    01453         (lang = getenv("LC_ALL")) == NULL &&
    01454         (lang = getenv("LC_MESSAGES")) == NULL &&
    01455         (lang = getenv("LANG")) == NULL)
    01456             return entry->data;
    01457
    01458     /*@-mods@*/
    01459     if ((table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
    01460         return entry->data;
    01461     /*@=mods@*/
    01462
    01463     for (l = lang; *l != '\0'; l = le) {
    01464         const char *td;
    01465         char *ed;
    01466         int langNum;
    01467
    01468         while (*l && *l == ':')                 /* skip leading colons */
    01469             l++;
    01470         if (*l == '\0')
    01471             break;
    01472         for (le = l; *le && *le != ':'; le++)   /* find end of this locale */
    01473             {};
    01474
    01475         /* For each entry in the header ... */
    01476         for (langNum = 0, td = table->data, ed = entry->data;
    01477              langNum < entry->info.count;
    01478              langNum++, td += strlen(td) + 1, ed += strlen(ed) + 1) {
    01479
    01480                 if (headerMatchLocale(td, l, le))
    01481                     return ed;
    01482
    01483         }
    01484     }
    01485
    01486     return entry->data;
    01487 }
    01488
    01499 static int intGetEntry(Header h, int_32 tag,
    01500                 /*@null@*/ /*@out@*/ hTAG_t type,
    01501                 /*@null@*/ /*@out@*/ hPTR_t * p,
    01502                 /*@null@*/ /*@out@*/ hCNT_t c,
    01503                 int minMem)
    01504         /*@modifies *type, *p, *c @*/
    01505 {
    01506     indexEntry entry;
    01507     int rc;
    01508
    01509     /* First find the tag */
    01510     /*@-mods@*/         /*@ FIX: h modified by sort. */
    01511     entry = findEntry(h, tag, RPM_NULL_TYPE);
    01512     /*@mods@*/
    01513     if (entry == NULL) {
    01514         if (type) type = 0;
    01515         if (p) *p = NULL;
    01516         if (c) *c = 0;
    01517         return 0;
    01518     }
    01519
    01520     switch (entry->info.type) {
    01521     case RPM_I18NSTRING_TYPE:
    01522         rc = 1;
    01523         if (type) *type = RPM_STRING_TYPE;
    01524         if (c) *c = 1;
    01525         /*@-dependenttrans@*/
    01526         if (p) *p = headerFindI18NString(h, entry);
    01527         /*@=dependenttrans@*/
    01528         break;
    01529     default:
    01530         rc = copyEntry(entry, type, p, c, minMem);
    01531         break;
    01532     }
    01533
    01534     /* XXX 1 on success */
    01535     return ((rc == 1) ? 1 : 0);
    01536 }
    01537
    01545 static /*@null@*/ void * headerFreeTag(/*@unused@*/ Header h,
    01546                 /*@only@*/ /*@null@*/ const void * data, rpmTagType type)
    01547         /*@modifies data @*/
    01548 {
    01549     if (data) {
    01550         /*@-branchstate@*/
    01551         if (type == -1 ||
    01552             type == RPM_STRING_ARRAY_TYPE ||
    01553             type == RPM_I18NSTRING_TYPE ||
    01554             type == RPM_BIN_TYPE)
    01555                 data = _free(data);
    01556         /*@=branchstate@*/
    01557     }
    01558     return NULL;
    01559 }
    01560
    01574 static
    01575 int headerGetEntry(Header h, int_32 tag,
    01576                         /*@null@*/ /*@out@*/ hTYP_t type,
    01577                         /*@null@*/ /*@out@*/ void ** p,
    01578                         /*@null@*/ /*@out@*/ hCNT_t c)
    01579         /*@modifies *type, *p, *c @*/
    01580 {
    01581     return intGetEntry(h, tag, type, (hPTR_t *)p, c, 0);
    01582 }
    01583
    01596 static
    01597 int headerGetEntryMinMemory(Header h, int_32 tag,
    01598                         /*@null@*/ /*@out@*/ hTYP_t type,
    01599                         /*@null@*/ /*@out@*/ hPTR_t * p,
    01600                         /*@null@*/ /*@out@*/ hCNT_t c)
    01601         /*@modifies *type, *p, *c @*/
    01602 {
    01603     return intGetEntry(h, tag, type, p, c, 1);
    01604 }
    01605
    01606 int headerGetRawEntry(Header h, int_32 tag, int_32 * type, hPTR_t * p,
    01607                 int_32 * c)
    01608 {
    01609     indexEntry entry;
    01610     int rc;
    01611
    01612     if (p == NULL) return headerIsEntry(h, tag);
    01613
    01614     /* First find the tag */
    01615     /*@-mods@*/         /*@ FIX: h modified by sort. */
    01616     entry = findEntry(h, tag, RPM_NULL_TYPE);
    01617     /*@=mods@*/
    01618     if (!entry) {
    01619         if (p) *p = NULL;
    01620         if (c) *c = 0;
    01621         return 0;
    01622     }
    01623
    01624     rc = copyEntry(entry, type, p, c, 0);
    01625
    01626     /* XXX 1 on success */
    01627     return ((rc == 1) ? 1 : 0);
    01628 }
    01629
    01632 static void copyData(int_32 type, /*@out@*/ void * dstPtr, const void * srcPtr,
    01633                 int_32 c, int dataLength)
    01634         /*@modifies *dstPtr @*/
    01635 {
    01636     const char ** src;
    01637     char * dst;
    01638     int i;
    01639
    01640     switch (type) {
    01641     case RPM_STRING_ARRAY_TYPE:
    01642     case RPM_I18NSTRING_TYPE:
    01643         /* Otherwise, p is char** */
    01644         i = c;
    01645         src = (const char **) srcPtr;
    01646         dst = dstPtr;
    01647         while (i--) {
    01648             if (*src) {
    01649                 int len = strlen(*src) + 1;
    01650                 memcpy(dst, *src, len);
    01651                 dst += len;
    01652             }
    01653             src++;
    01654         }
    01655         break;
    01656
    01657     default:
    01658         memmove(dstPtr, srcPtr, dataLength);
    01659         break;
    01660     }
    01661 }
    01662
    01671 static void * grabData(int_32 type, hPTR_t p, int_32 c,
    01672                 /*@out@*/ int * lengthPtr)
    01673         /*@modifies *lengthPtr @*/
    01674 {
    01675     int length = dataLength(type, p, c, 0);
    01676     void * data = xmalloc(length);
    01677
    01678     copyData(type, data, p, c, length);
    01679
    01680     if (lengthPtr)
    01681         *lengthPtr = length;
    01682     return data;
    01683 }
    01684
    01699 static
    01700 int headerAddEntry(Header h, int_32 tag, int_32 type, const void * p, int_32 c)
    01701         /*@modifies h @*/
    01702 {
    01703     indexEntry entry;
    01704
    01705     /* Count must always be >= 1 for headerAddEntry. */
    01706     if (c <= 0)
    01707         return 0;
    01708
    01709     /* Allocate more index space if necessary */
    01710     if (h->indexUsed == h->indexAlloced) {
    01711         h->indexAlloced += INDEX_MALLOC_SIZE;
    01712         h->index = xrealloc(h->index, h->indexAlloced * sizeof(*h->index));
    01713     }
    01714
    01715     /* Fill in the index */
    01716     entry = h->index + h->indexUsed;
    01717     entry->info.tag = tag;
    01718     entry->info.type = type;
    01719     entry->info.count = c;
    01720     entry->info.offset = 0;
    01721     entry->data = grabData(type, p, c, &entry->length);
    01722
    01723     if (h->indexUsed > 0 && tag < h->index[h->indexUsed-1].info.tag)
    01724         h->flags &= ~HEADERFLAG_SORTED;
    01725     h->indexUsed++;
    01726
    01727     return 1;
    01728 }
    01729
    01744 static
    01745 int headerAppendEntry(Header h, int_32 tag, int_32 type,
    01746                 const void * p, int_32 c)
    01747         /*@modifies h @*/
    01748 {
    01749     indexEntry entry;
    01750     int length;
    01751
    01752     /* First find the tag */
    01753     entry = findEntry(h, tag, type);
    01754     if (!entry)
    01755         return 0;
    01756
    01757     if (type == RPM_STRING_TYPE || type == RPM_I18NSTRING_TYPE) {
    01758         /* we can't do this */
    01759         return 0;
    01760     }
    01761
    01762     length = dataLength(type, p, c, 0);
    01763
    01764     if (ENTRY_IN_REGION(entry)) {
    01765         char * t = xmalloc(entry->length + length);
    01766         memcpy(t, entry->data, entry->length);
    01767         entry->data = t;
    01768         entry->info.offset = 0;
    01769     } else
    01770         entry->data = xrealloc(entry->data, entry->length + length);
    01771
    01772     copyData(type, ((char *) entry->data) + entry->length, p, c, length);
    01773
    01774     entry->length += length;
    01775
    01776     entry->info.count += c;
    01777
    01778     return 1;
    01779 }
    01780
    01791 static
    01792 int headerAddOrAppendEntry(Header h, int_32 tag, int_32 type,
    01793                 const void * p, int_32 c)
    01794         /*@modifies h @*/
    01795 {
    01796     return (findEntry(h, tag, type)
    01797         ? headerAppendEntry(h, tag, type, p, c)
    01798         : headerAddEntry(h, tag, type, p, c));
    01799 }
    01800
    01821 static
    01822 int headerAddI18NString(Header h, int_32 tag, const char * string,
    01823                 const char * lang)
    01824         /*@modifies h @*/
    01825 {
    01826     indexEntry table, entry;
    01827     const char ** strArray;
    01828     int length;
    01829     int ghosts;
    01830     int i, langNum;
    01831     char * buf;
    01832
    01833     table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
    01834     entry = findEntry(h, tag, RPM_I18NSTRING_TYPE);
    01835
    01836     if (!table && entry)
    01837         return 0;               /* this shouldn't ever happen!! */
    01838
    01839     if (!table && !entry) {
    01840         const char * charArray[2];
    01841         int count = 0;
    01842         if (!lang || (lang[0] == 'C' && lang[1] == '\0')) {
    01843             /*@-observertrans -readonlytrans@*/
    01844             charArray[count++] = "C";
    01845             /*@=observertrans =readonlytrans@*/
    01846         } else {
    01847             /*@-observertrans -readonlytrans@*/
    01848             charArray[count++] = "C";
    01849             /*@=observertrans =readonlytrans@*/
    01850             charArray[count++] = lang;
    01851         }
    01852         if (!headerAddEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE,
    01853                         &charArray, count))
    01854             return 0;
    01855         table = findEntry(h, HEADER_I18NTABLE, RPM_STRING_ARRAY_TYPE);
    01856     }
    01857
    01858     if (!table)
    01859         return 0;
    01860     /*@-branchstate@*/
    01861     if (!lang) lang = "C";
    01862     /*@=branchstate@*/
    01863
    01864     {   const char * l = table->data;
    01865         for (langNum = 0; langNum < table->info.count; langNum++) {
    01866             if (!strcmp(l, lang)) break;
    01867             l += strlen(l) + 1;
    01868         }
    01869     }
    01870
    01871     if (langNum >= table->info.count) {
    01872         length = strlen(lang) + 1;
    01873         if (ENTRY_IN_REGION(table)) {
    01874             char * t = xmalloc(table->length + length);
    01875             memcpy(t, table->data, table->length);
    01876             table->data = t;
    01877             table->info.offset = 0;
    01878         } else
    01879             table->data = xrealloc(table->data, table->length + length);
    01880         memmove(((char *)table->data) + table->length, lang, length);
    01881         table->length += length;
    01882         table->info.count++;
    01883     }
    01884
    01885     if (!entry) {
    01886         strArray = alloca(sizeof(*strArray) * (langNum + 1));
    01887         for (i = 0; i < langNum; i++)
    01888             strArray[i] = "";
    01889         strArray[langNum] = string;
    01890         return headerAddEntry(h, tag, RPM_I18NSTRING_TYPE, strArray,
    01891                                 langNum + 1);
    01892     } else if (langNum >= entry->info.count) {
    01893         ghosts = langNum - entry->info.count;
    01894
    01895         length = strlen(string) + 1 + ghosts;
    01896         if (ENTRY_IN_REGION(entry)) {
    01897             char * t = xmalloc(entry->length + length);
    01898             memcpy(t, entry->data, entry->length);
    01899             entry->data = t;
    01900             entry->info.offset = 0;
    01901         } else
    01902             entry->data = xrealloc(entry->data, entry->length + length);
    01903
    01904         memset(((char *)entry->data) + entry->length, '\0', ghosts);
    01905         memmove(((char *)entry->data) + entry->length + ghosts, string, strlen(string)+1);
    01906
    01907         entry->length += length;
    01908         entry->info.count = langNum + 1;
    01909     } else {
    01910         char *b, *be, *e, *ee, *t;
    01911         size_t bn, sn, en;
    01912
    01913         /* Set beginning/end pointers to previous data */
    01914         b = be = e = ee = entry->data;
    01915         for (i = 0; i < table->info.count; i++) {
    01916             if (i == langNum)
    01917                 be = ee;
    01918             ee += strlen(ee) + 1;
    01919             if (i == langNum)
    01920                 e  = ee;
    01921         }
    01922
    01923         /* Get storage for new buffer */
    01924         bn = (be-b);
    01925         sn = strlen(string) + 1;
    01926         en = (ee-e);
    01927         length = bn + sn + en;
    01928         t = buf = xmalloc(length);
    01929
    01930         /* Copy values into new storage */
    01931         memcpy(t, b, bn);
    01932         t += bn;
    01933 /*@-mayaliasunique@*/
    01934         memcpy(t, string, sn);
    01935         t += sn;
    01936         memcpy(t, e, en);
    01937         t += en;
    01938 /*@=mayaliasunique@*/
    01939
    01940         /* Replace I18N string array */
    01941         entry->length -= strlen(be) + 1;
    01942         entry->length += sn;
    01943
    01944         if (ENTRY_IN_REGION(entry)) {
    01945             entry->info.offset = 0;
    01946         } else
    01947             entry->data = _free(entry->data);
    01948         /*@-dependenttrans@*/
    01949         entry->data = buf;
    01950         /*@=dependenttrans@*/
    01951     }
    01952
    01953     return 0;
    01954 }
    01955
    01966 static
    01967 int headerModifyEntry(Header h, int_32 tag, int_32 type,
    01968                         const void * p, int_32 c)
    01969         /*@modifies h @*/
    01970 {
    01971     indexEntry entry;
    01972     void * oldData;
    01973
    01974     /* First find the tag */
    01975     entry = findEntry(h, tag, type);
    01976     if (!entry)
    01977         return 0;
    01978
    01979     /* make sure entry points to the first occurence of this tag */
    01980     while (entry > h->index && (entry - 1)->info.tag == tag)
    01981         entry--;
    01982
    01983     /* free after we've grabbed the new data in case the two are intertwined;
    01984        that's a bad idea but at least we won't break */
    01985     oldData = entry->data;
    01986
    01987     entry->info.count = c;
    01988     entry->info.type = type;
    01989     entry->data = grabData(type, p, c, &entry->length);
    01990
    01991     /*@-branchstate@*/
    01992     if (ENTRY_IN_REGION(entry)) {
    01993         entry->info.offset = 0;
    01994     } else
    01995         oldData = _free(oldData);
    01996     /*@=branchstate@*/
    01997
    01998     return 1;
    01999 }
    02000
    02003 static char escapedChar(const char ch)  /*@*/
    02004 {
    02005     switch (ch) {
    02006     case 'a':   return '\a';
    02007     case 'b':   return '\b';
    02008     case 'f':   return '\f';
    02009     case 'n':   return '\n';
    02010     case 'r':   return '\r';
    02011     case 't':   return '\t';
    02012     case 'v':   return '\v';
    02013     default:    return ch;
    02014     }
    02015 }
    02016
    02023 static /*@null@*/ sprintfToken
    02024 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
    02025         /*@modifies *format @*/
    02026 {
    02027     int i;
    02028
    02029     if (format == NULL) return NULL;
    02030     for (i = 0; i < num; i++) {
    02031         switch (format[i].type) {
    02032         case PTOK_ARRAY:
    02033             format[i].u.array.format =
    02034                 freeFormat(format[i].u.array.format,
    02035                         format[i].u.array.numTokens);
    02036             /*@switchbreak@*/ break;
    02037         case PTOK_COND:
    02038             format[i].u.cond.ifFormat =
    02039                 freeFormat(format[i].u.cond.ifFormat,
    02040                         format[i].u.cond.numIfTokens);
    02041             format[i].u.cond.elseFormat =
    02042                 freeFormat(format[i].u.cond.elseFormat,
    02043                         format[i].u.cond.numElseTokens);
    02044             /*@switchbreak@*/ break;
    02045         case PTOK_NONE:
    02046         case PTOK_TAG:
    02047         case PTOK_STRING:
    02048         default:
    02049             /*@switchbreak@*/ break;
    02050         }
    02051     }
    02052     format = _free(format);
    02053     return NULL;
    02054 }
    02055
    02058 static void findTag(char * name, const headerTagTableEntry tags,
    02059                     const headerSprintfExtension extensions,
    02060                     /*@out@*/ headerTagTableEntry * tagMatch,
    02061                     /*@out@*/ headerSprintfExtension * extMatch)
    02062         /*@modifies *tagMatch, *extMatch @*/
    02063 {
    02064     headerTagTableEntry entry;
    02065     headerSprintfExtension ext;
    02066     const char * tagname;
    02067
    02068     *tagMatch = NULL;
    02069     *extMatch = NULL;
    02070
    02071     if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
    02072         char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
    02073         (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
    02074         tagname = t;
    02075     } else {
    02076         tagname = name;
    02077     }
    02078
    02079     /* Search extensions first to permit overriding header tags. */
    02080     ext = extensions;
    02081     while (ext->type != HEADER_EXT_LAST) {
    02082         if (ext->name != NULL && ext->type == HEADER_EXT_TAG
    02083         && !xstrcasecmp(ext->name, tagname))
    02084             break;
    02085
    02086         if (ext->type == HEADER_EXT_MORE)
    02087             ext = ext->u.more;
    02088         else
    02089             ext++;
    02090     }
    02091
    02092     if (ext->type == HEADER_EXT_TAG) {
    02093         *extMatch = ext;
    02094         return;
    02095     }
    02096
    02097     /* Search header tags. */
    02098     for (entry = tags; entry->name; entry++)
    02099         if (entry->name && !xstrcasecmp(entry->name, tagname))
    02100             break;
    02101
    02102     if (entry->name) {
    02103         *tagMatch = entry;
    02104         return;
    02105     }
    02106 }
    02107
    02108 /* forward ref */
    02109 static int parseExpression(sprintfToken token, char * str,
    02110                 const headerTagTableEntry tags,
    02111                 const headerSprintfExtension extensions,
    02112                 /*@out@*/char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
    02113         /*@modifies str, *str, *token, *endPtr, *errmsg @*/;
    02114
    02117 static int parseFormat(char * str, const headerTagTableEntry tags,
    02118                 const headerSprintfExtension extensions,
    02119                 /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
    02120                 /*@null@*/ /*@out@*/ char ** endPtr, int state,
    02121                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
    02122         /*@modifies str, *str, *formatPtr, *numTokensPtr, *endPtr, *errmsg @*/
    02123 {
    02124     char * chptr, * start, * next, * dst;
    02125     sprintfToken format;
    02126     int numTokens;
    02127     int currToken;
    02128     headerTagTableEntry tag;
    02129     headerSprintfExtension ext;
    02130     int i;
    02131     int done = 0;
    02132
    02133     /* upper limit on number of individual formats */
    02134     numTokens = 0;
    02135     for (chptr = str; *chptr != '\0'; chptr++)
    02136         if (*chptr == '%') numTokens++;
    02137     numTokens = numTokens * 2 + 1;
    02138
    02139     format = xcalloc(numTokens, sizeof(*format));
    02140     if (endPtr) *endPtr = NULL;
    02141
    02142     /*@-infloops@*/ /* LCL: can't detect done termination */
    02143     dst = start = str;
    02144     currToken = -1;
    02145     while (*start != '\0') {
    02146         switch (*start) {
    02147         case '%':
    02148             /* handle %% */
    02149             if (*(start + 1) == '%') {
    02150                 if (currToken < 0 || format[currToken].type != PTOK_STRING) {
    02151                     currToken++;
    02152                     format[currToken].type = PTOK_STRING;
    02153                     /*@-temptrans -assignexpose@*/
    02154                     dst = format[currToken].u.string.string = start;
    02155                     /*@=temptrans =assignexpose@*/
    02156                 }
    02157
    02158                 start++;
    02159
    02160                 *dst++ = *start++;
    02161
    02162                 /*@switchbreak@*/ break;
    02163             }
    02164
    02165             currToken++;
    02166             *dst++ = '\0';
    02167             start++;
    02168
    02169             if (*start == '|') {
    02170                 char * newEnd;
    02171
    02172                 start++;
    02173                 if (parseExpression(format + currToken, start, tags,
    02174                                     extensions, &newEnd, errmsg))
    02175                 {
    02176                     format = freeFormat(format, numTokens);
    02177                     return 1;
    02178                 }
    02179                 start = newEnd;
    02180                 /*@switchbreak@*/ break;
    02181             }
    02182
    02183             /*@-assignexpose@*/
    02184             format[currToken].u.tag.format = start;
    02185             /*@=assignexpose@*/
    02186             format[currToken].u.tag.pad = 0;
    02187             format[currToken].u.tag.justOne = 0;
    02188             format[currToken].u.tag.arrayCount = 0;
    02189
    02190             chptr = start;
    02191             while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
    02192             if (!*chptr || *chptr == '%') {
    02193                 /*@-observertrans -readonlytrans@*/
    02194                 if (errmsg) *errmsg = _("missing { after %");
    02195                 /*@=observertrans =readonlytrans@*/
    02196                 format = freeFormat(format, numTokens);
    02197                 return 1;
    02198             }
    02199
    02200             *chptr++ = '\0';
    02201
    02202             while (start < chptr) {
    02203                 if (xisdigit(*start)) {
    02204                     i = strtoul(start, &start, 10);
    02205                     format[currToken].u.tag.pad += i;
    02206                 } else {
    02207                     start++;
    02208                 }
    02209             }
    02210
    02211             if (*start == '=') {
    02212                 format[currToken].u.tag.justOne = 1;
    02213                 start++;
    02214             } else if (*start == '#') {
    02215                 format[currToken].u.tag.justOne = 1;
    02216                 format[currToken].u.tag.arrayCount = 1;
    02217                 start++;
    02218             }
    02219
    02220             next = start;
    02221             while (*next && *next != '}') next++;
    02222             if (!*next) {
    02223                 /*@-observertrans -readonlytrans@*/
    02224                 if (errmsg) *errmsg = _("missing } after %{");
    02225                 /*@=observertrans =readonlytrans@*/
    02226                 format = freeFormat(format, numTokens);
    02227                 return 1;
    02228             }
    02229             *next++ = '\0';
    02230
    02231             chptr = start;
    02232             while (*chptr && *chptr != ':') chptr++;
    02233
    02234             if (*chptr != '\0') {
    02235                 *chptr++ = '\0';
    02236                 if (!*chptr) {
    02237                     /*@-observertrans -readonlytrans@*/
    02238                     if (errmsg) *errmsg = _("empty tag format");
    02239                     /*@=observertrans =readonlytrans@*/
    02240                     format = freeFormat(format, numTokens);
    02241                     return 1;
    02242                 }
    02243                 /*@-assignexpose@*/
    02244                 format[currToken].u.tag.type = chptr;
    02245                 /*@=assignexpose@*/
    02246             } else {
    02247                 format[currToken].u.tag.type = NULL;
    02248             }
    02249
    02250             if (!*start) {
    02251                 /*@-observertrans -readonlytrans@*/
    02252                 if (errmsg) *errmsg = _("empty tag name");
    02253                 /*@=observertrans =readonlytrans@*/
    02254                 format = freeFormat(format, numTokens);
    02255                 return 1;
    02256             }
    02257
    02258             i = 0;
    02259             findTag(start, tags, extensions, &tag, &ext);
    02260
    02261             if (tag) {
    02262                 format[currToken].u.tag.ext = NULL;
    02263                 format[currToken].u.tag.tag = tag->val;
    02264             } else if (ext) {
    02265                 format[currToken].u.tag.ext = ext->u.tagFunction;
    02266                 format[currToken].u.tag.extNum = ext - extensions;
    02267             } else {
    02268                 /*@-observertrans -readonlytrans@*/
    02269                 if (errmsg) *errmsg = _("unknown tag");
    02270                 /*@=observertrans =readonlytrans@*/
    02271                 format = freeFormat(format, numTokens);
    02272                 return 1;
    02273             }
    02274
    02275             format[currToken].type = PTOK_TAG;
    02276
    02277             start = next;
    02278
    02279             /*@switchbreak@*/ break;
    02280
    02281         case '[':
    02282             *dst++ = '\0';
    02283             *start++ = '\0';
    02284             currToken++;
    02285
    02286             if (parseFormat(start, tags, extensions,
    02287                             &format[currToken].u.array.format,
    02288                             &format[currToken].u.array.numTokens,
    02289                             &start, PARSER_IN_ARRAY, errmsg)) {
    02290                 format = freeFormat(format, numTokens);
    02291                 return 1;
    02292             }
    02293
    02294             if (!start) {
    02295                 /*@-observertrans -readonlytrans@*/
    02296                 if (errmsg) *errmsg = _("] expected at end of array");
    02297                 /*@=observertrans =readonlytrans@*/
    02298                 format = freeFormat(format, numTokens);
    02299                 return 1;
    02300             }
    02301
    02302             dst = start;
    02303
    02304             format[currToken].type = PTOK_ARRAY;
    02305
    02306             /*@switchbreak@*/ break;
    02307
    02308         case ']':
    02309         case '}':
    02310             if ((*start == ']' && state != PARSER_IN_ARRAY) ||
    02311                 (*start == '}' && state != PARSER_IN_EXPR)) {
    02312                 if (*start == ']') {
    02313                     /*@-observertrans -readonlytrans@*/
    02314                     if (errmsg) *errmsg = _("unexpected ]");
    02315                     /*@=observertrans =readonlytrans@*/
    02316                 } else {
    02317                     /*@-observertrans -readonlytrans@*/
    02318                     if (errmsg) *errmsg = _("unexpected }");
    02319                     /*@=observertrans =readonlytrans@*/
    02320                 }
    02321                 format = freeFormat(format, numTokens);
    02322                 return 1;
    02323             }
    02324             *start++ = '\0';
    02325             if (endPtr) *endPtr = start;
    02326             done = 1;
    02327             /*@switchbreak@*/ break;
    02328
    02329         default:
    02330             if (currToken < 0 || format[currToken].type != PTOK_STRING) {
    02331                 currToken++;
    02332                 format[currToken].type = PTOK_STRING;
    02333                 /*@-temptrans -assignexpose@*/
    02334                 dst = format[currToken].u.string.string = start;
    02335                 /*@=temptrans =assignexpose@*/
    02336             }
    02337
    02338             if (*start == '\\') {
    02339                 start++;
    02340                 *dst++ = escapedChar(*start++);
    02341             } else {
    02342                 *dst++ = *start++;
    02343             }
    02344             /*@switchbreak@*/ break;
    02345         }
    02346         if (done)
    02347             break;
    02348     }
    02349     /*@=infloops@*/
    02350
    02351     *dst = '\0';
    02352
    02353     currToken++;
    02354     for (i = 0; i < currToken; i++) {
    02355         if (format[i].type == PTOK_STRING)
    02356             format[i].u.string.len = strlen(format[i].u.string.string);
    02357     }
    02358
    02359     *numTokensPtr = currToken;
    02360     *formatPtr = format;
    02361
    02362     return 0;
    02363 }
    02364
    02367 static int parseExpression(sprintfToken token, char * str,
    02368                 const headerTagTableEntry tags,
    02369                 const headerSprintfExtension extensions,
    02370                 /*@out@*/ char ** endPtr,
    02371                 /*@null@*/ /*@out@*/ errmsg_t * errmsg)
    02372 {
    02373     headerTagTableEntry tag;
    02374     headerSprintfExtension ext;
    02375     char * chptr;
    02376     char * end;
    02377
    02378     if (errmsg) *errmsg = NULL;
    02379     chptr = str;
    02380     while (*chptr && *chptr != '?') chptr++;
    02381
    02382     if (*chptr != '?') {
    02383         /*@-observertrans -readonlytrans@*/
    02384         if (errmsg) *errmsg = _("? expected in expression");
    02385         /*@=observertrans =readonlytrans@*/
    02386         return 1;
    02387     }
    02388
    02389     *chptr++ = '\0';;
    02390
    02391     if (*chptr != '{') {
    02392         /*@-observertrans -readonlytrans@*/
    02393         if (errmsg) *errmsg = _("{ expected after ? in expression");
    02394         /*@=observertrans =readonlytrans@*/
    02395         return 1;
    02396     }
    02397
    02398     chptr++;
    02399
    02400     if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat,
    02401                     &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg))
    02402         return 1;
    02403
    02404     if (!*end) {
    02405         /*@-observertrans -readonlytrans@*/
    02406         if (errmsg) *errmsg = _("} expected in expression");
    02407         /*@=observertrans =readonlytrans@*/
    02408         token->u.cond.ifFormat =
    02409                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    02410         return 1;
    02411     }
    02412
    02413     chptr = end;
    02414     if (*chptr != ':' && *chptr != '|') {
    02415         /*@-observertrans -readonlytrans@*/
    02416         if (errmsg) *errmsg = _(": expected following ? subexpression");
    02417         /*@=observertrans =readonlytrans@*/
    02418         token->u.cond.ifFormat =
    02419                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    02420         return 1;
    02421     }
    02422
    02423     if (*chptr == '|') {
    02424         (void) parseFormat(xstrdup(""), tags, extensions,
    02425                         &token->u.cond.elseFormat,
    02426                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
    02427                         errmsg);
    02428     } else {
    02429         chptr++;
    02430
    02431         if (*chptr != '{') {
    02432             /*@-observertrans -readonlytrans@*/
    02433             if (errmsg) *errmsg = _("{ expected after : in expression");
    02434             /*@=observertrans =readonlytrans@*/
    02435             token->u.cond.ifFormat =
    02436                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    02437             return 1;
    02438         }
    02439
    02440         chptr++;
    02441
    02442         if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat,
    02443                         &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR,
    02444                         errmsg))
    02445             return 1;
    02446         if (!*end) {
    02447             /*@-observertrans -readonlytrans@*/
    02448             if (errmsg) *errmsg = _("} expected in expression");
    02449             /*@=observertrans =readonlytrans@*/
    02450             token->u.cond.ifFormat =
    02451                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    02452             return 1;
    02453         }
    02454
    02455         chptr = end;
    02456         if (*chptr != '|') {
    02457             /*@-observertrans -readonlytrans@*/
    02458             if (errmsg) *errmsg = _("| expected at end of expression");
    02459             /*@=observertrans =readonlytrans@*/
    02460             token->u.cond.ifFormat =
    02461                 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
    02462             token->u.cond.elseFormat =
    02463                 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
    02464             return 1;
    02465         }
    02466     }
    02467
    02468     chptr++;
    02469
    02470     *endPtr = chptr;
    02471
    02472     findTag(str, tags, extensions, &tag, &ext);
    02473
    02474     if (tag) {
    02475         token->u.cond.tag.ext = NULL;
    02476         token->u.cond.tag.tag = tag->val;
    02477     } else if (ext) {
    02478         token->u.cond.tag.ext = ext->u.tagFunction;
    02479         token->u.cond.tag.extNum = ext - extensions;
    02480     } else {
    02481         token->u.cond.tag.ext = NULL;
    02482         token->u.cond.tag.tag = -1;
    02483     }
    02484
    02485     token->type = PTOK_COND;
    02486
    02487     return 0;
    02488 }
    02489
    02493 static int getExtension(Header h, headerTagTagFunction fn,
    02494                 /*@out@*/ hTYP_t typeptr,
    02495                 /*@out@*/ hPTR_t * data,
    02496                 /*@out@*/ hCNT_t countptr,
    02497                 extensionCache ext)
    02498         /*@modifies *typeptr, *data, *countptr, ext @*/
    02499 {
    02500     if (!ext->avail) {
    02501         if (fn(h, &ext->type, &ext->data, &ext->count, &ext->freeit))
    02502             return 1;
    02503         ext->avail = 1;
    02504     }
    02505
    02506     if (typeptr) *typeptr = ext->type;
    02507     if (data) *data = ext->data;
    02508     if (countptr) *countptr = ext->count;
    02509
    02510     return 0;
    02511 }
    02512
    02515 static char * formatValue(sprintfTag tag, Header h,
    02516                 const headerSprintfExtension extensions,
    02517                 extensionCache extCache, int element)
    02518         /*@modifies extCache @*/
    02519 {
    02520     int len;
    02521     char buf[20];
    02522     int_32 count, type;
    02523     hPTR_t data;
    02524     unsigned int intVal;
    02525     char * val = NULL;
    02526     const char ** strarray;
    02527     int mayfree = 0;
    02528     int countBuf;
    02529     headerTagFormatFunction tagtype = NULL;
    02530     headerSprintfExtension ext;
    02531
    02532     memset(buf, 0, sizeof(buf));
    02533     /*@-branchstate@*/
    02534     if (tag->ext) {
    02535         if (getExtension(h, tag->ext, &type, &data, &count,
    02536                          extCache + tag->extNum))
    02537         {
    02538             count = 1;
    02539             type = RPM_STRING_TYPE;
    02540             data = "(none)";            /* XXX i18n? NO!, sez; gafton */
    02541         }
    02542     } else {
    02543         if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
    02544             count = 1;
    02545             type = RPM_STRING_TYPE;
    02546             data = "(none)";            /* XXX i18n? NO!, sez; gafton */
    02547         }
    02548
    02549         mayfree = 1;
    02550     }
    02551     /*@=branchstate@*/
    02552
    02553     if (tag->arrayCount) {
    02554         /*@-observertrans -modobserver@*/
    02555         data = headerFreeData(data, type);
    02556         /*@=observertrans =modobserver@*/
    02557
    02558         countBuf = count;
    02559         data = &countBuf;
    02560         count = 1;
    02561         type = RPM_INT32_TYPE;
    02562     }
    02563
    02564     (void) stpcpy( stpcpy(buf, "%"), tag->format);
    02565
    02566     if (tag->type) {
    02567         ext = extensions;
    02568         while (ext->type != HEADER_EXT_LAST) {
    02569             if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
    02570             && !strcmp(ext->name, tag->type))
    02571             {
    02572                 tagtype = ext->u.formatFunction;
    02573                 break;
    02574             }
    02575
    02576             if (ext->type == HEADER_EXT_MORE)
    02577                 ext = ext->u.more;
    02578             else
    02579                 ext++;
    02580         }
    02581     }
    02582
    02583     /*@-branchstate@*/
    02584     switch (type) {
    02585     case RPM_STRING_ARRAY_TYPE:
    02586         strarray = (const char **)data;
    02587
    02588         if (tagtype)
    02589             val = tagtype(RPM_STRING_TYPE, strarray[element], buf, tag->pad, 0);
    02590
    02591         if (!val) {
    02592             strcat(buf, "s");
    02593
    02594             len = strlen(strarray[element]) + tag->pad + 20;
    02595             val = xmalloc(len);
    02596             /*@-formatconst@*/
    02597             sprintf(val, buf, strarray[element]);
    02598             /*@=formatconst@*/
    02599         }
    02600
    02601         /*@-observertrans -modobserver@*/
    02602         if (mayfree) data = _free(data);
    02603         /*@=observertrans =modobserver@*/
    02604
    02605         break;
    02606
    02607     case RPM_STRING_TYPE:
    02608         if (tagtype)
    02609             val = tagtype(RPM_STRING_ARRAY_TYPE, data, buf, tag->pad,  0);
    02610
    02611         if (!val) {
    02612             strcat(buf, "s");
    02613
    02614             len = strlen(data) + tag->pad + 20;
    02615             val = xmalloc(len);
    02616             /*@-formatconst@*/
    02617             sprintf(val, buf, data);
    02618             /*@=formatconst@*/
    02619         }
    02620         break;
    02621
    02622     case RPM_CHAR_TYPE:
    02623     case RPM_INT8_TYPE:
    02624     case RPM_INT16_TYPE:
    02625     case RPM_INT32_TYPE:
    02626         switch (type) {
    02627         case RPM_CHAR_TYPE:
    02628         case RPM_INT8_TYPE:
    02629             intVal = *(((int_8 *) data) + element);
    02630             /*@innerbreak@*/ break;
    02631         case RPM_INT16_TYPE:
    02632             intVal = *(((uint_16 *) data) + element);
    02633             /*@innerbreak@*/ break;
    02634         default:                /* keep -Wall quiet */
    02635         case RPM_INT32_TYPE:
    02636             intVal = *(((int_32 *) data) + element);
    02637             /*@innerbreak@*/ break;
    02638         }
    02639
    02640         if (tagtype)
    02641             val = tagtype(RPM_INT32_TYPE, &intVal, buf, tag->pad,  element);
    02642
    02643         if (!val) {
    02644             strcat(buf, "d");
    02645             len = 10 + tag->pad + 20;
    02646             val = xmalloc(len);
    02647             /*@-formatconst@*/
    02648             sprintf(val, buf, intVal);
    02649             /*@=formatconst@*/
    02650         }
    02651         break;
    02652
    02653     case RPM_BIN_TYPE:
    02654         if (tagtype)
    02655             val = tagtype(RPM_BIN_TYPE, data, buf, tag->pad, count);
    02656
    02657         if (!val) {
    02658 #ifdef  NOTYET
    02659             val = memcpy(xmalloc(count), data, count);
    02660 #else
    02661             /* XXX format string not used */
    02662             static char hex[] = "0123456789abcdef";
    02663             const char * s = data;
    02664             char * t;
    02665
    02666             strcat(buf, "s");
    02667             len = 2*count + tag->pad + 1;
    02668             val = t = xmalloc(len);
    02669             while (count-- > 0) {
    02670                 unsigned int i;
    02671                 i = *s++;
    02672                 *t++ = hex[ (i >> 4) & 0xf ];
    02673                 *t++ = hex[ (i     ) & 0xf ];
    02674             }
    02675             *t = '\0';
    02676 #endif
    02677         }
    02678         break;
    02679
    02680     default:
    02681         val = xstrdup(_("(unknown type)"));
    02682         break;
    02683     }
    02684     /*@=branchstate@*/
    02685
    02686     return val;
    02687 }
    02688
    02691 static const char * singleSprintf(Header h, sprintfToken token,
    02692                 const headerSprintfExtension extensions,
    02693                 extensionCache extCache, int element)
    02694         /*@modifies h, extCache @*/
    02695 {
    02696     char * val;
    02697     const char * thisItem;
    02698     int thisItemLen;
    02699     int len, alloced;
    02700     int i, j;
    02701     int numElements;
    02702     int type;
    02703     sprintfToken condFormat;
    02704     int condNumFormats;
    02705
    02706     /* we assume the token and header have been validated already! */
    02707
    02708     switch (token->type) {
    02709     case PTOK_NONE:
    02710         break;
    02711
    02712     case PTOK_STRING:
    02713         val = xmalloc(token->u.string.len + 1);
    02714         strcpy(val, token->u.string.string);
    02715         break;
    02716
    02717     case PTOK_TAG:
    02718         val = formatValue(&token->u.tag, h, extensions, extCache,
    02719                           token->u.tag.justOne ? 0 : element);
    02720         break;
    02721
    02722     case PTOK_COND:
    02723         if (token->u.cond.tag.ext ||
    02724             headerIsEntry(h, token->u.cond.tag.tag)) {
    02725             condFormat = token->u.cond.ifFormat;
    02726             condNumFormats = token->u.cond.numIfTokens;
    02727         } else {
    02728             condFormat = token->u.cond.elseFormat;
    02729             condNumFormats = token->u.cond.numElseTokens;
    02730         }
    02731
    02732         alloced = condNumFormats * 20;
    02733         val = xmalloc(alloced ? alloced : 1);
    02734         *val = '\0';
    02735         len = 0;
    02736
    02737         if (condFormat)
    02738         for (i = 0; i < condNumFormats; i++) {
    02739             thisItem = singleSprintf(h, condFormat + i,
    02740                                      extensions, extCache, element);
    02741             thisItemLen = strlen(thisItem);
    02742             if ((thisItemLen + len) >= alloced) {
    02743                 alloced = (thisItemLen + len) + 200;
    02744                 val = xrealloc(val, alloced);
    02745             }
    02746             strcat(val, thisItem);
    02747             len += thisItemLen;
    02748             thisItem = _free(thisItem);
    02749         }
    02750
    02751         break;
    02752
    02753     case PTOK_ARRAY:
    02754         numElements = -1;
    02755         for (i = 0; i < token->u.array.numTokens; i++) {
    02756             if (token->u.array.format[i].type != PTOK_TAG ||
    02757                 token->u.array.format[i].u.tag.arrayCount ||
    02758                 token->u.array.format[i].u.tag.justOne) continue;
    02759
    02760             if (token->u.array.format[i].u.tag.ext) {
    02761                 const void * data;
    02762                 if (getExtension(h, token->u.array.format[i].u.tag.ext,
    02763                                  &type, &data, &numElements,
    02764                                  extCache +
    02765                                    token->u.array.format[i].u.tag.extNum))
    02766                      continue;
    02767             } else {
    02768                 if (!headerGetEntry(h, token->u.array.format[i].u.tag.tag,
    02769                                     &type, (void **) &val, &numElements))
    02770                     continue;
    02771                 val = headerFreeData(val, type);
    02772             }
    02773             /*@loopbreak@*/ break;
    02774         }
    02775
    02776         if (numElements == -1) {
    02777             val = xstrdup("(none)");    /* XXX i18n? NO!, sez; gafton */
    02778         } else {
    02779             alloced = numElements * token->u.array.numTokens * 20;
    02780             val = xmalloc(alloced);
    02781             *val = '\0';
    02782             len = 0;
    02783
    02784             for (j = 0; j < numElements; j++) {
    02785                 for (i = 0; i < token->u.array.numTokens; i++) {
    02786                     thisItem = singleSprintf(h, token->u.array.format + i,
    02787                                              extensions, extCache, j);
    02788                     thisItemLen = strlen(thisItem);
    02789                     if ((thisItemLen + len) >= alloced) {
    02790                         alloced = (thisItemLen + len) + 200;
    02791                         val = xrealloc(val, alloced);
    02792                     }
    02793                     strcat(val, thisItem);
    02794                     len += thisItemLen;
    02795                     thisItem = _free(thisItem);
    02796                 }
    02797             }
    02798         }
    02799
    02800         break;
    02801     }
    02802
    02803     return val;
    02804 }
    02805
    02808 static /*@only@*/ extensionCache
    02809 allocateExtensionCache(const headerSprintfExtension extensions)
    02810         /*@*/
    02811 {
    02812     headerSprintfExtension ext = extensions;
    02813     int i = 0;
    02814
    02815     while (ext->type != HEADER_EXT_LAST) {
    02816         i++;
    02817         if (ext->type == HEADER_EXT_MORE)
    02818             ext = ext->u.more;
    02819         else
    02820             ext++;
    02821     }
    02822
    02823     /*@-sizeoftype@*/
    02824     return xcalloc(i, sizeof(struct extensionCache));
    02825     /*@=sizeoftype@*/
    02826 }
    02827
    02831 static /*@null@*/ extensionCache
    02832 freeExtensionCache(const headerSprintfExtension extensions,
    02833                         /*@only@*/ extensionCache cache)
    02834         /*@*/
    02835 {
    02836     headerSprintfExtension ext = extensions;
    02837     int i = 0;
    02838
    02839     while (ext->type != HEADER_EXT_LAST) {
    02840         if (cache[i].freeit) cache[i].data = _free(cache[i].data);
    02841
    02842         i++;
    02843         if (ext->type == HEADER_EXT_MORE)
    02844             ext = ext->u.more;
    02845         else
    02846             ext++;
    02847     }
    02848
    02849     cache = _free(cache);
    02850     return NULL;
    02851 }
    02852
    02864 static /*@only@*/ /*@null@*/
    02865 char * headerSprintf(Header h, const char * fmt,
    02866                      const struct headerTagTableEntry_s * tbltags,
    02867                      const struct headerSprintfExtension_s * extensions,
    02868                      /*@null@*/ /*@out@*/ errmsg_t * errmsg)
    02869         /*@modifies *errmsg @*/
    02870 {
    02871     /*@-castexpose@*/   /* FIX: legacy API shouldn't change. */
    02872     headerSprintfExtension exts = (headerSprintfExtension) extensions;
    02873     headerTagTableEntry tags = (headerTagTableEntry) tbltags;
    02874     /*@=castexpose@*/
    02875     char * fmtString;
    02876     sprintfToken format;
    02877     int numTokens;
    02878     char * answer;
    02879     int answerLength;
    02880     int answerAlloced;
    02881     int i;
    02882     extensionCache extCache;
    02883
    02884     /*fmtString = escapeString(fmt);*/
    02885     fmtString = xstrdup(fmt);
    02886
    02887     if (parseFormat(fmtString, tags, exts, &format, &numTokens,
    02888                     NULL, PARSER_BEGIN, errmsg)) {
    02889         fmtString = _free(fmtString);
    02890         return NULL;
    02891     }
    02892
    02893     extCache = allocateExtensionCache(exts);
    02894
    02895     answerAlloced = 1024;
    02896     answerLength = 0;
    02897     answer = xmalloc(answerAlloced);
    02898     *answer = '\0';
    02899
    02900     for (i = 0; i < numTokens; i++) {
    02901         const char * piece;
    02902         int pieceLength;
    02903
    02904         /*@-mods@*/
    02905         piece = singleSprintf(h, format + i, exts, extCache, 0);
    02906         /*@=mods@*/
    02907         if (piece) {
    02908             pieceLength = strlen(piece);
    02909             if ((answerLength + pieceLength) >= answerAlloced) {
    02910                 while ((answerLength + pieceLength) >= answerAlloced)
    02911                     answerAlloced += 1024;
    02912                 answer = xrealloc(answer, answerAlloced);
    02913             }
    02914
    02915             strcat(answer, piece);
    02916             answerLength += pieceLength;
    02917             piece = _free(piece);
    02918         }
    02919     }
    02920
    02921     fmtString = _free(fmtString);
    02922     extCache = freeExtensionCache(exts, extCache);
    02923     format = _free(format);
    02924
    02925     return answer;
    02926 }
    02927
    02930 static char * octalFormat(int_32 type, hPTR_t data,
    02931                 char * formatPrefix, int padding, /*@unused@*/int element)
    02932         /*@modifies formatPrefix @*/
    02933 {
    02934     char * val;
    02935
    02936     if (type != RPM_INT32_TYPE) {
    02937         val = xstrdup(_("(not a number)"));
    02938     } else {
    02939         val = xmalloc(20 + padding);
    02940         strcat(formatPrefix, "o");
    02941         /*@-formatconst@*/
    02942         sprintf(val, formatPrefix, *((int_32 *) data));
    02943         /*@=formatconst@*/
    02944     }
    02945
    02946     return val;
    02947 }
    02948
    02951 static char * hexFormat(int_32 type, hPTR_t data,
    02952                 char * formatPrefix, int padding, /*@unused@*/int element)
    02953         /*@modifies formatPrefix @*/
    02954 {
    02955     char * val;
    02956
    02957     if (type != RPM_INT32_TYPE) {
    02958         val = xstrdup(_("(not a number)"));
    02959     } else {
    02960         val = xmalloc(20 + padding);
    02961         strcat(formatPrefix, "x");
    02962         /*@-formatconst@*/
    02963         sprintf(val, formatPrefix, *((int_32 *) data));
    02964         /*@=formatconst@*/
    02965     }
    02966
    02967     return val;
    02968 }
    02969
    02972 static char * realDateFormat(int_32 type, hPTR_t data,
    02973                 char * formatPrefix, int padding, /*@unused@*/int element,
    02974                 const char * strftimeFormat)
    02975         /*@modifies formatPrefix @*/
    02976 {
    02977     char * val;
    02978
    02979     if (type != RPM_INT32_TYPE) {
    02980         val = xstrdup(_("(not a number)"));
    02981     } else {
    02982         struct tm * tstruct;
    02983         char buf[50];
    02984
    02985         val = xmalloc(50 + padding);
    02986         strcat(formatPrefix, "s");
    02987
    02988         /* this is important if sizeof(int_32) ! sizeof(time_t) */
    02989         {   time_t dateint = *((int_32 *) data);
    02990             tstruct = localtime(&dateint);
    02991         }
    02992         buf[0] = '\0';
    02993         if (tstruct)
    02994             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
    02995         /*@-formatconst@*/
    02996         sprintf(val, formatPrefix, buf);
    02997         /*@=formatconst@*/
    02998     }
    02999
    03000     return val;
    03001 }
    03002
    03005 static char * dateFormat(int_32 type, hPTR_t data,
    03006                          char * formatPrefix, int padding, int element)
    03007         /*@modifies formatPrefix @*/
    03008 {
    03009     return realDateFormat(type, data, formatPrefix, padding, element, "%c");
    03010 }
    03011
    03014 static char * dayFormat(int_32 type, hPTR_t data,
    03015                          char * formatPrefix, int padding, int element)
    03016         /*@modifies formatPrefix @*/
    03017 {
    03018     return realDateFormat(type, data, formatPrefix, padding, element,
    03019                           "%a %b %d %Y");
    03020 }
    03021
    03024 static char * shescapeFormat(int_32 type, hPTR_t data,
    03025                 char * formatPrefix, int padding, /*@unused@*/int element)
    03026         /*@modifies formatPrefix @*/
    03027 {
    03028     char * result, * dst, * src, * buf;
    03029
    03030     if (type == RPM_INT32_TYPE) {
    03031         result = xmalloc(padding + 20);
    03032         strcat(formatPrefix, "d");
    03033         /*@-formatconst@*/
    03034         sprintf(result, formatPrefix, *((int_32 *) data));
    03035         /*@=formatconst@*/
    03036     } else {
    03037         buf = alloca(strlen(data) + padding + 2);
    03038         strcat(formatPrefix, "s");
    03039         /*@-formatconst@*/
    03040         sprintf(buf, formatPrefix, data);
    03041         /*@=formatconst@*/
    03042
    03043         result = dst = xmalloc(strlen(buf) * 4 + 3);
    03044         *dst++ = '\'';
    03045         for (src = buf; *src != '\0'; src++) {
    03046             if (*src == '\'') {
    03047                 *dst++ = '\'';
    03048                 *dst++ = '\\';
    03049                 *dst++ = '\'';
    03050                 *dst++ = '\'';
    03051             } else {
    03052                 *dst++ = *src;
    03053             }
    03054         }
    03055         *dst++ = '\'';
    03056         *dst = '\0';
    03057
    03058     }
    03059
    03060     return result;
    03061 }
    03062
    03063 /*@-type@*/ /* FIX: cast? */
    03064 const struct headerSprintfExtension_s headerDefaultFormats[] = {
    03065     { HEADER_EXT_FORMAT, "octal", { octalFormat } },
    03066     { HEADER_EXT_FORMAT, "hex", { hexFormat } },
    03067     { HEADER_EXT_FORMAT, "date", { dateFormat } },
    03068     { HEADER_EXT_FORMAT, "day", { dayFormat } },
    03069     { HEADER_EXT_FORMAT, "shescape", { shescapeFormat } },
    03070     { HEADER_EXT_LAST, NULL, { NULL } }
    03071 };
    03072 /*@=type@*/
    03073
    03080 static
    03081 void headerCopyTags(Header headerFrom, Header headerTo, hTAG_t tagstocopy)
    03082         /*@modifies headerTo @*/
    03083 {
    03084     int * p;
    03085
    03086     if (headerFrom == headerTo)
    03087         return;
    03088
    03089     for (p = tagstocopy; *p != 0; p++) {
    03090         char *s;
    03091         int_32 type;
    03092         int_32 count;
    03093         if (headerIsEntry(headerTo, *p))
    03094             continue;
    03095         if (!headerGetEntryMinMemory(headerFrom, *p, &type,
    03096                                 (hPTR_t *) &s, &count))
    03097             continue;
    03098         (void) headerAddEntry(headerTo, *p, type, s, count);
    03099         s = headerFreeData(s, type);
    03100     }
    03101 }
    03102
    03106 struct headerIteratorS {
    03107 /*@unused@*/ Header h;
    03108 /*@unused@*/ int next_index;
    03109 };
    03110
    03116 static /*@null@*/
    03117 HeaderIterator headerFreeIterator(/*@only@*/ HeaderIterator hi)
    03118         /*@modifies hi @*/
    03119 {
    03120     hi->h = headerFree(hi->h);
    03121     hi = _free(hi);
    03122     return hi;
    03123 }
    03124
    03130 static
    03131 HeaderIterator headerInitIterator(Header h)
    03132         /*@modifies h */
    03133 {
    03134     HeaderIterator hi = xmalloc(sizeof(*hi));
    03135
    03136     headerSort(h);
    03137
    03138     hi->h = headerLink(h);
    03139     hi->next_index = 0;
    03140     return hi;
    03141 }
    03142
    03152 static
    03153 int headerNextIterator(HeaderIterator hi,
    03154                 /*@null@*/ /*@out@*/ hTAG_t tag,
    03155                 /*@null@*/ /*@out@*/ hTYP_t type,
    03156                 /*@null@*/ /*@out@*/ hPTR_t * p,
    03157                 /*@null@*/ /*@out@*/ hCNT_t c)
    03158         /*@modifies hi, *tag, *type, *p, *c @*/
    03159 {
    03160     Header h = hi->h;
    03161     int slot = hi->next_index;
    03162     indexEntry entry = NULL;
    03163     int rc;
    03164
    03165     for (slot = hi->next_index; slot < h->indexUsed; slot++) {
    03166         entry = h->index + slot;
    03167         if (!ENTRY_IS_REGION(entry))
    03168             break;
    03169     }
    03170     hi->next_index = slot;
    03171     if (entry == NULL || slot >= h->indexUsed)
    03172         return 0;
    03173     /*@-noeffect@*/     /* LCL: no clue */
    03174     hi->next_index++;
    03175     /*@=noeffect@*/
    03176
    03177     if (tag)
    03178         *tag = entry->info.tag;
    03179
    03180     rc = copyEntry(entry, type, p, c, 0);
    03181
    03182     /* XXX 1 on success */
    03183     return ((rc == 1) ? 1 : 0);
    03184 }
    03185
    03191 static /*@null@*/
    03192 Header headerCopy(Header h)
    03193         /*@modifies h @*/
    03194 {
    03195     Header nh = headerNew();
    03196     HeaderIterator hi;
    03197     int_32 tag, type, count;
    03198     hPTR_t ptr;
    03199
    03200     /*@-branchstate@*/
    03201     for (hi = headerInitIterator(h);
    03202         headerNextIterator(hi, &tag, &type, &ptr, &count);
    03203         ptr = headerFreeData((void *)ptr, type))
    03204     {
    03205         if (ptr) (void) headerAddEntry(nh, tag, type, ptr, count);
    03206     }
    03207     hi = headerFreeIterator(hi);
    03208     /*@=branchstate@*/
    03209
    03210     return headerReload(nh, HEADER_IMAGE);
    03211 }
    03212
    03213 /*@observer@*/ /*@unchecked@*/
    03214 static struct HV_s hdrVec1 = {
    03215     headerNew,
    03216     headerFree,
    03217     headerLink,
    03218     headerSort,
    03219     headerUnsort,
    03220     headerSizeof,
    03221     headerUnload,
    03222     headerReload,
    03223     headerCopy,
    03224     headerLoad,
    03225     headerCopyLoad,
    03226     headerRead,
    03227     headerWrite,
    03228     headerIsEntry,
    03229     headerFreeTag,
    03230     headerGetEntry,
    03231     headerGetEntryMinMemory,
    03232     headerAddEntry,
    03233     headerAppendEntry,
    03234     headerAddOrAppendEntry,
    03235     headerAddI18NString,
    03236     headerModifyEntry,
    03237     headerRemoveEntry,
    03238     headerSprintf,
    03239     headerCopyTags,
    03240     headerFreeIterator,
    03241     headerInitIterator,
    03242     headerNextIterator,
    03243     headerUnlink,
    03244     NULL, NULL,
    03245     1
    03246 };
    03247
    03248 /*@-compmempass -redef@*/
    03249 /*@observer@*/ /*@unchecked@*/
    03250 HV_t hdrVec = &hdrVec1;
    03251 /*@=compmempass =redef@*/