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