From 1244f8f8e7c4ce92f538a40f369107ca6d022e84 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 9 May 2018 21:21:39 -0500 Subject: [PATCH] libpkgconf: refactor out the rfc822 message parser so that the cross-personality code can share it --- Makefile.am | 3 +- libpkgconf/CMakeLists.txt | 1 + libpkgconf/libpkgconf.h | 8 +++- libpkgconf/parser.c | 95 +++++++++++++++++++++++++++++++++++++++ libpkgconf/pkg.c | 90 +++++++++---------------------------- meson.build | 1 + 6 files changed, 127 insertions(+), 71 deletions(-) create mode 100644 libpkgconf/parser.c diff --git a/Makefile.am b/Makefile.am index a819f51..78f6494 100644 --- a/Makefile.am +++ b/Makefile.am @@ -137,7 +137,8 @@ libpkgconf_la_SOURCES = \ libpkgconf/dependency.c \ libpkgconf/queue.c \ libpkgconf/path.c \ - libpkgconf/personality.c + libpkgconf/personality.c \ + libpkgconf/parser.c libpkgconf_la_LDFLAGS = -no-undefined -version-info 3:0:0 -export-symbols-regex '^pkgconf_' dist_man_MANS = \ diff --git a/libpkgconf/CMakeLists.txt b/libpkgconf/CMakeLists.txt index 3504248..4ff40ca 100644 --- a/libpkgconf/CMakeLists.txt +++ b/libpkgconf/CMakeLists.txt @@ -13,6 +13,7 @@ ADD_LIBRARY(libpkgconf SHARED dependency.c fileio.c fragment.c + parser.c path.c personality.c pkg.c diff --git a/libpkgconf/libpkgconf.h b/libpkgconf/libpkgconf.h index 98006e7..8381b0e 100644 --- a/libpkgconf/libpkgconf.h +++ b/libpkgconf/libpkgconf.h @@ -248,7 +248,6 @@ PKGCONF_API const pkgconf_cross_personality_t *pkgconf_cross_personality_default #define PKGCONF_PKG_ERRF_PACKAGE_CONFLICT 0x4 #define PKGCONF_PKG_ERRF_DEPGRAPH_BREAK 0x8 -/* pkg.c */ #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define PRINTFLIKE(fmtarg, firstvararg) \ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) @@ -259,6 +258,13 @@ PKGCONF_API const pkgconf_cross_personality_t *pkgconf_cross_personality_default #define DEPRECATED #endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) */ +/* parser.c */ +typedef void (*pkgconf_parser_operand_func_t)(void *data, const size_t lineno, const char *key, const char *value); +typedef void (*pkgconf_parser_warn_func_t)(void *data, const char *fmt, ...); + +PKGCONF_API void pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename); + +/* pkg.c */ PKGCONF_API bool pkgconf_error(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3); PKGCONF_API bool pkgconf_warn(const pkgconf_client_t *client, const char *format, ...) PRINTFLIKE(2, 3); PKGCONF_API bool pkgconf_trace(const pkgconf_client_t *client, const char *filename, size_t lineno, const char *funcname, const char *format, ...) PRINTFLIKE(5, 6); diff --git a/libpkgconf/parser.c b/libpkgconf/parser.c new file mode 100644 index 0000000..704c4de --- /dev/null +++ b/libpkgconf/parser.c @@ -0,0 +1,95 @@ +/* + * parser.c + * rfc822 message parser + * + * Copyright (c) 2018 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include +#include +#include + +/* + * !doc + * + * .. c:function:: pkgconf_pkg_t *pkgconf_pkg_new_from_file(const pkgconf_client_t *client, const char *filename, FILE *f) + * + * Parse a .pc file into a pkgconf_pkg_t object structure. + * + * :param pkgconf_client_t* client: The pkgconf client object to use for dependency resolution. + * :param char* filename: The filename of the package file (including full path). + * :param FILE* f: The file object to read from. + * :returns: A ``pkgconf_pkg_t`` object which contains the package data. + * :rtype: pkgconf_pkg_t * + */ +void +pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *ops, const pkgconf_parser_warn_func_t warnfunc, const char *filename) +{ + char readbuf[PKGCONF_BUFSIZE]; + size_t lineno = 0; + + while (pkgconf_fgetline(readbuf, PKGCONF_BUFSIZE, f) != NULL) + { + char op, *p, *key, *value; + bool warned_key_whitespace = false, warned_value_whitespace = false; + + lineno++; + + p = readbuf; + while (*p && (isalpha((unsigned int)*p) || isdigit((unsigned int)*p) || *p == '_' || *p == '.')) + p++; + + key = readbuf; + if (!isalpha((unsigned int)*key) && !isdigit((unsigned int)*p)) + continue; + + while (*p && isspace((unsigned int)*p)) + { + if (!warned_key_whitespace) + { + warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n", + filename, lineno); + warned_key_whitespace = true; + } + + /* set to null to avoid trailing spaces in key */ + *p = '\0'; + p++; + } + + op = *p; + *p = '\0'; + p++; + + while (*p && isspace((unsigned int)*p)) + p++; + + value = p; + p = value + (strlen(value) - 1); + while (*p && isspace((unsigned int) *p) && p > value) + { + if (!warned_value_whitespace && op == '=') + { + warnfunc(data, "%s:" SIZE_FMT_SPECIFIER ": warning: trailing whitespace encountered while parsing value section\n", + filename, lineno); + warned_value_whitespace = true; + } + + *p = '\0'; + p--; + } + + if (ops[(unsigned char) op]) + ops[(unsigned char) op](data, lineno, key, value); + } + + fclose(f); +} diff --git a/libpkgconf/pkg.c b/libpkgconf/pkg.c index 2f3d12b..f01d32c 100644 --- a/libpkgconf/pkg.c +++ b/libpkgconf/pkg.c @@ -236,6 +236,26 @@ static const pkgconf_pkg_validity_check_t pkgconf_pkg_validations[] = { {"Version", offsetof(pkgconf_pkg_t, version)}, }; +static const pkgconf_parser_operand_func_t pkg_parser_funcs[] = { + [':'] = (pkgconf_parser_operand_func_t) pkgconf_pkg_parser_keyword_set, + ['='] = (pkgconf_parser_operand_func_t) pkgconf_pkg_parser_value_set +}; + +static void pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...) PRINTFLIKE(2, 3); + +static void +pkg_warn_func(pkgconf_pkg_t *pkg, const char *fmt, ...) +{ + char buf[PKGCONF_ITEM_SIZE]; + va_list va; + + va_start(va, fmt); + vsnprintf(buf, sizeof buf, fmt, va); + va_end(va); + + pkgconf_warn(pkg->owner, "%s", buf); +} + static bool pkgconf_pkg_validate(const pkgconf_client_t *client, const pkgconf_pkg_t *pkg) { @@ -273,9 +293,7 @@ pkgconf_pkg_t * pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *f) { pkgconf_pkg_t *pkg; - char readbuf[PKGCONF_BUFSIZE]; char *idptr; - size_t lineno = 0; pkg = calloc(sizeof(pkgconf_pkg_t), 1); pkg->owner = client; @@ -298,73 +316,7 @@ pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE * if (idptr) *idptr = '\0'; - while (pkgconf_fgetline(readbuf, PKGCONF_BUFSIZE, f) != NULL) - { - char op, *p, *key, *value; - bool warned_key_whitespace = false, warned_value_whitespace = false; - - lineno++; - - PKGCONF_TRACE(client, "%s:" SIZE_FMT_SPECIFIER " > [%s]", filename, lineno, readbuf); - - p = readbuf; - while (*p && (isalpha((unsigned int)*p) || isdigit((unsigned int)*p) || *p == '_' || *p == '.')) - p++; - - key = readbuf; - if (!isalpha((unsigned int)*key) && !isdigit((unsigned int)*p)) - continue; - - while (*p && isspace((unsigned int)*p)) - { - if (!warned_key_whitespace) - { - pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: whitespace encountered while parsing key section\n", - pkg->filename, lineno); - warned_key_whitespace = true; - } - - /* set to null to avoid trailing spaces in key */ - *p = '\0'; - p++; - } - - op = *p; - *p = '\0'; - p++; - - while (*p && isspace((unsigned int)*p)) - p++; - - value = p; - p = value + (strlen(value) - 1); - while (*p && isspace((unsigned int) *p) && p > value) - { - if (!warned_value_whitespace && op == '=') - { - pkgconf_warn(client, "%s:" SIZE_FMT_SPECIFIER ": warning: trailing whitespace encountered while parsing value section\n", - pkg->filename, lineno); - warned_value_whitespace = true; - } - - *p = '\0'; - p--; - } - - switch (op) - { - case ':': - pkgconf_pkg_parser_keyword_set(pkg, lineno, key, value); - break; - case '=': - pkgconf_pkg_parser_value_set(pkg, lineno, key, value); - break; - default: - break; - } - } - - fclose(f); + pkgconf_parser_parse(f, pkg, pkg_parser_funcs, (pkgconf_parser_warn_func_t) pkg_warn_func, pkg->filename); if (!pkgconf_pkg_validate(client, pkg)) { diff --git a/meson.build b/meson.build index 457b25f..b6bf81a 100644 --- a/meson.build +++ b/meson.build @@ -66,6 +66,7 @@ libpkgconf = shared_library('pkgconf', 'libpkgconf/dependency.c', 'libpkgconf/fileio.c', 'libpkgconf/fragment.c', + 'libpkgconf/parser.c', 'libpkgconf/path.c', 'libpkgconf/personality.c', 'libpkgconf/pkg.c',