Blame gl/strverscmp.c

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