]>
Commit | Line | Data |
---|---|---|
1f205a47 | 1 | /* Compare strings while treating digits characters numerically. |
d614a753 | 2 | Copyright (C) 1997-2020 Free Software Foundation, Inc. |
1f205a47 | 3 | This file is part of the GNU C Library. |
e6855a3b | 4 | Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997. |
1f205a47 UD |
5 | |
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
1f205a47 UD |
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 | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
1f205a47 | 15 | |
41bdb6e2 | 16 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 17 | License along with the GNU C Library; if not, see |
5a82c748 | 18 | <https://www.gnu.org/licenses/>. */ |
1f205a47 | 19 | |
45466462 | 20 | #include <stdint.h> |
1f205a47 UD |
21 | #include <string.h> |
22 | #include <ctype.h> | |
23 | ||
24 | /* states: S_N: normal, S_I: comparing integral part, S_F: comparing | |
bfbc5754 | 25 | fractionnal parts, S_Z: idem but with leading Zeroes only */ |
1f205a47 | 26 | #define S_N 0x0 |
45466462 UD |
27 | #define S_I 0x3 |
28 | #define S_F 0x6 | |
29 | #define S_Z 0x9 | |
1f205a47 UD |
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 | |
9d46370c | 42 | __strverscmp (const char *s1, const char *s2) |
1f205a47 UD |
43 | { |
44 | const unsigned char *p1 = (const unsigned char *) s1; | |
45 | const unsigned char *p2 = (const unsigned char *) s2; | |
1f205a47 | 46 | |
45466462 UD |
47 | /* Symbol(s) 0 [1-9] others |
48 | Transition (10) 0 (01) d (00) x */ | |
49 | static const uint8_t next_state[] = | |
1f205a47 | 50 | { |
45466462 UD |
51 | /* state x d 0 */ |
52 | /* S_N */ S_N, S_I, S_Z, | |
53 | /* S_I */ S_N, S_I, S_I, | |
54 | /* S_F */ S_N, S_F, S_F, | |
55 | /* S_Z */ S_N, S_F, S_Z | |
1f205a47 UD |
56 | }; |
57 | ||
45466462 | 58 | static const int8_t result_type[] = |
1f205a47 | 59 | { |
45466462 UD |
60 | /* state x/x x/d x/0 d/x d/d d/0 0/x 0/d 0/0 */ |
61 | ||
62 | /* S_N */ CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, | |
63 | /* S_I */ CMP, -1, -1, +1, LEN, LEN, +1, LEN, LEN, | |
64 | /* S_F */ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, | |
65 | /* S_Z */ CMP, +1, +1, -1, CMP, CMP, -1, CMP, CMP | |
1f205a47 UD |
66 | }; |
67 | ||
68 | if (p1 == p2) | |
69 | return 0; | |
70 | ||
45466462 UD |
71 | unsigned char c1 = *p1++; |
72 | unsigned char c2 = *p2++; | |
1f205a47 | 73 | /* Hint: '0' is a digit too. */ |
4bcb2658 | 74 | int state = S_N + ((c1 == '0') + (isdigit (c1) != 0)); |
1f205a47 | 75 | |
45466462 UD |
76 | int diff; |
77 | while ((diff = c1 - c2) == 0) | |
1f205a47 | 78 | { |
45466462 UD |
79 | if (c1 == '\0') |
80 | return diff; | |
81 | ||
1f205a47 UD |
82 | state = next_state[state]; |
83 | c1 = *p1++; | |
84 | c2 = *p2++; | |
4bcb2658 | 85 | state += (c1 == '0') + (isdigit (c1) != 0); |
1f205a47 UD |
86 | } |
87 | ||
4bcb2658 | 88 | state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))]; |
1f205a47 UD |
89 | |
90 | switch (state) | |
91 | { | |
92 | case CMP: | |
93 | return diff; | |
94 | ||
95 | case LEN: | |
96 | while (isdigit (*p1++)) | |
97 | if (!isdigit (*p2++)) | |
98 | return 1; | |
99 | ||
100 | return isdigit (*p2) ? -1 : diff; | |
101 | ||
102 | default: | |
103 | return state; | |
104 | } | |
105 | } | |
a20d8dbe | 106 | libc_hidden_def (__strverscmp) |
cbdee279 | 107 | weak_alias (__strverscmp, strverscmp) |