Minimize ars passed throuch headerSprintf call chain.
authorjbj <devnull@localhost>
Mon, 10 Mar 2003 14:39:07 +0000 (14:39 +0000)
committerjbj <devnull@localhost>
Mon, 10 Mar 2003 14:39:07 +0000 (14:39 +0000)
CVS patchset: 6670
CVS date: 2003/03/10 14:39:07

rpmdb/header.c

index cdad7c0..c7eef80 100644 (file)
@@ -2264,101 +2264,106 @@ freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, int num)
 
 /**
  */
-static void findTag(char * name, const headerTagTableEntry tags, 
-                   const headerSprintfExtension extensions,
-                   /*@out@*/ headerTagTableEntry * tagMatch,
-                   /*@out@*/ headerSprintfExtension * extMatch)
+typedef struct headerSprintfArgs_s {
+    Header h;
+    char * fmt;
+/*@temp@*/
+    headerTagTableEntry tags;
+/*@temp@*/
+    headerSprintfExtension exts;
+/*@observer@*/ /*@null@*/
+    const char * errmsg;
+    sprintfToken format;
+    int numTokens;
+    rpmec ec;
+/*@owned@*/
+    char * val;
+    size_t vallen;
+    size_t alloced;
+} * headerSprintfArgs;
+
+/**
+ * @param hsa          headerSprintf args
+ * @param tagname
+ * @retval *tagMatch
+ * @retval *extMatch
+ */
+static void findTag(headerSprintfArgs hsa, const char * tagname,
+                   /*@out@*/ headerTagTableEntry *const tagMatch,
+                   /*@out@*/ headerSprintfExtension *const extMatch)
        /*@modifies *tagMatch, *extMatch @*/
        /*@requires maxSet(tagMatch) >= 0 /\ maxSet(extMatch) >= 0 @*/
 {
     headerTagTableEntry entry;
     headerSprintfExtension ext;
-    const char * tagname;
 
     *tagMatch = NULL;
     *extMatch = NULL;
 
-    if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
+/*@-branchstate@*/
+    if (strncmp("RPMTAG_", tagname, sizeof("RPMTAG_")-1)) {
 /*@-boundswrite@*/
-       char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
-       (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
+       char * t = alloca(strlen(tagname) + sizeof("RPMTAG_"));
+       (void) stpcpy( stpcpy(t, "RPMTAG_"), tagname);
        tagname = t;
 /*@=boundswrite@*/
-    } else {
-       tagname = name;
     }
+/*@=branchstate@*/
 
     /* Search extensions first to permit overriding header tags. */
-    ext = extensions;
-    while (ext->type != HEADER_EXT_LAST) {
-       if (ext->name != NULL && ext->type == HEADER_EXT_TAG
-        && !xstrcasecmp(ext->name, tagname))
-           break;
-
-       if (ext->type == HEADER_EXT_MORE)
-           ext = ext->u.more;
-       else
-           ext++;
-    }
-
-    if (ext->type == HEADER_EXT_TAG) {
-       *extMatch = ext;
-       return;
+    for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
+       ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
+    {
+       if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
+           continue;
+       if (!xstrcasecmp(ext->name, tagname)) {
+           *extMatch = ext;
+           return;
+       }
     }
 
     /* Search header tags. */
-    for (entry = tags; entry->name; entry++)
-       if (entry->name && !xstrcasecmp(entry->name, tagname))
-           break;
-
-    if (entry->name) {
-       *tagMatch = entry;
-       return;
+    for (entry = hsa->tags; entry->name != NULL; entry++) {
+       if (!xstrcasecmp(entry->name, tagname)) {
+           *tagMatch = entry;
+           return;
+       }
     }
 }
 
 /* forward ref */
 /**
+ * @param hsa          headerSprintf args
  * @param token
  * @param str
- * @param tags
- * @param extensions
  * @retval *endPtr
- * @retval *errmsg     error message (if any)
  * @return             0 on success
  */
-static int parseExpression(sprintfToken token, char * str, 
-               const headerTagTableEntry tags, 
-               const headerSprintfExtension extensions,
-               /*@out@*/char ** endPtr, /*@null@*/ /*@out@*/ errmsg_t * errmsg)
-       /*@modifies str, *str, *token, *endPtr, *errmsg @*/
-       /*@requires maxSet(endPtr) >= 0 /\ maxSet(errmsg) >= 0 @*/;
+static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
+               char * str, /*@out@*/char ** endPtr)
+       /*@modifies hsa, str, *token, *endPtr @*/
+       /*@requires maxSet(endPtr) >= 0 @*/;
 
 /**
+ * @param hsa          headerSprintf args
  * @param str
- * @param tags
- * @param extensions
  * @retval *formatPtr
  * @retval *numTokensPtr
  * @retval *endPtr
  * @param state
- * @retval *errmsg     error message (if any)
  * @return             0 on success
  */
-/*@-boundswrite@*/
-static int parseFormat(/*@null@*/ char * str, const headerTagTableEntry tags,
-               const headerSprintfExtension extensions,
+static int parseFormat(headerSprintfArgs hsa, /*@null@*/ char * str,
                /*@out@*/sprintfToken * formatPtr, /*@out@*/int * numTokensPtr,
-               /*@null@*/ /*@out@*/ char ** endPtr, int state,
-               /*@null@*/ /*@out@*/ errmsg_t * errmsg)
-       /*@modifies str, *str, *formatPtr, *numTokensPtr, *endPtr, *errmsg @*/
+               /*@null@*/ /*@out@*/ char ** endPtr, int state)
+       /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
        /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
-               /\ maxSet(endPtr) >= 0 /\ maxSet(errmsg) >= 0 @*/
+               /\ maxSet(endPtr) >= 0 @*/
 {
     char * chptr, * start, * next, * dst;
     sprintfToken format;
+    sprintfToken token;
     int numTokens;
-    int currToken;
     headerTagTableEntry tag;
     headerSprintfExtension ext;
     int i;
@@ -2376,209 +2381,218 @@ static int parseFormat(/*@null@*/ char * str, const headerTagTableEntry tags,
 
     /*@-infloops@*/ /* LCL: can't detect done termination */
     dst = start = str;
-    currToken = -1;
+    numTokens = 0;
+    token = NULL;
     if (start != NULL)
     while (*start != '\0') {
        switch (*start) {
        case '%':
            /* handle %% */
            if (*(start + 1) == '%') {
-               if (currToken < 0 || format[currToken].type != PTOK_STRING) {
-                   currToken++;
-                   format[currToken].type = PTOK_STRING;
+               if (token == NULL || token->type != PTOK_STRING) {
+                   token = format + numTokens++;
+                   token->type = PTOK_STRING;
                    /*@-temptrans -assignexpose@*/
-                   dst = format[currToken].u.string.string = start;
+                   dst = token->u.string.string = start;
                    /*@=temptrans =assignexpose@*/
                }
                start++;
+/*@-boundswrite@*/
                *dst++ = *start++;
+/*@=boundswrite@*/
                /*@switchbreak@*/ break;
            } 
 
-           currToken++;
+           token = format + numTokens++;
+/*@-boundswrite@*/
            *dst++ = '\0';
+/*@=boundswrite@*/
            start++;
 
            if (*start == '|') {
                char * newEnd;
 
                start++;
-               if (parseExpression(format + currToken, start, tags, 
-                                   extensions, &newEnd, errmsg))
+/*@-boundswrite@*/
+               if (parseExpression(hsa, token, start, &newEnd))
                {
                    format = freeFormat(format, numTokens);
                    return 1;
                }
+/*@=boundswrite@*/
                start = newEnd;
                /*@switchbreak@*/ break;
            }
 
            /*@-assignexpose@*/
-           format[currToken].u.tag.format = start;
+           token->u.tag.format = start;
            /*@=assignexpose@*/
-           format[currToken].u.tag.pad = 0;
-           format[currToken].u.tag.justOne = 0;
-           format[currToken].u.tag.arrayCount = 0;
+           token->u.tag.pad = 0;
+           token->u.tag.justOne = 0;
+           token->u.tag.arrayCount = 0;
 
            chptr = start;
            while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
            if (!*chptr || *chptr == '%') {
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg) *errmsg = _("missing { after %");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("missing { after %");
                format = freeFormat(format, numTokens);
                return 1;
            }
 
+/*@-boundswrite@*/
            *chptr++ = '\0';
+/*@=boundswrite@*/
 
            while (start < chptr) {
                if (xisdigit(*start)) {
                    i = strtoul(start, &start, 10);
-                   format[currToken].u.tag.pad += i;
+                   token->u.tag.pad += i;
                } else {
                    start++;
                }
            }
 
            if (*start == '=') {
-               format[currToken].u.tag.justOne = 1;
+               token->u.tag.justOne = 1;
                start++;
            } else if (*start == '#') {
-               format[currToken].u.tag.justOne = 1;
-               format[currToken].u.tag.arrayCount = 1;
+               token->u.tag.justOne = 1;
+               token->u.tag.arrayCount = 1;
                start++;
            }
 
            next = start;
            while (*next && *next != '}') next++;
            if (!*next) {
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg) *errmsg = _("missing } after %{");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("missing } after %{");
                format = freeFormat(format, numTokens);
                return 1;
            }
+/*@-boundswrite@*/
            *next++ = '\0';
+/*@=boundswrite@*/
 
            chptr = start;
            while (*chptr && *chptr != ':') chptr++;
 
            if (*chptr != '\0') {
+/*@-boundswrite@*/
                *chptr++ = '\0';
+/*@=boundswrite@*/
                if (!*chptr) {
-                   /*@-observertrans -readonlytrans@*/
-                   if (errmsg) *errmsg = _("empty tag format");
-                   /*@=observertrans =readonlytrans@*/
+                   hsa->errmsg = _("empty tag format");
                    format = freeFormat(format, numTokens);
                    return 1;
                }
                /*@-assignexpose@*/
-               format[currToken].u.tag.type = chptr;
+               token->u.tag.type = chptr;
                /*@=assignexpose@*/
            } else {
-               format[currToken].u.tag.type = NULL;
+               token->u.tag.type = NULL;
            }
            
            if (!*start) {
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg) *errmsg = _("empty tag name");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("empty tag name");
                format = freeFormat(format, numTokens);
                return 1;
            }
 
            i = 0;
-           findTag(start, tags, extensions, &tag, &ext);
+/*@-boundswrite@*/
+           findTag(hsa, start, &tag, &ext);
+/*@=boundswrite@*/
 
            if (tag) {
-               format[currToken].u.tag.ext = NULL;
-               format[currToken].u.tag.tag = tag->val;
+               token->u.tag.ext = NULL;
+               token->u.tag.tag = tag->val;
            } else if (ext) {
-               format[currToken].u.tag.ext = ext->u.tagFunction;
-               format[currToken].u.tag.extNum = ext - extensions;
+               token->u.tag.ext = ext->u.tagFunction;
+               token->u.tag.extNum = ext - hsa->exts;
            } else {
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg) *errmsg = _("unknown tag");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("unknown tag");
                format = freeFormat(format, numTokens);
                return 1;
            }
 
-           format[currToken].type = PTOK_TAG;
+           token->type = PTOK_TAG;
 
            start = next;
 
            /*@switchbreak@*/ break;
 
        case '[':
+/*@-boundswrite@*/
            *dst++ = '\0';
            *start++ = '\0';
-           currToken++;
+/*@=boundswrite@*/
+           token = format + numTokens++;
 
-           if (parseFormat(start, tags, extensions, 
-                           &format[currToken].u.array.format,
-                           &format[currToken].u.array.numTokens,
-                           &start, PARSER_IN_ARRAY, errmsg)) {
+/*@-boundswrite@*/
+           if (parseFormat(hsa, start,
+                           &token->u.array.format,
+                           &token->u.array.numTokens,
+                           &start, PARSER_IN_ARRAY))
+           {
                format = freeFormat(format, numTokens);
                return 1;
            }
+/*@=boundswrite@*/
 
            if (!start) {
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg) *errmsg = _("] expected at end of array");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("] expected at end of array");
                format = freeFormat(format, numTokens);
                return 1;
            }
 
            dst = start;
 
-           format[currToken].type = PTOK_ARRAY;
+           token->type = PTOK_ARRAY;
 
            /*@switchbreak@*/ break;
 
        case ']':
            if (state != PARSER_IN_ARRAY) {
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg) *errmsg = _("unexpected ]");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("unexpected ]");
                format = freeFormat(format, numTokens);
                return 1;
            }
+/*@-boundswrite@*/
            *start++ = '\0';
+/*@=boundswrite@*/
            if (endPtr) *endPtr = start;
            done = 1;
            /*@switchbreak@*/ break;
 
        case '}':
            if (state != PARSER_IN_EXPR) {
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg) *errmsg = _("unexpected }");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("unexpected }");
                format = freeFormat(format, numTokens);
                return 1;
            }
+/*@-boundswrite@*/
            *start++ = '\0';
+/*@=boundswrite@*/
            if (endPtr) *endPtr = start;
            done = 1;
            /*@switchbreak@*/ break;
 
        default:
-           if (currToken < 0 || format[currToken].type != PTOK_STRING) {
-               currToken++;
-               format[currToken].type = PTOK_STRING;
+           if (token == NULL || token->type != PTOK_STRING) {
+               token = format + numTokens++;
+               token->type = PTOK_STRING;
                /*@-temptrans -assignexpose@*/
-               dst = format[currToken].u.string.string = start;
+               dst = token->u.string.string = start;
                /*@=temptrans =assignexpose@*/
            }
 
+/*@-boundswrite@*/
            if (*start == '\\') {
                start++;
                *dst++ = escapedChar(*start++);
            } else {
                *dst++ = *start++;
            }
+/*@=boundswrite@*/
            /*@switchbreak@*/ break;
        }
        if (done)
@@ -2586,65 +2600,57 @@ static int parseFormat(/*@null@*/ char * str, const headerTagTableEntry tags,
     }
     /*@=infloops@*/
 
+/*@-boundswrite@*/
     if (dst != NULL)
         *dst = '\0';
+/*@=boundswrite@*/
 
-    currToken++;
-    for (i = 0; i < currToken; i++) {
-       if (format[i].type == PTOK_STRING)
-           format[i].u.string.len = strlen(format[i].u.string.string);
+    for (i = 0; i < numTokens; i++) {
+       token = format + i;
+       if (token->type == PTOK_STRING)
+           token->u.string.len = strlen(token->u.string.string);
     }
 
-    *numTokensPtr = currToken;
+    *numTokensPtr = numTokens;
     *formatPtr = format;
 
     return 0;
 }
-/*@=boundswrite@*/
 
 /*@-boundswrite@*/
-static int parseExpression(sprintfToken token, char * str, 
-               const headerTagTableEntry tags, 
-               const headerSprintfExtension extensions,
-               /*@out@*/ char ** endPtr,
-               /*@null@*/ /*@out@*/ errmsg_t * errmsg)
+static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
+               char * str, /*@out@*/ char ** endPtr)
 {
     headerTagTableEntry tag;
     headerSprintfExtension ext;
     char * chptr;
     char * end;
 
-    if (errmsg) *errmsg = NULL;
+    hsa->errmsg = NULL;
     chptr = str;
     while (*chptr && *chptr != '?') chptr++;
 
     if (*chptr != '?') {
-       /*@-observertrans -readonlytrans@*/
-       if (errmsg) *errmsg = _("? expected in expression");
-       /*@=observertrans =readonlytrans@*/
+       hsa->errmsg = _("? expected in expression");
        return 1;
     }
 
     *chptr++ = '\0';;
 
     if (*chptr != '{') {
-       /*@-observertrans -readonlytrans@*/
-       if (errmsg) *errmsg = _("{ expected after ? in expression");
-       /*@=observertrans =readonlytrans@*/
+       hsa->errmsg = _("{ expected after ? in expression");
        return 1;
     }
 
     chptr++;
 
-    if (parseFormat(chptr, tags, extensions, &token->u.cond.ifFormat, 
-                   &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR, errmsg)) 
+    if (parseFormat(hsa, chptr, &token->u.cond.ifFormat, 
+                   &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR)) 
        return 1;
 
     /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
     if (!(end && *end)) {
-       /*@-observertrans -readonlytrans@*/
-       if (errmsg) *errmsg = _("} expected in expression");
-       /*@=observertrans =readonlytrans@*/
+       hsa->errmsg = _("} expected in expression");
        token->u.cond.ifFormat =
                freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
        return 1;
@@ -2652,17 +2658,15 @@ static int parseExpression(sprintfToken token, char * str,
 
     chptr = end;
     if (*chptr != ':' && *chptr != '|') {
-       /*@-observertrans -readonlytrans@*/
-       if (errmsg) *errmsg = _(": expected following ? subexpression");
-       /*@=observertrans =readonlytrans@*/
+       hsa->errmsg = _(": expected following ? subexpression");
        token->u.cond.ifFormat =
                freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
        return 1;
     }
 
     if (*chptr == '|') {
-       if (parseFormat(NULL, tags, extensions, &token->u.cond.elseFormat, 
-               &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, errmsg))
+       if (parseFormat(hsa, NULL, &token->u.cond.elseFormat, 
+               &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
        {
            token->u.cond.ifFormat =
                freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
@@ -2672,9 +2676,7 @@ static int parseExpression(sprintfToken token, char * str,
        chptr++;
 
        if (*chptr != '{') {
-           /*@-observertrans -readonlytrans@*/
-           if (errmsg) *errmsg = _("{ expected after : in expression");
-           /*@=observertrans =readonlytrans@*/
+           hsa->errmsg = _("{ expected after : in expression");
            token->u.cond.ifFormat =
                freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
            return 1;
@@ -2682,16 +2684,13 @@ static int parseExpression(sprintfToken token, char * str,
 
        chptr++;
 
-       if (parseFormat(chptr, tags, extensions, &token->u.cond.elseFormat, 
-                       &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR, 
-                       errmsg)) 
+       if (parseFormat(hsa, chptr, &token->u.cond.elseFormat, 
+                       &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR)) 
            return 1;
 
        /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
        if (!(end && *end)) {
-           /*@-observertrans -readonlytrans@*/
-           if (errmsg) *errmsg = _("} expected in expression");
-           /*@=observertrans =readonlytrans@*/
+           hsa->errmsg = _("} expected in expression");
            token->u.cond.ifFormat =
                freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
            return 1;
@@ -2699,9 +2698,7 @@ static int parseExpression(sprintfToken token, char * str,
 
        chptr = end;
        if (*chptr != '|') {
-           /*@-observertrans -readonlytrans@*/
-           if (errmsg) *errmsg = _("| expected at end of expression");
-           /*@=observertrans =readonlytrans@*/
+           hsa->errmsg = _("| expected at end of expression");
            token->u.cond.ifFormat =
                freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
            token->u.cond.elseFormat =
@@ -2714,14 +2711,14 @@ static int parseExpression(sprintfToken token, char * str,
 
     *endPtr = chptr;
 
-    findTag(str, tags, extensions, &tag, &ext);
+    findTag(hsa, str, &tag, &ext);
 
     if (tag) {
        token->u.cond.tag.ext = NULL;
        token->u.cond.tag.tag = tag->val;
     } else if (ext) {
        token->u.cond.tag.ext = ext->u.tagFunction;
-       token->u.cond.tag.extNum = ext - extensions;
+       token->u.cond.tag.extNum = ext - hsa->exts;
     } else {
        token->u.cond.tag.ext = NULL;
        token->u.cond.tag.tag = -1;
@@ -2735,15 +2732,15 @@ static int parseExpression(sprintfToken token, char * str,
 
 /**
  * Call a header extension only once, saving results.
- * @param h            header
+ * @param hsa          headerSprintf args
  * @param fn
  * @retval *typeptr
  * @retval *data
  * @retval *countptr
- * @param ec           extension cache
+ * @retval ec          extension cache
  * @return             0 on success, 1 on failure
  */
-static int getExtension(Header h, headerTagTagFunction fn,
+static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
                /*@out@*/ hTYP_t typeptr,
                /*@out@*/ hPTR_t * data,
                /*@out@*/ hCNT_t countptr,
@@ -2753,7 +2750,7 @@ static int getExtension(Header h, headerTagTagFunction fn,
                /\ maxSet(countptr) >= 0 @*/
 {
     if (!ec->avail) {
-       if (fn(h, &ec->type, &ec->data, &ec->count, &ec->freeit))
+       if (fn(hsa->h, &ec->type, &ec->data, &ec->count, &ec->freeit))
            return 1;
        ec->avail = 1;
     }
@@ -2766,29 +2763,36 @@ static int getExtension(Header h, headerTagTagFunction fn,
 }
 
 /**
+ * Reserve sufficient buffer space for next output value.
+ * @param hsa          headerSprintf args
+ * @param need         no. of bytes to reserve
+ * @return             pointer to reserved space
+ */
+/*@dependent@*/ /*@exposed@*/
+static char * hsaReserve(headerSprintfArgs hsa, size_t need)
+       /*@modifies hsa */
+{
+    if ((hsa->vallen + need) >= hsa->alloced) {
+       if (hsa->alloced <= need)
+           hsa->alloced += need;
+       hsa->alloced <<= 1;
+       hsa->val = xrealloc(hsa->val, hsa->alloced+1);  
+    }
+    return hsa->val + hsa->vallen;
+}
+
+/**
+ * @param hsa          headerSprintf args
  * @param tag
- * @param h            header
- * @param extensions
- * @param ec           extension cache
  * @param element
- * @retval *valp
- * @retval *vallenp
- * @retval *allocedp
- * @retval *errmsg     error message (if any)
  * @return             end of formatted string (NULL on error)
  */
 /*@observer@*/ /*@null@*/
-static char * formatValue(sprintfTag tag, Header h, 
-               const headerSprintfExtension extensions,
-               rpmec ec, int element,
-               char ** valp, int * vallenp, int * allocedp,
-               /*@null@*/ /*@out@*/ errmsg_t * errmsg)
-       /*@modifies ec, *valp, *vallenp, *allocedp, *errmsg @*/
-       /*@requires maxSet(valp) >= 0 /\ maxSet(vallenp) >= 0
-               /\ maxSet(allocedp) >= 0 /\ maxSet(errmsg) >= 0 @*/
+static char * formatValue(headerSprintfArgs hsa, sprintfTag tag, int element)
+       /*@modifies hsa @*/
 {
     char * val = NULL;
-    int need = 0;
+    size_t need = 0;
     char * t, * te;
     char buf[20];
     int_32 count, type;
@@ -2803,7 +2807,7 @@ static char * formatValue(sprintfTag tag, Header h,
     memset(buf, 0, sizeof(buf));
     if (tag->ext) {
 /*@-boundswrite -branchstate @*/
-       if (getExtension(h, tag->ext, &type, &data, &count, ec + tag->extNum))
+       if (getExtension(hsa, tag->ext, &type, &data, &count, hsa->ec + tag->extNum))
        {
            count = 1;
            type = RPM_STRING_TYPE;     
@@ -2812,7 +2816,7 @@ static char * formatValue(sprintfTag tag, Header h,
 /*@=boundswrite =branchstate @*/
     } else {
 /*@-boundswrite -branchstate @*/
-       if (!headerGetEntry(h, tag->tag, &type, (void **)&data, &count)) {
+       if (!headerGetEntry(hsa->h, tag->tag, &type, (void **)&data, &count)) {
            count = 1;
            type = RPM_STRING_TYPE;     
            data = "(none)";
@@ -2827,10 +2831,7 @@ static char * formatValue(sprintfTag tag, Header h,
                data = headerFreeData(data, type);
                /*@=modobserver =observertrans@*/
 
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg)
-                   *errmsg = _("(index out of range)");
-               /*@=observertrans =readonlytrans@*/
+               hsa->errmsg = _("(index out of range)");
                return NULL;
            }
            break;
@@ -2858,19 +2859,15 @@ static char * formatValue(sprintfTag tag, Header h,
 /*@=boundswrite@*/
 
     if (tag->type) {
-       ext = extensions;
-       while (ext->type != HEADER_EXT_LAST) {
-           if (ext->name != NULL && ext->type == HEADER_EXT_FORMAT
-           && !strcmp(ext->name, tag->type))
-           {
+       for (ext = hsa->exts; ext != NULL && ext->type != HEADER_EXT_LAST;
+           ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
+       {
+           if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
+               continue;
+           if (!strcmp(ext->name, tag->type)) {
                tagtype = ext->u.formatFunction;
                break;
            }
-
-           if (ext->type == HEADER_EXT_MORE)
-               ext = ext->u.more;
-           else
-               ext++;
        }
     }
     
@@ -2989,49 +2986,28 @@ static char * formatValue(sprintfTag tag, Header h,
 
     /*@-branchstate@*/
     if (val && need > 0) {
-       if (((*vallenp) + need) >= (*allocedp)) {
-           if ((*allocedp) <= need)
-               (*allocedp) += need;
-/*@-shiftimplementation@*/
-           (*allocedp) <<= 1;
-/*@=shiftimplementation@*/
-/*@-unqualifiedtrans@*/ /* FIX: double indirection */
-           (*valp) = xrealloc((*valp), (*allocedp)+1); 
-/*@=unqualifiedtrans@*/
-       }
-       t = (*valp) + (*vallenp);
+       t = hsaReserve(hsa, need);
 /*@-boundswrite@*/
        te = stpcpy(t, val);
 /*@=boundswrite@*/
-       (*vallenp) += (te - t);
+       hsa->vallen += (te - t);
        val = _free(val);
     }
     /*@=branchstate@*/
 
-    return ((*valp) + (*vallenp));
+    return (hsa->val + hsa->vallen);
 }
 
 /**
- * @param h            header
+ * @param hsa          headerSprintf args
  * @param token
- * @param extensions
- * @param ec           extension cache
  * @param element
- * @retval *valp
- * @retval *vallenp
- * @retval *allocedp
- * @retval *errmsg     error message (if any)
  * @return             end of formatted string (NULL on error)
  */
 /*@observer@*/
-static char * singleSprintf(Header h, sprintfToken token,
-               const headerSprintfExtension extensions,
-               rpmec ec, int element,
-               char ** valp, int * vallenp, int * allocedp,
-               /*@null@*/ /*@out@*/ errmsg_t * errmsg)
-       /*@modifies h, ec, *valp, *vallenp, *allocedp, *errmsg @*/
-       /*@requires maxSet(valp) >= 0 /\ maxSet(vallenp) >= 0
-               /\ maxSet(allocedp) >= 0 /\ maxSet(errmsg) >= 0 @*/
+static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
+               int element)
+       /*@modifies hsa @*/
 {
     char * t, * te;
     int i, j;
@@ -3040,7 +3016,7 @@ static char * singleSprintf(Header h, sprintfToken token,
     int_32 count;
     sprintfToken spft;
     int condNumFormats;
-    int need;
+    size_t need;
 
     /* we assume the token and header have been validated already! */
 
@@ -3050,35 +3026,24 @@ static char * singleSprintf(Header h, sprintfToken token,
 
     case PTOK_STRING:
        need = token->u.string.len;
-       if (need <= 0) break;
-       if (((*vallenp) + need) >= (*allocedp)) {
-           if ((*allocedp) <= need)
-               (*allocedp) += need;
-/*@-shiftimplementation@*/
-           (*allocedp) <<= 1;
-/*@=shiftimplementation@*/
-/*@-unqualifiedtrans@*/ /* FIX: double indirection */
-           (*valp) = xrealloc((*valp), (*allocedp)+1); 
-/*@=unqualifiedtrans@*/
-       }
-       t = (*valp) + (*vallenp);
+       if (need == 0) break;
+       t = hsaReserve(hsa, need);
 /*@-boundswrite@*/
        te = stpcpy(t, token->u.string.string);
 /*@=boundswrite@*/
-       (*vallenp) += (te - t);
+       hsa->vallen += (te - t);
        break;
 
     case PTOK_TAG:
-       t = (*valp) + (*vallenp);
-       te = formatValue(&token->u.tag, h, extensions, ec,
-                       (token->u.tag.justOne ? 0 : element),
-                       valp, vallenp, allocedp, errmsg);
+       t = hsa->val + hsa->vallen;
+       te = formatValue(hsa, &token->u.tag,
+                       (token->u.tag.justOne ? 0 : element));
        if (te == NULL)
            return NULL;
        break;
 
     case PTOK_COND:
-       if (token->u.cond.tag.ext || headerIsEntry(h, token->u.cond.tag.tag)) {
+       if (token->u.cond.tag.ext || headerIsEntry(hsa->h, token->u.cond.tag.tag)) {
            spft = token->u.cond.ifFormat;
            condNumFormats = token->u.cond.numIfTokens;
        } else {
@@ -3087,22 +3052,11 @@ static char * singleSprintf(Header h, sprintfToken token,
        }
 
        need = condNumFormats * 20;
-       if (spft == NULL || need <= 0) break;
-       if (((*vallenp) + need) >= (*allocedp)) {
-           if ((*allocedp) <= need)
-               (*allocedp) += need;
-/*@-shiftimplementation@*/
-           (*allocedp) <<= 1;
-/*@=shiftimplementation@*/
-/*@-unqualifiedtrans@*/ /* FIX: double indirection */
-           (*valp) = xrealloc((*valp), (*allocedp)+1); 
-/*@=unqualifiedtrans@*/
-       }
+       if (spft == NULL || need == 0) break;
 
-       t = (*valp) + (*vallenp);
+       t = hsaReserve(hsa, need);
        for (i = 0; i < condNumFormats; i++, spft++) {
-           te = singleSprintf(h, spft, extensions, ec,
-                               element, valp, vallenp, allocedp, errmsg);
+           te = singleSprintf(hsa, spft, element);
            if (te == NULL)
                return NULL;
        }
@@ -3118,24 +3072,21 @@ static char * singleSprintf(Header h, sprintfToken token,
 
            if (spft->u.tag.ext) {
 /*@-boundswrite@*/
-               if (getExtension(h, spft->u.tag.ext, &type, NULL, &count, 
-                                ec + spft->u.tag.extNum))
+               if (getExtension(hsa, spft->u.tag.ext, &type, NULL, &count, 
+                                hsa->ec + spft->u.tag.extNum))
                     continue;
 /*@=boundswrite@*/
            } else {
 /*@-boundswrite@*/
-               if (!headerGetEntry(h, spft->u.tag.tag, &type, NULL, &count))
+               if (!headerGetEntry(hsa->h, spft->u.tag.tag, &type, NULL, &count))
                    continue;
 /*@=boundswrite@*/
            } 
            if (numElements > 1 && count != numElements)
            switch (type) {
            default:
-               /*@-observertrans -readonlytrans@*/
-               if (errmsg)
-                   *errmsg =
+               hsa->errmsg =
                        _("array iterator used with different sized arrays");
-               /*@=observertrans =readonlytrans@*/
                return NULL;
                /*@notreached@*/ /*@switchbreak@*/ break;
            case RPM_BIN_TYPE:
@@ -3148,41 +3099,20 @@ static char * singleSprintf(Header h, sprintfToken token,
 
        if (numElements == -1) {
            need = sizeof("(none)") - 1;
-           if (((*vallenp) + need) >= (*allocedp)) {
-               if ((*allocedp) <= need)
-                   (*allocedp) += need;
-/*@-shiftimplementation@*/
-               (*allocedp) <<= 1;
-/*@=shiftimplementation@*/
-/*@-unqualifiedtrans@*/ /* FIX: double indirection */
-               (*valp) = xrealloc((*valp), (*allocedp)+1);     
-/*@=unqualifiedtrans@*/
-           }
-           t = (*valp) + (*vallenp);
+           t = hsaReserve(hsa, need);
 /*@-boundswrite@*/
            te = stpcpy(t, "(none)");
 /*@=boundswrite@*/
-           (*vallenp) += (te - t);
+           hsa->vallen += (te - t);
        } else {
            need = numElements * token->u.array.numTokens * 10;
-           if (need <= 0) break;
-           if (((*vallenp) + need) >= (*allocedp)) {
-               if ((*allocedp) <= need)
-                   (*allocedp) += need;
-/*@-shiftimplementation@*/
-               (*allocedp) <<= 1;
-/*@=shiftimplementation@*/
-/*@-unqualifiedtrans@*/ /* FIX: double indirection */
-               (*valp) = xrealloc((*valp), (*allocedp)+1);     
-/*@=unqualifiedtrans@*/
-           }
+           if (need == 0) break;
 
-           t = (*valp) + (*vallenp);
+           t = hsaReserve(hsa, need);
            for (j = 0; j < numElements; j++) {
                spft = token->u.array.format;
                for (i = 0; i < token->u.array.numTokens; i++, spft++) {
-                   te = singleSprintf(h, spft, extensions, ec, j,
-                                       valp, vallenp, allocedp, errmsg);
+                   te = singleSprintf(hsa, spft, j);
                    if (te == NULL)
                        return NULL;
                }
@@ -3191,7 +3121,7 @@ static char * singleSprintf(Header h, sprintfToken token,
        break;
     }
 
-    return ((*valp) + (*vallenp));
+    return (hsa->val + hsa->vallen);
 }
 
 /**
@@ -3203,17 +3133,16 @@ static /*@only@*/ rpmec
 rpmecNew(const headerSprintfExtension extensions)
        /*@*/
 {
-    headerSprintfExtension ext = extensions;
+    headerSprintfExtension ext;
     rpmec ec;
     int i = 0;
 
-    while (ext->type != HEADER_EXT_LAST) {
+    for (ext = extensions; ext != NULL && ext->type != HEADER_EXT_LAST;
+       ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
+    {
        i++;
-       if (ext->type == HEADER_EXT_MORE)
-           ext = ext->u.more;
-       else
-           ext++;
     }
+
     ec = xcalloc(i, sizeof(*ec));
     return ec;
 }
@@ -3228,19 +3157,16 @@ static /*@null@*/ rpmec
 rpmecFree(const headerSprintfExtension extensions, /*@only@*/ rpmec ec)
        /*@modifies ec @*/
 {
-    headerSprintfExtension ext = extensions;
+    headerSprintfExtension ext;
     int i = 0;
 
-    while (ext->type != HEADER_EXT_LAST) {
+    for (ext = extensions; ext != NULL && ext->type != HEADER_EXT_LAST;
+       ext = (ext->type == HEADER_EXT_MORE ? ext->u.more : ext+1))
+    {
 /*@-boundswrite@*/
        if (ec[i].freeit) ec[i].data = _free(ec[i].data);
 /*@=boundswrite@*/
-
        i++;
-       if (ext->type == HEADER_EXT_MORE)
-           ext = ext->u.more;
-       else
-           ext++;
     }
 
     ec = _free(ec);
@@ -3263,56 +3189,55 @@ char * headerSprintf(Header h, const char * fmt,
                     const struct headerTagTableEntry_s * tbltags,
                     const struct headerSprintfExtension_s * extensions,
                     /*@null@*/ /*@out@*/ errmsg_t * errmsg)
-       /*@modifies *errmsg @*/
+       /*@modifies h, *errmsg @*/
+       /*@requires maxSet(errmsg) >= 0 @*/
 {
-/*@-castexpose@*/      /* FIX: legacy API shouldn't change. */
-    headerSprintfExtension exts = (headerSprintfExtension) extensions;
-    headerTagTableEntry tags = (headerTagTableEntry) tbltags;
-/*@=castexpose@*/
+    headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
     char * te;
-    char * fmtString;
-    sprintfToken format;
-    int numTokens;
-    char * val = NULL;
-    int vallen = 0;
-    int alloced = 0;
     int i;
-    rpmec ec;
  
-    /*fmtString = escapeString(fmt);*/
-    fmtString = xstrdup(fmt);
-   
+    hsa->h = headerLink(h);
+    hsa->fmt = xstrdup(fmt);
+/*@-castexpose@*/      /* FIX: legacy API shouldn't change. */
+    hsa->exts = (headerSprintfExtension) extensions;
+    hsa->tags = (headerTagTableEntry) tbltags;
+/*@=castexpose@*/
+    hsa->errmsg = NULL;
+
 /*@-boundswrite@*/
-    if (parseFormat(fmtString, tags, exts, &format, &numTokens, 
-                   NULL, PARSER_BEGIN, errmsg))
+    if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
        goto exit;
 /*@=boundswrite@*/
 
-    ec = rpmecNew(exts);
+    hsa->ec = rpmecNew(hsa->exts);
 
-    val = xstrdup("");
-    for (i = 0; i < numTokens; i++) {
+    hsa->val = xstrdup("");
+    for (i = 0; i < hsa->numTokens; i++) {
 /*@-boundswrite@*/
        /*@-mods@*/
-       te = singleSprintf(h, format + i, exts, ec, 0,
-               &val, &vallen, &alloced, errmsg);
+       te = singleSprintf(hsa, hsa->format + i, 0);
        /*@=mods@*/
        if (te == NULL) {
-           val = _free(val);
+           hsa->val = _free(hsa->val);
            break;
        }
 /*@=boundswrite@*/
     }
 
-    if (val != NULL && vallen < alloced)
-       val = xrealloc(val, vallen+1);  
+    if (hsa->val != NULL && hsa->vallen < hsa->alloced)
+       hsa->val = xrealloc(hsa->val, hsa->vallen+1);   
 
-    ec = rpmecFree(exts, ec);
-    format = freeFormat(format, numTokens);
+    hsa->ec = rpmecFree(hsa->exts, hsa->ec);
+    hsa->format = freeFormat(hsa->format, hsa->numTokens);
 
 exit:
-    fmtString = _free(fmtString);
-    return val;
+/*@-dependenttrans -observertrans @*/
+    if (errmsg)
+       *errmsg = hsa->errmsg;
+/*@=dependenttrans =observertrans @*/
+    hsa->h = headerFree(hsa->h);
+    hsa->fmt = _free(hsa->fmt);
+    return hsa->val;
 }
 
 /**