Blame gl/strverscmp.c

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