gplugin/gplugin-version.c

Tue, 06 Aug 2024 15:00:14 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Tue, 06 Aug 2024 15:00:14 -0500
changeset 2045
a65481169daa
parent 2037
64302a63c78b
permissions
-rw-r--r--

Fix the docs build on fedora 40

I'm not sure why this isn't showing up elsewhere, but it is. The ultimate fix
was making sure Gio was in the includes for the introspection file.

Also vapigen breaks horribly when Gio is pulled in, so I disabled it for now
as nothing is using it.

Testing Done:
Ran the build under the fedora-40-amd64 container.

Reviewed at https://reviews.imfreedom.org/r/3343/

/*
 * Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
 */

#include <stdlib.h>

#include <glib/gi18n-lib.h>

#include <gplugin/gplugin-core.h>
#include <gplugin/gplugin-version.h>

/******************************************************************************
 * Globals
 *****************************************************************************/
GRegex *regex = NULL;

static const char *version_pattern = "^(?P<major>\\d+)(\\."
									 "(?P<minor>\\d+)"
									 "(\\.(?P<micro>\\d+)(?P<extra>.*))?)?$";

/******************************************************************************
 * Helpers
 *****************************************************************************/
static void
gplugin_version_lazy_init(void)
{
	static gsize init = 0;

	if(g_once_init_enter(&init)) {
		GError *error = NULL;

		regex =
			g_regex_new(version_pattern, G_REGEX_NO_AUTO_CAPTURE, 0, &error);

		if(error) {
			g_warning(
				_("Failed to initialize the version regex: %s"),
				(error->message) ? error->message : _("unknown"));
			g_error_free(error);
		}

		g_once_init_leave(&init, 1);
	}
}

/*< private >
 * gplugin_version_parser:
 * @version: The string version to parse.
 * @major: (out) (nullable): A return pointer for the major version.
 * @minor: (out) (nullable): A return pointer for the minor version.
 * @micro: (out) (nullable): A return pointer for the micro version.
 * @extra: (out) (nullable): A return pointer for any extra version info.
 *
 * Attempts to parse a version string into its @major, @minor, @micro, and
 * @extra parts.  If @version doesn't match a semantic version string, @major
 * will be set to %-1, @minor will be set to %0, and @micro will be set to %0.
 */
static void
gplugin_version_parser(
	const char *version,
	int *major,
	int *minor,
	int *micro,
	char **extra)
{
	GMatchInfo *info = NULL;
	gboolean matches = FALSE;
	char *temp = NULL;

	/* initialize everything to our failed state */
	if(major != NULL) {
		*major = -1;
	}

	if(minor != NULL) {
		*minor = 0;
	}

	if(micro != NULL) {
		*micro = 0;
	}

	if(version == NULL) {
		/* if a version was not provided, return our failed values */
		return;
	}

	matches = g_regex_match(regex, version, 0, &info);
	if(!matches) {
		/* If we failed to match the regex, free info and return our failed
		 * values.
		 */
		g_match_info_unref(info);

		return;
	}

	/* grab the major version */
	if(major) {
		temp = g_match_info_fetch_named(info, "major");
		*major = (temp) ? atoi(temp) : 0;
		g_free(temp);
	}

	/* grab the minor version */
	if(minor) {
		temp = g_match_info_fetch_named(info, "minor");
		*minor = (temp) ? atoi(temp) : 0;
		g_free(temp);
	}

	/* grab the micro version */
	if(micro) {
		temp = g_match_info_fetch_named(info, "micro");
		*micro = (temp) ? atoi(temp) : 0;
		g_free(temp);
	}

	/* grab the extra version */
	if(extra) {
		*extra = g_match_info_fetch_named(info, "extra");
	}

	g_match_info_unref(info);
}

/******************************************************************************
 * GPluginVersion API
 *****************************************************************************/

/**
 * GPLUGIN_MAJOR_VERSION:
 *
 * This is the major version number of GPlugin that was compiled against.
 */

/**
 * GPLUGIN_MINOR_VERSION:
 *
 * This is the minor version number of GPlugin that was compiled against.
 */

/**
 * GPLUGIN_MICRO_VERSION:
 *
 * This is the micro version number of GPlugin that was compiled against.
 */

/**
 * GPLUGIN_EXTRA_VERSION:
 *
 * This is the extra version string of GPlugin that was compiled against.
 */

/**
 * GPLUGIN_VERSION:
 *
 * This is the string version number of GPlugin that was compiled against.
 */

/**
 * GPLUGIN_VERSION_CHECK:
 * @major: The major version to compare for.
 * @minor: The minor version to compare for.
 * @micro: The micro version to compare for.
 *
 * Checks the version of the GPlugin library that is being compiled
 * against.
 *
 * Returns: %TRUE if the version of the GPlugin header files
 * is the same as or newer than the passed-in version.
 */

/**
 * gplugin_version_check:
 * @major: The required major version.
 * @minor: The required minor version.
 * @micro: The required micro version.
 *
 * Checks that the GPlugin library in use is compatible with the given version.
 *
 * Generally you would pass in the constants [const@GPlugin.MAJOR_VERSION],
 * [const@GPlugin.MINOR_VERSION], [const@GPlugin.MICRO_VERSION] as the three
 * arguments to this function; that produces a check that the library in use is
 * compatible with the version of GPlugin the application or module was
 * compiled against.
 *
 * Compatibility is defined by two things: first the version of the running
 * library is newer than the version @major.@minor.@micro. Second the running
 * library must be binary compatible with the version @major.@minor.@micro
 * (same major version).
 *
 * Returns: %NULL if the GPlugin library is compatible with the given version,
 *          or a string describing the version mismatch. The returned string
 *          is owned by GPlugin and must not be modified or freed.
 */
const char *
gplugin_version_check(guint major, guint minor, guint micro)
{
	if(major > GPLUGIN_MAJOR_VERSION) {
		return "gplugin version too old (major mismatch)";
	}

#if GPLUGIN_VERSION_CHECK(1, 0, 0)
	if(major < GPLUGIN_MAJOR_VERSION) {
		return "gplugin version too new (major mismatch)";
	}
#endif

	if(minor > GPLUGIN_MINOR_VERSION) {
		return "gplugin version too old (minor mismatch)";
	}

	if(minor == GPLUGIN_MINOR_VERSION && micro > GPLUGIN_MICRO_VERSION) {
		return "gplugin version too old (micro mismatch)";
	}

	return NULL;
}

/**
 * gplugin_version_compare:
 * @v1: The first version to compare.
 * @v2: The second version to compare.
 *
 * A semantic version checker which ignores any characters after the micro
 * version.
 *
 * Returns: less than 0 if @v1 is less than @v2, 0 if @v1 is equal to @v1, and
 *          greater than 0 if @v1 is greater than @v2.
 */
int
gplugin_version_compare(const char *v1, const char *v2)
{
	int v1_maj = 0, v1_min = 0, v1_mic = 0;
	int v2_maj = 0, v2_min = 0, v2_mic = 0;
	int t = 0;

	if(regex == NULL) {
		gplugin_version_lazy_init();
	}

	/* parse v1 */
	gplugin_version_parser(v1, &v1_maj, &v1_min, &v1_mic, NULL);

	/* parse v2 */
	gplugin_version_parser(v2, &v2_maj, &v2_min, &v2_mic, NULL);

	/* now figure out if they match */
	t = v1_maj - v2_maj;
	if(t != 0)
		return t;

	t = v1_min - v2_min;
	if(t != 0)
		return t;

	return v1_mic - v2_mic;
}

mercurial