mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 18:18:18 +00:00
385 lines
12 KiB
Perl
385 lines
12 KiB
Perl
|
###############################################################################
|
||
|
#
|
||
|
# 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;
|