[Rpm-maint] [PATCH 16/18] Update %policy parsing to allow for more tags

Steve Lawrence slawrence at tresys.com
Wed Dec 23 20:57:36 UTC 2009


The previous %policy section parsing assumed %module would be the only
tag in in the section. This is limiting as we may need to add more tags
in the future. This patch generalizes %policy section parsing and makes
it much easier to add new tags.

To add a tag, all that must be done is add a new POLDECTag entry, add an
entry in policyDeclarations, and add a function to parse the tag.

This also adds some error checking/cleanup.
---
 build/policies.c |  217 ++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 145 insertions(+), 72 deletions(-)

diff --git a/build/policies.c b/build/policies.c
index 7e4d2ee..fbd8c8f 100644
--- a/build/policies.c
+++ b/build/policies.c
@@ -15,8 +15,8 @@
 
 #include "debug.h"
 
-#define SKIPSPACE(s)    { while (*(s) &&  risspace(*(s))) (s)++; }
-#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
+#define SKIPSPACE(s)    { while ((s) && *(s) &&  risspace(*(s))) (s)++; }
+#define SKIPNONSPACE(s) { while ((s) && *(s) && !risspace(*(s))) (s)++; }
 
 typedef struct ModuleRec_s {
 	char *path;
@@ -26,6 +26,19 @@ typedef struct ModuleRec_s {
 	uint32_t base;
 } *ModuleRec;
 
+typedef enum POLDECTag_e {
+	POLDEC_UNKNOWN = 0,
+	POLDEC_MODULE = 1,
+} POLDECTag;
+
+typedef const struct POLDEC {
+	POLDECTag tag;
+	int deprecated;
+	size_t len;
+	const char *token;
+	rpmRC (*parse)(const struct POLDEC * dec, ARGV_t *lines, Package pkg);
+} POLDEC_t;
+
 typedef enum MODATag_e {
 	MODOPT_UNKNOWN = 0,
 	MODOPT_NAME = 1,
@@ -41,8 +54,16 @@ typedef const struct MODA {
 	const char *token;
 } MODA_t;
 
+static rpmRC parseModule(POLDEC_t *dec, ARGV_t *pol, Package pkg);
+
+
 #define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
 
+static POLDEC_t const policyDeclarations[] = {
+	{POLDEC_MODULE, 0, LEN_AND_STR("%module"), &parseModule},
+	{POLDEC_UNKNOWN, 0, 0, 0, 0} /* must be last */
+};
+
 static MODA_t const moduleAttrs[] = {
 	{MODOPT_NAME, 0, LEN_AND_STR("name")},
 	{MODOPT_OBSOLETES, 0, LEN_AND_STR("obsoletes")},
@@ -89,6 +110,10 @@ static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg)
 	rpmtdReset(&policytypes);
 	rpmtdReset(&policytypesidx);
 
+	if (!mod || !pkg) {
+		goto exit;
+	}
+
 	fullpath = rpmGenPath(buildDir, NULL, mod->path);
 
 	if ((rpmioSlurp(fullpath, &raw, &rawlen)) != 0 || raw == NULL) {
@@ -270,108 +295,81 @@ static ModuleRec newModule(char * path)
 }
 
 
-static rpmRC parseModuleAttr(ModuleRec mod, char *line)
+static rpmRC parseModuleAttr(ModuleRec mod, MODATag key, char *val)
 {
-	MODA_t *moda;
-	char *l;
 	char *s;
 	char *end;
 	int multitoken;
 	rpmRC rc = RPMRC_FAIL;
 
-	if (!mod) {
-		rpmlog(RPMLOG_ERR, _("Expected %%module directive: %s\n"), line);
-		goto exit;
-	}
-
-	l = line;
-	SKIPSPACE(l);
-
-	for (moda = moduleAttrs; moda->token != MODOPT_UNKNOWN; moda++) {
-		if (rstrncasecmp(l, moda->token, moda->len)) {
-			continue;
-		}
-		if (moda->deprecated) {
-			rpmlog(RPMLOG_WARNING, _("%s is deprecated: %s\n"), moda->token, line);
-		}
-		break;
-	}
-
-	if (moda->token == MODOPT_UNKNOWN) {
-		rpmlog(RPMLOG_ERR, _("Unknown option: %s\n"), line);
+	SKIPSPACE(val);
+	if (val == '\0') {
+		rpmlog(RPMLOG_ERR, _("Empty value for module attribute %i\n"), key);
 		goto exit;
 	}
 
-	l += moda->len;
-	SKIPSPACE(l);
-	if (*l++ != ':') {
-		rpmlog(RPMLOG_ERR, _("Malformed option: %s\n"), line);
-		goto exit;
-	}
-
-	SKIPSPACE(l);
-	if (*l == '\0') {
-		rpmlog(RPMLOG_ERR, _("Empty option: %s\n"), line);
+	if (!mod) {
+		rpmlog(RPMLOG_ERR, _("No %module directive given for attribute: %s\n"), val);
 		goto exit;
 	}
 
-	s = end = l;
+	s = end = val;
 	SKIPNONSPACE(s); SKIPSPACE(s);
 	while (*end) end++;
 	multitoken = (s != end);
 
 #define SINGLE_TOKEN_ONLY \
 	if (multitoken) { \
-		rpmlog(RPMLOG_ERR, _("Option takes single token only: %s\n"), line); \
+		rpmlog(RPMLOG_ERR, _("Option takes single token only: %s\n"), val); \
 		goto exit; \
 	}
 
 #define SINGLE_DEFINE_ONLY(ptr) \
 	if (ptr) { \
-		rpmlog(RPMLOG_ERR, _("Option specified more than once: %s\n"), line); \
+		rpmlog(RPMLOG_ERR, _("Option specified more than once: %s\n"), val); \
 		goto exit; \
 	}
 
-	switch (moda->tag) {
+	switch (key) {
 	case MODOPT_NAME:
 		SINGLE_DEFINE_ONLY(mod->name)
 		SINGLE_TOKEN_ONLY
-		mod->name = strdup(l);
+		mod->name = strdup(val);
 		break;
 	case MODOPT_OBSOLETES:
 		SINGLE_DEFINE_ONLY(mod->obsoletes)
-		s = l;
+		s = val;
 		do {
 			SKIPNONSPACE(s);
 			end = s;
 			SKIPSPACE(s);
 			*end = '\0';
-			argvAdd(&mod->obsoletes, l);
-			l = s;
-		} while (*l != '\0');
+			argvAdd(&mod->obsoletes, val);
+			val = s;
+		} while (*val != '\0');
 		break;
 	case MODOPT_TYPES:
 		SINGLE_DEFINE_ONLY(mod->types)
-		s = l;
+		s = val;
 		do {
 			SKIPNONSPACE(s);
 			end = s;
 			SKIPSPACE(s);
 			*end = '\0';
-			argvAdd(&mod->types, l);
-			l = s;
-		} while (*l != '\0');
+			argvAdd(&mod->types, val);
+			val = s;
+		} while (*val != '\0');
 		break;
 	case MODOPT_BASE:
 		SINGLE_TOKEN_ONLY
-		mod->base = parseYesNo(l);
+		mod->base = parseYesNo(val);
 		if (mod->base == -1) {
-			rpmlog(RPMLOG_ERR, _("Unknown boolean value: %s\n"), line);
+			rpmlog(RPMLOG_ERR, _("Unknown boolean value: %s\n"), val);
 			goto exit;
 		}
 		break;
 	default:
-		rpmlog(RPMLOG_ERR, _("Unhandled option: %s\n"), line);
+		rpmlog(RPMLOG_ERR, _("Unhandled option: %s\n"), val);
 		goto exit;
 	}
 
@@ -381,14 +379,96 @@ exit:
 	return rc;
 }
 
+static rpmRC parseModule(POLDEC_t *dec, ARGV_t *pol, Package pkg)
+{
+	char *line;
+	char *s;
+	ModuleRec mod;
+	MODA_t *moda;
+	rpmRC rc = RPMRC_FAIL;
+
+	if (!dec || !pol || !pkg) {
+		goto exit;
+	}
+
+	line = **pol;
+	SKIPSPACE(line);
+	if (dec->tag != POLDEC_MODULE || rstrncasecmp(line, dec->token, dec->len)) {
+		rpmlog(RPMLOG_ERR, _("parseModule() cannot parse line: %s\n"), line);
+		goto exit;
+	}
+	line += dec->len;
+
+	mod = newModule(line);
+	if (!mod) {
+		goto exit;
+	}
+
+	/* parse attributes of the module */
+	while(*pol && *((*pol)+1)) {
+		s = line = *(*(pol)+1);
+		SKIPSPACE(s);
+
+		for (moda = moduleAttrs; moda->token != MODOPT_UNKNOWN; moda++) {
+			if (rstrncasecmp(s, moda->token, moda->len)) {
+				continue;
+			}
+			if (moda->deprecated) {
+				rpmlog(RPMLOG_WARNING, _("%s is deprecated: %s\n"), moda->token, line);
+			}
+			break;
+		}
+
+		if (moda->token == MODOPT_UNKNOWN) {
+			rc = RPMRC_OK;
+			goto exit;
+		}
+
+		s += moda->len;
+		SKIPSPACE(s);
+		if (*s++ != ':') {
+			rpmlog(RPMLOG_ERR, _("Malformed option: %s\n"), line);
+			goto exit;
+		}
+
+		SKIPSPACE(s);
+		if (*s == '\0') {
+			rpmlog(RPMLOG_ERR, _("Empty option: %s\n"), line);
+			goto exit;
+		}
+
+		rc = parseModuleAttr(mod, moda->tag, s);
+		if (rc != RPMRC_OK) {
+			goto exit;
+		}
+
+		(*pol)++;
+	}
+
+
+exit:
+	if (rc == RPMRC_OK) {
+		rc = writeModuleToHeader(mod, pkg);
+	}
+
+	freeModule(mod);
+
+	return rc;
+
+}
+
 static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
 {
 	ARGV_t policies = NULL;
 	ARGV_t pol;
-	ModuleRec mod = NULL;
 	char *linep;
+	POLDEC_t *dec;
 	rpmRC rc = RPMRC_FAIL;
 
+	if (!spec || !pkg) {
+		goto exit;
+	}
+
 	argvSplit(&policies, getStringBuf(pkg->policyList), "\n");
 	for (pol = policies; *pol != NULL; pol++) {
 		linep = *pol;
@@ -397,29 +477,23 @@ static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
 			continue;
 		}
 
-		if (!rstrncasecmp(linep, "%module", strlen("%module"))) {
-			if (mod) {
-				rc = writeModuleToHeader(mod, pkg);
-				if (rc != RPMRC_OK) {
-					goto exit;
-				}
-				mod = freeModule(mod);
-			}
-			mod = newModule(linep + strlen("%module"));
-			if (!mod) {
-				rc = RPMRC_FAIL;
-				goto exit;
+		for (dec = policyDeclarations; dec->tag != POLDEC_UNKNOWN; dec++) {
+			if (rstrncasecmp(linep, dec->token, dec->len)) {
+				continue;
 			}
-		} else {
-			rc = parseModuleAttr(mod, linep);
-			if (rc != RPMRC_OK) {
-				goto exit;
+			if (dec->deprecated) {
+				rpmlog(RPMLOG_WARNING, _("%s is deprecated: %s\n"), dec->token, linep);
 			}
+			break;
 		}
-	}
 
-	if (mod) {
-		rc = writeModuleToHeader(mod, pkg);
+		if (dec->tag == POLDEC_UNKNOWN) {
+			rpmlog(RPMLOG_ERR, _("Unknown option in %%policy section: %s\n"), linep);
+			rc = RPMRC_FAIL;
+			goto exit;
+		}
+
+		rc = dec->parse(dec, &pol, pkg);
 		if (rc != RPMRC_OK) {
 			goto exit;
 		}
@@ -428,7 +502,6 @@ static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
 	rc = RPMRC_OK;
 
 exit:
-	mod = freeModule(mod);
 	argvFree(policies);
 
 	return rc;
-- 
1.6.0.6



More information about the Rpm-maint mailing list