From fecf31143c2da611b824e323299ac52c7144c46a Mon Sep 17 00:00:00 2001 From: jbj Date: Tue, 6 Oct 1998 17:34:58 +0000 Subject: [PATCH] add generalized expression handler (Tom Dyas) CVS patchset: 2403 CVS date: 1998/10/06 17:34:58 --- CHANGES | 1 + build/Makefile.in | 2 +- build/expression.c | 652 +++++++++++++++++++++++++++++++++++++++++++++ build/parseSpec.c | 99 +++++-- build/rpmbuild.h | 5 + build/rpmspec.h | 15 +- build/spec.c | 29 +- po/Makefile.in | 9 +- 8 files changed, 779 insertions(+), 33 deletions(-) create mode 100644 build/expression.c diff --git a/CHANGES b/CHANGES index 8e1d6e503..83adcf1b1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,5 @@ 2.5.5 -> 2.9 + - add generalized expression handler (Tom Dyas) - use /usr/lib/rpm/mkinstalldirs if mkdir -p fails. - more portable dirent handling (Hermann Lauer). - add Slovak translation (Stanislav Meduna ) diff --git a/build/Makefile.in b/build/Makefile.in index edd5876d1..df50eda1f 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -3,7 +3,7 @@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ LIBOBJECTS = \ - build.o files.o misc.o myftw.o names.o pack.o \ + build.o expression.o files.o misc.o myftw.o names.o pack.o \ parseBuildInstallClean.o parseChangelog.o parseDescription.o \ parseFiles.o parsePreamble.o parsePrep.o parseReqs.o \ parseScript.o parseSpec.o reqprov.o spec.o diff --git a/build/expression.c b/build/expression.c new file mode 100644 index 000000000..8aefeebb7 --- /dev/null +++ b/build/expression.c @@ -0,0 +1,652 @@ +/* + * Simple Expression Parser + * Copyright (C) 1998 Tom Dyas + * + * This module implements a basic expression parser with support for + * integer and string datatypes. For ease of programming, we use the + * top-down "recursive descent" method of parsing. While a + * table-driven bottom-up parser might be faster, it does not really + * matter for the expressions we will be parsing. + * + * This work is provided under the GPL or LGPL at your choice. + */ + +#include "system.h" + +#include "intl.h" +#include "rpmbuild.h" +#include "rpmlib.h" + +/* #define DEBUG_PARSER */ + +#ifdef DEBUG_PARSER +#include +#define DEBUG(x) do { x ; } while (0) +#else +#define DEBUG(x) do { } while (0) +#endif + + +/* + * Encapsulation of a "value" + */ + +typedef struct _value +{ + enum { VALUE_TYPE_INTEGER, VALUE_TYPE_STRING } type; + union { + char *s; + int i; + } data; +} *Value; + +static Value valueMakeInteger(int i) +{ + Value v; + + v = (Value) malloc(sizeof(struct _value)); + v->type = VALUE_TYPE_INTEGER; + v->data.i = i; + return v; +} + +static Value valueMakeString(const char *s) +{ + Value v; + + v = (Value) malloc(sizeof(struct _value)); + v->type = VALUE_TYPE_STRING; + v->data.s = strdup(s); + return v; +} + +static void valueFree(Value v) +{ + if (v) { + if (v->type == VALUE_TYPE_STRING) free(v->data.s); + free(v); + } +} + +static void valueDump(Value v, FILE *fp) +{ + if (v) { + if (v->type == VALUE_TYPE_INTEGER) + fprintf(fp, "INTEGER %d\n", v->data.i); + else + fprintf(fp, "STRING '%s'\n", v->data.s); + } else + fprintf(fp, "NULL\n"); +} + +#define valueIsInteger(v) ((v)->type == VALUE_TYPE_INTEGER) +#define valueIsString(v) ((v)->type == VALUE_TYPE_STRING) +#define valueSameType(v1,v2) ((v1)->type == (v2)->type) + + +/* + * Parser state. + */ + +typedef struct _parseState +{ + char *str; /* expression string */ + char *p; /* current position in expression string */ + int nextToken; /* current lookahead token */ + Value tokenValue; /* valid when TOK_INTEGER or TOK_STRING */ + Spec spec; /* spec file that we are parsing inside of */ +} *ParseState; + + +/* + * Token parser. + */ + +#define TOK_EOF 0 +#define TOK_INTEGER 1 +#define TOK_STRING 2 +#define TOK_IDENTIFIER 3 +#define TOK_ADD 4 +#define TOK_MINUS 5 +#define TOK_MULTIPLY 6 +#define TOK_DIVIDE 7 +#define TOK_OPEN_P 8 +#define TOK_CLOSE_P 9 +#define TOK_EQ 10 +#define TOK_NEQ 11 +#define TOK_LT 12 +#define TOK_LE 13 +#define TOK_GT 14 +#define TOK_GE 15 +#define TOK_NOT 16 +#define TOK_LOGICAL_AND 17 +#define TOK_LOGICAL_OR 18 + +#define EXPRBUFSIZ BUFSIZ + +static int readToken(ParseState state) +{ + int token; + Value v = NULL; + char *p = state->p; + + /* Skip whitespace before the next token. */ + while (*p && isspace(*p)) p++; + + switch (*p) { + case '\0': + token = TOK_EOF; + p--; + break; + case '+': + token = TOK_ADD; + break; + case '-': + token = TOK_MINUS; + break; + case '*': + token = TOK_MULTIPLY; + break; + case '/': + token = TOK_DIVIDE; + break; + case '(': + token = TOK_OPEN_P; + break; + case ')': + token = TOK_CLOSE_P; + break; + case '=': + token = TOK_EQ; + break; + case '!': + if (p[1] == '=') { + token = TOK_NEQ; + p++; + } else + token = TOK_NOT; + break; + case '<': + if (p[1] == '=') { + token = TOK_LE; + p++; + } else + token = TOK_LT; + break; + case '>': + if (p[1] == '=') { + token = TOK_GE; + p++; + } else + token = TOK_GT; + break; + case '&': + if (p[1] == '&') { + token = TOK_LOGICAL_AND; + p++; + } else { + rpmError(RPMERR_BADSPEC, _("parse error in tokenizer")); + return -1; + } + break; + case '|': + if (p[1] == '|') { + token = TOK_LOGICAL_OR; + p++; + } else { + rpmError(RPMERR_BADSPEC, _("parse error in tokenizer")); + return -1; + } + break; + + default: + if (isdigit(*p)) { + char temp[EXPRBUFSIZ], *t = temp; + + while (*p && isdigit(*p)) + *t++ = *p++; + *t++ = '\0'; + p--; + + token = TOK_INTEGER; + v = valueMakeInteger(atoi(temp)); + + } else if (isalpha(*p)) { + char temp[EXPRBUFSIZ], *t = temp; + + while (*p && (isalnum(*p) || *p == '_')) + *t++ = *p++; + *t++ = '\0'; + p--; + + token = TOK_IDENTIFIER; + v = valueMakeString(temp); + + } else if (*p == '\"') { + char temp[EXPRBUFSIZ], *t = temp; + + p++; + while (*p && *p != '\"') + *t++ = *p++; + *t++ = '\0'; + + expandMacros(state->spec, state->spec->macros, temp, sizeof(temp)); + + token = TOK_STRING; + v = valueMakeString(temp); + + } else { + rpmError(RPMERR_BADSPEC, _("parse error in expression")); + return -1; + } + } + + state->p = p + 1; + state->nextToken = token; + state->tokenValue = v; + + DEBUG(printf("readToken: token=%d\n", token)); + DEBUG(valueDump(state->tokenValue, stdout)); + + return 0; +} + + +static Value doLogical(ParseState state); + +static Value doPrimary(ParseState state) +{ + Value v; + + DEBUG(printf("doPrimary()\n")); + + switch (state->nextToken) { + case TOK_OPEN_P: + if (readToken(state)) + return NULL; + v = doLogical(state); + if (state->nextToken != TOK_CLOSE_P) { + rpmError(RPMERR_BADSPEC, _("unmatched (")); + return NULL; + } + break; + + case TOK_INTEGER: + case TOK_STRING: + v = state->tokenValue; + if (readToken(state)) + return NULL; + break; + + case TOK_IDENTIFIER: { + char *name = state->tokenValue->data.s; + const char *body; + + body = getMacroBody(state->spec->macros, name); + if (!body) { + rpmError(RPMERR_BADSPEC, _("undefined identifier")); + return NULL; + } + + v = valueMakeString(body); + if (readToken(state)) + return NULL; + break; + } + + case TOK_MINUS: + if (readToken(state)) + return NULL; + + v = doPrimary(state); + if (v == NULL) + return NULL; + + if (! valueIsInteger(v)) { + rpmError(RPMERR_BADSPEC, _("- only on numbers")); + return NULL; + } + + v = valueMakeInteger(- v->data.i); + break; + + case TOK_NOT: + if (readToken(state)) + return NULL; + + v = doPrimary(state); + if (v == NULL) + return NULL; + + if (! valueIsInteger(v)) { + rpmError(RPMERR_BADSPEC, _("! only on numbers")); + return NULL; + } + + v = valueMakeInteger(! v->data.i); + break; + } + + DEBUG(valueDump(v, stdout)); + return v; +} + +static Value doMultiplyDivide(ParseState state) +{ + Value v1, v2 = NULL; + + DEBUG(printf("doMultiplyDivide()\n")); + + v1 = doPrimary(state); + if (v1 == NULL) + return NULL; + + while (state->nextToken == TOK_MULTIPLY + || state->nextToken == TOK_DIVIDE) { + int op = state->nextToken; + + if (readToken(state)) + return NULL; + + if (v2) valueFree(v2); + + v2 = doPrimary(state); + if (v2 == NULL) + return NULL; + + if (! valueSameType(v1, v2)) { + rpmError(RPMERR_BADSPEC, _("types must match")); + return NULL; + } + + if (valueIsInteger(v1)) { + int i1 = v1->data.i, i2 = v2->data.i; + + valueFree(v1); + if (op == TOK_MULTIPLY) + v1 = valueMakeInteger(i1 * i2); + else + v1 = valueMakeInteger(i1 / i2); + } else { + rpmError(RPMERR_BADSPEC, _("* / not suported for strings")); + return NULL; + } + } + + if (v2) valueFree(v2); + return v1; +} + +static Value doAddSubtract(ParseState state) +{ + Value v1, v2 = NULL; + + DEBUG(printf("doAddSubtract()\n")); + + v1 = doMultiplyDivide(state); + if (v1 == NULL) + return NULL; + + while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) { + int op = state->nextToken; + + if (readToken(state)) + return NULL; + + if (v2) valueFree(v2); + + v2 = doMultiplyDivide(state); + if (v2 == NULL) + return NULL; + + if (! valueSameType(v1, v2)) { + rpmError(RPMERR_BADSPEC, _("types must match")); + return NULL; + } + + if (valueIsInteger(v1)) { + int i1 = v1->data.i, i2 = v2->data.i; + + valueFree(v1); + if (op == TOK_ADD) + v1 = valueMakeInteger(i1 + i2); + else + v1 = valueMakeInteger(i1 - i2); + } else { + char *copy; + + if (op == TOK_MINUS) { + rpmError(RPMERR_BADSPEC, _("- not suported for strings")); + return NULL; + } + + copy = malloc(strlen(v1->data.s) + strlen(v2->data.s) + 1); + strcpy(copy, v1->data.s); + strcat(copy, v2->data.s); + + valueFree(v1); + v1 = valueMakeString(copy); + free(copy); + } + } + + if (v2) valueFree(v2); + return v1; +} + +static Value doRelational(ParseState state) +{ + Value v1, v2 = NULL; + + DEBUG(printf("doRelational()\n")); + + v1 = doAddSubtract(state); + if (v1 == NULL) + return NULL; + + while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) { + int op = state->nextToken; + + if (readToken(state)) + return NULL; + + if (v2) valueFree(v2); + + v2 = doAddSubtract(state); + if (v2 == NULL) + return NULL; + + if (! valueSameType(v1, v2)) { + rpmError(RPMERR_BADSPEC, _("types must match")); + return NULL; + } + + if (valueIsInteger(v1)) { + int i1 = v1->data.i, i2 = v2->data.i, r; + switch (op) { + case TOK_EQ: + r = (i1 == i2); + break; + case TOK_NEQ: + r = (i1 != i2); + break; + case TOK_LT: + r = (i1 < i2); + break; + case TOK_LE: + r = (i1 <= i2); + break; + case TOK_GT: + r = (i1 > i2); + break; + case TOK_GE: + r = (i1 >= i2); + break; + } + valueFree(v1); + v1 = valueMakeInteger(r); + } else { + char *s1 = v1->data.s, *s2 = v2->data.s, r; + switch (op) { + case TOK_EQ: + r = (strcmp(s1,s2) == 0); + break; + case TOK_NEQ: + r = (strcmp(s1,s2) != 0); + break; + case TOK_LT: + r = (strcmp(s1,s2) < 0); + break; + case TOK_LE: + r = (strcmp(s1,s2) <= 0); + break; + case TOK_GT: + r = (strcmp(s1,s2) > 0); + break; + case TOK_GE: + r = (strcmp(s1,s2) >= 0); + break; + } + valueFree(v1); + v1 = valueMakeInteger(r); + } + } + + if (v2) valueFree(v2); + return v1; +} + +static Value doLogical(ParseState state) +{ + Value v1, v2 = NULL; + + DEBUG(printf("doLogical()\n")); + + v1 = doRelational(state); + if (v1 == NULL) + return NULL; + + while (state->nextToken == TOK_LOGICAL_AND + || state->nextToken == TOK_LOGICAL_OR) { + int op = state->nextToken; + + if (readToken(state)) + return NULL; + + if (v2) valueFree(v2); + + v2 = doRelational(state); + if (v2 == NULL) + return NULL; + + if (! valueSameType(v1, v2)) { + rpmError(RPMERR_BADSPEC, _("types must match")); + return NULL; + } + + if (valueIsInteger(v1)) { + int i1 = v1->data.i, i2 = v2->data.i; + + valueFree(v1); + if (op == TOK_LOGICAL_AND) + v1 = valueMakeInteger(i1 && i2); + else + v1 = valueMakeInteger(i1 || i2); + } else { + rpmError(RPMERR_BADSPEC, _("&& and || not suported for strings")); + return NULL; + } + } + + if (v2) valueFree(v2); + return v1; +} + +int parseExpressionBoolean(Spec spec, char *expr) +{ + struct _parseState state; + int result; + Value v; + + DEBUG(printf("parseExprBoolean(?, '%s')\n", expr)); + + /* Initialize the expression parser state. */ + state.str = state.p = strdup(expr); + state.spec = spec; + readToken(&state); + + /* Parse the expression. */ + v = doLogical(&state); + if (!v) { + free(state.str); + return -1; + } + + /* If the next token is not TOK_EOF, we have a syntax error. */ + if (state.nextToken != TOK_EOF) { + rpmError(RPMERR_BADSPEC, _("syntax error in expression")); + free(state.str); + return -1; + } + + DEBUG(valueDump(v, stdout)); + + switch (v->type) { + case VALUE_TYPE_INTEGER: + result = v->data.i != 0; + break; + case VALUE_TYPE_STRING: + result = v->data.s[0] != '\0'; + break; + } + + free(state.str); + valueFree(v); + return result; +} + +char * parseExpressionString(Spec spec, char *expr) +{ + struct _parseState state; + char *result; + Value v; + + DEBUG(printf("parseExprBoolean(?, '%s')\n", expr)); + + /* Initialize the expression parser state. */ + state.str = state.p = strdup(expr); + state.spec = spec; + readToken(&state); + + /* Parse the expression. */ + v = doLogical(&state); + if (!v) { + free(state.str); + return NULL; + } + + /* If the next token is not TOK_EOF, we have a syntax error. */ + if (state.nextToken != TOK_EOF) { + rpmError(RPMERR_BADSPEC, _("syntax error in expression")); + free(state.str); + return NULL; + } + + DEBUG(valueDump(v, stdout)); + + switch (v->type) { + case VALUE_TYPE_INTEGER: { + char buf[128]; + sprintf(buf, "%d", v->data.i); + result = strdup(buf); + break; + } + case VALUE_TYPE_STRING: + result = strdup(v->data.s); + break; + } + + free(state.str); + valueFree(v); + return result; +} diff --git a/build/parseSpec.c b/build/parseSpec.c index af838256e..9ae2b7fe6 100644 --- a/build/parseSpec.c +++ b/build/parseSpec.c @@ -101,33 +101,50 @@ int readLine(Spec spec, int strip) int match; char ch; struct ReadLevelEntry *rl; + struct OpenFileInfo *ofi = spec->fileStack; - /* Make sure the spec file is open */ - if (!spec->file) { - if (!(spec->file = fopen(spec->specFile, "r"))) { - rpmError(RPMERR_BADSPEC, "Unable to open: %s\n", spec->specFile); + /* Make sure the current file is open */ +retry: + if (!ofi->file) { + if (!(ofi->file = fopen(ofi->fileName, "r"))) { + rpmError(RPMERR_BADSPEC, _("Unable to open: %s\n"), + ofi->fileName); return RPMERR_BADSPEC; } - spec->lineNum = 0; + spec->lineNum = ofi->lineNum = 0; } /* Make sure we have something in the read buffer */ - if (!spec->readPtr || ! *(spec->readPtr)) { - if (!fgets(spec->readBuf, BUFSIZ, spec->file)) { + if (!ofi->readPtr || ! *(ofi->readPtr)) { + if (!fgets(ofi->readBuf, BUFSIZ, ofi->file)) { /* EOF */ if (spec->readStack->next) { - rpmError(RPMERR_UNMATCHEDIF, "Unclosed %%if"); + rpmError(RPMERR_UNMATCHEDIF, _("Unclosed %%if")); return RPMERR_UNMATCHEDIF; } - return 1; + + /* remove this file from the stack */ + spec->fileStack = ofi->next; + fclose(ofi->file); + FREE(ofi->fileName); + free(ofi); + + /* only on last file do we signal EOF to caller */ + ofi = spec->fileStack; + if (ofi == NULL) + return 1; + + /* otherwise, go back and try the read again. */ + goto retry; } - spec->readPtr = spec->readBuf; - spec->lineNum++; + ofi->readPtr = ofi->readBuf; + ofi->lineNum++; + spec->lineNum = ofi->lineNum; /*rpmMessage(RPMMESS_DEBUG, "LINE: %s", spec->readBuf);*/ } /* Copy a single line to the line buffer */ - from = spec->readPtr; + from = ofi->readPtr; to = last = spec->line; ch = ' '; while (*from && ch != '\n') { @@ -137,7 +154,7 @@ int readLine(Spec spec, int strip) } } *to = '\0'; - spec->readPtr = from; + ofi->readPtr = from; if (strip & STRIP_COMMENTS) { handleComments(spec->line); @@ -149,7 +166,7 @@ int readLine(Spec spec, int strip) if (spec->readStack->reading) { if (expandMacros(spec, spec->macros, spec->line, sizeof(spec->line))) { - rpmError(RPMERR_BADSPEC, "line %d: %s", spec->lineNum, spec->line); + rpmError(RPMERR_BADSPEC, _("line %d: %s"), spec->lineNum, spec->line); return RPMERR_BADSPEC; } } @@ -167,11 +184,14 @@ int readLine(Spec spec, int strip) match = matchTok(os, s); } else if (! strncmp("%ifnos", s, 6)) { match = !matchTok(os, s); + } else if (! strncmp("%if", s, 3)) { + match = parseExpressionBoolean(spec, s + 3); + if (match < 0) return RPMERR_BADSPEC; } else if (! strncmp("%else", s, 5)) { if (! spec->readStack->next) { /* Got an else with no %if ! */ - rpmError(RPMERR_UNMATCHEDIF, "line %d: Got a %%else with no if", - spec->lineNum); + rpmError(RPMERR_UNMATCHEDIF, _("%s:%d: Got a %%else with no if"), + ofi->fileName, ofi->lineNum); return RPMERR_UNMATCHEDIF; } spec->readStack->reading = @@ -180,14 +200,36 @@ int readLine(Spec spec, int strip) } else if (! strncmp("%endif", s, 6)) { if (! spec->readStack->next) { /* Got an end with no %if ! */ - rpmError(RPMERR_UNMATCHEDIF, "line %d: Got a %%endif with no if", - spec->lineNum); + rpmError(RPMERR_UNMATCHEDIF, _("%s:%d: Got a %%endif with no if"), + ofi->fileName, ofi->lineNum); return RPMERR_UNMATCHEDIF; } rl = spec->readStack; spec->readStack = spec->readStack->next; free(rl); spec->line[0] = '\0'; + } else if (! strncmp("%include", s, 8)) { + char *fileName = s + 8, *endFileName, *p; + + if (! isspace(*fileName)) { + rpmError(RPMERR_BADSPEC, _("malformed %%include statement")); + return RPMERR_BADSPEC; + } + while (*fileName && isspace(*fileName)) fileName++; + endFileName = fileName; + while (*endFileName && !isspace(*endFileName)) endFileName++; + p = endFileName; + SKIPSPACE(p); + if (*p != '\0') { + rpmError(RPMERR_BADSPEC, _("malformed %%include statement")); + return RPMERR_BADSPEC; + } + + *endFileName = '\0'; + forceIncludeFile(spec, fileName); + + ofi = spec->fileStack; + goto retry; } if (match != -1) { rl = malloc(sizeof(struct ReadLevelEntry)); @@ -206,10 +248,25 @@ int readLine(Spec spec, int strip) void closeSpec(Spec spec) { - if (spec->file) { - fclose(spec->file); + struct OpenFileInfo *ofi; + + while (spec->fileStack) { + ofi = spec->fileStack; + spec->fileStack = spec->fileStack->next; + if (ofi->file) fclose(ofi->file); + FREE(ofi->fileName); + free(ofi); } - spec->file = NULL; +} + +void forceIncludeFile(Spec spec, const char * fileName) +{ + struct OpenFileInfo * ofi; + + ofi = newOpenFileInfo(); + ofi->fileName = strdup(fileName); + ofi->next = spec->fileStack; + spec->fileStack = ofi; } int noLang = 0; /* XXX FIXME: pass as arg */ diff --git a/build/rpmbuild.h b/build/rpmbuild.h index add90f57b..81d634405 100644 --- a/build/rpmbuild.h +++ b/build/rpmbuild.h @@ -113,6 +113,11 @@ int parseTrigger(Spec spec, Package pkg, char *field, int tag); int parseScript(Spec spec, int parsePart); int parseBuildInstallClean(Spec spec, int parsePart); +/* from build/expression.h */ + +int parseExpressionBoolean(Spec, char *); +char *parseExpressionString(Spec, char *); + /* from build/build.h */ int doScript(Spec spec, int what, char *name, StringBuf sb, int test); diff --git a/build/rpmspec.h b/build/rpmspec.h index c76056e97..f5b933f4a 100644 --- a/build/rpmspec.h +++ b/build/rpmspec.h @@ -42,13 +42,20 @@ struct ReadLevelEntry { struct ReadLevelEntry *next; }; +struct OpenFileInfo { + char *fileName; + FILE *file; + int lineNum; + char readBuf[BUFSIZ]; + char *readPtr; + struct OpenFileInfo *next; +}; + struct SpecStruct { char *specFile; char *sourceRpmName; - FILE *file; - char readBuf[BUFSIZ]; - char *readPtr; + struct OpenFileInfo *fileStack; char line[BUFSIZ]; int lineNum; @@ -129,6 +136,8 @@ extern "C" { Spec newSpec(void); void freeSpec(Spec spec); +struct OpenFileInfo * newOpenFileInfo(void); + int addSource(Spec spec, Package pkg, char *field, int tag); int parseNoSource(Spec spec, char *field, int tag); diff --git a/build/spec.c b/build/spec.c index c50af5ba4..be5ee2287 100644 --- a/build/spec.c +++ b/build/spec.c @@ -333,9 +333,7 @@ Spec newSpec(void) spec->specFile = NULL; spec->sourceRpmName = NULL; - spec->file = NULL; - spec->readBuf[0] = '\0'; - spec->readPtr = NULL; + spec->fileStack = NULL; spec->line[0] = '\0'; spec->readStack = malloc(sizeof(struct ReadLevelEntry)); spec->readStack->next = NULL; @@ -396,8 +394,9 @@ static void freeSources(Spec spec) void freeSpec(Spec spec) { + struct OpenFileInfo *ofi; struct ReadLevelEntry *rl; - + freeStringBuf(spec->prep); freeStringBuf(spec->build); freeStringBuf(spec->install); @@ -408,6 +407,13 @@ void freeSpec(Spec spec) FREE(spec->specFile); FREE(spec->sourceRpmName); + while (spec->fileStack) { + ofi = spec->fileStack; + spec->fileStack = spec->fileStack->next; + FREE(ofi->fileName); + free(ofi); + } + while (spec->readStack) { rl = spec->readStack; spec->readStack = spec->readStack->next; @@ -444,3 +450,18 @@ void freeSpec(Spec spec) free(spec); } + +struct OpenFileInfo * newOpenFileInfo(void) +{ + struct OpenFileInfo *ofi; + + ofi = malloc(sizeof(struct OpenFileInfo)); + ofi->file = NULL; + ofi->fileName = NULL; + ofi->lineNum = 0; + ofi->readBuf[0] = '\0'; + ofi->readPtr = NULL; + ofi->next = NULL; + + return ofi; +} diff --git a/po/Makefile.in b/po/Makefile.in index f28cd1bbc..c80869c5f 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -19,10 +19,11 @@ POTFILES = \ ../install.c ../query.c ../rpm.c \ ../url.c ../verify.c \ ../rpm2cpio.c ../convertdb.c ../oldrpmdb.c \ - ../build/build.c ../build/files.c ../build/misc.c ../build/myftw.c \ - ../build/names.c ../build/pack.c ../build/parseBuildInstallClean.c \ - ../build/parseChangelog.c ../build/parseDescription.c \ - ../build/parseFiles.c ../build/parsePreamble.c ../build/parsePrep.c \ + ../build/build.c ../build/expression.c ../build/files.c \ + ../build/misc.c ../build/myftw.c ../build/names.c ../build/pack.c \ + ../build/parseBuildInstallClean.c ../build/parseChangelog.c \ + ../build/parseDescription.c ../build/parseFiles.c \ + ../build/parsePreamble.c ../build/parsePrep.c \ ../build/parseReqs.c ../build/parseScript.c ../build/parseSpec.c \ ../build/reqprov.c ../build/spec.c \ ../lib/cpio.c ../lib/dbindex.c ../lib/depends.c ../lib/falloc.c \