about summary refs log tree commit diff
path: root/docs/tool/Modules/NaturalDocs/Version.pm
diff options
context:
space:
mode:
Diffstat (limited to 'docs/tool/Modules/NaturalDocs/Version.pm')
-rw-r--r--docs/tool/Modules/NaturalDocs/Version.pm384
1 files changed, 384 insertions, 0 deletions
diff --git a/docs/tool/Modules/NaturalDocs/Version.pm b/docs/tool/Modules/NaturalDocs/Version.pm
new file mode 100644
index 00000000..36d2d88c
--- /dev/null
+++ b/docs/tool/Modules/NaturalDocs/Version.pm
@@ -0,0 +1,384 @@
+###############################################################################
+#
+#   Package: NaturalDocs::Version
+#
+###############################################################################
+#
+#   A package for handling version information.  What?  That's right.  Although it should be easy and obvious, version numbers
+#   need to be dealt with in a variety of formats, plus there's compatibility with older releases which handled it differently.  I
+#   wanted to centralize the code after it started getting complicated.  So there ya go.
+#
+###############################################################################
+
+# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
+# Natural Docs is licensed under the GPL
+
+use strict;
+use integer;
+
+package NaturalDocs::Version;
+
+
+###############################################################################
+# Group: Functions
+
+
+#
+#   Function: ToString
+#
+#   Converts a <VersionInt> to a string.
+#
+sub ToString #(VersionInt version) => string
+    {
+    my ($self, $version) = @_;
+
+    my ($major, $minor, $month, $day, $year) = $self->ToValues($version);
+
+    if ($minor % 10 == 0)
+        {  $minor /= 10;  };
+
+    if ($day)
+        {  return sprintf('Development Release %02d-%02d-%d (%d.%d base)', $month, $day, $year, $major, $minor);  }
+    else
+        {  return $major . '.' . $minor;  };
+    };
+
+
+#
+#   Function: FromString
+#
+#   Converts a version string to a <VersionInt>.
+#
+sub FromString #(string string) => VersionInt
+    {
+    my ($self, $string) = @_;
+
+    if ($string eq '1')
+        {
+        return $self->FromValues(0, 91, 0, 0, 0);  # 0.91
+        }
+    else
+        {
+        my ($major, $minor, $month, $day, $year);
+
+        if ($string =~ /^(\d{1,2})\.(\d{1,2})$/)
+            {
+            ($major, $minor) = ($1, $2);
+            ($month, $day, $year) = (0, 0, 0);
+            }
+        elsif ($string =~ /^Development Release (\d{1,2})-(\d{1,2})-(\d\d\d\d) \((\d{1,2})\.(\d{1,2}) base\)$/)
+            {
+            ($month, $day, $year, $major, $minor) = ($1, $2, $3, $4, $5);
+
+            # We have to do sanity checking because these can come from user-editable text files.  The version numbers should
+            # already be constrained simply by being forced to have only two digits.
+
+            if ($month > 12 || $month < 1 || $day > 31 || $day < 1 || $year > 2255 || $year < 2000)
+                {  die 'The version string ' . $string . " doesn't have a valid date.\n";  };
+            }
+        else
+            {
+            die 'The version string ' . $string . " isn't in a recognized format.\n";
+            };
+
+        if (length $minor == 1)
+            {  $minor *= 10;  };
+
+        return $self->FromValues($major, $minor, $month, $day, $year);
+        };
+    };
+
+
+#
+#   Function: ToTextFile
+#
+#   Writes a <VersionInt> to a text file.
+#
+#   Parameters:
+#
+#       fileHandle - The handle of the file to write it to.  It should be at the correct location.
+#       version - The <VersionInt> to write.
+#
+sub ToTextFile #(handle fileHandle, VersionInt version)
+    {
+    my ($self, $fileHandle, $version) = @_;
+
+    print $fileHandle $self->ToString($version) . "\n";
+    };
+
+
+#
+#   Function: FromTextFile
+#
+#   Retrieves a <VersionInt> from a text file.
+#
+#   Parameters:
+#
+#       fileHandle - The handle of the file to read it from.  It should be at the correct location.
+#
+#   Returns:
+#
+#       The <VersionInt>.
+#
+sub FromTextFile #(handle fileHandle) => VersionInt
+    {
+    my ($self, $fileHandle) = @_;
+
+    my $version = <$fileHandle>;
+    ::XChomp(\$version);
+
+    return $self->FromString($version);
+    };
+
+
+#
+#   Function: ToBinaryFile
+#
+#   Writes a <VersionInt> to a binary file.
+#
+#   Parameters:
+#
+#       fileHandle - The handle of the file to write it to.  It should be at the correct location.
+#       version - The <VersionInt> to write.
+#
+sub ToBinaryFile #(handle fileHandle, VersionInt version)
+    {
+    my ($self, $fileHandle, $version) = @_;
+
+    my ($major, $minor, $month, $day, $year) = $self->ToValues($version);
+
+    # 1.35 development releases are encoded as 1.36.  Everything else is literal.
+    if ($day && $major == 1 && $minor == 35)
+        {  $minor = 36;  };
+
+    print $fileHandle pack('CC', $major, $minor);
+
+    # Date fields didn't exist with 1.35 stable and earlier.  1.35 development releases are encoded as 1.36, so this works.
+    if ($major > 1 || ($major == 1 && $minor > 35))
+        {
+        if ($day)
+            {  $year -= 2000;  };
+
+        print $fileHandle pack('CCC', $month, $day, $year);
+        };
+    };
+
+
+#
+#   Function: FromBinaryFile
+#
+#   Retrieves a <VersionInt> from a binary file.
+#
+#   Parameters:
+#
+#       fileHandle - The handle of the file to read it from.  It should be at the correct location.
+#
+#   Returns:
+#
+#       The <VersionInt>.
+#
+sub FromBinaryFile #(handle fileHandle) => VersionInt
+    {
+    my ($self, $fileHandle) = @_;
+
+    my ($major, $minor, $month, $day, $year);
+
+    my $raw;
+    read($fileHandle, $raw, 2);
+
+    ($major, $minor) = unpack('CC', $raw);
+
+    # 1.35 stable is the last release without the date fields.  1.35 development releases are encoded as 1.36, so this works.
+    if ($major > 1 || ($major == 1 && $minor > 35))
+        {
+        read($fileHandle, $raw, 3);
+        ($month, $day, $year) = unpack('CCC', $raw);
+
+        if ($day)
+            {  $year += 2000;  };
+        }
+    else
+        {  ($month, $day, $year) = (0, 0, 0);  };
+
+    # Fix the 1.35 development release special encoding.
+    if ($major == 1 && $minor == 36)
+        {  $minor = 35;  };
+
+
+    return $self->FromValues($major, $minor, $month, $day, $year);
+    };
+
+
+#
+#   Function: ToValues
+#
+#   Converts a <VersionInt> to the array ( major, minor, month, day, year ).  The minor version will be in two digit form, so x.2
+#   will return 20.  The date fields will be zero for stable releases.
+#
+sub ToValues #(VersionInt version) => ( int, int, int, int, int )
+    {
+    my ($self, $version) = @_;
+
+    my $major = ($version & 0x00003F80) >> 7;
+    my $minor = ($version & 0x0000007F);
+    my $month = ($version & 0x00780000) >> 19;
+    my $day = ($version & 0x0007C000) >> 14;
+    my $year = ($version & 0x7F800000) >> 23;
+
+    if ($year)
+        {  $year += 2000;  };
+
+    return ( $major, $minor, $month, $day, $year );
+    };
+
+
+#
+#   Function: FromValues
+#
+#   Returns a <VersionInt> created from the passed values.
+#
+#   Parameters:
+#
+#       major - The major version number.  For development releases, it should be the stable version it's based off of.
+#       minor - The minor version number.  It should always be two digits, so x.2 should pass 20.  For development
+#                  releases, it should be the stable version it's based off of.
+#       month - The numeric month of the development release.  For stable releases it should be zero.
+#       day - The day of the development release.  For stable releases it should be zero.
+#       year - The year of the development release.  For stable releases it should be zero.
+#
+#   Returns:
+#
+#       The <VersionInt>.
+#
+sub FromValues #(int major, int minor, int month, int day, int year) => VersionInt
+    {
+    my ($self, $major, $minor, $month, $day, $year) = @_;
+
+    if ($day)
+        {  $year -= 2000;  };
+
+    return ($major << 7) + ($minor) + ($month << 19) + ($day << 14) + ($year << 23);
+    };
+
+
+#
+#   Function: CheckFileFormat
+#
+#   Checks if a file's format is compatible with the current release.
+#
+#   - If the application is a development release or the file is from one, this only returns true if they are from the exact same
+#     development release.
+#   - If neither of them are development releases, this only returns true if the file is from a release between the minimum specified
+#     and the current version.  If there's no minimum it just checks that it's below the current version.
+#
+#   Parameters:
+#
+#       fileVersion - The <VersionInt> of the file format.
+#       minimumVersion - The minimum <VersionInt> required of the file format.  May be undef.
+#
+#   Returns:
+#
+#       Whether the file's format is compatible per the above rules.
+#
+sub CheckFileFormat #(VersionInt fileVersion, optional VersionInt minimumVersion) => bool
+    {
+    my ($self, $fileVersion, $minimumVersion) = @_;
+
+    my $appVersion = NaturalDocs::Settings->AppVersion();
+
+    if ($self->IsDevelopmentRelease($appVersion) || $self->IsDevelopmentRelease($fileVersion))
+        {  return ($appVersion == $fileVersion);  }
+    elsif ($minimumVersion && $fileVersion < $minimumVersion)
+        {  return 0;  }
+    else
+        {  return ($fileVersion <= $appVersion);  };
+    };
+
+
+#
+#   Function: IsDevelopmentRelease
+#
+#   Returns whether the passed <VersionInt> is for a development release.
+#
+sub IsDevelopmentRelease #(VersionInt version) => bool
+    {
+    my ($self, $version) = @_;
+
+    # Return if any of the date fields are set.
+    return ($version & 0x7FFFC000);
+    };
+
+
+
+###############################################################################
+# Group: Implementation
+
+#
+#   About: String Format
+#
+#   Full Releases:
+#
+#       Full releases are in the common major.minor format.  Either part can be up to two digits.  The minor version is interpreted
+#       as decimal places, so 1.3 > 1.22.  There are no leading or trailing zeroes.
+#
+#   Development Releases:
+#
+#       Development releases are in the format "Development Release mm-dd-yyyy (vv.vv base)" where vv.vv is the version
+#       number of the full release it's based off of.  The month and day will have leading zeroes where applicable.  Example:
+#       "Development Release 07-09-2006 (1.35 base)".
+#
+#   0.91 and Earlier:
+#
+#       Text files from releases prior to 0.95 had a separate file format version number that was used instead of the application
+#       version.  These were never changed between 0.85 and 0.91, so they are simply "1".  Text version numbers that are "1"
+#       instead of "1.0" will be interpreted as 0.91.
+#
+
+#
+#   About: Integer Format
+#
+#   <VersionInts> are 32-bit values with the bit distribution below.
+#
+#   > s yyyyyyyy mmmm ddddd vvvvvvv xxxxxxx
+#   > [syyy|yyyy] [ymmm|mddd] [ddvv|vvvv] [vxxx|xxxx]
+#
+#   s - The sign bit.  Always zero, so it's always interpreted as positive.
+#   y - The year bits if it's a development release, zero otherwise.  2000 is added to the value, so the range is from 2000 to 2255.
+#   m - The month bits if it's a development release, zero otherwise.
+#   d - The day bits if it's a development release, zero otherwise.
+#   v - The major version bits.  For development releases, it's the last stable version it was based off of.
+#   x - The minor version bits.  It's always stored as two decimals, so x.2 would store 20 here.  For development releases, it's the
+#        last stable version it was based off of.
+#
+#   It's stored with the development release date at a higher significance than the version because we want a stable release to
+#   always treat a development release as higher than itself, and thus not attempt to read any of the data files.  I'm not tracking
+#   data file formats at the development release level.
+#
+
+#
+#   About: Binary File Format
+#
+#   Current:
+#
+#       Five 8-bit unsigned values, appearing major, minor, month, day, year.  Minor is always stored with two digits, so x.2 would
+#       store 20.  Year is stored minus 2000, so 2006 is stored 6.  Stable releases store zero for all the date fields.
+#
+#   1.35 Development Releases:
+#
+#       1.35-based development releases are stored the same as current releases, but with 1.36 as the version number.  This is
+#       done so previous versions of Natural Docs that didn't include the date fields would still know it's a higher version.  There is
+#       no actual 1.36 release.
+#
+#   1.35 and Earlier:
+#
+#       Two 8-bit unsigned values, appearing major then minor.  Minor is always stored with two digits, so x.2 would store 20.
+#
+
+#
+#   About: Text File Format
+#
+#   In text files, versions are the <String Format> followed by a native line break.
+#
+
+
+1;