From 842bccfc33b46570b73956e39be8c0d9c064453b Mon Sep 17 00:00:00 2001
From: Kamil Dudka
Date: Wed, 24 Sep 2008 16:01:57 +0200
Subject: [PATCH] add new module filevercmp
* lib/filevercmp.h: New function FILEVERCMP comparing version strings
(and file names with version).
* lib/filevercmp.c: Implementation of FILEVERCMP function.
* m4/filevercmp.m4: Link filevercmp module to library.
* modules/filevercmp: Module metadata.
* tests/test-filevercmp.c: Unit test for new module.
* modules/filevercmp-tests: Unit test metadata.
* MODULES.html.sh: Add FILEVERCMP module.
* NEWS: Mention the change.
---
MODULES.html.sh | 1 +
NEWS | 8 +++
lib/filevercmp.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++
lib/filevercmp.h | 29 +++++++++
m4/filevercmp.m4 | 7 ++
modules/filevercmp | 24 +++++++
modules/filevercmp-tests | 11 +++
tests/test-filevercmp.c | 101 +++++++++++++++++++++++++++++
8 files changed, 338 insertions(+), 0 deletions(-)
create mode 100644 lib/filevercmp.c
create mode 100644 lib/filevercmp.h
create mode 100644 m4/filevercmp.m4
create mode 100644 modules/filevercmp
create mode 100644 modules/filevercmp-tests
create mode 100644 tests/test-filevercmp.c
diff --git a/MODULES.html.sh b/MODULES.html.sh
index afaf8ba..3ab5a90 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1856,6 +1856,7 @@ func_all_modules ()
func_module readtokens
func_module readtokens0
func_module strverscmp
+ func_module filevercmp
func_end_table
element="Support for systems lacking ISO C 99"
diff --git a/NEWS b/NEWS
index 16917cb..2b400ed 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,14 @@ User visible incompatible changes
Date Modules Changes
+2008-09-24 filevercmp New module containing FILEVERCMP function comparing
+ version strings (and file names with version). This
+ function is supposed to be replacement for
+ STRVERSCMP function. It has same parameters and
+ return value as standard STRCMP function. It is
+ based on VERREVCMP function from dpkg and improved
+ to deal better with file suffixes.
+
2008-09-23 sys_socket Under Windows (MinGW), the module now adds
wrappers around Winsock functions, so that
socket descriptors are now compatible with
diff --git a/lib/filevercmp.c b/lib/filevercmp.c
new file mode 100644
index 0000000..b5528b5
--- /dev/null
+++ b/lib/filevercmp.c
@@ -0,0 +1,157 @@
+/*
+TODO: copyright?
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#include
+#include
+#include
+#include
+
+#include "filevercmp.h"
+
+#define xisalnum(c) isalnum ((unsigned char) c)
+#define xisdigit(c) isdigit ((unsigned char) c)
+#define xisalpha(c) isalpha ((unsigned char) c)
+
+static int verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t
+ s2_len);
+static const char * match_suffix (const char **str);
+
+/* function comparing version strings (and file names with version)
+
+ This function is supposed to be replacement for STRVERSCMP function. Same
+ parameters and return value as standard STRCMP function.
+
+ It is based on verrevcmp function from dpkg and improved to deal better
+ with file suffixes. */
+int
+filevercmp (const char *s1, const char *s2)
+{
+ /* easy comparison to see if versions are identical */
+ if (!strcmp (s1, s2))
+ return 0;
+
+ /* "cut" file suffixes */
+ const char *s1_pos = s1;
+ const char *s2_pos = s2;
+ const char *s1_suffix = match_suffix (&s1_pos);
+ const char *s2_suffix = match_suffix (&s2_pos);
+ size_t s1_len = (s1_suffix ? s1_suffix : s1_pos) - s1;
+ size_t s2_len = (s2_suffix ? s2_suffix : s2_pos) - s2;
+
+ /* restore file suffixes if strings are identical after "cut" */
+ if ((s1_suffix || s2_suffix) && (s1_len == s2_len) && 0 ==
+ strncmp (s1, s2, s1_len))
+ {
+ s1_len = s1_pos - s1;
+ s2_len = s2_pos - s2;
+ }
+
+ int rc = verrevcmp (s1, s1_len, s2, s2_len);
+ return (rc == 0)
+ /* return 0 if (and only if) strings S1 and S2 are identical */
+ ? strcmp(s1, s2) : rc;
+}
+
+/*
+ match file suffix defined as RE (\.[A-Za-z][A-Za-z0-9]*)*$
+
+ Scan string pointed by *str and return pointer to suffix begin or NULL if
+ not found. Pointer *str points to ending zero of scanned string after
+ return. */
+static const char *
+match_suffix (const char **str)
+{
+ const char *match = NULL;
+ bool read_alpha = false;
+ while (**str)
+ {
+ if (read_alpha)
+ {
+ read_alpha = false;
+ if (!xisalpha (**str))
+ match = NULL;
+ }
+ else if ('.'==**str)
+ {
+ read_alpha = true;
+ if (!match)
+ match = *str;
+ }
+ else if (!xisalnum (**str))
+ match = NULL;
+ (*str)++;
+ }
+ return match;
+}
+
+/* verrevcmp helper function */
+inline int
+order (unsigned char c)
+{
+ if (c == '~')
+ return -1;
+ else if (xisdigit (c))
+ return 0;
+ else if (xisalpha (c))
+ return c;
+ else
+ return c + 256;
+}
+
+/* slightly modified ververcmp function from dpkg
+ S1, S2 - compared string
+ S1_LEN, S2_LEN - length of strings to be scanned */
+static int
+verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t s2_len)
+{
+ int s1_pos = 0;
+ int s2_pos = 0;
+ while (s1_pos < s1_len || s2_pos < s2_len)
+ {
+ int first_diff = 0;
+ while ((s1_pos < s1_len && !xisdigit (s1[s1_pos])) || (s2_pos < s2_len
+ && !xisdigit (s2[s2_pos])))
+ {
+ int s1_c = (s1_pos == s1_len)
+ ? 0 : order (s1[s1_pos]);
+ int s2_c = (s2_pos == s2_len)
+ ? 0 : order (s2[s2_pos]);
+ if (s1_c != s2_c)
+ return s1_c - s2_c;
+ s1_pos++;
+ s2_pos++;
+ }
+ while (s1[s1_pos] == '0')
+ s1_pos++;
+ while (s2[s2_pos] == '0')
+ s2_pos++;
+ while (xisdigit (s1[s1_pos]) && xisdigit (s2[s2_pos]))
+ {
+ if (!first_diff)
+ first_diff = s1[s1_pos] - s2[s2_pos];
+ s1_pos++;
+ s2_pos++;
+ }
+ if (xisdigit (s1[s1_pos]))
+ return 1;
+ if (xisdigit (s2[s2_pos]))
+ return -1;
+ if (first_diff)
+ return first_diff;
+ }
+ return 0;
+}
+
diff --git a/lib/filevercmp.h b/lib/filevercmp.h
new file mode 100644
index 0000000..5076b4f
--- /dev/null
+++ b/lib/filevercmp.h
@@ -0,0 +1,29 @@
+/*
+TODO: copyright?
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#ifndef FILEVERCMP_H
+#define FILEVERCMP_H
+
+/* function comparing version strings (and file names with version)
+
+ This function is supposed to be replacement for STRVERSCMP function. Same
+ parameters and return value as standard STRCMP function.
+
+ It is based on verrevcmp function from dpkg and improved to deal better
+ with file suffixes. */
+int filevercmp (const char *s1, const char *s2);
+
+#endif // FILEVERCMP_H
diff --git a/m4/filevercmp.m4 b/m4/filevercmp.m4
new file mode 100644
index 0000000..5c78ea0
--- /dev/null
+++ b/m4/filevercmp.m4
@@ -0,0 +1,7 @@
+# filevercmp.m4
+# TODO: license?
+
+AC_DEFUN([gl_FILEVERCMP],
+[
+ AC_LIBOBJ([filevercmp])
+])
diff --git a/modules/filevercmp b/modules/filevercmp
new file mode 100644
index 0000000..bdbd6df
--- /dev/null
+++ b/modules/filevercmp
@@ -0,0 +1,24 @@
+Description:
+function comparing version strings (and file names with version)
+
+Files:
+lib/filevercmp.h
+lib/filevercmp.c
+m4/filevercmp.m4
+
+Depends-on:
+string
+
+configure.ac:
+gl_FILEVERCMP
+
+Makefile.am:
+
+Include:
+"filevercmp.h"
+
+License:
+GPL
+
+Maintainer:
+all
diff --git a/modules/filevercmp-tests b/modules/filevercmp-tests
new file mode 100644
index 0000000..02554fe
--- /dev/null
+++ b/modules/filevercmp-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-filevercmp.c
+
+Depends-on:
+filevercmp
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-filevercmp
+check_PROGRAMS += test-filevercmp
diff --git a/tests/test-filevercmp.c b/tests/test-filevercmp.c
new file mode 100644
index 0000000..696d538
--- /dev/null
+++ b/tests/test-filevercmp.c
@@ -0,0 +1,101 @@
+/* Test of filevercmp() function.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include
+
+#include "filevercmp.h"
+
+#include
+#include
+
+#define ASSERT(expr) \
+ do \
+ { \
+ if (!(expr)) \
+ { \
+ fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+ fflush (stderr); \
+ abort (); \
+ } \
+ } \
+ while (0)
+
+/* set of well sorted examples */
+static const char *examples[] =
+{
+ "gcc-c++-10.fc9.tar.gz",
+ "gcc-c++-10.8.12-0.7rc2.fc9.tar.bz2",
+ "glibc-2-0.1.beta1.fc10.rpm",
+ "glibc-common-5-0.2.beta2.fc9.ebuild",
+ "glibc-common-5-0.2b.deb",
+ "glibc-common-11b.ebuild",
+ "glibc-common-11-0.6rc2.ebuild",
+ "libstdc++-0.5.8.11-0.7rc2.fc10.tar.gz",
+ "libstdc++-4a.fc8.tar.gz",
+ "libstdc++-4.10.4.20040204svn.rpm",
+ "libstdc++-devel-3.fc8.ebuild",
+ "libstdc++-devel-3a.fc9.tar.gz",
+ "libstdc++-devel-8.fc8.deb",
+ "libstdc++-devel-8.6.2-0.4b.fc8",
+ "nss_ldap-1-0.2b.fc9.tar.bz2",
+ "nss_ldap-1-0.6rc2.fc8.tar.gz",
+ "nss_ldap-1.0-0.1a.tar.gz",
+ "nss_ldap-10beta1.fc8.tar.gz",
+ "nss_ldap-10.11.8.6.20040204cvs.fc10.ebuild",
+ 0
+};
+
+int
+main (int argc, char **argv)
+{
+ /* Following tests taken from test-strverscmp.c */
+ ASSERT (filevercmp ("", "") == 0);
+ ASSERT (filevercmp ("a", "a") == 0);
+ ASSERT (filevercmp ("a", "b") < 0);
+ ASSERT (filevercmp ("b", "a") > 0);
+ /* these results differ from strverscmp
+ ASSERT (filevercmp ("000", "00") < 0);
+ ASSERT (filevercmp ("00", "000") > 0); */
+ ASSERT (filevercmp ("a0", "a") > 0);
+ ASSERT (filevercmp ("00", "01") < 0);
+ ASSERT (filevercmp ("01", "010") < 0);
+ /* these results differ from strverscmp
+ ASSERT (filevercmp ("010", "09") < 0);
+ ASSERT (filevercmp ("09", "0") < 0); */
+ ASSERT (filevercmp ("9", "10") < 0);
+ ASSERT (filevercmp ("0a", "0") > 0);
+
+ /* compare each version string with each other - O(n^2) */
+ const char **i;
+ for (i = examples; *i; i++)
+ {
+ const char **j;
+ for (j = examples; *j; j++)
+ {
+ int result = filevercmp (*i, *j);
+ if (result < 0)
+ ASSERT (i < j);
+ else if (0 < result)
+ ASSERT (j < i);
+ else
+ ASSERT (i == j);
+ }
+ }
+
+ return 0;
+}
+
--
1.5.4.1