Blame gl/strverscmp.c

Packit aea12f
/* Compare strings while treating digits characters numerically.
Packit aea12f
   Copyright (C) 1997-2019 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 aea12f
   modify it under the terms of the GNU General Public
Packit aea12f
   License as published by the Free Software Foundation; either
Packit aea12f
   version 3 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 aea12f
   General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU General Public
Packit aea12f
   License along with the GNU C Library; if not, see
Packit aea12f
   <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
#if !_LIBC
Packit aea12f
# include <config.h>
Packit aea12f
#endif
Packit aea12f
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
#ifndef weak_alias
Packit aea12f
# define __strverscmp strverscmp
Packit aea12f
#endif
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
  unsigned char c1, c2;
Packit aea12f
  int state;
Packit aea12f
  int diff;
Packit aea12f
Packit aea12f
  /* Symbol(s)    0       [1-9]   others
Packit aea12f
     Transition   (10) 0  (01) d  (00) x   */
Packit aea12f
  static const unsigned char 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 aea12f
  static const signed char 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 aea12f
  c1 = *p1++;
Packit aea12f
  c2 = *p2++;
Packit aea12f
  /* Hint: '0' is a digit too.  */
Packit aea12f
  state = S_N + ((c1 == '0') + (isdigit (c1) != 0));
Packit aea12f
Packit aea12f
  while ((diff = c1 - c2) == 0)
Packit aea12f
    {
Packit aea12f
      if (c1 == '\0')
Packit aea12f
        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 aea12f
    {
Packit aea12f
    case CMP:
Packit aea12f
      return diff;
Packit aea12f
Packit aea12f
    case LEN:
Packit aea12f
      while (isdigit (*p1++))
Packit aea12f
        if (!isdigit (*p2++))
Packit aea12f
          return 1;
Packit aea12f
Packit aea12f
      return isdigit (*p2) ? -1 : diff;
Packit aea12f
Packit aea12f
    default:
Packit aea12f
      return state;
Packit aea12f
    }
Packit aea12f
}
Packit aea12f
#ifdef weak_alias
Packit aea12f
libc_hidden_def (__strverscmp)
Packit aea12f
weak_alias (__strverscmp, strverscmp)
Packit aea12f
#endif