aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Ingebrigtsen2016-02-21 15:32:45 +1100
committerLars Ingebrigtsen2016-02-21 15:32:45 +1100
commit71783e90a46ca913ea2c334cdc8cb24cd74055f8 (patch)
tree3c35b883caea4392789d6c991a08bb74475407ad /src
parent1ba50a0d8cbef6686ecf752583832e7bbb9137ef (diff)
downloademacs-71783e90a46ca913ea2c334cdc8cb24cd74055f8.tar.gz
emacs-71783e90a46ca913ea2c334cdc8cb24cd74055f8.zip
Add the string-numeric-lessp function
* doc/lispref/strings.texi (Text Comparison): Document `string-numerical-lessp'. * src/fns.c (Fstring_numeric_lessp): New function. (gather_number_from_string): Helper function for that function. * test/src/fns-tests.el (fns-tests-string-numeric-lessp): Add tests.
Diffstat (limited to 'src')
-rw-r--r--src/fns.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/src/fns.c b/src/fns.c
index d1808440966..927fcdac02d 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -331,6 +331,103 @@ Symbols are also allowed; their print names are used instead. */)
331 return i1 < SCHARS (string2) ? Qt : Qnil; 331 return i1 < SCHARS (string2) ? Qt : Qnil;
332} 332}
333 333
334/* Return the numerical value of a consecutive run of numerical
335 characters from STRING. The ISP and ISP_BYTE address pointer
336 pointers are increased and left at the next character after the
337 numerical characters. */
338static size_t
339gather_number_from_string (int c, Lisp_Object string,
340 ptrdiff_t *isp, ptrdiff_t *isp_byte)
341{
342 size_t number = c - '0';
343 unsigned char *chp;
344 int chlen;
345
346 do
347 {
348 if (STRING_MULTIBYTE (string))
349 {
350 chp = &SDATA (string)[*isp_byte];
351 c = STRING_CHAR_AND_LENGTH (chp, chlen);
352 }
353 else
354 {
355 c = SREF (string, *isp_byte);
356 chlen = 1;
357 }
358
359 /* If we're still in a number, add it to the sum and continue. */
360 /* FIXME: Integer overflow? */
361 if (c >= '0' && c <= '9')
362 {
363 number = number * 10;
364 number += c - '0';
365 (*isp)++;
366 (*isp_byte) += chlen;
367 }
368 else
369 break;
370 }
371 /* Stop when we get to the end of the string anyway. */
372 while (c != 0);
373
374 return number;
375}
376
377DEFUN ("string-numeric-lessp", Fstring_numeric_lessp,
378 Sstring_numeric_lessp, 2, 2, 0,
379 doc: /* Return non-nil if STRING1 is less than STRING2 in 'numeric' order.
380Sequences of non-numerical characters are compared lexicographically,
381while sequences of numerical characters are converted into numbers,
382and then the numbers are compared. This means that \"foo2.png\" is
383less than \"foo12.png\" according to this predicate.
384Case is significant.
385Symbols are also allowed; their print names are used instead. */)
386 (register Lisp_Object string1, Lisp_Object string2)
387{
388 ptrdiff_t end;
389 ptrdiff_t i1, i1_byte, i2, i2_byte;
390 size_t num1, num2;
391
392 if (SYMBOLP (string1))
393 string1 = SYMBOL_NAME (string1);
394 if (SYMBOLP (string2))
395 string2 = SYMBOL_NAME (string2);
396 CHECK_STRING (string1);
397 CHECK_STRING (string2);
398
399 i1 = i1_byte = i2 = i2_byte = 0;
400
401 end = SCHARS (string1);
402 if (end > SCHARS (string2))
403 end = SCHARS (string2);
404
405 while (i1 < end)
406 {
407 /* When we find a mismatch, we must compare the
408 characters, not just the bytes. */
409 int c1, c2;
410
411 FETCH_STRING_CHAR_ADVANCE (c1, string1, i1, i1_byte);
412 FETCH_STRING_CHAR_ADVANCE (c2, string2, i2, i2_byte);
413
414 if (c1 >= '0' && c1 <= '9' &&
415 c2 >= '0' && c2 <= '9')
416 /* Both strings are numbers, so compare them. */
417 {
418 num1 = gather_number_from_string (c1, string1, &i1, &i1_byte);
419 num2 = gather_number_from_string (c2, string2, &i2, &i2_byte);
420 if (num1 < num2)
421 return Qt;
422 else if (num1 > num2)
423 return Qnil;
424 }
425 else if (c1 != c2)
426 return c1 < c2 ? Qt : Qnil;
427 }
428 return i1 < SCHARS (string2) ? Qt : Qnil;
429}
430
334DEFUN ("string-collate-lessp", Fstring_collate_lessp, Sstring_collate_lessp, 2, 4, 0, 431DEFUN ("string-collate-lessp", Fstring_collate_lessp, Sstring_collate_lessp, 2, 4, 0,
335 doc: /* Return t if first arg string is less than second in collation order. 432 doc: /* Return t if first arg string is less than second in collation order.
336Symbols are also allowed; their print names are used instead. 433Symbols are also allowed; their print names are used instead.
@@ -5049,6 +5146,7 @@ this variable. */);
5049 defsubr (&Sstring_equal); 5146 defsubr (&Sstring_equal);
5050 defsubr (&Scompare_strings); 5147 defsubr (&Scompare_strings);
5051 defsubr (&Sstring_lessp); 5148 defsubr (&Sstring_lessp);
5149 defsubr (&Sstring_numeric_lessp);
5052 defsubr (&Sstring_collate_lessp); 5150 defsubr (&Sstring_collate_lessp);
5053 defsubr (&Sstring_collate_equalp); 5151 defsubr (&Sstring_collate_equalp);
5054 defsubr (&Sappend); 5152 defsubr (&Sappend);