From 9f56b79acf30747a1102bffcd85b0a9a585ec9a9 Mon Sep 17 00:00:00 2001 From: ewt Date: Mon, 7 Jul 1997 20:46:18 +0000 Subject: [PATCH] Added termnary expression evaluation CVS patchset: 1730 CVS date: 1997/07/07 20:46:18 --- CHANGES | 1 + docs/queryformat | 14 ++ lib/header.c | 410 ++++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 301 insertions(+), 124 deletions(-) diff --git a/CHANGES b/CHANGES index df9f19d..665ef5d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ 2.4.2 -> 2.4.3: - implemented install time prerequisites - repaired %{#TAG} query format + - implemented ternary operator as query expression 2.4.1 -> 2.4.2: - completely rewrote queryformat code diff --git a/docs/queryformat b/docs/queryformat index 3ad119b..621847a 100644 --- a/docs/queryformat +++ b/docs/queryformat @@ -121,3 +121,17 @@ name after the tag name. Here are some examples: The :shescape may be used on plain strings to get a string which can pass through a single level of shell and give the original string. + +Query Expressions +----------------- + +Simple conditionals may be evaluated through query expressions. Expressions +are delimited by %|...|. The only type of expression currently supported +is a C-like ternary conditional, which provides simple if/then/else +conditions. For example, the following query format display "present" if +the SOMETAG tag is present, and "missing" otherwise: + + %|SOMETAG?{present}:{missing}| + +Notice that the subformats "present" and "missing" must be inside of curly +braces. diff --git a/lib/header.c b/lib/header.c index a52578a..3d2ac12 100644 --- a/lib/header.c +++ b/lib/header.c @@ -28,6 +28,10 @@ #define INDEX_MALLOC_SIZE 8 +#define PARSER_BEGIN 0 +#define PARSER_IN_ARRAY 1 +#define PARSER_IN_EXPR 2 + static unsigned char header_magic[4] = { 0x8e, 0xad, 0xe8, 0x01 }; /* handy -- this tells us alignments for defined elements as well */ @@ -85,7 +89,7 @@ struct extensionCache { }; struct sprintfToken { - enum { PTOK_NONE = 0, PTOK_TAG, PTOK_ARRAY, PTOK_STRING } type; + enum { PTOK_NONE = 0, PTOK_TAG, PTOK_ARRAY, PTOK_STRING, PTOK_NEST } type; union { struct { struct sprintfToken * format; @@ -96,6 +100,10 @@ struct sprintfToken { char * string; int len; } string; + struct { + struct sprintfToken * format; + int numTokens; + } nest; } u; }; @@ -107,15 +115,22 @@ static int dataLength(int_32 type, void * p, int_32 count, int onDisk); static void copyEntry(struct indexEntry * entry, int_32 *type, void **p, int_32 *c); static void freeFormat(struct sprintfToken * format, int num); -int parseFormat(char * format, const struct headerTagTableEntry * tags, - const struct headerSprintfExtension * extentions, - struct sprintfToken ** formatPtr, int * numTokensPtr, - char ** endPtr, char ** error); +static void findTag(char * name, const struct headerTagTableEntry * tags, + const struct headerSprintfExtension * extensions, + const struct headerTagTableEntry ** tagMatch, + const struct headerSprintfExtension ** extMatch); +static int parseExpression(struct sprintfToken * token, char * str, + const struct headerTagTableEntry * tags, + const struct headerSprintfExtension * extensions, + char ** endPtr, char ** error); +static int parseFormat(char * format, const struct headerTagTableEntry * tags, + const struct headerSprintfExtension * extentions, + struct sprintfToken ** formatPtr, int * numTokensPtr, + char ** endPtr, int state, char ** error); static char * singleSprintf(Header h, struct sprintfToken * token, const struct headerSprintfExtension * extensions, struct extensionCache * extCache, int element); static char escapedChar(const char ch); -static char * escapeString(const char * src); static char * formatValue(struct sprintfTag * tag, Header h, const struct headerSprintfExtension * extensions, struct extensionCache * extcache, int element); @@ -1096,15 +1111,151 @@ static void freeFormat(struct sprintfToken * format, int num) { for (i = 0; i < num; i++) { if (format[i].type == PTOK_ARRAY) freeFormat(format[i].u.array.format, format[i].u.array.numTokens); + if (format[i].type == PTOK_NEST) + freeFormat(format[i].u.nest.format, format[i].u.nest.numTokens); } free(format); } -int parseFormat(char * str, const struct headerTagTableEntry * tags, - const struct headerSprintfExtension * extensions, - struct sprintfToken ** formatPtr, int * numTokensPtr, - char ** endPtr, char ** error) { - char * chptr, * start, * next, * tagname; +static void findTag(char * name, const struct headerTagTableEntry * tags, + const struct headerSprintfExtension * extensions, + const struct headerTagTableEntry ** tagMatch, + const struct headerSprintfExtension ** extMatch) { + const struct headerTagTableEntry * entry; + const struct headerSprintfExtension * ext; + char * tagname; + int i; + + *tagMatch = NULL; + *extMatch = NULL; + + if (strncmp("RPMTAG_", name, 7)) { + tagname = alloca(strlen(name) + 10); + strcpy(tagname, "RPMTAG_"); + strcat(tagname, name); + } else { + tagname = name; + } + + for (entry = tags; entry->name; entry++) + if (!strcasecmp(entry->name, tagname)) break; + + if (entry->name) { + *tagMatch = entry; + } else { + ext = extensions, i =0; + while (ext->type != HEADER_EXT_LAST) { + if (ext->type == HEADER_EXT_TAG && + !strcasecmp(ext->name, tagname)) { + break; + } + + if (ext->type == HEADER_EXT_MORE) + ext = ext->u.more; + else + ext++; + i++; + } + + if (ext->type == HEADER_EXT_TAG) { + *extMatch = ext; + } + } +} + +static int parseExpression(struct sprintfToken * token, char * str, + const struct headerTagTableEntry * tags, + const struct headerSprintfExtension * extensions, + char ** endPtr, char ** error) { + char * chptr, * end; + struct sprintfToken ifpart, elsepart; + const struct headerTagTableEntry * entry; + const struct headerSprintfExtension * ext; + + chptr = str; + while (*chptr && *chptr != '?') chptr++; + + if (*chptr != '?') { + *error = "? expected in expression"; + return 1; + } + + *chptr++ = '\0';; + + if (*chptr != '{') { + *error = "{ exected after ? in expression"; + return 1; + } + + chptr++; + + if (parseFormat(chptr, tags, extensions, &ifpart.u.nest.format, + &ifpart.u.nest.numTokens, &end, PARSER_IN_EXPR, error)) + return 1; + if (!*end) { + *error = "} expected in expression"; + freeFormat(ifpart.u.nest.format, ifpart.u.nest.numTokens); + return 1; + } + + chptr = end; + if (*chptr != ':') { + *error = ": expected following ? subexpression"; + freeFormat(ifpart.u.nest.format, ifpart.u.nest.numTokens); + return 1; + } + + chptr++; + + if (*chptr != '{') { + *error = "{ exected after : in expression"; + return 1; + } + + chptr++; + + if (parseFormat(chptr, tags, extensions, &elsepart.u.nest.format, + &elsepart.u.nest.numTokens, &end, PARSER_IN_EXPR, error)) + return 1; + if (!*end) { + *error = "} expected in expression"; + freeFormat(ifpart.u.nest.format, ifpart.u.nest.numTokens); + freeFormat(elsepart.u.nest.format, elsepart.u.nest.numTokens); + return 1; + } + + chptr = end; + if (*chptr != '|') { + *error = "| expected at end of expression"; + freeFormat(ifpart.u.nest.format, ifpart.u.nest.numTokens); + freeFormat(elsepart.u.nest.format, elsepart.u.nest.numTokens); + return 1; + } + + chptr++; + + *endPtr = chptr; + + findTag(str, tags, extensions, &entry, &ext); + + if (entry || ext) { + freeFormat(elsepart.u.nest.format, elsepart.u.nest.numTokens); + *token = ifpart; + } else { + freeFormat(ifpart.u.nest.format, ifpart.u.nest.numTokens); + *token = elsepart; + } + + token->type = PTOK_NEST; + + return 0; +} + +static int parseFormat(char * str, const struct headerTagTableEntry * tags, + const struct headerSprintfExtension * extensions, + struct sprintfToken ** formatPtr, int * numTokensPtr, + char ** endPtr, int state, char ** error) { + char * chptr, * start, * next, * dst; struct sprintfToken * format; int numTokens; int currToken; @@ -1120,120 +1271,109 @@ int parseFormat(char * str, const struct headerTagTableEntry * tags, numTokens = numTokens * 2 + 1; format = calloc(sizeof(*format), numTokens); + if (endPtr) *endPtr = NULL; - start = str; + dst = start = str; currToken = -1; while (*start && !done) { switch (*start) { case '%': currToken++; + *dst++ = '\0'; + start++; - *start++ = '\0'; - format[currToken].u.tag.format = start; - format[currToken].u.tag.pad = 0; - format[currToken].u.tag.justOne = 0; - format[currToken].u.tag.arrayCount = 0; - - chptr = start; - while (*chptr && *chptr != '{') chptr++; - if (!*chptr) { - *error = "missing { after %"; - freeFormat(format, numTokens); - return 1; - } + if (*start == '|') { + char * newEnd; - *chptr++ = '\0'; + start++; + if (parseExpression(format + currToken, start, tags, + extensions, &newEnd, error)) { + freeFormat(format, numTokens); + return 1; + } + start = newEnd; + } else { + format[currToken].u.tag.format = start; + format[currToken].u.tag.pad = 0; + format[currToken].u.tag.justOne = 0; + format[currToken].u.tag.arrayCount = 0; - while (start < chptr) { - if (isdigit(*start)) { - i = strtoul(start, &start, 10); - format[currToken].u.tag.pad += i; - } else { - start++; + chptr = start; + while (*chptr && *chptr != '{') chptr++; + if (!*chptr) { + *error = "missing { after %"; + freeFormat(format, numTokens); + return 1; } - } - if (*start == '=') { - format[currToken].u.tag.justOne = 1; - start++; - } else if (*start == '#') { - format[currToken].u.tag.justOne = 1; - format[currToken].u.tag.arrayCount = 1; - start++; - } + *chptr++ = '\0'; - next = start; - while (*next && *next != '}') next++; - if (!*next) { - *error = "missing } after %{"; - freeFormat(format, numTokens); - return 1; - } - *next++ = '\0'; + while (start < chptr) { + if (isdigit(*start)) { + i = strtoul(start, &start, 10); + format[currToken].u.tag.pad += i; + } else { + start++; + } + } - chptr = start; - while (*chptr && *chptr != ':') chptr++; + if (*start == '=') { + format[currToken].u.tag.justOne = 1; + start++; + } else if (*start == '#') { + format[currToken].u.tag.justOne = 1; + format[currToken].u.tag.arrayCount = 1; + start++; + } - if (*chptr) { - *chptr++ = '\0'; - if (!*chptr) { - *error = "empty tag format"; + next = start; + while (*next && *next != '}') next++; + if (!*next) { + *error = "missing } after %{"; freeFormat(format, numTokens); return 1; } - format[currToken].u.tag.type = chptr; - } else { - format[currToken].u.tag.type = NULL; - } - - if (!*start) { - *error = "empty tag name"; - freeFormat(format, numTokens); - return 1; - } + *next++ = '\0'; - if (strncmp("RPMTAG_", start, 7)) { - tagname = malloc(strlen(start) + 10); - strcpy(tagname, "RPMTAG_"); - strcat(tagname, start); - } else { - tagname = strdup(start); - } - - for (entry = tags; entry->name; entry++) - if (!strcasecmp(entry->name, tagname)) break; + chptr = start; + while (*chptr && *chptr != ':') chptr++; - if (!entry->name) { - ext = extensions, i =0; - while (ext->type != HEADER_EXT_LAST) { - if (ext->type == HEADER_EXT_TAG && - !strcasecmp(ext->name, tagname)) { - break; + if (*chptr) { + *chptr++ = '\0'; + if (!*chptr) { + *error = "empty tag format"; + freeFormat(format, numTokens); + return 1; } - - if (ext->type == HEADER_EXT_MORE) - ext = ext->u.more; - else - ext++; - i++; + format[currToken].u.tag.type = chptr; + } else { + format[currToken].u.tag.type = NULL; + } + + if (!*start) { + *error = "empty tag name"; + freeFormat(format, numTokens); + return 1; } - if (ext->type != HEADER_EXT_TAG) { + findTag(start, tags, extensions, &entry, &ext); + + if (entry) { + format[currToken].u.tag.ext = NULL; + format[currToken].u.tag.tag = entry->val; + } else if (ext) { + format[currToken].u.tag.ext = ext->u.tagFunction; + format[currToken].u.tag.extNum = ext - extensions; + } else { *error = "unknown tag"; freeFormat(format, numTokens); return 1; } - format[currToken].u.tag.ext = ext->u.tagFunction; - format[currToken].u.tag.extNum = i; - } else { - format[currToken].u.tag.ext = NULL; - format[currToken].u.tag.tag = entry->val; - } + format[currToken].type = PTOK_TAG; - format[currToken].type = PTOK_TAG; - - start = next; + start = next; + } break; @@ -1244,7 +1384,13 @@ int parseFormat(char * str, const struct headerTagTableEntry * tags, if (parseFormat(start, tags, extensions, &format[currToken].u.array.format, &format[currToken].u.array.numTokens, - &start, error)) { + &start, PARSER_IN_ARRAY, error)) { + freeFormat(format, numTokens); + return 1; + } + + if (!start) { + *error = "] expected at end of array"; freeFormat(format, numTokens); return 1; } @@ -1254,8 +1400,13 @@ int parseFormat(char * str, const struct headerTagTableEntry * tags, break; case ']': - if (!endPtr) { - *error = "unexpected ]"; + case '}': + if ((*start == ']' && state != PARSER_IN_ARRAY) || + (*start == '}' && state != PARSER_IN_EXPR)) { + if (*start == ']') + *error = "unexpected ]"; + else + *error = "unexpected }"; freeFormat(format, numTokens); return 1; } @@ -1268,12 +1419,20 @@ int parseFormat(char * str, const struct headerTagTableEntry * tags, if (currToken < 0 || format[currToken].type != PTOK_STRING) { currToken++; format[currToken].type = PTOK_STRING; - format[currToken].u.string.string = start; + dst = format[currToken].u.string.string = start; + } + + if (*start == '\\') { + start++; + *dst++ = escapedChar(*start++); + } else { + *dst++ = *start++; } - start++; } } + *dst = '\0'; + currToken++; for (i = 0; i < currToken; i++) { if (format[i].type == PTOK_STRING) @@ -1455,6 +1614,27 @@ static char * singleSprintf(Header h, struct sprintfToken * token, token->u.tag.justOne ? 0 : element); break; + case PTOK_NEST: + alloced = token->u.nest.numTokens * 20; + val = malloc(alloced); + *val = '\0'; + len = 0; + + for (i = 0; i < token->u.nest.numTokens; i++) { + thisItem = singleSprintf(h, token->u.nest.format + i, + extensions, extCache, i); + thisItemLen = strlen(thisItem); + if ((thisItemLen + len) >= alloced) { + alloced = (thisItemLen + len) + 200; + val = realloc(val, alloced); + } + strcat(val, thisItem); + len += thisItemLen; + free(thisItem); + } + + break; + case PTOK_ARRAY: numElements = -1; for (i = 0; i < token->u.array.numTokens; i++) { @@ -1508,26 +1688,6 @@ static char * singleSprintf(Header h, struct sprintfToken * token, return val; } -static char * escapeString(const char * src) { - char * rc = malloc(strlen(src) + 1); - char * dst; - - dst = rc; - - while (*src) { - if (*src == '\\') { - src++; - *dst++ = escapedChar(*src++); - } else { - *dst++ = *src++; - } - } - - *dst = '\0'; - - return rc; -} - static struct extensionCache * allocateExtensionCache( const struct headerSprintfExtension * extensions) { const struct headerSprintfExtension * ext = extensions; @@ -1558,9 +1718,11 @@ char * headerSprintf(Header h, const char * origFmt, int i; struct extensionCache * extCache; - fmtString = escapeString(origFmt); + /*fmtString = escapeString(origFmt);*/ + fmtString = strdup(origFmt); - if (parseFormat(fmtString, tags, extensions, &format, &numTokens, NULL, error)) { + if (parseFormat(fmtString, tags, extensions, &format, &numTokens, + NULL, PARSER_BEGIN, error)) { free(fmtString); return NULL; } -- 2.7.4