974
|
1 /* Compare strings while treating digits characters numerically. |
|
2 Copyright (C) 1997 Free Software Foundation, Inc. |
|
3 This file is part of the GNU C Library. |
|
4 Contributed by Jean-Francois Bignolles <bignolle@ecoledoc.ibp.fr>, 1997. |
|
5 |
|
6 The GNU C Library is free software; you can redistribute it and/or |
|
7 modify it under the terms of the GNU Library General Public License as |
|
8 published by the Free Software Foundation; either version 2 of the |
|
9 License, or (at your option) any later version. |
|
10 |
|
11 The GNU C Library is distributed in the hope that it will be useful, |
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 Library General Public License for more details. |
|
15 |
|
16 You should have received a copy of the GNU Library General Public |
|
17 License along with the GNU C Library; see the file COPYING.LIB. If not, |
|
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
19 Boston, MA 02111-1307, USA. */ |
|
20 |
|
21 #include <string.h> |
|
22 #include <ctype.h> |
|
23 |
|
24 /* states: S_N: normal, S_I: comparing integral part, S_F: comparing |
975
|
25 Fractional parts, S_Z: idem but with leading Zeroes only */ |
974
|
26 #define S_N 0x0 |
|
27 #define S_I 0x4 |
|
28 #define S_F 0x8 |
|
29 #define S_Z 0xC |
|
30 |
|
31 /* result_type: CMP: return diff; LEN: compare using len_diff/diff */ |
|
32 #define CMP 2 |
|
33 #define LEN 3 |
|
34 |
|
35 |
|
36 /* Compare S1 and S2 as strings holding indices/version numbers, |
|
37 returning less than, equal to or greater than zero if S1 is less than, |
|
38 equal to or greater than S2 (for more info, see the texinfo doc). |
|
39 */ |
|
40 |
|
41 int |
|
42 strverscmp (s1, s2) |
|
43 const char *s1; |
|
44 const char *s2; |
|
45 { |
|
46 const unsigned char *p1 = (const unsigned char *) s1; |
|
47 const unsigned char *p2 = (const unsigned char *) s2; |
|
48 unsigned char c1, c2; |
|
49 int state; |
|
50 int diff; |
|
51 |
|
52 /* Symbol(s) 0 [1-9] others (padding) |
|
53 Transition (10) 0 (01) d (00) x (11) - */ |
|
54 static const unsigned int next_state[] = |
|
55 { |
|
56 /* state x d 0 - */ |
|
57 /* S_N */ S_N, S_I, S_Z, S_N, |
|
58 /* S_I */ S_N, S_I, S_I, S_I, |
|
59 /* S_F */ S_N, S_F, S_F, S_F, |
|
60 /* S_Z */ S_N, S_F, S_Z, S_Z |
|
61 }; |
|
62 |
|
63 static const int result_type[] = |
|
64 { |
|
65 /* state x/x x/d x/0 x/- d/x d/d d/0 d/- |
|
66 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */ |
|
67 |
|
68 /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, |
|
69 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, |
|
70 /* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP, |
|
71 +1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, |
|
72 /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, |
|
73 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, |
|
74 /* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP, |
|
75 -1, CMP, CMP, CMP |
|
76 }; |
|
77 |
|
78 if (p1 == p2) |
|
79 return 0; |
|
80 |
|
81 c1 = *p1++; |
|
82 c2 = *p2++; |
|
83 /* Hint: '0' is a digit too. */ |
|
84 state = S_N | (c1 == '0') + (isdigit (c1) != 0); |
|
85 |
|
86 while ((diff = c1 - c2) == 0 && c1 != '\0') |
|
87 { |
|
88 state = next_state[state]; |
|
89 c1 = *p1++; |
|
90 c2 = *p2++; |
|
91 state |= (c1 == '0') + (isdigit (c1) != 0); |
|
92 } |
|
93 |
|
94 state = result_type[state << 2 | ((c2 == '0') + (isdigit (c2) != 0))]; |
|
95 |
|
96 switch (state) |
|
97 { |
|
98 case CMP: |
|
99 return diff; |
|
100 |
|
101 case LEN: |
|
102 while (isdigit (*p1++)) |
|
103 if (!isdigit (*p2++)) |
|
104 return 1; |
|
105 |
|
106 return isdigit (*p2) ? -1 : diff; |
|
107 |
|
108 default: |
|
109 return state; |
|
110 } |
|
111 } |