mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
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:
1 parent
0cf7106da9
commit
fe9da42ef1
190 files changed
+5965
-1375
No files matched your search
+84
-18
@@ -1,27 +1,93 @@
|
||||
# pkgconf Code of Conduct
|
||||
|
||||
We invite and encourage everybody to express their opinions on relevant
|
||||
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.
|
||||
## Human participants
|
||||
|
||||
To foster tolerance, respect and hospitality in our community, we agree not
|
||||
to engage in discriminatory, disparaging or offensive speech or actions,
|
||||
including as to (but not limited to) gender, sexuality, race, nationality,
|
||||
religion or profession. We are a community of many different nationalities
|
||||
and backgrounds, and we cherish our strength in diversity.
|
||||
Human participants in the pkgconf project are expected to follow the current
|
||||
version of the [Contributor Covenant][covenant], as posted on
|
||||
contributor-covenant.org. The version posted there at the time of an
|
||||
incident is the version that applies.
|
||||
|
||||
[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
|
||||
|
||||
Please report any incidents which may be perceived as violations to
|
||||
`ariadne+conduct@dereferenced.org`. Incidents will be investigated and,
|
||||
if warranted, acted upon.
|
||||
Report anything you believe violates this document to
|
||||
`ariadne+conduct@ariadne.space`. Reports reach the maintainers directly.
|
||||
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
|
||||
|
||||
This CoC is derived from the [FSFE Code of Conduct][fsfe-coc].
|
||||
|
||||
[fsfe-coc]: https://fsfe.org/about/codeofconduct.en.html
|
||||
You do not need to be a contributor to report something, and you will not
|
||||
be asked to justify why the conduct troubled you.
|
||||
+1
-1
@@ -77,7 +77,7 @@ By submitting a patch, you affirm that:
|
||||
* You can account for how the contribution was produced.
|
||||
|
||||
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].
|
||||
|
||||
Contributions produced primarily by autonomous or agentic systems
|
||||
|
||||
+131
-3
@@ -12,17 +12,29 @@ nodist_pkgconfig_DATA = libpkgconf.pc
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
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
|
||||
|
||||
EXTRA_DIST = pkg.m4 \
|
||||
meson.build \
|
||||
meson_options.txt \
|
||||
pkgconf.manifest.in \
|
||||
pkgconf.rc.in \
|
||||
pkgconf.wxs.in \
|
||||
txt2rtf.py \
|
||||
libpkgconf/meson.build \
|
||||
libpkgconf/config.h.meson \
|
||||
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/atleast-pkgconfig-version-fail.test \
|
||||
t/cli/atleast-pkgconfig-version-pass.test \
|
||||
@@ -32,6 +44,11 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/cli/atleast-version-pass.test \
|
||||
t/cli/cflags-libs.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/dont-define-prefix.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-overrides.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/missing-package.test \
|
||||
t/cli/missing-package-error.test \
|
||||
@@ -84,10 +104,13 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/cli/short-errors.test \
|
||||
t/cli/silence-errors.test \
|
||||
t/cli/simulate.test \
|
||||
t/cli/single-package-limit.out \
|
||||
t/cli/single-package-limit.test \
|
||||
t/cli/solution.test \
|
||||
t/cli/unknown-option.test \
|
||||
t/cli/validate-warning.test \
|
||||
t/cli/validate.test \
|
||||
t/cli/variable-multiple-packages.test \
|
||||
t/cli/variable.test \
|
||||
t/cli/verbose.test \
|
||||
t/cli/version.test \
|
||||
@@ -145,6 +168,7 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/basic/uninstalled-not.test \
|
||||
t/basic/uninstalled.test \
|
||||
t/basic/variable-env.test \
|
||||
t/basic/variable-multiple-packages.test \
|
||||
t/basic/variable-no-recursion.test \
|
||||
t/basic/variable.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-2.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/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-2.test \
|
||||
t/parser/fragment-escaping-3.test \
|
||||
@@ -200,7 +229,9 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/parser/multiline-folding-libs.test \
|
||||
t/parser/no-trailing-newline.test \
|
||||
t/parser/paren-quoting.test \
|
||||
t/parser/self-referential-fragment.test \
|
||||
t/parser/shell-quoted-output.test \
|
||||
t/parser/spaces-in-paths.test \
|
||||
t/parser/tilde-quoting-1.test \
|
||||
t/parser/tilde-quoting-2.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-directpc.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-ignore.test \
|
||||
t/solver/conflicts-solution-is-fine-standalone.test \
|
||||
@@ -321,6 +356,17 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/spdxtool/version.test \
|
||||
t/spdxtool/version-operator.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-foo.test \
|
||||
t/sbom/license-isc.test \
|
||||
@@ -354,7 +400,27 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/symlink/pcfiledir_symlink_relative_env12.test \
|
||||
t/sysroot/cflags-rewriting.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/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-sysroot-prefixed.test \
|
||||
t/sysroot/no-pc_sysrootdir-rewriting-2.test \
|
||||
@@ -373,6 +439,10 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/sysroot/uninstalled-rewriting.test \
|
||||
t/sysroot/variable-rewriting-1.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/case-sensitivity-1.test \
|
||||
t/tuple/case-sensitivity-2.test \
|
||||
@@ -380,6 +450,12 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/tuple/define-variable.test \
|
||||
t/tuple/duplicate-upsert.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/cxx-leaf.test \
|
||||
t/link-abi/cxx-leaf-static.test \
|
||||
@@ -389,7 +465,15 @@ EXTRA_DIST = pkg.m4 \
|
||||
t/link-abi/multi-dedup.test \
|
||||
tests/win-shim.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/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/billion-laughs.pc \
|
||||
tests/lib1/dollar-sign-escape.pc \
|
||||
@@ -511,6 +595,28 @@ EXTRA_DIST = pkg.m4 \
|
||||
tests/lib1/duplicate-tuple.pc \
|
||||
tests/lib1/flag-whitespace.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/test1.pc \
|
||||
tests/lib-sbom/test2.pc \
|
||||
@@ -598,7 +704,8 @@ dist_man_MANS = \
|
||||
man/pkg.m4.7 \
|
||||
man/pc.5 \
|
||||
man/pkgconf-personality.5 \
|
||||
man/spdxtool.1
|
||||
man/spdxtool.1 \
|
||||
man/pccritic.1
|
||||
|
||||
pkgconf_LDADD = libpkgconf.la
|
||||
pkgconf_SOURCES = \
|
||||
@@ -617,7 +724,8 @@ noinst_HEADERS = \
|
||||
cli/spdxtool/serialize.h \
|
||||
cli/spdxtool/simplelicensing.h \
|
||||
cli/spdxtool/software.h \
|
||||
cli/spdxtool/util.h
|
||||
cli/spdxtool/util.h \
|
||||
cli/pccritic/critic.h
|
||||
|
||||
bomtool_LDADD = libpkgconf.la
|
||||
bomtool_SOURCES = \
|
||||
@@ -637,6 +745,13 @@ spdxtool_SOURCES = \
|
||||
cli/getopt_long.c
|
||||
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 = \
|
||||
test-api-audit \
|
||||
test-api-buffer \
|
||||
@@ -651,6 +766,7 @@ API_TEST_PROGS = \
|
||||
test-api-queue \
|
||||
test-api-serialize \
|
||||
test-api-tuple \
|
||||
test-api-util \
|
||||
test-api-variable \
|
||||
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_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_SOURCES = tests/api/test-variable.c
|
||||
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-serialize$(EXEEXT)
|
||||
$(builddir)/test-api-tuple$(EXEEXT)
|
||||
$(builddir)/test-api-util$(EXEEXT)
|
||||
$(builddir)/test-api-variable$(EXEEXT)
|
||||
$(builddir)/test-api-version$(EXEEXT)
|
||||
$(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/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/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/sysroot
|
||||
$(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/tuple
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ all: pkgconf-lite
|
||||
libpkgconf/config.h:
|
||||
@echo '#define PACKAGE_NAME "pkgconf-lite"' >> $@
|
||||
@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' >> $@
|
||||
|
||||
pkgconf-lite: preflight libpkgconf/config.h ${PKGCONF_OBJS}
|
||||
|
||||
@@ -1,6 +1,186 @@
|
||||
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:
|
||||
----------------------------
|
||||
|
||||
@@ -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
|
||||
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.
|
||||
- kyua is no longer required to run tests.
|
||||
- Declarative configuration for integration tests, C unit tests for functional tests.
|
||||
- Tests now run on Windows.
|
||||
- .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
|
||||
for better performance. Binary-mode handling by moi15moi.
|
||||
was reworked to correctly handle LF, CRLF and lone-CR line endings, including
|
||||
on non-seekable streams. Binary-mode handling by moi15moi.
|
||||
Major contributions by Elizabeth Ashford.
|
||||
|
||||
* 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,
|
||||
including billion-laughs style expansion and excessively complex bytecode
|
||||
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
|
||||
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
|
||||
functions.
|
||||
|
||||
@@ -110,6 +307,11 @@ Changes from 2.5.1 to 3.0.0:
|
||||
WantDefaultStatic.
|
||||
- The vestigial --relocate=path option, which existed only for the old test
|
||||
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_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
|
||||
validated. Patches by Tuukka Pasanen.
|
||||
|
||||
* The libpkgconf API and ABI were substantially reworked, breaking ABI
|
||||
compatibility. The libpkgconf soversion is now 8.
|
||||
* The libpkgconf API and ABI were substantially reworked, breaking both API and
|
||||
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
|
||||
of fixed-size stack buffers, removing a class of truncation bugs.
|
||||
- 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
|
||||
via pkgconf_variable_eval (backed by the new bytecode engine).
|
||||
- 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.
|
||||
- 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:
|
||||
----------------------------
|
||||
@@ -374,7 +590,7 @@ Changes from 2.0.0 to 2.0.1:
|
||||
|
||||
The order of --modversion output is based on the dependency resolution
|
||||
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
|
||||
is possible to disambiguate which version belongs to which module:
|
||||
|
||||
+28
-9
@@ -209,8 +209,10 @@ write_copyright_lines(pkgconf_client_t *client, const pkgconf_list_t *copyright_
|
||||
}
|
||||
|
||||
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;
|
||||
(void) client;
|
||||
(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, "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, "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.
|
||||
*/
|
||||
#if 0
|
||||
@@ -240,7 +241,13 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
|
||||
|
||||
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));
|
||||
int errno_save = errno;
|
||||
pkgconf_buffer_finalize(&license_buf);
|
||||
@@ -269,8 +276,10 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
|
||||
}
|
||||
|
||||
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) 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. */
|
||||
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)
|
||||
{
|
||||
if (pkgconf_buffer_len(&queryparams) > 0)
|
||||
pkgconf_buffer_push_byte(&queryparams, ' ');
|
||||
if ((pkgconf_buffer_len(&queryparams) > 0 &&
|
||||
!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++;
|
||||
}
|
||||
|
||||
|
||||
+152
-119
@@ -170,8 +170,10 @@ apply_provides(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int
|
||||
|
||||
#ifndef PKGCONF_LITE
|
||||
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_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
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
continue;
|
||||
|
||||
result = variable_eval(client, &pkg->vars, variable);
|
||||
result = pkgconf_variable_eval_name(client, &pkg->vars, variable);
|
||||
|
||||
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_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
unsigned int eflag;
|
||||
bool ret = true;
|
||||
|
||||
eflag = collect_fn(client, world, &unfiltered_list, maxdepth);
|
||||
if (eflag != PKGCONF_PKG_ERRF_OK)
|
||||
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)
|
||||
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)
|
||||
goto out;
|
||||
|
||||
pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' ');
|
||||
pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s='%s'\n",
|
||||
if (!pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops,
|
||||
(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));
|
||||
pkgconf_buffer_finalize(&render_buf);
|
||||
|
||||
out:
|
||||
pkgconf_buffer_finalize(&render_buf);
|
||||
pkgconf_fragment_free(&unfiltered_list);
|
||||
pkgconf_fragment_free(&filtered_list);
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
|
||||
if (filtered_list.head == NULL)
|
||||
goto out;
|
||||
|
||||
pkgconf_fragment_copy_list(client, target_list, &filtered_list);
|
||||
pkgconf_list_splice(target_list, &filtered_list);
|
||||
|
||||
out:
|
||||
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)
|
||||
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)
|
||||
goto out;
|
||||
|
||||
pkgconf_fragment_copy_list(client, target_list, &filtered_list);
|
||||
pkgconf_list_splice(target_list, &filtered_list);
|
||||
|
||||
out:
|
||||
pkgconf_fragment_free(&unfiltered_list);
|
||||
@@ -671,8 +656,10 @@ apply_requires_private(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unu
|
||||
}
|
||||
|
||||
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;
|
||||
(void) client;
|
||||
|
||||
@@ -695,8 +682,10 @@ apply_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, in
|
||||
|
||||
#ifndef PKGCONF_LITE
|
||||
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;
|
||||
|
||||
(void) data;
|
||||
@@ -788,10 +777,12 @@ apply_fragment_tree(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data,
|
||||
}
|
||||
|
||||
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;
|
||||
(void) data;
|
||||
int *retval = data;
|
||||
|
||||
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
|
||||
return;
|
||||
@@ -804,9 +795,11 @@ print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
|
||||
else
|
||||
{
|
||||
/* NOASSERTION is the default when the license is unknown, per SPDX spec § 3.15 */
|
||||
pkgconf_license_render(client, &pkg->license, &render_buf);
|
||||
pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id);
|
||||
pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true);
|
||||
if (!pkgconf_license_render(client, &pkg->license, &render_buf) ||
|
||||
!pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id) ||
|
||||
!pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true))
|
||||
*retval = EXIT_FAILURE;
|
||||
|
||||
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;
|
||||
|
||||
if (pkgconf_buffer_len(&render_buf))
|
||||
pkgconf_buffer_push_byte(&render_buf, ' ');
|
||||
|
||||
pkgconf_buffer_append(&render_buf, pkgconf_buffer_str(&tag->buffer));
|
||||
if ((pkgconf_buffer_len(&render_buf) &&
|
||||
!pkgconf_buffer_push_byte(&render_buf, ' ')) ||
|
||||
!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);
|
||||
@@ -858,8 +856,10 @@ apply_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int m
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim)
|
||||
{
|
||||
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;
|
||||
|
||||
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
|
||||
@@ -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
|
||||
register_builtins(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality)
|
||||
{
|
||||
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;
|
||||
path_list_to_buffer(&personality->filter_libdirs, &pc_system_libdirs_buf, ':');
|
||||
|
||||
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 (pkg_config_virtual == NULL)
|
||||
{
|
||||
if (!path_list_to_buffer(&personality->dir_list, &pc_path_buf, PKG_CONFIG_PATH_SEP_S[0]) ||
|
||||
!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;
|
||||
}
|
||||
|
||||
pkg_config_virtual->owner = client;
|
||||
pkg_config_virtual->id = strdup("pkg-config");
|
||||
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))
|
||||
{
|
||||
if (!register_builtin(client, "pkg-config", &pc_path_buf, &pc_system_libdirs_buf, &pc_system_includedirs_buf) ||
|
||||
!register_builtin(client, "pkgconf", &pc_path_buf, &pc_system_libdirs_buf, &pc_system_includedirs_buf))
|
||||
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:
|
||||
pkgconf_buffer_finalize(&pc_path_buf);
|
||||
@@ -1015,13 +1017,13 @@ static void
|
||||
dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p)
|
||||
{
|
||||
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;
|
||||
path_list_to_buffer(&p->filter_libdirs, &pc_system_libdirs_buf, ':');
|
||||
|
||||
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);
|
||||
|
||||
@@ -1038,6 +1040,7 @@ dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p)
|
||||
if (p->want_default_static)
|
||||
pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultStatic: true\n");
|
||||
|
||||
out:
|
||||
pkgconf_buffer_finalize(&pc_path_buf);
|
||||
pkgconf_buffer_finalize(&pc_system_libdirs_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.
|
||||
* 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_PRIVATE) == PKG_REQUIRES_PRIVATE ||
|
||||
(state->want_flags & PKG_PROVIDES) == PKG_PROVIDES ||
|
||||
(state->want_flags & PKG_VARIABLES) == PKG_VARIABLES ||
|
||||
(state->want_flags & PKG_PATH) == PKG_PATH ||
|
||||
state->want_variable != NULL)
|
||||
state->want_variable != NULL;
|
||||
|
||||
if (querying_flattened_metadata)
|
||||
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.
|
||||
*/
|
||||
if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES ||
|
||||
(state->want_flags & PKG_PATH) == PKG_PATH ||
|
||||
state->want_variable != NULL)
|
||||
{
|
||||
if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || (state->want_flags & PKG_PATH) == PKG_PATH)
|
||||
state->maximum_package_count = 1;
|
||||
}
|
||||
|
||||
if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE ||
|
||||
(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 (!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])
|
||||
{
|
||||
if (pkgconf_buffer_len(&queryparams) > 0)
|
||||
pkgconf_buffer_push_byte(&queryparams, ' ');
|
||||
if ((pkgconf_buffer_len(&queryparams) > 0 &&
|
||||
!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++;
|
||||
}
|
||||
|
||||
@@ -1269,12 +1287,25 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg
|
||||
|
||||
dep->compare = compare;
|
||||
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_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);
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
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' : ' ');
|
||||
pkgconf_output_putbuf(state->pkg_client.output, PKGCONF_OUTPUT_STDOUT, &render_buf, true);
|
||||
if (!pkgconf_fragment_render_buf(&target_list, &render_buf, true, state->want_render_ops,
|
||||
(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_fragment_free(&target_list);
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ typedef struct {
|
||||
bool opened_error_msgout;
|
||||
} 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 void pkgconf_cli_state_reset(pkgconf_cli_state_t *state);
|
||||
|
||||
|
||||
+42
-8
@@ -21,6 +21,22 @@
|
||||
#include "getopt_long.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 *
|
||||
environ_lookup_handler(const pkgconf_client_t *client, const char *key)
|
||||
{
|
||||
@@ -66,7 +82,7 @@ deduce_personality(char *argv[])
|
||||
if (i != NULL)
|
||||
argv0 = i + 1;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__OS2__)
|
||||
i = strrchr(argv0, '\\');
|
||||
if (i != NULL)
|
||||
argv0 = i + 1;
|
||||
@@ -166,7 +182,7 @@ usage(void)
|
||||
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-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(" (for static linking)\n");
|
||||
printf(" --shared use a simplified dependency graph (usually default)\n");
|
||||
@@ -240,6 +256,7 @@ main(int argc, char *argv[])
|
||||
int ret;
|
||||
pkgconf_cli_state_t state = {
|
||||
.want_flags = 0,
|
||||
.maximum_traverse_depth = 256,
|
||||
};
|
||||
pkgconf_list_t dir_list = PKGCONF_LIST_INITIALIZER;
|
||||
char *env_traverse_depth;
|
||||
@@ -252,7 +269,7 @@ main(int argc, char *argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__OS2__)
|
||||
/* When running regression tests in cygwin, and building native
|
||||
* executable, tests fail unless native executable outputs unix
|
||||
* 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;
|
||||
break;
|
||||
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;
|
||||
case 27:
|
||||
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 */
|
||||
pkgconf_client_init(&state.pkg_client, error_handler, &state, personality, &state, environ_lookup_handler);
|
||||
pkgconf_client_set_unveil_handler(&state.pkg_client, unveil_handler);
|
||||
pkgconf_client_options_t client_options = {
|
||||
.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
|
||||
if (getenv("PKG_CONFIG_MSVC_SYNTAX") != NULL)
|
||||
state.want_flags |= PKG_MSVC_SYNTAX;
|
||||
#endif
|
||||
|
||||
if ((env_traverse_depth = getenv("PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH")) != NULL)
|
||||
state.maximum_traverse_depth = atoi(env_traverse_depth);
|
||||
if ((env_traverse_depth = getenv("PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH")) != NULL &&
|
||||
!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)
|
||||
state.want_flags |= (PKG_SILENCE_ERRORS);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
@@ -50,41 +50,50 @@ allowed_fragment(const pkgconf_fragment_t *frag)
|
||||
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)
|
||||
{
|
||||
pkgconf_buffer_t tmpbuf = PKGCONF_BUFFER_INITIALIZER;
|
||||
bool escape = ctx->escape;
|
||||
|
||||
if (!allowed_fragment(frag))
|
||||
return;
|
||||
return true;
|
||||
|
||||
switch(frag->type) {
|
||||
case 'D':
|
||||
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;
|
||||
case 'L':
|
||||
pkgconf_buffer_append(buf, "/libpath:");
|
||||
if (!pkgconf_buffer_append(buf, "/libpath:"))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
pkgconf_buffer_append(&tmpbuf, frag->data);
|
||||
if (!pkgconf_buffer_append(&tmpbuf, frag->data))
|
||||
return false;
|
||||
|
||||
if (frag->type == 'l')
|
||||
pkgconf_buffer_append(&tmpbuf, ".lib");
|
||||
if (frag->type == 'l' && !pkgconf_buffer_append(&tmpbuf, ".lib"))
|
||||
goto fail;
|
||||
|
||||
escape = should_quote(&tmpbuf);
|
||||
|
||||
if (escape)
|
||||
pkgconf_buffer_push_byte(buf, '"');
|
||||
if (escape && !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)
|
||||
pkgconf_buffer_push_byte(buf, '"');
|
||||
if (escape && !pkgconf_buffer_push_byte(buf, '"'))
|
||||
goto fail;
|
||||
|
||||
pkgconf_buffer_finalize(&tmpbuf);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
pkgconf_buffer_finalize(&tmpbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
static pkgconf_fragment_render_ops_t msvc_renderer_ops = {
|
||||
|
||||
+153
-12
@@ -124,6 +124,116 @@ err:
|
||||
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
|
||||
*
|
||||
@@ -140,9 +250,9 @@ err:
|
||||
* :return: NULL if some problem occurs and CreationInfo struct if not
|
||||
*/
|
||||
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;
|
||||
|
||||
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->created = time ? strdup(time) : spdxtool_util_get_current_iso8601_time();
|
||||
creation->created_by = strdup(agent_id);
|
||||
creation->created_using = strdup(tool_id);
|
||||
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;
|
||||
|
||||
return creation;
|
||||
@@ -186,6 +297,7 @@ spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation)
|
||||
free(creation->id);
|
||||
free(creation->created);
|
||||
free(creation->created_by);
|
||||
free(creation->created_using);
|
||||
free(creation->spec_version);
|
||||
|
||||
free(creation);
|
||||
@@ -220,17 +332,39 @@ spdxtool_core_creation_info_to_object(pkgconf_client_t *client, const spdxtool_c
|
||||
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)))
|
||||
spdxtool_serialize_array_t *created_using = spdxtool_serialize_array_new();
|
||||
if (!created_using)
|
||||
{
|
||||
/* created_by has not been handed to the object list yet */
|
||||
spdxtool_serialize_array_free(created_by);
|
||||
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 */
|
||||
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)))
|
||||
{
|
||||
goto err;
|
||||
@@ -523,10 +657,14 @@ spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_
|
||||
return false;
|
||||
}
|
||||
|
||||
pkgconf_node_insert_tail(node, expression, &spdx->licenses);
|
||||
if (!spdxtool_core_spdx_document_add_element(client, spdx, expression->spdx_id))
|
||||
{
|
||||
spdxtool_simplelicensing_licenseExpression_free(expression);
|
||||
free(node);
|
||||
return false;
|
||||
}
|
||||
|
||||
pkgconf_node_insert_tail(node, expression, &spdx->licenses);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -613,11 +751,14 @@ spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_co
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkgconf_node_insert_tail(node, agent, &spdx->maintainers);
|
||||
|
||||
if (!spdxtool_core_spdx_document_add_element(client, spdx, agent->spdx_id))
|
||||
{
|
||||
free(node);
|
||||
spdxtool_core_agent_free(agent);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkgconf_node_insert_tail(node, agent, &spdx->maintainers);
|
||||
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->spdx_id = strdup(spdx_id);
|
||||
relationship->from = strdup(from);
|
||||
relationship->to = to;
|
||||
relationship->relationship_type = strdup(relationship_type);
|
||||
|
||||
if (!relationship->creation_info || !relationship->spdx_id || !relationship->from || !relationship->relationship_type)
|
||||
goto err;
|
||||
|
||||
relationship->to = to;
|
||||
return relationship;
|
||||
|
||||
err:
|
||||
|
||||
+10
-1
@@ -28,8 +28,17 @@ spdxtool_core_agent_free(spdxtool_core_agent_t *agent);
|
||||
spdxtool_serialize_value_t *
|
||||
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_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
|
||||
spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation);
|
||||
|
||||
+84
-26
@@ -17,20 +17,47 @@
|
||||
#include "simplelicensing.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
|
||||
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;
|
||||
pkgconf_node_t *node = NULL;
|
||||
(void) iter_flags;
|
||||
|
||||
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;
|
||||
char *package_spdx = 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);
|
||||
|
||||
if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
|
||||
return;
|
||||
|
||||
if (ctx->failed)
|
||||
return;
|
||||
|
||||
spdx_id_string = spdxtool_util_get_spdx_id_string(client, "software_Sbom", pkg->id);
|
||||
if (!spdx_id_string)
|
||||
goto err;
|
||||
@@ -48,12 +75,16 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
|
||||
if (!package_spdx)
|
||||
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);
|
||||
package_spdx = NULL;
|
||||
|
||||
pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0);
|
||||
pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, 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) == NULL)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pkg->maintainer != NULL)
|
||||
{
|
||||
@@ -61,14 +92,15 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
|
||||
if (!supplier)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (!spdx_id_name)
|
||||
goto err;
|
||||
@@ -78,12 +110,14 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
|
||||
if (!package_spdx)
|
||||
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);
|
||||
package_spdx = NULL;
|
||||
|
||||
pkgconf_buffer_t concluded_buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep);
|
||||
if (!pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep))
|
||||
goto err;
|
||||
|
||||
spdx_id_name = pkgconf_buffer_freeze(&concluded_buf);
|
||||
if (!spdx_id_name)
|
||||
goto err;
|
||||
@@ -93,13 +127,14 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
|
||||
if (!package_spdx)
|
||||
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);
|
||||
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 (!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 (!node)
|
||||
if (!generate_spdx_document_add_sbom(client, document, sbom))
|
||||
goto err;
|
||||
|
||||
pkgconf_node_insert_tail(node, sbom, &document->rootElement);
|
||||
sbom = NULL;
|
||||
return;
|
||||
|
||||
err:
|
||||
ctx->failed = true;
|
||||
pkgconf_error(client, "generate_spdx_package: failed for %s", pkg->id);
|
||||
free(package_spdx);
|
||||
free(spdx_id_string);
|
||||
pkgconf_buffer_finalize(&spdx_id_buf);
|
||||
pkgconf_buffer_finalize(&concluded_buf);
|
||||
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 *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);
|
||||
if (!agent)
|
||||
@@ -136,10 +175,19 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
|
||||
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)
|
||||
{
|
||||
pkgconf_error(client, "Could not create creation info struct");
|
||||
spdxtool_core_tool_free(tool);
|
||||
spdxtool_core_agent_free(agent);
|
||||
return false;
|
||||
}
|
||||
@@ -155,8 +203,11 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
|
||||
return false;
|
||||
}
|
||||
|
||||
int eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, document, maxdepth, 0);
|
||||
if (eflag != PKGCONF_PKG_ERRF_OK)
|
||||
generate_spdx_ctx_t ctx = {
|
||||
.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_creation_info_free(creation);
|
||||
@@ -164,7 +215,7 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int
|
||||
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)
|
||||
{
|
||||
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;
|
||||
spdxtool_serialize_value_to_buf(&buffer, root, 0);
|
||||
bool ret = spdxtool_serialize_value_to_buf(&buffer, root, 0);
|
||||
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);
|
||||
|
||||
spdxtool_core_spdx_document_free(document);
|
||||
spdxtool_core_creation_info_free(creation);
|
||||
spdxtool_core_tool_free(tool);
|
||||
spdxtool_core_agent_free(agent);
|
||||
|
||||
if (!ret)
|
||||
pkgconf_error(client, "spdxtool: Could not output to file: %s", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
+23
-6
@@ -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-id Use string as creation id [default: '_:creationinfo_1']\n");
|
||||
printf(" --help this message\n");
|
||||
printf(" --about print bomtool version and license to stdout\n");
|
||||
printf(" --version print bomtool version to stdout\n");
|
||||
printf(" --about print spdxtool version and license to stdout\n");
|
||||
printf(" --version print spdxtool version to stdout\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(" --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. */
|
||||
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)
|
||||
{
|
||||
if (pkgconf_buffer_len(&queryparams) > 0)
|
||||
pkgconf_buffer_push_byte(&queryparams, ' ');
|
||||
if ((pkgconf_buffer_len(&queryparams) > 0 &&
|
||||
!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++;
|
||||
}
|
||||
|
||||
@@ -215,6 +225,13 @@ main(int argc, char *argv[])
|
||||
|
||||
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))
|
||||
{
|
||||
ret = EXIT_FAILURE;
|
||||
|
||||
+65
-45
@@ -18,48 +18,60 @@
|
||||
#include "simplelicensing.h"
|
||||
#include "serialize.h"
|
||||
|
||||
static void
|
||||
static bool
|
||||
serialize_escape_string(pkgconf_buffer_t *buffer, const char *s)
|
||||
{
|
||||
for (const char *p = s; *p; p++)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
switch (*p)
|
||||
{
|
||||
case '\"':
|
||||
pkgconf_buffer_append(buffer, "\\\"");
|
||||
ret = pkgconf_buffer_append(buffer, "\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
pkgconf_buffer_append(buffer, "\\\\");
|
||||
ret = pkgconf_buffer_append(buffer, "\\\\");
|
||||
break;
|
||||
case '\b':
|
||||
pkgconf_buffer_append(buffer, "\\b");
|
||||
ret = pkgconf_buffer_append(buffer, "\\b");
|
||||
break;
|
||||
case '\f':
|
||||
pkgconf_buffer_append(buffer, "\\f");
|
||||
ret = pkgconf_buffer_append(buffer, "\\f");
|
||||
break;
|
||||
case '\n':
|
||||
pkgconf_buffer_append(buffer, "\\n");
|
||||
ret = pkgconf_buffer_append(buffer, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
pkgconf_buffer_append(buffer, "\\r");
|
||||
ret = pkgconf_buffer_append(buffer, "\\r");
|
||||
break;
|
||||
case '\t':
|
||||
pkgconf_buffer_append(buffer, "\\t");
|
||||
ret = pkgconf_buffer_append(buffer, "\\t");
|
||||
break;
|
||||
default:
|
||||
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
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
case SPDXTOOL_SERIALIZE_TYPE_STRING:
|
||||
pkgconf_buffer_push_byte(buffer, '"');
|
||||
serialize_escape_string(buffer, value->value.s ? value->value.s : "");
|
||||
pkgconf_buffer_push_byte(buffer, '"');
|
||||
break;
|
||||
return pkgconf_buffer_push_byte(buffer, '"') &&
|
||||
serialize_escape_string(buffer, value->value.s ? value->value.s : "") &&
|
||||
pkgconf_buffer_push_byte(buffer, '"');
|
||||
case SPDXTOOL_SERIALIZE_TYPE_INT:
|
||||
pkgconf_buffer_append_fmt(buffer, "%d", value->value.i);
|
||||
break;
|
||||
return pkgconf_buffer_append_fmt(buffer, "%d", value->value.i);
|
||||
case SPDXTOOL_SERIALIZE_TYPE_BOOL:
|
||||
pkgconf_buffer_append(buffer, value->value.b ? "true" : "false");
|
||||
break;
|
||||
return pkgconf_buffer_append(buffer, value->value.b ? "true" : "false");
|
||||
case SPDXTOOL_SERIALIZE_TYPE_NULL:
|
||||
pkgconf_buffer_append(buffer, "null");
|
||||
break;
|
||||
return pkgconf_buffer_append(buffer, "null");
|
||||
case SPDXTOOL_SERIALIZE_TYPE_OBJECT:
|
||||
{
|
||||
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)
|
||||
{
|
||||
spdxtool_serialize_object_t *entry = iter->data;
|
||||
serialize_add_indent(buffer, indent + 1);
|
||||
pkgconf_buffer_append_fmt(buffer, "\"%s\": ", entry->key);
|
||||
spdxtool_serialize_value_to_buf(buffer, entry->value, indent + 1);
|
||||
if (iter->next)
|
||||
pkgconf_buffer_push_byte(buffer, ',');
|
||||
pkgconf_buffer_push_byte(buffer, '\n');
|
||||
|
||||
if (!serialize_add_indent(buffer, indent + 1) ||
|
||||
!pkgconf_buffer_push_byte(buffer, '"') ||
|
||||
!serialize_escape_string(buffer, entry->key ? entry->key : "") ||
|
||||
!pkgconf_buffer_append(buffer, "\": ") ||
|
||||
!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);
|
||||
pkgconf_buffer_push_byte(buffer, '}');
|
||||
break;
|
||||
return serialize_add_indent(buffer, indent) &&
|
||||
pkgconf_buffer_push_byte(buffer, '}');
|
||||
}
|
||||
case SPDXTOOL_SERIALIZE_TYPE_ARRAY:
|
||||
{
|
||||
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)
|
||||
{
|
||||
spdxtool_serialize_value_t *entry = iter->data;
|
||||
serialize_add_indent(buffer, indent + 1);
|
||||
spdxtool_serialize_value_to_buf(buffer, entry, indent + 1);
|
||||
if (iter->next)
|
||||
pkgconf_buffer_push_byte(buffer, ',');
|
||||
pkgconf_buffer_push_byte(buffer, '\n');
|
||||
|
||||
if (!serialize_add_indent(buffer, indent + 1) ||
|
||||
!spdxtool_serialize_value_to_buf(buffer, entry, indent + 1) ||
|
||||
(iter->next && !pkgconf_buffer_push_byte(buffer, ',')) ||
|
||||
!pkgconf_buffer_push_byte(buffer, '\n'))
|
||||
return false;
|
||||
}
|
||||
serialize_add_indent(buffer, indent);
|
||||
pkgconf_buffer_push_byte(buffer, ']');
|
||||
break;
|
||||
|
||||
return serialize_add_indent(buffer, indent) &&
|
||||
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.
|
||||
*/
|
||||
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";
|
||||
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)))
|
||||
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)))
|
||||
goto err;
|
||||
|
||||
|
||||
@@ -536,7 +536,7 @@ spdxtool_serialize_array_add_array(spdxtool_serialize_array_t *array, spdxtool_s
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
+76
-61
@@ -16,6 +16,25 @@
|
||||
#include "software.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
|
||||
*
|
||||
@@ -26,7 +45,7 @@
|
||||
* :param pkgconf_client_t *client: The pkgconf client being accessed.
|
||||
* :param const char *spdx_id: spdxId for this SBOM element
|
||||
* :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
|
||||
*/
|
||||
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_pkg_t *match = dep->match;
|
||||
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
/* an unresolved (but tolerated) dependency has no match */
|
||||
if (match == NULL)
|
||||
continue;
|
||||
|
||||
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id);
|
||||
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);
|
||||
char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep);
|
||||
if (!spdx_id_relation)
|
||||
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_pkg_t *match = dep->match;
|
||||
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
/* an unresolved (but tolerated) dependency has no match */
|
||||
if (match == NULL)
|
||||
continue;
|
||||
|
||||
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id);
|
||||
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);
|
||||
char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep);
|
||||
if (!spdx_id_relation)
|
||||
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)
|
||||
{
|
||||
const pkgconf_bufferset_t *set = node->data;
|
||||
pkgconf_buffer_join(©right_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL);
|
||||
if (!pkgconf_buffer_join(©right_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL))
|
||||
{
|
||||
pkgconf_buffer_finalize(©right_buf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ok = spdxtool_serialize_object_add_string(object_list, "software_copyrightText", pkgconf_buffer_str_or_empty(©right_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_object_list_t *object_list = NULL;
|
||||
spdxtool_serialize_array_t *originated_by = NULL;
|
||||
spdxtool_serialize_array_t *supplied_by = NULL;
|
||||
char *creation_info = NULL;
|
||||
char *spdx_id = NULL;
|
||||
char *agent = NULL;
|
||||
@@ -368,20 +376,8 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
|
||||
goto err;
|
||||
|
||||
supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy");
|
||||
if (supplier)
|
||||
{
|
||||
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 (supplier && !spdxtool_serialize_object_add_string(object_list, "suppliedBy", supplier))
|
||||
goto err;
|
||||
|
||||
if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright))
|
||||
goto err;
|
||||
@@ -410,7 +406,8 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
|
||||
if (!spdx_id_license)
|
||||
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);
|
||||
spdx_id_license = NULL;
|
||||
}
|
||||
@@ -426,14 +423,21 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
|
||||
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");
|
||||
free(tuple_license);
|
||||
if (!relationship)
|
||||
goto err;
|
||||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||||
goto err;
|
||||
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");
|
||||
@@ -446,14 +450,21 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
|
||||
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");
|
||||
free(tuple_license);
|
||||
if (!relationship)
|
||||
goto err;
|
||||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||||
goto err;
|
||||
cpy_relations = NULL;
|
||||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||||
{
|
||||
spdxtool_core_relationship_free(relationship);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
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_pkg_t *match = dep->match;
|
||||
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
/* an unresolved (but tolerated) dependency has no match */
|
||||
if (match == NULL)
|
||||
continue;
|
||||
|
||||
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id);
|
||||
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);
|
||||
char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep);
|
||||
if (!spdx_id_relation)
|
||||
goto err;
|
||||
|
||||
@@ -492,34 +496,35 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
|
||||
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");
|
||||
free(spdx_id_relation);
|
||||
free(spdx_id_package);
|
||||
if (!relationship)
|
||||
goto err;
|
||||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||||
goto err;
|
||||
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_dependency_t *dep = node->data;
|
||||
pkgconf_pkg_t *match = dep->match;
|
||||
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
/* an unresolved (but tolerated) dependency has no match */
|
||||
if (match == NULL)
|
||||
continue;
|
||||
|
||||
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id);
|
||||
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);
|
||||
char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep);
|
||||
if (!spdx_id_relation)
|
||||
goto err;
|
||||
|
||||
@@ -538,7 +543,12 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
|
||||
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");
|
||||
free(spdx_id_relation);
|
||||
free(spdx_id_package);
|
||||
@@ -569,8 +579,13 @@ err:
|
||||
free(agent);
|
||||
free(supplier);
|
||||
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_array_free(originated_by);
|
||||
spdxtool_serialize_array_free(supplied_by);
|
||||
return ret;
|
||||
}
|
||||
+110
-6
@@ -16,12 +16,82 @@
|
||||
#include <ctype.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
|
||||
*
|
||||
* .. 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 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);
|
||||
char sep = spdxtool_util_get_uri_separator(client);
|
||||
pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER;
|
||||
pkgconf_buffer_t escaped_uri = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, NULL);
|
||||
pkgconf_buffer_append_fmt(¤t_uri, "%c" SIZE_FMT_SPECIFIER, sep, ++last_id);
|
||||
if (last_id == SIZE_MAX ||
|
||||
!pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, NULL) ||
|
||||
!pkgconf_buffer_append_fmt(¤t_uri, "%c" SIZE_FMT_SPECIFIER, sep, last_id + 1))
|
||||
{
|
||||
pkgconf_buffer_finalize(¤t_uri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pkgconf_buffer_freeze(¤t_uri);
|
||||
last_id++;
|
||||
|
||||
if (!util_escape_uri_string(&escaped_uri, ¤t_uri))
|
||||
{
|
||||
pkgconf_buffer_finalize(¤t_uri);
|
||||
pkgconf_buffer_finalize(&escaped_uri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkgconf_buffer_finalize(¤t_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);
|
||||
char sep = spdxtool_util_get_uri_separator(client);
|
||||
pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER;
|
||||
pkgconf_buffer_t escaped_uri = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, string_id, NULL);
|
||||
if (!pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, string_id, NULL))
|
||||
{
|
||||
pkgconf_buffer_finalize(¤t_uri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pkgconf_buffer_freeze(¤t_uri);
|
||||
if (!util_escape_uri_string(&escaped_uri, ¤t_uri))
|
||||
{
|
||||
pkgconf_buffer_finalize(¤t_uri);
|
||||
pkgconf_buffer_finalize(&escaped_uri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkgconf_buffer_finalize(¤t_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;
|
||||
|
||||
if (!pkgconf_variable_eval(client, vars, v, &buf, NULL))
|
||||
{
|
||||
pkgconf_buffer_finalize(&buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pkgconf_buffer_freeze(&buf);
|
||||
}
|
||||
+10
-1
@@ -28,13 +28,22 @@ typedef struct spdxtool_core_agent_
|
||||
char *name;
|
||||
} 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_
|
||||
{
|
||||
char *id;
|
||||
const char *type;
|
||||
char *created;
|
||||
char *created_by;
|
||||
const char *created_using;
|
||||
char *create_using;
|
||||
char *created_using;
|
||||
char *spec_version;
|
||||
} spdxtool_core_creation_info_t;
|
||||
|
||||
|
||||
+4
-2
@@ -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.
|
||||
|
||||
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([
|
||||
===================================================================
|
||||
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([-Wformat=2], [CFLAGS="$CFLAGS -Wformat=2"])
|
||||
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_CHECK_DECLS([strndup], [], [], [[#include <string.h>]])
|
||||
AC_CHECK_DECLS([pledge, unveil], [], [], [[#include <unistd.h>]])
|
||||
AC_CHECK_DECLS([readlinkat], [], [], [[#include <unistd.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], [], [], [[
|
||||
#ifdef __APPLE__
|
||||
#include <xlocale.h>
|
||||
|
||||
+22
-11
@@ -25,7 +25,9 @@
|
||||
|
||||
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
|
||||
|
||||
/* 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 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 *
|
||||
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 */
|
||||
run_spdx(pers, dir, out);
|
||||
|
||||
/* then fail each allocation site reachable by this input, one at a time */
|
||||
for (unsigned long i = 1; i <= ALLOC_FAIL_MAX; i++)
|
||||
{
|
||||
alloc_inject_arm(i);
|
||||
run_spdx(pers, dir, out);
|
||||
alloc_inject_disarm();
|
||||
|
||||
if (!alloc_inject_fired())
|
||||
break;
|
||||
}
|
||||
/* Exercise one deterministic allocation failure per input. Mutations vary
|
||||
* the selected site, while keeping the per-input cost constant. */
|
||||
alloc_inject_arm(allocation_failure_for_input(data, size));
|
||||
run_spdx(pers, dir, out);
|
||||
alloc_inject_disarm();
|
||||
|
||||
pkgconf_cross_personality_deinit(pers);
|
||||
fclose(out);
|
||||
|
||||
@@ -8,6 +8,7 @@ datadir=@datadir@
|
||||
Name: libpkgconf
|
||||
Description: a library for accessing and manipulating development framework configuration
|
||||
URL: https://github.com/pkgconf/pkgconf
|
||||
Maintainer: Ariadne Conill <[email protected]>
|
||||
License: ISC
|
||||
License.file: ${datadir}/doc/pkgconf/COPYING
|
||||
Source: https://github.com/pkgconf/pkgconf
|
||||
|
||||
+69
-13
@@ -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)
|
||||
*
|
||||
* Splits a string into an argument vector.
|
||||
*
|
||||
* :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
|
||||
* 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
|
||||
* else, leaving it spelled exactly as it was written. Otherwise they are
|
||||
* consumed, as a shell would consume them.
|
||||
*/
|
||||
int
|
||||
pkgconf_argv_split(const char *src, int *argc, char ***argv)
|
||||
static int
|
||||
argv_split(const char *src, int *argc, char ***argv, bool raw)
|
||||
{
|
||||
char *buf = calloc(1, strlen(src) + 1);
|
||||
if (buf == NULL)
|
||||
@@ -92,7 +87,7 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
|
||||
if (escaped)
|
||||
{
|
||||
/* 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 == '\\'))
|
||||
*dst_iter++ = '\\';
|
||||
@@ -109,9 +104,19 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
|
||||
else if (quote)
|
||||
{
|
||||
if (*src_iter == quote)
|
||||
{
|
||||
quote = 0;
|
||||
|
||||
if (raw)
|
||||
*dst_iter++ = *src_iter;
|
||||
}
|
||||
else if (*src_iter == '\\' && quote != '\'')
|
||||
{
|
||||
escaped = true;
|
||||
|
||||
if (raw)
|
||||
*dst_iter++ = *src_iter;
|
||||
}
|
||||
else
|
||||
*dst_iter++ = *src_iter;
|
||||
}
|
||||
@@ -145,11 +150,17 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
|
||||
{
|
||||
case '\\':
|
||||
escaped = true;
|
||||
|
||||
if (raw)
|
||||
*dst_iter++ = *src_iter;
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
case '\'':
|
||||
quote = *src_iter;
|
||||
|
||||
if (raw)
|
||||
*dst_iter++ = *src_iter;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -176,3 +187,48 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv)
|
||||
*argc = argc_count;
|
||||
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);
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
#else
|
||||
/*
|
||||
* 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 *
|
||||
pkgconf_strndup_impl(const char *src, size_t len)
|
||||
|
||||
+232
-48
@@ -28,10 +28,69 @@
|
||||
* dynamically-allocated buffers.
|
||||
*/
|
||||
|
||||
static inline size_t
|
||||
target_allocation_size(size_t target_size)
|
||||
/* buffers below BUFFER_LINEAR_GROWTH_MAX increment by 128 bytes each time */
|
||||
#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
|
||||
@@ -53,6 +112,7 @@ buffer_debug(pkgconf_buffer_t *buffer)
|
||||
* .. c:function:: bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
|
||||
*
|
||||
* 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 char *text: The null-terminated string to append.
|
||||
@@ -61,20 +121,27 @@ buffer_debug(pkgconf_buffer_t *buffer)
|
||||
bool
|
||||
pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
|
||||
{
|
||||
size_t needed = strlen(text) + 1;
|
||||
size_t newsize = pkgconf_buffer_len(buffer) + needed;
|
||||
size_t len = pkgconf_buffer_len(buffer);
|
||||
size_t text_len = strlen(text);
|
||||
|
||||
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
|
||||
if (newbase == NULL)
|
||||
if (text_len == SIZE_MAX)
|
||||
return false;
|
||||
|
||||
char *newend = newbase + pkgconf_buffer_len(buffer);
|
||||
memcpy(newend, text, needed);
|
||||
if (buffer_storage_overlaps(buffer, text, text_len + 1))
|
||||
return false;
|
||||
|
||||
buffer->base = newbase;
|
||||
buffer->end = newend + (needed - 1);
|
||||
if (len > SIZE_MAX - text_len)
|
||||
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';
|
||||
|
||||
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)
|
||||
*
|
||||
* 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 char *p: Pointer to the byte sequence to append.
|
||||
@@ -93,14 +161,25 @@ pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text)
|
||||
bool
|
||||
pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n)
|
||||
{
|
||||
size_t len = pkgconf_buffer_len(buf);
|
||||
|
||||
if (n == 0)
|
||||
return true;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
if (!pkgconf_buffer_push_byte(buf, p[i]))
|
||||
return false;
|
||||
}
|
||||
if (buffer_storage_overlaps(buf, p, n))
|
||||
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;
|
||||
}
|
||||
@@ -120,27 +199,32 @@ pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n)
|
||||
bool
|
||||
pkgconf_buffer_append_vfmt(pkgconf_buffer_t *buffer, const char *fmt, va_list src_va)
|
||||
{
|
||||
char stackbuf[256];
|
||||
va_list va;
|
||||
char *buf;
|
||||
size_t needed;
|
||||
int formatted_len;
|
||||
|
||||
va_copy(va, src_va);
|
||||
needed = vsnprintf(NULL, 0, fmt, va) + 1;
|
||||
formatted_len = vsnprintf(stackbuf, sizeof stackbuf, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
buf = malloc(needed);
|
||||
if (buf == NULL)
|
||||
if (formatted_len < 0)
|
||||
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;
|
||||
|
||||
va_copy(va, src_va);
|
||||
vsnprintf(buf, needed, fmt, va);
|
||||
vsnprintf(buffer->base + len, (size_t) formatted_len + 1, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
bool ret = pkgconf_buffer_append(buffer, buf);
|
||||
buffer->end = buffer->base + len + (size_t) formatted_len;
|
||||
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -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.
|
||||
* 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 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_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))
|
||||
return false;
|
||||
@@ -193,11 +288,11 @@ pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text)
|
||||
}
|
||||
|
||||
if (pkgconf_buffer_len(&tmpbuf))
|
||||
pkgconf_buffer_copy(&tmpbuf, buffer);
|
||||
ret = pkgconf_buffer_copy(&tmpbuf, buffer);
|
||||
|
||||
pkgconf_buffer_finalize(&tmpbuf);
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -214,17 +309,19 @@ pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text)
|
||||
bool
|
||||
pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte)
|
||||
{
|
||||
size_t newsize = pkgconf_buffer_len(buffer) + 1;
|
||||
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
|
||||
if (newbase == NULL)
|
||||
size_t len = pkgconf_buffer_len(buffer);
|
||||
|
||||
if (len == SIZE_MAX)
|
||||
return false;
|
||||
|
||||
char *newend = newbase + newsize;
|
||||
*(newend - 1) = byte;
|
||||
*newend = '\0';
|
||||
size_t new_len = len + 1;
|
||||
if (!buffer_reserve(buffer, new_len))
|
||||
return false;
|
||||
|
||||
buffer->base = newbase;
|
||||
buffer->end = newend;
|
||||
buffer->base[len] = byte;
|
||||
|
||||
buffer->end = buffer->base + new_len;
|
||||
*buffer->end = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -246,14 +343,11 @@ pkgconf_buffer_trim_byte(pkgconf_buffer_t *buffer)
|
||||
if (len == 0)
|
||||
return false;
|
||||
|
||||
size_t newsize = len - 1;
|
||||
char *newbase = realloc(buffer->base, target_allocation_size(newsize));
|
||||
|
||||
if (newbase == NULL)
|
||||
size_t new_len = len - 1;
|
||||
if (!buffer_reserve(buffer, new_len))
|
||||
return false;
|
||||
|
||||
buffer->base = newbase;
|
||||
buffer->end = newbase + newsize;
|
||||
buffer->end = buffer->base + new_len;
|
||||
*(buffer->end) = '\0';
|
||||
|
||||
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*.
|
||||
* 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 *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;
|
||||
|
||||
if (dest == src ||
|
||||
buffer_storage_overlaps(dest, src->base, pkgconf_buffer_len(src) + 1))
|
||||
return false;
|
||||
|
||||
if (pattern == NULL)
|
||||
pattern = "";
|
||||
|
||||
@@ -480,6 +579,9 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const
|
||||
value = "";
|
||||
|
||||
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))
|
||||
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
|
||||
* 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 *src: The source buffer.
|
||||
@@ -522,23 +625,104 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const
|
||||
*/
|
||||
bool
|
||||
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 *run = p;
|
||||
|
||||
if (dest == src ||
|
||||
buffer_storage_overlaps(dest, src->base, pkgconf_buffer_len(src) + 1))
|
||||
return false;
|
||||
|
||||
if (!pkgconf_buffer_len(src))
|
||||
return true;
|
||||
|
||||
for (; *p; p++)
|
||||
{
|
||||
if (pkgconf_span_contains((unsigned char) *p, spans, nspans))
|
||||
{
|
||||
if (!pkgconf_buffer_push_byte(dest, '\\'))
|
||||
return false;
|
||||
}
|
||||
if (!pkgconf_charset_contains(charset, (unsigned char) *p))
|
||||
continue;
|
||||
|
||||
if (!pkgconf_buffer_push_byte(dest, *p))
|
||||
if (p > run && !pkgconf_buffer_append_slice(dest, run, (size_t) (p - run)))
|
||||
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;
|
||||
}
|
||||
+48
-30
@@ -64,6 +64,21 @@ pkgconf_bytecode_eval_append(pkgconf_bytecode_eval_ctx_t *ctx, pkgconf_buffer_t
|
||||
static bool
|
||||
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 *
|
||||
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)
|
||||
return false;
|
||||
|
||||
if (bc->len != 0 && bc->base == NULL)
|
||||
return false;
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -150,15 +168,12 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b
|
||||
return false;
|
||||
}
|
||||
|
||||
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 ((const uint8_t *)op + sizeof(*op) > end)
|
||||
return false;
|
||||
|
||||
if ((const uint8_t *)op + sizeof(*op) + op->size > end)
|
||||
if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size))
|
||||
return false;
|
||||
|
||||
switch (op->tag)
|
||||
@@ -186,7 +201,8 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b
|
||||
return false;
|
||||
}
|
||||
|
||||
p = (const uint8_t *)pkgconf_bytecode_op_next(op);
|
||||
p += op_size;
|
||||
remaining -= op_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -301,7 +317,7 @@ void
|
||||
pkgconf_bytecode_from_buffer(pkgconf_bytecode_t *bc, const pkgconf_buffer_t *buf)
|
||||
{
|
||||
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
|
||||
@@ -446,24 +462,23 @@ pkgconf_bytecode_eval_str(const pkgconf_client_t *client, const pkgconf_list_t *
|
||||
bool
|
||||
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;
|
||||
|
||||
if (buf == NULL || key == NULL)
|
||||
return false;
|
||||
|
||||
klen = strlen(key);
|
||||
p = (uint8_t *) buf->base;
|
||||
end = (uint8_t *) buf->end;
|
||||
p = (const uint8_t *) buf->base;
|
||||
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)
|
||||
return false;
|
||||
|
||||
if (p + sizeof(*op) + op->size > end)
|
||||
if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size))
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
p += sizeof(*op) + op->size;
|
||||
p += op_size;
|
||||
remaining -= op_size;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -504,17 +520,18 @@ pkgconf_bytecode_append_stream(pkgconf_buffer_t *dst, const pkgconf_buffer_t *bc
|
||||
bool
|
||||
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;
|
||||
const uint8_t *end = (uint8_t *) rhs->end;
|
||||
if (out == NULL || rhs == NULL || key == NULL || prev == NULL)
|
||||
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)
|
||||
return false;
|
||||
|
||||
if (p + sizeof(*op) + op->size > end)
|
||||
if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size))
|
||||
return false;
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
p += sizeof(*op) + op->size;
|
||||
p += op_size;
|
||||
remaining -= op_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+24
-45
@@ -42,37 +42,6 @@ cache_member_cmp(const void *a, const void *b)
|
||||
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
|
||||
*
|
||||
@@ -127,6 +96,13 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
|
||||
if (pkg == NULL)
|
||||
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_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[client->cache_count - 1] = pkg;
|
||||
|
||||
qsort(client->cache_table, client->cache_count,
|
||||
sizeof(void *), cache_member_sort_cmp);
|
||||
size_t lo = 0, hi = client->cache_count - 1;
|
||||
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);
|
||||
}
|
||||
@@ -192,18 +179,10 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
|
||||
|
||||
(*slot)->flags &= ~PKGCONF_PKG_PROPF_CACHED;
|
||||
pkgconf_pkg_unref(client, *slot);
|
||||
*slot = NULL;
|
||||
|
||||
qsort(client->cache_table, client->cache_count,
|
||||
sizeof(void *), cache_member_sort_cmp);
|
||||
|
||||
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();
|
||||
}
|
||||
size_t idx = (size_t)(slot - client->cache_table);
|
||||
memmove(&client->cache_table[idx], &client->cache_table[idx + 1],
|
||||
(client->cache_count - idx - 1) * sizeof(void *));
|
||||
|
||||
client->cache_count--;
|
||||
if (client->cache_count > 0)
|
||||
|
||||
+76
-15
@@ -108,11 +108,38 @@ pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_pers
|
||||
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_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->client_data = client_data;
|
||||
client->environ_lookup_handler = environ_lookup_handler;
|
||||
client->error_handler_data = error_handler_data;
|
||||
client->error_handler = error_handler;
|
||||
client->client_data = options->client_data;
|
||||
client->environ_lookup_handler = options->environ_lookup_handler;
|
||||
client->error_handler_data = options->error_handler_data;
|
||||
client->error_handler = options->error_handler;
|
||||
client->auditf = NULL;
|
||||
client->cache_table = NULL;
|
||||
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);
|
||||
#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_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_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_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));
|
||||
if (out == 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/* 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_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;
|
||||
|
||||
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_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");
|
||||
client->unveil_handler = default_unveil_handler;
|
||||
}
|
||||
else
|
||||
PKGCONF_TRACE(client, "installing custom unveil handler");
|
||||
}
|
||||
|
||||
#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_data = trace_handler_data;
|
||||
|
||||
if (client->trace_handler == NULL)
|
||||
{
|
||||
client->trace_handler = pkgconf_default_error_handler;
|
||||
PKGCONF_TRACE(client, "installing default trace handler");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -825,7 +883,10 @@ pkgconf_client_preload_path(pkgconf_client_t *client, const char *path)
|
||||
if (pkg == NULL)
|
||||
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
|
||||
* 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.
|
||||
* :return: the environmental variable contents else NULL
|
||||
* :rtype: const char*
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
/* 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. */
|
||||
#mesondefine HAVE_STRNDUP
|
||||
|
||||
@@ -24,36 +18,30 @@
|
||||
/* Define to 1 if you have the `unveil' function. */
|
||||
#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. */
|
||||
#mesondefine HAVE_DECL_NL_LANGINFO_L
|
||||
|
||||
/* Name of package */
|
||||
#mesondefine PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#mesondefine PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#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. */
|
||||
#mesondefine PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#mesondefine PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#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. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
|
||||
+42
-8
@@ -43,10 +43,12 @@ static inline const char *
|
||||
dependency_to_buf(const pkgconf_dependency_t *dep, pkgconf_buffer_t *buf)
|
||||
{
|
||||
pkgconf_buffer_reset(buf);
|
||||
pkgconf_buffer_append(buf, dep->package);
|
||||
if (!pkgconf_buffer_append(buf, dep->package))
|
||||
return NULL;
|
||||
|
||||
if (dep->version != NULL)
|
||||
pkgconf_buffer_append_fmt(buf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version);
|
||||
if (dep->version != NULL &&
|
||||
!pkgconf_buffer_append_fmt(buf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version))
|
||||
return NULL;
|
||||
|
||||
return pkgconf_buffer_str(buf);
|
||||
}
|
||||
@@ -71,18 +73,34 @@ find_colliding_dependency(const pkgconf_dependency_t *dep, const pkgconf_list_t
|
||||
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 *
|
||||
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_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 */
|
||||
if (dep2 != NULL)
|
||||
{
|
||||
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]",
|
||||
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)
|
||||
{
|
||||
dep->version = pkgconf_strndup(version, version_sz);
|
||||
if (dep->version == NULL)
|
||||
{
|
||||
pkgconf_dependency_free_one(dep);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dep->compare = compare;
|
||||
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))
|
||||
break;
|
||||
|
||||
pkgconf_buffer_reset(&cmpname);
|
||||
pkgconf_buffer_append_slice(&cmpname, opstart, ptr - opstart);
|
||||
pkgconf_buffer_rewind(&cmpname);
|
||||
if (!pkgconf_buffer_append_slice(&cmpname, opstart, ptr - opstart))
|
||||
goto out;
|
||||
|
||||
compare = pkgconf_pkg_comparator_lookup_by_name(pkgconf_buffer_str(&cmpname));
|
||||
state = AFTER_OPERATOR;
|
||||
// fallthrough
|
||||
@@ -439,7 +466,7 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
|
||||
compare = PKGCONF_CMP_ANY;
|
||||
package_sz = 0;
|
||||
opstart = NULL;
|
||||
pkgconf_buffer_reset(&cmpname);
|
||||
pkgconf_buffer_rewind(&cmpname);
|
||||
}
|
||||
|
||||
if (state == OUTSIDE_MODULE)
|
||||
@@ -508,7 +535,14 @@ pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *de
|
||||
}
|
||||
|
||||
if (dep->version != NULL)
|
||||
{
|
||||
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->flags = dep->flags;
|
||||
|
||||
+53
-79
@@ -15,107 +15,81 @@
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <libpkgconf/config.h>
|
||||
#include <libpkgconf/stdinc.h>
|
||||
#include <libpkgconf/libpkgconf.h>
|
||||
|
||||
#define push_or_return_fail(buf, c) \
|
||||
do { if (!pkgconf_buffer_push_byte((buf), (char) (c))) return false; } while (0)
|
||||
|
||||
#define trim_or_return_fail(buf) \
|
||||
do { if (!pkgconf_buffer_trim_byte((buf))) return false; } while (0)
|
||||
#if HAVE_DECL_GETC_UNLOCKED
|
||||
# define pkgconf_getc(stream) getc_unlocked(stream)
|
||||
#else
|
||||
# define pkgconf_getc(stream) getc(stream)
|
||||
#endif
|
||||
|
||||
bool
|
||||
pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream)
|
||||
{
|
||||
bool quoted = false;
|
||||
bool got_data = false;
|
||||
char in[PKGCONF_ITEM_SIZE];
|
||||
long unread = 0;
|
||||
char run[256];
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
if (quoted)
|
||||
{
|
||||
quoted = false;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
push_or_return_fail(buffer, (char) c);
|
||||
|
||||
goto done;
|
||||
}
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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 (unread > 0 && fseek(stream, -unread, SEEK_CUR) != 0)
|
||||
if (runlen != 0 && !pkgconf_buffer_append_slice(buffer, run, runlen))
|
||||
return false;
|
||||
|
||||
/* Remove newline character. */
|
||||
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);
|
||||
return got_data && !ferror(stream);
|
||||
}
|
||||
+628
-246
File diff suppressed because it is too large.
Load diff
@@ -46,6 +46,26 @@ pkgconf_list_zero(pkgconf_list_t *list)
|
||||
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
|
||||
pkgconf_node_insert(pkgconf_node_t *node, void *data, pkgconf_list_t *list)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
# else
|
||||
# define PKGCONF_API __declspec(dllimport)
|
||||
# endif
|
||||
#elif defined(__OS2__)
|
||||
# if defined(LIBPKGCONF_EXPORT) || defined(DLL_EXPORT)
|
||||
# define PKGCONF_API __declspec(dllexport)
|
||||
# else
|
||||
# define PKGCONF_API
|
||||
# endif
|
||||
#else
|
||||
# define PKGCONF_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
+105
-21
@@ -71,8 +71,8 @@ typedef struct pkgconf_license_ pkgconf_license_t;
|
||||
#define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \
|
||||
for ((value) = (tail); (value) != NULL; (value) = (value)->prev)
|
||||
|
||||
#define LIBPKGCONF_VERSION 20993
|
||||
#define LIBPKGCONF_VERSION_STR "2.9.93"
|
||||
#define LIBPKGCONF_VERSION 30009
|
||||
#define LIBPKGCONF_VERSION_STR "3.0.9"
|
||||
|
||||
struct pkgconf_queue_ {
|
||||
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 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_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 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_ {
|
||||
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 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_name(pkgconf_client_t *client, const pkgconf_list_t *vars, const char *varname);
|
||||
|
||||
/* 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_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_with_options(const pkgconf_client_options_t *options);
|
||||
PKGCONF_API void pkgconf_client_deinit(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);
|
||||
@@ -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_NO_CACHE 0x0040
|
||||
#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_REDEFINE_PREFIX 0x0400
|
||||
#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_PKGCONF1_SYSROOT_RULES 0x10000
|
||||
#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_PRIVATE 0x2
|
||||
@@ -457,11 +475,15 @@ PKGCONF_API bool pkgconf_default_error_handler(const char *msg, const pkgconf_cl
|
||||
#ifndef PKGCONF_LITE
|
||||
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
|
||||
#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)
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
#else
|
||||
@@ -499,6 +521,7 @@ PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_copy(pkgconf_client_t *clie
|
||||
|
||||
/* argvsplit.c */
|
||||
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);
|
||||
|
||||
/* fragment.c */
|
||||
@@ -508,29 +531,46 @@ typedef struct pkgconf_fragment_render_ctx_ {
|
||||
} pkgconf_fragment_render_ctx_t;
|
||||
|
||||
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;
|
||||
|
||||
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 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_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_delete(pkgconf_list_t *list, pkgconf_fragment_t *node);
|
||||
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_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_is_locale_utf8(void);
|
||||
|
||||
/* 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 void 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_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base);
|
||||
PKGCONF_API bool 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(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_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_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data);
|
||||
PKGCONF_API bool pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf);
|
||||
|
||||
/* 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);
|
||||
@@ -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 void pkgconf_path_free(pkgconf_list_t *dirlist);
|
||||
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_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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_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);
|
||||
@@ -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_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_charset(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_charset_t *charset);
|
||||
|
||||
/*
|
||||
* !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)
|
||||
{
|
||||
if (buffer->base == NULL)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* !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
|
||||
*
|
||||
* .. c:function:: static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer)
|
||||
*
|
||||
* Free the underlying buffer, copying the underlying string.
|
||||
* The string must be freed by the caller.
|
||||
* Hand ownership of the underlying storage to the caller as a string and
|
||||
* empty the buffer. The string must be freed by the caller.
|
||||
*
|
||||
* :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)
|
||||
{
|
||||
if (buffer->base == NULL)
|
||||
return NULL;
|
||||
char *out = buffer->base;
|
||||
|
||||
buffer->base = buffer->end = NULL;
|
||||
|
||||
char *out = pkgconf_strndup(pkgconf_buffer_str(buffer), pkgconf_buffer_len(buffer));
|
||||
pkgconf_buffer_reset(buffer);
|
||||
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)
|
||||
*
|
||||
* 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 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)
|
||||
{
|
||||
if (buffer == newptr || (buffer->base != NULL && buffer->base == newptr->base))
|
||||
return false;
|
||||
|
||||
pkgconf_buffer_reset(newptr);
|
||||
return pkgconf_buffer_append_slice(newptr, pkgconf_buffer_str(buffer), pkgconf_buffer_len(buffer));
|
||||
}
|
||||
|
||||
+144
-100
@@ -18,7 +18,7 @@
|
||||
#include <libpkgconf/stdinc.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;
|
||||
/*
|
||||
@@ -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] == ':')
|
||||
{
|
||||
pkgconf_buffer_push_byte(buf, s[i]);
|
||||
if (!pkgconf_buffer_push_byte(buf, s[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* !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`
|
||||
*
|
||||
* :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* 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_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));
|
||||
|
||||
if (cpy_license == NULL)
|
||||
continue;
|
||||
return false;
|
||||
|
||||
cpy_license->type = license->type;
|
||||
|
||||
if (license->data != NULL)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -97,12 +107,14 @@ pkgconf_license_free(pkgconf_list_t *list)
|
||||
free(license->data);
|
||||
free(license);
|
||||
}
|
||||
|
||||
pkgconf_list_zero(list);
|
||||
}
|
||||
|
||||
/*
|
||||
* !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.
|
||||
*
|
||||
@@ -110,31 +122,39 @@ pkgconf_license_free(pkgconf_list_t *list)
|
||||
* :param pkgconf_list_t* list: The fragment list.
|
||||
* :param char type: The type 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)
|
||||
{
|
||||
(void) client;
|
||||
|
||||
pkgconf_license_t *license;
|
||||
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
license = calloc(1, sizeof(pkgconf_license_t));
|
||||
if (!license)
|
||||
{
|
||||
pkgconf_error(client, "pkgconf_license_insert: out of memory");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
license->type = type;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* !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:
|
||||
* - 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 char* expression: The dependency data to parse.
|
||||
* :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_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;
|
||||
|
||||
if (expression == NULL)
|
||||
return;
|
||||
return true;
|
||||
|
||||
buf_size = strlen(expression) + 1;
|
||||
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:
|
||||
* so add AND
|
||||
*/
|
||||
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);
|
||||
if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND"))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* .. 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:
|
||||
* - 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 char* expression: The dependency data to parse.
|
||||
* :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)
|
||||
{
|
||||
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);
|
||||
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.
|
||||
* :return: nothing
|
||||
*/
|
||||
void
|
||||
bool
|
||||
pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf)
|
||||
{
|
||||
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;
|
||||
is_delim = true;
|
||||
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))
|
||||
{
|
||||
@@ -323,7 +364,10 @@ pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkg
|
||||
|
||||
if (node->next != NULL && is_delim)
|
||||
{
|
||||
pkgconf_buffer_push_byte(buf, ' ');
|
||||
if (!pkgconf_buffer_push_byte(buf, ' '))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
+18
-8
@@ -24,11 +24,15 @@ pkgconf_output_putbuf(pkgconf_output_t *output, pkgconf_output_stream_t stream,
|
||||
bool ret;
|
||||
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
if (pkgconf_buffer_len(buffer) != 0)
|
||||
pkgconf_buffer_append(&buf, pkgconf_buffer_str(buffer));
|
||||
if (pkgconf_buffer_len(buffer) != 0 &&
|
||||
!pkgconf_buffer_append(&buf, pkgconf_buffer_str(buffer)))
|
||||
return false;
|
||||
|
||||
if (newline)
|
||||
pkgconf_buffer_push_byte(&buf, '\n');
|
||||
if (newline && !pkgconf_buffer_push_byte(&buf, '\n'))
|
||||
{
|
||||
pkgconf_buffer_finalize(&buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = output->write(output, stream, &buf);
|
||||
pkgconf_buffer_finalize(&buf);
|
||||
@@ -42,8 +46,13 @@ pkgconf_output_puts(pkgconf_output_t *output, pkgconf_output_stream_t stream, co
|
||||
bool ret;
|
||||
pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
pkgconf_buffer_append(&buf, str);
|
||||
pkgconf_buffer_push_byte(&buf, '\n');
|
||||
if (!pkgconf_buffer_append(&buf, str) ||
|
||||
!pkgconf_buffer_push_byte(&buf, '\n'))
|
||||
{
|
||||
pkgconf_buffer_finalize(&buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = output->write(output, stream, &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;
|
||||
|
||||
va_copy(va, src_va);
|
||||
pkgconf_buffer_append_vfmt(&buf, fmt, va);
|
||||
ret = pkgconf_buffer_append_vfmt(&buf, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
ret = output->write(output, stream, &buf);
|
||||
if (ret)
|
||||
ret = output->write(output, stream, &buf);
|
||||
pkgconf_buffer_finalize(&buf);
|
||||
|
||||
return ret;
|
||||
|
||||
+1
-1
@@ -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);
|
||||
pkgconf_parser_parse_buffer(data, ops, warnfunc, &readbuf, warnprefix);
|
||||
pkgconf_buffer_reset(&readbuf);
|
||||
pkgconf_buffer_rewind(&readbuf);
|
||||
}
|
||||
|
||||
pkgconf_buffer_finalize(&readbuf);
|
||||
|
||||
+60
-36
@@ -67,8 +67,14 @@ prepare_path_node(const char *text, pkgconf_list_t *dirlist, bool filter)
|
||||
pkgconf_path_t *node;
|
||||
pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
pkgconf_buffer_append(&pathbuf, text);
|
||||
pkgconf_path_relocate(&pathbuf);
|
||||
if (!pkgconf_buffer_append(&pathbuf, text))
|
||||
return NULL;
|
||||
|
||||
if (!pkgconf_path_relocate(&pathbuf))
|
||||
{
|
||||
pkgconf_buffer_finalize(&pathbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef PKGCONF_CACHE_INODES
|
||||
struct stat st;
|
||||
@@ -267,7 +273,9 @@ pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
|
||||
if (path == NULL)
|
||||
return false;
|
||||
|
||||
pkgconf_buffer_append(&relocated, path);
|
||||
if (!pkgconf_buffer_append(&relocated, path))
|
||||
return false;
|
||||
|
||||
cpath = pkgconf_buffer_str(&relocated);
|
||||
|
||||
if (pkgconf_path_relocate(&relocated))
|
||||
@@ -400,32 +408,32 @@ pkgconf_path_free(pkgconf_list_t *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)
|
||||
return NULL;
|
||||
|
||||
const char *path = pkgconf_buffer_str(pathbuf);
|
||||
char *copy = strdup(path);
|
||||
if (NULL == copy)
|
||||
return NULL;
|
||||
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;
|
||||
#ifdef _WIN32
|
||||
for (; *path != '\0'; path++)
|
||||
if (*path == PKG_DIR_SEP_S)
|
||||
*path = '/';
|
||||
#else
|
||||
(void) path;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -433,7 +441,8 @@ normpath(const pkgconf_buffer_t *pathbuf)
|
||||
*
|
||||
* .. 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.
|
||||
* :return: true on success, false on error
|
||||
@@ -442,15 +451,30 @@ normpath(const pkgconf_buffer_t *pathbuf)
|
||||
bool
|
||||
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);
|
||||
pkgconf_buffer_append(buf, tmpbuf);
|
||||
free(tmpbuf);
|
||||
*w++ = *r;
|
||||
if (*r == '/')
|
||||
while (r[1] == '/')
|
||||
r++;
|
||||
}
|
||||
|
||||
*w = '\0';
|
||||
buf->end = w;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -474,7 +498,7 @@ pkgconf_path_trim_basename(pkgconf_buffer_t *buf)
|
||||
return false;
|
||||
|
||||
sep = strrchr(buf->base, PKG_DIR_SEP_S);
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__OS2__)
|
||||
char *sep2 = strrchr(buf->base, '/');
|
||||
if (sep2 != NULL && (sep == NULL || sep2 > sep))
|
||||
sep = sep2;
|
||||
@@ -507,7 +531,7 @@ pkgconf_path_find_basename(const char *path)
|
||||
const char *sep;
|
||||
|
||||
sep = strrchr(path, PKG_DIR_SEP_S);
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32) || defined(__OS2__)
|
||||
const char *sep2 = strrchr(path, '/');
|
||||
if (sep2 != NULL && (sep == NULL || sep2 > sep))
|
||||
sep = sep2;
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
int sizepath = GetModuleFileName(NULL, namebuf, sizeof namebuf - 1);
|
||||
char * winslash;
|
||||
namebuf[sizepath] = '\0';
|
||||
|
||||
while ((winslash = strchr(namebuf, '\\')) != NULL)
|
||||
*winslash = '/';
|
||||
pkgconf_path_normalize_separators(namebuf);
|
||||
|
||||
p = strrchr(namebuf, '/');
|
||||
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_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_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 == NULL)
|
||||
pkgconf_buffer_append(&pathbuf, path);
|
||||
{
|
||||
if (!pkgconf_buffer_append(&pathbuf, path))
|
||||
return NULL;
|
||||
}
|
||||
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
|
||||
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));
|
||||
if (p == NULL)
|
||||
|
||||
+225
-89
@@ -38,7 +38,8 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
|
||||
pkgconf_pkg_traverse_func_t func,
|
||||
void *data,
|
||||
int maxdepth,
|
||||
unsigned int skip_flags);
|
||||
unsigned int skip_flags,
|
||||
unsigned int iter_flags);
|
||||
|
||||
static inline bool
|
||||
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 pathbuf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
pkgconf_buffer_append(&buf, pkg->filename);
|
||||
if (!pkgconf_buffer_append(&buf, pkg->filename))
|
||||
goto fail;
|
||||
|
||||
#ifndef _WIN32
|
||||
struct stat path_stat;
|
||||
@@ -73,8 +75,9 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
|
||||
char sourcebuf[PKGCONF_ITEM_SIZE];
|
||||
char *targetfilename, *targetdir;
|
||||
|
||||
pkgconf_buffer_reset(&pathbuf);
|
||||
pkgconf_buffer_append(&pathbuf, buf.base);
|
||||
pkgconf_buffer_rewind(&pathbuf);
|
||||
if (!pkgconf_buffer_append(&pathbuf, buf.base))
|
||||
goto fail;
|
||||
|
||||
targetfilename = strrchr(pathbuf.base, '/');
|
||||
if (targetfilename != NULL)
|
||||
@@ -91,7 +94,7 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
|
||||
targetdir = ".";
|
||||
}
|
||||
|
||||
#ifdef HAVE_DECL_READLINKAT
|
||||
#if HAVE_DECL_READLINKAT
|
||||
const int dirfd = open(targetdir, O_DIRECTORY);
|
||||
if (dirfd == -1)
|
||||
break;
|
||||
@@ -106,7 +109,7 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
|
||||
break;
|
||||
sourcebuf[len] = '\0';
|
||||
|
||||
pkgconf_buffer_reset(&buf);
|
||||
pkgconf_buffer_rewind(&buf);
|
||||
|
||||
/*
|
||||
* 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 (relative) | /foo/link (absolute) | /foo/../bar (relative)
|
||||
*/
|
||||
if ((sourcebuf[0] != '/') && strcmp(targetdir, "."))
|
||||
pkgconf_buffer_append_fmt(&buf, "%s/", targetdir);
|
||||
if ((sourcebuf[0] != '/') &&
|
||||
#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
|
||||
|
||||
@@ -131,6 +142,11 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
|
||||
pkgconf_path_trim_basename(&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);
|
||||
@@ -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_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf);
|
||||
pkgconf_bufferset_extend(dest, &buf);
|
||||
if (pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf))
|
||||
pkgconf_bufferset_extend(dest, &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++;
|
||||
|
||||
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))
|
||||
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_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset);
|
||||
(void)keyword;
|
||||
(void)warnprefix;
|
||||
pkgconf_license_evaluate(client, pkg, dest, value, 0);
|
||||
|
||||
if (!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 */
|
||||
@@ -361,7 +386,9 @@ pkgconf_pkg_parser_keyword_set(void *opaque, const char *warnprefix, const char
|
||||
static bool
|
||||
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_trim_basename(pathbuf);
|
||||
@@ -396,18 +423,28 @@ convert_path_to_value(const char *path)
|
||||
|
||||
for (i = path; *i != '\0'; i++)
|
||||
{
|
||||
if (*i == PKG_DIR_SEP_S)
|
||||
pkgconf_buffer_push_byte(&buf, '/');
|
||||
else if (*i == ' ')
|
||||
char c = *i;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (c == PKG_DIR_SEP_S)
|
||||
c = '/';
|
||||
#endif
|
||||
|
||||
if (c == ' ')
|
||||
{
|
||||
pkgconf_buffer_push_byte(&buf, '\\');
|
||||
pkgconf_buffer_push_byte(&buf, ' ');
|
||||
if (!pkgconf_buffer_push_byte(&buf, '\\') ||
|
||||
!pkgconf_buffer_push_byte(&buf, ' '))
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
pkgconf_buffer_push_byte(&buf, *i);
|
||||
else if (!pkgconf_buffer_push_byte(&buf, c))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return pkgconf_buffer_freeze(&buf);
|
||||
|
||||
fail:
|
||||
pkgconf_buffer_finalize(&buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -440,22 +477,37 @@ canonicalize_path(char *buf)
|
||||
static bool
|
||||
is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return !_strnicmp(path1, path2, path2_len);
|
||||
#if defined(_WIN32) || defined(__OS2__)
|
||||
return !strncasecmp(path1, path2, path2_len);
|
||||
#else
|
||||
return !strncmp(path1, path2, path2_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_path_separator(char c)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return c == '/' || c == '\\';
|
||||
#else
|
||||
return c == '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
@@ -463,7 +515,11 @@ lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const ch
|
||||
*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
|
||||
@@ -482,17 +538,17 @@ pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *k
|
||||
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))
|
||||
goto out;
|
||||
|
||||
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
|
||||
* which is broken when redefining the prefix. We try to outsmart the
|
||||
* 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)
|
||||
{
|
||||
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_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix));
|
||||
pkgconf_buffer_append(&newvalue, pkgconf_buffer_str(&canonicalized_value) + oplen);
|
||||
if (!pkgconf_buffer_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix)) ||
|
||||
!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_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);
|
||||
char *prefix_value = convert_path_to_value(relvalue);
|
||||
|
||||
pkgconf_buffer_append(&pkg->orig_prefix, pkgconf_buffer_str(&canonicalized_value));
|
||||
pkgconf_buffer_append(&pkg->calculated_prefix, prefix_value);
|
||||
if (prefix_value == NULL ||
|
||||
!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);
|
||||
free(prefix_value);
|
||||
@@ -720,6 +797,10 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign
|
||||
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);
|
||||
pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pc_filedir_value, true, pkg->flags);
|
||||
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_append(&abibuf, "c");
|
||||
if (!pkgconf_buffer_append(&abibuf, "c"))
|
||||
{
|
||||
pkgconf_pkg_free(client, pkg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkgconf_bufferset_extend(&pkg->link_abi, &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_t *pkg = NULL;
|
||||
char locbuf[PKGCONF_ITEM_SIZE];
|
||||
char uninst_locbuf[PKGCONF_ITEM_SIZE];
|
||||
pkgconf_buffer_t locbuf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
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))
|
||||
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)
|
||||
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)
|
||||
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;
|
||||
}
|
||||
@@ -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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
@@ -920,13 +1023,34 @@ pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkg
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
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))
|
||||
{
|
||||
outpkg = pkg;
|
||||
@@ -1523,7 +1647,8 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client,
|
||||
pkgconf_pkg_traverse_func_t func,
|
||||
void *data,
|
||||
int depth,
|
||||
unsigned int skip_flags)
|
||||
unsigned int skip_flags,
|
||||
unsigned int iter_flags)
|
||||
{
|
||||
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
|
||||
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)
|
||||
{
|
||||
/* 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
|
||||
* memory is leaked due to circular ownership.
|
||||
* 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);
|
||||
|
||||
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:
|
||||
pkgconf_pkg_unref(client, pkgdep);
|
||||
}
|
||||
@@ -1661,7 +1786,8 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
|
||||
pkgconf_pkg_traverse_func_t func,
|
||||
void *data,
|
||||
int maxdepth,
|
||||
unsigned int skip_flags)
|
||||
unsigned int skip_flags,
|
||||
unsigned int iter_flags)
|
||||
{
|
||||
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 (func != NULL)
|
||||
func(client, root, data);
|
||||
func(client, root, data, iter_flags);
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
return eflags;
|
||||
|
||||
@@ -1704,18 +1830,14 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
|
||||
{
|
||||
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)
|
||||
return eflags;
|
||||
}
|
||||
|
||||
PKGCONF_TRACE(client, "%s: walking 'Requires.private' list", root->id);
|
||||
|
||||
/* XXX: ugly */
|
||||
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;
|
||||
|
||||
eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth, skip_flags, iter_flags | PKGCONF_PKG_ITERF_PRIVATE);
|
||||
if (eflags != PKGCONF_PKG_ERRF_OK)
|
||||
return eflags;
|
||||
|
||||
@@ -1730,8 +1852,7 @@ pkgconf_pkg_traverse(pkgconf_client_t *client,
|
||||
int maxdepth,
|
||||
unsigned int skip_flags)
|
||||
{
|
||||
if (root->flags & PKGCONF_PKG_PROPF_VIRTUAL)
|
||||
client->serial++;
|
||||
client->serial++;
|
||||
|
||||
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_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
|
||||
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;
|
||||
|
||||
(void) iter_flags;
|
||||
|
||||
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node)
|
||||
{
|
||||
pkgconf_fragment_t *frag = node->data;
|
||||
pkgconf_fragment_copy(client, list, frag, false);
|
||||
pkgconf_fragment_copy_cursor(client, cursor, frag, false);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
(void) iter_flags;
|
||||
|
||||
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_private.head, node)
|
||||
{
|
||||
pkgconf_fragment_t *frag = node->data;
|
||||
pkgconf_fragment_copy(client, list, frag, true);
|
||||
pkgconf_fragment_copy_cursor(client, cursor, frag, true);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
(void) iter_flags;
|
||||
|
||||
PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_shared.head, node)
|
||||
{
|
||||
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 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_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 (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
|
||||
{
|
||||
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)
|
||||
{
|
||||
pkgconf_fragment_free(&frags);
|
||||
return eflag;
|
||||
}
|
||||
|
||||
pkgconf_fragment_copy_list(client, list, &frags);
|
||||
pkgconf_fragment_free(&frags);
|
||||
pkgconf_list_splice(list, &frags);
|
||||
|
||||
return eflag;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_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)
|
||||
@@ -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_fragment_t *frag = node->data;
|
||||
pkgconf_fragment_copy(client, list, frag, true);
|
||||
pkgconf_fragment_copy_cursor(client, cursor, frag, true);
|
||||
}
|
||||
}
|
||||
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_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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -1895,11 +2029,13 @@ pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *
|
||||
}
|
||||
|
||||
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_node_t *node;
|
||||
|
||||
(void) iter_flags;
|
||||
|
||||
if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
|
||||
return;
|
||||
|
||||
|
||||
+42
-17
@@ -52,11 +52,22 @@ pkgconf_queue_push_dependency(pkgconf_list_t *list, const pkgconf_dependency_t *
|
||||
if (pkgq == NULL)
|
||||
return;
|
||||
|
||||
pkgconf_buffer_append(&depbuf, dep->package);
|
||||
if (dep->version != NULL)
|
||||
pkgconf_buffer_append_fmt(&depbuf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version);
|
||||
if (!pkgconf_buffer_append(&depbuf, dep->package) ||
|
||||
(dep->version != NULL &&
|
||||
!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);
|
||||
if (pkgq->package == NULL)
|
||||
{
|
||||
free(pkgq);
|
||||
return;
|
||||
}
|
||||
|
||||
pkgconf_node_insert_tail(&pkgq->iter, pkgq, list);
|
||||
}
|
||||
|
||||
@@ -80,6 +91,12 @@ pkgconf_queue_push(pkgconf_list_t *list, const char *package)
|
||||
return;
|
||||
|
||||
pkgq->package = strdup(package);
|
||||
if (pkgq->package == NULL)
|
||||
{
|
||||
free(pkgq);
|
||||
return;
|
||||
}
|
||||
|
||||
pkgconf_node_insert_tail(&pkgq->iter, pkgq, list);
|
||||
}
|
||||
|
||||
@@ -137,8 +154,10 @@ pkgconf_queue_free(pkgconf_list_t *list)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
pkgconf_list_t *list = data;
|
||||
@@ -161,13 +180,15 @@ static unsigned int
|
||||
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
|
||||
pkgconf_pkg_t *root,
|
||||
void *data,
|
||||
int maxdepth);
|
||||
int maxdepth,
|
||||
unsigned int iter_flags);
|
||||
|
||||
static inline unsigned int
|
||||
pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client,
|
||||
pkgconf_list_t *deplist,
|
||||
void *data,
|
||||
int depth)
|
||||
int depth,
|
||||
unsigned int iter_flags)
|
||||
{
|
||||
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
|
||||
pkgconf_node_t *node;
|
||||
@@ -191,12 +212,12 @@ pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client,
|
||||
if (pkg->serial == client->serial)
|
||||
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;
|
||||
else
|
||||
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);
|
||||
if (flattened_dep == NULL)
|
||||
@@ -215,7 +236,8 @@ static unsigned int
|
||||
pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client,
|
||||
pkgconf_pkg_t *root,
|
||||
void *data,
|
||||
int maxdepth)
|
||||
int maxdepth,
|
||||
unsigned int iter_flags)
|
||||
{
|
||||
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);
|
||||
|
||||
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)
|
||||
return eflags;
|
||||
}
|
||||
|
||||
PKGCONF_TRACE(client, "%s: collecting private dependencies, level %d", root->id, maxdepth);
|
||||
|
||||
/* XXX: ugly */
|
||||
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;
|
||||
eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth, iter_flags | PKGCONF_PKG_ITERF_PRIVATE);
|
||||
if (eflags != PKGCONF_PKG_ERRF_OK)
|
||||
return eflags;
|
||||
|
||||
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)
|
||||
return eflags;
|
||||
|
||||
@@ -266,7 +284,7 @@ pkgconf_queue_collect_dependencies(pkgconf_client_t *client,
|
||||
int maxdepth)
|
||||
{
|
||||
++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
|
||||
@@ -306,6 +324,13 @@ pkgconf_queue_collect_conflicts(pkgconf_client_t *client,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-9
@@ -33,10 +33,15 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#if defined(_WIN32) || defined(__OS2__)
|
||||
# ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# else
|
||||
# include <unistd.h> /* readlink */
|
||||
# endif
|
||||
# include <malloc.h>
|
||||
# include <io.h> /* for _setmode() */
|
||||
# include <fcntl.h>
|
||||
@@ -62,7 +67,7 @@
|
||||
# define SIZE_FMT_SPECIFIER "%u"
|
||||
# endif
|
||||
# endif
|
||||
# ifndef ssize_t
|
||||
# if !(defined(ssize_t) || defined(__OS2__))
|
||||
# ifndef __MINGW32__
|
||||
# include <BaseTsd.h>
|
||||
# else
|
||||
@@ -70,7 +75,7 @@
|
||||
# endif
|
||||
# define ssize_t SSIZE_T
|
||||
# endif
|
||||
# ifndef __MINGW32__
|
||||
# if !(defined (__MINGW32__) || defined(__OS2__))
|
||||
# include "win-dirent.h"
|
||||
# else
|
||||
# include <dirent.h>
|
||||
@@ -78,9 +83,13 @@
|
||||
# define PKGCONF_ITEM_SIZE (_MAX_PATH + 1024)
|
||||
# define PKG_CONFIG_PATH_SEP_S ";"
|
||||
# define PKG_DIR_SEP_S '\\'
|
||||
# define strcasecmp _stricmp
|
||||
# define strncasecmp _strnicmp
|
||||
# define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
|
||||
# ifndef __OS2__
|
||||
# define strcasecmp _stricmp
|
||||
# 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
|
||||
# define PATH_DEV_NULL "/dev/null"
|
||||
# define SIZE_FMT_SPECIFIER "%zu"
|
||||
@@ -89,7 +98,6 @@
|
||||
# endif
|
||||
# include <dirent.h>
|
||||
# include <unistd.h>
|
||||
# include <limits.h>
|
||||
# include <strings.h>
|
||||
# include <fcntl.h> // open
|
||||
# include <libgen.h> // basename/dirname
|
||||
|
||||
+37
-16
@@ -73,7 +73,7 @@ pkgconf_tuple_find_global(pkgconf_client_t *client, const char *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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
v->flags = flags;
|
||||
|
||||
if (!parse)
|
||||
{
|
||||
pkgconf_buffer_reset(&v->bcbuf);
|
||||
pkgconf_bytecode_emit_text(&v->bcbuf, dequote_value, strlen(dequote_value));
|
||||
pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf);
|
||||
if (!pkgconf_bytecode_emit_text(&rhs_bcbuf, dequote_value, strlen(dequote_value)))
|
||||
{
|
||||
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);
|
||||
return (pkgconf_tuple_t *) v;
|
||||
}
|
||||
|
||||
pkgconf_bytecode_compile(&rhs_bcbuf, dequote_value);
|
||||
free(dequote_value);
|
||||
|
||||
/* 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 new_bcbuf = PKGCONF_BUFFER_INITIALIZER;
|
||||
|
||||
/* 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} */
|
||||
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 */
|
||||
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(&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_buffer_finalize(&rhs_bcbuf);
|
||||
|
||||
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)
|
||||
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);
|
||||
|
||||
|
||||
+34
-8
@@ -32,20 +32,18 @@ pkgconf_variable_t *
|
||||
pkgconf_variable_new(const char *key)
|
||||
{
|
||||
pkgconf_variable_t *v;
|
||||
size_t keylen;
|
||||
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
v = calloc(1, sizeof(*v));
|
||||
keylen = strlen(key);
|
||||
v = calloc(1, sizeof(*v) + keylen + 1);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
|
||||
v->key = strdup(key);
|
||||
if (v->key == NULL)
|
||||
{
|
||||
free(v);
|
||||
return NULL;
|
||||
}
|
||||
v->key = (char *)(v + 1);
|
||||
memcpy(v->key, key, keylen + 1);
|
||||
|
||||
return v;
|
||||
}
|
||||
@@ -57,7 +55,6 @@ pkgconf_variable_free(pkgconf_variable_t *v)
|
||||
return;
|
||||
|
||||
pkgconf_buffer_finalize(&v->bcbuf);
|
||||
free(v->key);
|
||||
free(v);
|
||||
}
|
||||
|
||||
@@ -160,3 +157,32 @@ pkgconf_variable_eval_str(pkgconf_client_t *client,
|
||||
|
||||
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
@@ -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
@@ -7,7 +7,7 @@
|
||||
.\" 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 23, 2026
|
||||
.Dd September 8, 2026
|
||||
.Dt PKGCONF 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -117,8 +117,7 @@ options:
|
||||
.It
|
||||
Single-module output options:
|
||||
.Fl -path ,
|
||||
.Fl -print-variables ,
|
||||
.Fl -variable :
|
||||
.Fl -print-variables :
|
||||
If any of these options is specified, only the first
|
||||
.Ar module
|
||||
argument is used, all other arguments are silently ignored,
|
||||
@@ -128,8 +127,9 @@ Depth-one output options:
|
||||
.Fl -print-provides ,
|
||||
.Fl -modversion ,
|
||||
.Fl -print-requires ,
|
||||
.Fl -print-requires-private ,
|
||||
and
|
||||
.Fl -print-requires-private :
|
||||
.Fl -variable :
|
||||
If any of these options is specified, only modules
|
||||
explicitly specified on the command line are inspected
|
||||
and no dependency resolution is attempted.
|
||||
@@ -288,6 +288,19 @@ Most other options and all command line arguments are ignored.
|
||||
Ignore
|
||||
.Sq Conflicts
|
||||
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
|
||||
Keep CFLAGS or linker flag fragments that would be filtered due to being
|
||||
included by default in the compiler.
|
||||
@@ -384,6 +397,12 @@ is greater than the requested
|
||||
number.
|
||||
.It Fl -maximum-traverse-depth Ns = Ns Ar depth
|
||||
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
|
||||
.Ar depth
|
||||
of 2 restricts the resolver from acting on child
|
||||
@@ -570,12 +589,11 @@ This option implies
|
||||
and
|
||||
.Fl -errors-to-stdout .
|
||||
.It Fl -variable Ns = Ns Ar varname
|
||||
For the first
|
||||
.Ar module
|
||||
given on the command line, print the value of the variable with the name
|
||||
For each specified
|
||||
.Ar module ,
|
||||
print the value of the variable with the name
|
||||
.Ar varname
|
||||
to standard output.
|
||||
Any subsequent arguments are silently ignored.
|
||||
to standard output in command-line order.
|
||||
This option implies
|
||||
.Fl -maximum-traverse-depth Ns =1
|
||||
and overrides and disables all
|
||||
@@ -621,9 +639,15 @@ in the same way as
|
||||
.It Ev DESTDIR
|
||||
If set to the same value as
|
||||
.Ev PKG_CONFIG_SYSROOT_DIR ,
|
||||
behave in the same way as if
|
||||
follow
|
||||
.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
|
||||
.Ev PKG_CONFIG_SYSROOT_DIR
|
||||
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.
|
||||
.It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH
|
||||
Impose a limit on the allowed depth in the dependency graph.
|
||||
Set this variable to \-1 to allow unlimited traversal.
|
||||
This variable overrides the
|
||||
.Fl -maximum-traverse-depth
|
||||
option, but is overridden by the other options mentioned there.
|
||||
|
||||
+3
-3
@@ -19,12 +19,12 @@
|
||||
.Ar module ...
|
||||
.Sh DESCRIPTION
|
||||
.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.
|
||||
The output of this tool can then be translated into other SBOM
|
||||
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/
|
||||
.Pp
|
||||
The
|
||||
@@ -46,7 +46,7 @@ Set agent name-property
|
||||
in /Core/Agent-class. Default is 'Default'
|
||||
.It Fl -creation-time
|
||||
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.
|
||||
This takes precedence over the
|
||||
.Ev SOURCE_DATE_EPOCH
|
||||
|
||||
+83
-36
@@ -1,5 +1,5 @@
|
||||
project('pkgconf', 'c',
|
||||
version : '2.9.93',
|
||||
version : '3.0.8',
|
||||
license : 'ISC',
|
||||
default_options : [
|
||||
'c_std=c99',
|
||||
@@ -18,6 +18,7 @@ if cc.get_argument_syntax() != 'msvc'
|
||||
)
|
||||
endif
|
||||
add_project_arguments(
|
||||
'-D_ATFILE_SOURCE',
|
||||
'-D_BSD_SOURCE',
|
||||
'-D_DARWIN_C_SOURCE',
|
||||
'-D_DEFAULT_SOURCE',
|
||||
@@ -65,6 +66,7 @@ endif
|
||||
cdata = configuration_data()
|
||||
|
||||
check_functions = [
|
||||
['getc_unlocked', 'stdio.h'],
|
||||
['strndup', 'string.h'],
|
||||
['strdup', 'string.h'],
|
||||
['strncasecmp', 'strings.h'],
|
||||
@@ -73,11 +75,13 @@ check_functions = [
|
||||
['pledge', 'unistd.h'],
|
||||
['unveil', 'unistd.h'],
|
||||
['readlinkat', 'unistd.h'],
|
||||
['mkdtemp', 'stdlib.h'],
|
||||
]
|
||||
|
||||
# Feature-test macros mirroring those defined globally by the build, so that
|
||||
# the function probes below see the same declarations as the actual sources.
|
||||
feature_macros = {
|
||||
'_ATFILE_SOURCE': '',
|
||||
'_BSD_SOURCE': '',
|
||||
'_DARWIN_C_SOURCE': '',
|
||||
'_DEFAULT_SOURCE': '',
|
||||
@@ -128,10 +132,14 @@ else
|
||||
cdata.set('HAVE_DECL_NL_LANGINFO_L', 0)
|
||||
endif
|
||||
|
||||
default_path = []
|
||||
foreach f : ['libdir', 'datadir']
|
||||
default_path += [join_paths(get_option('prefix'), get_option(f), 'pkgconfig')]
|
||||
endforeach
|
||||
PKG_DEFAULT_PATH = get_option('with-pkg-config-dir')
|
||||
if PKG_DEFAULT_PATH == ''
|
||||
default_path = []
|
||||
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 = []
|
||||
foreach f : ['libdir', 'datadir']
|
||||
@@ -150,11 +158,11 @@ if SYSTEM_INCLUDEDIR != ''
|
||||
else
|
||||
cdata.set_quoted('SYSTEM_INCLUDEDIR', join_paths(get_option('prefix'), get_option('includedir')))
|
||||
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('PACKAGE_NAME', meson.project_name())
|
||||
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_builddir', meson.current_build_dir())
|
||||
|
||||
@@ -210,11 +218,9 @@ if fuzzing
|
||||
subdir('fuzzer')
|
||||
endif
|
||||
|
||||
# If we have a new enough meson override the dependency so that only
|
||||
# `dependency('libpkgconf')` is required from the consumer
|
||||
if meson.version().version_compare('>= 0.54.0')
|
||||
meson.override_dependency('libpkgconf', dep_libpkgconf)
|
||||
endif
|
||||
# override the dependency so that only `dependency('libpkgconf')` is
|
||||
# required from the consumer
|
||||
meson.override_dependency('libpkgconf', dep_libpkgconf)
|
||||
|
||||
pkg = import('pkgconfig')
|
||||
pkg.generate(libpkgconf,
|
||||
@@ -278,6 +284,16 @@ spdxtool_exe = executable('spdxtool',
|
||||
include_directories : include_directories('cli', 'cli/spdxtool'),
|
||||
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',
|
||||
'cli/core.c',
|
||||
'cli/getopt_long.c',
|
||||
@@ -287,7 +303,8 @@ test_runner_exe = executable('test-runner',
|
||||
link_with : libpkgconf,
|
||||
c_args : build_static,
|
||||
include_directories : cli_include,
|
||||
install : false)
|
||||
install : false,
|
||||
build_by_default : false)
|
||||
|
||||
api_tests = [
|
||||
'audit',
|
||||
@@ -313,7 +330,8 @@ foreach t : api_tests
|
||||
link_with : libpkgconf,
|
||||
c_args : build_static,
|
||||
include_directories : [include_directories('.'), include_directories('tests/api')],
|
||||
install : false)
|
||||
install : false,
|
||||
build_by_default : false)
|
||||
test('api-' + t, exe)
|
||||
endforeach
|
||||
|
||||
@@ -330,9 +348,27 @@ test_api_serialize_exe = executable('test-api-serialize',
|
||||
link_with : libpkgconf,
|
||||
c_args : build_static,
|
||||
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)
|
||||
|
||||
# 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
|
||||
# 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
|
||||
@@ -352,24 +388,29 @@ oom_wrap_args = [
|
||||
]
|
||||
|
||||
if build_oom_tests
|
||||
# Unit test: fault-inject spdxtool's own allocations. It links libpkgconf
|
||||
# normally (shared); only spdxtool's compiled-in allocations are wrapped,
|
||||
# which is exactly what we want to fail here.
|
||||
test_api_oom_spdxtool_exe = executable('test-api-oom-spdxtool',
|
||||
'tests/api/test-oom-spdxtool.c',
|
||||
'fuzzer/alloc-inject.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,
|
||||
link_args : oom_wrap_args,
|
||||
include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool'), include_directories('fuzzer')],
|
||||
install : false)
|
||||
test('api-oom-spdxtool', test_api_oom_spdxtool_exe)
|
||||
# Unit test: fault-inject spdxtool's own allocations. It requires a shared
|
||||
# libpkgconf so that the linker's --wrap only reaches spdxtool's compiled-in
|
||||
# allocations. With a static libpkgconf its allocations are wrapped too,
|
||||
# invalidating the test's expectation that every injected failure makes the
|
||||
# spdxtool operation fail.
|
||||
if libtype != 'static'
|
||||
test_api_oom_spdxtool_exe = executable('test-api-oom-spdxtool',
|
||||
'tests/api/test-oom-spdxtool.c',
|
||||
'fuzzer/alloc-inject.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,
|
||||
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,
|
||||
# deterministically and without libFuzzer, so the libpkgconf OOM paths they
|
||||
@@ -394,7 +435,8 @@ if build_oom_tests
|
||||
c_args : build_static,
|
||||
link_args : oom_wrap_args,
|
||||
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.
|
||||
test('fuzz-replay-' + r[0], replay_exe, args : [r[1]], timeout : 120)
|
||||
endforeach
|
||||
@@ -416,13 +458,14 @@ test_suites = [
|
||||
'tuple',
|
||||
'bomtool',
|
||||
'spdxtool',
|
||||
'pccritic',
|
||||
'symlink'
|
||||
]
|
||||
|
||||
foreach t : test_suites
|
||||
test(t, test_runner_exe,
|
||||
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
|
||||
|
||||
install_man('man/bomtool.1')
|
||||
@@ -431,6 +474,7 @@ install_man('man/pkg.m4.7')
|
||||
install_man('man/pc.5')
|
||||
install_man('man/pkgconf-personality.5')
|
||||
install_man('man/spdxtool.1')
|
||||
install_man('man/pccritic.1')
|
||||
install_data('pkg.m4', install_dir: 'share/aclocal')
|
||||
install_data('AUTHORS', 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.set('VERSION', meson.project_version())
|
||||
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('BUILD_TYPE', libtype)
|
||||
|
||||
@@ -470,7 +517,7 @@ if host_machine.system() == 'windows'
|
||||
if wix.found()
|
||||
msi = custom_target(
|
||||
msi_filename,
|
||||
input: [wxsfile, licensefile, pkgconf_exe],
|
||||
input: [wxsfile, licensefile, pkgconf_exe, bomtool_exe, spdxtool_exe, pccritic_exe],
|
||||
output: msi_filename,
|
||||
command: [wix, 'build', wxsfile, '-arch', wix_arch, '-ext', 'WixToolset.UI.wixext', '-o', msi_filename],
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
'with-system-libdir',
|
||||
type: 'string',
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<application>
|
||||
<windowsSettings>
|
||||
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
+16
-1
@@ -19,7 +19,7 @@
|
||||
</Feature>
|
||||
|
||||
<StandardDirectory Id="ProgramFiles6432Folder">
|
||||
<Directory Id="INSTALLFOLDER" Name="pkgconf @VERSION@" />
|
||||
<Directory Id="INSTALLFOLDER" Name="pkgconf-@VERSION@" />
|
||||
</StandardDirectory>
|
||||
|
||||
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
|
||||
@@ -41,6 +41,21 @@
|
||||
Source="@EXE@"
|
||||
KeyPath="yes" />
|
||||
</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" ?>
|
||||
<Component Id="PkgconfDll" Guid="*">
|
||||
<File Id="PkgconfDllFile"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
PackageSearchPath: lib1
|
||||
PackageSearchPath: lib2
|
||||
Query: pkg-config
|
||||
WantVariable: pc_path
|
||||
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: lib2
|
||||
Query: pkgconf
|
||||
WantVariable: pc_path
|
||||
ExpectedExitCode: 0
|
||||
ExpectedStdout: %TEST_FIXTURES_DIR%/lib1
|
||||
ExpectedStdout: %TEST_FIXTURES_DIR%/lib1%DIR_SEP%%TEST_FIXTURES_DIR%/lib2
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@ Tool: pkgconf
|
||||
ToolArgs: --exists foo 2>&1
|
||||
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1
|
||||
Environment: PKG_CONFIG_EARLY_TRACE=1
|
||||
ExpectedStdout: installing default unveil handler
|
||||
ExpectedStdout: installing custom unveil handler
|
||||
MatchStdout: partial
|
||||
ExpectedExitCode: 0
|
||||
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
|
||||
@@ -0,0 +1,2 @@
|
||||
pcfiledir
|
||||
qux
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
PackageSearchPath: lib1
|
||||
Query: self-referential-fragment
|
||||
WantedFlags: cflags
|
||||
ExpectedStdout: $\{x\}
|
||||
@@ -0,0 +1,4 @@
|
||||
PackageSearchPath: lib1
|
||||
Query: spaces-in-paths
|
||||
WantedFlags: cflags
|
||||
ExpectedStdout: -I/test\ with\ spaces/include -I/test\ with\ spaces/include/subdir
|
||||
@@ -0,0 +1,5 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: --about
|
||||
ExpectedStdout: pccritic
|
||||
MatchStdout: Partial
|
||||
ExpectedExitCode: 0
|
||||
@@ -0,0 +1,5 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: --help
|
||||
ExpectedStdout: usage: pccritic
|
||||
MatchStdout: Partial
|
||||
ExpectedExitCode: 0
|
||||
@@ -0,0 +1,3 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: --min-score invalid polluted
|
||||
ExpectedExitCode: 1
|
||||
@@ -0,0 +1,3 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: --min-score 101 polluted
|
||||
ExpectedExitCode: 1
|
||||
@@ -0,0 +1,4 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: --quiet --min-score 90 polluted
|
||||
Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-pccritic
|
||||
ExpectedExitCode: 1
|
||||
@@ -0,0 +1,5 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: --quiet %TEST_FIXTURES_DIR%/lib-pccritic/nodesc.pc
|
||||
ExpectedStdout: 75/100 (C)
|
||||
MatchStdout: Partial
|
||||
ExpectedExitCode: 0
|
||||
@@ -0,0 +1,2 @@
|
||||
Tool: pccritic
|
||||
ExpectedExitCode: 1
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: this-module-does-not-exist
|
||||
ExpectedExitCode: 1
|
||||
@@ -0,0 +1,5 @@
|
||||
Tool: pccritic
|
||||
ToolArgs: --version
|
||||
ExpectedStdout: pccritic
|
||||
MatchStdout: Partial
|
||||
ExpectedExitCode: 0
|
||||
@@ -0,0 +1,7 @@
|
||||
PackageSearchPath: lib1
|
||||
Query: conflicts, foo
|
||||
WantedFlags: dump-license
|
||||
ExpectedStdout: conflicts: NOASSERTION
|
||||
ExpectedStdout: foo: ISC
|
||||
ExpectedExitCode: 0
|
||||
MatchStdout: partial
|
||||
@@ -0,0 +1,7 @@
|
||||
PackageSearchPath: lib1
|
||||
Query: conflicts, foo
|
||||
WantedFlags: modversion
|
||||
ExpectedStdout: 1.2.3
|
||||
ExpectedStdout: 1.2.3
|
||||
ExpectedExitCode: 0
|
||||
MatchStdout: partial
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,5 +2,4 @@ Environment: PKG_CONFIG_SYSROOT_DIR=%TEST_FIXTURES_DIR%
|
||||
PackageSearchPath: lib1
|
||||
Query: idirafter
|
||||
WantedFlags: cflags
|
||||
ExpectedStdout: -idirafter %TEST_FIXTURES_DIR%/opt/bad/include
|
||||
MatchStdout: partial
|
||||
ExpectedStdout: -idirafter %TEST_FIXTURES_DIR%/opt/bad/include -idirafter %TEST_FIXTURES_DIR%/opt/bad2/include
|
||||
@@ -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
|
||||
@@ -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
Reference in new issue
Block a user