summaryrefslogtreecommitdiff
path: root/cli/spdxtool/util.c
diff options
context:
space:
mode:
authorPierre Pronchery <khorben@FreeBSD.org>2026-06-24 19:47:19 +0000
committerPierre Pronchery <khorben@FreeBSD.org>2026-06-29 05:21:29 +0000
commitebcc78644e0cbc4141807c0887ef8d902cb91bb4 (patch)
treeda5efe7c3c9ae0f140e24a1b69833a476fb09f01 /cli/spdxtool/util.c
parent6294b6ab217a2d5f1d2bc23a64505a228294c508 (diff)
Diffstat (limited to 'cli/spdxtool/util.c')
-rw-r--r--cli/spdxtool/util.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/cli/spdxtool/util.c b/cli/spdxtool/util.c
new file mode 100644
index 000000000000..e47bf0a1e61f
--- /dev/null
+++ b/cli/spdxtool/util.c
@@ -0,0 +1,331 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ *​ Copyright (c) 2025 The FreeBSD Foundation
+ *​
+ *​ Portions of this software were developed by
+ * Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
+ * the FreeBSD Foundation
+ */
+
+#include <libpkgconf/libpkgconf.h>
+#include <libpkgconf/stdinc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include "util.h"
+
+/*
+ * !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
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :param const char *key: Key to be preserved
+ * :param const char *key_value: Value for key
+ * :param const char *key_default: Default value if key_value is NULL
+ * :return: nothing
+ */
+void
+spdxtool_util_set_key(pkgconf_client_t *client, const char *key, const char *key_value, const char *key_default)
+{
+ PKGCONF_TRACE(client, "set uri_root to: %s", key_value != NULL ? key_value : key_default);
+ pkgconf_tuple_add_global(client, key, key_value != NULL ? key_value : key_default);
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: void spdxtool_util_set_uri_root(pkgconf_client_t *client, const char *uri_root)
+ *
+ * Set URI/URL root for spdxId. Type for this is 'xsd:anyURI' which means
+ * it can they may be absolute or relative.
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :param const char *uri_root: URI root.
+ * :return: nothing
+ */
+void
+spdxtool_util_set_uri_root(pkgconf_client_t *client, const char *uri_root)
+{
+ spdxtool_util_set_key(client, "spdx_uri_root", uri_root, "https://github.com/pkgconf/pkgconf");
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: const char *spdxtool_util_get_uri_root(pkgconf_client_t *client)
+ *
+ * Get current URI
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :return: URI or NULL
+ */
+const char *
+spdxtool_util_get_uri_root(pkgconf_client_t *client)
+{
+ return pkgconf_tuple_find_global(client, "spdx_uri_root");
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: void spdxtool_util_set_uri_separator_colon(pkgconf_client_t *client, bool is_colon)
+ *
+ * when using URI rather than URL change separator from slash '/' to colon ':'.
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :param bool is_colon If true use colon ':' is separator and otherwise slash '/'
+ * :return: nothing
+ */
+void
+spdxtool_util_set_uri_separator_colon(pkgconf_client_t *client, bool is_colon)
+{
+ if (is_colon == true)
+ client->flags |= SPDXTOOL_SEPARATOR_COLON;
+ else
+ client->flags = client->flags & ~SPDXTOOL_SEPARATOR_COLON;
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: char spdxtool_util_get_uri_separator(pkgconf_client_t *client)
+ *
+ * Get separator char
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :return: Colon ':' or slash '/'
+ */
+char
+spdxtool_util_get_uri_separator(pkgconf_client_t *client)
+{
+ if (client->flags & SPDXTOOL_SEPARATOR_COLON)
+ return ':';
+
+ return '/';
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: void spdxtool_util_set_spdx_version(pkgconf_client_t *client, const char *spdx_version)
+ *
+ * Set current SPDX SBOM Spec version. If not set it's 3.0.1
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :param char* spdx_version: SPDX specification version.
+ * :return: nothing
+ */
+void
+spdxtool_util_set_spdx_version(pkgconf_client_t *client, const char *spdx_version)
+{
+ spdxtool_util_set_key(client, "spdx_version", spdx_version, "3.0.1");
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: const char *spdxtool_util_get_spdx_version(pkgconf_client_t *client)
+ *
+ * Get SPDX SBOM specification version in use
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :return: Spec version
+ */
+const char *
+spdxtool_util_get_spdx_version(pkgconf_client_t *client)
+{
+ return pkgconf_tuple_find_global(client, "spdx_version");
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: void spdxtool_util_set_spdx_license(pkgconf_client_t *client, const char *spdx_license)
+ *
+ * Under which license SBOM is released. License string should be in
+ * SPDX style. Something like: FreeBSD-DOC, CC0-1.0 or MIT
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :param const char *spdx_license: SPDX compatible license
+ * :return: nothing
+ */
+void
+spdxtool_util_set_spdx_license(pkgconf_client_t *client, const char *spdx_license)
+{
+ spdxtool_util_set_key(client, "spdx_license", spdx_license, "CC0-1.0");
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: const char *spdxtool_util_get_spdx_license(pkgconf_client_t *client)
+ *
+ * Get license which SBOM is release in
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :return: SPDX license
+ */
+const char *
+spdxtool_util_get_spdx_license(pkgconf_client_t *client)
+{
+ return pkgconf_tuple_find_global(client, "spdx_license");
+}
+
+static size_t last_id = 0;
+
+/*
+ * !doc
+ *
+ * .. c:function:: char *spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, char *part)
+ *
+ * Get spdxId with current URI.
+ * URI is lookg like https://test/part/1
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :param char *part: Addition subdir part before number
+ * :return: URI
+ */
+char *
+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_join(&current_uri, sep, global_xsd_any_uri, part, NULL);
+ pkgconf_buffer_append_fmt(&current_uri, "%c" SIZE_FMT_SPECIFIER, sep, ++last_id);
+
+ return pkgconf_buffer_freeze(&current_uri);
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: char *spdxtool_util_get_spdx_id_string(pkgconf_client_t *client, const char *part, const char *string_id)
+ *
+ * Get string id URI
+ * looks something like: https://test/part/string_id
+ *
+ * :param pkgconf_client_t* client: The pkgconf client being accessed.
+ * :param const char* part: subdir part of URI.
+ * :param const char* string_id: String ID.
+ * :return: URI
+ */
+char *
+spdxtool_util_get_spdx_id_string(pkgconf_client_t *client, const char *part, const char *string_id)
+{
+ 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_join(&current_uri, sep, global_xsd_any_uri, part, string_id, NULL);
+
+ return pkgconf_buffer_freeze(&current_uri);
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: char *spdxtool_util_get_iso8601_time(time_t *wanted_time)
+ *
+ * Get ISO8601 time string
+ *
+ * :param time_t *wanted_time: Time to be converted
+ * :return: Time string in ISO8601 format
+ */
+char *
+spdxtool_util_get_iso8601_time(time_t *wanted_time)
+{
+ char buf[PKGCONF_ITEM_SIZE];
+
+ if (!wanted_time)
+ return NULL;
+
+ struct tm *tm_info = gmtime(wanted_time);
+ if (!tm_info)
+ return NULL;
+
+ /* ISO8601 time with Z at the end */
+ strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%SZ", tm_info);
+ return strdup(buf);
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: char *spdxtool_util_get_current_iso8601_time(void)
+ *
+ * Get ISO8601 current timestamp
+ *
+ * :return: Time string in ISO8601 format
+ */
+char *
+spdxtool_util_get_current_iso8601_time(void)
+{
+ time_t now;
+ time(&now);
+ return spdxtool_util_get_iso8601_time(&now);
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: char *spdxtool_util_string_correction(char *str)
+ *
+ * Lowercase string and change spaces to '_'
+ *
+ * :param char *str: String to be converted
+ * :return: Converted string
+ */
+char *
+spdxtool_util_string_correction(char *str)
+{
+ char *ptr = str;
+ /* Lowecase string and make spaces '_' */
+ for ( ; *ptr; ++ptr)
+ {
+ *ptr = (char) tolower(*ptr);
+ if(isspace((unsigned char) *ptr))
+ {
+ *ptr = '_';
+ }
+ }
+
+ return str;
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: char *spdxtool_util_tuple_lookup(pkgconf_client_t *client, pkgconf_list_t *vars, const char *key)
+ *
+ * Lowercase string and change spaces to '_'
+ *
+ * :param pkgconf_client_t *client: client to use for the lookup
+ * :param pkgconf_list_t *vars: locally-scoped vars to look through
+ * :param char *key: key to lookup
+ * :return: Converted string
+ */
+char *
+spdxtool_util_tuple_lookup(pkgconf_client_t *client, pkgconf_list_t *vars, const char *key)
+{
+ pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER;
+ pkgconf_bytecode_eval_ctx_t ctx = {
+ .client = client,
+ .vars = vars,
+ };
+
+ pkgconf_variable_t *v = pkgconf_bytecode_eval_lookup_var(&ctx, key, strlen(key));
+ if (v == NULL)
+ return NULL;
+
+ if (!pkgconf_variable_eval(client, vars, v, &buf, NULL))
+ return NULL;
+
+ return pkgconf_buffer_freeze(&buf);
+}