1 | /* |
---|
2 | FUNCTION |
---|
3 | <<strverscmp>>---version string compare |
---|
4 | |
---|
5 | INDEX |
---|
6 | strverscmp |
---|
7 | |
---|
8 | SYNOPSIS |
---|
9 | #define _GNU_SOURCE |
---|
10 | #include <string.h> |
---|
11 | int strverscmp(const char *<[a]>, const char *<[b]>); |
---|
12 | |
---|
13 | DESCRIPTION |
---|
14 | <<strverscmp>> compares the string at <[a]> to |
---|
15 | the string at <[b]> in a version-logical order. |
---|
16 | |
---|
17 | RETURNS |
---|
18 | |
---|
19 | If <<*<[a]>>> version-sorts after <<*<[b]>>>, <<strverscmp>> returns |
---|
20 | a number greater than zero. If the two strings match, <<strverscmp>> |
---|
21 | returns zero. If <<*<[a]>>> version-sorts before <<*<[b]>>>, |
---|
22 | <<strverscmp>> returns a number less than zero. |
---|
23 | |
---|
24 | PORTABILITY |
---|
25 | <<strverscmp>> is a GNU extension. |
---|
26 | |
---|
27 | <<strverscmp>> requires no supporting OS subroutines. It uses |
---|
28 | isdigit() from elsewhere in this library. |
---|
29 | |
---|
30 | QUICKREF |
---|
31 | strverscmp |
---|
32 | */ |
---|
33 | |
---|
34 | /* |
---|
35 | From musl src/string/strverscmp.c |
---|
36 | |
---|
37 | Copyright © 2005-2014 Rich Felker, et al. |
---|
38 | |
---|
39 | Permission is hereby granted, free of charge, to any person obtaining |
---|
40 | a copy of this software and associated documentation files (the |
---|
41 | "Software"), to deal in the Software without restriction, including |
---|
42 | without limitation the rights to use, copy, modify, merge, publish, |
---|
43 | distribute, sublicense, and/or sell copies of the Software, and to |
---|
44 | permit persons to whom the Software is furnished to do so, subject to |
---|
45 | the following conditions: |
---|
46 | |
---|
47 | The above copyright notice and this permission notice shall be |
---|
48 | included in all copies or substantial portions of the Software. |
---|
49 | |
---|
50 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
51 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
---|
52 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
---|
53 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
---|
54 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
---|
55 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
---|
56 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
---|
57 | */ |
---|
58 | |
---|
59 | #define _GNU_SOURCE |
---|
60 | #include <ctype.h> |
---|
61 | #include <string.h> |
---|
62 | |
---|
63 | int strverscmp(const char *l0, const char *r0) |
---|
64 | { |
---|
65 | const unsigned char *l = (const void *)l0; |
---|
66 | const unsigned char *r = (const void *)r0; |
---|
67 | size_t i, dp, j; |
---|
68 | int z = 1; |
---|
69 | |
---|
70 | /* Find maximal matching prefix and track its maximal digit |
---|
71 | * suffix and whether those digits are all zeros. */ |
---|
72 | for (dp=i=0; l[i]==r[i]; i++) { |
---|
73 | int c = l[i]; |
---|
74 | if (!c) return 0; |
---|
75 | if (!isdigit(c)) dp=i+1, z=1; |
---|
76 | else if (c!='0') z=0; |
---|
77 | } |
---|
78 | |
---|
79 | if (l[dp]!='0' && r[dp]!='0') { |
---|
80 | /* If we're not looking at a digit sequence that began |
---|
81 | * with a zero, longest digit string is greater. */ |
---|
82 | for (j=i; isdigit(l[j]); j++) |
---|
83 | if (!isdigit(r[j])) return 1; |
---|
84 | if (isdigit(r[j])) return -1; |
---|
85 | } else if (z && dp<i && (isdigit(l[i]) || isdigit(r[i]))) { |
---|
86 | /* Otherwise, if common prefix of digit sequence is |
---|
87 | * all zeros, digits order less than non-digits. */ |
---|
88 | return (unsigned char)(l[i]-'0') - (unsigned char)(r[i]-'0'); |
---|
89 | } |
---|
90 | |
---|
91 | return l[i] - r[i]; |
---|
92 | } |
---|