+# Ruby implementation of glibc strverscmp-workalike, with some improvements.
+#
+# Copyright © 2021 Nick Bowler
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# This implementation is partially adapted from the GNU C Library, covered by
+# the following copyright and permission notice:
+#
+# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+module SVC
+ ZERO = "0".ord
+ NINE = "9".ord
+ A_UP = "A".ord
+ A_LO = "a".ord
+ Z_UP = "Z".ord
+ Z_LO = "z".ord
+ DOT = ".".ord
+
+ def SVC.my_ord(s)
+ s ? s.ord : 0
+ end
+
+ def SVC.isdigit(x)
+ return x >= ZERO && x <= NINE
+ end
+
+ def SVC.isdigitnz(x)
+ return x > ZERO && x <= NINE
+ end
+
+ def SVC.isalpha(x)
+ return x >= A_UP && x <= A_LO ||
+ x >= A_LO && x <= Z_LO
+ end
+
+ def SVC.rank(x, xs, i)
+ return 3 if isdigit(x)
+ return 2 if x == DOT and isdigit(my_ord(xs[i+1]))
+ return 1 if isalpha(x)
+ return 0
+ end
+end
+
+def strverscmp(as, bs)
+ state = :normal
+ i = 0
+
+ # locate first difference, tracking context
+ while true
+ a, b = SVC.my_ord(as[i]), SVC.my_ord(bs[i])
+
+ break if a == 0 or a != b
+ i = i+1
+
+ if a == SVC::ZERO
+ state = :zeroes if state == :normal or state == :dot
+ elsif a > SVC::ZERO and a <= SVC::NINE
+ state = :integral if state == :normal or state == :dot
+ state = :fractional if state == :zeroes
+ elsif a == SVC::DOT
+ state = :dot unless state == :normal
+ else
+ state = :normal
+ end
+ end
+
+ # found first differing character
+ diff = a - b
+
+ case state
+ when :fractional
+ return diff
+ when :normal
+ return diff unless SVC.isdigitnz(a) and SVC.isdigitnz(b)
+ when :zeroes
+ ra, rb = SVC.rank(a, as, i), SVC.rank(b, bs, i)
+
+ if ( cmp = ra <=> rb ) != 0
+ return cmp if a == SVC::DOT and SVC.isalpha(b)
+ return cmp if b == SVC::DOT and SVC.isalpha(a)
+ return -cmp
+ end
+
+ return diff
+ when :integral
+ ra, rb = SVC.rank(a, as, i), SVC.rank(b, bs, i)
+ return ra <=> rb if ra != rb
+ return diff unless SVC.isdigit(b)
+ end
+
+ while SVC.isdigit(a)
+ return 1 unless SVC.isdigit(b)
+ i = i + 1
+ a, b = SVC.my_ord(as[i]), SVC.my_ord(bs[i])
+ end
+
+ return -1 if SVC.isdigit(b)
+ return diff
+end