From maintainers-request at octave dot org Fri Mar 24 10:41:47 2006 Subject: Re: comparing version numbers From: David Bateman To: =?UTF-8?B?77+9IEhhdWJlcmc=?= Cc: "John W. Eaton" , octave maintainers mailing list Date: Fri, 24 Mar 2006 17:37:15 +0100 Søren Hauberg wrote: >tor, 23 03 2006 kl. 23:34 +0100, skrev Søren Hauberg: > > >>tor, 23 03 2006 kl. 17:22 -0500, skrev John W. Eaton: >> >> >>>If there is a need to compare version numbers, then perhaps we should >>>have a function to do it that can handle things like 2.9.5+ or >>>2.9.5+SVN-serial-number (or similar). >>> >>> >>There is a function for comparing version numbers in the package system I >>sent you a while back. I don't think it supports anything else than numbers, >>but it might provide a starting base. (I don't have the source in front >>of me, so I can't say what should be changed) >> >> >Okay, so I found the source and modified it a bit to make the function a bit >more general than what was needed in the package system. The attached function >supports version strings such as 2.9.5-Whatever. > >Two things should be noted: > 1) It acts like strcmp in C, i.e it returns -1 if the first version >string is "smaller" than the second, 0 if they are "equal", and 1 >otherwise. I say "equal" (and "smaller") because 2.6 == 2.6.0 > 2) The function doesn't work :-) >I need to be able to compare strings like I can in C using strcmp. Is >there an easy way to do this? > > Why not use something like text = !strcmp (text1, text2); if (text) texts = sort([text1;text2]); if (strcmp(deblank(texts[1,:]),text1) text = -1; else text = 1; endif endif Though I believe you must be careful with the strsort function of octave-forge which dispatches to sort. The fact is the 2.9.x sort function treats strings correctly and strsort.m should probably therefore be dropped. D. >/Søren > > >------------------------------------------------------------------------ > >## Copyright (C) 2006 Søren Hauberg >## >## 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 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, write to the Free Software >## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > >## -*- texinfo -*- >## at deftypefn {Function File} {} compare_version (@var{v1}, @var{v2}) >## Compares two version strings, returning 0 if they are equal, 1 if >## at var{v1} is larger (i.e. more recent) than @var{v2}, and -1 otherwise. >## >## A version string is a string that describes the version of a piece of >## software. This function supports the most common type of version strings >## found in Free Software, i.e. "Major.Minor.Revision-Text". In this format >## Minor, Revision and Text are optional, but for clarity it is recommended >## to at least provide Minor and Revision. If Minor or Revision is not >## given, they default to 0, while Text defaults to the empty string. Hence >## the following is true, >## at example >## 2.6 == 2.6.0 < 2.6.0-SVN < 2.6.1 >## at end example >## at end deftypefn > >function [ ret ] = compare_version (v1, v2) > ## Both arguments must be strings > if (!ischar(v1) || !ischar(v2)) > error("compare_version: Both input arguments must be strings."); > endif > > ## Split the strings into parts X.Y.Z-TEXT > [major1, minor1, rev1, text1] = get_parts(v1); > [major2, minor2, rev2, text2] = get_parts(v2); > > ## Gentleman, start your comparing... > major = sign(major1 - major2); > minor = sign(minor1 - minor2); > rev = sign(rev1 - rev2); > text = !strcmp(text1, text2); % XXX: This is just plain wrong! (But it'll have to do for now!) > > if (major != 0) > ret = major; > elseif (minor != 0) > ret = minor; > elseif (rev != 0) > ret = rev; > else > ret = text; > endif >endfunction > >## Splits a version string into Major.Minor.Revision-Text. >## Minor and Revision defaults to 0 ,while Text defaults to the empty string. >function [major, minor, revision, text] = get_parts(v) > ## Default values > minor = revision = 0; > text = ""; > > ## Get text > dash = find(v == "-"); > if (length(dash) > 0) > text = v(dash(1)+1:end); > v = v(1:dash(1)-1); > endif > > ## Get major, minor, and revision > dots = [find(v == "."), length(v)+1]; > major = str2num( v(1:dots(1)-1) ); > if (length(dots) >= 2) > minor = str2num( v( dots(1)+1:dots(2)-1 ) ); > endif > if (length(dots) >= 3) > revision = str2num( v( dots(2)+1:dots(3)-1 ) ); > endif > > ## Is everything okay? > if ( isempty(major) || isempty(minor) || isempty(revision) ) > error("Input argument is not a valid version string."); > endif >endfunction > >%!test >%! if (compare_version("2.6.1", "2.6.0") != 1) >%! error("Test 1"); >%! endif > >%!test >%! if (compare_version("2.6", "2.6.0") != 0) >%! error("Test 2"); >%! endif > >%!test >%! if (compare_version("2.6-SVN", "2.6.0") != 1) >%! error("Test 3"); >%! endif > >## XXX: Is there a more easy way to test that a function returns an error? >%!test >%! test_failed = true; >%! try >%! compare_version("2.6.0", "Monkey"); >%! catch >%! test_failed = false; >%! end_try_catch >%! if (test_failed) >%! error("Test 4"); >%! endif > >%!test >%! if (compare_version("2.6.0-SVN2", "2.6.0-SVN1")) >%! error("Test 5"); >%! endif > > -- David Bateman David dot Bateman at motorola dot com Motorola Labs - Paris +33 1 69 35 48 04 (Ph) Parc Les Algorithmes, Commune de St Aubin +33 6 72 01 06 33 (Mob) 91193 Gif-Sur-Yvette FRANCE +33 1 69 35 77 01 (Fax) The information contained in this communication has been classified as: [x] General Business Information [ ] Motorola Internal Use Only [ ] Motorola Confidential Proprietary