OSDN Git Service

Version 5.91
[vbslib/main.git] / GPL_bin_fullset / NaturalDocs / Modules / NaturalDocs / Version.pm
1 ###############################################################################
2 #
3 #   Package: NaturalDocs::Version
4 #
5 ###############################################################################
6 #
7 #   A package for handling version information.  What?  That's right.  Although it should be easy and obvious, version numbers
8 #   need to be dealt with in a variety of formats, plus there's compatibility with older releases which handled it differently.  I
9 #   wanted to centralize the code after it started getting complicated.  So there ya go.
10 #
11 ###############################################################################
12
13 # This file is part of Natural Docs, which is Copyright © 2003-2010 Greg Valure
14 # Natural Docs is licensed under version 3 of the GNU Affero General Public License (AGPL)
15 # Refer to License.txt for the complete details
16
17 use strict;
18 use integer;
19
20 package NaturalDocs::Version;
21
22
23 ###############################################################################
24 # Group: Functions
25
26
27 #
28 #   Function: ToString
29 #
30 #   Converts a <VersionInt> to a string.
31 #
32 sub ToString #(VersionInt version) => string
33     {
34     my ($self, $version) = @_;
35
36     my ($major, $minor, $month, $day, $year) = $self->ToValues($version);
37
38     if ($minor % 10 == 0)
39         {  $minor /= 10;  };
40
41     if ($day)
42         {  return sprintf('Development Release %02d-%02d-%d (%d.%d base)', $month, $day, $year, $major, $minor);  }
43     else
44         {  return $major . '.' . $minor;  };
45     };
46
47
48 #
49 #   Function: FromString
50 #
51 #   Converts a version string to a <VersionInt>.
52 #
53 sub FromString #(string string) => VersionInt
54     {
55     my ($self, $string) = @_;
56
57     if ($string eq '1')
58         {
59         return $self->FromValues(0, 91, 0, 0, 0);  # 0.91
60         }
61     else
62         {
63         my ($major, $minor, $month, $day, $year);
64
65         if ($string =~ /^(\d{1,2})\.(\d{1,2})$/)
66             {
67             ($major, $minor) = ($1, $2);
68             ($month, $day, $year) = (0, 0, 0);
69             }
70         elsif ($string =~ /^Development Release (\d{1,2})-(\d{1,2})-(\d\d\d\d) \((\d{1,2})\.(\d{1,2}) base\)$/)
71             {
72             ($month, $day, $year, $major, $minor) = ($1, $2, $3, $4, $5);
73
74             # We have to do sanity checking because these can come from user-editable text files.  The version numbers should
75             # already be constrained simply by being forced to have only two digits.
76
77             if ($month > 12 || $month < 1 || $day > 31 || $day < 1 || $year > 2255 || $year < 2000)
78                 {  die 'The version string ' . $string . " doesn't have a valid date.\n";  };
79             }
80         else
81             {
82             die 'The version string ' . $string . " isn't in a recognized format.\n";
83             };
84
85         if (length $minor == 1)
86             {  $minor *= 10;  };
87
88         return $self->FromValues($major, $minor, $month, $day, $year);
89         };
90     };
91
92
93 #
94 #   Function: ToTextFile
95 #
96 #   Writes a <VersionInt> to a text file.
97 #
98 #   Parameters:
99 #
100 #       fileHandle - The handle of the file to write it to.  It should be at the correct location.
101 #       version - The <VersionInt> to write.
102 #
103 sub ToTextFile #(handle fileHandle, VersionInt version)
104     {
105     my ($self, $fileHandle, $version) = @_;
106
107     print $fileHandle $self->ToString($version) . "\n";
108     };
109
110
111 #
112 #   Function: ToBinaryFile
113 #
114 #   Writes a <VersionInt> to a binary file.
115 #
116 #   Parameters:
117 #
118 #       fileHandle - The handle of the file to write it to.  It should be at the correct location.
119 #       version - The <VersionInt> to write.
120 #
121 sub ToBinaryFile #(handle fileHandle, VersionInt version)
122     {
123     my ($self, $fileHandle, $version) = @_;
124
125     my ($major, $minor, $month, $day, $year) = $self->ToValues($version);
126
127     # 1.35 development releases are encoded as 1.36.  Everything else is literal.
128     if ($day && $major == 1 && $minor == 35)
129         {  $minor = 36;  };
130
131     print $fileHandle pack('CC', $major, $minor);
132
133     # Date fields didn't exist with 1.35 stable and earlier.  1.35 development releases are encoded as 1.36, so this works.
134     if ($major > 1 || ($major == 1 && $minor > 35))
135         {
136         if ($day)
137             {  $year -= 2000;  };
138
139         print $fileHandle pack('CCC', $month, $day, $year);
140         };
141     };
142
143
144 #
145 #   Function: FromBinaryFile
146 #
147 #   Retrieves a <VersionInt> from a binary file.
148 #
149 #   Parameters:
150 #
151 #       fileHandle - The handle of the file to read it from.  It should be at the correct location.
152 #
153 #   Returns:
154 #
155 #       The <VersionInt>.
156 #
157 sub FromBinaryFile #(handle fileHandle) => VersionInt
158     {
159     my ($self, $fileHandle) = @_;
160
161     my ($major, $minor, $month, $day, $year);
162
163     my $raw;
164     read($fileHandle, $raw, 2);
165
166     ($major, $minor) = unpack('CC', $raw);
167
168     # 1.35 stable is the last release without the date fields.  1.35 development releases are encoded as 1.36, so this works.
169     if ($major > 1 || ($major == 1 && $minor > 35))
170         {
171         read($fileHandle, $raw, 3);
172         ($month, $day, $year) = unpack('CCC', $raw);
173
174         if ($day)
175             {  $year += 2000;  };
176         }
177     else
178         {  ($month, $day, $year) = (0, 0, 0);  };
179
180     # Fix the 1.35 development release special encoding.
181     if ($major == 1 && $minor == 36)
182         {  $minor = 35;  };
183
184
185     return $self->FromValues($major, $minor, $month, $day, $year);
186     };
187
188
189 #
190 #   Function: ToValues
191 #
192 #   Converts a <VersionInt> to the array ( major, minor, month, day, year ).  The minor version will be in two digit form, so x.2
193 #   will return 20.  The date fields will be zero for stable releases.
194 #
195 sub ToValues #(VersionInt version) => ( int, int, int, int, int )
196     {
197     my ($self, $version) = @_;
198
199     my $major = ($version & 0x00003F80) >> 7;
200     my $minor = ($version & 0x0000007F);
201     my $month = ($version & 0x00780000) >> 19;
202     my $day = ($version & 0x0007C000) >> 14;
203     my $year = ($version & 0x7F800000) >> 23;
204
205     if ($year)
206         {  $year += 2000;  };
207
208     return ( $major, $minor, $month, $day, $year );
209     };
210
211
212 #
213 #   Function: FromValues
214 #
215 #   Returns a <VersionInt> created from the passed values.
216 #
217 #   Parameters:
218 #
219 #       major - The major version number.  For development releases, it should be the stable version it's based off of.
220 #       minor - The minor version number.  It should always be two digits, so x.2 should pass 20.  For development
221 #                  releases, it should be the stable version it's based off of.
222 #       month - The numeric month of the development release.  For stable releases it should be zero.
223 #       day - The day of the development release.  For stable releases it should be zero.
224 #       year - The year of the development release.  For stable releases it should be zero.
225 #
226 #   Returns:
227 #
228 #       The <VersionInt>.
229 #
230 sub FromValues #(int major, int minor, int month, int day, int year) => VersionInt
231     {
232     my ($self, $major, $minor, $month, $day, $year) = @_;
233
234     if ($day)
235         {  $year -= 2000;  };
236
237     return ($major << 7) + ($minor) + ($month << 19) + ($day << 14) + ($year << 23);
238     };
239
240
241 #
242 #   Function: CheckFileFormat
243 #
244 #   Checks if a file's format is compatible with the current release.
245 #
246 #   - If the application is a development release or the file is from one, this only returns true if they are from the exact same
247 #     development release.
248 #   - If neither of them are development releases, this only returns true if the file is from a release between the minimum specified
249 #     and the current version.  If there's no minimum it just checks that it's below the current version.
250 #
251 #   Parameters:
252 #
253 #       fileVersion - The <VersionInt> of the file format.
254 #       minimumVersion - The minimum <VersionInt> required of the file format.  May be undef.
255 #
256 #   Returns:
257 #
258 #       Whether the file's format is compatible per the above rules.
259 #
260 sub CheckFileFormat #(VersionInt fileVersion, optional VersionInt minimumVersion) => bool
261     {
262     my ($self, $fileVersion, $minimumVersion) = @_;
263
264     my $appVersion = NaturalDocs::Settings->AppVersion();
265
266     if ($self->IsDevelopmentRelease($appVersion) || $self->IsDevelopmentRelease($fileVersion))
267         {  return ($appVersion == $fileVersion);  }
268     elsif ($minimumVersion && $fileVersion < $minimumVersion)
269         {  return 0;  }
270     else
271         {  return ($fileVersion <= $appVersion);  };
272     };
273
274
275 #
276 #   Function: IsDevelopmentRelease
277 #
278 #   Returns whether the passed <VersionInt> is for a development release.
279 #
280 sub IsDevelopmentRelease #(VersionInt version) => bool
281     {
282     my ($self, $version) = @_;
283
284     # Return if any of the date fields are set.
285     return ($version & 0x7FFFC000);
286     };
287
288
289
290 ###############################################################################
291 # Group: Implementation
292
293 #
294 #   About: String Format
295 #
296 #   Full Releases:
297 #
298 #       Full releases are in the common major.minor format.  Either part can be up to two digits.  The minor version is interpreted
299 #       as decimal places, so 1.3 > 1.22.  There are no leading or trailing zeroes.
300 #
301 #   Development Releases:
302 #
303 #       Development releases are in the format "Development Release mm-dd-yyyy (vv.vv base)" where vv.vv is the version
304 #       number of the full release it's based off of.  The month and day will have leading zeroes where applicable.  Example:
305 #       "Development Release 07-09-2006 (1.35 base)".
306 #
307 #   0.91 and Earlier:
308 #
309 #       Text files from releases prior to 0.95 had a separate file format version number that was used instead of the application
310 #       version.  These were never changed between 0.85 and 0.91, so they are simply "1".  Text version numbers that are "1"
311 #       instead of "1.0" will be interpreted as 0.91.
312 #
313
314 #
315 #   About: Integer Format
316 #
317 #   <VersionInts> are 32-bit values with the bit distribution below.
318 #
319 #   > s yyyyyyyy mmmm ddddd vvvvvvv xxxxxxx
320 #   > [syyy|yyyy] [ymmm|mddd] [ddvv|vvvv] [vxxx|xxxx]
321 #
322 #   s - The sign bit.  Always zero, so it's always interpreted as positive.
323 #   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.
324 #   m - The month bits if it's a development release, zero otherwise.
325 #   d - The day bits if it's a development release, zero otherwise.
326 #   v - The major version bits.  For development releases, it's the last stable version it was based off of.
327 #   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
328 #        last stable version it was based off of.
329 #
330 #   It's stored with the development release date at a higher significance than the version because we want a stable release to
331 #   always treat a development release as higher than itself, and thus not attempt to read any of the data files.  I'm not tracking
332 #   data file formats at the development release level.
333 #
334
335 #
336 #   About: Binary File Format
337 #
338 #   Current:
339 #
340 #       Five 8-bit unsigned values, appearing major, minor, month, day, year.  Minor is always stored with two digits, so x.2 would
341 #       store 20.  Year is stored minus 2000, so 2006 is stored 6.  Stable releases store zero for all the date fields.
342 #
343 #   1.35 Development Releases:
344 #
345 #       1.35-based development releases are stored the same as current releases, but with 1.36 as the version number.  This is
346 #       done so previous versions of Natural Docs that didn't include the date fields would still know it's a higher version.  There is
347 #       no actual 1.36 release.
348 #
349 #   1.35 and Earlier:
350 #
351 #       Two 8-bit unsigned values, appearing major then minor.  Minor is always stored with two digits, so x.2 would store 20.
352 #
353
354 #
355 #   About: Text File Format
356 #
357 #   In text files, versions are the <String Format> followed by a native line break.
358 #
359
360
361 1;