Back to index

glibc  2.9
strverscmp.c
Go to the documentation of this file.
00001 /* Compare strings while treating digits characters numerically.
00002    Copyright (C) 1997, 2002 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <string.h>
00022 #include <ctype.h>
00023 
00024 /* states: S_N: normal, S_I: comparing integral part, S_F: comparing
00025            fractionnal parts, S_Z: idem but with leading Zeroes only */
00026 #define  S_N    0x0
00027 #define  S_I    0x4
00028 #define  S_F    0x8
00029 #define  S_Z    0xC
00030 
00031 /* result_type: CMP: return diff; LEN: compare using len_diff/diff */
00032 #define  CMP    2
00033 #define  LEN    3
00034 
00035 
00036 /* Compare S1 and S2 as strings holding indices/version numbers,
00037    returning less than, equal to or greater than zero if S1 is less than,
00038    equal to or greater than S2 (for more info, see the texinfo doc).
00039 */
00040 
00041 int
00042 __strverscmp (s1, s2)
00043      const char *s1;
00044      const char *s2;
00045 {
00046   const unsigned char *p1 = (const unsigned char *) s1;
00047   const unsigned char *p2 = (const unsigned char *) s2;
00048   unsigned char c1, c2;
00049   int state;
00050   int diff;
00051 
00052   /* Symbol(s)    0       [1-9]   others  (padding)
00053      Transition   (10) 0  (01) d  (00) x  (11) -   */
00054   static const unsigned int next_state[] =
00055   {
00056       /* state    x    d    0    - */
00057       /* S_N */  S_N, S_I, S_Z, S_N,
00058       /* S_I */  S_N, S_I, S_I, S_I,
00059       /* S_F */  S_N, S_F, S_F, S_F,
00060       /* S_Z */  S_N, S_F, S_Z, S_Z
00061   };
00062 
00063   static const int result_type[] =
00064   {
00065       /* state   x/x  x/d  x/0  x/-  d/x  d/d  d/0  d/-
00066                  0/x  0/d  0/0  0/-  -/x  -/d  -/0  -/- */
00067 
00068       /* S_N */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
00069                  CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
00070       /* S_I */  CMP, -1,  -1,  CMP, +1,  LEN, LEN, CMP,
00071                  +1,  LEN, LEN, CMP, CMP, CMP, CMP, CMP,
00072       /* S_F */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
00073                  CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
00074       /* S_Z */  CMP, +1,  +1,  CMP, -1,  CMP, CMP, CMP,
00075                  -1,  CMP, CMP, CMP
00076   };
00077 
00078   if (p1 == p2)
00079     return 0;
00080 
00081   c1 = *p1++;
00082   c2 = *p2++;
00083   /* Hint: '0' is a digit too.  */
00084   state = S_N | ((c1 == '0') + (isdigit (c1) != 0));
00085 
00086   while ((diff = c1 - c2) == 0 && c1 != '\0')
00087     {
00088       state = next_state[state];
00089       c1 = *p1++;
00090       c2 = *p2++;
00091       state |= (c1 == '0') + (isdigit (c1) != 0);
00092     }
00093 
00094   state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))];
00095 
00096   switch (state)
00097   {
00098     case CMP:
00099       return diff;
00100 
00101     case LEN:
00102       while (isdigit (*p1++))
00103        if (!isdigit (*p2++))
00104          return 1;
00105 
00106       return isdigit (*p2) ? -1 : diff;
00107 
00108     default:
00109       return state;
00110   }
00111 }
00112 libc_hidden_def (__strverscmp)
00113 weak_alias (__strverscmp, strverscmp)