From 95fee14dfa5bd3896c510077af36ea371a9a2975 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 26 Oct 2018 13:47:53 +0300 Subject: Merge with 1.5.4 upstream package version --- libpkgconf/pkg.c | 330 +++++++++++++++++++++++++++---------------------------- 1 file changed, 161 insertions(+), 169 deletions(-) (limited to 'libpkgconf/pkg.c') diff --git a/libpkgconf/pkg.c b/libpkgconf/pkg.c index 0feb4d6..24ace6f 100644 --- a/libpkgconf/pkg.c +++ b/libpkgconf/pkg.c @@ -49,80 +49,19 @@ str_has_suffix(const char *str, const char *suffix) return !strncasecmp(str + str_len - suf_len, suffix, suf_len); } -static inline const char * -get_default_pkgconfig_path(char *outbuf, size_t outlen) +static char * +pkg_get_parent_dir(pkgconf_pkg_t *pkg) { -#ifdef _WIN32 - char namebuf[MAX_PATH]; - char *p; - - int sizepath = GetModuleFileName(NULL, namebuf, sizeof namebuf); - char * winslash; - namebuf[sizepath] = '\0'; - while ((winslash = strchr (namebuf, '\\')) != NULL) - { - *winslash = '/'; - } - p = strrchr(namebuf, '/'); - if (p == NULL) - return PKG_DEFAULT_PATH; - - *p = '\0'; - pkgconf_strlcpy(outbuf, namebuf, outlen); - pkgconf_strlcat(outbuf, "/", outlen); - pkgconf_strlcat(outbuf, "../lib/pkgconfig", outlen); - pkgconf_strlcat(outbuf, ";", outlen); - pkgconf_strlcat(outbuf, namebuf, outlen); - pkgconf_strlcat(outbuf, "/", outlen); - pkgconf_strlcat(outbuf, "../share/pkgconfig", outlen); - - return outbuf; -#else - (void) outbuf; - (void) outlen; -#endif - - return PKG_DEFAULT_PATH; -} - -static const char * -pkg_get_parent_dir(pkgconf_pkg_t *pkg, char *buf, size_t buflen) -{ - char *pathbuf; + char buf[PKGCONF_ITEM_SIZE], *pathbuf; - pkgconf_strlcpy(buf, pkg->filename, buflen); + pkgconf_strlcpy(buf, pkg->filename, sizeof buf); pathbuf = strrchr(buf, PKG_DIR_SEP_S); if (pathbuf == NULL) pathbuf = strrchr(buf, '/'); if (pathbuf != NULL) pathbuf[0] = '\0'; - return buf; -} - -/* - * !doc - * - * .. c:function:: void pkgconf_pkg_dir_list_build(pkgconf_client_t *client) - * - * Bootstraps the package search paths. If the ``PKGCONF_PKG_PKGF_ENV_ONLY`` `flag` is set on the client, - * then only the ``PKG_CONFIG_PATH`` environment variable will be used, otherwise both the - * ``PKG_CONFIG_PATH`` and ``PKG_CONFIG_LIBDIR`` environment variables will be used. - * - * :param pkgconf_client_t* client: The pkgconf client object to bootstrap. - * :return: nothing - */ -void -pkgconf_pkg_dir_list_build(pkgconf_client_t *client) -{ - pkgconf_path_build_from_environ("PKG_CONFIG_PATH", NULL, &client->dir_list, true); - - if (!(client->flags & PKGCONF_PKG_PKGF_ENV_ONLY)) - { - char pathbuf[PKGCONF_BUFSIZE]; - - pkgconf_path_build_from_environ("PKG_CONFIG_LIBDIR", get_default_pkgconfig_path(pathbuf, sizeof pathbuf), &client->dir_list, true); - } + return strdup(buf); } typedef void (*pkgconf_pkg_parser_keyword_func_t)(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value); @@ -168,7 +107,18 @@ pkgconf_pkg_parser_dependency_func(const pkgconf_client_t *client, pkgconf_pkg_t (void) lineno; pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); - pkgconf_dependency_parse(client, pkg, dest, value); + pkgconf_dependency_parse(client, pkg, dest, value, 0); +} + +/* a variant of pkgconf_pkg_parser_dependency_func which colors the dependency node as an "internal" dependency. */ +static void +pkgconf_pkg_parser_internal_dependency_func(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value) +{ + (void) keyword; + (void) lineno; + + pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); + pkgconf_dependency_parse(client, pkg, dest, value, PKGCONF_PKG_DEPF_INTERNAL); } /* keep this in alphabetical order */ @@ -182,22 +132,25 @@ static const pkgconf_pkg_parser_keyword_pair_t pkgconf_pkg_parser_keyword_funcs[ {"Name", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, realname)}, {"Provides", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, provides)}, {"Requires", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, required)}, + {"Requires.internal", pkgconf_pkg_parser_internal_dependency_func, offsetof(pkgconf_pkg_t, requires_private)}, {"Requires.private", pkgconf_pkg_parser_dependency_func, offsetof(pkgconf_pkg_t, requires_private)}, {"Version", pkgconf_pkg_parser_tuple_func, offsetof(pkgconf_pkg_t, version)}, }; -static bool -pkgconf_pkg_parser_keyword_set(const pkgconf_client_t *client, pkgconf_pkg_t *pkg, const size_t lineno, const char *keyword, char *value) +/* + * Fix the return type (issue #13 is reported). + */ +static void +pkgconf_pkg_parser_keyword_set(pkgconf_pkg_t *pkg, const size_t lineno, const char *keyword, char *value) { const pkgconf_pkg_parser_keyword_pair_t *pair = bsearch(keyword, pkgconf_pkg_parser_keyword_funcs, PKGCONF_ARRAY_SIZE(pkgconf_pkg_parser_keyword_funcs), sizeof(pkgconf_pkg_parser_keyword_pair_t), pkgconf_pkg_parser_keyword_pair_cmp); if (pair == NULL || pair->func == NULL) - return false; + return; - pair->func(client, pkg, keyword, lineno, pair->offset, value); - return true; + pair->func(pkg->owner, pkg, keyword, lineno, pair->offset, value); } static const char * @@ -237,6 +190,96 @@ determine_prefix(const pkgconf_pkg_t *pkg, char *buf, size_t buflen) return buf; } +static void +remove_additional_separators(char *buf) +{ + char *p = buf; + + while (*p) { + if (*p == '/') { + char *q; + + q = ++p; + while (*q && *q == '/') + q++; + + if (p != q) + memmove (p, q, strlen (q) + 1); + } else { + p++; + } + } +} + +static void +canonicalize_path(char *buf) +{ +#ifdef _WIN32 + char *p = buf; + + while (*p) { + if (*p == '\\') + *p = '/'; + p++; + } +#endif + + remove_additional_separators(buf); +} + +static bool +is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len) +{ +#ifdef _WIN32 + return !_strnicmp(path1, path2, path2_len); +#else + return !strncmp(path1, path2, path2_len); +#endif +} + +/* + * Fix the return type (issue #13 is reported). + */ +static void +pkgconf_pkg_parser_value_set(pkgconf_pkg_t *pkg, const size_t lineno, const char *keyword, char *value) +{ + char canonicalized_value[PKGCONF_ITEM_SIZE]; + + (void) lineno; + + pkgconf_strlcpy(canonicalized_value, value, sizeof canonicalized_value); + canonicalize_path(canonicalized_value); + + /* Some pc files will use absolute paths for all of their directories + * which is broken when redefining the prefix. We try to outsmart the + * file and rewrite any directory that starts with the same prefix. + */ + if (pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX && pkg->orig_prefix + && is_path_prefix_equal(canonicalized_value, pkg->orig_prefix->value, strlen(pkg->orig_prefix->value))) + { + char newvalue[PKGCONF_ITEM_SIZE]; + + pkgconf_strlcpy(newvalue, pkg->prefix->value, sizeof newvalue); + pkgconf_strlcat(newvalue, canonicalized_value + strlen(pkg->orig_prefix->value), sizeof newvalue); + pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, newvalue, false); + } + else if (strcmp(keyword, pkg->owner->prefix_varname) || !(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX)) + pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true); + else + { + char pathbuf[PKGCONF_ITEM_SIZE]; + const char *relvalue = determine_prefix(pkg, pathbuf, sizeof pathbuf); + + if (relvalue != NULL) + { + pkg->orig_prefix = pkgconf_tuple_add(pkg->owner, &pkg->vars, "orig_prefix", canonicalized_value, true); + pkg->prefix = pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, relvalue, false); + } + else + pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true); + } +} + typedef struct { const char *field; const ptrdiff_t offset; @@ -248,6 +291,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[256] = { + [':'] = (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) { @@ -285,14 +348,13 @@ 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 pathbuf[PKGCONF_ITEM_SIZE]; char *idptr; - size_t lineno = 0; pkg = calloc(sizeof(pkgconf_pkg_t), 1); + pkg->owner = client; pkg->filename = strdup(filename); - pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pkg_get_parent_dir(pkg, pathbuf, sizeof pathbuf), true); + pkg->pc_filedir = pkg_get_parent_dir(pkg); + pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pkg->pc_filedir, true); /* make module id */ if ((idptr = strrchr(pkg->filename, PKG_DIR_SEP_S)) != NULL) @@ -309,85 +371,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(client, pkg, lineno, key, value); - break; - case '=': - if (strcmp(key, client->prefix_varname) || !(client->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX)) - pkgconf_tuple_add(client, &pkg->vars, key, value, true); - else - { - const char *relvalue = determine_prefix(pkg, pathbuf, sizeof pathbuf); - if (relvalue != NULL) - { - pkgconf_tuple_add(client, &pkg->vars, "orig_prefix", value, true); - pkgconf_tuple_add(client, &pkg->vars, key, relvalue, false); - } - else - pkgconf_tuple_add(client, &pkg->vars, key, value, true); - } - 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)) { @@ -396,7 +380,7 @@ pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE * return NULL; } - pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL); + pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0); return pkgconf_pkg_ref(client, pkg); } @@ -480,7 +464,6 @@ pkgconf_pkg_ref(pkgconf_client_t *client, pkgconf_pkg_t *pkg) if (pkg->owner != NULL && pkg->owner != client) PKGCONF_TRACE(client, "WTF: client %p refers to package %p owned by other client %p", client, pkg, pkg->owner); - pkg->owner = client; pkg->refcount++; PKGCONF_TRACE(client, "refcount@%p: %d", pkg, pkg->refcount); @@ -676,7 +659,6 @@ pkgconf_pkg_find_in_registry_key(pkgconf_client_t *client, HKEY hkey, const char pkgconf_pkg_t * pkgconf_pkg_find(pkgconf_client_t *client, const char *name) { - char pathbuf[PKGCONF_ITEM_SIZE]; pkgconf_pkg_t *pkg = NULL; pkgconf_node_t *n; FILE *f; @@ -695,7 +677,7 @@ pkgconf_pkg_find(pkgconf_client_t *client, const char *name) pkg = pkgconf_pkg_new_from_file(client, name, f); if (pkg != NULL) { - pkgconf_path_add(pkg_get_parent_dir(pkg, pathbuf, sizeof pathbuf), &client->dir_list, true); + pkgconf_path_add(pkg->pc_filedir, &client->dir_list, true); return pkg; } } @@ -1347,7 +1329,7 @@ pkgconf_pkg_verify_dependency(pkgconf_client_t *client, pkgconf_dependency_t *pk unsigned int pkgconf_pkg_verify_graph(pkgconf_client_t *client, pkgconf_pkg_t *root, int depth) { - return pkgconf_pkg_traverse(client, root, NULL, NULL, depth); + return pkgconf_pkg_traverse(client, root, NULL, NULL, depth, 0); } static unsigned int @@ -1388,7 +1370,8 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client, pkgconf_list_t *deplist, pkgconf_pkg_traverse_func_t func, void *data, - int depth) + int depth, + unsigned int skip_flags) { unsigned int eflags = PKGCONF_PKG_ERRF_OK; pkgconf_node_t *node; @@ -1419,10 +1402,16 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client, continue; } + if (skip_flags && (depnode->flags & skip_flags) == skip_flags) + { + pkgconf_pkg_unref(client, pkgdep); + continue; + } + pkgconf_audit_log_dependency(client, pkgdep, depnode); pkgdep->flags |= PKGCONF_PKG_PROPF_SEEN; - eflags |= pkgconf_pkg_traverse(client, pkgdep, func, data, depth - 1); + eflags |= pkgconf_pkg_traverse(client, pkgdep, func, data, depth - 1, skip_flags); pkgdep->flags &= ~PKGCONF_PKG_PROPF_SEEN; pkgconf_pkg_unref(client, pkgdep); } @@ -1480,7 +1469,7 @@ pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client, /* * !doc * - * .. c:function:: unsigned int pkgconf_pkg_traverse(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_pkg_traverse_func_t func, void *data, int maxdepth) + * .. c:function:: unsigned int pkgconf_pkg_traverse(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_pkg_traverse_func_t func, void *data, int maxdepth, unsigned int skip_flags) * * Walk and resolve the dependency graph up to `maxdepth` levels. * @@ -1489,6 +1478,7 @@ pkgconf_pkg_walk_conflicts_list(pkgconf_client_t *client, * :param pkgconf_pkg_traverse_func_t func: A traversal function to call for each resolved node in the dependency graph. * :param void* data: An opaque pointer to data to be passed to the traversal function. * :param int maxdepth: The maximum depth to walk the dependency graph for. -1 means infinite recursion. + * :param uint skip_flags: Skip over dependency nodes containing the specified flags. A setting of 0 skips no dependency nodes. * :return: ``PKGCONF_PKG_ERRF_OK`` on success, else an error code. * :rtype: unsigned int */ @@ -1497,7 +1487,8 @@ pkgconf_pkg_traverse(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_pkg_traverse_func_t func, void *data, - int maxdepth) + int maxdepth, + unsigned int skip_flags) { unsigned int eflags = PKGCONF_PKG_ERRF_OK; @@ -1520,7 +1511,7 @@ pkgconf_pkg_traverse(pkgconf_client_t *client, } PKGCONF_TRACE(client, "%s: walking requires list", root->id); - eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth); + eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth, skip_flags); if (eflags != PKGCONF_PKG_ERRF_OK) return eflags; @@ -1530,7 +1521,7 @@ pkgconf_pkg_traverse(pkgconf_client_t *client, /* XXX: ugly */ client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; - eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth); + eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth, skip_flags); client->flags &= ~PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; if (eflags != PKGCONF_PKG_ERRF_OK) @@ -1584,14 +1575,15 @@ unsigned int pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) { unsigned int eflag; + unsigned int skip_flags = (client->flags & PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS) == 0 ? PKGCONF_PKG_DEPF_INTERNAL : 0; - eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, list, maxdepth); + eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, list, maxdepth, skip_flags); if (eflag != PKGCONF_PKG_ERRF_OK) pkgconf_fragment_free(list); if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) { - eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, list, maxdepth); + eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, list, maxdepth, skip_flags); if (eflag != PKGCONF_PKG_ERRF_OK) pkgconf_fragment_free(list); } @@ -1640,7 +1632,7 @@ pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t * { unsigned int eflag; - eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, list, maxdepth); + eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, list, maxdepth, 0); if (eflag != PKGCONF_PKG_ERRF_OK) { -- cgit v1.1