diff options
| author | Paul Eggert | 2016-02-21 13:25:24 -0800 |
|---|---|---|
| committer | Paul Eggert | 2016-02-21 13:27:40 -0800 |
| commit | 1f7feecaee0ed3fb79758fe60020aefb30d9ff01 (patch) | |
| tree | b0476096aabea32658be041242caa74e7a5232cd /lib | |
| parent | 3e67708d7239cde24b0988d4d1288bc75585cfea (diff) | |
| download | emacs-1f7feecaee0ed3fb79758fe60020aefb30d9ff01.tar.gz emacs-1f7feecaee0ed3fb79758fe60020aefb30d9ff01.zip | |
Use Gnulib filevercmp for version comparison
* admin/merge-gnulib (GNULIB_MODULES): Add filevercmp.
* doc/lispref/strings.texi (Text Comparison):
* etc/NEWS, src/fns.c:
* test/src/fns-tests.el (fns-tests-string-version-lessp):
Rename newly-introduced function to string-version-lessp, by
analogy with strverscmp.
* lib/filevercmp.c, lib/filevercmp.h: New files, copied from gnulib.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* src/fns.c: Include <filevercmp.h>.
(gather_number_from_string): Remove.
(Fstring_version_lessp): Reimplement via filevercmp.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/filevercmp.c | 181 | ||||
| -rw-r--r-- | lib/filevercmp.h | 42 | ||||
| -rw-r--r-- | lib/gnulib.mk | 10 |
3 files changed, 232 insertions, 1 deletions
diff --git a/lib/filevercmp.c b/lib/filevercmp.c new file mode 100644 index 00000000000..a75c9468e31 --- /dev/null +++ b/lib/filevercmp.c | |||
| @@ -0,0 +1,181 @@ | |||
| 1 | /* | ||
| 2 | Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk> | ||
| 3 | Copyright (C) 2001 Anthony Towns <aj@azure.humbug.org.au> | ||
| 4 | Copyright (C) 2008-2016 Free Software Foundation, Inc. | ||
| 5 | |||
| 6 | This program is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | #include <config.h> | ||
| 20 | #include "filevercmp.h" | ||
| 21 | |||
| 22 | #include <sys/types.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <stdbool.h> | ||
| 25 | #include <string.h> | ||
| 26 | #include <c-ctype.h> | ||
| 27 | #include <limits.h> | ||
| 28 | |||
| 29 | /* Match a file suffix defined by this regular expression: | ||
| 30 | /(\.[A-Za-z~][A-Za-z0-9~]*)*$/ | ||
| 31 | Scan the string *STR and return a pointer to the matching suffix, or | ||
| 32 | NULL if not found. Upon return, *STR points to terminating NUL. */ | ||
| 33 | static const char * | ||
| 34 | match_suffix (const char **str) | ||
| 35 | { | ||
| 36 | const char *match = NULL; | ||
| 37 | bool read_alpha = false; | ||
| 38 | while (**str) | ||
| 39 | { | ||
| 40 | if (read_alpha) | ||
| 41 | { | ||
| 42 | read_alpha = false; | ||
| 43 | if (!c_isalpha (**str) && '~' != **str) | ||
| 44 | match = NULL; | ||
| 45 | } | ||
| 46 | else if ('.' == **str) | ||
| 47 | { | ||
| 48 | read_alpha = true; | ||
| 49 | if (!match) | ||
| 50 | match = *str; | ||
| 51 | } | ||
| 52 | else if (!c_isalnum (**str) && '~' != **str) | ||
| 53 | match = NULL; | ||
| 54 | (*str)++; | ||
| 55 | } | ||
| 56 | return match; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* verrevcmp helper function */ | ||
| 60 | static int | ||
| 61 | order (unsigned char c) | ||
| 62 | { | ||
| 63 | if (c_isdigit (c)) | ||
| 64 | return 0; | ||
| 65 | else if (c_isalpha (c)) | ||
| 66 | return c; | ||
| 67 | else if (c == '~') | ||
| 68 | return -1; | ||
| 69 | else | ||
| 70 | return (int) c + UCHAR_MAX + 1; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* slightly modified verrevcmp function from dpkg | ||
| 74 | S1, S2 - compared string | ||
| 75 | S1_LEN, S2_LEN - length of strings to be scanned | ||
| 76 | |||
| 77 | This implements the algorithm for comparison of version strings | ||
| 78 | specified by Debian and now widely adopted. The detailed | ||
| 79 | specification can be found in the Debian Policy Manual in the | ||
| 80 | section on the 'Version' control field. This version of the code | ||
| 81 | implements that from s5.6.12 of Debian Policy v3.8.0.1 | ||
| 82 | http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version */ | ||
| 83 | static int _GL_ATTRIBUTE_PURE | ||
| 84 | verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t s2_len) | ||
| 85 | { | ||
| 86 | size_t s1_pos = 0; | ||
| 87 | size_t s2_pos = 0; | ||
| 88 | while (s1_pos < s1_len || s2_pos < s2_len) | ||
| 89 | { | ||
| 90 | int first_diff = 0; | ||
| 91 | while ((s1_pos < s1_len && !c_isdigit (s1[s1_pos])) | ||
| 92 | || (s2_pos < s2_len && !c_isdigit (s2[s2_pos]))) | ||
| 93 | { | ||
| 94 | int s1_c = (s1_pos == s1_len) ? 0 : order (s1[s1_pos]); | ||
| 95 | int s2_c = (s2_pos == s2_len) ? 0 : order (s2[s2_pos]); | ||
| 96 | if (s1_c != s2_c) | ||
| 97 | return s1_c - s2_c; | ||
| 98 | s1_pos++; | ||
| 99 | s2_pos++; | ||
| 100 | } | ||
| 101 | while (s1[s1_pos] == '0') | ||
| 102 | s1_pos++; | ||
| 103 | while (s2[s2_pos] == '0') | ||
| 104 | s2_pos++; | ||
| 105 | while (c_isdigit (s1[s1_pos]) && c_isdigit (s2[s2_pos])) | ||
| 106 | { | ||
| 107 | if (!first_diff) | ||
| 108 | first_diff = s1[s1_pos] - s2[s2_pos]; | ||
| 109 | s1_pos++; | ||
| 110 | s2_pos++; | ||
| 111 | } | ||
| 112 | if (c_isdigit (s1[s1_pos])) | ||
| 113 | return 1; | ||
| 114 | if (c_isdigit (s2[s2_pos])) | ||
| 115 | return -1; | ||
| 116 | if (first_diff) | ||
| 117 | return first_diff; | ||
| 118 | } | ||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Compare version strings S1 and S2. | ||
| 123 | See filevercmp.h for function description. */ | ||
| 124 | int | ||
| 125 | filevercmp (const char *s1, const char *s2) | ||
| 126 | { | ||
| 127 | const char *s1_pos; | ||
| 128 | const char *s2_pos; | ||
| 129 | const char *s1_suffix, *s2_suffix; | ||
| 130 | size_t s1_len, s2_len; | ||
| 131 | int result; | ||
| 132 | |||
| 133 | /* easy comparison to see if strings are identical */ | ||
| 134 | int simple_cmp = strcmp (s1, s2); | ||
| 135 | if (simple_cmp == 0) | ||
| 136 | return 0; | ||
| 137 | |||
| 138 | /* special handle for "", "." and ".." */ | ||
| 139 | if (!*s1) | ||
| 140 | return -1; | ||
| 141 | if (!*s2) | ||
| 142 | return 1; | ||
| 143 | if (0 == strcmp (".", s1)) | ||
| 144 | return -1; | ||
| 145 | if (0 == strcmp (".", s2)) | ||
| 146 | return 1; | ||
| 147 | if (0 == strcmp ("..", s1)) | ||
| 148 | return -1; | ||
| 149 | if (0 == strcmp ("..", s2)) | ||
| 150 | return 1; | ||
| 151 | |||
| 152 | /* special handle for other hidden files */ | ||
| 153 | if (*s1 == '.' && *s2 != '.') | ||
| 154 | return -1; | ||
| 155 | if (*s1 != '.' && *s2 == '.') | ||
| 156 | return 1; | ||
| 157 | if (*s1 == '.' && *s2 == '.') | ||
| 158 | { | ||
| 159 | s1++; | ||
| 160 | s2++; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* "cut" file suffixes */ | ||
| 164 | s1_pos = s1; | ||
| 165 | s2_pos = s2; | ||
| 166 | s1_suffix = match_suffix (&s1_pos); | ||
| 167 | s2_suffix = match_suffix (&s2_pos); | ||
| 168 | s1_len = (s1_suffix ? s1_suffix : s1_pos) - s1; | ||
| 169 | s2_len = (s2_suffix ? s2_suffix : s2_pos) - s2; | ||
| 170 | |||
| 171 | /* restore file suffixes if strings are identical after "cut" */ | ||
| 172 | if ((s1_suffix || s2_suffix) && (s1_len == s2_len) | ||
| 173 | && 0 == strncmp (s1, s2, s1_len)) | ||
| 174 | { | ||
| 175 | s1_len = s1_pos - s1; | ||
| 176 | s2_len = s2_pos - s2; | ||
| 177 | } | ||
| 178 | |||
| 179 | result = verrevcmp (s1, s1_len, s2, s2_len); | ||
| 180 | return result == 0 ? simple_cmp : result; | ||
| 181 | } | ||
diff --git a/lib/filevercmp.h b/lib/filevercmp.h new file mode 100644 index 00000000000..220b71b5790 --- /dev/null +++ b/lib/filevercmp.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* | ||
| 2 | Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk> | ||
| 3 | Copyright (C) 2001 Anthony Towns <aj@azure.humbug.org.au> | ||
| 4 | Copyright (C) 2008-2016 Free Software Foundation, Inc. | ||
| 5 | |||
| 6 | This program is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | #ifndef FILEVERCMP_H | ||
| 20 | #define FILEVERCMP_H | ||
| 21 | |||
| 22 | /* Compare version strings: | ||
| 23 | |||
| 24 | This function compares strings S1 and S2: | ||
| 25 | 1) By PREFIX in the same way as strcmp. | ||
| 26 | 2) Then by VERSION (most similarly to version compare of Debian's dpkg). | ||
| 27 | Leading zeros in version numbers are ignored. | ||
| 28 | 3) If both (PREFIX and VERSION) are equal, strcmp function is used for | ||
| 29 | comparison. So this function can return 0 if (and only if) strings S1 | ||
| 30 | and S2 are identical. | ||
| 31 | |||
| 32 | It returns number >0 for S1 > S2, 0 for S1 == S2 and number <0 for S1 < S2. | ||
| 33 | |||
| 34 | This function compares strings, in a way that if VER1 and VER2 are version | ||
| 35 | numbers and PREFIX and SUFFIX (SUFFIX defined as (\.[A-Za-z~][A-Za-z0-9~]*)*) | ||
| 36 | are strings then VER1 < VER2 implies filevercmp (PREFIX VER1 SUFFIX, | ||
| 37 | PREFIX VER2 SUFFIX) < 0. | ||
| 38 | |||
| 39 | This function is intended to be a replacement for strverscmp. */ | ||
| 40 | int filevercmp (const char *s1, const char *s2) _GL_ATTRIBUTE_PURE; | ||
| 41 | |||
| 42 | #endif /* FILEVERCMP_H */ | ||
diff --git a/lib/gnulib.mk b/lib/gnulib.mk index b1edd86f92c..cc8429658e1 100644 --- a/lib/gnulib.mk +++ b/lib/gnulib.mk | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | # the same distribution terms as the rest of that program. | 21 | # the same distribution terms as the rest of that program. |
| 22 | # | 22 | # |
| 23 | # Generated by gnulib-tool. | 23 | # Generated by gnulib-tool. |
| 24 | # Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=flexmember --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=unsetenv --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings | 24 | # Reproduce by: gnulib-tool --import --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=flexmember --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=setenv --avoid=sigprocmask --avoid=stdarg --avoid=stdbool --avoid=threadlib --avoid=unsetenv --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt binary-io byteswap c-ctype c-strcase careadlinkat close-stream count-one-bits count-trailing-zeros crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode filevercmp fstatat fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strftime strtoimax strtoumax symlink sys_stat sys_time time time_r time_rz timegm timer-time timespec-add timespec-sub unsetenv update-copyright utimens vla warnings |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | MOSTLYCLEANFILES += core *.stackdump | 27 | MOSTLYCLEANFILES += core *.stackdump |
| @@ -441,6 +441,14 @@ EXTRA_DIST += filemode.h | |||
| 441 | 441 | ||
| 442 | ## end gnulib module filemode | 442 | ## end gnulib module filemode |
| 443 | 443 | ||
| 444 | ## begin gnulib module filevercmp | ||
| 445 | |||
| 446 | libgnu_a_SOURCES += filevercmp.c | ||
| 447 | |||
| 448 | EXTRA_DIST += filevercmp.h | ||
| 449 | |||
| 450 | ## end gnulib module filevercmp | ||
| 451 | |||
| 444 | ## begin gnulib module fpending | 452 | ## begin gnulib module fpending |
| 445 | 453 | ||
| 446 | 454 | ||