aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2016-02-21 13:25:24 -0800
committerPaul Eggert2016-02-21 13:27:40 -0800
commit1f7feecaee0ed3fb79758fe60020aefb30d9ff01 (patch)
treeb0476096aabea32658be041242caa74e7a5232cd /src
parent3e67708d7239cde24b0988d4d1288bc75585cfea (diff)
downloademacs-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 'src')
-rw-r--r--src/fns.c129
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/>. */
21#include <config.h> 21#include <config.h>
22 22
23#include <unistd.h> 23#include <unistd.h>
24#include <filevercmp.h>
24#include <intprops.h> 25#include <intprops.h>
25#include <vla.h> 26#include <vla.h>
26#include <errno.h> 27#include <errno.h>
@@ -332,50 +333,21 @@ Symbols are also allowed; their print names are used instead. */)
332 return i1 < SCHARS (string2) ? Qt : Qnil; 333 return i1 < SCHARS (string2) ? Qt : Qnil;
333} 334}
334 335
335/* Return the numerical value of a consecutive run of numerical 336DEFUN ("string-version-lessp", Fstring_version_lessp,
336 characters from STRING. The ISP and ISP_BYTE address pointer 337 Sstring_version_lessp, 2, 2, 0,
337 pointers are increased and left at the next character after the 338 doc: /* Return non-nil if S1 is less than S2, as version strings.
338 numerical characters. */ 339
339static size_t 340This function compares version strings S1 and S2:
340gather_number_from_string (Lisp_Object string, 341 1) By prefix lexicographically.
341 ptrdiff_t *isp, ptrdiff_t *isp_byte) 342 2) Then by version (similarly to version comparison of Debian's dpkg).
342{ 343 Leading zeros in version numbers are ignored.
343 size_t number = 0; 344 3) If both prefix and version are equal, compare as ordinary strings.
344 char *s = SSDATA (string);
345 char *end;
346
347 errno = 0;
348 number = strtoumax (s + *isp_byte, &end, 10);
349 if (errno == ERANGE)
350 /* If we have an integer overflow, then we fall back on lexical
351 comparison. */
352 return -1;
353 else
354 {
355 size_t diff = end - (s + *isp_byte);
356 (*isp) += diff;
357 (*isp_byte) += diff;
358 return number;
359 }
360}
361 345
362DEFUN ("string-numeric-lessp", Fstring_numeric_lessp, 346For example, \"foo2.png\" compares less than \"foo12.png\".
363 Sstring_numeric_lessp, 2, 2, 0,
364 doc: /* Return non-nil if STRING1 is less than STRING2 in 'numeric' order.
365Sequences of non-numerical characters are compared lexicographically,
366while sequences of numerical characters are converted into numbers,
367and then the numbers are compared. This means that \"foo2.png\" is
368less than \"foo12.png\" according to this predicate.
369Case is significant. 347Case is significant.
370Symbols are also allowed; their print names are used instead. */) 348Symbols are also allowed; their print names are used instead. */)
371 (register Lisp_Object string1, Lisp_Object string2) 349 (Lisp_Object string1, Lisp_Object string2)
372{ 350{
373 ptrdiff_t end;
374 ptrdiff_t i1, i1_byte, i2, i2_byte;
375 size_t num1, num2;
376 unsigned char *chp;
377 int chlen1, chlen2;
378
379 if (SYMBOLP (string1)) 351 if (SYMBOLP (string1))
380 string1 = SYMBOL_NAME (string1); 352 string1 = SYMBOL_NAME (string1);
381 if (SYMBOLP (string2)) 353 if (SYMBOLP (string2))
@@ -383,67 +355,26 @@ Symbols are also allowed; their print names are used instead. */)
383 CHECK_STRING (string1); 355 CHECK_STRING (string1);
384 CHECK_STRING (string2); 356 CHECK_STRING (string2);
385 357
386 i1 = i1_byte = i2 = i2_byte = 0; 358 char *p1 = SSDATA (string1);
359 char *p2 = SSDATA (string2);
360 char *lim1 = p1 + SBYTES (string1);
361 char *lim2 = p2 + SBYTES (string2);
362 int cmp;
387 363
388 end = SCHARS (string1); 364 while ((cmp = filevercmp (p1, p2)) == 0)
389 if (end > SCHARS (string2))
390 end = SCHARS (string2);
391
392 while (i1 < end)
393 { 365 {
394 /* When we find a mismatch, we must compare the 366 /* If the strings are identical through their first null bytes,
395 characters, not just the bytes. */ 367 skip past identical prefixes and try again. */
396 int c1, c2; 368 ptrdiff_t size = strlen (p1) + 1;
397 369 p1 += size;
398 if (STRING_MULTIBYTE (string1)) 370 p2 += size;
399 { 371 if (lim1 < p1)
400 chp = &SDATA (string1)[i1_byte]; 372 return lim2 < p2 ? Qnil : Qt;
401 c1 = STRING_CHAR_AND_LENGTH (chp, chlen1); 373 if (lim2 < p2)
402 } 374 return Qnil;
403 else
404 {
405 c1 = SREF (string1, i1_byte);
406 chlen1 = 1;
407 }
408
409 if (STRING_MULTIBYTE (string2))
410 {
411 chp = &SDATA (string1)[i2_byte];
412 c2 = STRING_CHAR_AND_LENGTH (chp, chlen2);
413 }
414 else
415 {
416 c2 = SREF (string2, i2_byte);
417 chlen2 = 1;
418 }
419
420 if (c1 >= '0' && c1 <= '9' &&
421 c2 >= '0' && c2 <= '9')
422 /* Both strings are numbers, so compare them. */
423 {
424 num1 = gather_number_from_string (string1, &i1, &i1_byte);
425 num2 = gather_number_from_string (string2, &i2, &i2_byte);
426 /* If we have an integer overflow, then resort to sorting
427 the entire string lexicographically. */
428 if (num1 == -1 || num2 == -1)
429 return Fstring_lessp (string1, string2);
430 else if (num1 < num2)
431 return Qt;
432 else if (num1 > num2)
433 return Qnil;
434 }
435 else
436 {
437 if (c1 != c2)
438 return c1 < c2 ? Qt : Qnil;
439
440 i1++;
441 i2++;
442 i1_byte += chlen1;
443 i2_byte += chlen2;
444 }
445 } 375 }
446 return i1 < SCHARS (string2) ? Qt : Qnil; 376
377 return cmp < 0 ? Qt : Qnil;
447} 378}
448 379
449DEFUN ("string-collate-lessp", Fstring_collate_lessp, Sstring_collate_lessp, 2, 4, 0, 380DEFUN ("string-collate-lessp", Fstring_collate_lessp, Sstring_collate_lessp, 2, 4, 0,
@@ -5164,7 +5095,7 @@ this variable. */);
5164 defsubr (&Sstring_equal); 5095 defsubr (&Sstring_equal);
5165 defsubr (&Scompare_strings); 5096 defsubr (&Scompare_strings);
5166 defsubr (&Sstring_lessp); 5097 defsubr (&Sstring_lessp);
5167 defsubr (&Sstring_numeric_lessp); 5098 defsubr (&Sstring_version_lessp);
5168 defsubr (&Sstring_collate_lessp); 5099 defsubr (&Sstring_collate_lessp);
5169 defsubr (&Sstring_collate_equalp); 5100 defsubr (&Sstring_collate_equalp);
5170 defsubr (&Sappend); 5101 defsubr (&Sappend);