add generalized expression handler (Tom Dyas<tdyas@remus.rutgers.edu>)
CVS patchset: 2403 CVS date: 1998/10/06 17:34:58
This commit is contained in:
parent
606a74badc
commit
fecf31143c
1
CHANGES
1
CHANGES
|
@ -1,4 +1,5 @@
|
|||
2.5.5 -> 2.9
|
||||
- add generalized expression handler (Tom Dyas<tdyas@remus.rutgers.edu>)
|
||||
- use /usr/lib/rpm/mkinstalldirs if mkdir -p fails.
|
||||
- more portable dirent handling (Hermann Lauer).
|
||||
- add Slovak translation (Stanislav Meduna <stano@trillian.eunet.sk>)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,652 @@
|
|||
/*
|
||||
* Simple Expression Parser
|
||||
* Copyright (C) 1998 Tom Dyas <tdyas@eden.rutgers.edu>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
29
build/spec.c
29
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;
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
Loading…
Reference in New Issue