Blame string/strverscmp.c

Packit 6c4009
/* Compare strings while treating digits characters numerically.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
Packit 6c4009
/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
Packit 6c4009
           fractionnal parts, S_Z: idem but with leading Zeroes only */
Packit 6c4009
#define  S_N    0x0
Packit 6c4009
#define  S_I    0x3
Packit 6c4009
#define  S_F    0x6
Packit 6c4009
#define  S_Z    0x9
Packit 6c4009
Packit 6c4009
/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
Packit 6c4009
#define  CMP    2
Packit 6c4009
#define  LEN    3
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Compare S1 and S2 as strings holding indices/version numbers,
Packit 6c4009
   returning less than, equal to or greater than zero if S1 is less than,
Packit 6c4009
   equal to or greater than S2 (for more info, see the texinfo doc).
Packit 6c4009
*/
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__strverscmp (const char *s1, const char *s2)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *p1 = (const unsigned char *) s1;
Packit 6c4009
  const unsigned char *p2 = (const unsigned char *) s2;
Packit 6c4009
Packit 6c4009
  /* Symbol(s)    0       [1-9]   others
Packit 6c4009
     Transition   (10) 0  (01) d  (00) x   */
Packit 6c4009
  static const uint8_t next_state[] =
Packit 6c4009
  {
Packit 6c4009
      /* state    x    d    0  */
Packit 6c4009
      /* S_N */  S_N, S_I, S_Z,
Packit 6c4009
      /* S_I */  S_N, S_I, S_I,
Packit 6c4009
      /* S_F */  S_N, S_F, S_F,
Packit 6c4009
      /* S_Z */  S_N, S_F, S_Z
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
  static const int8_t result_type[] =
Packit 6c4009
  {
Packit 6c4009
      /* state   x/x  x/d  x/0  d/x  d/d  d/0  0/x  0/d  0/0  */
Packit 6c4009
Packit 6c4009
      /* S_N */  CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP,
Packit 6c4009
      /* S_I */  CMP, -1,  -1,  +1,  LEN, LEN, +1,  LEN, LEN,
Packit 6c4009
      /* S_F */  CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
Packit 6c4009
      /* S_Z */  CMP, +1,  +1,  -1,  CMP, CMP, -1,  CMP, CMP
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
  if (p1 == p2)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  unsigned char c1 = *p1++;
Packit 6c4009
  unsigned char c2 = *p2++;
Packit 6c4009
  /* Hint: '0' is a digit too.  */
Packit 6c4009
  int state = S_N + ((c1 == '0') + (isdigit (c1) != 0));
Packit 6c4009
Packit 6c4009
  int diff;
Packit 6c4009
  while ((diff = c1 - c2) == 0)
Packit 6c4009
    {
Packit 6c4009
      if (c1 == '\0')
Packit 6c4009
	return diff;
Packit 6c4009
Packit 6c4009
      state = next_state[state];
Packit 6c4009
      c1 = *p1++;
Packit 6c4009
      c2 = *p2++;
Packit 6c4009
      state += (c1 == '0') + (isdigit (c1) != 0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))];
Packit 6c4009
Packit 6c4009
  switch (state)
Packit 6c4009
  {
Packit 6c4009
    case CMP:
Packit 6c4009
      return diff;
Packit 6c4009
Packit 6c4009
    case LEN:
Packit 6c4009
      while (isdigit (*p1++))
Packit 6c4009
	if (!isdigit (*p2++))
Packit 6c4009
	  return 1;
Packit 6c4009
Packit 6c4009
      return isdigit (*p2) ? -1 : diff;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      return state;
Packit 6c4009
  }
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__strverscmp)
Packit 6c4009
weak_alias (__strverscmp, strverscmp)