From: Paul Eggert Date: Tue, 30 Aug 2016 15:23:44 +0000 (-0700) Subject: strverscmp: sync with glibc X-Git-Tag: v1.0~6667 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=5d856f70e9515ea5288d9cc9b15996af41bf4f7f;p=gnulib.git strverscmp: sync with glibc Although this doesn't exactly synchronize with glibc byte-for-byte, it makes the code behave the same as glibc. * lib/strverscmp.c (S_I, S_F, S_Z): Now masks, not powers of 2. (ISDIGIT): Remove, as glibc is sticking with isdigit, and the difference shouldn't matter in practical use. All uses changed back to isdigit. (__strverscmp, strverscmp): Use new glibc method for weak aliases. (next_state): Now unsigned char array; redo elements. (result_type): Now signed char array; redo elements. (__strverscmp): Fix glibc bug 9913 by using new states. * tests/test-strverscmp.c (main): Test glibc bug 9913. --- diff --git a/ChangeLog b/ChangeLog index d69407668c..7d0cdbd8fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2016-08-30 Paul Eggert + + strverscmp: sync with glibc + Although this doesn't exactly synchronize with glibc + byte-for-byte, it makes the code behave the same as glibc. + * lib/strverscmp.c (S_I, S_F, S_Z): Now masks, not powers of 2. + (ISDIGIT): Remove, as glibc is sticking with isdigit, and the + difference shouldn't matter in practical use. All uses changed + back to isdigit. + (__strverscmp, strverscmp): Use new glibc method for weak aliases. + (next_state): Now unsigned char array; redo elements. + (result_type): Now signed char array; redo elements. + (__strverscmp): Fix glibc bug 9913 by using new states. + * tests/test-strverscmp.c (main): Test glibc bug 9913. + 2016-08-29 Jim Meyering xalloc-oversized.h: port __builtin_mul_overflow change to GCC 6.2.0 diff --git a/lib/strverscmp.c b/lib/strverscmp.c index bb04d6b251..a23e47fc8b 100644 --- a/lib/strverscmp.c +++ b/lib/strverscmp.c @@ -1,21 +1,21 @@ -/* Compare strings while treating digits numerically. -*- coding: utf-8 -*- - Copyright (C) 1997, 2000, 2002, 2004, 2006, 2009-2016 Free Software - Foundation, Inc. +/* Compare strings while treating digits characters numerically. + Copyright (C) 1997-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jean-François Bignolles , 1997. - 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 2, or (at your option) - any later version. + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + The GNU C Library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 . */ + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ #if !_LIBC # include @@ -26,32 +26,16 @@ /* states: S_N: normal, S_I: comparing integral part, S_F: comparing fractional parts, S_Z: idem but with leading Zeroes only */ -#define S_N 0x0 -#define S_I 0x4 -#define S_F 0x8 -#define S_Z 0xC +#define S_N 0x0 +#define S_I 0x3 +#define S_F 0x6 +#define S_Z 0x9 /* result_type: CMP: return diff; LEN: compare using len_diff/diff */ -#define CMP 2 -#define LEN 3 +#define CMP 2 +#define LEN 3 -/* ISDIGIT differs from isdigit, as follows: - - Its arg may be any int or unsigned int; it need not be an unsigned char - or EOF. - - It's typically faster. - POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to - isdigit unless it's important to use the locale's definition - of "digit" even when the host does not conform to POSIX. */ -#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9) - -#undef __strverscmp -#undef strverscmp - -#ifndef weak_alias -# define __strverscmp strverscmp -#endif - /* Compare S1 and S2 as strings holding indices/version numbers, returning less than, equal to or greater than zero if S1 is less than, equal to or greater than S2 (for more info, see the texinfo doc). @@ -66,30 +50,25 @@ __strverscmp (const char *s1, const char *s2) int state; int diff; - /* Symbol(s) 0 [1-9] others (padding) - Transition (10) 0 (01) d (00) x (11) - */ - static const unsigned int next_state[] = + /* Symbol(s) 0 [1-9] others + Transition (10) 0 (01) d (00) x */ + static const unsigned char next_state[] = { - /* state x d 0 - */ - /* S_N */ S_N, S_I, S_Z, S_N, - /* S_I */ S_N, S_I, S_I, S_I, - /* S_F */ S_N, S_F, S_F, S_F, - /* S_Z */ S_N, S_F, S_Z, S_Z + /* state x d 0 */ + /* S_N */ S_N, S_I, S_Z, + /* S_I */ S_N, S_I, S_I, + /* S_F */ S_N, S_F, S_F, + /* S_Z */ S_N, S_F, S_Z }; - static const int result_type[] = + static const signed char result_type[] = { - /* state x/x x/d x/0 x/- d/x d/d d/0 d/- - 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */ - - /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, - CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, - /* S_I */ CMP, -1, -1, CMP, 1, LEN, LEN, CMP, - 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, - /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, - CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, - /* S_Z */ CMP, 1, 1, CMP, -1, CMP, CMP, CMP, - -1, CMP, CMP, CMP + /* state x/x x/d x/0 d/x d/d d/0 0/x 0/d 0/0 */ + + /* S_N */ CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, + /* S_I */ CMP, -1, -1, +1, LEN, LEN, +1, LEN, LEN, + /* S_F */ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_Z */ CMP, +1, +1, -1, CMP, CMP, -1, CMP, CMP }; if (p1 == p2) @@ -98,17 +77,20 @@ __strverscmp (const char *s1, const char *s2) c1 = *p1++; c2 = *p2++; /* Hint: '0' is a digit too. */ - state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0)); + state = S_N + ((c1 == '0') + (isdigit (c1) != 0)); - while ((diff = c1 - c2) == 0 && c1 != '\0') + while ((diff = c1 - c2) == 0) { + if (c1 == '\0') + return diff; + state = next_state[state]; c1 = *p1++; c2 = *p2++; - state |= (c1 == '0') + (ISDIGIT (c1) != 0); + state += (c1 == '0') + (isdigit (c1) != 0); } - state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT (c2) != 0))]; + state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))]; switch (state) { @@ -116,16 +98,17 @@ __strverscmp (const char *s1, const char *s2) return diff; case LEN: - while (ISDIGIT (*p1++)) - if (!ISDIGIT (*p2++)) + while (isdigit (*p1++)) + if (!isdigit (*p2++)) return 1; - return ISDIGIT (*p2) ? -1 : diff; + return isdigit (*p2) ? -1 : diff; default: return state; } } #ifdef weak_alias +libc_hidden_def (__strverscmp) weak_alias (__strverscmp, strverscmp) #endif diff --git a/tests/test-strverscmp.c b/tests/test-strverscmp.c index e5a6bb10f8..0cafe08fb1 100644 --- a/tests/test-strverscmp.c +++ b/tests/test-strverscmp.c @@ -41,5 +41,19 @@ main (void) ASSERT (strverscmp ("09", "0") < 0); ASSERT (strverscmp ("9", "10") < 0); ASSERT (strverscmp ("0a", "0") > 0); + + /* From glibc bug 9913. */ + { + static char const a[] = "B0075022800016.gbp.corp.com"; + static char const b[] = "B007502280067.gbp.corp.com"; + static char const c[] = "B007502357019.GBP.CORP.COM"; + ASSERT (strverscmp (a, b) < 0); + ASSERT (strverscmp (b, c) < 0); + ASSERT (strverscmp (a, c) < 0); + ASSERT (strverscmp (b, a) > 0); + ASSERT (strverscmp (c, b) > 0); + ASSERT (strverscmp (c, a) > 0); + } + return 0; }