2 #include "string-list.h"
5 * versioncmp(): copied from string/strverscmp.c in glibc commit
6 * ee9247c38a8def24a59eb5cfb7196a98bef8cfdc, reformatted to Git coding
7 * style. The implementation is under LGPL-2.1 and Git relicenses it
12 * states: S_N: normal, S_I: comparing integral part, S_F: comparing
13 * fractionnal parts, S_Z: idem but with leading Zeroes only
20 /* result_type: CMP: return diff; LEN: compare using len_diff/diff */
24 static const struct string_list
*prereleases
;
25 static int initialized
;
28 * p1 and p2 point to the first different character in two strings. If
29 * either p1 or p2 starts with a prerelease suffix, it will be forced
32 * If both p1 and p2 start with (different) suffix, the order is
33 * determined by config file.
35 * Note that we don't have to deal with the situation when both p1 and
36 * p2 start with the same suffix because the common part is already
37 * consumed by the caller.
39 * Return non-zero if *diff contains the return value for versioncmp()
41 static int swap_prereleases(const void *p1_
,
47 int i
, i1
= -1, i2
= -1;
49 for (i
= 0; i
< prereleases
->nr
; i
++) {
50 const char *suffix
= prereleases
->items
[i
].string
;
51 if (i1
== -1 && starts_with(p1
, suffix
))
53 if (i2
== -1 && starts_with(p2
, suffix
))
56 if (i1
== -1 && i2
== -1)
58 if (i1
>= 0 && i2
>= 0)
62 else /* if (i2 >= 0) */
68 * Compare S1 and S2 as strings holding indices/version numbers,
69 * returning less than, equal to or greater than zero if S1 is less
70 * than, equal to or greater than S2 (for more info, see the texinfo
74 int versioncmp(const char *s1
, const char *s2
)
76 const unsigned char *p1
= (const unsigned char *) s1
;
77 const unsigned char *p2
= (const unsigned char *) s2
;
82 * Symbol(s) 0 [1-9] others
83 * Transition (10) 0 (01) d (00) x
85 static const uint8_t next_state
[] = {
87 /* S_N */ S_N
, S_I
, S_Z
,
88 /* S_I */ S_N
, S_I
, S_I
,
89 /* S_F */ S_N
, S_F
, S_F
,
90 /* S_Z */ S_N
, S_F
, S_Z
93 static const int8_t result_type
[] = {
94 /* state x/x x/d x/0 d/x d/d d/0 0/x 0/d 0/0 */
96 /* S_N */ CMP
, CMP
, CMP
, CMP
, LEN
, CMP
, CMP
, CMP
, CMP
,
97 /* S_I */ CMP
, -1, -1, +1, LEN
, LEN
, +1, LEN
, LEN
,
98 /* S_F */ CMP
, CMP
, CMP
, CMP
, CMP
, CMP
, CMP
, CMP
, CMP
,
99 /* S_Z */ CMP
, +1, +1, -1, CMP
, CMP
, -1, CMP
, CMP
107 /* Hint: '0' is a digit too. */
108 state
= S_N
+ ((c1
== '0') + (isdigit (c1
) != 0));
110 while ((diff
= c1
- c2
) == 0) {
114 state
= next_state
[state
];
117 state
+= (c1
== '0') + (isdigit (c1
) != 0);
122 prereleases
= git_config_get_value_multi("versionsort.prereleasesuffix");
124 if (prereleases
&& swap_prereleases(p1
- 1, p2
- 1, &diff
))
127 state
= result_type
[state
* 3 + (((c2
== '0') + (isdigit (c2
) != 0)))];
134 while (isdigit (*p1
++))
135 if (!isdigit (*p2
++))
138 return isdigit (*p2
) ? -1 : diff
;