gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

versions.el v1.3


From: Vinicius Jose Latorre
Subject: versions.el v1.3
Date: Sun, 12 Jun 2005 20:37:51 -0300
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050511


;;; versions.el --- version string comparison

;; Copyright (C) 2005 Vinicius Jose Latorre

;; Author: Vinicius Jose Latorre <address@hidden>
;; Maintainer: Vinicius Jose Latorre <address@hidden>
;; Keywords: help, internal, maintenance, debug
;; Time-stamp: <2005/06/12 20:34:09 vinicius>
;; Version: 1.3
;; X-URL: http://www.cpqd.com.br/~vinicius/emacs/

;; This file is *NOT* (yet?) part of GNU Emacs.

;; 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 2, 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 GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Introduction
;; ------------
;;
;; This package provides routines to compare string version and to convert
;; string version into an integer list.
;;
;; versions was tested with GNU Emacs 22.0.50.1.
;;
;; I don't know if it is still compatible with XEmacs.
;;
;; It provides the following functions:
;;
;; `version-to-list'            convert a version string into an integer list.
;;
;; `integer-list-<'             return t if integer list L1 is lesser than L2.
;;
;; `integer-list-='             return t if integer list L1 is equal to L2.
;;
;; `integer-list-<='            return t if integer list L1 is lesser than or
;;                              equal to L2.
;;
;; `version='                   return t if version V1 is equal to V2.
;;
;; `version<'                   return t if version V1 is less than V2.
;;
;; `version<='                  return t if version V1 is less than or equal to
;;                              V2.
;;
;;
;; Usage
;; -----
;;
;; To use versions, insert in your Emacs Lisp code:
;;
;;    (require 'versions)
;;
;; So, you can compare versions in Emacs Lisp code like:
;;
;;    (and (version< other-version "6.6pre4")
;;         (error "`my-pack' requires `other' package v6.6pre4 or later"))
;;
;;
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; code:


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; User variables


