This source file includes following definitions.
- file_prefixlen
- order
- verrevcmp
- filevercmp
- filenvercmp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21 #include "filevercmp.h"
22
23 #include <c-ctype.h>
24 #include <limits.h>
25 #include <idx.h>
26
27
28
29
30
31
32
33
34
35 static idx_t
36 file_prefixlen (char const *s, ptrdiff_t *len)
37 {
38 size_t n = *len;
39 idx_t prefixlen = 0;
40
41 for (idx_t i = 0; ; )
42 {
43 if (*len < 0 ? !s[i] : i == n)
44 {
45 *len = i;
46 return prefixlen;
47 }
48
49 i++;
50 prefixlen = i;
51 while (i + 1 < n && s[i] == '.' && (c_isalpha (s[i + 1])
52 || s[i + 1] == '~'))
53 for (i += 2; i < n && (c_isalnum (s[i]) || s[i] == '~'); i++)
54 continue;
55 }
56 }
57
58
59
60
61 static int
62 order (char const *s, idx_t pos, idx_t len)
63 {
64 if (pos == len)
65 return -1;
66
67 unsigned char c = s[pos];
68 if (c_isdigit (c))
69 return 0;
70 else if (c_isalpha (c))
71 return c;
72 else if (c == '~')
73 return -2;
74 else
75 {
76 static_assert (UCHAR_MAX <= (INT_MAX - 1 - 2) / 2);
77 return c + UCHAR_MAX + 1;
78 }
79 }
80
81
82
83
84
85
86
87
88
89
90
91 static int _GL_ATTRIBUTE_PURE
92 verrevcmp (const char *s1, idx_t s1_len, const char *s2, idx_t s2_len)
93 {
94 idx_t s1_pos = 0;
95 idx_t s2_pos = 0;
96 while (s1_pos < s1_len || s2_pos < s2_len)
97 {
98 int first_diff = 0;
99 while ((s1_pos < s1_len && !c_isdigit (s1[s1_pos]))
100 || (s2_pos < s2_len && !c_isdigit (s2[s2_pos])))
101 {
102 int s1_c = order (s1, s1_pos, s1_len);
103 int s2_c = order (s2, s2_pos, s2_len);
104 if (s1_c != s2_c)
105 return s1_c - s2_c;
106 s1_pos++;
107 s2_pos++;
108 }
109 while (s1_pos < s1_len && s1[s1_pos] == '0')
110 s1_pos++;
111 while (s2_pos < s2_len && s2[s2_pos] == '0')
112 s2_pos++;
113 while (s1_pos < s1_len && s2_pos < s2_len
114 && c_isdigit (s1[s1_pos]) && c_isdigit (s2[s2_pos]))
115 {
116 if (!first_diff)
117 first_diff = s1[s1_pos] - s2[s2_pos];
118 s1_pos++;
119 s2_pos++;
120 }
121 if (s1_pos < s1_len && c_isdigit (s1[s1_pos]))
122 return 1;
123 if (s2_pos < s2_len && c_isdigit (s2[s2_pos]))
124 return -1;
125 if (first_diff)
126 return first_diff;
127 }
128 return 0;
129 }
130
131
132
133 int
134 filevercmp (const char *s1, const char *s2)
135 {
136 return filenvercmp (s1, -1, s2, -1);
137 }
138
139
140
141 int
142 filenvercmp (char const *a, ptrdiff_t alen, char const *b, ptrdiff_t blen)
143 {
144
145 bool aempty = alen < 0 ? !a[0] : !alen;
146 bool bempty = blen < 0 ? !b[0] : !blen;
147 if (aempty)
148 return -!bempty;
149 if (bempty)
150 return 1;
151
152
153
154 if (a[0] == '.')
155 {
156 if (b[0] != '.')
157 return -1;
158
159 bool adot = alen < 0 ? !a[1] : alen == 1;
160 bool bdot = blen < 0 ? !b[1] : blen == 1;
161 if (adot)
162 return -!bdot;
163 if (bdot)
164 return 1;
165
166 bool adotdot = a[1] == '.' && (alen < 0 ? !a[2] : alen == 2);
167 bool bdotdot = b[1] == '.' && (blen < 0 ? !b[2] : blen == 2);
168 if (adotdot)
169 return -!bdotdot;
170 if (bdotdot)
171 return 1;
172 }
173 else if (b[0] == '.')
174 return 1;
175
176
177 idx_t aprefixlen = file_prefixlen (a, &alen);
178 idx_t bprefixlen = file_prefixlen (b, &blen);
179
180
181 bool one_pass_only = aprefixlen == alen && bprefixlen == blen;
182
183 int result = verrevcmp (a, aprefixlen, b, bprefixlen);
184
185
186
187 return result || one_pass_only ? result : verrevcmp (a, alen, b, blen);
188 }