version.el v1.0

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

version.el v1.0

Vinicius Jose Latorre
;;; version.el --- version string comparison

;; Copyright (C) 2005 Vinicius Jose Latorre

;; Author:    Vinicius Jose Latorre <[hidden email]>
;; Maintainer:    Vinicius Jose Latorre <[hidden email]>
;; Keywords:    help, internal, maintenance, debug
;; Time-stamp:    <2005/06/05 13:49:36 vinicius>
;; Version:    1.0
;; X-URL:

;; 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
;; 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 to an integer list.
;; version was tested with GNU Emacs
;; I don't know if still is compatible with XEmacs.
;; Usage
;; -----
;; To use version, insert in your Emacs Lisp code:
;;        (require 'version)
;; So, you can compare versions in Emacs Lisp code like:
;; (and (< (version-compare other-version "6.6pre4") 0)
;;      (error "`my-pack' requires `other' package version 6.6pre4 or
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; code:

;; User variables

(defgroup version nil
  "Version group"
  :link '(emacs-library-link :tag "Source Lisp File" "version.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 any other string."
  :type '(string :tag "Version Separator")
  :group 'version)

(defcustom version-regexp-alist
  '(("^a\\(lpha\\)?$" . 0)
    ("^b\\(eta\\)?$"  . 1)
    ("^pre\\|rc$"     . 2))
  "*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:


Each element has the following form:



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

PRIORITY    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:


   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   22.8beta3   0.9alpha1

As an example of invalid version syntax:

   1.0prepre2   1.0..7.5   22.8X3

As an example of version convertion:

   \"\"            (1 0 7 5)
   \"1.0pre2\"            (1 0 2 2)
   \"1.0PRE2\"            (1 0 2 2)
   \"22.8beta3\"          (22 8 1 3)
   \"22.8Beta3\"          (22 8 1 3)
   \"0.9alpha1\"          (0 9 0 1)
   \"0.9AlphA1\"          (0 9 0 1)
   \"0.9alpha\"           (0 9 0)
  (or (and (stringp ver) (not (string= ver "")))
      (error "Invalid version syntax: '%s'" ver))
    (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)))
          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 version-compare (v1 v2)
  "Compare version string V1 with V2.

If V1 = V2, return 0.
If V1 > V2, return 1.
If V1 < V2, return -1.
It is an error if V1 or V2 is not a valid string version.

It uses `version-to-list' (which see)."
  (let ((l1 (version-to-string v1))
    (l2 (version-to-string v2))
    (r  0)
    e1 e2)
    (while (and (= r 0) l1 l2)
      (setq e1 (car l1)
        e2 (car l2)
        l1 (cdr l1)
        l2 (cdr l2)
        r  (cond ((= e1 e2) 0)
             ((> e1 e2) 1)
             (t         -1))))
    (cond ((or (/= r 0) (and (null l1) (null l2)))
      ;; r = 0 and l1 not null and l2 null ==> l1 length > l2 length
      (l1 1)
      ;; r = 0 and l1 null and l2 not null ==> l2 length > l1 length
      (t  -1))))


(provide 'version)

;;; version.el ends here

Gnu-emacs-sources mailing list
[hidden email]