(defgroup version nil
  "Version group"
  :link '(emacs-library-link :tag "Source Lisp File" "ver.el")
  :prefix "version-"
  :group 'internal
  :group 'maintenance
  :group 'debug)


(defcustom version-separator "."
  "*Specify the string used to separate the version elements.

Usually the separator is \".\", but it can be any other string."
  :type '(string :tag "Version Separator")
  :group 'version)


(defcustom version-regexp-alist
  '(("^a\\(lpha\\)?$" . -3)
    ("^b\\(eta\\)?$"  . -2)
    ("^pre\\|rc$"     . -1))
  "*Specify association between non-numeric version part and a priority.

This association is used to handle version string like \"1.0pre2\",
\"0.9alpha1\", etc.  It's used by `version-to-list' (which see) to convert the
non-numeric part to an integer.  For example:

   ORIGINAL VERSION     VERSION CONVERTED
   1.0pre2              1.0.-1.2
   1.0PRE2              1.0.-1.2
   22.8beta3            22.8.-2.3
   22.8Beta3            22.8.-2.3
   0.9alpha1            0.9.-3.1
   0.9AlphA1            0.9.-3.1

Each element has the following form:

   (REGEXP . PRIORITY)

Where:

REGEXP          regexp used to match non-numeric part of a version string.

PRIORITY        negative integer which indicate the non-numeric priority."
  :type '(repeat :tag "Version Regexp Alist"
                 (cons :tag ""
                       (string :tag "Version Regexp")
                       (integer :tag "Version Priority")))
  :group 'version)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions


(defun version-to-list (ver)
  "Convert version string VER into an integer list.

The version syntax is given by the following EBNF:

   VERSION ::= NUMBER ( SEPARATOR NUMBER )*.

   NUMBER ::= (0|1|2|3|4|5|6|7|8|9)+.

   SEPARATOR ::= `version-separator' (which see)
               | `version-regexp-alist' (which see).

As an example of valid version syntax:

   1.0pre2   1.0.7.5   22.8beta3   0.9alpha1

As an example of invalid version syntax:

   1.0prepre2   1.0..7.5   22.8X3   alpha3.2   .5

As an example of version convertion:

   ORIGINAL VERSION     VERSION CONVERTED
   \"1.0.7.5\"            (1 0 7 5)
   \"1.0pre2\"            (1 0 -1 2)
   \"1.0PRE2\"            (1 0 -1 2)
   \"22.8beta3\"          (22 8 -2 3)
   \"22.8Beta3\"          (22 8 -2 3)
   \"0.9alpha1\"          (0 9 -3 1)
   \"0.9AlphA1\"          (0 9 -3 1)
   \"0.9alpha\"           (0 9 -3)
"
  (or (and (stringp ver) (not (string= ver "")))
      (error "Invalid version string: '%s'" ver))
  (save-match-data
    (let ((i 0)
          case-fold-search              ; ignore case in matching
          lst s al)
      (while (and (setq s (string-match "[0-9]+" ver i))
                  (= s i))
        ;; handle numeric part
        (setq lst (cons (string-to-number (substring ver i (match-end 0)))
                        lst)
              i   (match-end 0))
        ;; handle non-numeric part
        (when (and (setq s (string-match "[^0-9]+" ver i))
                   (= s i))
          (setq s (substring ver i (match-end 0))
                i (match-end 0))
          ;; handle alpha, beta, pre, etc. separator
          (unless (string= s version-separator)
            (setq al version-regexp-alist)
            (while (and al (not (string-match (caar al) s)))
              (setq al (cdr al)))
            (or al (error "Invalid version syntax: '%s'" ver))
            (setq lst (cons (cdar al) lst)))))
      (if (null lst)
          (error "Invalid version syntax: '%s'" ver)
        (nreverse lst)))))


(defun integer-list-< (l1 l2)
  "Return t if integer list L1 is lesser than L2.

Note that integer list (1) is equal to (1 0), (1 0 0), (1 0 0 0),
etc.  That is, the trailing zeroes are irrelevant.  Also, integer
list (1) is greater than (1 -1) which is greater than (1 -2)
which is greater than (1 -3)."
  (if (and (null l1) (null l2))
      nil
    (while (and l1 l2 (< (car l1) (car l2)))
      (setq l1 (cdr l1)
            l2 (cdr l2)))
    (cond
     ;; l1 null and l2 null     ==> l1 length = l2 length
     ((and (null l1) (null l2)))
     ;; l1 not null and l2 null ==> l1 length > l2 length
     (l1 (< (integer-list-not-zero l1) 0))
     ;; l1 null and l2 not null ==> l2 length > l1 length
     (t  (< 0 (integer-list-not-zero l2))))))


(defun integer-list-= (l1 l2)
  "Return t if integer list L1 is equal to L2.

Note that integer list (1) is equal to (1 0), (1 0 0), (1 0 0 0),
etc.  That is, the trailing zeroes are irrelevant.  Also, integer
list (1) is greater than (1 -1) which is greater than (1 -2)
which is greater than (1 -3)."
  (while (and l1 l2 (= (car l1) (car l2)))
    (setq l1 (cdr l1)
          l2 (cdr l2)))
  (cond
   ;; l1 null and l2 null     ==> l1 length = l2 length
   ((and (null l1) (null l2)))
   ;; l1 not null and l2 null ==> l1 length > l2 length
   (l1 (zerop (integer-list-not-zero l1)))
   ;; l1 null and l2 not null ==> l2 length > l1 length
   (t  (zerop (integer-list-not-zero l2)))))


(defun integer-list-<= (l1 l2)
  "Return t if integer list L1 is lesser than or equal to L2.

Note that integer list (1) is equal to (1 0), (1 0 0), (1 0 0 0),
etc.  That is, the trailing zeroes are irrelevant.  Also, integer
list (1) is greater than (1 -1) which is greater than (1 -2)
which is greater than (1 -3)."
  (while (and l1 l2 (<= (car l1) (car l2)))
    (setq l1 (cdr l1)
          l2 (cdr l2)))
  (cond
   ;; l1 null and l2 null     ==> l1 length = l2 length
   ((and (null l1) (null l2)))
   ;; l1 not null and l2 null ==> l1 length > l2 length
   (l1 (<= (integer-list-not-zero l1) 0))
   ;; l1 null and l2 not null ==> l2 length > l1 length
   (t  (<= 0 (integer-list-not-zero l2)))))


(defun version= (v1 v2)
  "Return t if version V1 is equal to V2.

Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\",
etc.  That is, the trailing \".0\"s are irrelevant.  Also, version string \"1\"
is greater than \"1pre\" which is greater than \"1beta\" which is greater than
\"1alpha\"."
  (interger-list-= (version-to-list v1) (version-to-list v2)))


(defun version< (v1 v2)
  "Return t if version V1 is lesser than V2.

Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\",
etc.  That is, the trailing \".0\"s are irrelevant.  Also, version string \"1\"
is greater than \"1pre\" which is greater than \"1beta\" which is greater than
\"1alpha\"."
  (interger-list-< (version-to-list v1) (version-to-list v2)))


(defun version<= (v1 v2)
  "Return t if version V1 is lesser than or equal to V2.

Note that version string \"1\" is equal to \"1.0\", \"1.0.0\", \"1.0.0.0\",
etc.  That is, the trailing \".0\"s are irrelevant.  Also, version string \"1\"
is greater than \"1pre\" which is greater than \"1beta\" which is greater than
\"1alpha\"."
  (interger-list-<= (version-to-list v1) (version-to-list v2)))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal functions


(defun integer-list-not-zero (lst)
  "Return the first non-zero element; otherwise, return zero."
  (while (and lst (zerop (car lst)))
    (setq lst (cdr lst)))
  (if lst
      (car lst)
    ;; there is no element different of zero
    0))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


(provide 'versions)


;;; versions.el ends here

reply via email to

[Prev in Thread] Current Thread [Next in Thread]