From c6197b39acef1dcbcc026bb38fb5233a27ef4a55 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 24 Jul 2011 23:19:53 -0500 Subject: [PATCH] parser: add dependency list support and refactor slightly --- parse.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 7 deletions(-) diff --git a/parse.c b/parse.c index b3bf392..4b8f15d 100644 --- a/parse.c +++ b/parse.c @@ -103,6 +103,165 @@ strdup_parse(pkg_t *pkg, const char *value) return strdup(buf); } +/* + * parse_deplist(pkg, depends) + * + * Add requirements to a .pc file. + * Commas are counted as whitespace, as to allow: + * @SUBSTVAR@, zlib + * getting substituted to: + * , zlib. + */ +typedef enum { + OUTSIDE_MODULE = 0, + INSIDE_MODULE_NAME = 1, + BEFORE_OPERATOR = 2, + INSIDE_OPERATOR = 3, + AFTER_OPERATOR = 4, + INSIDE_VERSION = 5 +} parse_state_t; + +static pkg_dependency_t * +pkg_dependency_add(pkg_dependency_t *head, const char *package, const char *version, pkg_comparator_t compare) +{ + pkg_dependency_t *dep; + + dep = calloc(sizeof(pkg_dependency_t), 1); + dep->package = strdup(package); + + if (dep->version != NULL) + dep->version = strdup(version); + + dep->compare = compare; + + dep->prev = head; + if (dep->prev != NULL) + dep->prev->next = dep; + + return dep; +} + +#define MODULE_SEPARATOR(c) ((c) == ',' || isspace ((c))) +#define OPERATOR_CHAR(c) ((c) == '<' || (c) == '>' || (c) == '!' || (c) == '=') + +static pkg_dependency_t * +parse_deplist(pkg_t *pkg, const char *depends) +{ + parse_state_t state = OUTSIDE_MODULE; + parse_state_t last_state = OUTSIDE_MODULE; + pkg_dependency_t *deplist = NULL; + pkg_dependency_t *deplist_head = NULL; + pkg_comparator_t compare = PKG_ANY; + char *kvdepends = strdup_parse(pkg, depends); + char *start = kvdepends; + char *ptr = kvdepends; + char *vstart = NULL; + char *package, *version; + + while (*ptr) + { + switch (state) + { + case OUTSIDE_MODULE: + if (!MODULE_SEPARATOR(*ptr)) + state = INSIDE_MODULE_NAME; + break; + + case INSIDE_MODULE_NAME: + if (isspace(*ptr)) + { + const char *sptr = ptr; + + while (*sptr && isspace(*sptr)) + sptr++; + + if (*sptr == '\0') + state = OUTSIDE_MODULE; + else if (MODULE_SEPARATOR(*sptr)) + state = OUTSIDE_MODULE; + else if (OPERATOR_CHAR(*sptr)) + state = BEFORE_OPERATOR; + else + state = OUTSIDE_MODULE; + } + else if (MODULE_SEPARATOR(*ptr)) + state = OUTSIDE_MODULE; + + if (state != INSIDE_MODULE_NAME && start != ptr) + { + char *iter = start; + + while (MODULE_SEPARATOR(*iter)) + iter++; + + package = strndup(iter, ptr - iter); +// fprintf(stderr, "Found package: %s\n", package); + start = ptr; + } + + if (state == OUTSIDE_MODULE) + { + deplist = pkg_dependency_add(deplist, package, NULL, PKG_ANY); + + if (deplist_head == NULL) + deplist_head = deplist; + + free(package); + package = NULL; + version = NULL; + } + + break; + + case BEFORE_OPERATOR: + if (OPERATOR_CHAR(*ptr)) + state = INSIDE_OPERATOR; + break; + + case INSIDE_OPERATOR: + if (!OPERATOR_CHAR(*ptr)) + state = AFTER_OPERATOR; + break; + + case AFTER_OPERATOR: + if (!isspace(*ptr)) + { + vstart = ptr; + state = INSIDE_VERSION; + } + break; + + case INSIDE_VERSION: + if (MODULE_SEPARATOR(*ptr)) + { + version = strndup(vstart, ptr - vstart); + state = OUTSIDE_MODULE; + +// fprintf(stderr, "Found version: %s\n", version); + deplist = pkg_dependency_add(deplist, package, version, PKG_ANY); + + if (deplist_head == NULL) + deplist_head = deplist; + + free(package); + package = NULL; + + free(version); + version = NULL; + } + + if (state == OUTSIDE_MODULE) + start = ptr; + break; + } + + ptr++; + } + + free(kvdepends); + return deplist_head; +} + /* * parse_file(filename) * @@ -124,7 +283,7 @@ parse_file(const char *filename) while (fgets(readbuf, BUFSIZ, f) != NULL) { - char *p, *key = NULL, *value = NULL; + char op, *p, *key = NULL, *value = NULL; readbuf[strlen(readbuf) - 1] = '\0'; @@ -139,21 +298,30 @@ parse_file(const char *filename) while (*p && isspace(*p)) p++; - value = strdup(p + 1); + op = *p++; - switch (*p) + while (*p && isspace(*p)) + p++; + + value = strdup(p); + + switch (op) { case ':': if (!strcasecmp(key, "Name")) pkg->realname = strdup_parse(pkg, value); - if (!strcasecmp(key, "Description")) + else if (!strcasecmp(key, "Description")) pkg->description = strdup_parse(pkg, value); - if (!strcasecmp(key, "Version")) + else if (!strcasecmp(key, "Version")) pkg->version = strdup_parse(pkg, value); - if (!strcasecmp(key, "CFLAGS")) + else if (!strcasecmp(key, "CFLAGS")) pkg->cflags = strdup_parse(pkg, value); - if (!strcasecmp(key, "LIBS")) + else if (!strcasecmp(key, "LIBS")) pkg->libs = strdup_parse(pkg, value); + else if (!strcasecmp(key, "Requires")) + pkg->requires = parse_deplist(pkg, value); + else if (!strcasecmp(key, "Conflicts")) + pkg->conflicts = parse_deplist(pkg, value); break; case '=': pkg->vars = tuple_add(pkg->vars, key, value);