~skin/zippm

e678a8994d4deb3c66418cb5d019fe61ea4fdaff — Daniel Jay Haskin 7 months ago 389bfed
Still in rough draft mode
3 files changed, 59 insertions(+), 75 deletions(-)

M src/version.lisp
M tests/version.lisp
M zippm.asd
M src/version.lisp => src/version.lisp +51 -69
@@ 1,76 1,51 @@
;; A
(defpackage #:skin.djha.zippm/version
  (:use :cl)
  (:import-from #:uiop)
  (:import-from #:alexandria)
  (:documentation
    "A straight implementation in common lisp of the Debian Version Comparison Algorithm."))
    "Version comparison for zippm"))

(in-package #:skin.djha.zippm/version)

(defun justify
    (seq len &key make-array-args)
    "Return a vector of the given length, with the given sequence justified to
     the left."
  (let ((justified (apply #'make-array
                          (concatenate 'list
                                       (list len)
                                       make-array-args))))
    (replace justified seq :start1 0 :end1 (min len
                                                (length seq)))
    justified))

(defun rectify
    (a b &rest make-array-args)
  "Return two sequences of the same length, with the shorter one justified to
  the left."
  (let ((la (length a))
        (lb (length b))
        (maxlength (max la lb))
        (ja (if (= maxlength la) a (justify a
                                            maxlength
                                            :make-array-args
                                            make-array-args)))
        (jb (if (= maxlength lb) b (justify b maxlength
                                            :make-array-args
                                            make-array-args))))
    (values maxlength ja jb)))

(defparameter *nullc* (code-char 0))
(defparameter *trumpc* #\-)
(defparameter *fillerc* #\Space)

(defun nonnumeric-part-compare
    (a b)
  (if (string= a b)
      0
      (multiple-value-bind
          (maxlength ja jb)
          (rectify a b
                   :element-type 'char
                   :initial-element *nullc*)
        (loop for i from 0 below maxlength
              for a = (elt ja i)
              for b = (elt jb i)
              do
              (let ((diff
                      (cond ((char= a b) 0)
                            ((char= a #\~) -1)
                            ((char= b #\~) 1)
                            ((char= a *nullc*) -1)
                            ((char= b *nullc*) 1)
                            ((and (alpha-char-p a)
                                  (not (alpha-char-p b))) -1)
                            ((and (alpha-char-p b)
                                  (not (alpha-char-p a))) 1)
                            (:else
                             (- (char-code a) (char-code b))))))
                (when (not (zerop diff))
                  (return diff)))
              finally (return 0)))))
  "
  Compare two version parts which both consist entirely of
  non-digits (or are empty).
  "
  (declare (type string a b))
  (loop with maxlength = (max (length a) (length b))
        for i from 0 below maxlength
        for ca = (if (< i (length a))
                     (elt a i)
                     *fillerc*)
        for cb = (if (< i (length b))
                     (elt b i)
                     *fillerc*)
        do
        (let ((diff
                (cond ((char= ca cb) 0)
                      ((char= ca *trumpc*) -1)
                      ((char= cb *trumpc*) 1)
                      ((and (alpha-char-p a)
                            (not (alpha-char-p b))) -1)
                      ((and (alpha-char-p b)
                            (not (alpha-char-p a))) 1)
                      (:else
                       (- (char-code a) (char-code b))))))
          (when (not (zerop diff))
            (return diff)))
        finally (return 0)))

(defun numeric-part-compare
  (a b)
  "Compares two version parts, which both consist
  entirely of digits."
    (a b)
  "
  Compares two version parts, which both consist
  entirely of digits (or are empty).
  "
  (declare (type string a b))
  (let ((trimmed-a (string-left-trim '(#\0) a))
        (trimmed-b (string-left-trim '(#\0) b))


@@ 102,6 77,11 @@
  "
  (declare (type string version))
  (loop
    with parts = (make-array 10
                             :element-type 'string
                             :initial-element ""
                             :adjustable t
                             :fill-pointer 0)
    for i = 0 then (1+ i)
    for check = (if (zerop (mod i 2))
                    #'digit-char-p


@@ 111,7 91,9 @@
                         (position-if check scratch)
                         (length scratch))
    while (not (zerop (length scratch)))
    collect (subseq scratch 0 next-checked)))
    do
    (vector-push-extend (subseq scratch 0 next-checked) parts)
    finally (return parts)))

(defun epochless-vercmp (a b)
  "


@@ 122,14 104,14 @@
      0
      (let ((split-a (version-parts-split a))
            (split-b (version-parts-split b)))
        (multiple-value-bind
            (maxlength ja jb)
            (rectify split-a split-b
                     :element-type 'string
                     :initial-element "")
          (loop for i = 0 then (1+ i)
                for a across ja
                for b across jb
          (loop with maxlength = (max (length split-a) (length split-b))
                for i = 0 below maxlength
                for a = (if (< i (length split-a))
                            (elt split-a i)
                            "")
                for b = (if (< i (length split-b))
                            (elt split-b i)
                            "")
                for cmp = (version-part-compare i a b)
                while (zerop cmp)
                finally (return cmp))))))

M tests/version.lisp => tests/version.lisp +4 -4
@@ 1,8 1,8 @@
(defpackage #:zippm/tests/version
(defpackage #:skin.djha.zippm/tests/version
  (:use #:cl
        #:skin.djha.zippm/version
        #:rove))
(in-package #:zippm/tests/version)
        #:rove)
  (:import-from #:skin.djha.zippm/version))
(in-package #:skin.djha.zippm/tests/version)

;; NOTE: To run this test file, execute `(asdf:test-system :zippm)' in your Lisp.
+(or)

M zippm.asd => zippm.asd +4 -2
@@ 8,7 8,8 @@
  )
  :components ((:module "src"
                :components
                ((:file "main"))))
                ((:file "main")
                 (:file "version"))))
  :description ""
  :in-order-to ((test-op (test-op "zippm/tests"))))



@@ 20,6 21,7 @@
               "rove")
  :components ((:module "tests"
                :components
                ((:file "main"))))
                ((:file "main")
                 (:file "version"))))
  :description "Test system for zippm"
  :perform (test-op (op c) (symbol-call :rove :run c)))