[444] | 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 | } |
---|