// (C) Ximian, Inc. http://www.ximian.com
//
-namespace System {
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace System
+{
+ [Serializable]
+ public sealed class Version : ICloneable, IComparable
+#if NET_2_0
+ , IComparable<Version>, IEquatable <Version>
+#endif
+ {
+
+ int _Major, _Minor, _Build, _Revision;
+
+ private const int UNDEFINED = -1;
- public class Version : ICloneable, IComparable {
- int major, minor, build, revision;
+ private void CheckedSet (int defined, int major, int minor, int build, int revision)
+ {
+ // defined should be 2, 3 or 4
+
+ if (major < 0) {
+ throw new ArgumentOutOfRangeException ("major");
+ }
+ this._Major = major;
+
+ if (minor < 0) {
+ throw new ArgumentOutOfRangeException ("minor");
+ }
+ this._Minor = minor;
+
+ if (defined == 2) {
+ this._Build = UNDEFINED;
+ this._Revision = UNDEFINED;
+ return;
+ }
+
+ if (build < 0) {
+ throw new ArgumentOutOfRangeException ("build");
+ }
+ this._Build = build;
+
+ if (defined == 3) {
+ this._Revision = UNDEFINED;
+ return;
+ }
+
+ if (revision < 0) {
+ throw new ArgumentOutOfRangeException ("revision");
+ }
+ this._Revision = revision;
+ }
+
+ public Version ()
+ {
+ CheckedSet (2, 0, 0, -1, -1);
+ }
- const int MAXINT = int.MaxValue;
-
public Version (string version)
{
int n;
- string [] vals = version.Split (new Char [] {'.'});
-
+ string [] vals;
+ int major = -1, minor = -1, build = -1, revision = -1;
+
+ if (version == null) {
+ throw new ArgumentNullException ("version");
+ }
+
+ vals = version.Split (new Char [] {'.'});
n = vals.Length;
+
+ if (n < 2 || n > 4) {
+ throw new ArgumentException (Locale.GetText
+ ("There must be 2, 3 or 4 components in the version string."));
+ }
+
if (n > 0)
major = int.Parse (vals [0]);
if (n > 1)
if (n > 2)
build = int.Parse (vals [2]);
if (n > 3)
- build = int.Parse (vals [3]);
+ revision = int.Parse (vals [3]);
+
+ CheckedSet (n, major, minor, build, revision);
}
-
+
public Version (int major, int minor)
{
- this.major = major;
- this.minor = minor;
- this.build = MAXINT;
- this.revision = MAXINT;
+ CheckedSet (2, major, minor, 0, 0);
}
public Version (int major, int minor, int build)
{
- this.major = major;
- this.minor = minor;
- this.build = build;
- this.revision = MAXINT;
+ CheckedSet (3, major, minor, build, 0);
}
public Version (int major, int minor, int build, int revision)
{
- this.major = major;
- this.minor = minor;
- this.build = build;
- this.revision = revision;
+ CheckedSet (4, major, minor, build, revision);
}
public int Build {
get {
- return build;
+ return _Build;
}
}
public int Major {
get {
- return major;
+ return _Major;
}
}
public int Minor {
get {
- return minor;
+ return _Minor;
}
}
public int Revision {
get {
- return revision;
+ return _Revision;
}
}
public object Clone ()
{
- return new Version (major, minor, build, revision);
+ if (_Build == -1)
+ return new Version (_Major, _Minor);
+ else if (_Revision == -1)
+ return new Version (_Major, _Minor, _Build);
+ else
+ return new Version (_Major, _Minor, _Build, _Revision);
}
public int CompareTo (object version)
{
- Version v;
-
if (version == null)
- throw new ArgumentNullException ("version");
+ return 1;
+
if (! (version is Version))
- throw new ArgumentException ("version");
+ throw new ArgumentException (Locale.GetText ("Argument to Version.CompareTo must be a Version."));
- v = version;
+ return this.CompareTo ((Version) version);
+ }
- if (this.major > v.major)
+ public override bool Equals (object obj)
+ {
+ return this.Equals (obj as Version);
+ }
+
+#if NET_2_0
+ public
+#endif
+ int CompareTo (Version v)
+ {
+ if (v == null)
+ return 1;
+
+ if (this._Major > v._Major)
return 1;
- else if (this.major < v.major)
+ else if (this._Major < v._Major)
return -1;
- if (this.minor > v.minor)
+ if (this._Minor > v._Minor)
return 1;
- else if (this.minor < this.minor)
+ else if (this._Minor < v._Minor)
return -1;
- if (this.build > v.build)
+ if (this._Build > v._Build)
return 1;
- else if (this.build < this.build)
+ else if (this._Build < v._Build)
return -1;
- // FIXME: Compare revision or build first?
- if (this.revision > v.revision)
+ if (this._Revision > v._Revision)
return 1;
- else if (this.revision < v.revision)
+ else if (this._Revision < v._Revision)
return -1;
return 0;
}
- public override bool Equals (object obj)
+#if NET_2_0
+ public
+#endif
+ bool Equals (Version x)
{
- Version x;
-
- if (obj == null)
- throw new ArgumentNullException ("obj");
- if (!(obj is Version))
- return false;
-
- x = (Version) obj;
-
- if ((x.major == major) &&
- (x.minor == minor) &&
- (x.build == build) &&
- (x.revision == revision))
- return true;
- return false;
+ return ((x != null) &&
+ (x._Major == _Major) &&
+ (x._Minor == _Minor) &&
+ (x._Build == _Build) &&
+ (x._Revision == _Revision));
}
- // <summary>
- // This is sort of lame: the documentation claims that the
- // return value is a 32-bit integer, but "int" can be 64
- // on Alphas for example.
- // </summary>
public override int GetHashCode ()
{
- return (revision << 24) | (build << 16) | (minor << 8) | major;
+ return (_Revision << 24) | (_Build << 16) | (_Minor << 8) | _Major;
}
// <summary>
// </summary>
public override string ToString ()
{
- string mm = major.ToString + "." + minor.ToString ();
+ string mm = _Major.ToString () + "." + _Minor.ToString ();
- if (build != MAXINT)
- mm = mm + "." + build.ToString ();
- if (revision != MAXINT)
- mm = mm + "." + revision.ToString ();
+ if (_Build != UNDEFINED)
+ mm = mm + "." + _Build.ToString ();
+ if (_Revision != UNDEFINED)
+ mm = mm + "." + _Revision.ToString ();
return mm;
}
if (fields == 0)
return "";
if (fields == 1)
- return major.ToString ();
+ return _Major.ToString ();
if (fields == 2)
- return major.ToString () + "." + minor.ToString ();
+ return _Major.ToString () + "." + _Minor.ToString ();
if (fields == 3){
- if (build == MAXINT)
- throw new ArgumentException ("fields is larger than the number of components defined in this instance");
- return major.ToString () + "." + minor.ToString () + "." +
- build.ToString ();
+ if (_Build == UNDEFINED)
+ throw new ArgumentException (Locale.GetText
+ ("fields is larger than the number of components defined in this instance."));
+ return _Major.ToString () + "." + _Minor.ToString () + "." +
+ _Build.ToString ();
}
if (fields == 4){
- if (build == MAXINT || revision == MAXINT)
- throw new ArgumentException ("fields is larger than the number of components defined in this instance");
- return major.ToString () + "." + minor.ToString () + "." +
- build.ToString () + "." + revision.ToString ();
+ if (_Build == UNDEFINED || _Revision == UNDEFINED)
+ throw new ArgumentException (Locale.GetText
+ ("fields is larger than the number of components defined in this instance."));
+ return _Major.ToString () + "." + _Minor.ToString () + "." +
+ _Build.ToString () + "." + _Revision.ToString ();
}
-
+ throw new ArgumentException (Locale.GetText ("Invalid fields parameter: ") + fields.ToString());
+ }
+
+ public static bool operator== (Version v1, Version v2)
+ {
+ return Equals (v1, v2);
+ }
+
+ public static bool operator!= (Version v1, Version v2)
+ {
+ return !Equals (v1, v2);
}
- }
-}
+ public static bool operator> (Version v1, Version v2)
+ {
+ return v1.CompareTo (v2) > 0;
+ }
+
+ public static bool operator>= (Version v1, Version v2)
+ {
+ return v1.CompareTo (v2) >= 0;
+ }
+
+ public static bool operator< (Version v1, Version v2)
+ {
+ return v1.CompareTo (v2) < 0;
+ }
+
+ public static bool operator<= (Version v1, Version v2)
+ {
+ return v1.CompareTo (v2) <= 0;
+ }
+
+ // a very gentle way to construct a Version object which takes
+ // the first four numbers in a string as the version
+ internal static Version CreateFromString (string info)
+ {
+ int major = 0;
+ int minor = 0;
+ int build = 0;
+ int revision = 0;
+ int state = 1;
+ int number = UNDEFINED; // string may not begin with a digit
+ if (info == null)
+ return new Version (0, 0, 0, 0);
+
+ for (int i=0; i < info.Length; i++) {
+ char c = info [i];
+ if (Char.IsDigit (c)) {
+ if (number < 0) {
+ number = (c - '0');
+ }
+ else {
+ number = (number * 10) + (c - '0');
+ }
+ }
+ else if (number >= 0) {
+ // assign
+ switch (state) {
+ case 1:
+ major = number;
+ break;
+ case 2:
+ minor = number;
+ break;
+ case 3:
+ build = number;
+ break;
+ case 4:
+ revision = number;
+ break;
+ }
+ number = -1;
+ state ++;
+ }
+ // ignore end of string
+ if (state == 5)
+ break;
+ }
+ // Last number
+ if (number >= 0) {
+ switch (state) {
+ case 1:
+ major = number;
+ break;
+ case 2:
+ minor = number;
+ break;
+ case 3:
+ build = number;
+ break;
+ case 4:
+ revision = number;
+ break;
+ }
+ }
+ return new Version (major, minor, build, revision);
+ }
+ }
+}