aboutsummaryrefslogtreecommitdiff
path: root/libpkgconf/pkg.c
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-10-26 13:47:53 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-10-26 18:26:28 +0300
commit95fee14dfa5bd3896c510077af36ea371a9a2975 (patch)
treeb1a85ba6ab458731e3aeba30efc645c7b2a50225 /libpkgconf/pkg.c
parent9be7ac171fba73340e2974ff7ba55739a7ca81fb (diff)
Merge with 1.5.4 upstream package version
Diffstat (limited to 'libpkgconf/pkg.c')
-rw-r--r--libpkgconf/pkg.c330
1 files changed, 161 insertions, 169 deletions
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)
{