diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2016-02-21 13:25:24 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2016-02-21 13:27:40 -0800 |
commit | 1f7feecaee0ed3fb79758fe60020aefb30d9ff01 (patch) | |
tree | b0476096aabea32658be041242caa74e7a5232cd /src/fns.c | |
parent | 3e67708d7239cde24b0988d4d1288bc75585cfea (diff) | |
download | emacs-1f7feecaee0ed3fb79758fe60020aefb30d9ff01.tar.gz emacs-1f7feecaee0ed3fb79758fe60020aefb30d9ff01.tar.bz2 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 'src/fns.c')
-rw-r--r-- | src/fns.c | 129 |
1 files changed, 30 insertions, 99 deletions
diff --git a/src/fns.c b/src/fns.c index 77ad4505c94..d314fcd0711 100644 --- a/src/fns.c +++ b/src/fns.c @@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <config.h> #include <unistd.h> +#include <filevercmp.h> #include <intprops.h> #include <vla.h> #include <errno.h> @@ -332,50 +333,21 @@ Symbols are also allowed; their print names are used instead. */) return i1 < SCHARS (string2) ? Qt : Qnil; } -/* Return the numerical value of a consecutive run of numerical - characters from STRING. The ISP and ISP_BYTE address pointer - pointers are increased and left at the next character after the - numerical characters. */ -static size_t -gather_number_from_string (Lisp_Object string, - ptrdiff_t *isp, ptrdiff_t *isp_byte) -{ - size_t number = 0; - char *s = SSDATA (string); - char *end; - - errno = 0; - number = strtoumax (s + *isp_byte, &end, 10); - if (errno == ERANGE) - /* If we have an integer overflow, then we fall back on lexical - comparison. */ - return -1; - else - { - size_t diff = end - (s + *isp_byte); - (*isp) += diff; - (*isp_byte) += diff; - return number; - } -} +DEFUN ("string-version-lessp", Fstring_version_lessp, + Sstring_version_lessp, 2, 2, 0, + doc: /* Return non-nil if S1 is less than S2, as version strings. + +This function compares version strings S1 and S2: + 1) By prefix lexicographically. + 2) Then by version (similarly to version comparison of Debian's dpkg). + Leading zeros in version numbers are ignored. + 3) If both prefix and version are equal, compare as ordinary strings. -DEFUN ("string-numeric-lessp", Fstring_numeric_lessp, - Sstring_numeric_lessp, 2, 2, 0, - doc: /* Return non-nil if STRING1 is less than STRING2 in 'numeric' order. -Sequences of non-numerical characters are compared lexicographically, -while sequences of numerical characters are converted into numbers, -and then the numbers are compared. This means that \"foo2.png\" is -less than \"foo12.png\" according to this predicate. +For example, \"foo2.png\" compares less than \"foo12.png\". Case is significant. Symbols are also allowed; their print names are used instead. */) - (register Lisp_Object string1, Lisp_Object string2) + (Lisp_Object string1, Lisp_Object string2) { - ptrdiff_t end; - ptrdiff_t i1, i1_byte, i2, i2_byte; - size_t num1, num2; - unsigned char *chp; - int chlen1, chlen2; - if (SYMBOLP (string1)) string1 = SYMBOL_NAME (string1); if (SYMBOLP (string2)) @@ -383,67 +355,26 @@ Symbols are also allowed; their print names are used instead. */) CHECK_STRING (string1); CHECK_STRING (string2); - i1 = i1_byte = i2 = i2_byte = 0; + char *p1 = SSDATA (string1); + char *p2 = SSDATA (string2); + char *lim1 = p1 + SBYTES (string1); + char *lim2 = p2 + SBYTES (string2); + int cmp; - end = SCHARS (string1); - if (end > SCHARS (string2)) - end = SCHARS (string2); - - while (i1 < end) + while ((cmp = filevercmp (p1, p2)) == 0) { - /* When we find a mismatch, we must compare the - characters, not just the bytes. */ - int c1, c2; - - if (STRING_MULTIBYTE (string1)) - { - chp = &SDATA (string1)[i1_byte]; - c1 = STRING_CHAR_AND_LENGTH (chp, chlen1); - } - else - { - c1 = SREF (string1, i1_byte); - chlen1 = 1; - } - - if (STRING_MULTIBYTE (string2)) - { - chp = &SDATA (string1)[i2_byte]; - c2 = STRING_CHAR_AND_LENGTH (chp, chlen2); - } - else - { - c2 = SREF (string2, i2_byte); - chlen2 = 1; - } - - if (c1 >= '0' && c1 <= '9' && - c2 >= '0' && c2 <= '9') - /* Both strings are numbers, so compare them. */ - { - num1 = gather_number_from_string (string1, &i1, &i1_byte); - num2 = gather_number_from_string (string2, &i2, &i2_byte); - /* If we have an integer overflow, then resort to sorting - the entire string lexicographically. */ - if (num1 == -1 || num2 == -1) - return Fstring_lessp (string1, string2); - else if (num1 < num2) - return Qt; - else if (num1 > num2) - return Qnil; - } - else - { - if (c1 != c2) - return c1 < c2 ? Qt : Qnil; - - i1++; - i2++; - i1_byte += chlen1; - i2_byte += chlen2; - } + /* If the strings are identical through their first null bytes, + skip past identical prefixes and try again. */ + ptrdiff_t size = strlen (p1) + 1; + p1 += size; + p2 += size; + if (lim1 < p1) + return lim2 < p2 ? Qnil : Qt; + if (lim2 < p2) + return Qnil; } - return i1 < SCHARS (string2) ? Qt : Qnil; + + return cmp < 0 ? Qt : Qnil; } DEFUN ("string-collate-lessp", Fstring_collate_lessp, Sstring_collate_lessp, 2, 4, 0, @@ -5164,7 +5095,7 @@ this variable. */); defsubr (&Sstring_equal); defsubr (&Scompare_strings); defsubr (&Sstring_lessp); - defsubr (&Sstring_numeric_lessp); + defsubr (&Sstring_version_lessp); defsubr (&Sstring_collate_lessp); defsubr (&Sstring_collate_equalp); defsubr (&Sappend); |