Vendor import of pkgconf 3.0.9

Obtained from https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-3.0.9.tar.gz

SHA1: a390f016a7a5ff419c9eef9e2b2c01fe86c11971  -
SHA256: 32310a33bb97425ebc0707cb5af59f9dc05d10282dcd4db628a45ed904993dc6  -
SHA512: 30776d31f860910286b96fbf60a19b5a6d1e73cb6a1077a019d763ae6e5ed1e8d81bc3649978c83f40e5e90ae779f7e530c513b700c8e73bb6399883dd6ef7ab  -

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Pierre Pronchery committed 2026-11-02 00:28:01 +01:00
1 parent 0cf7106da9
commit fe9da42ef1
190 files changed
+5965 -1375

No files matched your search

+84 -18
View File
@@ -1,27 +1,93 @@
# pkgconf Code of Conduct # pkgconf Code of Conduct
We invite and encourage everybody to express their opinions on relevant ## Human participants
topics. All participants should at all times feel at ease to do so without
fearing any form of attack, reprisal or harassment. We ask everybody to be
respectful and considerate towards each other, especially when attempting
to provide constructive criticism.
To foster tolerance, respect and hospitality in our community, we agree not Human participants in the pkgconf project are expected to follow the current
to engage in discriminatory, disparaging or offensive speech or actions, version of the [Contributor Covenant][covenant], as posted on
including as to (but not limited to) gender, sexuality, race, nationality, contributor-covenant.org. The version posted there at the time of an
religion or profession. We are a community of many different nationalities incident is the version that applies.
and backgrounds, and we cherish our strength in diversity.
[covenant]: https://www.contributor-covenant.org/
## Organizations and agents: respect for maintainer autonomy
Humans and agents acting on behalf of a corporate project must additionally
respect the autonomy of the pkgconf maintainers.
The pkgconf maintainers decide what is merged, what is released, what is
supported, what is disclosed, and on what schedule. These decisions are not
subject to the priorities, deadlines, embargoes, or escalation paths of any
outside organization, consortium, or foundation, regardless of who its
members are or how critical it believes pkgconf to be.
Conduct that disrespects this autonomy includes, but is not limited to:
* Asserting a disclosure deadline, embargo, or remediation timeline for
pkgconf that the maintainers did not agree to.
* Requiring the maintainers to accept confidentiality obligations as a
condition of receiving a vulnerability report. Reports are welcome on
the maintainers' terms; a report offered only under conditions the
maintainers have not accepted is not a contribution, it is leverage.
* Submitting machine-generated patches, reports, or issues at a volume or
cadence that transfers the cost of review onto the maintainers, or
continuing to do so after being asked to stop.
* Escalating a maintainer decision to the maintainers' employer, to a
downstream distributor, to a funder, or to the press in order to obtain
a different outcome.
* Characterizing pkgconf as unmaintained, abandoned, under-maintained, or
in need of external stewardship, other than by the maintainers
themselves.
Behavior that disrespects this autonomy will result in an organization-wide
ban: the organization the human or agent is acting on behalf of will be
banned from participation in its entirety, not merely the individual human
or agent involved. Where the actor is a consortium, alliance, or foundation
program, the ban extends to the program as a whole.
## "Maintainer of last resort"
pkgconf is actively maintained. Only the pkgconf maintainers are competent
to declare otherwise, and no such declaration has been made.
pkgconf is distributed under the ISC license, which permits anyone to copy,
modify, and redistribute the software, including as a fork. Nothing in this
document restricts that right, and forks made under a distinct name are a
legitimate exercise of it.
The license does not, however, convey the pkgconf name, nor the right to
speak for the pkgconf project or its authors. The following is unwelcome,
and carries the same consequence as any other failure to respect maintainer
autonomy:
* Representing any person or organization as the maintainer, steward, or
"maintainer of last resort" of pkgconf, whether generally or in response
to a ban under this document.
* Distributing a modified pkgconf under the pkgconf name, or under a name
likely to be mistaken for it, in a manner that presents it as the
upstream project.
* Representing patches, releases, or advisories as authored, reviewed,
endorsed, or sanctioned by the pkgconf project or its authors when they
were not.
If someone does these things anyway, we will say so plainly and publicly,
for as long as it takes to keep the record straight. Fork the code if you
find it necessary; give the fork your own name and speak for it in your own
voice.
## Reporting incidents ## Reporting incidents
Please report any incidents which may be perceived as violations to Report anything you believe violates this document to
`ariadne+conduct@dereferenced.org`. Incidents will be investigated and, `ariadne+conduct@ariadne.space`. Reports reach the maintainers directly.
if warranted, acted upon. We will look into what you tell us, and we will act on it where action is
warranted.
Reports about a human participant are handled under the Contributor
Covenant. Reports about an organization, or about an agent acting on its
behalf, are decided by the maintainers, and the consequence is the one
described above.
## Credits You do not need to be a contributor to report something, and you will not
be asked to justify why the conduct troubled you.
This CoC is derived from the [FSFE Code of Conduct][fsfe-coc].
[fsfe-coc]: https://fsfe.org/about/codeofconduct.en.html
+1 -1
View File
@@ -77,7 +77,7 @@ By submitting a patch, you affirm that:
* You can account for how the contribution was produced. * You can account for how the contribution was produced.
Submitting contributions that you do not understand, cannot explain Submitting contributions that you do not understand, cannot explain
or cannot clearly attribute may be treated as harrassment per the or cannot clearly attribute may be treated as harassment per the
pkgconf [Code of Conduct][coc]. pkgconf [Code of Conduct][coc].
Contributions produced primarily by autonomous or agentic systems Contributions produced primarily by autonomous or agentic systems
+131 -3
View File
@@ -12,17 +12,29 @@ nodist_pkgconfig_DATA = libpkgconf.pc
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -DPERSONALITY_PATH=\"$(personality_dir)\" -DPKG_DEFAULT_PATH=\"$(pkg_default_dir)\" -DSYSTEM_INCLUDEDIR=\"$(system_includedir)\" -DSYSTEM_LIBDIR=\"$(system_libdir)\" AM_CFLAGS = -DPERSONALITY_PATH=\"$(personality_dir)\" -DPKG_DEFAULT_PATH=\"$(pkg_default_dir)\" -DSYSTEM_INCLUDEDIR=\"$(system_includedir)\" -DSYSTEM_LIBDIR=\"$(system_libdir)\"
bin_PROGRAMS = pkgconf bomtool spdxtool bin_PROGRAMS = pkgconf bomtool spdxtool pccritic
lib_LTLIBRARIES = libpkgconf.la lib_LTLIBRARIES = libpkgconf.la
EXTRA_DIST = pkg.m4 \ EXTRA_DIST = pkg.m4 \
meson.build \ meson.build \
meson_options.txt \ meson_options.txt \
pkgconf.manifest.in \
pkgconf.rc.in \
pkgconf.wxs.in \ pkgconf.wxs.in \
txt2rtf.py \ txt2rtf.py \
libpkgconf/meson.build \ libpkgconf/meson.build \
libpkgconf/config.h.meson \ libpkgconf/config.h.meson \
libpkgconf/win-dirent.h \ libpkgconf/win-dirent.h \
fuzzer/meson.build \
fuzzer/alloc-inject.c \
fuzzer/alloc-inject.h \
fuzzer/parser-fuzzer.c \
fuzzer/replay.c \
fuzzer/solver-fuzzer.c \
fuzzer/spdxtool-fuzzer.c \
fuzzer/solver-corpus/chain \
fuzzer/solver-corpus/constraints \
fuzzer/solver-corpus/cycle \
t/cli/about.test \ t/cli/about.test \
t/cli/atleast-pkgconfig-version-fail.test \ t/cli/atleast-pkgconfig-version-fail.test \
t/cli/atleast-pkgconfig-version-pass.test \ t/cli/atleast-pkgconfig-version-pass.test \
@@ -32,6 +44,11 @@ EXTRA_DIST = pkg.m4 \
t/cli/atleast-version-pass.test \ t/cli/atleast-version-pass.test \
t/cli/cflags-libs.test \ t/cli/cflags-libs.test \
t/cli/debug.test \ t/cli/debug.test \
t/cli/define-prefix-boundary.test \
t/cli/define-prefix-boundary-sibling.test \
t/cli/define-prefix-plain.test \
t/cli/define-prefix-trailing-slash.test \
t/cli/define-prefix-trailing-slash-cflags.test \
t/cli/define-variable.test \ t/cli/define-variable.test \
t/cli/dont-define-prefix.test \ t/cli/dont-define-prefix.test \
t/cli/dump-personality-loaded.test \ t/cli/dump-personality-loaded.test \
@@ -65,6 +82,9 @@ EXTRA_DIST = pkg.m4 \
t/cli/max-version-inline-constraint.test \ t/cli/max-version-inline-constraint.test \
t/cli/max-version-inline-overrides.test \ t/cli/max-version-inline-overrides.test \
t/cli/max-version-pass.test \ t/cli/max-version-pass.test \
t/cli/maximum-traverse-depth-invalid-env.test \
t/cli/maximum-traverse-depth-invalid.test \
t/cli/maximum-traverse-depth-unlimited.test \
t/cli/maximum-traverse-depth.test \ t/cli/maximum-traverse-depth.test \
t/cli/missing-package.test \ t/cli/missing-package.test \
t/cli/missing-package-error.test \ t/cli/missing-package-error.test \
@@ -84,10 +104,13 @@ EXTRA_DIST = pkg.m4 \
t/cli/short-errors.test \ t/cli/short-errors.test \
t/cli/silence-errors.test \ t/cli/silence-errors.test \
t/cli/simulate.test \ t/cli/simulate.test \
t/cli/single-package-limit.out \
t/cli/single-package-limit.test \
t/cli/solution.test \ t/cli/solution.test \
t/cli/unknown-option.test \ t/cli/unknown-option.test \
t/cli/validate-warning.test \ t/cli/validate-warning.test \
t/cli/validate.test \ t/cli/validate.test \
t/cli/variable-multiple-packages.test \
t/cli/variable.test \ t/cli/variable.test \
t/cli/verbose.test \ t/cli/verbose.test \
t/cli/version.test \ t/cli/version.test \
@@ -145,6 +168,7 @@ EXTRA_DIST = pkg.m4 \
t/basic/uninstalled-not.test \ t/basic/uninstalled-not.test \
t/basic/uninstalled.test \ t/basic/uninstalled.test \
t/basic/variable-env.test \ t/basic/variable-env.test \
t/basic/variable-multiple-packages.test \
t/basic/variable-no-recursion.test \ t/basic/variable-no-recursion.test \
t/basic/variable.test \ t/basic/variable.test \
t/basic/version-atleast-1.test \ t/basic/version-atleast-1.test \
@@ -176,8 +200,13 @@ EXTRA_DIST = pkg.m4 \
t/parser/dollar-sign-escape.test \ t/parser/dollar-sign-escape.test \
t/parser/dollar-sign-escape-2.test \ t/parser/dollar-sign-escape-2.test \
t/parser/dos-lineendings.test \ t/parser/dos-lineendings.test \
t/parser/escape-layers-bare-var-libs.test \
t/parser/escape-layers-cflags.test \
t/parser/escape-layers-libs.test \
t/parser/escaped-backslashes-in-output.test \ t/parser/escaped-backslashes-in-output.test \
t/parser/fragment-comment.test \ t/parser/fragment-comment.test \
t/parser/fragment-escaped-space-var-cflags.test \
t/parser/fragment-escaped-space-var-libs.test \
t/parser/fragment-escaping-1.test \ t/parser/fragment-escaping-1.test \
t/parser/fragment-escaping-2.test \ t/parser/fragment-escaping-2.test \
t/parser/fragment-escaping-3.test \ t/parser/fragment-escaping-3.test \
@@ -200,7 +229,9 @@ EXTRA_DIST = pkg.m4 \
t/parser/multiline-folding-libs.test \ t/parser/multiline-folding-libs.test \
t/parser/no-trailing-newline.test \ t/parser/no-trailing-newline.test \
t/parser/paren-quoting.test \ t/parser/paren-quoting.test \
t/parser/self-referential-fragment.test \
t/parser/shell-quoted-output.test \ t/parser/shell-quoted-output.test \
t/parser/spaces-in-paths.test \
t/parser/tilde-quoting-1.test \ t/parser/tilde-quoting-1.test \
t/parser/tilde-quoting-2.test \ t/parser/tilde-quoting-2.test \
t/parser/truncated-files-should-fail-to-parse.test \ t/parser/truncated-files-should-fail-to-parse.test \
@@ -218,6 +249,10 @@ EXTRA_DIST = pkg.m4 \
t/solver/circular-reference-2.test \ t/solver/circular-reference-2.test \
t/solver/circular-reference-directpc.test \ t/solver/circular-reference-directpc.test \
t/solver/compound-foo-metapackage-3.test \ t/solver/compound-foo-metapackage-3.test \
t/solver/conflicts-license.test \
t/solver/conflicts-modversion.test \
t/solver/conflicts-print-provides.test \
t/solver/conflicts-print-requires.test \
t/solver/conflicts-solution-error.test \ t/solver/conflicts-solution-error.test \
t/solver/conflicts-solution-ignore.test \ t/solver/conflicts-solution-ignore.test \
t/solver/conflicts-solution-is-fine-standalone.test \ t/solver/conflicts-solution-is-fine-standalone.test \
@@ -321,6 +356,17 @@ EXTRA_DIST = pkg.m4 \
t/spdxtool/version.test \ t/spdxtool/version.test \
t/spdxtool/version-operator.test \ t/spdxtool/version-operator.test \
t/spdxtool/with-dependency.test \ t/spdxtool/with-dependency.test \
t/pccritic/about.test \
t/pccritic/help.test \
t/pccritic/min-score-invalid.test \
t/pccritic/min-score-out-of-range.test \
t/pccritic/min-score.test \
t/pccritic/missing-field.test \
t/pccritic/no-arguments.test \
t/pccritic/perfect.test \
t/pccritic/polluted.test \
t/pccritic/unknown-package.test \
t/pccritic/version.test \
t/sbom/license-file-bar.test \ t/sbom/license-file-bar.test \
t/sbom/license-file-foo.test \ t/sbom/license-file-foo.test \
t/sbom/license-isc.test \ t/sbom/license-isc.test \
@@ -354,7 +400,27 @@ EXTRA_DIST = pkg.m4 \
t/symlink/pcfiledir_symlink_relative_env12.test \ t/symlink/pcfiledir_symlink_relative_env12.test \
t/sysroot/cflags-rewriting.test \ t/sysroot/cflags-rewriting.test \
t/sysroot/explicit-sysroot.test \ t/sysroot/explicit-sysroot.test \
t/sysroot/fdo-sysroot-system-path-filtering.test \
t/sysroot/fdo-sysroot-variable-not-rewritten.test \
t/sysroot/idirafter-munge-sysroot.test \ t/sysroot/idirafter-munge-sysroot.test \
t/sysroot/inject-bare-sysrootdir.test \
t/sysroot/inject-common-prefix-derived.test \
t/sysroot/inject-common-prefix-hardcoded.test \
t/sysroot/inject-common-prefix-literal.test \
t/sysroot/inject-explicit-cflags.test \
t/sysroot/inject-explicit-libs.test \
t/sysroot/inject-hardcoded-cflags.test \
t/sysroot/inject-hardcoded-libs.test \
t/sysroot/inject-isystem-attached.test \
t/sysroot/inject-isystem-explicit.test \
t/sysroot/inject-isystem-literal.test \
t/sysroot/inject-isystem-separate.test \
t/sysroot/inject-literal-prefixed.test \
t/sysroot/inject-mixed-fragments.test \
t/sysroot/inject-multi-fragment-var.test \
t/sysroot/inject-prefix-derived.test \
t/sysroot/inject-root-sysroot-hardcoded.test \
t/sysroot/inject-root-sysroot-isystem.test \
t/sysroot/isystem-munge-sysroot.test \ t/sysroot/isystem-munge-sysroot.test \
t/sysroot/isystem-sysroot-prefixed.test \ t/sysroot/isystem-sysroot-prefixed.test \
t/sysroot/no-pc_sysrootdir-rewriting-2.test \ t/sysroot/no-pc_sysrootdir-rewriting-2.test \
@@ -373,6 +439,10 @@ EXTRA_DIST = pkg.m4 \
t/sysroot/uninstalled-rewriting.test \ t/sysroot/uninstalled-rewriting.test \
t/sysroot/variable-rewriting-1.test \ t/sysroot/variable-rewriting-1.test \
t/sysroot/variable-rewriting-2.test \ t/sysroot/variable-rewriting-2.test \
t/sysroot/windows-drive-path-no-inject.test \
t/sysroot/windows-sysroot-inject.test \
t/sysroot/windows-system-libdir-filter.test \
t/sysroot/windows-top-builddir.test \
t/tuple/billion-laughs.test \ t/tuple/billion-laughs.test \
t/tuple/case-sensitivity-1.test \ t/tuple/case-sensitivity-1.test \
t/tuple/case-sensitivity-2.test \ t/tuple/case-sensitivity-2.test \
@@ -380,6 +450,12 @@ EXTRA_DIST = pkg.m4 \
t/tuple/define-variable.test \ t/tuple/define-variable.test \
t/tuple/duplicate-upsert.test \ t/tuple/duplicate-upsert.test \
t/tuple/empty-tuple.test \ t/tuple/empty-tuple.test \
t/tuple/escaped-backslash-variable.test \
t/tuple/escaped-whitespace-variable-dquoted.test \
t/tuple/escaped-whitespace-variable-nested.test \
t/tuple/escaped-whitespace-variable-squoted.test \
t/tuple/escaped-whitespace-variable-unquoted.test \
t/tuple/escaped-whitespace-variable.test \
t/link-abi/default-c.test \ t/link-abi/default-c.test \
t/link-abi/cxx-leaf.test \ t/link-abi/cxx-leaf.test \
t/link-abi/cxx-leaf-static.test \ t/link-abi/cxx-leaf-static.test \
@@ -389,7 +465,15 @@ EXTRA_DIST = pkg.m4 \
t/link-abi/multi-dedup.test \ t/link-abi/multi-dedup.test \
tests/win-shim.h \ tests/win-shim.h \
tests/api/test-api.h \ tests/api/test-api.h \
tests/api/oom.h \
tests/api/test-oom-spdxtool.c \
tests/lib-relocatable/lib/pkgconfig/foo.pc \ tests/lib-relocatable/lib/pkgconfig/foo.pc \
tests/lib-relocatable/abs-boundary/lib/pkgconfig/boundary.pc \
tests/lib-relocatable/plain-prefix/lib/pkgconfig/plain.pc \
tests/lib-relocatable/trailing-prefix/lib/pkgconfig/trailing.pc \
tests/lib1/self-referential-fragment.pc \
tests/lib1/maxpkg-first.pc \
tests/lib1/maxpkg-second.pc \
tests/lib1/argv-parse-2.pc \ tests/lib1/argv-parse-2.pc \
tests/lib1/billion-laughs.pc \ tests/lib1/billion-laughs.pc \
tests/lib1/dollar-sign-escape.pc \ tests/lib1/dollar-sign-escape.pc \
@@ -511,6 +595,28 @@ EXTRA_DIST = pkg.m4 \
tests/lib1/duplicate-tuple.pc \ tests/lib1/duplicate-tuple.pc \
tests/lib1/flag-whitespace.pc \ tests/lib1/flag-whitespace.pc \
tests/lib1/flag-whitespace-2.pc \ tests/lib1/flag-whitespace-2.pc \
tests/lib1/fragment-escaped-space-var.pc \
tests/lib1/windows-sysroot-inject.pc \
tests/lib1/windows-sysroot-libdir.pc \
tests/lib1/windows-system-libdir.pc \
tests/lib1/windows-top-builddir.pc \
tests/lib1/spaces-in-paths.pc \
tests/lib1/sysroot-inject-bare.pc \
tests/lib1/sysroot-inject-explicit.pc \
tests/lib1/sysroot-inject-hardcoded.pc \
tests/lib1/sysroot-inject-isystem-explicit.pc \
tests/lib1/sysroot-inject-isystem-literal.pc \
tests/lib1/sysroot-inject-isystem-separate.pc \
tests/lib1/sysroot-inject-literal.pc \
tests/lib1/sysroot-inject-mixed.pc \
tests/lib1/sysroot-inject-multi-fragment.pc \
tests/lib1/sysroot-inject-prefix.pc \
tests/lib1/escape-layers-bare-var.pc \
tests/lib1/escape-layers.pc \
tests/lib1/sysroot-inject-isystem-attached.pc \
tests/lib-pccritic/perfect.pc \
tests/lib-pccritic/polluted.pc \
tests/lib-pccritic/nodesc.pc \
tests/lib-sbom/meta_package.pc \ tests/lib-sbom/meta_package.pc \
tests/lib-sbom/test1.pc \ tests/lib-sbom/test1.pc \
tests/lib-sbom/test2.pc \ tests/lib-sbom/test2.pc \
@@ -598,7 +704,8 @@ dist_man_MANS = \
man/pkg.m4.7 \ man/pkg.m4.7 \
man/pc.5 \ man/pc.5 \
man/pkgconf-personality.5 \ man/pkgconf-personality.5 \
man/spdxtool.1 man/spdxtool.1 \
man/pccritic.1
pkgconf_LDADD = libpkgconf.la pkgconf_LDADD = libpkgconf.la
pkgconf_SOURCES = \ pkgconf_SOURCES = \
@@ -617,7 +724,8 @@ noinst_HEADERS = \
cli/spdxtool/serialize.h \ cli/spdxtool/serialize.h \
cli/spdxtool/simplelicensing.h \ cli/spdxtool/simplelicensing.h \
cli/spdxtool/software.h \ cli/spdxtool/software.h \
cli/spdxtool/util.h cli/spdxtool/util.h \
cli/pccritic/critic.h
bomtool_LDADD = libpkgconf.la bomtool_LDADD = libpkgconf.la
bomtool_SOURCES = \ bomtool_SOURCES = \
@@ -637,6 +745,13 @@ spdxtool_SOURCES = \
cli/getopt_long.c cli/getopt_long.c
spdxtool_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/spdxtool spdxtool_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/spdxtool
pccritic_LDADD = libpkgconf.la
pccritic_SOURCES = \
cli/pccritic/main.c \
cli/pccritic/critic.c \
cli/getopt_long.c
pccritic_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/pccritic
API_TEST_PROGS = \ API_TEST_PROGS = \
test-api-audit \ test-api-audit \
test-api-buffer \ test-api-buffer \
@@ -651,6 +766,7 @@ API_TEST_PROGS = \
test-api-queue \ test-api-queue \
test-api-serialize \ test-api-serialize \
test-api-tuple \ test-api-tuple \
test-api-util \
test-api-variable \ test-api-variable \
test-api-version test-api-version
@@ -725,6 +841,16 @@ test_api_tuple_LDADD = $(api_test_ldadd)
test_api_tuple_SOURCES = tests/api/test-tuple.c test_api_tuple_SOURCES = tests/api/test-tuple.c
test_api_tuple_CPPFLAGS = $(api_test_cppflags) test_api_tuple_CPPFLAGS = $(api_test_cppflags)
test_api_util_LDADD = $(api_test_ldadd)
test_api_util_SOURCES = \
tests/api/test-util.c \
cli/spdxtool/core.c \
cli/spdxtool/software.c \
cli/spdxtool/serialize.c \
cli/spdxtool/simplelicensing.c \
cli/spdxtool/util.c
test_api_util_CPPFLAGS = $(api_test_cppflags) -I$(top_srcdir)/cli/spdxtool
test_api_variable_LDADD = $(api_test_ldadd) test_api_variable_LDADD = $(api_test_ldadd)
test_api_variable_SOURCES = tests/api/test-variable.c test_api_variable_SOURCES = tests/api/test-variable.c
test_api_variable_CPPFLAGS = $(api_test_cppflags) test_api_variable_CPPFLAGS = $(api_test_cppflags)
@@ -754,6 +880,7 @@ check: pkgconf test-runner $(API_TEST_PROGS)
$(builddir)/test-api-queue$(EXEEXT) $(builddir)/test-api-queue$(EXEEXT)
$(builddir)/test-api-serialize$(EXEEXT) $(builddir)/test-api-serialize$(EXEEXT)
$(builddir)/test-api-tuple$(EXEEXT) $(builddir)/test-api-tuple$(EXEEXT)
$(builddir)/test-api-util$(EXEEXT)
$(builddir)/test-api-variable$(EXEEXT) $(builddir)/test-api-variable$(EXEEXT)
$(builddir)/test-api-version$(EXEEXT) $(builddir)/test-api-version$(EXEEXT)
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/basic $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/basic
@@ -766,6 +893,7 @@ check: pkgconf test-runner $(API_TEST_PROGS)
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sbom $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sbom
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/bomtool $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/bomtool
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/spdxtool $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/spdxtool
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/pccritic
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/symlink $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/symlink
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sysroot $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sysroot
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/tuple $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/tuple
+1 -1
View File
@@ -60,7 +60,7 @@ all: pkgconf-lite
libpkgconf/config.h: libpkgconf/config.h:
@echo '#define PACKAGE_NAME "pkgconf-lite"' >> $@ @echo '#define PACKAGE_NAME "pkgconf-lite"' >> $@
@echo '#define PACKAGE_BUGREPORT "https://git.dereferenced.org/pkgconf/pkgconf/issues"' >> $@ @echo '#define PACKAGE_BUGREPORT "https://git.dereferenced.org/pkgconf/pkgconf/issues"' >> $@
@echo '#define PACKAGE_VERSION "2.9.93"' >> $@ @echo '#define PACKAGE_VERSION "3.0.9"' >> $@
@echo '#define PACKAGE PACKAGE_NAME " " PACKAGE_VERSION' >> $@ @echo '#define PACKAGE PACKAGE_NAME " " PACKAGE_VERSION' >> $@
pkgconf-lite: preflight libpkgconf/config.h ${PKGCONF_OBJS} pkgconf-lite: preflight libpkgconf/config.h ${PKGCONF_OBJS}
+222 -6
View File
@@ -1,6 +1,186 @@
Changes from previous version of pkgconf Changes from previous version of pkgconf
======================================== ========================================
Changes from 3.0.8 to 3.0.9:
----------------------------
* Build fixes:
- The Autotools build now includes and runs the spdxtool utility API tests,
ensuring that they are included in release tarballs.
Patch by commitmaniac.
Changes from 3.0.7 to 3.0.8:
----------------------------
* Correctness and portability fixes:
- spdxtool now percent-encodes problematic ASCII characters in generated
SPDX URLs and URNs. Patch by Tuukka Pasanen, sponsored by The FreeBSD
Foundation.
- The built-in pc_path, pc_system_libdirs and pc_system_includedirs variables
now use the platform path separator, fixing their output for multiple paths
on Windows. Patch by Christoph Reiter.
* Documentation and build fixes:
- Correct the pkgconf(1) description of --variable to document that it prints
values for every module specified on the command line. Patch by Christoph
Reiter.
- Update the bug-report URL embedded by Meson builds to point to the pkgconf
issue tracker on GitHub.
Changes from 3.0.6 to 3.0.7:
----------------------------
* Correctness fixes:
- spdxtool now serializes the SPDX 3.0 suppliedBy property as a single Agent
reference instead of a one-element array, as required by the official JSON
schema.
- bomtool no longer emits PackageDownloadLocation twice for each package.
These fixes were contributed by R. Christian McDonald.
* Build, packaging and portability fixes:
- The Windows installer uses a default installation directory without a
space in its name. Patch by Kai Pastor.
- Skip the spdxtool allocation-failure test for static builds, where linker
wrapping also intercepts libpkgconf allocations and invalidates the test.
See https://github.com/pkgconf/pkgconf/issues/593.
- Use PKGCONF_ITEM_SIZE instead of PATH_MAX in the test runner, allowing it
to build on systems where PATH_MAX is not declared, such as GNU Hurd.
See https://github.com/pkgconf/pkgconf/issues/600.
Changes from 3.0.5 to 3.0.6:
----------------------------
* Command-line behavior:
- --variable accepts multiple modules and prints the requested
variable's value for each module, in argument order. --path and
--print-variables remain limited to a single module.
- pccritic no longer reports the PC061 style finding for CRLF line endings,
avoiding a noisy warning for normal Windows files.
See https://github.com/pkgconf/pkgconf/issues/587.
* Build and portability fixes:
- Improve OS/2 support by exporting libpkgconf APIs from DLL builds,
recognizing OS/2 drive letters and path separators, comparing paths without
case sensitivity, and using binary mode for redirected standard output and
error. Patches by KO Myung-Hun.
- Declare pkgconf long-path-aware in its Windows application manifest,
allowing paths beyond the traditional MAX_PATH limit when long paths are
enabled by the operating system. Patch by moi15moi.
Changes from 3.0.4 to 3.0.5:
----------------------------
* Correctness fixes:
- Shell quoting and backslash escapes in pc(5) properties are now consumed
once, after variable substitution, instead of while splitting the property
beforehand. Quoting arriving from a variable is therefore treated like
quoting written inline, --variable reports a value as the .pc file spells
it, and fragments are escaped exactly once when rendered. This supersedes
the 3.0.4 fix, which unescaped whitespace at parse time and so hid the
escaping from consumers such as cmake's FindPkgConfig.
See https://github.com/pkgconf/pkgconf/issues/575 and
https://github.com/pkgconf/pkgconf/issues/579.
- Metadata queries no longer consult Conflicts rules between the modules named
on the command line, as reporting metadata does not combine them into a
build. This covers --license, --license-file, --modversion, --path,
--print-provides, --print-requires, --print-requires-private,
--print-variables, --source and --variable. --cflags, --libs and --exists
are unaffected.
See https://github.com/pkgconf/pkgconf/issues/580.
- ${pc_sysrootdir} is now injected into the path taken by every -isystem and
-idirafter flag in a fragment list, rather than only the first.
- -isystem and -idirafter written joined to their path, as in `-isystem/opt`,
are split into the flag and the path it takes, so that the path is subject
to the same sysroot injection and deduplication as the separated spelling.
- Sysroot injection is decided by reading the fragment's path instead of
remembering whether ${pc_sysrootdir} was expanded, so a path which already
lies under the sysroot never acquires a doubled prefix.
* Performance:
- The package cache and the fragment deduplication index are kept sorted and
searched with bsearch() rather than re-sorted or scanned linearly.
- Variable keys and fragment text are stored with the structures they belong
to, and buffers are rewound and reused rather than reallocated.
- Escaping, fragment rendering and path relocation write into their
destination buffer directly.
Resolving a graph of roughly forty modules is about six times faster than
3.0.4, and a small graph such as gio-2.0 about twice as fast.
* Build and portability fixes:
- Fix the pkgconf-lite build, which failed to link because the dependency list
renderer had come to depend on tracing machinery that pkgconf-lite omits.
- Fix the test runner failing to build on MinGW, where the mkdtemp(3) fallback
was compiled only for MSVC builds.
See https://github.com/pkgconf/pkgconf/issues/582.
- The meson build now defines HAVE_DECL_READLINKAT, so readlinkat(2) is used
where it is available instead of always falling back to readlink(2).
The MinGW and readlinkat fixes are by moi15moi.
* New libpkgconf API additions:
- pkgconf_argv_split_raw: splits a string into an argument vector like
pkgconf_argv_split, but leaves the quoting it reads in place.
- pkgconf_fragment_filter_splice: like pkgconf_fragment_filter, but moves the
matching fragments to the destination list instead of copying them.
- pkgconf_charset_from_spans: compiles a span list into a byte set.
- pkgconf_buffer_escape_charset: escapes a buffer against such a byte set.
- pkgconf_buffer_rewind: empties a buffer while keeping its allocation.
- pkgconf_list_splice: moves the contents of one list onto the end of another.
Changes from 3.0.3 to 3.0.4:
----------------------------
* Fix a crash (stack overflow) triggered by a crafted .pc file containing a
self-referential fragment variable, such as `x=$${x}` referenced from Cflags.
Fragment variables are now evaluated only once while re-splitting. Found
through fuzzing.
* Fix over-escaping of variable values containing backslash-escaped whitespace,
such as paths quoted with `printf %q`. Such a value was stored with its
escapes intact and then escaped a second time when rendered into a fragment,
producing output like `-L/a\\\ dir`. This broke meson's test suite, which
uses paths with spaces to stay Windows-safe.
* Fix mangled and duplicated -L/-I paths on Windows when PKG_CONFIG_SYSROOT_DIR
and PKG_CONFIG_LIBDIR are set. Path separators are now normalized to forward
slashes for all runtime-injected paths (sysroot, build root, search paths and
pcfiledir), so that sysroot matching and injection operate on a consistent
basis.
* Fix `--define-prefix` dropping a path separator when the redefined prefix ends
with a trailing slash, and only rewrite a package's directories when they match
the original prefix on a path component boundary.
* Fix single-package queries returning results drawn from more than the requested
module, by restoring the package limit that was lost during a refactor of the
query builder.
Changes from 3.0.2 to 3.0.3:
----------------------------
* Restore correct handling of sysroots when emulating legacy pkg-config, and
add explicit regression tests for this case.
* Fix references to bomtool in spdxtool --help.
Patch by Pierre Pronchery.
* Fix various typos in the source code.
Patch by Christian Clauss.
Changes from 3.0.1 to 3.0.2:
----------------------------
* Fix build on systems where readlinkat(2) is missing, such as Illumos when
built without appropriate CFLAGS.
* Fix detection of readlinkat(2) on systems where it is gated behind
_ATFILE_SOURCE, such as on certain builds of Illumos.
Changes from 3.0.0 to 3.0.1:
----------------------------
* Various Meson-related fixes and improvements.
Patches by Benjamin Gilbert.
Changes from 2.5.1 to 3.0.0: Changes from 2.5.1 to 3.0.0:
---------------------------- ----------------------------
@@ -38,13 +218,21 @@ Changes from 2.5.1 to 3.0.0:
PackageDownloadLocation is derived from the Source tag, and SPDX 2.3 package PackageDownloadLocation is derived from the Source tag, and SPDX 2.3 package
names are used. Patches by Stéphane Rochoy and Tuukka Pasanen. names are used. Patches by Stéphane Rochoy and Tuukka Pasanen.
* New pccritic(1) utility which scores the quality of pc(5) files. Each module
or .pc file is graded from A to F based on findings across several categories:
required and recommended metadata, version sanity, relocatability of libdir
and includedir, Cflags and Libs hygiene, the Requires relationship, the NTIA
SBOM minimum elements, and file-formatting style. Supports --quiet for a
one-line score per target, --min-score for use as a CI gate, and colorized
output.
* New test and I/O framework. * New test and I/O framework.
- kyua is no longer required to run tests. - kyua is no longer required to run tests.
- Declarative configuration for integration tests, C unit tests for functional tests. - Declarative configuration for integration tests, C unit tests for functional tests.
- Tests now run on Windows. - Tests now run on Windows.
- .pc and personality files are now opened in binary mode, and the line reader - .pc and personality files are now opened in binary mode, and the line reader
was reworked to correctly handle CRLF line endings and to avoid getc/ungetc was reworked to correctly handle LF, CRLF and lone-CR line endings, including
for better performance. Binary-mode handling by moi15moi. on non-seekable streams. Binary-mode handling by moi15moi.
Major contributions by Elizabeth Ashford. Major contributions by Elizabeth Ashford.
* New pc(5) features: * New pc(5) features:
@@ -89,8 +277,17 @@ Changes from 2.5.1 to 3.0.0:
- Variable substitution is now guarded against denial-of-service inputs, - Variable substitution is now guarded against denial-of-service inputs,
including billion-laughs style expansion and excessively complex bytecode including billion-laughs style expansion and excessively complex bytecode
programs. programs.
- Dependency traversal is now limited to 256 levels by default to prevent
stack exhaustion from excessively deep graphs. A depth of -1 explicitly
enables unlimited traversal.
- Bytecode validation now uses overflow-safe bounds checks and rejects
truncated, oversized and otherwise malformed programs.
- Dynamic buffers now reject overlapping source and destination storage and
guard allocation-size arithmetic against overflow.
- LLVM libFuzzer targets were added for the pc(5) parser and the solver, and - LLVM libFuzzer targets were added for the pc(5) parser and the solver, and
the numerous out-of-memory and crash paths they surfaced were hardened. the numerous out-of-memory and crash paths they surfaced were hardened.
- Allocation failures are now propagated through parsing, rendering, output
and SBOM generation instead of silently producing partial results.
- Dropped use of strlcpy, strlcat and other silently truncating string - Dropped use of strlcpy, strlcat and other silently truncating string
functions. functions.
@@ -110,6 +307,11 @@ Changes from 2.5.1 to 3.0.0:
WantDefaultStatic. WantDefaultStatic.
- The vestigial --relocate=path option, which existed only for the old test - The vestigial --relocate=path option, which existed only for the old test
suite, has been removed. suite, has been removed.
- pccritic --min-score now strictly accepts integer values from 0 through 100.
* Build system changes:
- The meson build gained a with-pkg-config-dir option to override the default
package search path, matching the autotools --with-pkg-config-dir option.
* pkg.m4 changes: * pkg.m4 changes:
- PKG_WITH_MODULES now properly quotes its action arguments (serial 16). - PKG_WITH_MODULES now properly quotes its action arguments (serial 16).
@@ -145,8 +347,9 @@ Changes from 2.5.1 to 3.0.0:
- SPDX license expressions in the License field are now properly parsed and - SPDX license expressions in the License field are now properly parsed and
validated. Patches by Tuukka Pasanen. validated. Patches by Tuukka Pasanen.
* The libpkgconf API and ABI were substantially reworked, breaking ABI * The libpkgconf API and ABI were substantially reworked, breaking both API and
compatibility. The libpkgconf soversion is now 8. ABI compatibility. Consumers will need source changes as well as a rebuild.
The libpkgconf soversion is now 8.
- An abstract pkgconf_buffer_t type is now used throughout libpkgconf in place - An abstract pkgconf_buffer_t type is now used throughout libpkgconf in place
of fixed-size stack buffers, removing a class of truncation bugs. of fixed-size stack buffers, removing a class of truncation bugs.
- A new pkgconf_output API abstracts all output, allowing the output stream to - A new pkgconf_output API abstracts all output, allowing the output stream to
@@ -155,9 +358,22 @@ Changes from 2.5.1 to 3.0.0:
- The pkgconf_tuple_parse API has been removed; variables are now evaluated - The pkgconf_tuple_parse API has been removed; variables are now evaluated
via pkgconf_variable_eval (backed by the new bytecode engine). via pkgconf_variable_eval (backed by the new bytecode engine).
- The fragment rendering API was reworked around pkgconf_buffer_t, and the old - The fragment rendering API was reworked around pkgconf_buffer_t, and the old
pkgconf_fragment_render API has been removed. pkgconf_fragment_render API has been removed. Fragment renderer callbacks
and pkgconf_fragment_render_buf now return bool so allocation and rendering
failures can be reported.
- pkgconf_license_render now returns bool so allocation failures can be
reported.
- The package copyright field was migrated to a bufferset. - The package copyright field was migrated to a bufferset.
- Environment variable lookups can now be mocked via pkgconf_client_getenv. - Environment variable lookups can now be mocked via pkgconf_client_getenv.
- Client construction gained an options-based API: pkgconf_client_init_with_options
and pkgconf_client_new_with_options accept a pkgconf_client_options_t struct, with
the original pkgconf_client_init and pkgconf_client_new retained as wrappers. The
unveil handler may now be supplied directly as a client option.
- New pkgconf_variable_eval_name API, which evaluates a named variable and
applies sysroot fixups to the result.
- The pkgconf_pkg_traverse_func_t callback gained a trailing iter_flags
argument carrying per-traversal state (PKGCONF_PKG_ITERF_*), replacing the
removed PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE client flag.
Changes from 2.5.0 to 2.5.1: Changes from 2.5.0 to 2.5.1:
---------------------------- ----------------------------
@@ -374,7 +590,7 @@ Changes from 2.0.0 to 2.0.1:
The order of --modversion output is based on the dependency resolution The order of --modversion output is based on the dependency resolution
queue which is passed to the solver, which itself generally maps to the queue which is passed to the solver, which itself generally maps to the
order of the constrants provided on the command line. order of the constraints provided on the command line.
* A new flag, --verbose, has been added. When used with `--modversion`, it * A new flag, --verbose, has been added. When used with `--modversion`, it
is possible to disambiguate which version belongs to which module: is possible to disambiguate which version belongs to which module:
+28 -9
View File
@@ -209,8 +209,10 @@ write_copyright_lines(pkgconf_client_t *client, const pkgconf_list_t *copyright_
} }
static void static void
write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused, unsigned int iter_flags)
{ {
(void) iter_flags;
pkgconf_buffer_t license_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t license_buf = PKGCONF_BUFFER_INITIALIZER;
(void) client; (void) client;
(void) unused; (void) unused;
@@ -222,9 +224,8 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
OUTPUT_OR_RET(client, sbom_out, "PackageName: %s\n", sbom_identity(pkg)); OUTPUT_OR_RET(client, sbom_out, "PackageName: %s\n", sbom_identity(pkg));
OUTPUT_OR_RET(client, sbom_out, "SPDXID: SPDXRef-Package-%s\n", sbom_spdx_identity(pkg)); OUTPUT_OR_RET(client, sbom_out, "SPDXID: SPDXRef-Package-%s\n", sbom_spdx_identity(pkg));
OUTPUT_OR_RET(client, sbom_out, "PackageVersion: %s\n", pkg->version); OUTPUT_OR_RET(client, sbom_out, "PackageVersion: %s\n", pkg->version);
OUTPUT_OR_RET(client, sbom_out, "PackageDownloadLocation: NOASSERTION\n");
/* NOASSERTION is not a valide value for PackageVerificationCode. It /* NOASSERTION is not a valid value for PackageVerificationCode. It
* expect 40 lowercase hexadecimal digits. * expect 40 lowercase hexadecimal digits.
*/ */
#if 0 #if 0
@@ -240,7 +241,13 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
if (pkg->license.head != NULL) if (pkg->license.head != NULL)
{ {
pkgconf_license_render(client, &pkg->license, &license_buf); if (!pkgconf_license_render(client, &pkg->license, &license_buf))
{
pkgconf_buffer_finalize(&license_buf);
pkgconf_error(client, "bomtool: could not render package license");
return;
}
bool ret = pkgconf_output_file_fmt(sbom_out, "PackageLicenseDeclared: %s\n", pkgconf_buffer_str_or_empty(&license_buf)); bool ret = pkgconf_output_file_fmt(sbom_out, "PackageLicenseDeclared: %s\n", pkgconf_buffer_str_or_empty(&license_buf));
int errno_save = errno; int errno_save = errno;
pkgconf_buffer_finalize(&license_buf); pkgconf_buffer_finalize(&license_buf);
@@ -269,8 +276,10 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
} }
static void static void
write_sbom_relationships(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) write_sbom_relationships(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused, unsigned int iter_flags)
{ {
(void) iter_flags;
(void) client; (void) client;
(void) unused; (void) unused;
@@ -433,7 +442,12 @@ main(int argc, char *argv[])
} }
} }
pkgconf_client_init(&pkg_client, error_handler, NULL, personality, NULL, environ_lookup_handler); pkgconf_client_options_t client_options = {
.error_handler = error_handler,
.personality = personality,
.environ_lookup_handler = environ_lookup_handler,
};
pkgconf_client_init_with_options(&pkg_client, &client_options);
/* we have determined what features we want most likely. in some cases, we override later. */ /* we have determined what features we want most likely. in some cases, we override later. */
pkgconf_client_set_flags(&pkg_client, want_client_flags); pkgconf_client_set_flags(&pkg_client, want_client_flags);
@@ -458,10 +472,15 @@ main(int argc, char *argv[])
while (pkg_optind < argc && argv[pkg_optind] != NULL) while (pkg_optind < argc && argv[pkg_optind] != NULL)
{ {
if (pkgconf_buffer_len(&queryparams) > 0) if ((pkgconf_buffer_len(&queryparams) > 0 &&
pkgconf_buffer_push_byte(&queryparams, ' '); !pkgconf_buffer_push_byte(&queryparams, ' ')) ||
!pkgconf_buffer_append(&queryparams, argv[pkg_optind]))
{
pkgconf_buffer_finalize(&queryparams);
ret = EXIT_FAILURE;
goto out;
}
pkgconf_buffer_append(&queryparams, argv[pkg_optind]);
pkg_optind++; pkg_optind++;
} }
+152 -119
View File
@@ -170,8 +170,10 @@ apply_provides(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
static void static void
print_digraph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) print_digraph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
(void) iter_flags;
pkgconf_node_t *node; pkgconf_node_t *node;
pkgconf_pkg_t **last_seen = data; pkgconf_pkg_t **last_seen = data;
@@ -272,8 +274,10 @@ apply_digraph(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int ma
} }
static void static void
print_solution_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) print_solution_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused, unsigned int iter_flags)
{ {
(void) iter_flags;
(void) unused; (void) unused;
pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s (%llu)%s\n", pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s (%llu)%s\n",
@@ -372,32 +376,6 @@ apply_path(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int max
return true; return true;
} }
static char *
variable_eval(pkgconf_client_t *client, const pkgconf_list_t *vars, const char *varname)
{
pkgconf_buffer_t varbuf = PKGCONF_BUFFER_INITIALIZER;
const pkgconf_buffer_t *sysroot_dir = PKGCONF_BUFFER_FROM_STR(client->sysroot_dir);
bool saw_sysroot = false;
pkgconf_variable_t *v;
pkgconf_bytecode_eval_ctx_t ctx = {
.client = client,
.vars = vars,
};
v = pkgconf_bytecode_eval_lookup_var(&ctx, varname, strlen(varname));
(void) pkgconf_variable_eval(client, vars, v, &varbuf, &saw_sysroot);
if (!saw_sysroot && pkgconf_path_is_plausible(&varbuf))
{
/* if sysroot is set, and value does not already begin with sysroot */
if (!pkgconf_buffer_has_prefix(&varbuf, sysroot_dir))
pkgconf_buffer_prepend(&varbuf, pkgconf_buffer_str_or_empty(sysroot_dir));
}
return pkgconf_buffer_freeze(&varbuf);
}
static bool static bool
apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *variable, int maxdepth) apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *variable, int maxdepth)
{ {
@@ -413,7 +391,7 @@ apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *varia
if (pkg == NULL) if (pkg == NULL)
continue; continue;
result = variable_eval(client, &pkg->vars, variable); result = pkgconf_variable_eval_name(client, &pkg->vars, variable);
if (result != NULL) if (result != NULL)
{ {
@@ -439,12 +417,13 @@ apply_env_var(const char *prefix, pkgconf_client_t *client, pkgconf_pkg_t *world
pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER; pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER;
pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER;
unsigned int eflag; unsigned int eflag;
bool ret = true;
eflag = collect_fn(client, world, &unfiltered_list, maxdepth); eflag = collect_fn(client, world, &unfiltered_list, maxdepth);
if (eflag != PKGCONF_PKG_ERRF_OK) if (eflag != PKGCONF_PKG_ERRF_OK)
return false; return false;
pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_fn, NULL); pkgconf_fragment_filter_splice(client, &filtered_list, &unfiltered_list, filter_fn, NULL);
if (postprocess_fn != NULL) if (postprocess_fn != NULL)
postprocess_fn(client, world, &filtered_list); postprocess_fn(client, world, &filtered_list);
@@ -452,16 +431,22 @@ apply_env_var(const char *prefix, pkgconf_client_t *client, pkgconf_pkg_t *world
if (filtered_list.head == NULL) if (filtered_list.head == NULL)
goto out; goto out;
pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' '); if (!pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops,
pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s='%s'\n", (state->want_flags & PKG_NEWLINES) ? '\n' : ' '))
{
ret = false;
goto out;
}
ret = pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s='%s'\n",
prefix, pkgconf_buffer_str_or_empty(&render_buf)); prefix, pkgconf_buffer_str_or_empty(&render_buf));
pkgconf_buffer_finalize(&render_buf);
out: out:
pkgconf_buffer_finalize(&render_buf);
pkgconf_fragment_free(&unfiltered_list); pkgconf_fragment_free(&unfiltered_list);
pkgconf_fragment_free(&filtered_list); pkgconf_fragment_free(&filtered_list);
return true; return ret;
} }
static void static void
@@ -595,13 +580,13 @@ apply_cflags(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *tar
if (eflag != PKGCONF_PKG_ERRF_OK) if (eflag != PKGCONF_PKG_ERRF_OK)
return false; return false;
pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_cflags, NULL); pkgconf_fragment_filter_splice(client, &filtered_list, &unfiltered_list, filter_cflags, NULL);
maybe_add_module_definitions(client, world, &filtered_list); maybe_add_module_definitions(client, world, &filtered_list);
if (filtered_list.head == NULL) if (filtered_list.head == NULL)
goto out; goto out;
pkgconf_fragment_copy_list(client, target_list, &filtered_list); pkgconf_list_splice(target_list, &filtered_list);
out: out:
pkgconf_fragment_free(&unfiltered_list); pkgconf_fragment_free(&unfiltered_list);
@@ -621,12 +606,12 @@ apply_libs(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *targe
if (eflag != PKGCONF_PKG_ERRF_OK) if (eflag != PKGCONF_PKG_ERRF_OK)
return false; return false;
pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_libs, NULL); pkgconf_fragment_filter_splice(client, &filtered_list, &unfiltered_list, filter_libs, NULL);
if (filtered_list.head == NULL) if (filtered_list.head == NULL)
goto out; goto out;
pkgconf_fragment_copy_list(client, target_list, &filtered_list); pkgconf_list_splice(target_list, &filtered_list);
out: out:
pkgconf_fragment_free(&unfiltered_list); pkgconf_fragment_free(&unfiltered_list);
@@ -671,8 +656,10 @@ apply_requires_private(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unu
} }
static void static void
check_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) check_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
(void) iter_flags;
int *retval = data; int *retval = data;
(void) client; (void) client;
@@ -695,8 +682,10 @@ apply_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, in
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
static void static void
print_graph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) print_graph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
(void) iter_flags;
pkgconf_node_t *n; pkgconf_node_t *n;
(void) data; (void) data;
@@ -788,10 +777,12 @@ apply_fragment_tree(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data,
} }
static void static void
print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
(void) iter_flags;
pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER;
(void) data; int *retval = data;
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
return; return;
@@ -804,9 +795,11 @@ print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
else else
{ {
/* NOASSERTION is the default when the license is unknown, per SPDX spec § 3.15 */ /* NOASSERTION is the default when the license is unknown, per SPDX spec § 3.15 */
pkgconf_license_render(client, &pkg->license, &render_buf); if (!pkgconf_license_render(client, &pkg->license, &render_buf) ||
pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id); !pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id) ||
pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); !pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true))
*retval = EXIT_FAILURE;
pkgconf_buffer_finalize(&render_buf); pkgconf_buffer_finalize(&render_buf);
} }
} }
@@ -843,10 +836,15 @@ apply_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int m
{ {
pkgconf_bufferset_t *tag = node->data; pkgconf_bufferset_t *tag = node->data;
if (pkgconf_buffer_len(&render_buf)) if ((pkgconf_buffer_len(&render_buf) &&
pkgconf_buffer_push_byte(&render_buf, ' '); !pkgconf_buffer_push_byte(&render_buf, ' ')) ||
!pkgconf_buffer_append(&render_buf, pkgconf_buffer_str(&tag->buffer)))
pkgconf_buffer_append(&render_buf, pkgconf_buffer_str(&tag->buffer)); {
pkgconf_buffer_finalize(&render_buf);
pkgconf_bufferset_free(&abis);
*retval = EXIT_FAILURE;
return false;
}
} }
pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true);
@@ -858,8 +856,10 @@ apply_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int m
} }
static void static void
print_license_file(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) print_license_file(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
(void) iter_flags;
(void) data; (void) data;
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
@@ -884,8 +884,10 @@ apply_license_file(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, i
} }
static void static void
print_source(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) print_source(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
(void) iter_flags;
(void) data; (void) data;
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
@@ -909,7 +911,7 @@ apply_source(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int max
return true; return true;
} }
void bool
path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim) path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim)
{ {
pkgconf_node_t *n; pkgconf_node_t *n;
@@ -919,10 +921,16 @@ path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char d
pkgconf_path_t *pn = n->data; pkgconf_path_t *pn = n->data;
if (n != list->head) if (n != list->head)
pkgconf_buffer_push_byte(buffer, delim); {
if (!pkgconf_buffer_push_byte(buffer, delim))
return false;
}
pkgconf_buffer_append(buffer, pn->path); if (!pkgconf_buffer_append(buffer, pn->path))
return false;
} }
return true;
} }
static void static void
@@ -947,62 +955,56 @@ unveil_search_paths(pkgconf_client_t *client, const pkgconf_cross_personality_t
} }
} }
/* SAFETY: pkgconf_client_t takes ownership of these package objects */ static bool
register_builtin(pkgconf_client_t *client, const char *id,
const pkgconf_buffer_t *pc_path_buf,
const pkgconf_buffer_t *pc_system_libdirs_buf,
const pkgconf_buffer_t *pc_system_includedirs_buf)
{
pkgconf_pkg_t *pkg = calloc(1, sizeof(pkgconf_pkg_t));
if (pkg == NULL)
return false;
pkg->owner = client;
pkg->id = strdup(id);
pkg->realname = strdup(id);
pkg->description = strdup("virtual package defining pkgconf API version supported");
pkg->url = strdup(PACKAGE_BUGREPORT);
pkg->version = strdup(PACKAGE_VERSION);
if (pkg->id == NULL ||
pkg->realname == NULL ||
pkg->description == NULL ||
pkg->url == NULL ||
pkg->version == NULL ||
pkgconf_tuple_add(client, &pkg->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(pc_system_libdirs_buf), false, 0) == NULL ||
pkgconf_tuple_add(client, &pkg->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(pc_system_includedirs_buf), false, 0) == NULL ||
pkgconf_tuple_add(client, &pkg->vars, "pc_path", pkgconf_buffer_str_or_empty(pc_path_buf), false, 0) == NULL ||
!pkgconf_client_preload_one(client, pkg))
{
pkgconf_pkg_free(client, pkg);
return false;
}
return true;
}
/* SAFETY: pkgconf_client_t takes ownership of successfully registered package objects */
static void static void
register_builtins(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality) register_builtins(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality)
{ {
pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER;
path_list_to_buffer(&personality->dir_list, &pc_path_buf, ':');
pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER;
path_list_to_buffer(&personality->filter_libdirs, &pc_system_libdirs_buf, ':');
pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER;
path_list_to_buffer(&personality->filter_includedirs, &pc_system_includedirs_buf, ':');
pkgconf_pkg_t *pkg_config_virtual = calloc(1, sizeof(pkgconf_pkg_t)); if (!path_list_to_buffer(&personality->dir_list, &pc_path_buf, PKG_CONFIG_PATH_SEP_S[0]) ||
if (pkg_config_virtual == NULL) !path_list_to_buffer(&personality->filter_libdirs, &pc_system_libdirs_buf, PKG_CONFIG_PATH_SEP_S[0]) ||
{ !path_list_to_buffer(&personality->filter_includedirs, &pc_system_includedirs_buf, PKG_CONFIG_PATH_SEP_S[0]))
goto error; goto error;
}
pkg_config_virtual->owner = client; if (!register_builtin(client, "pkg-config", &pc_path_buf, &pc_system_libdirs_buf, &pc_system_includedirs_buf) ||
pkg_config_virtual->id = strdup("pkg-config"); !register_builtin(client, "pkgconf", &pc_path_buf, &pc_system_libdirs_buf, &pc_system_includedirs_buf))
pkg_config_virtual->realname = strdup("pkg-config");
pkg_config_virtual->description = strdup("virtual package defining pkgconf API version supported");
pkg_config_virtual->url = strdup(PACKAGE_BUGREPORT);
pkg_config_virtual->version = strdup(PACKAGE_VERSION);
pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0);
pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0);
pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0);
if (!pkgconf_client_preload_one(client, pkg_config_virtual))
{
goto error; goto error;
}
pkgconf_pkg_t *pkgconf_virtual = calloc(1, sizeof(pkgconf_pkg_t));
if (pkgconf_virtual == NULL)
{
goto error;
}
pkgconf_virtual->owner = client;
pkgconf_virtual->id = strdup("pkgconf");
pkgconf_virtual->realname = strdup("pkgconf");
pkgconf_virtual->description = strdup("virtual package defining pkgconf API version supported");
pkgconf_virtual->url = strdup(PACKAGE_BUGREPORT);
pkgconf_virtual->version = strdup(PACKAGE_VERSION);
pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0);
pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0);
pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0);
if (!pkgconf_client_preload_one(client, pkgconf_virtual))
{
goto error;
}
error: error:
pkgconf_buffer_finalize(&pc_path_buf); pkgconf_buffer_finalize(&pc_path_buf);
@@ -1015,13 +1017,13 @@ static void
dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p) dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p)
{ {
pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER;
path_list_to_buffer(&p->dir_list, &pc_path_buf, ':');
pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER;
path_list_to_buffer(&p->filter_libdirs, &pc_system_libdirs_buf, ':');
pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER;
path_list_to_buffer(&p->filter_includedirs, &pc_system_includedirs_buf, ':');
if (!path_list_to_buffer(&p->dir_list, &pc_path_buf, ':') ||
!path_list_to_buffer(&p->filter_libdirs, &pc_system_libdirs_buf, ':') ||
!path_list_to_buffer(&p->filter_includedirs, &pc_system_includedirs_buf, ':'))
goto out;
pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "Triplet: %s\n", p->name); pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "Triplet: %s\n", p->name);
@@ -1038,6 +1040,7 @@ dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p)
if (p->want_default_static) if (p->want_default_static)
pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultStatic: true\n"); pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultStatic: true\n");
out:
pkgconf_buffer_finalize(&pc_path_buf); pkgconf_buffer_finalize(&pc_path_buf);
pkgconf_buffer_finalize(&pc_system_libdirs_buf); pkgconf_buffer_finalize(&pc_system_libdirs_buf);
pkgconf_buffer_finalize(&pc_system_includedirs_buf); pkgconf_buffer_finalize(&pc_system_includedirs_buf);
@@ -1146,24 +1149,33 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg
/* if these selectors are used, it means that we are querying metadata. /* if these selectors are used, it means that we are querying metadata.
* so signal to libpkgconf that we only want to walk the flattened dependency set. * so signal to libpkgconf that we only want to walk the flattened dependency set.
*/ */
if ((state->want_flags & PKG_MODVERSION) == PKG_MODVERSION || const bool querying_flattened_metadata =
(state->want_flags & PKG_MODVERSION) == PKG_MODVERSION ||
(state->want_flags & PKG_REQUIRES) == PKG_REQUIRES || (state->want_flags & PKG_REQUIRES) == PKG_REQUIRES ||
(state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE || (state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE ||
(state->want_flags & PKG_PROVIDES) == PKG_PROVIDES || (state->want_flags & PKG_PROVIDES) == PKG_PROVIDES ||
(state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || (state->want_flags & PKG_VARIABLES) == PKG_VARIABLES ||
(state->want_flags & PKG_PATH) == PKG_PATH || (state->want_flags & PKG_PATH) == PKG_PATH ||
state->want_variable != NULL) state->want_variable != NULL;
if (querying_flattened_metadata)
state->maximum_traverse_depth = 1; state->maximum_traverse_depth = 1;
/* if we are asking for a variable, path or list of variables, this only makes sense /* metadata queries only report properties of the modules the user asked about, they
* never combine those modules into a build, so 'Conflicts' rules between them are not
* relevant. see <https://github.com/pkgconf/pkgconf/issues/580>.
*/
if (querying_flattened_metadata ||
(state->want_flags & PKG_DUMP_LICENSE) == PKG_DUMP_LICENSE ||
(state->want_flags & PKG_DUMP_LICENSE_FILE) == PKG_DUMP_LICENSE_FILE ||
(state->want_flags & PKG_DUMP_SOURCE) == PKG_DUMP_SOURCE)
want_client_flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS;
/* if we are asking for a path or list of variables, this only makes sense
* for a single package. * for a single package.
*/ */
if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || (state->want_flags & PKG_PATH) == PKG_PATH)
(state->want_flags & PKG_PATH) == PKG_PATH ||
state->want_variable != NULL)
{
state->maximum_package_count = 1; state->maximum_package_count = 1;
}
if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE || if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE ||
(state->want_flags & PKG_CFLAGS)) (state->want_flags & PKG_CFLAGS))
@@ -1183,7 +1195,8 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg
if ((destdir = pkgconf_client_getenv(&state->pkg_client, "DESTDIR")) != NULL) if ((destdir = pkgconf_client_getenv(&state->pkg_client, "DESTDIR")) != NULL)
{ {
if (!strcmp(destdir, sysroot_dir)) if (!strcmp(destdir, sysroot_dir))
want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES; want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES |
PKGCONF_PKG_PKGF_NO_SYSROOT_INJECTION;
} }
} }
@@ -1228,10 +1241,15 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg
while (last_argc < argc && argv[last_argc]) while (last_argc < argc && argv[last_argc])
{ {
if (pkgconf_buffer_len(&queryparams) > 0) if ((pkgconf_buffer_len(&queryparams) > 0 &&
pkgconf_buffer_push_byte(&queryparams, ' '); !pkgconf_buffer_push_byte(&queryparams, ' ')) ||
!pkgconf_buffer_append(&queryparams, argv[last_argc]))
{
pkgconf_buffer_finalize(&queryparams);
ret = EXIT_FAILURE;
goto out;
}
pkgconf_buffer_append(&queryparams, argv[last_argc]);
last_argc++; last_argc++;
} }
@@ -1269,12 +1287,25 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg
dep->compare = compare; dep->compare = compare;
dep->version = strdup(target_version); dep->version = strdup(target_version);
if (dep->version == NULL)
{
pkgconf_dependency_free(&deplist);
ret = EXIT_FAILURE;
goto out;
}
} }
} }
PKGCONF_FOREACH_LIST_ENTRY(deplist.head, node) PKGCONF_FOREACH_LIST_ENTRY(deplist.head, node)
{ {
pkgconf_dependency_t *dep = node->data; pkgconf_dependency_t *dep = node->data;
/* check if there is a limit to the number of packages allowed to be included, if so and we have hit
* the limit, stop adding packages to the queue.
*/
if (state->maximum_package_count > 0 && pkgq.length >= state->maximum_package_count)
break;
pkgconf_queue_push_dependency(&pkgq, dep); pkgconf_queue_push_dependency(&pkgq, dep);
} }
@@ -1436,8 +1467,10 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg
if ((state->want_flags & PKG_LIBS)) if ((state->want_flags & PKG_LIBS))
apply_libs(&state->pkg_client, &world, &target_list, 2); apply_libs(&state->pkg_client, &world, &target_list, 2);
pkgconf_fragment_render_buf(&target_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' '); if (!pkgconf_fragment_render_buf(&target_list, &render_buf, true, state->want_render_ops,
pkgconf_output_putbuf(state->pkg_client.output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); (state->want_flags & PKG_NEWLINES) ? '\n' : ' ') ||
!pkgconf_output_putbuf(state->pkg_client.output, PKGCONF_OUTPUT_STDOUT, &render_buf, true))
ret = EXIT_FAILURE;
pkgconf_buffer_finalize(&render_buf); pkgconf_buffer_finalize(&render_buf);
pkgconf_fragment_free(&target_list); pkgconf_fragment_free(&target_list);
+1 -1
View File
@@ -96,7 +96,7 @@ typedef struct {
bool opened_error_msgout; bool opened_error_msgout;
} pkgconf_cli_state_t; } pkgconf_cli_state_t;
extern void path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim); extern bool path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim);
extern int pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_argc); extern int pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_argc);
extern void pkgconf_cli_state_reset(pkgconf_cli_state_t *state); extern void pkgconf_cli_state_reset(pkgconf_cli_state_t *state);
+42 -8
View File
@@ -21,6 +21,22 @@
#include "getopt_long.h" #include "getopt_long.h"
#include "core.h" #include "core.h"
static bool
parse_maximum_traverse_depth(const char *value, int *depth)
{
char *end;
long parsed;
errno = 0;
parsed = strtol(value, &end, 10);
if (value == end || *end != '\0' || errno == ERANGE || parsed < -1 || parsed > INT_MAX)
return false;
*depth = (int) parsed;
return true;
}
static const char * static const char *
environ_lookup_handler(const pkgconf_client_t *client, const char *key) environ_lookup_handler(const pkgconf_client_t *client, const char *key)
{ {
@@ -66,7 +82,7 @@ deduce_personality(char *argv[])
if (i != NULL) if (i != NULL)
argv0 = i + 1; argv0 = i + 1;
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64) || defined(__OS2__)
i = strrchr(argv0, '\\'); i = strrchr(argv0, '\\');
if (i != NULL) if (i != NULL)
argv0 = i + 1; argv0 = i + 1;
@@ -166,7 +182,7 @@ usage(void)
printf(" --uninstalled check whether or not an uninstalled module will be used\n"); printf(" --uninstalled check whether or not an uninstalled module will be used\n");
printf(" --no-uninstalled never use uninstalled modules when satisfying dependencies\n"); printf(" --no-uninstalled never use uninstalled modules when satisfying dependencies\n");
printf(" --no-provides do not use 'provides' rules to resolve dependencies\n"); printf(" --no-provides do not use 'provides' rules to resolve dependencies\n");
printf(" --maximum-traverse-depth maximum allowed depth for dependency graph\n"); printf(" --maximum-traverse-depth maximum allowed depth for dependency graph (-1 for unlimited)\n");
printf(" --static be more aggressive when computing dependency graph\n"); printf(" --static be more aggressive when computing dependency graph\n");
printf(" (for static linking)\n"); printf(" (for static linking)\n");
printf(" --shared use a simplified dependency graph (usually default)\n"); printf(" --shared use a simplified dependency graph (usually default)\n");
@@ -240,6 +256,7 @@ main(int argc, char *argv[])
int ret; int ret;
pkgconf_cli_state_t state = { pkgconf_cli_state_t state = {
.want_flags = 0, .want_flags = 0,
.maximum_traverse_depth = 256,
}; };
pkgconf_list_t dir_list = PKGCONF_LIST_INITIALIZER; pkgconf_list_t dir_list = PKGCONF_LIST_INITIALIZER;
char *env_traverse_depth; char *env_traverse_depth;
@@ -252,7 +269,7 @@ main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
#ifdef _WIN32 #if defined(_WIN32) || defined(__OS2__)
/* When running regression tests in cygwin, and building native /* When running regression tests in cygwin, and building native
* executable, tests fail unless native executable outputs unix * executable, tests fail unless native executable outputs unix
* line endings. Come to think of it, this will probably help * line endings. Come to think of it, this will probably help
@@ -365,7 +382,12 @@ main(int argc, char *argv[])
state.want_variable = pkg_optarg; state.want_variable = pkg_optarg;
break; break;
case 11: case 11:
state.maximum_traverse_depth = atoi(pkg_optarg); if (!parse_maximum_traverse_depth(pkg_optarg, &state.maximum_traverse_depth))
{
pkgconf_output_file_fmt(stderr, "pkgconf: invalid maximum traverse depth: %s\n", pkg_optarg);
ret = EXIT_FAILURE;
goto out;
}
break; break;
case 27: case 27:
pkgconf_tuple_define_global(&state.pkg_client, pkg_optarg); pkgconf_tuple_define_global(&state.pkg_client, pkg_optarg);
@@ -417,16 +439,28 @@ main(int argc, char *argv[])
} }
/* now, bring up the client. settings are preserved since the client is prealloced */ /* now, bring up the client. settings are preserved since the client is prealloced */
pkgconf_client_init(&state.pkg_client, error_handler, &state, personality, &state, environ_lookup_handler); pkgconf_client_options_t client_options = {
pkgconf_client_set_unveil_handler(&state.pkg_client, unveil_handler); .error_handler = error_handler,
.error_handler_data = &state,
.personality = personality,
.client_data = &state,
.environ_lookup_handler = environ_lookup_handler,
.unveil_handler = unveil_handler,
};
pkgconf_client_init_with_options(&state.pkg_client, &client_options);
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
if (getenv("PKG_CONFIG_MSVC_SYNTAX") != NULL) if (getenv("PKG_CONFIG_MSVC_SYNTAX") != NULL)
state.want_flags |= PKG_MSVC_SYNTAX; state.want_flags |= PKG_MSVC_SYNTAX;
#endif #endif
if ((env_traverse_depth = getenv("PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH")) != NULL) if ((env_traverse_depth = getenv("PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH")) != NULL &&
state.maximum_traverse_depth = atoi(env_traverse_depth); !parse_maximum_traverse_depth(env_traverse_depth, &state.maximum_traverse_depth))
{
pkgconf_output_file_fmt(stderr, "pkgconf: invalid maximum traverse depth: %s\n", env_traverse_depth);
ret = EXIT_FAILURE;
goto out;
}
if ((state.want_flags & PKG_PRINT_ERRORS) != PKG_PRINT_ERRORS) if ((state.want_flags & PKG_PRINT_ERRORS) != PKG_PRINT_ERRORS)
state.want_flags |= (PKG_SILENCE_ERRORS); state.want_flags |= (PKG_SILENCE_ERRORS);
+588
View File
@@ -0,0 +1,588 @@
/*
* pccritic/critic.c
* pc(5) quality scoring engine
*
* SPDX-License-Identifier: pkgconf
*
* Copyright (c) 2026 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 "libpkgconf/config.h"
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#include "critic.h"
/*
* Each severity carries a fixed point penalty. The score begins at 100 and
* each finding subtracts its severity's penalty; the result is clamped to the
* range 0..100. Keeping the weights here makes the scoring model auditable in
* one place.
*/
static const int severity_penalty[PCCRITIC_SEV_COUNT] = {
[PCCRITIC_SEV_CRITICAL] = 25,
[PCCRITIC_SEV_MAJOR] = 10,
[PCCRITIC_SEV_MINOR] = 4,
[PCCRITIC_SEV_INFO] = 1,
};
static const char *severity_names[PCCRITIC_SEV_COUNT] = {
[PCCRITIC_SEV_CRITICAL] = "critical",
[PCCRITIC_SEV_MAJOR] = "major",
[PCCRITIC_SEV_MINOR] = "minor",
[PCCRITIC_SEV_INFO] = "info",
};
static const char *category_names[PCCRITIC_CAT_COUNT] = {
[PCCRITIC_CAT_METADATA] = "metadata",
[PCCRITIC_CAT_VERSION] = "version",
[PCCRITIC_CAT_RELOCATION] = "relocation",
[PCCRITIC_CAT_CFLAGS] = "cflags",
[PCCRITIC_CAT_LIBS] = "libs",
[PCCRITIC_CAT_REQUIRES] = "requires",
[PCCRITIC_CAT_SBOM] = "sbom",
[PCCRITIC_CAT_STYLE] = "style",
};
const char *
pccritic_severity_name(pccritic_severity_t severity)
{
if (severity >= PCCRITIC_SEV_COUNT)
return "unknown";
return severity_names[severity];
}
const char *
pccritic_category_name(pccritic_category_t category)
{
if (category >= PCCRITIC_CAT_COUNT)
return "unknown";
return category_names[category];
}
pccritic_report_t *
pccritic_report_new(void)
{
pccritic_report_t *report = calloc(1, sizeof(*report));
if (report == NULL)
return NULL;
report->score = 100;
report->grade = 'A';
return report;
}
void
pccritic_report_free(pccritic_report_t *report)
{
pkgconf_node_t *node, *tmp;
if (report == NULL)
return;
PKGCONF_FOREACH_LIST_ENTRY_SAFE(report->findings.head, tmp, node)
{
pccritic_finding_t *finding = node->data;
free(finding->message);
free(finding);
}
free(report);
}
PRINTFLIKE(5, 6) static void
add_finding(pccritic_report_t *report, pccritic_severity_t severity, pccritic_category_t category,
const char *code, const char *fmt, ...)
{
pccritic_finding_t *finding;
va_list va;
char buf[1024];
finding = calloc(1, sizeof(*finding));
if (finding == NULL)
return;
va_start(va, fmt);
vsnprintf(buf, sizeof buf, fmt, va);
va_end(va);
finding->severity = severity;
finding->category = category;
finding->code = code;
finding->message = strdup(buf);
if (finding->message == NULL)
{
free(finding);
return;
}
report->counts[severity]++;
pkgconf_node_insert_tail(&finding->iter, finding, &report->findings);
}
static bool
str_empty(const char *s)
{
return s == NULL || *s == '\0';
}
/* ------------------------------------------------------------------------ */
static void
check_metadata(pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
if (str_empty(pkg->realname))
add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC001",
"missing required 'Name:' field");
if (str_empty(pkg->version))
add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC002",
"missing required 'Version:' field");
if (str_empty(pkg->description))
add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_METADATA, "PC003",
"missing required 'Description:' field");
else if (strlen(pkg->description) < 12)
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_METADATA, "PC004",
"'Description:' is very terse (\"%s\")", pkg->description);
if (str_empty(pkg->url))
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_METADATA, "PC005",
"missing recommended 'URL:' field");
}
static void
check_version(pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
const char *p;
bool has_digit = false, has_space = false;
if (str_empty(pkg->version))
return; /* already reported as PC002 */
for (p = pkg->version; *p != '\0'; p++)
{
if (*p >= '0' && *p <= '9')
has_digit = true;
if (*p == ' ' || *p == '\t')
has_space = true;
}
if (has_space)
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_VERSION, "PC011",
"'Version:' contains whitespace (\"%s\")", pkg->version);
if (!has_digit)
add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_VERSION, "PC010",
"'Version:' has no numeric component (\"%s\")", pkg->version);
}
static bool
var_relocatable(pkgconf_pkg_t *pkg, const char *name)
{
pkgconf_variable_t *v = pkgconf_variable_find(&pkg->vars, name);
if (v == NULL)
return true; /* not present: not our concern here */
return pkgconf_bytecode_references_var(&v->bcbuf, "prefix") ||
pkgconf_bytecode_references_var(&v->bcbuf, "exec_prefix");
}
static void
check_relocation(pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
bool has_prefix = pkgconf_variable_find(&pkg->vars, "prefix") != NULL;
if (!has_prefix)
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_RELOCATION, "PC020",
"no 'prefix' variable is defined; the package cannot be relocated");
if (pkgconf_variable_find(&pkg->vars, "libdir") != NULL && !var_relocatable(pkg, "libdir"))
add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_RELOCATION, "PC021",
"'libdir' is hardcoded; derive it from ${prefix} or ${exec_prefix} for relocatability");
if (pkgconf_variable_find(&pkg->vars, "includedir") != NULL && !var_relocatable(pkg, "includedir"))
add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_RELOCATION, "PC022",
"'includedir' is hardcoded; derive it from ${prefix} for relocatability");
}
/* Reconstruct a fragment's textual flag form for diagnostics. */
static const char *
fragment_text(const pkgconf_fragment_t *frag, char *buf, size_t buflen)
{
if (frag->type != 0)
snprintf(buf, buflen, "-%c%s", frag->type, frag->data != NULL ? frag->data : "");
else
snprintf(buf, buflen, "%s", frag->data != NULL ? frag->data : "");
return buf;
}
static bool
prefix_match(const char *s, const char *prefix)
{
size_t n = strlen(prefix);
return strncmp(s, prefix, n) == 0;
}
/* Well-known directories already on the compiler/linker default search path. */
static bool
is_system_includedir(const char *path)
{
#ifdef SYSTEM_INCLUDEDIR
if (!strcmp(path, SYSTEM_INCLUDEDIR))
return true;
#endif
return !strcmp(path, "/usr/include") || !strcmp(path, "/usr/local/include");
}
static bool
is_system_libdir(const char *path)
{
#ifdef SYSTEM_LIBDIR
if (!strcmp(path, SYSTEM_LIBDIR))
return true;
#endif
return !strcmp(path, "/usr/lib") || !strcmp(path, "/usr/lib64") ||
!strcmp(path, "/lib") || !strcmp(path, "/lib64") ||
!strcmp(path, "/usr/local/lib");
}
static void
check_cflags(pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
pkgconf_node_t *node;
char buf[PKGCONF_BUFSIZE];
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node)
{
pkgconf_fragment_t *frag = node->data;
switch (frag->type)
{
case 'I':
if (frag->data != NULL && is_system_includedir(frag->data))
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_CFLAGS, "PC031",
"Cflags adds an include path already on the default search path (pkgconf strips it): -I%s", frag->data);
break;
case 'D':
case 'U':
case 'F': /* -F: framework search dir (Darwin) */
break;
case 0:
/* raw / unmergeable flag: classify by content */
if (frag->data == NULL)
break;
if (!strcmp(frag->data, "-pthread") ||
prefix_match(frag->data, "-isystem") ||
prefix_match(frag->data, "-idirafter") ||
prefix_match(frag->data, "-iquote") ||
prefix_match(frag->data, "-imacros") ||
prefix_match(frag->data, "-include") ||
prefix_match(frag->data, "-framework"))
break;
if (prefix_match(frag->data, "-std=") || prefix_match(frag->data, "-stdlib="))
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_CFLAGS, "PC033",
"Cflags imposes a language standard on consumers: %s", frag->data);
else if (prefix_match(frag->data, "-Wl,"))
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_CFLAGS, "PC032",
"Cflags contains a linker flag, which belongs in Libs: %s", frag->data);
else
add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_CFLAGS, "PC030",
"Cflags contains a build-tuning flag that pollutes consumer builds: %s", frag->data);
break;
case 'l':
case 'L':
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_CFLAGS, "PC034",
"Cflags contains a linker flag, which belongs in Libs: %s",
fragment_text(frag, buf, sizeof buf));
break;
default:
add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_CFLAGS, "PC030",
"Cflags contains a build-tuning flag that pollutes consumer builds: %s",
fragment_text(frag, buf, sizeof buf));
break;
}
}
}
static void
check_libs_list(pkgconf_list_t *libs, const char *which, pccritic_report_t *report)
{
pkgconf_node_t *node;
char buf[PKGCONF_BUFSIZE];
PKGCONF_FOREACH_LIST_ENTRY(libs->head, node)
{
pkgconf_fragment_t *frag = node->data;
switch (frag->type)
{
case 'l':
break;
case 'L':
if (frag->data != NULL && is_system_libdir(frag->data))
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_LIBS, "PC040",
"%s adds a library path already on the default search path (pkgconf strips it): -L%s", which, frag->data);
break;
case 'F': /* -F framework dir / -framework arrives as type 0 */
break;
case 0:
if (frag->data == NULL)
break;
if (strstr(frag->data, "-rpath") != NULL || strstr(frag->data, "rpath=") != NULL)
add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_LIBS, "PC042",
"%s hardcodes a runtime library path: %s", which, frag->data);
else if (!strcmp(frag->data, "-pthread") ||
prefix_match(frag->data, "-framework") ||
prefix_match(frag->data, "-Wl,") ||
prefix_match(frag->data, "-l"))
break;
else
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_LIBS, "PC041",
"%s contains an unexpected flag: %s", which, frag->data);
break;
default:
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_LIBS, "PC041",
"%s contains an unexpected flag: %s", which, fragment_text(frag, buf, sizeof buf));
break;
}
}
}
static void
check_libs(pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
check_libs_list(&pkg->libs, "Libs", report);
check_libs_list(&pkg->libs_private, "Libs.private", report);
}
static bool
dep_in_list(pkgconf_list_t *list, const char *package)
{
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
{
pkgconf_dependency_t *dep = node->data;
if (dep->package != NULL && !strcmp(dep->package, package))
return true;
}
return false;
}
static void
check_requires(pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
pkgconf_node_t *node;
PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
{
pkgconf_dependency_t *dep = node->data;
if (dep->package != NULL && dep_in_list(&pkg->requires_private, dep->package))
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_REQUIRES, "PC051",
"'%s' appears in both Requires and Requires.private", dep->package);
}
}
/*
* The NTIA "minimum elements" for an SBOM are: supplier name, component name,
* component version, other unique identifiers, dependency relationships,
* author of the SBOM data, and a timestamp. Component name and version are
* the required pc(5) fields (PC001/PC002) and dependency relationships are the
* Requires fields, so they are covered elsewhere; author and timestamp are
* supplied by the SBOM generator (bomtool/spdxtool) rather than the .pc file.
* This leaves the supplier and a provenance identifier, both of which map to
* optional pkgconf fields that the SBOM tooling consumes.
*/
static void
check_sbom(pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
if (str_empty(pkg->maintainer))
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_SBOM, "PC070",
"missing 'Maintainer:' field; the NTIA SBOM supplier name cannot be determined");
if (str_empty(pkg->source))
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_SBOM, "PC071",
"missing 'Source:' field; an SBOM has no download location for this package");
if (pkg->license.head == NULL)
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_SBOM, "PC072",
"missing 'License:' field; an SBOM cannot record a declared license");
}
static void
check_style(const char *path, pccritic_report_t *report)
{
FILE *f;
int c, prev = '\n';
bool saw_trailing_ws = false, saw_bom = false;
long pos = 0;
if (path == NULL)
return;
f = fopen(path, "rb");
if (f == NULL)
return;
while ((c = fgetc(f)) != EOF)
{
if (pos < 3)
{
static const unsigned char bom[3] = { 0xEF, 0xBB, 0xBF };
if ((unsigned char) c == bom[pos])
{
if (pos == 2)
saw_bom = true;
}
else
pos = 3; /* not a BOM; stop checking */
}
if (c == '\n' && (prev == ' ' || prev == '\t'))
saw_trailing_ws = true;
prev = c;
pos++;
}
fclose(f);
if (saw_bom)
add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_STYLE, "PC060",
"file begins with a UTF-8 byte-order mark");
if (saw_trailing_ws)
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_STYLE, "PC062",
"file has trailing whitespace on one or more lines");
if (pos > 0 && prev != '\n')
add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_STYLE, "PC063",
"file does not end with a newline");
}
static void
finalize_score(pccritic_report_t *report)
{
int penalty = 0;
pccritic_severity_t sev;
for (sev = 0; sev < PCCRITIC_SEV_COUNT; sev++)
penalty += (int) report->counts[sev] * severity_penalty[sev];
report->score = 100 - penalty;
if (report->score < 0)
report->score = 0;
if (report->score >= 90)
report->grade = 'A';
else if (report->score >= 80)
report->grade = 'B';
else if (report->score >= 70)
report->grade = 'C';
else if (report->score >= 60)
report->grade = 'D';
else
report->grade = 'F';
}
void
pccritic_analyze(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
(void) client;
check_metadata(pkg, report);
check_version(pkg, report);
check_relocation(pkg, report);
check_cflags(pkg, report);
check_libs(pkg, report);
check_requires(pkg, report);
check_sbom(pkg, report);
check_style(pkg->filename, report);
finalize_score(report);
}
/* Does the file declare `key:' at the start of any logical line? */
static bool
file_declares_field(FILE *f, const char *key)
{
char line[PKGCONF_BUFSIZE];
size_t keylen = strlen(key);
rewind(f);
while (fgets(line, sizeof line, f) != NULL)
{
const char *p = line;
while (*p == ' ' || *p == '\t')
p++;
if (!strncmp(p, key, keylen))
{
p += keylen;
while (*p == ' ' || *p == '\t')
p++;
if (*p == ':')
return true;
}
}
return false;
}
void
pccritic_analyze_unparsable(pccritic_report_t *report, const char *path)
{
static const struct {
const char *field;
const char *code;
} required[] = {
{ "Name", "PC001" },
{ "Version", "PC002" },
{ "Description", "PC003" },
};
FILE *f = fopen(path, "rb");
size_t i;
if (f == NULL)
{
add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC000",
"file could not be read");
finalize_score(report);
return;
}
for (i = 0; i < PKGCONF_ARRAY_SIZE(required); i++)
if (!file_declares_field(f, required[i].field))
add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, required[i].code,
"missing required '%s:' field", required[i].field);
fclose(f);
if (report->findings.head == NULL)
add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC000",
"file is not a valid pc(5) file");
check_style(path, report);
finalize_score(report);
}
+81
View File
@@ -0,0 +1,81 @@
/*
* pccritic/critic.h
* pc(5) quality scoring engine
*
* SPDX-License-Identifier: pkgconf
*
* Copyright (c) 2026 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.
*/
#ifndef PCCRITIC_CRITIC_H
#define PCCRITIC_CRITIC_H
#include <libpkgconf/libpkgconf.h>
typedef enum {
PCCRITIC_SEV_CRITICAL = 0,
PCCRITIC_SEV_MAJOR,
PCCRITIC_SEV_MINOR,
PCCRITIC_SEV_INFO,
PCCRITIC_SEV_COUNT
} pccritic_severity_t;
typedef enum {
PCCRITIC_CAT_METADATA = 0,
PCCRITIC_CAT_VERSION,
PCCRITIC_CAT_RELOCATION,
PCCRITIC_CAT_CFLAGS,
PCCRITIC_CAT_LIBS,
PCCRITIC_CAT_REQUIRES,
PCCRITIC_CAT_SBOM,
PCCRITIC_CAT_STYLE,
PCCRITIC_CAT_COUNT
} pccritic_category_t;
typedef struct {
pkgconf_node_t iter;
pccritic_severity_t severity;
pccritic_category_t category;
const char *code;
char *message;
} pccritic_finding_t;
typedef struct {
pkgconf_list_t findings;
unsigned int counts[PCCRITIC_SEV_COUNT];
int score; /* 0..100 */
char grade; /* 'A'..'F' */
} pccritic_report_t;
pccritic_report_t *pccritic_report_new(void);
void pccritic_report_free(pccritic_report_t *report);
/*
* Analyze a parsed package, appending findings to the report and computing
* its score and letter grade. The package must already have been loaded via
* pkgconf_pkg_new_from_path() or pkgconf_pkg_find().
*/
void pccritic_analyze(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pccritic_report_t *report);
/*
* Analyze a .pc file that libpkgconf refused to load (typically because it is
* missing one of the required Name/Description/Version fields). The raw file
* is scanned directly so that the most broken files can still be scored.
*/
void pccritic_analyze_unparsable(pccritic_report_t *report, const char *path);
const char *pccritic_severity_name(pccritic_severity_t severity);
const char *pccritic_category_name(pccritic_category_t category);
#endif /* PCCRITIC_CRITIC_H */
+422
View File
@@ -0,0 +1,422 @@
/*
* pccritic/main.c
* pc(5) quality scorer
*
* SPDX-License-Identifier: pkgconf
*
* Copyright (c) 2026 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 "libpkgconf/config.h"
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#include "getopt_long.h"
#include "critic.h"
#define PKG_VERSION (((uint64_t) 1) << 1)
#define PKG_ABOUT (((uint64_t) 1) << 2)
#define PKG_HELP (((uint64_t) 1) << 3)
#define PKG_QUIET 100
#define PKG_MIN_SCORE 101
#define PKG_DEFINE_VARIABLE 102
#define PKG_COLOR 103
#define ANSI_RESET "\033[0m"
#define ANSI_DIM "\033[2m"
typedef enum {
COLOR_AUTO = 0,
COLOR_ALWAYS,
COLOR_NEVER,
} color_mode_t;
static pkgconf_client_t pkg_client;
static uint64_t want_flags;
static bool opt_quiet = false;
static int opt_min_score = -1;
static color_mode_t opt_color = COLOR_AUTO;
static bool color_on = false;
static FILE *out = NULL;
static FILE *error_msgout = NULL;
static bool
parse_min_score(const char *value, int *score)
{
char *end;
long parsed;
errno = 0;
parsed = strtol(value, &end, 10);
if (value == end || *end != '\0' || errno == ERANGE || parsed < 0 || parsed > 100)
return false;
*score = (int) parsed;
return true;
}
static void
resolve_color(void)
{
switch (opt_color)
{
case COLOR_ALWAYS:
color_on = true;
break;
case COLOR_NEVER:
color_on = false;
break;
case COLOR_AUTO:
default:
color_on = isatty(fileno(out)) && getenv("NO_COLOR") == NULL;
break;
}
}
static const char *
severity_color(pccritic_severity_t severity)
{
if (!color_on)
return "";
switch (severity)
{
case PCCRITIC_SEV_CRITICAL: return "\033[1;31m"; /* bold red */
case PCCRITIC_SEV_MAJOR: return "\033[31m"; /* red */
case PCCRITIC_SEV_MINOR: return "\033[33m"; /* yellow */
case PCCRITIC_SEV_INFO: return "\033[36m"; /* cyan */
default: return "";
}
}
static const char *
grade_color(char grade)
{
if (!color_on)
return "";
switch (grade)
{
case 'A':
case 'B': return "\033[32m"; /* green */
case 'C':
case 'D': return "\033[33m"; /* yellow */
default: return "\033[1;31m"; /* bold red */
}
}
static const char *
dim(void)
{
return color_on ? ANSI_DIM : "";
}
static const char *
reset(void)
{
return color_on ? ANSI_RESET : "";
}
static const char *
environ_lookup_handler(const pkgconf_client_t *client, const char *key)
{
(void) client;
return getenv(key);
}
static bool
error_handler(const char *msg, const pkgconf_client_t *client, void *data)
{
(void) client;
(void) data;
return pkgconf_output_file_fmt(error_msgout, "%s", msg);
}
/* pccritic emits its own findings; swallow libpkgconf's own warnings so they
* do not interleave with the report.
*/
static bool
silent_handler(const char *msg, const pkgconf_client_t *client, void *data)
{
(void) msg;
(void) client;
(void) data;
return true;
}
static int
version(void)
{
printf("pccritic %s\n", PACKAGE_VERSION);
return EXIT_SUCCESS;
}
static int
about(void)
{
printf("pccritic (%s %s)\n", PACKAGE_NAME, PACKAGE_VERSION);
printf("Copyright (c) 2011-2026 pkgconf authors (see AUTHORS in documentation directory)\n\n");
printf("Permission to use, copy, modify, and/or distribute this software for any\n");
printf("purpose with or without fee is hereby granted, provided that the above\n");
printf("copyright notice and this permission notice appear in all copies.\n\n");
printf("This software is provided 'as is' and without any warranty, express or\n");
printf("implied. In no event shall the authors be liable for any damages arising\n");
printf("from the use of this software.\n\n");
printf("Report bugs at <%s>.\n", PACKAGE_BUGREPORT);
return EXIT_SUCCESS;
}
static int
usage(void)
{
printf("usage: pccritic [--flags] [module-or-file ...]\n");
printf("\npccritic scores the quality of pkg-config (pc(5)) files. Each argument\n");
printf("is either a module name resolved from the search path, or a path to a\n");
printf(".pc file. Findings are reported and the file is graded from A to F.\n");
printf("\nbasic options:\n\n");
printf(" --help this message\n");
printf(" --about print pccritic version and license to stdout\n");
printf(" --version print pccritic version to stdout\n");
printf(" --quiet print only the score and grade per target\n");
printf(" --min-score N exit non-zero if any target scores below N\n");
printf(" --color[=WHEN] colorize output; WHEN is 'auto', 'always' or 'never'\n");
printf(" --define-variable=varname=value define variable 'varname' as 'value'\n");
return EXIT_SUCCESS;
}
static bool
ends_with(const char *str, const char *suffix)
{
size_t slen = strlen(str), xlen = strlen(suffix);
return slen >= xlen && strcmp(str + slen - xlen, suffix) == 0;
}
static bool
looks_like_path(const char *arg)
{
return strchr(arg, '/') != NULL || ends_with(arg, ".pc");
}
static bool
file_readable(const char *path)
{
FILE *f = fopen(path, "rb");
if (f == NULL)
return false;
fclose(f);
return true;
}
static pkgconf_pkg_t *
resolve_target(pkgconf_client_t *client, const char *arg)
{
if (looks_like_path(arg))
return pkgconf_pkg_new_from_path(client, arg, 0);
return pkgconf_pkg_find(client, arg);
}
static void
render_report(const char *target, pkgconf_pkg_t *pkg, pccritic_report_t *report)
{
pkgconf_node_t *node;
if (opt_quiet)
{
pkgconf_output_file_fmt(out, "%s: %d/100 %s(%c)%s\n",
target, report->score, grade_color(report->grade), report->grade, reset());
return;
}
pkgconf_output_file_fmt(out, "%s\n", target);
if (pkg != NULL && pkg->filename != NULL && strcmp(pkg->filename, target) != 0)
pkgconf_output_file_fmt(out, " file: %s\n", pkg->filename);
pkgconf_output_file_fmt(out, " score: %d/100 grade: %s%c%s %s(%u critical, %u major, %u minor, %u info)%s\n",
report->score, grade_color(report->grade), report->grade, reset(),
dim(),
report->counts[PCCRITIC_SEV_CRITICAL], report->counts[PCCRITIC_SEV_MAJOR],
report->counts[PCCRITIC_SEV_MINOR], report->counts[PCCRITIC_SEV_INFO],
reset());
if (report->findings.head == NULL)
{
pkgconf_output_file_fmt(out, " no issues found.\n\n");
return;
}
PKGCONF_FOREACH_LIST_ENTRY(report->findings.head, node)
{
pccritic_finding_t *finding = node->data;
pkgconf_output_file_fmt(out, " %s[%-8s]%s %s %s(%s/%s)%s\n",
severity_color(finding->severity), pccritic_severity_name(finding->severity), reset(),
finding->message,
dim(), pccritic_category_name(finding->category), finding->code, reset());
}
pkgconf_output_file_fmt(out, "\n");
}
int
main(int argc, char *argv[])
{
int ret = EXIT_SUCCESS;
int exit_code = EXIT_SUCCESS;
unsigned int want_client_flags = PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_SKIP_ERRORS;
pkgconf_cross_personality_t *personality = pkgconf_cross_personality_default();
out = stdout;
error_msgout = stderr;
struct pkg_option options[] = {
{ "version", no_argument, &want_flags, PKG_VERSION, },
{ "about", no_argument, &want_flags, PKG_ABOUT, },
{ "help", no_argument, &want_flags, PKG_HELP, },
{ "quiet", no_argument, NULL, PKG_QUIET, },
{ "min-score", required_argument, NULL, PKG_MIN_SCORE, },
{ "color", optional_argument, NULL, PKG_COLOR, },
{ "define-variable", required_argument, NULL, PKG_DEFINE_VARIABLE, },
{ NULL, 0, NULL, 0 }
};
while ((ret = pkg_getopt_long_only(argc, argv, "", options, NULL)) != -1)
{
switch (ret)
{
case PKG_QUIET:
opt_quiet = true;
break;
case PKG_MIN_SCORE:
if (!parse_min_score(pkg_optarg, &opt_min_score))
{
pkgconf_output_file_fmt(error_msgout,
"pccritic: invalid --min-score value '%s' (use 0 through 100)\n",
pkg_optarg);
return EXIT_FAILURE;
}
break;
case PKG_COLOR:
if (pkg_optarg == NULL || !strcmp(pkg_optarg, "always"))
opt_color = COLOR_ALWAYS;
else if (!strcmp(pkg_optarg, "never"))
opt_color = COLOR_NEVER;
else if (!strcmp(pkg_optarg, "auto"))
opt_color = COLOR_AUTO;
else
{
pkgconf_output_file_fmt(error_msgout, "pccritic: invalid --color value '%s' (use auto, always or never)\n", pkg_optarg);
return EXIT_FAILURE;
}
break;
case PKG_DEFINE_VARIABLE:
pkgconf_tuple_define_global(&pkg_client, pkg_optarg);
break;
case '?':
case ':':
return EXIT_FAILURE;
default:
break;
}
}
pkgconf_client_options_t client_options = {
.error_handler = error_handler,
.personality = personality,
.environ_lookup_handler = environ_lookup_handler,
};
pkgconf_client_init_with_options(&pkg_client, &client_options);
pkgconf_client_set_warn_handler(&pkg_client, silent_handler, NULL);
pkgconf_client_set_flags(&pkg_client, want_client_flags);
pkgconf_client_dir_list_build(&pkg_client, personality);
if ((want_flags & PKG_ABOUT) == PKG_ABOUT)
{
exit_code = about();
goto out;
}
if ((want_flags & PKG_VERSION) == PKG_VERSION)
{
exit_code = version();
goto out;
}
if ((want_flags & PKG_HELP) == PKG_HELP)
{
exit_code = usage();
goto out;
}
if (pkg_optind >= argc || argv[pkg_optind] == NULL)
{
pkgconf_output_file_fmt(error_msgout, "pccritic: please specify at least one module name or .pc file\n");
exit_code = EXIT_FAILURE;
goto out;
}
resolve_color();
for (; pkg_optind < argc && argv[pkg_optind] != NULL; pkg_optind++)
{
const char *target = argv[pkg_optind];
pkgconf_pkg_t *pkg;
pccritic_report_t *report;
pkg = resolve_target(&pkg_client, target);
if (pkg == NULL && !(looks_like_path(target) && file_readable(target)))
{
pkgconf_output_file_fmt(error_msgout, "pccritic: could not load '%s'\n", target);
exit_code = EXIT_FAILURE;
continue;
}
report = pccritic_report_new();
if (report == NULL)
{
if (pkg != NULL)
pkgconf_pkg_unref(&pkg_client, pkg);
pkgconf_output_file_fmt(error_msgout, "pccritic: out of memory\n");
exit_code = EXIT_FAILURE;
goto out;
}
if (pkg != NULL)
pccritic_analyze(&pkg_client, pkg, report);
else
pccritic_analyze_unparsable(report, target);
render_report(target, pkg, report);
if (opt_min_score >= 0 && report->score < opt_min_score)
exit_code = EXIT_FAILURE;
pccritic_report_free(report);
if (pkg != NULL)
pkgconf_pkg_unref(&pkg_client, pkg);
}
out:
pkgconf_cross_personality_deinit(personality);
pkgconf_client_deinit(&pkg_client);
return exit_code;
}
+21 -12
View File
@@ -50,41 +50,50 @@ allowed_fragment(const pkgconf_fragment_t *frag)
return !(!frag->type || frag->data == NULL || strchr("DILl", frag->type) == NULL); return !(!frag->type || frag->data == NULL || strchr("DILl", frag->type) == NULL);
} }
static void static bool
msvc_renderer_render(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf) msvc_renderer_render(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf)
{ {
pkgconf_buffer_t tmpbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t tmpbuf = PKGCONF_BUFFER_INITIALIZER;
bool escape = ctx->escape; bool escape = ctx->escape;
if (!allowed_fragment(frag)) if (!allowed_fragment(frag))
return; return true;
switch(frag->type) { switch(frag->type) {
case 'D': case 'D':
case 'I': case 'I':
pkgconf_buffer_append_fmt(buf, "/%c", frag->type); if (!pkgconf_buffer_push_byte(buf, '/') || !pkgconf_buffer_push_byte(buf, frag->type))
return false;
break; break;
case 'L': case 'L':
pkgconf_buffer_append(buf, "/libpath:"); if (!pkgconf_buffer_append(buf, "/libpath:"))
return false;
break; break;
} }
pkgconf_buffer_append(&tmpbuf, frag->data); if (!pkgconf_buffer_append(&tmpbuf, frag->data))
return false;
if (frag->type == 'l') if (frag->type == 'l' && !pkgconf_buffer_append(&tmpbuf, ".lib"))
pkgconf_buffer_append(&tmpbuf, ".lib"); goto fail;
escape = should_quote(&tmpbuf); escape = should_quote(&tmpbuf);
if (escape) if (escape && !pkgconf_buffer_push_byte(buf, '"'))
pkgconf_buffer_push_byte(buf, '"'); goto fail;
pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(&tmpbuf)); if (!pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(&tmpbuf)))
goto fail;
if (escape) if (escape && !pkgconf_buffer_push_byte(buf, '"'))
pkgconf_buffer_push_byte(buf, '"'); goto fail;
pkgconf_buffer_finalize(&tmpbuf); pkgconf_buffer_finalize(&tmpbuf);
return true;
fail:
pkgconf_buffer_finalize(&tmpbuf);
return false;
} }
static pkgconf_fragment_render_ops_t msvc_renderer_ops = { static pkgconf_fragment_render_ops_t msvc_renderer_ops = {
+153 -12
View File
@@ -124,6 +124,116 @@ err:
return ret; return ret;
} }
/*
* !doc
*
* .. c:function:: spdxtool_core_tool_t *spdxtool_core_tool_new(pkgconf_client_t *client, const char *creation_info_id, const char *short_name, const char *name)
*
* Create new /Core/Tool struct
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param char *creation_info_id: CreationInfo spdxId
* :param char *short_name Shorter name for tool used in SPDX id (default: 'spdxtool')
* :param char *name: Long name of tool (default: 'spdxtool')
* :return: NULL if some problem occurs and Tool struct if not
*/
spdxtool_core_tool_t *
spdxtool_core_tool_new(pkgconf_client_t *client, const char *creation_info_id, const char *short_name, const char *name)
{
if (!client || !creation_info_id || !name)
return NULL;
spdxtool_core_tool_t *tool = calloc(1, sizeof(spdxtool_core_tool_t));
if (!tool)
goto err;
tool->type = "Tool";
char *spdx_id_name = strdup(short_name);
if (!spdx_id_name)
goto err;
spdxtool_util_string_correction(spdx_id_name);
tool->spdx_id = spdxtool_util_get_spdx_id_string(client, tool->type, spdx_id_name);
free(spdx_id_name);
tool->creation_info = strdup(creation_info_id);
tool->name = strdup(name);
if (!tool->spdx_id || !tool->creation_info || !tool->name)
goto err;
return tool;
err:
pkgconf_error(client, "spdxtool_core_agent_new: out of memory");
spdxtool_core_tool_free(tool);
return NULL;
}
/*
* !doc
*
* .. c:function:: void spdxtool_core_tool_free(spdxtool_core_tool_t *tool)
*
* Free /Core/Tool struct
*
* :param spdxtool_core_tool_t *tool: Tool struct to be freed.
* :return: nothing
*/
void
spdxtool_core_tool_free(spdxtool_core_tool_t *tool)
{
if (!tool)
return;
free(tool->creation_info);
free(tool->spdx_id);
free(tool->name);
free(tool);
}
/*
* !doc
*
* .. c:function:: spdxtool_serialize_value_t *spdxtool_core_tool_to_object(pkgconf_client_t *client, const spdxtool_core_tool_t *tool)
*
* Serialize /Core/Tool struct to a JSON value tree.
*
* :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param const spdxtool_core_tool_t *tool: Tool struct to be serialized.
* :return: spdxtool_serialize_value_t * representing the Agent object.
*/
spdxtool_serialize_value_t *
spdxtool_core_tool_to_object(pkgconf_client_t *client, const spdxtool_core_tool_t *tool)
{
spdxtool_serialize_value_t *ret = NULL;
spdxtool_serialize_object_list_t *object_list = spdxtool_serialize_object_list_new();
if (!object_list)
goto err;
if (!(spdxtool_serialize_object_add_string(object_list, "type", tool->type) &&
spdxtool_serialize_object_add_string(object_list, "creationInfo", tool->creation_info) &&
spdxtool_serialize_object_add_string(object_list, "spdxId", tool->spdx_id) &&
spdxtool_serialize_object_add_string(object_list, "name", tool->name)))
{
goto err;
}
ret = spdxtool_serialize_value_object(object_list);
object_list = NULL;
err:
if (!ret)
pkgconf_error(client, "spdxtool_core_agent_to_object: out of memory");
spdxtool_serialize_object_list_free(object_list);
return ret;
}
/* /*
* !doc * !doc
* *
@@ -140,9 +250,9 @@ err:
* :return: NULL if some problem occurs and CreationInfo struct if not * :return: NULL if some problem occurs and CreationInfo struct if not
*/ */
spdxtool_core_creation_info_t * spdxtool_core_creation_info_t *
spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *id, const char *time) spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *tool_id, const char *id, const char *time)
{ {
if (!client || !agent_id || !id) if (!client || !agent_id || !id || !tool_id)
return NULL; return NULL;
spdxtool_core_creation_info_t *creation = calloc(1, sizeof(spdxtool_core_creation_info_t)); spdxtool_core_creation_info_t *creation = calloc(1, sizeof(spdxtool_core_creation_info_t));
@@ -154,9 +264,10 @@ spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id,
creation->id = strdup(id); creation->id = strdup(id);
creation->created = time ? strdup(time) : spdxtool_util_get_current_iso8601_time(); creation->created = time ? strdup(time) : spdxtool_util_get_current_iso8601_time();
creation->created_by = strdup(agent_id); creation->created_by = strdup(agent_id);
creation->created_using = strdup(tool_id);
creation->spec_version = strdup(spdxtool_util_get_spdx_version(client)); creation->spec_version = strdup(spdxtool_util_get_spdx_version(client));
if (!creation->id || !creation->created || !creation->created_by || !creation->spec_version) if (!creation->id || !creation->created || !creation->created_by || !creation->created_using | !creation->spec_version)
goto err; goto err;
return creation; return creation;
@@ -186,6 +297,7 @@ spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation)
free(creation->id); free(creation->id);
free(creation->created); free(creation->created);
free(creation->created_by); free(creation->created_by);
free(creation->created_using);
free(creation->spec_version); free(creation->spec_version);
free(creation); free(creation);
@@ -220,17 +332,39 @@ spdxtool_core_creation_info_to_object(pkgconf_client_t *client, const spdxtool_c
goto err; goto err;
} }
if (!(spdxtool_serialize_object_add_string(object_list, "type", creation->type) && spdxtool_serialize_array_t *created_using = spdxtool_serialize_array_new();
spdxtool_serialize_object_add_string(object_list, "@id", creation->id) && if (!created_using)
spdxtool_serialize_object_add_string(object_list, "created", creation->created)))
{ {
/* created_by has not been handed to the object list yet */
spdxtool_serialize_array_free(created_by); spdxtool_serialize_array_free(created_by);
goto err; goto err;
} }
if (!spdxtool_serialize_array_add_string(created_using, creation->created_using))
{
spdxtool_serialize_array_free(created_by);
spdxtool_serialize_array_free(created_using);
goto err;
}
if (!(spdxtool_serialize_object_add_string(object_list, "type", creation->type) &&
spdxtool_serialize_object_add_string(object_list, "@id", creation->id) &&
spdxtool_serialize_object_add_string(object_list, "created", creation->created)))
{
/* created_by or created_using has not been handed to the object list yet */
spdxtool_serialize_array_free(created_by);
spdxtool_serialize_array_free(created_using);
goto err;
}
/* object_add_array takes ownership of created_by, freeing it on failure */ /* object_add_array takes ownership of created_by, freeing it on failure */
if (!(spdxtool_serialize_object_add_array(object_list, "createdBy", created_by) && if (!spdxtool_serialize_object_add_array(object_list, "createdBy", created_by))
{
spdxtool_serialize_array_free(created_using);
goto err;
}
/* object_add_array takes ownership of created_using, freeing it on failure */
if (!(spdxtool_serialize_object_add_array(object_list, "createUsing", created_using) &&
spdxtool_serialize_object_add_string(object_list, "specVersion", creation->spec_version))) spdxtool_serialize_object_add_string(object_list, "specVersion", creation->spec_version)))
{ {
goto err; goto err;
@@ -523,10 +657,14 @@ spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_
return false; return false;
} }
pkgconf_node_insert_tail(node, expression, &spdx->licenses);
if (!spdxtool_core_spdx_document_add_element(client, spdx, expression->spdx_id)) if (!spdxtool_core_spdx_document_add_element(client, spdx, expression->spdx_id))
{
spdxtool_simplelicensing_licenseExpression_free(expression);
free(node);
return false; return false;
}
pkgconf_node_insert_tail(node, expression, &spdx->licenses);
return true; return true;
} }
@@ -613,11 +751,14 @@ spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_co
return NULL; return NULL;
} }
pkgconf_node_insert_tail(node, agent, &spdx->maintainers);
if (!spdxtool_core_spdx_document_add_element(client, spdx, agent->spdx_id)) if (!spdxtool_core_spdx_document_add_element(client, spdx, agent->spdx_id))
{
free(node);
spdxtool_core_agent_free(agent);
return NULL; return NULL;
}
pkgconf_node_insert_tail(node, agent, &spdx->maintainers);
return agent->spdx_id; return agent->spdx_id;
} }
@@ -710,12 +851,12 @@ spdxtool_core_relationship_new(pkgconf_client_t *client, const char *creation_in
relationship->creation_info = strdup(creation_info_id); relationship->creation_info = strdup(creation_info_id);
relationship->spdx_id = strdup(spdx_id); relationship->spdx_id = strdup(spdx_id);
relationship->from = strdup(from); relationship->from = strdup(from);
relationship->to = to;
relationship->relationship_type = strdup(relationship_type); relationship->relationship_type = strdup(relationship_type);
if (!relationship->creation_info || !relationship->spdx_id || !relationship->from || !relationship->relationship_type) if (!relationship->creation_info || !relationship->spdx_id || !relationship->from || !relationship->relationship_type)
goto err; goto err;
relationship->to = to;
return relationship; return relationship;
err: err:
+10 -1
View File
@@ -28,8 +28,17 @@ spdxtool_core_agent_free(spdxtool_core_agent_t *agent);
spdxtool_serialize_value_t * spdxtool_serialize_value_t *
spdxtool_core_agent_to_object(pkgconf_client_t *client, const spdxtool_core_agent_t *agent); spdxtool_core_agent_to_object(pkgconf_client_t *client, const spdxtool_core_agent_t *agent);
spdxtool_core_tool_t *
spdxtool_core_tool_new(pkgconf_client_t *client, const char *creation_info_id, const char *short_name, const char *name);
void
spdxtool_core_tool_free(spdxtool_core_tool_t *tool);
spdxtool_serialize_value_t *
spdxtool_core_tool_to_object(pkgconf_client_t *client, const spdxtool_core_tool_t *tool);
spdxtool_core_creation_info_t * spdxtool_core_creation_info_t *
spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *id, const char *time); spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *tool_id, const char *id, const char *time);
void void
spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation); spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation);
+84 -26
View File
@@ -17,20 +17,47 @@
#include "simplelicensing.h" #include "simplelicensing.h"
#include "generate.h" #include "generate.h"
typedef struct {
spdxtool_core_spdx_document_t *document;
bool failed;
} generate_spdx_ctx_t;
static bool
generate_spdx_document_add_sbom(pkgconf_client_t *client, spdxtool_core_spdx_document_t *document, spdxtool_software_sbom_t *sbom)
{
pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t));
if (!node)
{
pkgconf_error(client, "generate_spdx_document_add_sbom: out of memory");
return false;
}
pkgconf_node_insert_tail(node, sbom, &document->rootElement);
return true;
}
// NOTE: this function is passed to pkgconf_pkg_traverse // NOTE: this function is passed to pkgconf_pkg_traverse
static void static void
generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr, unsigned int iter_flags)
{ {
spdxtool_core_spdx_document_t *document = (spdxtool_core_spdx_document_t *)ptr; (void) iter_flags;
pkgconf_node_t *node = NULL;
generate_spdx_ctx_t *ctx = ptr;
spdxtool_core_spdx_document_t *document = ctx->document;
pkgconf_node_t *iter = NULL;
spdxtool_software_sbom_t *sbom = NULL; spdxtool_software_sbom_t *sbom = NULL;
char *package_spdx = NULL; char *package_spdx = NULL;
char *spdx_id_string = NULL; char *spdx_id_string = NULL;
pkgconf_buffer_t spdx_id_buf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_t concluded_buf = PKGCONF_BUFFER_INITIALIZER;
char sep = spdxtool_util_get_uri_separator(client); char sep = spdxtool_util_get_uri_separator(client);
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
return; return;
if (ctx->failed)
return;
spdx_id_string = spdxtool_util_get_spdx_id_string(client, "software_Sbom", pkg->id); spdx_id_string = spdxtool_util_get_spdx_id_string(client, "software_Sbom", pkg->id);
if (!spdx_id_string) if (!spdx_id_string)
goto err; goto err;
@@ -48,12 +75,16 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
if (!package_spdx) if (!package_spdx)
goto err; goto err;
pkgconf_tuple_add(client, &pkg->vars, "spdxId", package_spdx, false, 0); if (pkgconf_tuple_add(client, &pkg->vars, "spdxId", package_spdx, false, 0) == NULL)
goto err;
free(package_spdx); free(package_spdx);
package_spdx = NULL; package_spdx = NULL;
pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0); if (pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0) == NULL ||
pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0); pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0) == NULL)
{
goto err;
}
if (pkg->maintainer != NULL) if (pkg->maintainer != NULL)
{ {
@@ -61,14 +92,15 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
if (!supplier) if (!supplier)
goto err; goto err;
pkgconf_tuple_add(client, &pkg->vars, "suppliedBy", supplier, false, 0); if (pkgconf_tuple_add(client, &pkg->vars, "suppliedBy", supplier, false, 0) == NULL)
goto err;
} }
if (pkg->license.head != NULL) if (pkg->license.head != NULL)
{ {
pkgconf_buffer_t spdx_id_buf = PKGCONF_BUFFER_INITIALIZER; if (!pkgconf_buffer_append_fmt(&spdx_id_buf, "%s%chasDeclaredLicense", pkg->id, sep))
goto err;
pkgconf_buffer_append_fmt(&spdx_id_buf, "%s%chasDeclaredLicense", pkg->id, sep);
char *spdx_id_name = pkgconf_buffer_freeze(&spdx_id_buf); char *spdx_id_name = pkgconf_buffer_freeze(&spdx_id_buf);
if (!spdx_id_name) if (!spdx_id_name)
goto err; goto err;
@@ -78,12 +110,14 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
if (!package_spdx) if (!package_spdx)
goto err; goto err;
pkgconf_tuple_add(client, &pkg->vars, "hasDeclaredLicense", package_spdx, false, 0); if (pkgconf_tuple_add(client, &pkg->vars, "hasDeclaredLicense", package_spdx, false, 0) == NULL)
goto err;
free(package_spdx); free(package_spdx);
package_spdx = NULL; package_spdx = NULL;
pkgconf_buffer_t concluded_buf = PKGCONF_BUFFER_INITIALIZER; if (!pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep))
pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep); goto err;
spdx_id_name = pkgconf_buffer_freeze(&concluded_buf); spdx_id_name = pkgconf_buffer_freeze(&concluded_buf);
if (!spdx_id_name) if (!spdx_id_name)
goto err; goto err;
@@ -93,13 +127,14 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
if (!package_spdx) if (!package_spdx)
goto err; goto err;
pkgconf_tuple_add(client, &pkg->vars, "hasConcludedLicense", package_spdx, false, 0); if (pkgconf_tuple_add(client, &pkg->vars, "hasConcludedLicense", package_spdx, false, 0) == NULL)
goto err;
free(package_spdx); free(package_spdx);
package_spdx = NULL; package_spdx = NULL;
PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, iter)
{ {
const pkgconf_license_t *license = node->data; const pkgconf_license_t *license = iter->data;
if (license->type == PKGCONF_LICENSE_EXPRESSION) if (license->type == PKGCONF_LICENSE_EXPRESSION)
{ {
if (!spdxtool_core_spdx_document_add_license(client, document, license->data)) if (!spdxtool_core_spdx_document_add_license(client, document, license->data))
@@ -108,17 +143,19 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
} }
} }
node = calloc(1, sizeof(pkgconf_node_t)); if (!generate_spdx_document_add_sbom(client, document, sbom))
if (!node)
goto err; goto err;
pkgconf_node_insert_tail(node, sbom, &document->rootElement); sbom = NULL;
return; return;
err: err:
ctx->failed = true;
pkgconf_error(client, "generate_spdx_package: failed for %s", pkg->id); pkgconf_error(client, "generate_spdx_package: failed for %s", pkg->id);
free(package_spdx); free(package_spdx);
free(spdx_id_string); free(spdx_id_string);
pkgconf_buffer_finalize(&spdx_id_buf);
pkgconf_buffer_finalize(&concluded_buf);
spdxtool_software_sbom_free(sbom); spdxtool_software_sbom_free(sbom);
} }
@@ -128,6 +165,8 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
{ {
const char *agent_name_string = agent_name ? agent_name : "Default"; const char *agent_name_string = agent_name ? agent_name : "Default";
const char *creation_id_string = creation_id ? creation_id : "_:creationinfo_1"; const char *creation_id_string = creation_id ? creation_id : "_:creationinfo_1";
const char *tool_short_name_string = "spdxtool";
const char *tool_name_string = "spdxtool";
spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, creation_id_string, agent_name_string); spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, creation_id_string, agent_name_string);
if (!agent) if (!agent)
@@ -136,10 +175,19 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
return false; return false;
} }
spdxtool_core_creation_info_t *creation = spdxtool_core_creation_info_new(client, agent->spdx_id, creation_id_string, creation_time); spdxtool_core_tool_t *tool = spdxtool_core_tool_new(client, creation_id_string, tool_short_name_string, tool_name_string);
if (!tool)
{
pkgconf_error(client, "Could not create tool struct");
spdxtool_core_agent_free(agent);
return false;
}
spdxtool_core_creation_info_t *creation = spdxtool_core_creation_info_new(client, agent->spdx_id, tool->spdx_id, creation_id_string, creation_time);
if (!creation) if (!creation)
{ {
pkgconf_error(client, "Could not create creation info struct"); pkgconf_error(client, "Could not create creation info struct");
spdxtool_core_tool_free(tool);
spdxtool_core_agent_free(agent); spdxtool_core_agent_free(agent);
return false; return false;
} }
@@ -155,8 +203,11 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
return false; return false;
} }
int eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, document, maxdepth, 0); generate_spdx_ctx_t ctx = {
if (eflag != PKGCONF_PKG_ERRF_OK) .document = document,
};
int eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, &ctx, maxdepth, 0);
if (eflag != PKGCONF_PKG_ERRF_OK || ctx.failed)
{ {
spdxtool_core_spdx_document_free(document); spdxtool_core_spdx_document_free(document);
spdxtool_core_creation_info_free(creation); spdxtool_core_creation_info_free(creation);
@@ -164,7 +215,7 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
return false; return false;
} }
spdxtool_serialize_value_t *root = spdxtool_serialize_sbom(client, agent, creation, document); spdxtool_serialize_value_t *root = spdxtool_serialize_sbom(client, agent, tool, creation, document);
if (!root) if (!root)
{ {
spdxtool_core_spdx_document_free(document); spdxtool_core_spdx_document_free(document);
@@ -174,17 +225,24 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
} }
pkgconf_buffer_t buffer = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t buffer = PKGCONF_BUFFER_INITIALIZER;
spdxtool_serialize_value_to_buf(&buffer, root, 0); bool ret = spdxtool_serialize_value_to_buf(&buffer, root, 0);
spdxtool_serialize_value_free(root); spdxtool_serialize_value_free(root);
bool ret = pkgconf_output_file_fmt(out, "%s\n", pkgconf_buffer_str(&buffer)); if (ret)
{
ret = pkgconf_output_file_fmt(out, "%s\n", pkgconf_buffer_str(&buffer));
if (!ret)
pkgconf_error(client, "spdxtool: Could not output to file: %s", strerror(errno));
}
else
pkgconf_error(client, "spdxtool: Could not serialize SPDX document");
pkgconf_buffer_finalize(&buffer); pkgconf_buffer_finalize(&buffer);
spdxtool_core_spdx_document_free(document); spdxtool_core_spdx_document_free(document);
spdxtool_core_creation_info_free(creation); spdxtool_core_creation_info_free(creation);
spdxtool_core_tool_free(tool);
spdxtool_core_agent_free(agent); spdxtool_core_agent_free(agent);
if (!ret)
pkgconf_error(client, "spdxtool: Could not output to file: %s", strerror(errno));
return ret; return ret;
} }
+23 -6
View File
@@ -87,8 +87,8 @@ usage(void)
printf(" --creation-time Use string as creation time (Should be in ISO8601 format) [default: current time]\n"); printf(" --creation-time Use string as creation time (Should be in ISO8601 format) [default: current time]\n");
printf(" --creation-id Use string as creation id [default: '_:creationinfo_1']\n"); printf(" --creation-id Use string as creation id [default: '_:creationinfo_1']\n");
printf(" --help this message\n"); printf(" --help this message\n");
printf(" --about print bomtool version and license to stdout\n"); printf(" --about print spdxtool version and license to stdout\n");
printf(" --version print bomtool version to stdout\n"); printf(" --version print spdxtool version to stdout\n");
printf(" --output FILE output SBOM data to file\n"); printf(" --output FILE output SBOM data to file\n");
printf(" --spdx-base-id URL Uset string as base of SPDX ids [default: %s]\n", xsd_any_uri_default_base); printf(" --spdx-base-id URL Uset string as base of SPDX ids [default: %s]\n", xsd_any_uri_default_base);
printf(" --use-uri Use URIs not URLs as SPDX id"); printf(" --use-uri Use URIs not URLs as SPDX id");
@@ -177,7 +177,12 @@ main(int argc, char *argv[])
} }
} }
pkgconf_client_init(&pkg_client, error_handler, NULL, personality, NULL, environ_lookup_handler); pkgconf_client_options_t client_options = {
.error_handler = error_handler,
.personality = personality,
.environ_lookup_handler = environ_lookup_handler,
};
pkgconf_client_init_with_options(&pkg_client, &client_options);
/* we have determined what features we want most likely. in some cases, we override later. */ /* we have determined what features we want most likely. in some cases, we override later. */
pkgconf_client_set_flags(&pkg_client, want_client_flags); pkgconf_client_set_flags(&pkg_client, want_client_flags);
@@ -203,10 +208,15 @@ main(int argc, char *argv[])
while (pkg_optind < argc && argv[pkg_optind] != NULL) while (pkg_optind < argc && argv[pkg_optind] != NULL)
{ {
if (pkgconf_buffer_len(&queryparams) > 0) if ((pkgconf_buffer_len(&queryparams) > 0 &&
pkgconf_buffer_push_byte(&queryparams, ' '); !pkgconf_buffer_push_byte(&queryparams, ' ')) ||
!pkgconf_buffer_append(&queryparams, argv[pkg_optind]))
{
pkgconf_buffer_finalize(&queryparams);
ret = EXIT_FAILURE;
goto out;
}
pkgconf_buffer_append(&queryparams, argv[pkg_optind]);
pkg_optind++; pkg_optind++;
} }
@@ -215,6 +225,13 @@ main(int argc, char *argv[])
pkgconf_buffer_finalize(&queryparams); pkgconf_buffer_finalize(&queryparams);
if (pkgq.head == NULL)
{
pkgconf_output_file_fmt(stderr, "Please specify at least one package name on the command line.\n");
ret = EXIT_FAILURE;
goto out;
}
if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth)) if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth))
{ {
ret = EXIT_FAILURE; ret = EXIT_FAILURE;
+65 -45
View File
@@ -18,48 +18,60 @@
#include "simplelicensing.h" #include "simplelicensing.h"
#include "serialize.h" #include "serialize.h"
static void static bool
serialize_escape_string(pkgconf_buffer_t *buffer, const char *s) serialize_escape_string(pkgconf_buffer_t *buffer, const char *s)
{ {
for (const char *p = s; *p; p++) for (const char *p = s; *p; p++)
{ {
bool ret;
switch (*p) switch (*p)
{ {
case '\"': case '\"':
pkgconf_buffer_append(buffer, "\\\""); ret = pkgconf_buffer_append(buffer, "\\\"");
break; break;
case '\\': case '\\':
pkgconf_buffer_append(buffer, "\\\\"); ret = pkgconf_buffer_append(buffer, "\\\\");
break; break;
case '\b': case '\b':
pkgconf_buffer_append(buffer, "\\b"); ret = pkgconf_buffer_append(buffer, "\\b");
break; break;
case '\f': case '\f':
pkgconf_buffer_append(buffer, "\\f"); ret = pkgconf_buffer_append(buffer, "\\f");
break; break;
case '\n': case '\n':
pkgconf_buffer_append(buffer, "\\n"); ret = pkgconf_buffer_append(buffer, "\\n");
break; break;
case '\r': case '\r':
pkgconf_buffer_append(buffer, "\\r"); ret = pkgconf_buffer_append(buffer, "\\r");
break; break;
case '\t': case '\t':
pkgconf_buffer_append(buffer, "\\t"); ret = pkgconf_buffer_append(buffer, "\\t");
break; break;
default: default:
if ((unsigned char) *p < 0x20) if ((unsigned char) *p < 0x20)
pkgconf_buffer_append_fmt(buffer, "\\u%04x", (unsigned int)(unsigned char) *p); ret = pkgconf_buffer_append_fmt(buffer, "\\u%04x", (unsigned int)(unsigned char) *p);
else else
pkgconf_buffer_push_byte(buffer, *p); ret = pkgconf_buffer_push_byte(buffer, *p);
} }
if (!ret)
return false;
} }
return true;
} }
static inline void static inline bool
serialize_add_indent(pkgconf_buffer_t *buffer, unsigned int level) serialize_add_indent(pkgconf_buffer_t *buffer, unsigned int level)
{ {
for (; level; level--) for (; level; level--)
pkgconf_buffer_append(buffer, " "); {
if (!pkgconf_buffer_append(buffer, " "))
return false;
}
return true;
} }
/* /*
@@ -82,62 +94,67 @@ spdxtool_serialize_value_to_buf(pkgconf_buffer_t *buffer, spdxtool_serialize_val
switch(value->type) { switch(value->type) {
case SPDXTOOL_SERIALIZE_TYPE_STRING: case SPDXTOOL_SERIALIZE_TYPE_STRING:
pkgconf_buffer_push_byte(buffer, '"'); return pkgconf_buffer_push_byte(buffer, '"') &&
serialize_escape_string(buffer, value->value.s ? value->value.s : ""); serialize_escape_string(buffer, value->value.s ? value->value.s : "") &&
pkgconf_buffer_push_byte(buffer, '"'); pkgconf_buffer_push_byte(buffer, '"');
break;
case SPDXTOOL_SERIALIZE_TYPE_INT: case SPDXTOOL_SERIALIZE_TYPE_INT:
pkgconf_buffer_append_fmt(buffer, "%d", value->value.i); return pkgconf_buffer_append_fmt(buffer, "%d", value->value.i);
break;
case SPDXTOOL_SERIALIZE_TYPE_BOOL: case SPDXTOOL_SERIALIZE_TYPE_BOOL:
pkgconf_buffer_append(buffer, value->value.b ? "true" : "false"); return pkgconf_buffer_append(buffer, value->value.b ? "true" : "false");
break;
case SPDXTOOL_SERIALIZE_TYPE_NULL: case SPDXTOOL_SERIALIZE_TYPE_NULL:
pkgconf_buffer_append(buffer, "null"); return pkgconf_buffer_append(buffer, "null");
break;
case SPDXTOOL_SERIALIZE_TYPE_OBJECT: case SPDXTOOL_SERIALIZE_TYPE_OBJECT:
{ {
pkgconf_node_t *iter; pkgconf_node_t *iter;
pkgconf_buffer_push_byte(buffer, '{');
pkgconf_buffer_push_byte(buffer, '\n'); if (value->value.o == NULL ||
!pkgconf_buffer_push_byte(buffer, '{') ||
!pkgconf_buffer_push_byte(buffer, '\n'))
return false;
PKGCONF_FOREACH_LIST_ENTRY(value->value.o->entries.head, iter) PKGCONF_FOREACH_LIST_ENTRY(value->value.o->entries.head, iter)
{ {
spdxtool_serialize_object_t *entry = iter->data; spdxtool_serialize_object_t *entry = iter->data;
serialize_add_indent(buffer, indent + 1);
pkgconf_buffer_append_fmt(buffer, "\"%s\": ", entry->key); if (!serialize_add_indent(buffer, indent + 1) ||
spdxtool_serialize_value_to_buf(buffer, entry->value, indent + 1); !pkgconf_buffer_push_byte(buffer, '"') ||
if (iter->next) !serialize_escape_string(buffer, entry->key ? entry->key : "") ||
pkgconf_buffer_push_byte(buffer, ','); !pkgconf_buffer_append(buffer, "\": ") ||
pkgconf_buffer_push_byte(buffer, '\n'); !spdxtool_serialize_value_to_buf(buffer, entry->value, indent + 1) ||
(iter->next && !pkgconf_buffer_push_byte(buffer, ',')) ||
!pkgconf_buffer_push_byte(buffer, '\n'))
return false;
} }
serialize_add_indent(buffer, indent); return serialize_add_indent(buffer, indent) &&
pkgconf_buffer_push_byte(buffer, '}'); pkgconf_buffer_push_byte(buffer, '}');
break;
} }
case SPDXTOOL_SERIALIZE_TYPE_ARRAY: case SPDXTOOL_SERIALIZE_TYPE_ARRAY:
{ {
pkgconf_node_t *iter; pkgconf_node_t *iter;
pkgconf_buffer_push_byte(buffer, '[');
pkgconf_buffer_push_byte(buffer, '\n'); if (value->value.a == NULL ||
!pkgconf_buffer_push_byte(buffer, '[') ||
!pkgconf_buffer_push_byte(buffer, '\n'))
return false;
PKGCONF_FOREACH_LIST_ENTRY(value->value.a->items.head, iter) PKGCONF_FOREACH_LIST_ENTRY(value->value.a->items.head, iter)
{ {
spdxtool_serialize_value_t *entry = iter->data; spdxtool_serialize_value_t *entry = iter->data;
serialize_add_indent(buffer, indent + 1);
spdxtool_serialize_value_to_buf(buffer, entry, indent + 1); if (!serialize_add_indent(buffer, indent + 1) ||
if (iter->next) !spdxtool_serialize_value_to_buf(buffer, entry, indent + 1) ||
pkgconf_buffer_push_byte(buffer, ','); (iter->next && !pkgconf_buffer_push_byte(buffer, ',')) ||
pkgconf_buffer_push_byte(buffer, '\n'); !pkgconf_buffer_push_byte(buffer, '\n'))
return false;
} }
serialize_add_indent(buffer, indent);
pkgconf_buffer_push_byte(buffer, ']'); return serialize_add_indent(buffer, indent) &&
break; pkgconf_buffer_push_byte(buffer, ']');
} }
} }
return true; return false;
} }
/* /*
@@ -375,7 +392,7 @@ spdxtool_serialize_array_free(spdxtool_serialize_array_t *array)
* :return: spdxtool_serialize_value_t * representing the complete JSON-LD document, or a null string value on allocation failure. * :return: spdxtool_serialize_value_t * representing the complete JSON-LD document, or a null string value on allocation failure.
*/ */
spdxtool_serialize_value_t * spdxtool_serialize_value_t *
spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx) spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_tool_t *tool, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx)
{ {
const char *errstr = "out of memory"; const char *errstr = "out of memory";
spdxtool_serialize_value_t *ret = NULL; spdxtool_serialize_value_t *ret = NULL;
@@ -394,6 +411,9 @@ spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent,
if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_agent_to_object(client, agent))) if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_agent_to_object(client, agent)))
goto err; goto err;
if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_tool_to_object(client, tool)))
goto err;
if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_creation_info_to_object(client, creation))) if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_creation_info_to_object(client, creation)))
goto err; goto err;
+1 -1
View File
@@ -536,7 +536,7 @@ spdxtool_serialize_array_add_array(spdxtool_serialize_array_t *array, spdxtool_s
} }
spdxtool_serialize_value_t * spdxtool_serialize_value_t *
spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx); spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_tool_t *tool, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx);
#ifdef __cplusplus #ifdef __cplusplus
} }
+76 -61
View File
@@ -16,6 +16,25 @@
#include "software.h" #include "software.h"
#include "core.h" #include "core.h"
static char *
relationship_spdx_id(pkgconf_client_t *client, const char *from, const char *to, char sep)
{
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
char *spdx_id = NULL;
if (!pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", from, sep, sep, to))
goto out;
if (pkgconf_buffer_len(&relationship_buf) == 0)
goto out;
spdx_id = spdxtool_util_get_spdx_id_string(client, "Relationship", pkgconf_buffer_str(&relationship_buf));
out:
pkgconf_buffer_finalize(&relationship_buf);
return spdx_id;
}
/* /*
* !doc * !doc
* *
@@ -26,7 +45,7 @@
* :param pkgconf_client_t *client: The pkgconf client being accessed. * :param pkgconf_client_t *client: The pkgconf client being accessed.
* :param const char *spdx_id: spdxId for this SBOM element * :param const char *spdx_id: spdxId for this SBOM element
* :param const char *creation_id: id for CreationInfo * :param const char *creation_id: id for CreationInfo
* :param const char *sbom_type: Sbom types can be found SPDX documention * :param const char *sbom_type: Sbom types can be found SPDX documentation
* :return: NULL if some problem occurs and Sbom struct if not * :return: NULL if some problem occurs and Sbom struct if not
*/ */
spdxtool_software_sbom_t * spdxtool_software_sbom_t *
@@ -135,19 +154,12 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo
{ {
pkgconf_dependency_t *dep = node->data; pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match; pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
/* an unresolved (but tolerated) dependency has no match */ /* an unresolved (but tolerated) dependency has no match */
if (match == NULL) if (match == NULL)
continue; continue;
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id); char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)
goto err;
char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
free(relationship_str);
if (!spdx_id_relation) if (!spdx_id_relation)
goto err; goto err;
@@ -170,19 +182,12 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo
{ {
pkgconf_dependency_t *dep = node->data; pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match; pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
/* an unresolved (but tolerated) dependency has no match */ /* an unresolved (but tolerated) dependency has no match */
if (match == NULL) if (match == NULL)
continue; continue;
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id); char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)
goto err;
char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
free(relationship_str);
if (!spdx_id_relation) if (!spdx_id_relation)
goto err; goto err;
@@ -293,7 +298,11 @@ serialize_copyright_lines_to_object(spdxtool_serialize_object_list_t *object_lis
PKGCONF_FOREACH_LIST_ENTRY(copyright_lines->head, node) PKGCONF_FOREACH_LIST_ENTRY(copyright_lines->head, node)
{ {
const pkgconf_bufferset_t *set = node->data; const pkgconf_bufferset_t *set = node->data;
pkgconf_buffer_join(&copyright_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL); if (!pkgconf_buffer_join(&copyright_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL))
{
pkgconf_buffer_finalize(&copyright_buf);
return false;
}
} }
bool ok = spdxtool_serialize_object_add_string(object_list, "software_copyrightText", pkgconf_buffer_str_or_empty(&copyright_buf)) != NULL; bool ok = spdxtool_serialize_object_add_string(object_list, "software_copyrightText", pkgconf_buffer_str_or_empty(&copyright_buf)) != NULL;
@@ -321,7 +330,6 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
spdxtool_serialize_value_t *ret = NULL; spdxtool_serialize_value_t *ret = NULL;
spdxtool_serialize_object_list_t *object_list = NULL; spdxtool_serialize_object_list_t *object_list = NULL;
spdxtool_serialize_array_t *originated_by = NULL; spdxtool_serialize_array_t *originated_by = NULL;
spdxtool_serialize_array_t *supplied_by = NULL;
char *creation_info = NULL; char *creation_info = NULL;
char *spdx_id = NULL; char *spdx_id = NULL;
char *agent = NULL; char *agent = NULL;
@@ -368,20 +376,8 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
goto err; goto err;
supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy"); supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy");
if (supplier) if (supplier && !spdxtool_serialize_object_add_string(object_list, "suppliedBy", supplier))
{ goto err;
supplied_by = spdxtool_serialize_array_new();
if (!supplied_by)
goto err;
if (!spdxtool_serialize_array_add_string(supplied_by, supplier))
goto err;
ok = spdxtool_serialize_object_add_array(object_list, "suppliedBy", supplied_by);
supplied_by = NULL;
if (!ok)
goto err;
}
if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright)) if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright))
goto err; goto err;
@@ -410,7 +406,8 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
if (!spdx_id_license) if (!spdx_id_license)
goto err; goto err;
pkgconf_license_insert(client, &relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_license); if (!pkgconf_license_insert(client, &relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_license))
goto err;
free(spdx_id_license); free(spdx_id_license);
spdx_id_license = NULL; spdx_id_license = NULL;
} }
@@ -426,14 +423,21 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
goto err; goto err;
} }
pkgconf_license_copy_list(client, cpy_relations, &relations); if (!pkgconf_license_copy_list(client, cpy_relations, &relations))
{
free(tuple_license);
goto err;
}
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasDeclaredLicense"); spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasDeclaredLicense");
free(tuple_license); free(tuple_license);
if (!relationship) if (!relationship)
goto err; goto err;
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
goto err;
cpy_relations = NULL; cpy_relations = NULL;
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
{
spdxtool_core_relationship_free(relationship);
goto err;
}
} }
tuple_license = spdxtool_util_tuple_lookup(client, &pkg->vars, "hasConcludedLicense"); tuple_license = spdxtool_util_tuple_lookup(client, &pkg->vars, "hasConcludedLicense");
@@ -446,14 +450,21 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
goto err; goto err;
} }
pkgconf_license_copy_list(client, cpy_relations, &relations); if (!pkgconf_license_copy_list(client, cpy_relations, &relations))
{
free(tuple_license);
goto err;
}
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasConcludedLicense"); spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasConcludedLicense");
free(tuple_license); free(tuple_license);
if (!relationship) if (!relationship)
goto err; goto err;
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
goto err;
cpy_relations = NULL; cpy_relations = NULL;
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
{
spdxtool_core_relationship_free(relationship);
goto err;
}
} }
pkgconf_license_free(&relations); pkgconf_license_free(&relations);
@@ -461,19 +472,12 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
{ {
pkgconf_dependency_t *dep = node->data; pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match; pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
/* an unresolved (but tolerated) dependency has no match */ /* an unresolved (but tolerated) dependency has no match */
if (match == NULL) if (match == NULL)
continue; continue;
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id); char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)
goto err;
char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
free(relationship_str);
if (!spdx_id_relation) if (!spdx_id_relation)
goto err; goto err;
@@ -492,34 +496,35 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
goto err; goto err;
} }
pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package); if (!pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package))
{
free(spdx_id_relation);
free(spdx_id_package);
goto err;
}
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn"); spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn");
free(spdx_id_relation); free(spdx_id_relation);
free(spdx_id_package); free(spdx_id_package);
if (!relationship) if (!relationship)
goto err; goto err;
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
goto err;
cpy_relations = NULL; cpy_relations = NULL;
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
{
spdxtool_core_relationship_free(relationship);
goto err;
}
} }
PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
{ {
pkgconf_dependency_t *dep = node->data; pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *match = dep->match; pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
/* an unresolved (but tolerated) dependency has no match */ /* an unresolved (but tolerated) dependency has no match */
if (match == NULL) if (match == NULL)
continue; continue;
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id); char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)
goto err;
char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str);
free(relationship_str);
if (!spdx_id_relation) if (!spdx_id_relation)
goto err; goto err;
@@ -538,7 +543,12 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
goto err; goto err;
} }
pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package); if (!pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package))
{
free(spdx_id_relation);
free(spdx_id_package);
goto err;
}
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn"); spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn");
free(spdx_id_relation); free(spdx_id_relation);
free(spdx_id_package); free(spdx_id_package);
@@ -569,8 +579,13 @@ err:
free(agent); free(agent);
free(supplier); free(supplier);
free(spdx_id_license); free(spdx_id_license);
pkgconf_license_free(&relations);
if (cpy_relations != NULL)
{
pkgconf_license_free(cpy_relations);
free(cpy_relations);
}
spdxtool_serialize_object_list_free(object_list); spdxtool_serialize_object_list_free(object_list);
spdxtool_serialize_array_free(originated_by); spdxtool_serialize_array_free(originated_by);
spdxtool_serialize_array_free(supplied_by);
return ret; return ret;
} }
+110 -6
View File
@@ -16,12 +16,82 @@
#include <ctype.h> #include <ctype.h>
#include "util.h" #include "util.h"
static bool
util_escape_uri_string(pkgconf_buffer_t *dest, pkgconf_buffer_t *src)
{
const char *p = pkgconf_buffer_str(src);
if (dest == src)
return false;
if (!p)
return true;
for (; *p; p++)
{
bool ret;
switch (*p)
{
case 0x20:
ret = pkgconf_buffer_append(dest, "%20");
break;
case '"':
ret = pkgconf_buffer_append(dest, "%22");
break;
case '%':
ret = pkgconf_buffer_append(dest, "%25");
break;
case '\'':
ret = pkgconf_buffer_append(dest, "%27");
break;
case '+':
ret = pkgconf_buffer_append(dest, "%2B");
break;
case ',':
ret = pkgconf_buffer_append(dest, "%2C");
break;
case '<':
ret = pkgconf_buffer_append(dest, "%3C");
break;
case '>':
ret = pkgconf_buffer_append(dest, "%3E");
break;
case '\\':
ret = pkgconf_buffer_append(dest, "%5C");
break;
case '^':
ret = pkgconf_buffer_append(dest, "%5E");
break;
case '`':
ret = pkgconf_buffer_append(dest, "%60");
break;
case '{':
ret = pkgconf_buffer_append(dest, "%7B");
break;
case '|':
ret = pkgconf_buffer_append(dest, "%7C");
break;
case '}':
ret = pkgconf_buffer_append(dest, "%7D");
break;
default:
ret = pkgconf_buffer_push_byte(dest, *p);
}
if (!ret)
return false;
}
return true;
}
/* /*
* !doc * !doc
* *
* .. c:function:: void spdxtool_util_set_key(pkgconf_client_t *client, const char *key, const char *key_value, const char *key_default) * .. c:function:: void spdxtool_util_set_key(pkgconf_client_t *client, const char *key, const char *key_value, const char *key_default)
* *
* Set key wit default value. Default value is used if key is NULL * Set key with default value. Default value is used if key is NULL
* *
* :param pkgconf_client_t* client: The pkgconf client being accessed. * :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param const char *key: Key to be preserved * :param const char *key: Key to be preserved
@@ -179,11 +249,28 @@ spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, const char *part)
const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client); const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client);
char sep = spdxtool_util_get_uri_separator(client); char sep = spdxtool_util_get_uri_separator(client);
pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_t escaped_uri = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_join(&current_uri, sep, global_xsd_any_uri, part, NULL); if (last_id == SIZE_MAX ||
pkgconf_buffer_append_fmt(&current_uri, "%c" SIZE_FMT_SPECIFIER, sep, ++last_id); !pkgconf_buffer_join(&current_uri, sep, global_xsd_any_uri, part, NULL) ||
!pkgconf_buffer_append_fmt(&current_uri, "%c" SIZE_FMT_SPECIFIER, sep, last_id + 1))
{
pkgconf_buffer_finalize(&current_uri);
return NULL;
}
return pkgconf_buffer_freeze(&current_uri); last_id++;
if (!util_escape_uri_string(&escaped_uri, &current_uri))
{
pkgconf_buffer_finalize(&current_uri);
pkgconf_buffer_finalize(&escaped_uri);
return NULL;
}
pkgconf_buffer_finalize(&current_uri);
return pkgconf_buffer_freeze(&escaped_uri);
} }
/* /*
@@ -205,10 +292,24 @@ spdxtool_util_get_spdx_id_string(pkgconf_client_t *client, const char *part, con
const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client); const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client);
char sep = spdxtool_util_get_uri_separator(client); char sep = spdxtool_util_get_uri_separator(client);
pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_t escaped_uri = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_join(&current_uri, sep, global_xsd_any_uri, part, string_id, NULL); if (!pkgconf_buffer_join(&current_uri, sep, global_xsd_any_uri, part, string_id, NULL))
{
pkgconf_buffer_finalize(&current_uri);
return NULL;
}
return pkgconf_buffer_freeze(&current_uri); if (!util_escape_uri_string(&escaped_uri, &current_uri))
{
pkgconf_buffer_finalize(&current_uri);
pkgconf_buffer_finalize(&escaped_uri);
return NULL;
}
pkgconf_buffer_finalize(&current_uri);
return pkgconf_buffer_freeze(&escaped_uri);
} }
/* /*
@@ -314,7 +415,10 @@ spdxtool_util_tuple_lookup(pkgconf_client_t *client, pkgconf_list_t *vars, const
return NULL; return NULL;
if (!pkgconf_variable_eval(client, vars, v, &buf, NULL)) if (!pkgconf_variable_eval(client, vars, v, &buf, NULL))
{
pkgconf_buffer_finalize(&buf);
return NULL; return NULL;
}
return pkgconf_buffer_freeze(&buf); return pkgconf_buffer_freeze(&buf);
} }
+10 -1
View File
@@ -28,13 +28,22 @@ typedef struct spdxtool_core_agent_
char *name; char *name;
} spdxtool_core_agent_t; } spdxtool_core_agent_t;
typedef struct spdxtool_core_tool_
{
char *spdx_id;
const char *type;
char *creation_info;
char *name;
} spdxtool_core_tool_t;
typedef struct spdxtool_core_creation_info_ typedef struct spdxtool_core_creation_info_
{ {
char *id; char *id;
const char *type; const char *type;
char *created; char *created;
char *created_by; char *created_by;
const char *created_using; char *create_using;
char *created_using;
char *spec_version; char *spec_version;
} spdxtool_core_creation_info_t; } spdxtool_core_creation_info_t;
+4 -2
View File
@@ -12,7 +12,7 @@ dnl implied. In no event shall the authors be liable for any damages arising
dnl from the use of this software. dnl from the use of this software.
AC_PREREQ([2.71]) AC_PREREQ([2.71])
AC_INIT([pkgconf],[2.9.93],[https://github.com/pkgconf/pkgconf/issues/new]) AC_INIT([pkgconf],[3.0.9],[https://github.com/pkgconf/pkgconf/issues/new])
AC_MSG_WARN([ AC_MSG_WARN([
=================================================================== ===================================================================
Autotools support is deprecated and will be removed in pkgconf 3.1. Autotools support is deprecated and will be removed in pkgconf 3.1.
@@ -25,12 +25,14 @@ AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"])
AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"]) AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"])
AX_CHECK_COMPILE_FLAG([-Wformat=2], [CFLAGS="$CFLAGS -Wformat=2"]) AX_CHECK_COMPILE_FLAG([-Wformat=2], [CFLAGS="$CFLAGS -Wformat=2"])
AX_CHECK_COMPILE_FLAG([-std=c99], [CFLAGS="$CFLAGS -std=c99"]) AX_CHECK_COMPILE_FLAG([-std=c99], [CFLAGS="$CFLAGS -std=c99"])
CPPFLAGS="$CPPFLAGS -D_BSD_SOURCE -D_DARWIN_C_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700" CPPFLAGS="$CPPFLAGS -D_ATFILE_SOURCE -D_BSD_SOURCE -D_DARWIN_C_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700"
AC_CONFIG_HEADERS([libpkgconf/config.h]) AC_CONFIG_HEADERS([libpkgconf/config.h])
AC_CHECK_DECLS([strndup], [], [], [[#include <string.h>]]) AC_CHECK_DECLS([strndup], [], [], [[#include <string.h>]])
AC_CHECK_DECLS([pledge, unveil], [], [], [[#include <unistd.h>]]) AC_CHECK_DECLS([pledge, unveil], [], [], [[#include <unistd.h>]])
AC_CHECK_DECLS([readlinkat], [], [], [[#include <unistd.h>]]) AC_CHECK_DECLS([readlinkat], [], [], [[#include <unistd.h>]])
AC_CHECK_DECLS([reallocarray], [], [], [[#include <stdlib.h>]]) AC_CHECK_DECLS([reallocarray], [], [], [[#include <stdlib.h>]])
AC_CHECK_DECLS([mkdtemp], [], [], [[#include <stdlib.h>]])
AC_CHECK_DECLS([getc_unlocked], [], [], [[#include <stdio.h>]])
AC_CHECK_DECLS([nl_langinfo_l], [], [], [[ AC_CHECK_DECLS([nl_langinfo_l], [], [], [[
#ifdef __APPLE__ #ifdef __APPLE__
#include <xlocale.h> #include <xlocale.h>
+22 -11
View File
@@ -25,7 +25,9 @@
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
/* bound the number of injection rounds per input to keep executions cheap */ /* Bound the allocation site selected for fault injection. Exhaustively
* replaying every allocation for every libFuzzer input makes this relatively
* expensive solve-and-serialize target prohibitively slow. */
#define ALLOC_FAIL_MAX 4096 #define ALLOC_FAIL_MAX 4096
/* the fuzzer input is split on NUL bytes into up to this many .pc files, named /* the fuzzer input is split on NUL bytes into up to this many .pc files, named
@@ -37,6 +39,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
static const char universe_names[UNIVERSE_MAX] = { 'a', 'b', 'c', 'd' }; static const char universe_names[UNIVERSE_MAX] = { 'a', 'b', 'c', 'd' };
static unsigned long
allocation_failure_for_input(const uint8_t *data, size_t size)
{
uint32_t hash = UINT32_C(2166136261);
for (size_t i = 0; i < size; i++)
{
hash ^= data[i];
hash *= UINT32_C(16777619);
}
return (unsigned long)(hash % ALLOC_FAIL_MAX) + 1;
}
static const char * static const char *
environ_lookup_handler(const pkgconf_client_t *client, const char *key) environ_lookup_handler(const pkgconf_client_t *client, const char *key)
{ {
@@ -181,16 +197,11 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
/* baseline run with all allocations succeeding */ /* baseline run with all allocations succeeding */
run_spdx(pers, dir, out); run_spdx(pers, dir, out);
/* then fail each allocation site reachable by this input, one at a time */ /* Exercise one deterministic allocation failure per input. Mutations vary
for (unsigned long i = 1; i <= ALLOC_FAIL_MAX; i++) * the selected site, while keeping the per-input cost constant. */
{ alloc_inject_arm(allocation_failure_for_input(data, size));
alloc_inject_arm(i); run_spdx(pers, dir, out);
run_spdx(pers, dir, out); alloc_inject_disarm();
alloc_inject_disarm();
if (!alloc_inject_fired())
break;
}
pkgconf_cross_personality_deinit(pers); pkgconf_cross_personality_deinit(pers);
fclose(out); fclose(out);
+1
View File
@@ -8,6 +8,7 @@ datadir=@datadir@
Name: libpkgconf Name: libpkgconf
Description: a library for accessing and manipulating development framework configuration Description: a library for accessing and manipulating development framework configuration
URL: https://github.com/pkgconf/pkgconf URL: https://github.com/pkgconf/pkgconf
Maintainer: Ariadne Conill <[email protected]>
License: ISC License: ISC
License.file: ${datadir}/doc/pkgconf/COPYING License.file: ${datadir}/doc/pkgconf/COPYING
Source: https://github.com/pkgconf/pkgconf Source: https://github.com/pkgconf/pkgconf
+69 -13
View File
@@ -49,20 +49,15 @@ pkgconf_argv_free(char **argv)
} }
/* /*
* !doc * Walk `src`, breaking it at whitespace which is neither quoted nor escaped.
* *
* .. c:function:: int pkgconf_argv_split(const char *src, int *argc, char ***argv) * When `raw` is set, the quoting and escaping is only read to find those breaks:
* * the quotes and backslashes are copied into the argument along with everything
* Splits a string into an argument vector. * else, leaving it spelled exactly as it was written. Otherwise they are
* * consumed, as a shell would consume them.
* :param char* src: The string to split.
* :param int* argc: A pointer to an integer to store the argument count.
* :param char*** argv: A pointer to a pointer for an argument vector.
* :return: 0 on success, -1 on error.
* :rtype: int
*/ */
int static int
pkgconf_argv_split(const char *src, int *argc, char ***argv) argv_split(const char *src, int *argc, char ***argv, bool raw)
{ {
char *buf = calloc(1, strlen(src) + 1); char *buf = calloc(1, strlen(src) + 1);
if (buf == NULL) if (buf == NULL)
@@ -92,7 +87,7 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
if (escaped) if (escaped)
{ {
/* POSIX: only \CHAR is special inside a double quote if CHAR is {$, `, ", \, newline}. */ /* POSIX: only \CHAR is special inside a double quote if CHAR is {$, `, ", \, newline}. */
if (quote == '"') if (quote == '"' && !raw)
{ {
if (!(*src_iter == '$' || *src_iter == '`' || *src_iter == '"' || *src_iter == '\\')) if (!(*src_iter == '$' || *src_iter == '`' || *src_iter == '"' || *src_iter == '\\'))
*dst_iter++ = '\\'; *dst_iter++ = '\\';
@@ -109,9 +104,19 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
else if (quote) else if (quote)
{ {
if (*src_iter == quote) if (*src_iter == quote)
{
quote = 0; quote = 0;
if (raw)
*dst_iter++ = *src_iter;
}
else if (*src_iter == '\\' && quote != '\'') else if (*src_iter == '\\' && quote != '\'')
{
escaped = true; escaped = true;
if (raw)
*dst_iter++ = *src_iter;
}
else else
*dst_iter++ = *src_iter; *dst_iter++ = *src_iter;
} }
@@ -145,11 +150,17 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
{ {
case '\\': case '\\':
escaped = true; escaped = true;
if (raw)
*dst_iter++ = *src_iter;
break; break;
case '\"': case '\"':
case '\'': case '\'':
quote = *src_iter; quote = *src_iter;
if (raw)
*dst_iter++ = *src_iter;
break; break;
default: default:
@@ -176,3 +187,48 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
*argc = argc_count; *argc = argc_count;
return 0; return 0;
} }
/*
* !doc
*
* .. c:function:: int pkgconf_argv_split(const char *src, int *argc, char ***argv)
*
* Splits a string into an argument vector, consuming shell quoting and
* backslash escapes the way a shell would.
*
* :param char* src: The string to split.
* :param int* argc: A pointer to an integer to store the argument count.
* :param char*** argv: A pointer to a pointer for an argument vector.
* :return: 0 on success, -1 on error.
* :rtype: int
*/
int
pkgconf_argv_split(const char *src, int *argc, char ***argv)
{
return argv_split(src, argc, argv, false);
}
/*
* !doc
*
* .. c:function:: int pkgconf_argv_split_raw(const char *src, int *argc, char ***argv)
*
* Splits a string into an argument vector without interpreting it: the
* quoting and escaping says where the arguments end, but is left in the text.
*
* This is for input which still has to be expanded. Consuming the quoting
* here would consume only what the input itself spells, leaving whatever a
* variable substitutes into it unconsumed, so it is left for a second pass
* over the finished text.
*
* :param char* src: The string to split.
* :param int* argc: A pointer to an integer to store the argument count.
* :param char*** argv: A pointer to a pointer for an argument vector.
* :return: 0 on success, -1 on error.
* :rtype: int
*/
int
pkgconf_argv_split_raw(const char *src, int *argc, char ***argv)
{
return argv_split(src, argc, argv, true);
}
+1 -1
View File
@@ -21,7 +21,7 @@
#else #else
/* /*
* Creates a memory buffer and copies at most 'len' characters to it. * Creates a memory buffer and copies at most 'len' characters to it.
* If 'len' is less than the length of the source string, truncation occured. * If 'len' is less than the length of the source string, truncation occurred.
*/ */
static inline char * static inline char *
pkgconf_strndup_impl(const char *src, size_t len) pkgconf_strndup_impl(const char *src, size_t len)
+232 -48
View File
@@ -28,10 +28,69 @@
* dynamically-allocated buffers. * dynamically-allocated buffers.
*/ */
static inline size_t /* buffers below BUFFER_LINEAR_GROWTH_MAX increment by 128 bytes each time */
target_allocation_size(size_t target_size) #define BUFFER_LINEAR_GROWTH_MAX 4096
static inline bool
target_allocation_size(size_t target_size, size_t *allocation_size)
{ {
return 128 + (128 * (target_size / 128)); if (target_size < BUFFER_LINEAR_GROWTH_MAX)
{
*allocation_size = target_size + (128 - (target_size % 128));
return true;
}
size_t cap = BUFFER_LINEAR_GROWTH_MAX;
while (cap <= target_size)
{
if (cap > SIZE_MAX / 2)
return false;
cap *= 2;
}
*allocation_size = cap;
return true;
}
static inline bool
buffer_reserve(pkgconf_buffer_t *buffer, size_t content_len)
{
size_t new_cap, old_cap;
char *newbase;
if (!target_allocation_size(content_len, &new_cap))
return false;
if (buffer->base != NULL && target_allocation_size(pkgconf_buffer_len(buffer), &old_cap) && old_cap == new_cap)
return true;
newbase = realloc(buffer->base, new_cap);
if (newbase == NULL)
return false;
buffer->base = newbase;
return true;
}
static bool
buffer_storage_overlaps(const pkgconf_buffer_t *buffer, const void *source, size_t source_size)
{
if (buffer->base == NULL || source == NULL || source_size == 0)
return false;
size_t buffer_size = pkgconf_buffer_len(buffer) + 1;
uintptr_t buffer_start = (uintptr_t) buffer->base;
uintptr_t source_start = (uintptr_t) source;
if (buffer_start > UINTPTR_MAX - (buffer_size - 1) ||
source_start > UINTPTR_MAX - (source_size - 1))
return true;
uintptr_t buffer_end = buffer_start + buffer_size - 1;
uintptr_t source_end = source_start + source_size - 1;
return buffer_start <= source_end && source_start <= buffer_end;
} }
#if 0 #if 0
@@ -53,6 +112,7 @@ buffer_debug(pkgconf_buffer_t *buffer)
* .. c:function:: bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text) * .. c:function:: bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
* *
* Append a null-terminated string to the buffer, reallocating as necessary. * Append a null-terminated string to the buffer, reallocating as necessary.
* The storage occupied by *text* must not overlap the buffer.
* *
* :param pkgconf_buffer_t *buffer: The buffer to append to. * :param pkgconf_buffer_t *buffer: The buffer to append to.
* :param char *text: The null-terminated string to append. * :param char *text: The null-terminated string to append.
@@ -61,20 +121,27 @@ buffer_debug(pkgconf_buffer_t *buffer)
bool bool
pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text) pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
{ {
size_t needed = strlen(text) + 1; size_t len = pkgconf_buffer_len(buffer);
size_t newsize = pkgconf_buffer_len(buffer) + needed; size_t text_len = strlen(text);
char *newbase = realloc(buffer->base, target_allocation_size(newsize)); if (text_len == SIZE_MAX)
if (newbase == NULL)
return false; return false;
char *newend = newbase + pkgconf_buffer_len(buffer); if (buffer_storage_overlaps(buffer, text, text_len + 1))
memcpy(newend, text, needed); return false;
buffer->base = newbase; if (len > SIZE_MAX - text_len)
buffer->end = newend + (needed - 1); return false;
size_t new_len = len + text_len;
if (!buffer_reserve(buffer, new_len))
return false;
memcpy(buffer->base + len, text, text_len);
buffer->end = buffer->base + new_len;
*buffer->end = '\0'; *buffer->end = '\0';
return true; return true;
} }
@@ -84,6 +151,7 @@ pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
* .. c:function:: bool pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n) * .. c:function:: bool pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n)
* *
* Append a slice of *n* bytes to the buffer. Does nothing if *n* is zero. * Append a slice of *n* bytes to the buffer. Does nothing if *n* is zero.
* The source slice must not overlap the buffer.
* *
* :param pkgconf_buffer_t *buf: The buffer to append to. * :param pkgconf_buffer_t *buf: The buffer to append to.
* :param char *p: Pointer to the byte sequence to append. * :param char *p: Pointer to the byte sequence to append.
@@ -93,14 +161,25 @@ pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
bool bool
pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n) pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n)
{ {
size_t len = pkgconf_buffer_len(buf);
if (n == 0) if (n == 0)
return true; return true;
for (size_t i = 0; i < n; i++) if (buffer_storage_overlaps(buf, p, n))
{ return false;
if (!pkgconf_buffer_push_byte(buf, p[i]))
return false; if (len > SIZE_MAX - n)
} return false;
size_t new_len = len + n;
if (!buffer_reserve(buf, new_len))
return false;
memcpy(buf->base + len, p, n);
buf->end = buf->base + new_len;
*buf->end = '\0';
return true; return true;
} }
@@ -120,27 +199,32 @@ pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n)
bool bool
pkgconf_buffer_append_vfmt(pkgconf_buffer_t *buffer, const char *fmt, va_list src_va) pkgconf_buffer_append_vfmt(pkgconf_buffer_t *buffer, const char *fmt, va_list src_va)
{ {
char stackbuf[256];
va_list va; va_list va;
char *buf; int formatted_len;
size_t needed;
va_copy(va, src_va); va_copy(va, src_va);
needed = vsnprintf(NULL, 0, fmt, va) + 1; formatted_len = vsnprintf(stackbuf, sizeof stackbuf, fmt, va);
va_end(va); va_end(va);
buf = malloc(needed); if (formatted_len < 0)
if (buf == NULL) return false;
if ((size_t) formatted_len < sizeof stackbuf)
return pkgconf_buffer_append_slice(buffer, stackbuf, (size_t) formatted_len);
size_t len = pkgconf_buffer_len(buffer);
if (!buffer_reserve(buffer, len + (size_t) formatted_len))
return false; return false;
va_copy(va, src_va); va_copy(va, src_va);
vsnprintf(buf, needed, fmt, va); vsnprintf(buffer->base + len, (size_t) formatted_len + 1, fmt, va);
va_end(va); va_end(va);
bool ret = pkgconf_buffer_append(buffer, buf); buffer->end = buffer->base + len + (size_t) formatted_len;
free(buf); return true;
return ret;
} }
/* /*
@@ -173,6 +257,7 @@ pkgconf_buffer_append_fmt(pkgconf_buffer_t *buffer, const char *fmt, ...)
* *
* Prepend a null-terminated string to the beginning of the buffer. * Prepend a null-terminated string to the beginning of the buffer.
* If *text* is NULL, the buffer contents are unchanged. * If *text* is NULL, the buffer contents are unchanged.
* The storage occupied by *text* must not overlap the buffer.
* *
* :param pkgconf_buffer_t *buffer: The buffer to prepend to. * :param pkgconf_buffer_t *buffer: The buffer to prepend to.
* :param char *text: The null-terminated string to prepend, or NULL. * :param char *text: The null-terminated string to prepend, or NULL.
@@ -182,6 +267,16 @@ bool
pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text) pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text)
{ {
pkgconf_buffer_t tmpbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t tmpbuf = PKGCONF_BUFFER_INITIALIZER;
bool ret = true;
if (text != NULL)
{
size_t text_len = strlen(text);
if (text_len == SIZE_MAX ||
buffer_storage_overlaps(buffer, text, text_len + 1))
return false;
}
if (text != NULL && !pkgconf_buffer_append(&tmpbuf, text)) if (text != NULL && !pkgconf_buffer_append(&tmpbuf, text))
return false; return false;
@@ -193,11 +288,11 @@ pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text)
} }
if (pkgconf_buffer_len(&tmpbuf)) if (pkgconf_buffer_len(&tmpbuf))
pkgconf_buffer_copy(&tmpbuf, buffer); ret = pkgconf_buffer_copy(&tmpbuf, buffer);
pkgconf_buffer_finalize(&tmpbuf); pkgconf_buffer_finalize(&tmpbuf);
return true; return ret;
} }
/* /*
@@ -214,17 +309,19 @@ pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text)
bool bool
pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte) pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte)
{ {
size_t newsize = pkgconf_buffer_len(buffer) + 1; size_t len = pkgconf_buffer_len(buffer);
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
if (newbase == NULL) if (len == SIZE_MAX)
return false; return false;
char *newend = newbase + newsize; size_t new_len = len + 1;
*(newend - 1) = byte; if (!buffer_reserve(buffer, new_len))
*newend = '\0'; return false;
buffer->base = newbase; buffer->base[len] = byte;
buffer->end = newend;
buffer->end = buffer->base + new_len;
*buffer->end = '\0';
return true; return true;
} }
@@ -246,14 +343,11 @@ pkgconf_buffer_trim_byte(pkgconf_buffer_t *buffer)
if (len == 0) if (len == 0)
return false; return false;
size_t newsize = len - 1; size_t new_len = len - 1;
char *newbase = realloc(buffer->base, target_allocation_size(newsize)); if (!buffer_reserve(buffer, new_len))
if (newbase == NULL)
return false; return false;
buffer->base = newbase; buffer->end = buffer->base + new_len;
buffer->end = newbase + newsize;
*(buffer->end) = '\0'; *(buffer->end) = '\0';
return true; return true;
@@ -461,6 +555,7 @@ pkgconf_buffer_match(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *n
* *
* Copy *src* into *dest*, replacing all occurrences of *pattern* with *value*. * Copy *src* into *dest*, replacing all occurrences of *pattern* with *value*.
* If *pattern* is empty, *src* is appended to *dest* unmodified. * If *pattern* is empty, *src* is appended to *dest* unmodified.
* Neither *src*, *pattern* nor *value* may overlap *dest*.
* *
* :param pkgconf_buffer_t *dest: The destination buffer. * :param pkgconf_buffer_t *dest: The destination buffer.
* :param pkgconf_buffer_t *src: The source buffer. * :param pkgconf_buffer_t *src: The source buffer.
@@ -473,6 +568,10 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const
{ {
const char *iter = src->base; const char *iter = src->base;
if (dest == src ||
buffer_storage_overlaps(dest, src->base, pkgconf_buffer_len(src) + 1))
return false;
if (pattern == NULL) if (pattern == NULL)
pattern = ""; pattern = "";
@@ -480,6 +579,9 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const
value = ""; value = "";
size_t pattern_len = strlen(pattern); size_t pattern_len = strlen(pattern);
if (buffer_storage_overlaps(dest, pattern, pattern_len + 1) ||
buffer_storage_overlaps(dest, value, strlen(value) + 1))
return false;
if (!pkgconf_buffer_len(src)) if (!pkgconf_buffer_len(src))
return true; return true;
@@ -513,6 +615,7 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const
* *
* Copy *src* into *dest*, inserting a backslash before any byte that falls * Copy *src* into *dest*, inserting a backslash before any byte that falls
* within the provided character spans. * within the provided character spans.
* The source and destination buffers must not overlap.
* *
* :param pkgconf_buffer_t *dest: The destination buffer. * :param pkgconf_buffer_t *dest: The destination buffer.
* :param pkgconf_buffer_t *src: The source buffer. * :param pkgconf_buffer_t *src: The source buffer.
@@ -522,23 +625,104 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const
*/ */
bool bool
pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans) pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans)
{
pkgconf_charset_t charset;
pkgconf_charset_from_spans(&charset, spans, nspans);
return pkgconf_buffer_escape_charset(dest, src, &charset);
}
/*
* !doc
*
* .. c:function:: void pkgconf_charset_from_spans(pkgconf_charset_t *charset, const pkgconf_span_t *spans, size_t nspans)
*
* Build a byte-set from a list of character spans, so that membership tests over it are a
* single lookup. Callers which test many bytes against the same spans should build the set
* once and pass it to :c:func:`pkgconf_buffer_escape_charset`.
*
* :param pkgconf_charset_t *charset: The byte-set to populate.
* :param pkgconf_span_t *spans: Array of character spans to include.
* :param size_t nspans: Number of entries in the *spans* array.
* :return: nothing
*/
void
pkgconf_charset_from_spans(pkgconf_charset_t *charset, const pkgconf_span_t *spans, size_t nspans)
{
memset(charset, 0, sizeof(*charset));
for (size_t i = 0; i < nspans; i++)
{
unsigned int lo = spans[i].lo, hi = spans[i].hi;
if (lo > hi)
continue;
size_t wlo = lo >> 6, whi = hi >> 6;
/* bits at or above lo, and bits at or below hi, within their words */
uint64_t mlo = ~UINT64_C(0) << (lo & 63);
uint64_t mhi = (hi & 63) == 63 ? ~UINT64_C(0) : (UINT64_C(1) << ((hi & 63) + 1)) - 1;
if (wlo == whi)
{
charset->words[wlo] |= mlo & mhi;
continue;
}
charset->words[wlo] |= mlo;
for (size_t w = wlo + 1; w < whi; w++)
charset->words[w] = ~UINT64_C(0);
charset->words[whi] |= mhi;
}
}
/*
* !doc
*
* .. c:function:: bool pkgconf_buffer_escape_charset(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_charset_t *charset)
*
* Copy *src* into *dest*, inserting a backslash before any byte which is a member of
* *charset*. Like :c:func:`pkgconf_buffer_escape`, but takes a prebuilt byte-set.
* The source and destination buffers must not overlap.
*
* :param pkgconf_buffer_t *dest: The destination buffer.
* :param pkgconf_buffer_t *src: The source buffer.
* :param pkgconf_charset_t *charset: The set of bytes to escape.
* :return: :code:`true` on success, :code:`false` on allocation failure.
*/
bool
pkgconf_buffer_escape_charset(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_charset_t *charset)
{ {
const char *p = pkgconf_buffer_str(src); const char *p = pkgconf_buffer_str(src);
const char *run = p;
if (dest == src ||
buffer_storage_overlaps(dest, src->base, pkgconf_buffer_len(src) + 1))
return false;
if (!pkgconf_buffer_len(src)) if (!pkgconf_buffer_len(src))
return true; return true;
for (; *p; p++) for (; *p; p++)
{ {
if (pkgconf_span_contains((unsigned char) *p, spans, nspans)) if (!pkgconf_charset_contains(charset, (unsigned char) *p))
{ continue;
if (!pkgconf_buffer_push_byte(dest, '\\'))
return false;
}
if (!pkgconf_buffer_push_byte(dest, *p)) if (p > run && !pkgconf_buffer_append_slice(dest, run, (size_t) (p - run)))
return false; return false;
if (!pkgconf_buffer_push_byte(dest, '\\'))
return false;
run = p;
} }
if (p > run)
return pkgconf_buffer_append_slice(dest, run, (size_t) (p - run));
return true; return true;
} }
+48 -30
View File
@@ -64,6 +64,21 @@ pkgconf_bytecode_eval_append(pkgconf_bytecode_eval_ctx_t *ctx, pkgconf_buffer_t
static bool static bool
pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_bytecode_t *bc, pkgconf_buffer_t *out, bool *saw_sysroot); pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_bytecode_t *bc, pkgconf_buffer_t *out, bool *saw_sysroot);
static bool
pkgconf_bytecode_read_op(const uint8_t *p, size_t remaining,
const pkgconf_bytecode_op_t **op, size_t *op_size)
{
if (p == NULL || remaining < sizeof(**op))
return false;
*op = (const pkgconf_bytecode_op_t *) p;
if ((size_t) (*op)->size > remaining - sizeof(**op))
return false;
*op_size = sizeof(**op) + (size_t) (*op)->size;
return true;
}
static pkgconf_variable_t * static pkgconf_variable_t *
pkgconf_bytecode_eval_scan(const pkgconf_list_t *vars, const char *name, size_t nlen, unsigned int require_flags, unsigned int forbid_flags) pkgconf_bytecode_eval_scan(const pkgconf_list_t *vars, const char *name, size_t nlen, unsigned int require_flags, unsigned int forbid_flags)
{ {
@@ -139,8 +154,11 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b
if (bc == NULL || out == NULL) if (bc == NULL || out == NULL)
return false; return false;
if (bc->len != 0 && bc->base == NULL)
return false;
const uint8_t *p = bc->base; const uint8_t *p = bc->base;
const uint8_t *end = bc->base + bc->len; size_t remaining = bc->len;
if (++ctx->expansions > PKGCONF_EVAL_MAX_ITERATIONS) if (++ctx->expansions > PKGCONF_EVAL_MAX_ITERATIONS)
{ {
@@ -150,15 +168,12 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b
return false; return false;
} }
while (p < end) while (remaining != 0)
{ {
const pkgconf_bytecode_op_t *op = const pkgconf_bytecode_op_t *op;
(const pkgconf_bytecode_op_t *)p; size_t op_size;
if ((const uint8_t *)op + sizeof(*op) > end) if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size))
return false;
if ((const uint8_t *)op + sizeof(*op) + op->size > end)
return false; return false;
switch (op->tag) switch (op->tag)
@@ -186,7 +201,8 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b
return false; return false;
} }
p = (const uint8_t *)pkgconf_bytecode_op_next(op); p += op_size;
remaining -= op_size;
} }
return true; return true;
@@ -301,7 +317,7 @@ void
pkgconf_bytecode_from_buffer(pkgconf_bytecode_t *bc, const pkgconf_buffer_t *buf) pkgconf_bytecode_from_buffer(pkgconf_bytecode_t *bc, const pkgconf_buffer_t *buf)
{ {
bc->base = (const uint8_t *)buf->base; bc->base = (const uint8_t *)buf->base;
bc->len = (size_t)(buf->end - buf->base); bc->len = buf->base != NULL ? (size_t)(buf->end - buf->base) : 0;
} }
bool bool
@@ -446,24 +462,23 @@ pkgconf_bytecode_eval_str(const pkgconf_client_t *client, const pkgconf_list_t *
bool bool
pkgconf_bytecode_references_var(const pkgconf_buffer_t *buf, const char *key) pkgconf_bytecode_references_var(const pkgconf_buffer_t *buf, const char *key)
{ {
const uint8_t *p, *end; const uint8_t *p;
size_t remaining;
size_t klen; size_t klen;
if (buf == NULL || key == NULL) if (buf == NULL || key == NULL)
return false; return false;
klen = strlen(key); klen = strlen(key);
p = (uint8_t *) buf->base; p = (const uint8_t *) buf->base;
end = (uint8_t *) buf->end; remaining = pkgconf_buffer_len(buf);
while (p < end) while (remaining != 0)
{ {
const pkgconf_bytecode_op_t *op = (const pkgconf_bytecode_op_t *)p; const pkgconf_bytecode_op_t *op;
size_t op_size;
if (p + sizeof(*op) > end) if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size))
return false;
if (p + sizeof(*op) + op->size > end)
return false; return false;
if (op->tag == PKGCONF_BYTECODE_OP_VAR) if (op->tag == PKGCONF_BYTECODE_OP_VAR)
@@ -472,7 +487,8 @@ pkgconf_bytecode_references_var(const pkgconf_buffer_t *buf, const char *key)
return true; return true;
} }
p += sizeof(*op) + op->size; p += op_size;
remaining -= op_size;
} }
return false; return false;
@@ -504,17 +520,18 @@ pkgconf_bytecode_append_stream(pkgconf_buffer_t *dst, const pkgconf_buffer_t *bc
bool bool
pkgconf_bytecode_rewrite_selfrefs(pkgconf_buffer_t *out, const pkgconf_buffer_t *rhs, const char *key, const pkgconf_buffer_t *prev) pkgconf_bytecode_rewrite_selfrefs(pkgconf_buffer_t *out, const pkgconf_buffer_t *rhs, const char *key, const pkgconf_buffer_t *prev)
{ {
const uint8_t *p = (uint8_t *) rhs->base; if (out == NULL || rhs == NULL || key == NULL || prev == NULL)
const uint8_t *end = (uint8_t *) rhs->end; return false;
while (p < end) const uint8_t *p = (const uint8_t *) rhs->base;
size_t remaining = pkgconf_buffer_len(rhs);
while (remaining != 0)
{ {
const pkgconf_bytecode_op_t *op = (const pkgconf_bytecode_op_t *)p; const pkgconf_bytecode_op_t *op;
size_t op_size;
if (p + sizeof(*op) > end) if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size))
return false;
if (p + sizeof(*op) + op->size > end)
return false; return false;
if (pkgconf_bytecode_op_is_selfref(op, key)) if (pkgconf_bytecode_op_is_selfref(op, key))
@@ -524,11 +541,12 @@ pkgconf_bytecode_rewrite_selfrefs(pkgconf_buffer_t *out, const pkgconf_buffer_t
} }
else else
{ {
if (!pkgconf_buffer_append_slice(out, (const char *) op, sizeof(*op) + op->size)) if (!pkgconf_buffer_append_slice(out, (const char *) op, op_size))
return false; return false;
} }
p += sizeof(*op) + op->size; p += op_size;
remaining -= op_size;
} }
return true; return true;
+24 -45
View File
@@ -42,37 +42,6 @@ cache_member_cmp(const void *a, const void *b)
return strcmp(key, pkg->id); return strcmp(key, pkg->id);
} }
static int
cache_member_sort_cmp(const void *a, const void *b)
{
const pkgconf_pkg_t *pkgA = *(void **) a;
const pkgconf_pkg_t *pkgB = *(void **) b;
if (pkgA == NULL)
return 1;
if (pkgB == NULL)
return -1;
return strcmp(pkgA->id, pkgB->id);
}
static void
cache_dump(const pkgconf_client_t *client)
{
size_t i;
PKGCONF_TRACE(client, "dumping package cache contents");
for (i = 0; i < client->cache_count; i++)
{
const pkgconf_pkg_t *pkg = client->cache_table[i];
PKGCONF_TRACE(client, SIZE_FMT_SPECIFIER": %p(%s)",
i, pkg, pkg == NULL ? "NULL" : pkg->id);
}
}
/* /*
* !doc * !doc
* *
@@ -127,6 +96,13 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
if (pkg == NULL) if (pkg == NULL)
return; return;
pkgconf_pkg_t *cached_pkg = pkgconf_cache_lookup(client, pkg->id);
if (cached_pkg != NULL)
{
pkgconf_pkg_unref(client, cached_pkg);
return;
}
pkgconf_pkg_ref(client, pkg); pkgconf_pkg_ref(client, pkg);
pkgconf_pkg_t **new_table; pkgconf_pkg_t **new_table;
@@ -148,10 +124,21 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
} }
client->cache_table = new_table; client->cache_table = new_table;
client->cache_table[client->cache_count - 1] = pkg;
qsort(client->cache_table, client->cache_count, size_t lo = 0, hi = client->cache_count - 1;
sizeof(void *), cache_member_sort_cmp); while (lo < hi)
{
size_t mid = lo + (hi - lo) / 2;
if (strcmp(client->cache_table[mid]->id, pkg->id) < 0)
lo = mid + 1;
else
hi = mid;
}
memmove(&client->cache_table[lo + 1], &client->cache_table[lo],
(client->cache_count - 1 - lo) * sizeof(void *));
client->cache_table[lo] = pkg;
PKGCONF_TRACE(client, "added @%p to cache", pkg); PKGCONF_TRACE(client, "added @%p to cache", pkg);
} }
@@ -192,18 +179,10 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
(*slot)->flags &= ~PKGCONF_PKG_PROPF_CACHED; (*slot)->flags &= ~PKGCONF_PKG_PROPF_CACHED;
pkgconf_pkg_unref(client, *slot); pkgconf_pkg_unref(client, *slot);
*slot = NULL;
qsort(client->cache_table, client->cache_count, size_t idx = (size_t)(slot - client->cache_table);
sizeof(void *), cache_member_sort_cmp); memmove(&client->cache_table[idx], &client->cache_table[idx + 1],
(client->cache_count - idx - 1) * sizeof(void *));
if (client->cache_table[client->cache_count - 1] != NULL)
{
PKGCONF_TRACE(client, "end of cache table refers to %p, not NULL",
client->cache_table[client->cache_count - 1]);
cache_dump(client);
abort();
}
client->cache_count--; client->cache_count--;
if (client->cache_count > 0) if (client->cache_count > 0)
+76 -15
View File
@@ -108,11 +108,38 @@ pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_pers
void void
pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler) pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler)
{ {
pkgconf_client_options_t options = {
.error_handler = error_handler,
.error_handler_data = error_handler_data,
.personality = personality,
.client_data = client_data,
.environ_lookup_handler = environ_lookup_handler,
};
pkgconf_client_init_with_options(client, &options);
}
/*
* !doc
*
* .. c:function:: void pkgconf_client_init_with_options(pkgconf_client_t *client, const pkgconf_client_options_t *options)
*
* Initialise a pkgconf client object using an options structure.
*
* :param pkgconf_client_t* client: The client to initialise.
* :param pkgconf_client_options_t* options: The options used to configure the client.
* :return: nothing
*/
void
pkgconf_client_init_with_options(pkgconf_client_t *client, const pkgconf_client_options_t *options)
{
const pkgconf_cross_personality_t *personality = options->personality;
client->personality = personality; client->personality = personality;
client->client_data = client_data; client->client_data = options->client_data;
client->environ_lookup_handler = environ_lookup_handler; client->environ_lookup_handler = options->environ_lookup_handler;
client->error_handler_data = error_handler_data; client->error_handler_data = options->error_handler_data;
client->error_handler = error_handler; client->error_handler = options->error_handler;
client->auditf = NULL; client->auditf = NULL;
client->cache_table = NULL; client->cache_table = NULL;
client->cache_count = 0; client->cache_count = 0;
@@ -122,10 +149,12 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error
pkgconf_client_set_trace_handler(client, NULL, NULL); pkgconf_client_set_trace_handler(client, NULL, NULL);
#endif #endif
if (client->unveil_handler == NULL) if (options->unveil_handler != NULL)
pkgconf_client_set_unveil_handler(client, options->unveil_handler);
else if (client->unveil_handler == NULL)
pkgconf_client_set_unveil_handler(client, NULL); pkgconf_client_set_unveil_handler(client, NULL);
pkgconf_client_set_error_handler(client, error_handler, error_handler_data); pkgconf_client_set_error_handler(client, options->error_handler, options->error_handler_data);
pkgconf_client_set_warn_handler(client, NULL, NULL); pkgconf_client_set_warn_handler(client, NULL, NULL);
pkgconf_client_set_sysroot_dir(client, personality->sysroot_dir); pkgconf_client_set_sysroot_dir(client, personality->sysroot_dir);
@@ -183,12 +212,37 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error
*/ */
pkgconf_client_t * pkgconf_client_t *
pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler) pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler)
{
pkgconf_client_options_t options = {
.error_handler = error_handler,
.error_handler_data = error_handler_data,
.personality = personality,
.client_data = client_data,
.environ_lookup_handler = environ_lookup_handler,
};
return pkgconf_client_new_with_options(&options);
}
/*
* !doc
*
* .. c:function:: pkgconf_client_t* pkgconf_client_new_with_options(const pkgconf_client_options_t *options)
*
* Allocate and initialise a pkgconf client object using an options structure.
*
* :param pkgconf_client_options_t* options: The options used to configure the client.
* :return: A pkgconf client object.
* :rtype: pkgconf_client_t*
*/
pkgconf_client_t *
pkgconf_client_new_with_options(const pkgconf_client_options_t *options)
{ {
pkgconf_client_t *out = calloc(1, sizeof(pkgconf_client_t)); pkgconf_client_t *out = calloc(1, sizeof(pkgconf_client_t));
if (out == NULL) if (out == NULL)
return NULL; return NULL;
pkgconf_client_init(out, error_handler, error_handler_data, personality, client_data, environ_lookup_handler); pkgconf_client_init_with_options(out, options);
return out; return out;
} }
@@ -304,6 +358,11 @@ pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir
client->sysroot_dir = sysroot_dir != NULL ? strdup(sysroot_dir) : NULL; client->sysroot_dir = sysroot_dir != NULL ? strdup(sysroot_dir) : NULL;
/* normalize separators so the sysroot compares equal to the (already
* canonicalized) paths it is matched against during injection */
if (client->sysroot_dir != NULL)
pkgconf_path_normalize_separators(client->sysroot_dir);
PKGCONF_TRACE(client, "set sysroot_dir to: %s", client->sysroot_dir != NULL ? client->sysroot_dir : "<default>"); PKGCONF_TRACE(client, "set sysroot_dir to: %s", client->sysroot_dir != NULL ? client->sysroot_dir : "<default>");
pkgconf_tuple_add_global(client, "pc_sysrootdir", client->sysroot_dir != NULL ? client->sysroot_dir : ""); pkgconf_tuple_add_global(client, "pc_sysrootdir", client->sysroot_dir != NULL ? client->sysroot_dir : "");
@@ -348,6 +407,9 @@ pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot
client->buildroot_dir = buildroot_dir != NULL ? strdup(buildroot_dir) : NULL; client->buildroot_dir = buildroot_dir != NULL ? strdup(buildroot_dir) : NULL;
if (client->buildroot_dir != NULL)
pkgconf_path_normalize_separators(client->buildroot_dir);
PKGCONF_TRACE(client, "set buildroot_dir to: %s", client->buildroot_dir != NULL ? client->buildroot_dir : "<default>"); PKGCONF_TRACE(client, "set buildroot_dir to: %s", client->buildroot_dir != NULL ? client->buildroot_dir : "<default>");
pkgconf_tuple_add_global(client, "pc_top_builddir", client->buildroot_dir != NULL ? client->buildroot_dir : "$(top_builddir)"); pkgconf_tuple_add_global(client, "pc_top_builddir", client->buildroot_dir != NULL ? client->buildroot_dir : "$(top_builddir)");
@@ -736,6 +798,8 @@ pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handl
PKGCONF_TRACE(client, "installing default unveil handler"); PKGCONF_TRACE(client, "installing default unveil handler");
client->unveil_handler = default_unveil_handler; client->unveil_handler = default_unveil_handler;
} }
else
PKGCONF_TRACE(client, "installing custom unveil handler");
} }
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
@@ -772,12 +836,6 @@ pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler
{ {
client->trace_handler = trace_handler; client->trace_handler = trace_handler;
client->trace_handler_data = trace_handler_data; client->trace_handler_data = trace_handler_data;
if (client->trace_handler == NULL)
{
client->trace_handler = pkgconf_default_error_handler;
PKGCONF_TRACE(client, "installing default trace handler");
}
} }
#endif #endif
@@ -825,7 +883,10 @@ pkgconf_client_preload_path(pkgconf_client_t *client, const char *path)
if (pkg == NULL) if (pkg == NULL)
return false; return false;
return pkgconf_client_preload_one(client, pkg); bool ret = pkgconf_client_preload_one(client, pkg);
pkgconf_pkg_unref(client, pkg);
return ret;
} }
/* /*
@@ -895,7 +956,7 @@ pkgconf_client_set_output(pkgconf_client_t *client, pkgconf_output_t *output)
* Looks up an environmental variable which may be mocked, otherwise fetches * Looks up an environmental variable which may be mocked, otherwise fetches
* from the main environment. * from the main environment.
* *
* :param pkgconf_client_t* client: yhe client object to use for looking up environmental variables. * :param pkgconf_client_t* client: the client object to use for looking up environmental variables.
* :param char* key: the environmental variable to look up. * :param char* key: the environmental variable to look up.
* :return: the environmental variable contents else NULL * :return: the environmental variable contents else NULL
* :rtype: const char* * :rtype: const char*
+9 -21
View File
@@ -1,11 +1,5 @@
/* libpkgconf/config.h.in. Generated from configure.ac by autoheader. */ /* libpkgconf/config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the `strlcat' function. */
#mesondefine HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#mesondefine HAVE_STRLCPY
/* Define to 1 if you have the `strndup' function. */ /* Define to 1 if you have the `strndup' function. */
#mesondefine HAVE_STRNDUP #mesondefine HAVE_STRNDUP
@@ -24,36 +18,30 @@
/* Define to 1 if you have the `unveil' function. */ /* Define to 1 if you have the `unveil' function. */
#mesondefine HAVE_DECL_UNVEIL #mesondefine HAVE_DECL_UNVEIL
/* Define to 1 if you have the `readlinkat' function. */
#mesondefine HAVE_DECL_READLINKAT
/* Define to 1 if you have the `mkdtemp' function. */
#mesondefine HAVE_DECL_MKDTEMP
/* Define to 1 if you have the `getc_unlocked' function. */
#mesondefine HAVE_DECL_GETC_UNLOCKED
/* Define to 1 if you have the `nl_langinfo_l' function. */ /* Define to 1 if you have the `nl_langinfo_l' function. */
#mesondefine HAVE_DECL_NL_LANGINFO_L #mesondefine HAVE_DECL_NL_LANGINFO_L
/* Name of package */
#mesondefine PACKAGE
/* Define to the address where bug reports for this package should be sent. */ /* Define to the address where bug reports for this package should be sent. */
#mesondefine PACKAGE_BUGREPORT #mesondefine PACKAGE_BUGREPORT
/* Define to the full name of this package. */ /* Define to the full name of this package. */
#mesondefine PACKAGE_NAME #mesondefine PACKAGE_NAME
/* Define to the full name and version of this package. */
#mesondefine PACKAGE_STRING
/* Define to the one symbol short name of this package. */ /* Define to the one symbol short name of this package. */
#mesondefine PACKAGE_TARNAME #mesondefine PACKAGE_TARNAME
/* Define to the home page for this package. */
#mesondefine PACKAGE_URL
/* Define to the version of this package. */ /* Define to the version of this package. */
#mesondefine PACKAGE_VERSION #mesondefine PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#mesondefine STDC_HEADERS
/* Version number of package */
#mesondefine VERSION
/* Enable large inode numbers on Mac OS X 10.5. */ /* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE #ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1 # define _DARWIN_USE_64_BIT_INODE 1
+42 -8
View File
@@ -43,10 +43,12 @@ static inline const char *
dependency_to_buf(const pkgconf_dependency_t *dep, pkgconf_buffer_t *buf) dependency_to_buf(const pkgconf_dependency_t *dep, pkgconf_buffer_t *buf)
{ {
pkgconf_buffer_reset(buf); pkgconf_buffer_reset(buf);
pkgconf_buffer_append(buf, dep->package); if (!pkgconf_buffer_append(buf, dep->package))
return NULL;
if (dep->version != NULL) if (dep->version != NULL &&
pkgconf_buffer_append_fmt(buf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version); !pkgconf_buffer_append_fmt(buf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version))
return NULL;
return pkgconf_buffer_str(buf); return pkgconf_buffer_str(buf);
} }
@@ -71,18 +73,34 @@ find_colliding_dependency(const pkgconf_dependency_t *dep, const pkgconf_list_t
return NULL; return NULL;
} }
static inline const char *
dependency_trace_str(const pkgconf_client_t *client, const pkgconf_dependency_t *dep, pkgconf_buffer_t *buf)
{
#ifndef PKGCONF_LITE
const char *str;
if (pkgconf_client_get_trace_handler(client) == NULL)
return dep->package;
str = dependency_to_buf(dep, buf);
return str != NULL ? str : dep->package;
#else
return dep->package;
#endif
}
static inline pkgconf_dependency_t * static inline pkgconf_dependency_t *
add_or_replace_dependency_node(pkgconf_client_t *client, pkgconf_dependency_t *dep, pkgconf_list_t *list) add_or_replace_dependency_node(pkgconf_client_t *client, pkgconf_dependency_t *dep, pkgconf_list_t *list)
{ {
pkgconf_buffer_t depbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t depbuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_dependency_t *dep2 = find_colliding_dependency(dep, list); pkgconf_dependency_t *dep2 = find_colliding_dependency(dep, list);
const char *depstr = dependency_to_buf(dep, &depbuf); const char *depstr = dependency_trace_str(client, dep, &depbuf);
/* there is already a node in the graph which describes this dependency */ /* there is already a node in the graph which describes this dependency */
if (dep2 != NULL) if (dep2 != NULL)
{ {
pkgconf_buffer_t depbuf2 = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t depbuf2 = PKGCONF_BUFFER_INITIALIZER;
const char *depstr2 = dependency_to_buf(dep2, &depbuf2); const char *depstr2 = dependency_trace_str(client, dep2, &depbuf2);
PKGCONF_TRACE(client, "dependency collision: [%s/%x] -- [%s/%x]", PKGCONF_TRACE(client, "dependency collision: [%s/%x] -- [%s/%x]",
depstr, dep->flags, depstr2, dep2->flags); depstr, dep->flags, depstr2, dep2->flags);
@@ -149,7 +167,14 @@ pkgconf_dependency_addraw(pkgconf_client_t *client, pkgconf_list_t *list, const
} }
if (version_sz != 0) if (version_sz != 0)
{
dep->version = pkgconf_strndup(version, version_sz); dep->version = pkgconf_strndup(version, version_sz);
if (dep->version == NULL)
{
pkgconf_dependency_free_one(dep);
return NULL;
}
}
dep->compare = compare; dep->compare = compare;
dep->flags = flags; dep->flags = flags;
@@ -413,8 +438,10 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
if (PKGCONF_IS_OPERATOR_CHAR(*ptr)) if (PKGCONF_IS_OPERATOR_CHAR(*ptr))
break; break;
pkgconf_buffer_reset(&cmpname); pkgconf_buffer_rewind(&cmpname);
pkgconf_buffer_append_slice(&cmpname, opstart, ptr - opstart); if (!pkgconf_buffer_append_slice(&cmpname, opstart, ptr - opstart))
goto out;
compare = pkgconf_pkg_comparator_lookup_by_name(pkgconf_buffer_str(&cmpname)); compare = pkgconf_pkg_comparator_lookup_by_name(pkgconf_buffer_str(&cmpname));
state = AFTER_OPERATOR; state = AFTER_OPERATOR;
// fallthrough // fallthrough
@@ -439,7 +466,7 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
compare = PKGCONF_CMP_ANY; compare = PKGCONF_CMP_ANY;
package_sz = 0; package_sz = 0;
opstart = NULL; opstart = NULL;
pkgconf_buffer_reset(&cmpname); pkgconf_buffer_rewind(&cmpname);
} }
if (state == OUTSIDE_MODULE) if (state == OUTSIDE_MODULE)
@@ -508,7 +535,14 @@ pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *de
} }
if (dep->version != NULL) if (dep->version != NULL)
{
new_dep->version = strdup(dep->version); new_dep->version = strdup(dep->version);
if (new_dep->version == NULL)
{
pkgconf_dependency_free_one(new_dep);
return NULL;
}
}
new_dep->compare = dep->compare; new_dep->compare = dep->compare;
new_dep->flags = dep->flags; new_dep->flags = dep->flags;
+53 -79
View File
@@ -15,107 +15,81 @@
* from the use of this software. * from the use of this software.
*/ */
#include <libpkgconf/config.h>
#include <libpkgconf/stdinc.h> #include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h> #include <libpkgconf/libpkgconf.h>
#define push_or_return_fail(buf, c) \ #if HAVE_DECL_GETC_UNLOCKED
do { if (!pkgconf_buffer_push_byte((buf), (char) (c))) return false; } while (0) # define pkgconf_getc(stream) getc_unlocked(stream)
#else
#define trim_or_return_fail(buf) \ # define pkgconf_getc(stream) getc(stream)
do { if (!pkgconf_buffer_trim_byte((buf))) return false; } while (0) #endif
bool bool
pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream) pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream)
{ {
bool quoted = false; bool quoted = false;
bool got_data = false; bool got_data = false;
char in[PKGCONF_ITEM_SIZE]; char run[256];
long unread = 0; size_t runlen = 0;
int c;
while (fgets(in, sizeof in, stream) != NULL) while ((c = pkgconf_getc(stream)) != EOF)
{ {
char *p = in;
got_data = true; got_data = true;
while (*p != '\0') if (c == '\\' && !quoted)
{ {
unsigned char c = (unsigned char) *p++; quoted = true;
continue;
}
if (c == '\\' && !quoted) if (c == '\n')
{
if (quoted)
{ {
quoted = true; quoted = false;
continue; continue;
} }
else if (c == '\n')
{
if (quoted)
{
quoted = false;
continue;
}
else
push_or_return_fail(buffer, (char) c);
goto done; break;
}
else if (c == '\r')
{
if (*p == '\n')
{
p++;
}
else if (*p == '\0')
{
/*
* The matching '\n' may not have been read into `in`
* yet if '\r' landed exactly on the fgets() buffer
* boundary. Peek the real stream so a split CRLF
* isn't misparsed as two lines.
*/
int next = getc(stream);
if (next != '\n' && next != EOF && ungetc(next, stream) == EOF)
return false;
}
if (quoted)
{
quoted = false;
continue;
}
push_or_return_fail(buffer, '\n');
/* unlike '\n', a lone '\r' doesn't bound the fgets() call above */
unread = (long) strlen(p);
goto done;
}
else
{
if (quoted)
{
push_or_return_fail(buffer, '\\');
quoted = false;
}
push_or_return_fail(buffer, (char) c);
}
} }
if (c == '\r')
{
int next = pkgconf_getc(stream);
if (next != '\n' && next != EOF && ungetc(next, stream) == EOF)
return false;
if (quoted)
{
quoted = false;
continue;
}
break;
}
if (runlen > sizeof run - 2)
{
if (!pkgconf_buffer_append_slice(buffer, run, runlen))
return false;
runlen = 0;
}
if (quoted)
{
run[runlen++] = '\\';
quoted = false;
}
run[runlen++] = (char) c;
} }
done: if (runlen != 0 && !pkgconf_buffer_append_slice(buffer, run, runlen))
if (unread > 0 && fseek(stream, -unread, SEEK_CUR) != 0)
return false; return false;
/* Remove newline character. */ return got_data && !ferror(stream);
if (pkgconf_buffer_lastc(buffer) == '\n')
trim_or_return_fail(buffer);
if (pkgconf_buffer_lastc(buffer) == '\r')
trim_or_return_fail(buffer);
if (!got_data)
return false;
return !ferror(stream);
} }
+628 -246
View File
File diff suppressed because it is too large. Load diff
+20
View File
@@ -46,6 +46,26 @@ pkgconf_list_zero(pkgconf_list_t *list)
list->length = 0; list->length = 0;
} }
static inline void
pkgconf_list_splice(pkgconf_list_t *dest, pkgconf_list_t *src)
{
if (dest == src || src->head == NULL)
return;
if (dest->head == NULL)
dest->head = src->head;
else
{
dest->tail->next = src->head;
src->head->prev = dest->tail;
}
dest->tail = src->tail;
dest->length += src->length;
pkgconf_list_zero(src);
}
static inline void static inline void
pkgconf_node_insert(pkgconf_node_t *node, void *data, pkgconf_list_t *list) pkgconf_node_insert(pkgconf_node_t *node, void *data, pkgconf_list_t *list)
{ {
+6
View File
@@ -12,6 +12,12 @@
# else # else
# define PKGCONF_API __declspec(dllimport) # define PKGCONF_API __declspec(dllimport)
# endif # endif
#elif defined(__OS2__)
# if defined(LIBPKGCONF_EXPORT) || defined(DLL_EXPORT)
# define PKGCONF_API __declspec(dllexport)
# else
# define PKGCONF_API
# endif
#else #else
# define PKGCONF_API __attribute__((visibility("default"))) # define PKGCONF_API __attribute__((visibility("default")))
#endif #endif
+105 -21
View File
@@ -71,8 +71,8 @@ typedef struct pkgconf_license_ pkgconf_license_t;
#define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \ #define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \
for ((value) = (tail); (value) != NULL; (value) = (value)->prev) for ((value) = (tail); (value) != NULL; (value) = (value)->prev)
#define LIBPKGCONF_VERSION 20993 #define LIBPKGCONF_VERSION 30009
#define LIBPKGCONF_VERSION_STR "2.9.93" #define LIBPKGCONF_VERSION_STR "3.0.9"
struct pkgconf_queue_ { struct pkgconf_queue_ {
pkgconf_node_t iter; pkgconf_node_t iter;
@@ -256,12 +256,26 @@ struct pkgconf_pkg_ {
}; };
typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data); typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data);
typedef void (*pkgconf_pkg_traverse_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data);
/* iteration state threaded through pkgconf_pkg_traverse() to its callback */
#define PKGCONF_PKG_ITERF_NONE 0x0
#define PKGCONF_PKG_ITERF_PRIVATE 0x1
typedef void (*pkgconf_pkg_traverse_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags);
typedef bool (*pkgconf_queue_apply_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth); typedef bool (*pkgconf_queue_apply_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth);
typedef bool (*pkgconf_error_handler_func_t)(const char *msg, const pkgconf_client_t *client, void *data); typedef bool (*pkgconf_error_handler_func_t)(const char *msg, const pkgconf_client_t *client, void *data);
typedef void (*pkgconf_unveil_handler_func_t)(const pkgconf_client_t *client, const char *path, const char *permissions); typedef void (*pkgconf_unveil_handler_func_t)(const pkgconf_client_t *client, const char *path, const char *permissions);
typedef const char *(*pkgconf_environ_lookup_handler_func_t)(const pkgconf_client_t *client, const char *variable); typedef const char *(*pkgconf_environ_lookup_handler_func_t)(const pkgconf_client_t *client, const char *variable);
typedef struct pkgconf_client_options_ {
pkgconf_error_handler_func_t error_handler;
void *error_handler_data;
const pkgconf_cross_personality_t *personality;
void *client_data;
pkgconf_environ_lookup_handler_func_t environ_lookup_handler;
pkgconf_unveil_handler_func_t unveil_handler;
} pkgconf_client_options_t;
struct pkgconf_client_ { struct pkgconf_client_ {
pkgconf_list_t dir_list; pkgconf_list_t dir_list;
@@ -362,10 +376,13 @@ PKGCONF_API void pkgconf_variable_delete(pkgconf_list_t *vars, pkgconf_variable_
PKGCONF_API void pkgconf_variable_list_free(pkgconf_list_t *vars); PKGCONF_API void pkgconf_variable_list_free(pkgconf_list_t *vars);
PKGCONF_API bool pkgconf_variable_eval(pkgconf_client_t *client, const pkgconf_list_t *tuples, const pkgconf_variable_t *v, pkgconf_buffer_t *out, bool *saw_sysroot); PKGCONF_API bool pkgconf_variable_eval(pkgconf_client_t *client, const pkgconf_list_t *tuples, const pkgconf_variable_t *v, pkgconf_buffer_t *out, bool *saw_sysroot);
PKGCONF_API char *pkgconf_variable_eval_str(pkgconf_client_t *client, const pkgconf_list_t *tuples, const pkgconf_variable_t *v, bool *saw_sysroot); PKGCONF_API char *pkgconf_variable_eval_str(pkgconf_client_t *client, const pkgconf_list_t *tuples, const pkgconf_variable_t *v, bool *saw_sysroot);
PKGCONF_API char *pkgconf_variable_eval_name(pkgconf_client_t *client, const pkgconf_list_t *vars, const char *varname);
/* client.c */ /* client.c */
PKGCONF_API void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler); PKGCONF_API void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler);
PKGCONF_API void pkgconf_client_init_with_options(pkgconf_client_t *client, const pkgconf_client_options_t *options);
PKGCONF_API pkgconf_client_t * pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler); PKGCONF_API pkgconf_client_t * pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler);
PKGCONF_API pkgconf_client_t * pkgconf_client_new_with_options(const pkgconf_client_options_t *options);
PKGCONF_API void pkgconf_client_deinit(pkgconf_client_t *client); PKGCONF_API void pkgconf_client_deinit(pkgconf_client_t *client);
PKGCONF_API void pkgconf_client_free(pkgconf_client_t *client); PKGCONF_API void pkgconf_client_free(pkgconf_client_t *client);
PKGCONF_API const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client); PKGCONF_API const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client);
@@ -408,7 +425,7 @@ PKGCONF_API void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *p
#define PKGCONF_PKG_PKGF_SKIP_CONFLICTS 0x0020 #define PKGCONF_PKG_PKGF_SKIP_CONFLICTS 0x0020
#define PKGCONF_PKG_PKGF_NO_CACHE 0x0040 #define PKGCONF_PKG_PKGF_NO_CACHE 0x0040
#define PKGCONF_PKG_PKGF_SKIP_ERRORS 0x0080 #define PKGCONF_PKG_PKGF_SKIP_ERRORS 0x0080
#define PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE 0x0100 /* 0x0100 reserved (was PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; now threaded as a traversal parameter) */
#define PKGCONF_PKG_PKGF_SKIP_PROVIDES 0x0200 #define PKGCONF_PKG_PKGF_SKIP_PROVIDES 0x0200
#define PKGCONF_PKG_PKGF_REDEFINE_PREFIX 0x0400 #define PKGCONF_PKG_PKGF_REDEFINE_PREFIX 0x0400
#define PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS 0x0800 #define PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS 0x0800
@@ -418,6 +435,7 @@ PKGCONF_API void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *p
#define PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES 0x8000 #define PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES 0x8000
#define PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES 0x10000 #define PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES 0x10000
#define PKGCONF_PKG_PKGF_REQUIRE_INTERNAL 0x20000 #define PKGCONF_PKG_PKGF_REQUIRE_INTERNAL 0x20000
#define PKGCONF_PKG_PKGF_NO_SYSROOT_INJECTION 0x40000
#define PKGCONF_PKG_DEPF_INTERNAL 0x1 #define PKGCONF_PKG_DEPF_INTERNAL 0x1
#define PKGCONF_PKG_DEPF_PRIVATE 0x2 #define PKGCONF_PKG_DEPF_PRIVATE 0x2
@@ -457,11 +475,15 @@ PKGCONF_API bool pkgconf_default_error_handler(const char *msg, const pkgconf_cl
#ifndef PKGCONF_LITE #ifndef PKGCONF_LITE
#if defined(__GNUC__) || defined(__INTEL_COMPILER) #if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define PKGCONF_TRACE(client, ...) do { \ #define PKGCONF_TRACE(client, ...) do { \
pkgconf_trace(client, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__); \ const pkgconf_client_t *pkgconf_trace_client_ = (client); \
if (pkgconf_trace_client_ != NULL && pkgconf_trace_client_->trace_handler != NULL) \
pkgconf_trace(pkgconf_trace_client_, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__); \
} while (0) } while (0)
#else #else
#define PKGCONF_TRACE(client, ...) do { \ #define PKGCONF_TRACE(client, ...) do { \
pkgconf_trace(client, __FILE__, __LINE__, __func__, __VA_ARGS__); \ const pkgconf_client_t *pkgconf_trace_client_ = (client); \
if (pkgconf_trace_client_ != NULL && pkgconf_trace_client_->trace_handler != NULL) \
pkgconf_trace(pkgconf_trace_client_, __FILE__, __LINE__, __func__, __VA_ARGS__); \
} while (0) } while (0)
#endif #endif
#else #else
@@ -499,6 +521,7 @@ PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_copy(pkgconf_client_t *clie
/* argvsplit.c */ /* argvsplit.c */
PKGCONF_API int pkgconf_argv_split(const char *src, int *argc, char ***argv); PKGCONF_API int pkgconf_argv_split(const char *src, int *argc, char ***argv);
PKGCONF_API int pkgconf_argv_split_raw(const char *src, int *argc, char ***argv);
PKGCONF_API void pkgconf_argv_free(char **argv); PKGCONF_API void pkgconf_argv_free(char **argv);
/* fragment.c */ /* fragment.c */
@@ -508,29 +531,46 @@ typedef struct pkgconf_fragment_render_ctx_ {
} pkgconf_fragment_render_ctx_t; } pkgconf_fragment_render_ctx_t;
typedef struct pkgconf_fragment_render_ops_ { typedef struct pkgconf_fragment_render_ops_ {
void (*render)(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf); bool (*render)(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf);
} pkgconf_fragment_render_ops_t; } pkgconf_fragment_render_ops_t;
typedef bool (*pkgconf_fragment_filter_func_t)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data); typedef bool (*pkgconf_fragment_filter_func_t)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data);
/* A cursor accelerates repeated pkgconf_fragment_copy() calls into the same
* destination list by maintaining a sorted index of the fragments already
* present, so that the deduplication lookup is a bsearch() rather than a linear
* scan of the (potentially large) accumulator.
*/
typedef struct pkgconf_fragment_cursor_ {
pkgconf_list_t *list;
pkgconf_fragment_t **index;
size_t count;
size_t alloc;
} pkgconf_fragment_cursor_t;
PKGCONF_API bool pkgconf_fragment_parse(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags); PKGCONF_API bool pkgconf_fragment_parse(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags);
PKGCONF_API void pkgconf_fragment_insert(pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail); PKGCONF_API void pkgconf_fragment_insert(pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail);
PKGCONF_API void pkgconf_fragment_add(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *string, unsigned int flags); PKGCONF_API bool pkgconf_fragment_add(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *string, unsigned int flags);
PKGCONF_API void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private); PKGCONF_API void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private);
PKGCONF_API void pkgconf_fragment_cursor_init(pkgconf_fragment_cursor_t *cursor, pkgconf_list_t *list);
PKGCONF_API void pkgconf_fragment_cursor_deinit(pkgconf_fragment_cursor_t *cursor);
PKGCONF_API void pkgconf_fragment_copy_cursor(const pkgconf_client_t *client, pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base, bool is_private);
PKGCONF_API void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base); PKGCONF_API void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base);
PKGCONF_API void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node); PKGCONF_API void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node);
PKGCONF_API void pkgconf_fragment_free(pkgconf_list_t *list); PKGCONF_API void pkgconf_fragment_free(pkgconf_list_t *list);
PKGCONF_API void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data); PKGCONF_API void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data);
PKGCONF_API void pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim); PKGCONF_API void pkgconf_fragment_filter_splice(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data);
PKGCONF_API bool pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim);
PKGCONF_API bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag); PKGCONF_API bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag);
PKGCONF_API bool pkgconf_is_locale_utf8(void); PKGCONF_API bool pkgconf_is_locale_utf8(void);
/* license.c */ /* license.c */
PKGCONF_API void pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base); PKGCONF_API bool pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base);
PKGCONF_API void pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *expression, unsigned int flags); PKGCONF_API bool pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *expression, unsigned int flags);
PKGCONF_API void pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends, unsigned int flags); PKGCONF_API bool pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends, unsigned int flags);
PKGCONF_API void pkgconf_license_free(pkgconf_list_t *list); PKGCONF_API void pkgconf_license_free(pkgconf_list_t *list);
PKGCONF_API void pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data); PKGCONF_API bool pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data);
PKGCONF_API void pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf); PKGCONF_API bool pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf);
/* tuple.c */ /* tuple.c */
PKGCONF_API pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *parent, const char *key, const char *value, bool parse, unsigned int flags); PKGCONF_API pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *parent, const char *key, const char *value, bool parse, unsigned int flags);
@@ -574,6 +614,7 @@ PKGCONF_API size_t pkgconf_path_build_from_registry(pkgconf_client_t *client, /*
PKGCONF_API bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist); PKGCONF_API bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist);
PKGCONF_API void pkgconf_path_free(pkgconf_list_t *dirlist); PKGCONF_API void pkgconf_path_free(pkgconf_list_t *dirlist);
PKGCONF_API bool pkgconf_path_relocate(pkgconf_buffer_t *buf); PKGCONF_API bool pkgconf_path_relocate(pkgconf_buffer_t *buf);
PKGCONF_API void pkgconf_path_normalize_separators(char *path);
PKGCONF_API void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src); PKGCONF_API void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src);
PKGCONF_API void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src); PKGCONF_API void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src);
PKGCONF_API bool pkgconf_path_is_plausible(const pkgconf_buffer_t *buf); PKGCONF_API bool pkgconf_path_is_plausible(const pkgconf_buffer_t *buf);
@@ -592,6 +633,21 @@ static inline bool pkgconf_span_contains(unsigned char c, const pkgconf_span_t *
return false; return false;
} }
/* A set of byte values as a 256-bit map, so that membership is a single test
* rather than a walk over a span list. Build one with
* pkgconf_charset_from_spans() and keep it: the point is to hoist the span
* walk out of any per-byte loop. */
typedef struct pkgconf_charset_ {
uint64_t words[4];
} pkgconf_charset_t;
static inline bool pkgconf_charset_contains(const pkgconf_charset_t *charset, unsigned char c)
{
return (charset->words[c >> 6] >> (c & 63)) & 1;
}
PKGCONF_API void pkgconf_charset_from_spans(pkgconf_charset_t *charset, const pkgconf_span_t *spans, size_t nspans);
PKGCONF_API bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text); PKGCONF_API bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text);
PKGCONF_API bool pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n); PKGCONF_API bool pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n);
PKGCONF_API bool pkgconf_buffer_append_fmt(pkgconf_buffer_t *buffer, const char *fmt, ...) PRINTFLIKE(2, 3); PKGCONF_API bool pkgconf_buffer_append_fmt(pkgconf_buffer_t *buffer, const char *fmt, ...) PRINTFLIKE(2, 3);
@@ -609,6 +665,7 @@ PKGCONF_API bool pkgconf_buffer_contains_byte(const pkgconf_buffer_t *haystack,
PKGCONF_API bool pkgconf_buffer_match(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *needle); PKGCONF_API bool pkgconf_buffer_match(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *needle);
PKGCONF_API bool pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const char *pattern, const char *value); PKGCONF_API bool pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const char *pattern, const char *value);
PKGCONF_API bool pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans); PKGCONF_API bool pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans);
PKGCONF_API bool pkgconf_buffer_escape_charset(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_charset_t *charset);
/* /*
* !doc * !doc
@@ -652,6 +709,9 @@ static inline const char *pkgconf_buffer_str_or_empty(const pkgconf_buffer_t *bu
*/ */
static inline size_t pkgconf_buffer_len(const pkgconf_buffer_t *buffer) static inline size_t pkgconf_buffer_len(const pkgconf_buffer_t *buffer)
{ {
if (buffer->base == NULL)
return 0;
return (size_t)(ptrdiff_t)(buffer->end - buffer->base); return (size_t)(ptrdiff_t)(buffer->end - buffer->base);
} }
@@ -693,24 +753,44 @@ static inline void pkgconf_buffer_reset(pkgconf_buffer_t *buffer)
buffer->base = buffer->end = NULL; buffer->base = buffer->end = NULL;
} }
/*
* !doc
*
* .. c:function:: static inline void pkgconf_buffer_rewind(pkgconf_buffer_t *buffer)
*
* Truncate the buffer to empty while retaining its allocation, so it can be
* refilled without reallocating. Unlike pkgconf_buffer_reset(), the backing
* storage is kept.
*
* :param pkgconf_buffer_t *buffer: The buffer to rewind.
* :return: nothing
*/
static inline void pkgconf_buffer_rewind(pkgconf_buffer_t *buffer)
{
if (buffer->base != NULL)
{
buffer->end = buffer->base;
*buffer->base = '\0';
}
}
/* /*
* !doc * !doc
* *
* .. c:function:: static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer) * .. c:function:: static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer)
* *
* Free the underlying buffer, copying the underlying string. * Hand ownership of the underlying storage to the caller as a string and
* The string must be freed by the caller. * empty the buffer. The string must be freed by the caller.
* *
* :param pkgconf_buffer_t *buffer: The buffer to freeze. * :param pkgconf_buffer_t *buffer: The buffer to freeze.
* :return: The underlying string, copied. * :return: The underlying string.
*/ */
static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer) static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer)
{ {
if (buffer->base == NULL) char *out = buffer->base;
return NULL;
buffer->base = buffer->end = NULL;
char *out = pkgconf_strndup(pkgconf_buffer_str(buffer), pkgconf_buffer_len(buffer));
pkgconf_buffer_reset(buffer);
return out; return out;
} }
@@ -720,6 +800,7 @@ static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer)
* .. c:function:: static inline bool pkgconf_buffer_copy(pkgconf_buffer_t *buffer, pkgconf_buffer_t *newptr) * .. c:function:: static inline bool pkgconf_buffer_copy(pkgconf_buffer_t *buffer, pkgconf_buffer_t *newptr)
* *
* Copy the contents of one buffer to another, erasing the contents of the buffer in :code:`newptr`. * Copy the contents of one buffer to another, erasing the contents of the buffer in :code:`newptr`.
* The source and destination buffers must not overlap.
* *
* :param pkgconf_buffer_t *buffer: The buffer to copy from. * :param pkgconf_buffer_t *buffer: The buffer to copy from.
* :param pkgconf_buffer_t *buffer: The buffer to copy to. * :param pkgconf_buffer_t *buffer: The buffer to copy to.
@@ -727,6 +808,9 @@ static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer)
*/ */
static inline bool pkgconf_buffer_copy(pkgconf_buffer_t *buffer, pkgconf_buffer_t *newptr) static inline bool pkgconf_buffer_copy(pkgconf_buffer_t *buffer, pkgconf_buffer_t *newptr)
{ {
if (buffer == newptr || (buffer->base != NULL && buffer->base == newptr->base))
return false;
pkgconf_buffer_reset(newptr); pkgconf_buffer_reset(newptr);
return pkgconf_buffer_append_slice(newptr, pkgconf_buffer_str(buffer), pkgconf_buffer_len(buffer)); return pkgconf_buffer_append_slice(newptr, pkgconf_buffer_str(buffer), pkgconf_buffer_len(buffer));
} }
+144 -100
View File
@@ -18,7 +18,7 @@
#include <libpkgconf/stdinc.h> #include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h> #include <libpkgconf/libpkgconf.h>
static void license_sanitize_string(const char *s, pkgconf_buffer_t *buf) static bool license_sanitize_string(const char *s, pkgconf_buffer_t *buf)
{ {
unsigned int i = 0; unsigned int i = 0;
/* /*
@@ -31,24 +31,27 @@ static void license_sanitize_string(const char *s, pkgconf_buffer_t *buf)
{ {
if (isalnum((unsigned char) s[i]) || s[i] == '-' || s[i] == '+' || s[i] == '(' || s[i] == ')' || s[i] == '.' || s[i] == ':') if (isalnum((unsigned char) s[i]) || s[i] == '-' || s[i] == '+' || s[i] == '(' || s[i] == ')' || s[i] == '.' || s[i] == ':')
{ {
pkgconf_buffer_push_byte(buf, s[i]); if (!pkgconf_buffer_push_byte(buf, s[i]))
return false;
} }
} }
return true;
} }
/* /*
* !doc * !doc
* *
* .. c:function:: void pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base) * .. c:function:: bool pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base)
* *
* Copies a `license list` to another `license list` * Copies a `license list` to another `license list`
* *
* :param pkgconf_client_t* client: The pkgconf client being accessed. * :param pkgconf_client_t* client: The pkgconf client being accessed.
* :param pkgconf_list_t* list: The list the fragments are being added to. * :param pkgconf_list_t* list: The list the fragments are being added to.
* :param pkgconf_list_t* base: The list the fragments are being copied from. * :param pkgconf_list_t* base: The list the fragments are being copied from.
* :return: nothing * :return: true on success, false on allocation failure
*/ */
void bool
pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base) pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base)
{ {
pkgconf_node_t *node; pkgconf_node_t *node;
@@ -60,17 +63,24 @@ pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list,
pkgconf_license_t *cpy_license = calloc(1, sizeof(pkgconf_license_t)); pkgconf_license_t *cpy_license = calloc(1, sizeof(pkgconf_license_t));
if (cpy_license == NULL) if (cpy_license == NULL)
continue; return false;
cpy_license->type = license->type; cpy_license->type = license->type;
if (license->data != NULL) if (license->data != NULL)
{ {
cpy_license->data = strdup(license->data); cpy_license->data = strdup(license->data);
if (cpy_license->data == NULL)
{
free(cpy_license);
return false;
}
} }
pkgconf_node_insert_tail(&cpy_license->iter, cpy_license, list); pkgconf_node_insert_tail(&cpy_license->iter, cpy_license, list);
} }
return true;
} }
/* /*
@@ -97,12 +107,14 @@ pkgconf_license_free(pkgconf_list_t *list)
free(license->data); free(license->data);
free(license); free(license);
} }
pkgconf_list_zero(list);
} }
/* /*
* !doc * !doc
* *
* .. c:function:: void pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data) * .. c:function:: bool pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data)
* *
* Adds a `license` of text to a `license list` directly without interpreting it. * Adds a `license` of text to a `license list` directly without interpreting it.
* *
@@ -110,31 +122,39 @@ pkgconf_license_free(pkgconf_list_t *list)
* :param pkgconf_list_t* list: The fragment list. * :param pkgconf_list_t* list: The fragment list.
* :param char type: The type of the license. * :param char type: The type of the license.
* :param char* data: The data of the license * :param char* data: The data of the license
* :return: nothing * :return: true on success, false on allocation failure
*/ */
void bool
pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data) pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data)
{ {
(void) client;
pkgconf_license_t *license; pkgconf_license_t *license;
if (data == NULL)
return false;
license = calloc(1, sizeof(pkgconf_license_t)); license = calloc(1, sizeof(pkgconf_license_t));
if (!license) if (!license)
{ {
pkgconf_error(client, "pkgconf_license_insert: out of memory"); pkgconf_error(client, "pkgconf_license_insert: out of memory");
return; return false;
} }
license->type = type; license->type = type;
license->data = strdup(data); license->data = strdup(data);
if (license->data == NULL)
{
pkgconf_error(client, "pkgconf_license_insert: out of memory");
free(license);
return false;
}
pkgconf_node_insert_tail(&license->iter, license, list); pkgconf_node_insert_tail(&license->iter, license, list);
return true;
} }
/* /*
* !doc * !doc
* *
* .. c:function:: pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags) * .. c:function:: bool pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags)
* *
* Evaluates SPDX expression strings like: * Evaluates SPDX expression strings like:
* - BSD-3-Clause * - BSD-3-Clause
@@ -153,9 +173,9 @@ pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned
* :param pkgconf_list_t* license_list: The dependency list to populate with dependency nodes. * :param pkgconf_list_t* license_list: The dependency list to populate with dependency nodes.
* :param char* expression: The dependency data to parse. * :param char* expression: The dependency data to parse.
* :param uint flags: Any flags to attach to the dependency nodes. * :param uint flags: Any flags to attach to the dependency nodes.
* :return: nothing * :return: true on success, false on allocation failure
*/ */
void bool
pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags) pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags)
{ {
pkgconf_buffer_t out_buffer = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t out_buffer = PKGCONF_BUFFER_INITIALIZER;
@@ -168,95 +188,112 @@ pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_l
(void)flags; (void)flags;
if (expression == NULL) if (expression == NULL)
return; return true;
buf_size = strlen(expression) + 1; buf_size = strlen(expression) + 1;
ret = pkgconf_argv_split(expression, &argc, &argv); ret = pkgconf_argv_split(expression, &argc, &argv);
if (!ret) if (ret)
return true;
/* This is not the first License:
* so add AND
*/
if (license_list->head)
{ {
/* This is not the first License: if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND"))
* so add AND goto fail;
*/
if (license_list->head)
{
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND");
}
i = 0;
while (i < argc)
{
string_len = strnlen(argv[i], buf_size);
cur_word = argv[i];
if (string_len >= 1)
{
license_sanitize_string(cur_word, &out_buffer);
if (!pkgconf_buffer_len(&out_buffer))
{
i ++;
pkgconf_buffer_finalize(&out_buffer);
continue;
}
cur_word = (char *)pkgconf_buffer_str(&out_buffer);
size_t cur_len = strnlen(cur_word, buf_size);
if (!cur_len)
{
i ++;
pkgconf_buffer_finalize(&out_buffer);
continue;
}
if (cur_word[0] == '(')
{
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_OPEN, "(");
/* If there is more after '(' like '(BSD-2-Clause'
* Then append rest to fragments as license.
* This is expression like GPL-2.0-only OR (BSD-2-Clause AND ISC)
*/
if (cur_len >= 2)
{
cur_word ++;
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word);
}
}
else if (cur_word[cur_len - 1] == ')')
{
if (cur_len >= 2)
{
cur_word[cur_len - 1] = 0x00;
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word);
}
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_CLOSE, ")");
}
else if (!strcasecmp(cur_word, "and"))
{
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND");
}
else if (!strcasecmp(cur_word, "or"))
{
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_OR, "OR");
}
else if (!strcasecmp(cur_word, "with"))
{
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_WITH, "WITH");
}
else
{
pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word);
}
pkgconf_buffer_finalize(&out_buffer);
}
i++;
}
pkgconf_argv_free(argv);
} }
i = 0;
while (i < argc)
{
string_len = strnlen(argv[i], buf_size);
cur_word = argv[i];
if (string_len >= 1)
{
if (!license_sanitize_string(cur_word, &out_buffer))
goto fail;
if (!pkgconf_buffer_len(&out_buffer))
{
i ++;
pkgconf_buffer_finalize(&out_buffer);
continue;
}
cur_word = (char *)pkgconf_buffer_str(&out_buffer);
size_t cur_len = strnlen(cur_word, buf_size);
if (!cur_len)
{
i ++;
pkgconf_buffer_finalize(&out_buffer);
continue;
}
if (cur_word[0] == '(')
{
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_OPEN, "("))
goto fail;
/* If there is more after '(' like '(BSD-2-Clause'
* Then append rest to fragments as license.
* This is expression like GPL-2.0-only OR (BSD-2-Clause AND ISC)
*/
if (cur_len >= 2)
{
cur_word ++;
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word))
goto fail;
}
}
else if (cur_word[cur_len - 1] == ')')
{
if (cur_len >= 2)
{
cur_word[cur_len - 1] = 0x00;
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word))
goto fail;
}
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_CLOSE, ")"))
goto fail;
}
else if (!strcasecmp(cur_word, "and"))
{
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND"))
goto fail;
}
else if (!strcasecmp(cur_word, "or"))
{
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_OR, "OR"))
goto fail;
}
else if (!strcasecmp(cur_word, "with"))
{
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_WITH, "WITH"))
goto fail;
}
else
{
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word))
goto fail;
}
pkgconf_buffer_finalize(&out_buffer);
}
i++;
}
pkgconf_argv_free(argv);
return true;
fail:
pkgconf_buffer_finalize(&out_buffer);
pkgconf_argv_free(argv);
return false;
} }
/* /*
* !doc * !doc
* *
* .. c:function:: pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags) * .. c:function:: bool pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *license_list, const char *license_str, unsigned int flags)
* *
* Evaluates SPDX expression strings like: * Evaluates SPDX expression strings like:
* - BSD-3-Clause * - BSD-3-Clause
@@ -275,15 +312,18 @@ pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_l
* :param pkgconf_list_t* license_list: The dependency list to populate with dependency nodes. * :param pkgconf_list_t* license_list: The dependency list to populate with dependency nodes.
* :param char* expression: The dependency data to parse. * :param char* expression: The dependency data to parse.
* :param uint flags: Any flags to attach to the dependency nodes. * :param uint flags: Any flags to attach to the dependency nodes.
* :return: nothing * :return: true on success, false on allocation failure
*/ */
void bool
pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *license_list, const char *license_str, unsigned int flags) pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *license_list, const char *license_str, unsigned int flags)
{ {
char *license_expression = pkgconf_bytecode_eval_str(client, &pkg->vars, license_str, NULL); char *license_expression = pkgconf_bytecode_eval_str(client, &pkg->vars, license_str, NULL);
if (license_expression == NULL)
return false;
pkgconf_license_evaluate_str(client, license_list, license_expression, flags); bool ret = pkgconf_license_evaluate_str(client, license_list, license_expression, flags);
free(license_expression); free(license_expression);
return ret;
} }
/* /*
@@ -300,7 +340,7 @@ pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_l
* :param uint flags: Any flags to attach to the dependency nodes. * :param uint flags: Any flags to attach to the dependency nodes.
* :return: nothing * :return: nothing
*/ */
void bool
pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf) pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf)
{ {
const pkgconf_buffer_t *frag_string = NULL; const pkgconf_buffer_t *frag_string = NULL;
@@ -314,7 +354,8 @@ pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkg
pkgconf_license_t *license = node->data; pkgconf_license_t *license = node->data;
is_delim = true; is_delim = true;
frag_string = PKGCONF_BUFFER_FROM_STR(license->data); frag_string = PKGCONF_BUFFER_FROM_STR(license->data);
pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(frag_string)); if (!pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(frag_string)))
return false;
if (license->type == PKGCONF_LICENSE_BRACKET_OPEN || (node->next != NULL && ((const pkgconf_license_t *)node->next->data)->type == PKGCONF_LICENSE_BRACKET_CLOSE)) if (license->type == PKGCONF_LICENSE_BRACKET_OPEN || (node->next != NULL && ((const pkgconf_license_t *)node->next->data)->type == PKGCONF_LICENSE_BRACKET_CLOSE))
{ {
@@ -323,7 +364,10 @@ pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkg
if (node->next != NULL && is_delim) if (node->next != NULL && is_delim)
{ {
pkgconf_buffer_push_byte(buf, ' '); if (!pkgconf_buffer_push_byte(buf, ' '))
return false;
} }
} }
return true;
} }
+18 -8
View File
@@ -24,11 +24,15 @@ pkgconf_output_putbuf(pkgconf_output_t *output, pkgconf_output_stream_t stream,
bool ret; bool ret;
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
if (pkgconf_buffer_len(buffer) != 0) if (pkgconf_buffer_len(buffer) != 0 &&
pkgconf_buffer_append(&buf, pkgconf_buffer_str(buffer)); !pkgconf_buffer_append(&buf, pkgconf_buffer_str(buffer)))
return false;
if (newline) if (newline && !pkgconf_buffer_push_byte(&buf, '\n'))
pkgconf_buffer_push_byte(&buf, '\n'); {
pkgconf_buffer_finalize(&buf);
return false;
}
ret = output->write(output, stream, &buf); ret = output->write(output, stream, &buf);
pkgconf_buffer_finalize(&buf); pkgconf_buffer_finalize(&buf);
@@ -42,8 +46,13 @@ pkgconf_output_puts(pkgconf_output_t *output, pkgconf_output_stream_t stream, co
bool ret; bool ret;
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_append(&buf, str); if (!pkgconf_buffer_append(&buf, str) ||
pkgconf_buffer_push_byte(&buf, '\n'); !pkgconf_buffer_push_byte(&buf, '\n'))
{
pkgconf_buffer_finalize(&buf);
return false;
}
ret = output->write(output, stream, &buf); ret = output->write(output, stream, &buf);
pkgconf_buffer_finalize(&buf); pkgconf_buffer_finalize(&buf);
@@ -71,10 +80,11 @@ pkgconf_output_vfmt(pkgconf_output_t *output, pkgconf_output_stream_t stream, co
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
va_copy(va, src_va); va_copy(va, src_va);
pkgconf_buffer_append_vfmt(&buf, fmt, va); ret = pkgconf_buffer_append_vfmt(&buf, fmt, va);
va_end(va); va_end(va);
ret = output->write(output, stream, &buf); if (ret)
ret = output->write(output, stream, &buf);
pkgconf_buffer_finalize(&buf); pkgconf_buffer_finalize(&buf);
return ret; return ret;
+1 -1
View File
@@ -145,7 +145,7 @@ pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *o
snprintf(warnprefix, sizeof warnprefix, "%s:" SIZE_FMT_SPECIFIER, filename, lineno); snprintf(warnprefix, sizeof warnprefix, "%s:" SIZE_FMT_SPECIFIER, filename, lineno);
pkgconf_parser_parse_buffer(data, ops, warnfunc, &readbuf, warnprefix); pkgconf_parser_parse_buffer(data, ops, warnfunc, &readbuf, warnprefix);
pkgconf_buffer_reset(&readbuf); pkgconf_buffer_rewind(&readbuf);
} }
pkgconf_buffer_finalize(&readbuf); pkgconf_buffer_finalize(&readbuf);
+60 -36
View File
@@ -67,8 +67,14 @@ prepare_path_node(const char *text, pkgconf_list_t *dirlist, bool filter)
pkgconf_path_t *node; pkgconf_path_t *node;
pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_append(&pathbuf, text); if (!pkgconf_buffer_append(&pathbuf, text))
pkgconf_path_relocate(&pathbuf); return NULL;
if (!pkgconf_path_relocate(&pathbuf))
{
pkgconf_buffer_finalize(&pathbuf);
return NULL;
}
#ifdef PKGCONF_CACHE_INODES #ifdef PKGCONF_CACHE_INODES
struct stat st; struct stat st;
@@ -267,7 +273,9 @@ pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
if (path == NULL) if (path == NULL)
return false; return false;
pkgconf_buffer_append(&relocated, path); if (!pkgconf_buffer_append(&relocated, path))
return false;
cpath = pkgconf_buffer_str(&relocated); cpath = pkgconf_buffer_str(&relocated);
if (pkgconf_path_relocate(&relocated)) if (pkgconf_path_relocate(&relocated))
@@ -400,32 +408,32 @@ pkgconf_path_free(pkgconf_list_t *dirlist)
pkgconf_list_zero(dirlist); pkgconf_list_zero(dirlist);
} }
static char * /*
normpath(const pkgconf_buffer_t *pathbuf) * !doc
*
* .. c:function:: void pkgconf_path_normalize_separators(char *path)
*
* Rewrites a real OS path into pkgconf's canonical internal form, in which
* the platform directory separator is always represented as ``/``. On POSIX
* this is a no-op (a backslash is an ordinary filename character); on Windows
* it maps ``\`` to ``/``. Runtime-injected paths (search paths, sysroot,
* build root, prefix, pcfiledir) are normalized this way so that later path
* comparisons -- sysroot injection and system-directory filtering -- are all
* made on a consistent basis.
*
* :param char* path: The path to normalize in place.
* :return: nothing
*/
void
pkgconf_path_normalize_separators(char *path)
{ {
if (!pathbuf || pkgconf_buffer_len(pathbuf) == 0) #ifdef _WIN32
return NULL; for (; *path != '\0'; path++)
if (*path == PKG_DIR_SEP_S)
const char *path = pkgconf_buffer_str(pathbuf); *path = '/';
char *copy = strdup(path); #else
if (NULL == copy) (void) path;
return NULL; #endif
char *ptr = copy;
for (int ii = 0; copy[ii]; ii++)
{
*ptr++ = path[ii];
if ('/' == path[ii])
{
ii++;
while ('/' == path[ii])
ii++;
ii--;
}
}
*ptr = '\0';
return copy;
} }
/* /*
@@ -433,7 +441,8 @@ normpath(const pkgconf_buffer_t *pathbuf)
* *
* .. c:function:: bool pkgconf_path_relocate(pkgconf_buffer_t *buf) * .. c:function:: bool pkgconf_path_relocate(pkgconf_buffer_t *buf)
* *
* Relocates a path, possibly calling normpath() on it. * Normalizes a path in place: folds the platform separator to '/' and
* collapses runs of '/'.
* *
* :param pkgconf_buffer_t* buf: The path to relocate. * :param pkgconf_buffer_t* buf: The path to relocate.
* :return: true on success, false on error * :return: true on success, false on error
@@ -442,15 +451,30 @@ normpath(const pkgconf_buffer_t *pathbuf)
bool bool
pkgconf_path_relocate(pkgconf_buffer_t *buf) pkgconf_path_relocate(pkgconf_buffer_t *buf)
{ {
char *tmpbuf; char *base = buf->base;
char *w;
const char *r;
if ((tmpbuf = normpath(buf)) != NULL) if (base == NULL || pkgconf_buffer_len(buf) == 0)
return true;
/* fold the platform separator to '/' before collapsing runs, so that a
* mix of '\' and '/' (as seen on Windows) is treated uniformly. */
pkgconf_path_normalize_separators(base);
/* collapse runs of '/' in place; the result never grows, so w <= r always */
w = base;
for (r = base; *r != '\0'; r++)
{ {
pkgconf_buffer_reset(buf); *w++ = *r;
pkgconf_buffer_append(buf, tmpbuf); if (*r == '/')
free(tmpbuf); while (r[1] == '/')
r++;
} }
*w = '\0';
buf->end = w;
return true; return true;
} }
@@ -474,7 +498,7 @@ pkgconf_path_trim_basename(pkgconf_buffer_t *buf)
return false; return false;
sep = strrchr(buf->base, PKG_DIR_SEP_S); sep = strrchr(buf->base, PKG_DIR_SEP_S);
#ifdef _WIN32 #if defined(_WIN32) || defined(__OS2__)
char *sep2 = strrchr(buf->base, '/'); char *sep2 = strrchr(buf->base, '/');
if (sep2 != NULL && (sep == NULL || sep2 > sep)) if (sep2 != NULL && (sep == NULL || sep2 > sep))
sep = sep2; sep = sep2;
@@ -507,7 +531,7 @@ pkgconf_path_find_basename(const char *path)
const char *sep; const char *sep;
sep = strrchr(path, PKG_DIR_SEP_S); sep = strrchr(path, PKG_DIR_SEP_S);
#ifdef _WIN32 #if defined(_WIN32) || defined(__OS2__)
const char *sep2 = strrchr(path, '/'); const char *sep2 = strrchr(path, '/');
if (sep2 != NULL && (sep == NULL || sep2 > sep)) if (sep2 != NULL && (sep == NULL || sep2 > sep))
sep = sep2; sep = sep2;
+14 -7
View File
@@ -53,11 +53,9 @@ build_default_search_path(pkgconf_list_t* dirlist)
* https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea * https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea
*/ */
int sizepath = GetModuleFileName(NULL, namebuf, sizeof namebuf - 1); int sizepath = GetModuleFileName(NULL, namebuf, sizeof namebuf - 1);
char * winslash;
namebuf[sizepath] = '\0'; namebuf[sizepath] = '\0';
while ((winslash = strchr(namebuf, '\\')) != NULL) pkgconf_path_normalize_separators(namebuf);
*winslash = '/';
p = strrchr(namebuf, '/'); p = strrchr(namebuf, '/');
if (p == NULL) if (p == NULL)
@@ -69,7 +67,7 @@ build_default_search_path(pkgconf_list_t* dirlist)
pkgconf_buffer_append_fmt(&pathbuf, "%s/../lib/pkgconfig", namebuf); pkgconf_buffer_append_fmt(&pathbuf, "%s/../lib/pkgconfig", namebuf);
pkgconf_path_add(pkgconf_buffer_str(&pathbuf), dirlist, true); pkgconf_path_add(pkgconf_buffer_str(&pathbuf), dirlist, true);
pkgconf_buffer_reset(&pathbuf); pkgconf_buffer_rewind(&pathbuf);
pkgconf_buffer_append_fmt(&pathbuf, "%s/../share/pkgconfig", namebuf); pkgconf_buffer_append_fmt(&pathbuf, "%s/../share/pkgconfig", namebuf);
pkgconf_path_add(pkgconf_buffer_str(&pathbuf), dirlist, true); pkgconf_path_add(pkgconf_buffer_str(&pathbuf), dirlist, true);
@@ -275,11 +273,20 @@ load_personality_with_path(const char *path, const char *triplet, bool datadir)
/* if triplet is null, assume that path is a direct path to the personality file */ /* if triplet is null, assume that path is a direct path to the personality file */
if (triplet == NULL) if (triplet == NULL)
pkgconf_buffer_append(&pathbuf, path); {
if (!pkgconf_buffer_append(&pathbuf, path))
return NULL;
}
else if (datadir) else if (datadir)
pkgconf_buffer_append_fmt(&pathbuf, "%s/pkgconfig/personality.d/%s.personality", path, triplet); {
if (!pkgconf_buffer_append_fmt(&pathbuf, "%s/pkgconfig/personality.d/%s.personality", path, triplet))
return NULL;
}
else else
pkgconf_buffer_append_fmt(&pathbuf, "%s/%s.personality", path, triplet); {
if (!pkgconf_buffer_append_fmt(&pathbuf, "%s/%s.personality", path, triplet))
return NULL;
}
p = calloc(1, sizeof(pkgconf_cross_personality_t)); p = calloc(1, sizeof(pkgconf_cross_personality_t));
if (p == NULL) if (p == NULL)
+225 -89
View File
@@ -38,7 +38,8 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
pkgconf_pkg_traverse_func_t func, pkgconf_pkg_traverse_func_t func,
void *data, void *data,
int maxdepth, int maxdepth,
unsigned int skip_flags); unsigned int skip_flags,
unsigned int iter_flags);
static inline bool static inline bool
str_has_suffix(const char *str, const char *suffix) str_has_suffix(const char *str, const char *suffix)
@@ -61,7 +62,8 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_append(&buf, pkg->filename); if (!pkgconf_buffer_append(&buf, pkg->filename))
goto fail;
#ifndef _WIN32 #ifndef _WIN32
struct stat path_stat; struct stat path_stat;
@@ -73,8 +75,9 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
char sourcebuf[PKGCONF_ITEM_SIZE]; char sourcebuf[PKGCONF_ITEM_SIZE];
char *targetfilename, *targetdir; char *targetfilename, *targetdir;
pkgconf_buffer_reset(&pathbuf); pkgconf_buffer_rewind(&pathbuf);
pkgconf_buffer_append(&pathbuf, buf.base); if (!pkgconf_buffer_append(&pathbuf, buf.base))
goto fail;
targetfilename = strrchr(pathbuf.base, '/'); targetfilename = strrchr(pathbuf.base, '/');
if (targetfilename != NULL) if (targetfilename != NULL)
@@ -91,7 +94,7 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
targetdir = "."; targetdir = ".";
} }
#ifdef HAVE_DECL_READLINKAT #if HAVE_DECL_READLINKAT
const int dirfd = open(targetdir, O_DIRECTORY); const int dirfd = open(targetdir, O_DIRECTORY);
if (dirfd == -1) if (dirfd == -1)
break; break;
@@ -106,7 +109,7 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
break; break;
sourcebuf[len] = '\0'; sourcebuf[len] = '\0';
pkgconf_buffer_reset(&buf); pkgconf_buffer_rewind(&buf);
/* /*
* The logic here can be a bit tricky, so here's a table: * The logic here can be a bit tricky, so here's a table:
@@ -118,10 +121,18 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
* /bar (absolute) | /foo/link (absolute) | /bar (absolute) * /bar (absolute) | /foo/link (absolute) | /bar (absolute)
* ../bar (relative) | /foo/link (absolute) | /foo/../bar (relative) * ../bar (relative) | /foo/link (absolute) | /foo/../bar (relative)
*/ */
if ((sourcebuf[0] != '/') && strcmp(targetdir, ".")) if ((sourcebuf[0] != '/') &&
pkgconf_buffer_append_fmt(&buf, "%s/", targetdir); #ifdef __OS2__
!(sourcebuf[0] != '\0' && sourcebuf[1] == ':') &&
#endif
strcmp(targetdir, "."))
{
if (!pkgconf_buffer_append(&buf, targetdir) || !pkgconf_buffer_push_byte(&buf, '/'))
goto fail;
}
pkgconf_buffer_append(&buf, sourcebuf); if (!pkgconf_buffer_append(&buf, sourcebuf))
goto fail;
} }
#endif #endif
@@ -131,6 +142,11 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
pkgconf_path_trim_basename(&buf); pkgconf_path_trim_basename(&buf);
return pkgconf_buffer_freeze(&buf); return pkgconf_buffer_freeze(&buf);
fail:
pkgconf_buffer_finalize(&pathbuf);
pkgconf_buffer_finalize(&buf);
return NULL;
} }
typedef void (*pkgconf_pkg_parser_keyword_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value); typedef void (*pkgconf_pkg_parser_keyword_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value);
@@ -169,8 +185,9 @@ pkgconf_pkg_parser_bufferset_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg,
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf); if (pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf))
pkgconf_bufferset_extend(dest, &buf); pkgconf_bufferset_extend(dest, &buf);
pkgconf_buffer_finalize(&buf); pkgconf_buffer_finalize(&buf);
} }
@@ -195,7 +212,14 @@ pkgconf_pkg_parser_link_abi_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, c
p++; p++;
while (*p != '\0' && *p != ',' && !isspace((unsigned char) *p)) while (*p != '\0' && *p != ',' && !isspace((unsigned char) *p))
pkgconf_buffer_push_byte(&tag, (char) tolower((unsigned char) *p++)); {
if (!pkgconf_buffer_push_byte(&tag, (char) tolower((unsigned char) *p++)))
{
pkgconf_buffer_finalize(&tag);
free(expanded);
return;
}
}
if (pkgconf_buffer_len(&tag)) if (pkgconf_buffer_len(&tag))
pkgconf_bufferset_extend(dest, &tag); pkgconf_bufferset_extend(dest, &tag);
@@ -312,9 +336,10 @@ static void
pkgconf_pkg_evaluate_license_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) pkgconf_pkg_evaluate_license_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value)
{ {
pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
(void)keyword;
(void)warnprefix; if (!pkgconf_license_evaluate(client, pkg, dest, value, 0))
pkgconf_license_evaluate(client, pkg, dest, value, 0); pkgconf_warn(client, "%s: warning: license field '%s' could not be fully evaluated\n",
warnprefix, keyword);
} }
/* keep this in alphabetical order */ /* keep this in alphabetical order */
@@ -361,7 +386,9 @@ pkgconf_pkg_parser_keyword_set(void *opaque, const char *warnprefix, const char
static bool static bool
determine_prefix(const pkgconf_pkg_t *pkg, pkgconf_buffer_t *pathbuf) determine_prefix(const pkgconf_pkg_t *pkg, pkgconf_buffer_t *pathbuf)
{ {
pkgconf_buffer_append(pathbuf, pkg->filename); if (!pkgconf_buffer_append(pathbuf, pkg->filename))
return false;
pkgconf_path_relocate(pathbuf); pkgconf_path_relocate(pathbuf);
pkgconf_path_trim_basename(pathbuf); pkgconf_path_trim_basename(pathbuf);
@@ -396,18 +423,28 @@ convert_path_to_value(const char *path)
for (i = path; *i != '\0'; i++) for (i = path; *i != '\0'; i++)
{ {
if (*i == PKG_DIR_SEP_S) char c = *i;
pkgconf_buffer_push_byte(&buf, '/');
else if (*i == ' ') #ifdef _WIN32
if (c == PKG_DIR_SEP_S)
c = '/';
#endif
if (c == ' ')
{ {
pkgconf_buffer_push_byte(&buf, '\\'); if (!pkgconf_buffer_push_byte(&buf, '\\') ||
pkgconf_buffer_push_byte(&buf, ' '); !pkgconf_buffer_push_byte(&buf, ' '))
goto fail;
} }
else else if (!pkgconf_buffer_push_byte(&buf, c))
pkgconf_buffer_push_byte(&buf, *i); goto fail;
} }
return pkgconf_buffer_freeze(&buf); return pkgconf_buffer_freeze(&buf);
fail:
pkgconf_buffer_finalize(&buf);
return NULL;
} }
static void static void
@@ -440,22 +477,37 @@ canonicalize_path(char *buf)
static bool static bool
is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len) is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len)
{ {
#ifdef _WIN32 #if defined(_WIN32) || defined(__OS2__)
return !_strnicmp(path1, path2, path2_len); return !strncasecmp(path1, path2, path2_len);
#else #else
return !strncmp(path1, path2, path2_len); return !strncmp(path1, path2, path2_len);
#endif #endif
} }
static inline bool
is_path_separator(char c)
{
#ifdef _WIN32
return c == '/' || c == '\\';
#else
return c == '/';
#endif
}
static inline const char * static inline const char *
lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const char *keyword) lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const char *keyword)
{ {
char env_var[PKGCONF_ITEM_SIZE]; pkgconf_buffer_t env_var = PKGCONF_BUFFER_INITIALIZER;
const char *result;
char *c; char *c;
snprintf(env_var, sizeof env_var, "PKG_CONFIG_%s_%s", pkg_id, keyword); if (!pkgconf_buffer_join(&env_var, '_', "PKG_CONFIG", pkg_id, keyword, NULL))
{
pkgconf_buffer_finalize(&env_var);
return NULL;
}
for (c = env_var; *c; c++) for (c = env_var.base; *c != '\0'; c++)
{ {
*c = (char) toupper((unsigned char) *c); *c = (char) toupper((unsigned char) *c);
@@ -463,7 +515,11 @@ lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const ch
*c = '_'; *c = '_';
} }
return pkgconf_client_getenv(client, env_var); result = pkgconf_client_getenv(client, pkgconf_buffer_str(&env_var));
pkgconf_buffer_finalize(&env_var);
return result;
} }
static void static void
@@ -482,17 +538,17 @@ pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *k
value = env_content; value = env_content;
} }
if (!(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX))
{
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags);
return;
}
if (!pkgconf_buffer_append(&canonicalized_value, value)) if (!pkgconf_buffer_append(&canonicalized_value, value))
goto out; goto out;
canonicalize_path(canonicalized_value.base); canonicalize_path(canonicalized_value.base);
if (!(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX))
{
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags);
goto out;
}
/* Some pc files will use absolute paths for all of their directories /* Some pc files will use absolute paths for all of their directories
* which is broken when redefining the prefix. We try to outsmart the * which is broken when redefining the prefix. We try to outsmart the
* file and rewrite any directory that starts with the same prefix. * file and rewrite any directory that starts with the same prefix.
@@ -502,14 +558,29 @@ pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *k
if (pkgconf_buffer_len(&pkg->orig_prefix) != 0) if (pkgconf_buffer_len(&pkg->orig_prefix) != 0)
{ {
const char *op = pkgconf_buffer_str_or_empty(&pkg->orig_prefix); const char *op = pkgconf_buffer_str_or_empty(&pkg->orig_prefix);
const size_t oplen = pkgconf_buffer_len(&pkg->orig_prefix); const char *cv = pkgconf_buffer_str(&canonicalized_value);
size_t oplen = pkgconf_buffer_len(&pkg->orig_prefix);
if (is_path_prefix_equal(pkgconf_buffer_str(&canonicalized_value), op, oplen)) /* Match orig_prefix as a directory path: disregard any trailing
* separator so oplen describes the directory itself, and require
* the value to continue on a component boundary. This leaves the
* separator at cv[oplen] as the tail's leading character, which
* joins it to calculated_prefix (which never has a trailing one).
*/
while (oplen > 1 && is_path_separator(op[oplen - 1]))
oplen--;
if (is_path_prefix_equal(cv, op, oplen) &&
(cv[oplen] == '\0' || is_path_separator(cv[oplen])))
{ {
pkgconf_buffer_t newvalue = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t newvalue = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix)); if (!pkgconf_buffer_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix)) ||
pkgconf_buffer_append(&newvalue, pkgconf_buffer_str(&canonicalized_value) + oplen); !pkgconf_buffer_append(&newvalue, cv + oplen))
{
pkgconf_buffer_finalize(&newvalue);
goto out;
}
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, pkgconf_buffer_str(&newvalue), false, pkg->flags); pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, pkgconf_buffer_str(&newvalue), false, pkg->flags);
pkgconf_buffer_finalize(&newvalue); pkgconf_buffer_finalize(&newvalue);
@@ -529,8 +600,14 @@ pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *k
const char *relvalue = pkgconf_buffer_str(&pathbuf); const char *relvalue = pkgconf_buffer_str(&pathbuf);
char *prefix_value = convert_path_to_value(relvalue); char *prefix_value = convert_path_to_value(relvalue);
pkgconf_buffer_append(&pkg->orig_prefix, pkgconf_buffer_str(&canonicalized_value)); if (prefix_value == NULL ||
pkgconf_buffer_append(&pkg->calculated_prefix, prefix_value); !pkgconf_buffer_append(&pkg->orig_prefix, pkgconf_buffer_str(&canonicalized_value)) ||
!pkgconf_buffer_append(&pkg->calculated_prefix, prefix_value))
{
free(prefix_value);
pkgconf_buffer_finalize(&pathbuf);
goto out;
}
pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, prefix_value, false, pkg->flags); pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, prefix_value, false, pkg->flags);
free(prefix_value); free(prefix_value);
@@ -720,6 +797,10 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign
return NULL; return NULL;
} }
/* keep pc_filedir in canonical (forward-slash) form so it compares
* consistently against sysroot_dir and the search-path entries below */
pkgconf_path_normalize_separators(pkg->pc_filedir);
char *pc_filedir_value = convert_path_to_value(pkg->pc_filedir); char *pc_filedir_value = convert_path_to_value(pkg->pc_filedir);
pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pc_filedir_value, true, pkg->flags); pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pc_filedir_value, true, pkg->flags);
free(pc_filedir_value); free(pc_filedir_value);
@@ -770,7 +851,12 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign
{ {
pkgconf_buffer_t abibuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t abibuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_append(&abibuf, "c"); if (!pkgconf_buffer_append(&abibuf, "c"))
{
pkgconf_pkg_free(client, pkg);
return NULL;
}
pkgconf_bufferset_extend(&pkg->link_abi, &abibuf); pkgconf_bufferset_extend(&pkg->link_abi, &abibuf);
pkgconf_buffer_finalize(&abibuf); pkgconf_buffer_finalize(&abibuf);
} }
@@ -874,22 +960,35 @@ static inline pkgconf_pkg_t *
pkgconf_pkg_try_specific_path(pkgconf_client_t *client, const char *path, const char *name) pkgconf_pkg_try_specific_path(pkgconf_client_t *client, const char *path, const char *name)
{ {
pkgconf_pkg_t *pkg = NULL; pkgconf_pkg_t *pkg = NULL;
char locbuf[PKGCONF_ITEM_SIZE]; pkgconf_buffer_t locbuf = PKGCONF_BUFFER_INITIALIZER;
char uninst_locbuf[PKGCONF_ITEM_SIZE];
PKGCONF_TRACE(client, "trying path: %s for %s", path, name); PKGCONF_TRACE(client, "trying path: %s for %s", path, name);
snprintf(locbuf, sizeof locbuf, "%s%c%s" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name);
snprintf(uninst_locbuf, sizeof uninst_locbuf, "%s%c%s-uninstalled" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name);
if (!(client->flags & PKGCONF_PKG_PKGF_NO_UNINSTALLED)) if (!(client->flags & PKGCONF_PKG_PKGF_NO_UNINSTALLED))
pkg = pkgconf_pkg_new_from_path(client, uninst_locbuf, PKGCONF_PKG_PROPF_UNINSTALLED); {
pkgconf_buffer_append(&locbuf, path);
pkgconf_buffer_push_byte(&locbuf, PKG_DIR_SEP_S);
pkgconf_buffer_append(&locbuf, name);
pkgconf_buffer_append(&locbuf, "-uninstalled" PKG_CONFIG_EXT);
pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&locbuf), PKGCONF_PKG_PROPF_UNINSTALLED);
}
if (pkg == NULL) if (pkg == NULL)
pkg = pkgconf_pkg_new_from_path(client, locbuf, 0); {
pkgconf_buffer_rewind(&locbuf);
pkgconf_buffer_append(&locbuf, path);
pkgconf_buffer_push_byte(&locbuf, PKG_DIR_SEP_S);
pkgconf_buffer_append(&locbuf, name);
pkgconf_buffer_append(&locbuf, PKG_CONFIG_EXT);
pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&locbuf), 0);
}
if (pkg != NULL) if (pkg != NULL)
PKGCONF_TRACE(client, "found%s: %s", pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED ? " (uninstalled)" : "", uninst_locbuf); PKGCONF_TRACE(client, "found%s: %s", pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED ? " (uninstalled)" : "", pkgconf_buffer_str(&locbuf));
pkgconf_buffer_finalize(&locbuf);
return pkg; return pkg;
} }
@@ -910,9 +1009,13 @@ pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkg
for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir))
{ {
pkgconf_buffer_t filebuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t filebuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_pkg_t *pkg; pkgconf_pkg_t *pkg = NULL;
pkgconf_buffer_join(&filebuf, '/', path, dirent->d_name, NULL); if (!pkgconf_buffer_join(&filebuf, '/', path, dirent->d_name, NULL))
{
closedir(dir);
return NULL;
}
if (!str_has_suffix(pkgconf_buffer_str(&filebuf), PKG_CONFIG_EXT)) if (!str_has_suffix(pkgconf_buffer_str(&filebuf), PKG_CONFIG_EXT))
{ {
@@ -920,13 +1023,34 @@ pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkg
continue; continue;
} }
if (!(client->flags & PKGCONF_PKG_PKGF_NO_CACHE))
{
pkgconf_buffer_t idbuf = PKGCONF_BUFFER_INITIALIZER;
if (pkgconf_buffer_append(&idbuf, pkgconf_path_find_basename(pkgconf_buffer_str(&filebuf))))
{
char *idptr = strrchr(pkgconf_buffer_str(&idbuf), '.');
if (idptr != NULL)
*idptr = '\0';
pkg = pkgconf_cache_lookup(client, pkgconf_buffer_str(&idbuf));
}
pkgconf_buffer_finalize(&idbuf);
}
PKGCONF_TRACE(client, "trying file [%s]", pkgconf_buffer_str(&filebuf)); PKGCONF_TRACE(client, "trying file [%s]", pkgconf_buffer_str(&filebuf));
pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&filebuf), 0); if (pkg == NULL)
pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&filebuf), 0);
pkgconf_buffer_finalize(&filebuf); pkgconf_buffer_finalize(&filebuf);
if (pkg != NULL) if (pkg != NULL)
{ {
if (!(pkg->flags & PKGCONF_PKG_PROPF_CACHED) && !(client->flags & PKGCONF_PKG_PKGF_NO_CACHE))
pkgconf_cache_add(client, pkg);
if (func(pkg, data)) if (func(pkg, data))
{ {
outpkg = pkg; outpkg = pkg;
@@ -1523,7 +1647,8 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
pkgconf_pkg_traverse_func_t func, pkgconf_pkg_traverse_func_t func,
void *data, void *data,
int depth, int depth,
unsigned int skip_flags) unsigned int skip_flags,
unsigned int iter_flags)
{ {
unsigned int eflags = PKGCONF_PKG_ERRF_OK; unsigned int eflags = PKGCONF_PKG_ERRF_OK;
pkgconf_node_t *node, *next; pkgconf_node_t *node, *next;
@@ -1555,7 +1680,7 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
if((pkgdep->flags & PKGCONF_PKG_PROPF_ANCESTOR) != 0) if((pkgdep->flags & PKGCONF_PKG_PROPF_ANCESTOR) != 0)
{ {
/* In this case we have a circular reference. /* In this case we have a circular reference.
* We break that by deleteing the circular node from the * We break that by deleting the circular node from the
* the list, so that we dont create a situation where * the list, so that we dont create a situation where
* memory is leaked due to circular ownership. * memory is leaked due to circular ownership.
* i.e: A owns B owns A * i.e: A owns B owns A
@@ -1582,7 +1707,7 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
pkgconf_audit_log_dependency(client, pkgdep, depnode); pkgconf_audit_log_dependency(client, pkgdep, depnode);
eflags |= pkgconf_pkg_traverse_main(client, pkgdep, func, data, depth - 1, skip_flags); eflags |= pkgconf_pkg_traverse_main(client, pkgdep, func, data, depth - 1, skip_flags, iter_flags);
next: next:
pkgconf_pkg_unref(client, pkgdep); pkgconf_pkg_unref(client, pkgdep);
} }
@@ -1661,7 +1786,8 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
pkgconf_pkg_traverse_func_t func, pkgconf_pkg_traverse_func_t func,
void *data, void *data,
int maxdepth, int maxdepth,
unsigned int skip_flags) unsigned int skip_flags,
unsigned int iter_flags)
{ {
unsigned int eflags = PKGCONF_PKG_ERRF_OK; unsigned int eflags = PKGCONF_PKG_ERRF_OK;
@@ -1683,7 +1809,7 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
if ((root->flags & PKGCONF_PKG_PROPF_VIRTUAL) != PKGCONF_PKG_PROPF_VIRTUAL || (client->flags & PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) != PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) if ((root->flags & PKGCONF_PKG_PROPF_VIRTUAL) != PKGCONF_PKG_PROPF_VIRTUAL || (client->flags & PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) != PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL)
{ {
if (func != NULL) if (func != NULL)
func(client, root, data); func(client, root, data, iter_flags);
} }
if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS) && root->conflicts.head != NULL) if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS) && root->conflicts.head != NULL)
@@ -1696,7 +1822,7 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
} }
PKGCONF_TRACE(client, "%s: walking 'Requires' list", root->id); PKGCONF_TRACE(client, "%s: walking 'Requires' list", root->id);
eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth, skip_flags); eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth, skip_flags, iter_flags);
if (eflags != PKGCONF_PKG_ERRF_OK) if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags; return eflags;
@@ -1704,18 +1830,14 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
{ {
PKGCONF_TRACE(client, "%s: walking 'Requires.shared' list", root->id); PKGCONF_TRACE(client, "%s: walking 'Requires.shared' list", root->id);
eflags = pkgconf_pkg_walk_list(client, root, &root->requires_shared, func, data, maxdepth, skip_flags); eflags = pkgconf_pkg_walk_list(client, root, &root->requires_shared, func, data, maxdepth, skip_flags, iter_flags);
if (eflags != PKGCONF_PKG_ERRF_OK) if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags; return eflags;
} }
PKGCONF_TRACE(client, "%s: walking 'Requires.private' list", root->id); PKGCONF_TRACE(client, "%s: walking 'Requires.private' list", root->id);
/* XXX: ugly */ eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth, skip_flags, iter_flags | PKGCONF_PKG_ITERF_PRIVATE);
client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE;
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) if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags; return eflags;
@@ -1730,8 +1852,7 @@ pkgconf_pkg_traverse(pkgconf_client_t *client,
int maxdepth, int maxdepth,
unsigned int skip_flags) unsigned int skip_flags)
{ {
if (root->flags & PKGCONF_PKG_PROPF_VIRTUAL) client->serial++;
client->serial++;
if ((client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) == 0) if ((client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) == 0)
{ {
@@ -1742,45 +1863,51 @@ pkgconf_pkg_traverse(pkgconf_client_t *client,
// Skip shared deps in static mode // Skip shared deps in static mode
skip_flags |= PKGCONF_PKG_DEPF_SHARED; skip_flags |= PKGCONF_PKG_DEPF_SHARED;
return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags); return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags, PKGCONF_PKG_ITERF_NONE);
} }
static void static void
pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
pkgconf_list_t *list = data; pkgconf_fragment_cursor_t *cursor = data;
pkgconf_node_t *node; pkgconf_node_t *node;
(void) iter_flags;
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node)
{ {
pkgconf_fragment_t *frag = node->data; pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_copy(client, list, frag, false); pkgconf_fragment_copy_cursor(client, cursor, frag, false);
} }
} }
static void static void
pkgconf_pkg_cflags_private_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) pkgconf_pkg_cflags_private_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
pkgconf_list_t *list = data; pkgconf_fragment_cursor_t *cursor = data;
pkgconf_node_t *node; pkgconf_node_t *node;
(void) iter_flags;
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_private.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_private.head, node)
{ {
pkgconf_fragment_t *frag = node->data; pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_copy(client, list, frag, true); pkgconf_fragment_copy_cursor(client, cursor, frag, true);
} }
} }
static void static void
pkgconf_pkg_cflags_shared_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) pkgconf_pkg_cflags_shared_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
pkgconf_list_t *list = data; pkgconf_fragment_cursor_t *cursor = data;
pkgconf_node_t *node; pkgconf_node_t *node;
(void) iter_flags;
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_shared.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_shared.head, node)
{ {
pkgconf_fragment_t *frag = node->data; pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_copy(client, list, frag, true); pkgconf_fragment_copy_cursor(client, cursor, frag, true);
} }
} }
@@ -1804,37 +1931,41 @@ pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t
unsigned int eflag; unsigned int eflag;
unsigned int skip_flags = (client->flags & PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS) == 0 ? PKGCONF_PKG_DEPF_INTERNAL : 0; unsigned int skip_flags = (client->flags & PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS) == 0 ? PKGCONF_PKG_DEPF_INTERNAL : 0;
pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER;
pkgconf_fragment_cursor_t cursor;
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, &frags, maxdepth, skip_flags); pkgconf_fragment_cursor_init(&cursor, &frags);
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, &cursor, maxdepth, skip_flags);
if (eflag == PKGCONF_PKG_ERRF_OK) if (eflag == PKGCONF_PKG_ERRF_OK)
{ {
if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)
{ {
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &frags, maxdepth, skip_flags); eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &cursor, maxdepth, skip_flags);
} }
else else
{ {
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_shared_collect, &frags, maxdepth, skip_flags); eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_shared_collect, &cursor, maxdepth, skip_flags);
} }
} }
pkgconf_fragment_cursor_deinit(&cursor);
if (eflag != PKGCONF_PKG_ERRF_OK) if (eflag != PKGCONF_PKG_ERRF_OK)
{ {
pkgconf_fragment_free(&frags); pkgconf_fragment_free(&frags);
return eflag; return eflag;
} }
pkgconf_fragment_copy_list(client, list, &frags); pkgconf_list_splice(list, &frags);
pkgconf_fragment_free(&frags);
return eflag; return eflag;
} }
static void static void
pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
pkgconf_list_t *list = data; pkgconf_fragment_cursor_t *cursor = data;
pkgconf_node_t *node; pkgconf_node_t *node;
if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
@@ -1843,7 +1974,7 @@ pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *dat
PKGCONF_FOREACH_LIST_ENTRY(pkg->libs.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->libs.head, node)
{ {
pkgconf_fragment_t *frag = node->data; pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_copy(client, list, frag, (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) != 0); pkgconf_fragment_copy_cursor(client, cursor, frag, (iter_flags & PKGCONF_PKG_ITERF_PRIVATE) != 0);
} }
if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS)
@@ -1851,7 +1982,7 @@ pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *dat
PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_private.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_private.head, node)
{ {
pkgconf_fragment_t *frag = node->data; pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_copy(client, list, frag, true); pkgconf_fragment_copy_cursor(client, cursor, frag, true);
} }
} }
else else
@@ -1859,7 +1990,7 @@ pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *dat
PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_shared.head, node) PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_shared.head, node)
{ {
pkgconf_fragment_t *frag = node->data; pkgconf_fragment_t *frag = node->data;
pkgconf_fragment_copy(client, list, frag, true); pkgconf_fragment_copy_cursor(client, cursor, frag, true);
} }
} }
} }
@@ -1882,8 +2013,11 @@ unsigned int
pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth)
{ {
unsigned int eflag; unsigned int eflag;
pkgconf_fragment_cursor_t cursor;
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, list, maxdepth, 0); pkgconf_fragment_cursor_init(&cursor, list);
eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, &cursor, maxdepth, 0);
pkgconf_fragment_cursor_deinit(&cursor);
if (eflag != PKGCONF_PKG_ERRF_OK) if (eflag != PKGCONF_PKG_ERRF_OK)
{ {
@@ -1895,11 +2029,13 @@ pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *
} }
static void static void
pkgconf_pkg_link_abi_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) pkgconf_pkg_link_abi_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
pkgconf_list_t *list = data; pkgconf_list_t *list = data;
pkgconf_node_t *node; pkgconf_node_t *node;
(void) iter_flags;
if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
return; return;
+42 -17
View File
@@ -52,11 +52,22 @@ pkgconf_queue_push_dependency(pkgconf_list_t *list, const pkgconf_dependency_t *
if (pkgq == NULL) if (pkgq == NULL)
return; return;
pkgconf_buffer_append(&depbuf, dep->package); if (!pkgconf_buffer_append(&depbuf, dep->package) ||
if (dep->version != NULL) (dep->version != NULL &&
pkgconf_buffer_append_fmt(&depbuf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version); !pkgconf_buffer_append_fmt(&depbuf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version)))
{
pkgconf_buffer_finalize(&depbuf);
free(pkgq);
return;
}
pkgq->package = pkgconf_buffer_freeze(&depbuf); pkgq->package = pkgconf_buffer_freeze(&depbuf);
if (pkgq->package == NULL)
{
free(pkgq);
return;
}
pkgconf_node_insert_tail(&pkgq->iter, pkgq, list); pkgconf_node_insert_tail(&pkgq->iter, pkgq, list);
} }
@@ -80,6 +91,12 @@ pkgconf_queue_push(pkgconf_list_t *list, const char *package)
return; return;
pkgq->package = strdup(package); pkgq->package = strdup(package);
if (pkgq->package == NULL)
{
free(pkgq);
return;
}
pkgconf_node_insert_tail(&pkgq->iter, pkgq, list); pkgconf_node_insert_tail(&pkgq->iter, pkgq, list);
} }
@@ -137,8 +154,10 @@ pkgconf_queue_free(pkgconf_list_t *list)
} }
static void static void
pkgconf_queue_mark_public(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) pkgconf_queue_mark_public(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags)
{ {
(void) iter_flags;
if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
{ {
pkgconf_list_t *list = data; pkgconf_list_t *list = data;
@@ -161,13 +180,15 @@ static unsigned int
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client, pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
pkgconf_pkg_t *root, pkgconf_pkg_t *root,
void *data, void *data,
int maxdepth); int maxdepth,
unsigned int iter_flags);
static inline unsigned int static inline unsigned int
pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client, pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client,
pkgconf_list_t *deplist, pkgconf_list_t *deplist,
void *data, void *data,
int depth) int depth,
unsigned int iter_flags)
{ {
unsigned int eflags = PKGCONF_PKG_ERRF_OK; unsigned int eflags = PKGCONF_PKG_ERRF_OK;
pkgconf_node_t *node; pkgconf_node_t *node;
@@ -191,12 +212,12 @@ pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client,
if (pkg->serial == client->serial) if (pkg->serial == client->serial)
continue; continue;
if (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) if (iter_flags & PKGCONF_PKG_ITERF_PRIVATE)
pkg->flags |= PKGCONF_PKG_PROPF_VISITED_PRIVATE; pkg->flags |= PKGCONF_PKG_PROPF_VISITED_PRIVATE;
else else
pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE; pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE;
eflags |= pkgconf_queue_collect_dependencies_main(client, pkg, data, depth - 1); eflags |= pkgconf_queue_collect_dependencies_main(client, pkg, data, depth - 1, iter_flags);
flattened_dep = pkgconf_dependency_copy(client, dep); flattened_dep = pkgconf_dependency_copy(client, dep);
if (flattened_dep == NULL) if (flattened_dep == NULL)
@@ -215,7 +236,8 @@ static unsigned int
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client, pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
pkgconf_pkg_t *root, pkgconf_pkg_t *root,
void *data, void *data,
int maxdepth) int maxdepth,
unsigned int iter_flags)
{ {
unsigned int eflags = PKGCONF_PKG_ERRF_OK; unsigned int eflags = PKGCONF_PKG_ERRF_OK;
@@ -233,24 +255,20 @@ pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
{ {
PKGCONF_TRACE(client, "%s: collecting shared dependencies, level %d", root->id, maxdepth); PKGCONF_TRACE(client, "%s: collecting shared dependencies, level %d", root->id, maxdepth);
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_shared, data, maxdepth); eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_shared, data, maxdepth, iter_flags);
if (eflags != PKGCONF_PKG_ERRF_OK) if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags; return eflags;
} }
PKGCONF_TRACE(client, "%s: collecting private dependencies, level %d", root->id, maxdepth); PKGCONF_TRACE(client, "%s: collecting private dependencies, level %d", root->id, maxdepth);
/* XXX: ugly */ eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth, iter_flags | PKGCONF_PKG_ITERF_PRIVATE);
const unsigned int saved_flags = client->flags;
client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE;
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth);
client->flags = saved_flags;
if (eflags != PKGCONF_PKG_ERRF_OK) if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags; return eflags;
PKGCONF_TRACE(client, "%s: collecting public dependencies, level %d", root->id, maxdepth); PKGCONF_TRACE(client, "%s: collecting public dependencies, level %d", root->id, maxdepth);
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->required, data, maxdepth); eflags = pkgconf_queue_collect_dependencies_walk(client, &root->required, data, maxdepth, iter_flags);
if (eflags != PKGCONF_PKG_ERRF_OK) if (eflags != PKGCONF_PKG_ERRF_OK)
return eflags; return eflags;
@@ -266,7 +284,7 @@ pkgconf_queue_collect_dependencies(pkgconf_client_t *client,
int maxdepth) int maxdepth)
{ {
++client->serial; ++client->serial;
return pkgconf_queue_collect_dependencies_main(client, root, data, maxdepth); return pkgconf_queue_collect_dependencies_main(client, root, data, maxdepth, PKGCONF_PKG_ITERF_NONE);
} }
static inline unsigned int static inline unsigned int
@@ -306,6 +324,13 @@ pkgconf_queue_collect_conflicts(pkgconf_client_t *client,
} }
flattened_conflict->why = strdup(pkg->id); flattened_conflict->why = strdup(pkg->id);
if (flattened_conflict->why == NULL)
{
eflags |= PKGCONF_PKG_ERRF_DEPGRAPH_BREAK;
pkgconf_dependency_unref(client, flattened_conflict);
continue;
}
pkgconf_node_insert(&flattened_conflict->iter, flattened_conflict, &world->conflicts); pkgconf_node_insert(&flattened_conflict->iter, flattened_conflict, &world->conflicts);
} }
} }
+17 -9
View File
@@ -33,10 +33,15 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#ifdef _WIN32 #if defined(_WIN32) || defined(__OS2__)
# define WIN32_LEAN_AND_MEAN # ifdef _WIN32
# include <windows.h> # define WIN32_LEAN_AND_MEAN
# include <windows.h>
# else
# include <unistd.h> /* readlink */
# endif
# include <malloc.h> # include <malloc.h>
# include <io.h> /* for _setmode() */ # include <io.h> /* for _setmode() */
# include <fcntl.h> # include <fcntl.h>
@@ -62,7 +67,7 @@
# define SIZE_FMT_SPECIFIER "%u" # define SIZE_FMT_SPECIFIER "%u"
# endif # endif
# endif # endif
# ifndef ssize_t # if !(defined(ssize_t) || defined(__OS2__))
# ifndef __MINGW32__ # ifndef __MINGW32__
# include <BaseTsd.h> # include <BaseTsd.h>
# else # else
@@ -70,7 +75,7 @@
# endif # endif
# define ssize_t SSIZE_T # define ssize_t SSIZE_T
# endif # endif
# ifndef __MINGW32__ # if !(defined (__MINGW32__) || defined(__OS2__))
# include "win-dirent.h" # include "win-dirent.h"
# else # else
# include <dirent.h> # include <dirent.h>
@@ -78,9 +83,13 @@
# define PKGCONF_ITEM_SIZE (_MAX_PATH + 1024) # define PKGCONF_ITEM_SIZE (_MAX_PATH + 1024)
# define PKG_CONFIG_PATH_SEP_S ";" # define PKG_CONFIG_PATH_SEP_S ";"
# define PKG_DIR_SEP_S '\\' # define PKG_DIR_SEP_S '\\'
# define strcasecmp _stricmp # ifndef __OS2__
# define strncasecmp _strnicmp # define strcasecmp _stricmp
# define realpath(N,R) _fullpath((R),(N),_MAX_PATH) # define strncasecmp _strnicmp
# define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
# else
# define _setmode(h, m) if (!isatty((h))) setmode((h), (m))
# endif
#else #else
# define PATH_DEV_NULL "/dev/null" # define PATH_DEV_NULL "/dev/null"
# define SIZE_FMT_SPECIFIER "%zu" # define SIZE_FMT_SPECIFIER "%zu"
@@ -89,7 +98,6 @@
# endif # endif
# include <dirent.h> # include <dirent.h>
# include <unistd.h> # include <unistd.h>
# include <limits.h>
# include <strings.h> # include <strings.h>
# include <fcntl.h> // open # include <fcntl.h> // open
# include <libgen.h> // basename/dirname # include <libgen.h> // basename/dirname
+37 -16
View File
@@ -73,7 +73,7 @@ pkgconf_tuple_find_global(pkgconf_client_t *client, const char *key)
v = pkgconf_variable_find(&client->global_vars, key); v = pkgconf_variable_find(&client->global_vars, key);
pkgconf_buffer_reset(&client->_scratch_buffer); pkgconf_buffer_rewind(&client->_scratch_buffer);
(void) pkgconf_variable_eval(client, &client->global_vars, v, &client->_scratch_buffer, &saw_sysroot); (void) pkgconf_variable_eval(client, &client->global_vars, v, &client->_scratch_buffer, &saw_sysroot);
return pkgconf_buffer_str_or_empty(&client->_scratch_buffer); return pkgconf_buffer_str_or_empty(&client->_scratch_buffer);
@@ -195,28 +195,42 @@ pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const ch
return NULL; return NULL;
} }
v->flags = flags;
if (!parse) if (!parse)
{ {
pkgconf_buffer_reset(&v->bcbuf); if (!pkgconf_bytecode_emit_text(&rhs_bcbuf, dequote_value, strlen(dequote_value)))
pkgconf_bytecode_emit_text(&v->bcbuf, dequote_value, strlen(dequote_value)); {
pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); pkgconf_buffer_finalize(&rhs_bcbuf);
free(dequote_value);
return NULL;
}
free(dequote_value);
}
else
{
if (!pkgconf_bytecode_compile(&rhs_bcbuf, dequote_value))
{
pkgconf_buffer_finalize(&rhs_bcbuf);
free(dequote_value);
return NULL;
}
free(dequote_value); free(dequote_value);
return (pkgconf_tuple_t *) v;
} }
pkgconf_bytecode_compile(&rhs_bcbuf, dequote_value);
free(dequote_value);
/* ugh, we are doing var=${var}/foo stuff */ /* ugh, we are doing var=${var}/foo stuff */
if (pkgconf_bytecode_references_var(&rhs_bcbuf, key)) if (parse && pkgconf_bytecode_references_var(&rhs_bcbuf, key))
{ {
pkgconf_buffer_t old_bcbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t old_bcbuf = PKGCONF_BUFFER_INITIALIZER;
pkgconf_buffer_t new_bcbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t new_bcbuf = PKGCONF_BUFFER_INITIALIZER;
/* preserve the old bytecode */ /* preserve the old bytecode */
pkgconf_buffer_copy(&v->bcbuf, &old_bcbuf); if (!pkgconf_buffer_copy(&v->bcbuf, &old_bcbuf))
{
pkgconf_buffer_finalize(&old_bcbuf);
pkgconf_buffer_finalize(&rhs_bcbuf);
return NULL;
}
/* splice the selfrefs, using the old bytecode instead of ${var} */ /* splice the selfrefs, using the old bytecode instead of ${var} */
if (!pkgconf_bytecode_rewrite_selfrefs(&new_bcbuf, &rhs_bcbuf, key, &old_bcbuf)) if (!pkgconf_bytecode_rewrite_selfrefs(&new_bcbuf, &rhs_bcbuf, key, &old_bcbuf))
@@ -229,15 +243,22 @@ pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const ch
} }
/* copy the spliced bytecode back to &rhs_bcbuf, replacing its contents */ /* copy the spliced bytecode back to &rhs_bcbuf, replacing its contents */
pkgconf_buffer_copy(&new_bcbuf, &rhs_bcbuf); if (!pkgconf_buffer_copy(&new_bcbuf, &rhs_bcbuf))
{
pkgconf_buffer_finalize(&old_bcbuf);
pkgconf_buffer_finalize(&new_bcbuf);
pkgconf_buffer_finalize(&rhs_bcbuf);
return NULL;
}
pkgconf_buffer_finalize(&old_bcbuf); pkgconf_buffer_finalize(&old_bcbuf);
pkgconf_buffer_finalize(&new_bcbuf); pkgconf_buffer_finalize(&new_bcbuf);
} }
pkgconf_buffer_copy(&rhs_bcbuf, &v->bcbuf); pkgconf_buffer_finalize(&v->bcbuf);
v->bcbuf = rhs_bcbuf;
v->flags = flags;
pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf);
pkgconf_buffer_finalize(&rhs_bcbuf);
return (pkgconf_tuple_t *) v; return (pkgconf_tuple_t *) v;
} }
@@ -267,7 +288,7 @@ pkgconf_tuple_find(pkgconf_client_t *client, pkgconf_list_t *list, const char *k
if (v == NULL) if (v == NULL)
v = pkgconf_variable_find(&client->global_vars, key); v = pkgconf_variable_find(&client->global_vars, key);
pkgconf_buffer_reset(&client->_scratch_buffer); pkgconf_buffer_rewind(&client->_scratch_buffer);
(void) pkgconf_variable_eval(client, list, v, &client->_scratch_buffer, NULL); (void) pkgconf_variable_eval(client, list, v, &client->_scratch_buffer, NULL);
+34 -8
View File
@@ -32,20 +32,18 @@ pkgconf_variable_t *
pkgconf_variable_new(const char *key) pkgconf_variable_new(const char *key)
{ {
pkgconf_variable_t *v; pkgconf_variable_t *v;
size_t keylen;
if (key == NULL) if (key == NULL)
return NULL; return NULL;
v = calloc(1, sizeof(*v)); keylen = strlen(key);
v = calloc(1, sizeof(*v) + keylen + 1);
if (v == NULL) if (v == NULL)
return NULL; return NULL;
v->key = strdup(key); v->key = (char *)(v + 1);
if (v->key == NULL) memcpy(v->key, key, keylen + 1);
{
free(v);
return NULL;
}
return v; return v;
} }
@@ -57,7 +55,6 @@ pkgconf_variable_free(pkgconf_variable_t *v)
return; return;
pkgconf_buffer_finalize(&v->bcbuf); pkgconf_buffer_finalize(&v->bcbuf);
free(v->key);
free(v); free(v);
} }
@@ -160,3 +157,32 @@ pkgconf_variable_eval_str(pkgconf_client_t *client,
return pkgconf_buffer_freeze(&out); return pkgconf_buffer_freeze(&out);
} }
char *
pkgconf_variable_eval_name(pkgconf_client_t *client,
const pkgconf_list_t *vars,
const char *varname)
{
pkgconf_buffer_t varbuf = PKGCONF_BUFFER_INITIALIZER;
const pkgconf_buffer_t *sysroot_dir = PKGCONF_BUFFER_FROM_STR(client->sysroot_dir);
bool saw_sysroot = false;
pkgconf_variable_t *v;
pkgconf_bytecode_eval_ctx_t ctx = {
.client = client,
.vars = vars,
};
v = pkgconf_bytecode_eval_lookup_var(&ctx, varname, strlen(varname));
(void) pkgconf_variable_eval(client, vars, v, &varbuf, &saw_sysroot);
if (!(client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES) &&
!saw_sysroot && pkgconf_path_is_plausible(&varbuf))
{
/* if sysroot is set, and value does not already begin with sysroot */
if (!pkgconf_buffer_has_prefix(&varbuf, sysroot_dir))
pkgconf_buffer_prepend(&varbuf, pkgconf_buffer_str_or_empty(sysroot_dir));
}
return pkgconf_buffer_freeze(&varbuf);
}
+138
View File
@@ -0,0 +1,138 @@
.\" Copyright (c) 2026 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.
.Dd June 28, 2026
.Dt PCCRITIC 1
.Os
.Sh NAME
.Nm pccritic
.Nd a quality scorer for pkg-config files
.Sh SYNOPSIS
.Nm
.Op Ar options
.Ar module-or-file ...
.Sh DESCRIPTION
.Nm
inspects
.Xr pc 5
files and reports quality findings, assigning each file a score from 0 to 100
and a letter grade from A to F.
It is intended both as an interactive aid for package authors and as a check
that can be run in continuous integration.
.Pp
Each command-line argument is treated as a target.
If an argument contains a slash or ends in
.Pa .pc
it is interpreted as a path to a file; otherwise it is resolved as a module
name from the search path, exactly as
.Xr pkgconf 1
would resolve it.
A file that
.Xr pkgconf 1
refuses to load because it omits a required field is still scanned directly so
that the most broken files can be scored.
.Pp
Findings are classified by severity.
The score begins at 100 and each finding subtracts a fixed penalty: 25 for a
.Em critical
finding, 10 for a
.Em major
finding, 4 for a
.Em minor
finding, and 1 for an
.Em info
finding.
The result is clamped to the range 0 to 100.
Grades are assigned as A for 90 and above, B for 80, C for 70, D for 60, and F
below 60.
.Pp
The checks cover required and recommended metadata, version sanity,
relocatability of the
.Ic libdir
and
.Ic includedir
variables, hygiene of the
.Ic Cflags
and
.Ic Libs
fields, the
.Ic Requires
and
.Ic Requires.private
relationship, and basic file-formatting style.
.Pp
The
.Ar options
are as follows:
.Bl -tag -width indent
.It Fl -about
Print the version number, the Copyright notice, and the license of the
.Nm
program to standard output and exit.
.It Fl -version
Print the version number of the
.Nm
program to standard output and exit.
.It Fl -help
Print a short usage summary to standard output and exit.
.It Fl -quiet
Print only the score and grade for each target, one per line, instead of the
full list of findings.
.It Fl -min-score Ar n
Exit with a non-zero status if any target scores below
.Ar n .
This is useful for failing a continuous-integration job when a file's quality
regresses below a threshold.
.It Fl -color Ns Op = Ns Ar when
Control colorized output.
.Ar when
may be
.Cm auto
(the default),
.Cm always ,
or
.Cm never .
When
.Cm auto ,
color is enabled only when standard output is a terminal and the
.Ev NO_COLOR
environment variable is not set.
Giving
.Fl -color
without a value is equivalent to
.Cm always .
.It Fl -define-variable Ns = Ns Ar varname Ns = Ns Ar value
Define
.Ar varname
as
.Ar value .
This affects how variables in the inspected file are expanded.
.El
.Sh EXIT STATUS
.Nm
exits 0 on success.
It exits non-zero if a target could not be loaded, if the command line is
invalid, or if
.Fl -min-score
was given and a target scored below the threshold.
.Sh EXAMPLES
Score an installed module by name:
.Pp
.Dl $ pccritic zlib
.Pp
Score a file before installation and fail if it grades below a C:
.Pp
.Dl $ pccritic --min-score 70 ./mylib.pc
.Pp
Summarize every file in a directory:
.Pp
.Dl $ pccritic --quiet /usr/lib/pkgconfig/*.pc
.Sh SEE ALSO
.Xr pkgconf 1 ,
.Xr pc 5
+36 -11
View File
@@ -7,7 +7,7 @@
.\" This software is provided 'as is' and without any warranty, express or .\" 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 .\" implied. In no event shall the authors be liable for any damages arising
.\" from the use of this software. .\" from the use of this software.
.Dd June 23, 2026 .Dd September 8, 2026
.Dt PKGCONF 1 .Dt PKGCONF 1
.Os .Os
.Sh NAME .Sh NAME
@@ -117,8 +117,7 @@ options:
.It .It
Single-module output options: Single-module output options:
.Fl -path , .Fl -path ,
.Fl -print-variables , .Fl -print-variables :
.Fl -variable :
If any of these options is specified, only the first If any of these options is specified, only the first
.Ar module .Ar module
argument is used, all other arguments are silently ignored, argument is used, all other arguments are silently ignored,
@@ -128,8 +127,9 @@ Depth-one output options:
.Fl -print-provides , .Fl -print-provides ,
.Fl -modversion , .Fl -modversion ,
.Fl -print-requires , .Fl -print-requires ,
.Fl -print-requires-private ,
and and
.Fl -print-requires-private : .Fl -variable :
If any of these options is specified, only modules If any of these options is specified, only modules
explicitly specified on the command line are inspected explicitly specified on the command line are inspected
and no dependency resolution is attempted. and no dependency resolution is attempted.
@@ -288,6 +288,19 @@ Most other options and all command line arguments are ignored.
Ignore Ignore
.Sq Conflicts .Sq Conflicts
rules in modules. rules in modules.
This option is implied by the options which merely report metadata about the
requested modules rather than combining them into a build, namely
.Fl -license ,
.Fl -license-file ,
.Fl -modversion ,
.Fl -path ,
.Fl -print-provides ,
.Fl -print-requires ,
.Fl -print-requires-private ,
.Fl -print-variables ,
.Fl -source ,
and
.Fl -variable .
.It Fl -keep-system-cflags , Fl -keep-system-libs .It Fl -keep-system-cflags , Fl -keep-system-libs
Keep CFLAGS or linker flag fragments that would be filtered due to being Keep CFLAGS or linker flag fragments that would be filtered due to being
included by default in the compiler. included by default in the compiler.
@@ -384,6 +397,12 @@ is greater than the requested
number. number.
.It Fl -maximum-traverse-depth Ns = Ns Ar depth .It Fl -maximum-traverse-depth Ns = Ns Ar depth
Impose a limit on the allowed depth in the dependency graph. Impose a limit on the allowed depth in the dependency graph.
The default
.Ar depth
is 256.
Set
.Ar depth
to \-1 to allow unlimited traversal.
For example, a For example, a
.Ar depth .Ar depth
of 2 restricts the resolver from acting on child of 2 restricts the resolver from acting on child
@@ -570,12 +589,11 @@ This option implies
and and
.Fl -errors-to-stdout . .Fl -errors-to-stdout .
.It Fl -variable Ns = Ns Ar varname .It Fl -variable Ns = Ns Ar varname
For the first For each specified
.Ar module .Ar module ,
given on the command line, print the value of the variable with the name print the value of the variable with the name
.Ar varname .Ar varname
to standard output. to standard output in command-line order.
Any subsequent arguments are silently ignored.
This option implies This option implies
.Fl -maximum-traverse-depth Ns =1 .Fl -maximum-traverse-depth Ns =1
and overrides and disables all and overrides and disables all
@@ -621,9 +639,15 @@ in the same way as
.It Ev DESTDIR .It Ev DESTDIR
If set to the same value as If set to the same value as
.Ev PKG_CONFIG_SYSROOT_DIR , .Ev PKG_CONFIG_SYSROOT_DIR ,
behave in the same way as if follow
.Ev PKG_CONFIG_FDO_SYSROOT_RULES .Ev PKG_CONFIG_FDO_SYSROOT_RULES
is set. for variable lookups, but disable automatic sysroot injection into
.Fl I
and
.Fl L
fragments to avoid prefixing paths with
.Ev DESTDIR
twice.
If If
.Ev PKG_CONFIG_SYSROOT_DIR .Ev PKG_CONFIG_SYSROOT_DIR
is not set or set to a different value, is not set or set to a different value,
@@ -693,6 +717,7 @@ For more details, see the
command line option, which overrides this variable. command line option, which overrides this variable.
.It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH .It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
Impose a limit on the allowed depth in the dependency graph. Impose a limit on the allowed depth in the dependency graph.
Set this variable to \-1 to allow unlimited traversal.
This variable overrides the This variable overrides the
.Fl -maximum-traverse-depth .Fl -maximum-traverse-depth
option, but is overridden by the other options mentioned there. option, but is overridden by the other options mentioned there.
+3 -3
View File
@@ -19,12 +19,12 @@
.Ar module ... .Ar module ...
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a program which generates a JSON-LD formated SPDX Lite 3.0.1 software bill of is a program which generates a JSON-LD formatted SPDX Lite 3.0.1 software bill of
materials (SBOM) for a given set of pkg-config modules. materials (SBOM) for a given set of pkg-config modules.
The output of this tool can then be translated into other SBOM The output of this tool can then be translated into other SBOM
formats as necessary. formats as necessary.
More documention about SDPX 3.0.1 can be found from: More documentation about SDPX 3.0.1 can be found from:
.Lk https://spdx.github.io/spdx-spec/v3.0.1/ .Lk https://spdx.github.io/spdx-spec/v3.0.1/
.Pp .Pp
The The
@@ -46,7 +46,7 @@ Set agent name-property
in /Core/Agent-class. Default is 'Default' in /Core/Agent-class. Default is 'Default'
.It Fl -creation-time .It Fl -creation-time
Set create-property time in /Core/CreationInfo-class. Set create-property time in /Core/CreationInfo-class.
SPDX documentation recomends using ISO 8601-formated time which is: YYYY-MM-DDThh:mm:ssZ. SPDX documentation recommends using ISO 8601-formatted time which is: YYYY-MM-DDThh:mm:ssZ.
Default is document creation time. Default is document creation time.
This takes precedence over the This takes precedence over the
.Ev SOURCE_DATE_EPOCH .Ev SOURCE_DATE_EPOCH
+83 -36
View File
@@ -1,5 +1,5 @@
project('pkgconf', 'c', project('pkgconf', 'c',
version : '2.9.93', version : '3.0.8',
license : 'ISC', license : 'ISC',
default_options : [ default_options : [
'c_std=c99', 'c_std=c99',
@@ -18,6 +18,7 @@ if cc.get_argument_syntax() != 'msvc'
) )
endif endif
add_project_arguments( add_project_arguments(
'-D_ATFILE_SOURCE',
'-D_BSD_SOURCE', '-D_BSD_SOURCE',
'-D_DARWIN_C_SOURCE', '-D_DARWIN_C_SOURCE',
'-D_DEFAULT_SOURCE', '-D_DEFAULT_SOURCE',
@@ -65,6 +66,7 @@ endif
cdata = configuration_data() cdata = configuration_data()
check_functions = [ check_functions = [
['getc_unlocked', 'stdio.h'],
['strndup', 'string.h'], ['strndup', 'string.h'],
['strdup', 'string.h'], ['strdup', 'string.h'],
['strncasecmp', 'strings.h'], ['strncasecmp', 'strings.h'],
@@ -73,11 +75,13 @@ check_functions = [
['pledge', 'unistd.h'], ['pledge', 'unistd.h'],
['unveil', 'unistd.h'], ['unveil', 'unistd.h'],
['readlinkat', 'unistd.h'], ['readlinkat', 'unistd.h'],
['mkdtemp', 'stdlib.h'],
] ]
# Feature-test macros mirroring those defined globally by the build, so that # Feature-test macros mirroring those defined globally by the build, so that
# the function probes below see the same declarations as the actual sources. # the function probes below see the same declarations as the actual sources.
feature_macros = { feature_macros = {
'_ATFILE_SOURCE': '',
'_BSD_SOURCE': '', '_BSD_SOURCE': '',
'_DARWIN_C_SOURCE': '', '_DARWIN_C_SOURCE': '',
'_DEFAULT_SOURCE': '', '_DEFAULT_SOURCE': '',
@@ -128,10 +132,14 @@ else
cdata.set('HAVE_DECL_NL_LANGINFO_L', 0) cdata.set('HAVE_DECL_NL_LANGINFO_L', 0)
endif endif
default_path = [] PKG_DEFAULT_PATH = get_option('with-pkg-config-dir')
foreach f : ['libdir', 'datadir'] if PKG_DEFAULT_PATH == ''
default_path += [join_paths(get_option('prefix'), get_option(f), 'pkgconfig')] default_path = []
endforeach foreach f : ['libdir', 'datadir']
default_path += [join_paths(get_option('prefix'), get_option(f), 'pkgconfig')]
endforeach
PKG_DEFAULT_PATH = ':'.join(default_path)
endif
personality_path = [] personality_path = []
foreach f : ['libdir', 'datadir'] foreach f : ['libdir', 'datadir']
@@ -150,11 +158,11 @@ if SYSTEM_INCLUDEDIR != ''
else else
cdata.set_quoted('SYSTEM_INCLUDEDIR', join_paths(get_option('prefix'), get_option('includedir'))) cdata.set_quoted('SYSTEM_INCLUDEDIR', join_paths(get_option('prefix'), get_option('includedir')))
endif endif
cdata.set_quoted('PKG_DEFAULT_PATH', ':'.join(default_path)) cdata.set_quoted('PKG_DEFAULT_PATH', PKG_DEFAULT_PATH)
cdata.set_quoted('PERSONALITY_PATH', ':'.join(personality_path)) cdata.set_quoted('PERSONALITY_PATH', ':'.join(personality_path))
cdata.set_quoted('PACKAGE_NAME', meson.project_name()) cdata.set_quoted('PACKAGE_NAME', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version()) cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
cdata.set_quoted('PACKAGE_BUGREPORT', 'https://todo.sr.ht/~kaniini/pkgconf') cdata.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/pkgconf/pkgconf/issues')
cdata.set('abs_top_srcdir', meson.current_source_dir()) cdata.set('abs_top_srcdir', meson.current_source_dir())
cdata.set('abs_top_builddir', meson.current_build_dir()) cdata.set('abs_top_builddir', meson.current_build_dir())
@@ -210,11 +218,9 @@ if fuzzing
subdir('fuzzer') subdir('fuzzer')
endif endif
# If we have a new enough meson override the dependency so that only # override the dependency so that only `dependency('libpkgconf')` is
# `dependency('libpkgconf')` is required from the consumer # required from the consumer
if meson.version().version_compare('>= 0.54.0') meson.override_dependency('libpkgconf', dep_libpkgconf)
meson.override_dependency('libpkgconf', dep_libpkgconf)
endif
pkg = import('pkgconfig') pkg = import('pkgconfig')
pkg.generate(libpkgconf, pkg.generate(libpkgconf,
@@ -278,6 +284,16 @@ spdxtool_exe = executable('spdxtool',
include_directories : include_directories('cli', 'cli/spdxtool'), include_directories : include_directories('cli', 'cli/spdxtool'),
install : true) install : true)
pccritic_exe = executable('pccritic',
'cli/pccritic/main.c',
'cli/pccritic/critic.c',
'cli/getopt_long.c',
windows_manifest,
link_with : libpkgconf,
c_args : build_static,
include_directories : include_directories('cli', 'cli/pccritic'),
install : true)
test_runner_exe = executable('test-runner', test_runner_exe = executable('test-runner',
'cli/core.c', 'cli/core.c',
'cli/getopt_long.c', 'cli/getopt_long.c',
@@ -287,7 +303,8 @@ test_runner_exe = executable('test-runner',
link_with : libpkgconf, link_with : libpkgconf,
c_args : build_static, c_args : build_static,
include_directories : cli_include, include_directories : cli_include,
install : false) install : false,
build_by_default : false)
api_tests = [ api_tests = [
'audit', 'audit',
@@ -313,7 +330,8 @@ foreach t : api_tests
link_with : libpkgconf, link_with : libpkgconf,
c_args : build_static, c_args : build_static,
include_directories : [include_directories('.'), include_directories('tests/api')], include_directories : [include_directories('.'), include_directories('tests/api')],
install : false) install : false,
build_by_default : false)
test('api-' + t, exe) test('api-' + t, exe)
endforeach endforeach
@@ -330,9 +348,27 @@ test_api_serialize_exe = executable('test-api-serialize',
link_with : libpkgconf, link_with : libpkgconf,
c_args : build_static, c_args : build_static,
include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool')], include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool')],
install : false) install : false,
build_by_default : false)
test('api-serialize', test_api_serialize_exe) test('api-serialize', test_api_serialize_exe)
# Unit test for spdxtool's util uri encode.
test_api_util_exe = executable('test-api-util',
'tests/api/test-util.c',
'cli/spdxtool/core.c',
'cli/spdxtool/software.c',
'cli/spdxtool/serialize.c',
'cli/spdxtool/simplelicensing.c',
'cli/spdxtool/util.c',
windows_manifest,
link_with : libpkgconf,
c_args : build_static,
include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool')],
install : false,
build_by_default : false)
test('api-util', test_api_util_exe)
# Allocation-failure (OOM) tests. These drive the shared fuzzer/alloc-inject # Allocation-failure (OOM) tests. These drive the shared fuzzer/alloc-inject
# fault injector through the linker's --wrap, so they are built wherever --wrap # fault injector through the linker's --wrap, so they are built wherever --wrap
# is supported: glibc and musl Linux (GNU ld / lld), and skipped on macOS ld64 # is supported: glibc and musl Linux (GNU ld / lld), and skipped on macOS ld64
@@ -352,24 +388,29 @@ oom_wrap_args = [
] ]
if build_oom_tests if build_oom_tests
# Unit test: fault-inject spdxtool's own allocations. It links libpkgconf # Unit test: fault-inject spdxtool's own allocations. It requires a shared
# normally (shared); only spdxtool's compiled-in allocations are wrapped, # libpkgconf so that the linker's --wrap only reaches spdxtool's compiled-in
# which is exactly what we want to fail here. # allocations. With a static libpkgconf its allocations are wrapped too,
test_api_oom_spdxtool_exe = executable('test-api-oom-spdxtool', # invalidating the test's expectation that every injected failure makes the
'tests/api/test-oom-spdxtool.c', # spdxtool operation fail.
'fuzzer/alloc-inject.c', if libtype != 'static'
'cli/spdxtool/core.c', test_api_oom_spdxtool_exe = executable('test-api-oom-spdxtool',
'cli/spdxtool/software.c', 'tests/api/test-oom-spdxtool.c',
'cli/spdxtool/serialize.c', 'fuzzer/alloc-inject.c',
'cli/spdxtool/simplelicensing.c', 'cli/spdxtool/core.c',
'cli/spdxtool/util.c', 'cli/spdxtool/software.c',
windows_manifest, 'cli/spdxtool/serialize.c',
link_with : libpkgconf, 'cli/spdxtool/simplelicensing.c',
c_args : build_static, 'cli/spdxtool/util.c',
link_args : oom_wrap_args, windows_manifest,
include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool'), include_directories('fuzzer')], link_with : libpkgconf,
install : false) c_args : build_static,
test('api-oom-spdxtool', test_api_oom_spdxtool_exe) link_args : oom_wrap_args,
include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool'), include_directories('fuzzer')],
install : false,
build_by_default : false)
test('api-oom-spdxtool', test_api_oom_spdxtool_exe)
endif
# Replay the existing parser/solver fuzz targets over their seed corpus, # Replay the existing parser/solver fuzz targets over their seed corpus,
# deterministically and without libFuzzer, so the libpkgconf OOM paths they # deterministically and without libFuzzer, so the libpkgconf OOM paths they
@@ -394,7 +435,8 @@ if build_oom_tests
c_args : build_static, c_args : build_static,
link_args : oom_wrap_args, link_args : oom_wrap_args,
include_directories : [include_directories('.'), include_directories('fuzzer')], include_directories : [include_directories('.'), include_directories('fuzzer')],
install : false) install : false,
build_by_default : false)
# The exhaustive per-input injection loop is slow under ASAN; give it room. # The exhaustive per-input injection loop is slow under ASAN; give it room.
test('fuzz-replay-' + r[0], replay_exe, args : [r[1]], timeout : 120) test('fuzz-replay-' + r[0], replay_exe, args : [r[1]], timeout : 120)
endforeach endforeach
@@ -416,13 +458,14 @@ test_suites = [
'tuple', 'tuple',
'bomtool', 'bomtool',
'spdxtool', 'spdxtool',
'pccritic',
'symlink' 'symlink'
] ]
foreach t : test_suites foreach t : test_suites
test(t, test_runner_exe, test(t, test_runner_exe,
args : ['--test-fixtures', fixtures_dir, '--tool-dir', tool_dir, join_paths(meson.current_source_dir(), 't', t)], args : ['--test-fixtures', fixtures_dir, '--tool-dir', tool_dir, join_paths(meson.current_source_dir(), 't', t)],
depends : [pkgconf_exe, spdxtool_exe, bomtool_exe]) depends : [pkgconf_exe, spdxtool_exe, bomtool_exe, pccritic_exe])
endforeach endforeach
install_man('man/bomtool.1') install_man('man/bomtool.1')
@@ -431,6 +474,7 @@ install_man('man/pkg.m4.7')
install_man('man/pc.5') install_man('man/pc.5')
install_man('man/pkgconf-personality.5') install_man('man/pkgconf-personality.5')
install_man('man/spdxtool.1') install_man('man/spdxtool.1')
install_man('man/pccritic.1')
install_data('pkg.m4', install_dir: 'share/aclocal') install_data('pkg.m4', install_dir: 'share/aclocal')
install_data('AUTHORS', install_dir: 'share/doc/pkgconf') install_data('AUTHORS', install_dir: 'share/doc/pkgconf')
install_data('README.md', install_dir: 'share/doc/pkgconf') install_data('README.md', install_dir: 'share/doc/pkgconf')
@@ -440,6 +484,9 @@ if host_machine.system() == 'windows'
conf_data = configuration_data() conf_data = configuration_data()
conf_data.set('VERSION', meson.project_version()) conf_data.set('VERSION', meson.project_version())
conf_data.set('EXE', pkgconf_exe.full_path()) conf_data.set('EXE', pkgconf_exe.full_path())
conf_data.set('BOMTOOL_EXE', bomtool_exe.full_path())
conf_data.set('SPDXTOOL_EXE', spdxtool_exe.full_path())
conf_data.set('PCCRITIC_EXE', pccritic_exe.full_path())
conf_data.set('DLL', libpkgconf.full_path()) conf_data.set('DLL', libpkgconf.full_path())
conf_data.set('BUILD_TYPE', libtype) conf_data.set('BUILD_TYPE', libtype)
@@ -470,7 +517,7 @@ if host_machine.system() == 'windows'
if wix.found() if wix.found()
msi = custom_target( msi = custom_target(
msi_filename, msi_filename,
input: [wxsfile, licensefile, pkgconf_exe], input: [wxsfile, licensefile, pkgconf_exe, bomtool_exe, spdxtool_exe, pccritic_exe],
output: msi_filename, output: msi_filename,
command: [wix, 'build', wxsfile, '-arch', wix_arch, '-ext', 'WixToolset.UI.wixext', '-o', msi_filename], command: [wix, 'build', wxsfile, '-arch', wix_arch, '-ext', 'WixToolset.UI.wixext', '-o', msi_filename],
) )
+7
View File
@@ -1,3 +1,10 @@
option(
'with-pkg-config-dir',
type: 'string',
value: '',
description: 'Specify the default package search path (default {prefix}/{libdir}/pkgconfig:{prefix}/{datadir}/pkgconfig)'
)
option( option(
'with-system-libdir', 'with-system-libdir',
type: 'string', type: 'string',
+1
View File
@@ -4,6 +4,7 @@
<application> <application>
<windowsSettings> <windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage> <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings> </windowsSettings>
</application> </application>
</assembly> </assembly>
+16 -1
View File
@@ -19,7 +19,7 @@
</Feature> </Feature>
<StandardDirectory Id="ProgramFiles6432Folder"> <StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id="INSTALLFOLDER" Name="pkgconf @VERSION@" /> <Directory Id="INSTALLFOLDER" Name="pkgconf-@VERSION@" />
</StandardDirectory> </StandardDirectory>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
@@ -41,6 +41,21 @@
Source="@EXE@" Source="@EXE@"
KeyPath="yes" /> KeyPath="yes" />
</Component> </Component>
<Component Id="BomtoolExe" Guid="*">
<File Id="BomtoolExeFile"
Source="@BOMTOOL_EXE@"
KeyPath="yes" />
</Component>
<Component Id="SpdxtoolExe" Guid="*">
<File Id="SpdxtoolExeFile"
Source="@SPDXTOOL_EXE@"
KeyPath="yes" />
</Component>
<Component Id="PccriticExe" Guid="*">
<File Id="PccriticExeFile"
Source="@PCCRITIC_EXE@"
KeyPath="yes" />
</Component>
<?if "@BUILD_TYPE@" = "shared" ?> <?if "@BUILD_TYPE@" = "shared" ?>
<Component Id="PkgconfDll" Guid="*"> <Component Id="PkgconfDll" Guid="*">
<File Id="PkgconfDllFile" <File Id="PkgconfDllFile"
@@ -1,5 +1,6 @@
PackageSearchPath: lib1 PackageSearchPath: lib1
PackageSearchPath: lib2
Query: pkg-config Query: pkg-config
WantVariable: pc_path WantVariable: pc_path
ExpectedExitCode: 0 ExpectedExitCode: 0
ExpectedStdout: %TEST_FIXTURES_DIR%/lib1 ExpectedStdout: %TEST_FIXTURES_DIR%/lib1%DIR_SEP%%TEST_FIXTURES_DIR%/lib2
@@ -1,5 +1,6 @@
PackageSearchPath: lib1 PackageSearchPath: lib1
PackageSearchPath: lib2
Query: pkgconf Query: pkgconf
WantVariable: pc_path WantVariable: pc_path
ExpectedExitCode: 0 ExpectedExitCode: 0
ExpectedStdout: %TEST_FIXTURES_DIR%/lib1 ExpectedStdout: %TEST_FIXTURES_DIR%/lib1%DIR_SEP%%TEST_FIXTURES_DIR%/lib2
+4
View File
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: maxpkg-first maxpkg-second
WantVariable: qux
ExpectedStdout: first-value second-value
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --define-prefix --variable=siblingdir %TEST_FIXTURES_DIR%/lib-relocatable/abs-boundary/lib/pkgconfig/boundary.pc
ExpectedStdout: /nonexistent/hardcodedX
ExpectedExitCode: 0
+4
View File
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --define-prefix --variable=includedir %TEST_FIXTURES_DIR%/lib-relocatable/abs-boundary/lib/pkgconfig/boundary.pc
ExpectedStdout: %TEST_FIXTURES_DIR%/lib-relocatable/abs-boundary/include
ExpectedExitCode: 0
+4
View File
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --define-prefix --variable=includedir %TEST_FIXTURES_DIR%/lib-relocatable/plain-prefix/lib/pkgconfig/plain.pc
ExpectedStdout: %TEST_FIXTURES_DIR%/lib-relocatable/plain-prefix/include
ExpectedExitCode: 0
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --define-prefix --cflags %TEST_FIXTURES_DIR%/lib-relocatable/trailing-prefix/lib/pkgconfig/trailing.pc
ExpectedStdout: -I%TEST_FIXTURES_DIR%/lib-relocatable/trailing-prefix/include
ExpectedExitCode: 0
+4
View File
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --define-prefix --variable=includedir %TEST_FIXTURES_DIR%/lib-relocatable/trailing-prefix/lib/pkgconfig/trailing.pc
ExpectedStdout: %TEST_FIXTURES_DIR%/lib-relocatable/trailing-prefix/include
ExpectedExitCode: 0
+1 -1
View File
@@ -2,7 +2,7 @@ Tool: pkgconf
ToolArgs: --exists foo 2>&1 ToolArgs: --exists foo 2>&1
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1 Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
Environment: PKG_CONFIG_EARLY_TRACE=1 Environment: PKG_CONFIG_EARLY_TRACE=1
ExpectedStdout: installing default unveil handler ExpectedStdout: installing custom unveil handler
MatchStdout: partial MatchStdout: partial
ExpectedExitCode: 0 ExpectedExitCode: 0
SkipPlatforms: lite SkipPlatforms: lite
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --libs bar
Environment: PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH=-2
ExpectedExitCode: 1
@@ -0,0 +1,3 @@
Tool: pkgconf
ToolArgs: --maximum-traverse-depth=invalid --libs bar
ExpectedExitCode: 1
@@ -0,0 +1,5 @@
Tool: pkgconf
ToolArgs: --maximum-traverse-depth=-1 --libs bar
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
ExpectedStdout: -L/test/lib -lbar -lfoo
ExpectedExitCode: 0
+2
View File
@@ -0,0 +1,2 @@
pcfiledir
qux
+4
View File
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --with-path=%TEST_FIXTURES_DIR%/lib1 --print-variables maxpkg-first maxpkg-second
ExpectedStdoutFile: single-package-limit.out
ExpectedExitCode: 0
+4
View File
@@ -0,0 +1,4 @@
Tool: pkgconf
ToolArgs: --with-path=%TEST_FIXTURES_DIR%/lib1 --variable=qux maxpkg-first maxpkg-second
ExpectedStdout: first-value second-value
ExpectedExitCode: 0
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: escape-layers-bare-var
WantedFlags: libs
ExpectedStdout: -L/test/a\ dir -la -Wl,--foo\\bar
+4
View File
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: escape-layers
WantedFlags: cflags
ExpectedStdout: -I/test/a\ dir -DBS=x\\y -DLIT=p\\q -DLITSP=p\ q
+4
View File
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: escape-layers
WantedFlags: libs
ExpectedStdout: -L/test/a\ dir/lib -L/test/lit\ eral -la
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: fragment-escaped-space-var
WantedFlags: cflags
ExpectedStdout: -I/test/a\ dir/b\ dir
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: fragment-escaped-space-var
WantedFlags: libs
ExpectedStdout: -L/test/a\ dir/b\ dir -la
+4
View File
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: self-referential-fragment
WantedFlags: cflags
ExpectedStdout: $\{x\}
+4
View File
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: spaces-in-paths
WantedFlags: cflags
ExpectedStdout: -I/test\ with\ spaces/include -I/test\ with\ spaces/include/subdir
+5
View File
@@ -0,0 +1,5 @@
Tool: pccritic
ToolArgs: --about
ExpectedStdout: pccritic
MatchStdout: Partial
ExpectedExitCode: 0
+5
View File
@@ -0,0 +1,5 @@
Tool: pccritic
ToolArgs: --help
ExpectedStdout: usage: pccritic
MatchStdout: Partial
ExpectedExitCode: 0
+3
View File
@@ -0,0 +1,3 @@
Tool: pccritic
ToolArgs: --min-score invalid polluted
ExpectedExitCode: 1
+3
View File
@@ -0,0 +1,3 @@
Tool: pccritic
ToolArgs: --min-score 101 polluted
ExpectedExitCode: 1
+4
View File
@@ -0,0 +1,4 @@
Tool: pccritic
ToolArgs: --quiet --min-score 90 polluted
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-pccritic
ExpectedExitCode: 1
+5
View File
@@ -0,0 +1,5 @@
Tool: pccritic
ToolArgs: --quiet %TEST_FIXTURES_DIR%/lib-pccritic/nodesc.pc
ExpectedStdout: 75/100 (C)
MatchStdout: Partial
ExpectedExitCode: 0
+2
View File
@@ -0,0 +1,2 @@
Tool: pccritic
ExpectedExitCode: 1
+5
View File
@@ -0,0 +1,5 @@
Tool: pccritic
ToolArgs: --quiet perfect
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-pccritic
ExpectedStdout: perfect: 100/100 (A)
ExpectedExitCode: 0
+5
View File
@@ -0,0 +1,5 @@
Tool: pccritic
ToolArgs: --quiet polluted
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-pccritic
ExpectedStdout: polluted: 80/100 (B)
ExpectedExitCode: 0
+3
View File
@@ -0,0 +1,3 @@
Tool: pccritic
ToolArgs: this-module-does-not-exist
ExpectedExitCode: 1
+5
View File
@@ -0,0 +1,5 @@
Tool: pccritic
ToolArgs: --version
ExpectedStdout: pccritic
MatchStdout: Partial
ExpectedExitCode: 0
+7
View File
@@ -0,0 +1,7 @@
PackageSearchPath: lib1
Query: conflicts, foo
WantedFlags: dump-license
ExpectedStdout: conflicts: NOASSERTION
ExpectedStdout: foo: ISC
ExpectedExitCode: 0
MatchStdout: partial
+7
View File
@@ -0,0 +1,7 @@
PackageSearchPath: lib1
Query: conflicts, foo
WantedFlags: modversion
ExpectedStdout: 1.2.3
ExpectedStdout: 1.2.3
ExpectedExitCode: 0
MatchStdout: partial
+7
View File
@@ -0,0 +1,7 @@
PackageSearchPath: lib1
Query: conflicts, foo
WantedFlags: print-provides
ExpectedStdout: conflicts = 1.2.3
ExpectedStdout: foo = 1.2.3
ExpectedExitCode: 0
MatchStdout: partial
+4
View File
@@ -0,0 +1,4 @@
PackageSearchPath: lib1
Query: conflicts, foo
WantedFlags: print-requires
ExpectedExitCode: 0
@@ -0,0 +1,7 @@
Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot
Environment: PKG_CONFIG_SYSTEM_INCLUDE_PATH=/sysroot/test/include/foo
Environment: PKG_CONFIG_FDO_SYSROOT_RULES=1
PackageSearchPath: lib1
Query: foo
WantedFlags: cflags
ExpectedStdout: -fPIC
@@ -0,0 +1,6 @@
Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot
Environment: PKG_CONFIG_FDO_SYSROOT_RULES=1
PackageSearchPath: lib1
Query: foo
WantVariable: prefix
ExpectedStdout: /test
+1 -2
View File
@@ -2,5 +2,4 @@ Environment: PKG_CONFIG_SYSROOT_DIR=%TEST_FIXTURES_DIR%
PackageSearchPath: lib1 PackageSearchPath: lib1
Query: idirafter Query: idirafter
WantedFlags: cflags WantedFlags: cflags
ExpectedStdout: -idirafter %TEST_FIXTURES_DIR%/opt/bad/include ExpectedStdout: -idirafter %TEST_FIXTURES_DIR%/opt/bad/include -idirafter %TEST_FIXTURES_DIR%/opt/bad2/include
MatchStdout: partial
+5
View File
@@ -0,0 +1,5 @@
Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot
PackageSearchPath: lib1
Query: sysroot-inject-bare
WantedFlags: cflags
ExpectedStdout: -I/sysroot
@@ -0,0 +1,5 @@
Environment: PKG_CONFIG_SYSROOT_DIR=/usr
PackageSearchPath: lib1
Query: sysroot-inject-prefix
WantedFlags: cflags
ExpectedStdout: -I/usr/include
@@ -0,0 +1,5 @@
Environment: PKG_CONFIG_SYSROOT_DIR=/usr
PackageSearchPath: lib1
Query: sysroot-inject-hardcoded
WantedFlags: cflags
ExpectedStdout: -I/usr/opt/x
@@ -0,0 +1,5 @@
Environment: PKG_CONFIG_SYSROOT_DIR=/usr
PackageSearchPath: lib1
Query: sysroot-inject-literal
WantedFlags: cflags
ExpectedStdout: -I/usr/sysroot/opt/x
+5
View File
@@ -0,0 +1,5 @@
Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot
PackageSearchPath: lib1
Query: sysroot-inject-explicit
WantedFlags: cflags
ExpectedStdout: -I/sysroot/opt/x
Loaded 100 of 190 files, more files were not shown because too many files have changed in this diff. Show more