2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include "vers_rsrc.h"
32 #include <sys/systm.h>
33 #include <libsa/vers_rsrc.h>
34 #endif /* not KERNEL */
39 #define PRIV_EXT __private_extern__
40 #endif /* not KERNEL */
42 #define VERS_MAJOR_DIGITS (4)
43 #define VERS_MINOR_DIGITS (2)
44 #define VERS_REVISION_DIGITS (2)
45 #define VERS_STAGE_DIGITS (1)
46 #define VERS_STAGE_LEVEL_DIGITS (3)
48 #define VERS_MAJOR_MULT (100000000)
49 #define VERS_MINOR_MULT (1000000)
50 #define VERS_REVISION_MULT (10000)
51 #define VERS_STAGE_MULT (1000)
63 static int __vers_isdigit(char c
) {
65 c
== '1' || c
== '2' || c
== '3' ||
66 c
== '4' || c
== '5' || c
== '6' ||
67 c
== '7' || c
== '8' || c
== '9');
70 static int __vers_isspace(char c
) {
77 static int __vers_digit_for_char(char c
) {
79 case '0': return 0; break;
80 case '1': return 1; break;
81 case '2': return 2; break;
82 case '3': return 3; break;
83 case '4': return 4; break;
84 case '5': return 5; break;
85 case '6': return 6; break;
86 case '7': return 7; break;
87 case '8': return 8; break;
88 case '9': return 9; break;
89 default: return -1; break;
95 static int __VERS_isreleasestate(char c
) {
96 return (c
== 'd' || c
== 'a' || c
== 'b' || c
== 'f');
100 static VERS_stage
__VERS_stage_for_string(const char ** string_p
) {
103 if (!string_p
|| !*string_p
) {
109 if (__vers_isspace(string
[0]) || string
[0] == '\0') {
114 if (__vers_isdigit(string
[1])) {
115 *string_p
= &string
[1];
116 return VERS_development
;
120 if (__vers_isdigit(string
[1])) {
121 *string_p
= &string
[1];
126 if (__vers_isdigit(string
[1])) {
127 *string_p
= &string
[1];
132 if (__vers_isdigit(string
[1])) {
133 *string_p
= &string
[1];
134 return VERS_candidate
;
135 } else if (string
[1] == 'c' && __vers_isdigit(string
[2])) {
136 *string_p
= &string
[2];
137 return VERS_candidate
;
151 static const char * __VERS_string_for_stage(VERS_stage stage
) {
153 case VERS_invalid
: return "?"; break;
154 case VERS_development
: return "d"; break;
155 case VERS_alpha
: return "a"; break;
156 case VERS_beta
: return "b"; break;
157 case VERS_candidate
: return "f"; break;
158 case VERS_release
: return ""; break;
165 VERS_version
VERS_parse_string(const char * vers_string
) {
166 VERS_version result
= -1;
168 int num_digits_scanned
= 0;
169 VERS_version vers_major
= 0;
170 VERS_version vers_minor
= 0;
171 VERS_version vers_revision
= 0;
172 VERS_version vers_stage
= 0;
173 VERS_version vers_stage_level
= 0;
174 const char * current_char_p
;
176 if (!vers_string
|| *vers_string
== '\0') {
180 current_char_p
= (const char *)&vers_string
[0];
183 * Check for an initial digit of the major release number.
185 vers_major
= __vers_digit_for_char(*current_char_p
);
186 if (vers_major
< 0) {
191 num_digits_scanned
= 1;
193 /* Complete scan for major version number. Legal characters are
194 * any digit, period, any buildstage letter.
196 while (num_digits_scanned
< VERS_MAJOR_DIGITS
) {
197 if (__vers_isspace(*current_char_p
) || *current_char_p
== '\0') {
198 vers_stage
= VERS_release
;
200 } else if (__vers_isdigit(*current_char_p
)) {
201 vers_digit
= __vers_digit_for_char(*current_char_p
);
202 if (vers_digit
< 0) {
205 vers_major
= (vers_major
) * 10 + vers_digit
;
207 num_digits_scanned
++;
208 } else if (__VERS_isreleasestate(*current_char_p
)) {
210 } else if (*current_char_p
== '.') {
218 /* Check for too many digits.
220 if (num_digits_scanned
== VERS_MAJOR_DIGITS
) {
221 if (*current_char_p
== '.') {
223 } else if (__vers_isdigit(*current_char_p
)) {
230 num_digits_scanned
= 0;
232 /* Scan for minor version number. Legal characters are
233 * any digit, period, any buildstage letter.
235 while (num_digits_scanned
< VERS_MINOR_DIGITS
) {
236 if (__vers_isspace(*current_char_p
) || *current_char_p
== '\0') {
237 vers_stage
= VERS_release
;
239 } else if (__vers_isdigit(*current_char_p
)) {
240 vers_digit
= __vers_digit_for_char(*current_char_p
);
241 if (vers_digit
< 0) {
244 vers_minor
= (vers_minor
) * 10 + vers_digit
;
246 num_digits_scanned
++;
247 } else if (__VERS_isreleasestate(*current_char_p
)) {
249 } else if (*current_char_p
== '.') {
257 /* Check for too many digits.
259 if (num_digits_scanned
== VERS_MINOR_DIGITS
) {
260 if (*current_char_p
== '.') {
262 } else if (__vers_isdigit(*current_char_p
)) {
269 num_digits_scanned
= 0;
271 /* Scan for revision version number. Legal characters are
272 * any digit, any buildstage letter (NOT PERIOD).
274 while (num_digits_scanned
< VERS_REVISION_DIGITS
) {
275 if (__vers_isspace(*current_char_p
) || *current_char_p
== '\0') {
276 vers_stage
= VERS_release
;
278 } else if (__vers_isdigit(*current_char_p
)) {
279 vers_digit
= __vers_digit_for_char(*current_char_p
);
280 if (vers_digit
< 0) {
283 vers_revision
= (vers_revision
) * 10 + vers_digit
;
285 num_digits_scanned
++;
286 } else if (__VERS_isreleasestate(*current_char_p
)) {
293 /* Check for too many digits.
295 if (num_digits_scanned
== VERS_REVISION_DIGITS
) {
296 if (*current_char_p
== '.') {
298 } else if (__vers_isdigit(*current_char_p
)) {
306 * Check for the release state.
308 if (__vers_isspace(*current_char_p
) || *current_char_p
== '\0') {
309 vers_stage
= VERS_release
;
312 vers_stage
= __VERS_stage_for_string(¤t_char_p
);
313 if (vers_stage
== VERS_invalid
) {
321 num_digits_scanned
= 0;
323 /* Scan for stage level number. Legal characters are
326 while (num_digits_scanned
< VERS_STAGE_LEVEL_DIGITS
) {
327 if (__vers_isspace(*current_char_p
) || *current_char_p
== '\0') {
328 if (num_digits_scanned
) {
333 } else if (__vers_isdigit(*current_char_p
)) {
334 vers_digit
= __vers_digit_for_char(*current_char_p
);
335 if (vers_digit
< 0) {
338 vers_stage_level
= (vers_stage_level
) * 10 + vers_digit
;
340 num_digits_scanned
++;
346 /* Check for too many digits.
348 if ((num_digits_scanned
== VERS_STAGE_LEVEL_DIGITS
) &&
349 ! (__vers_isspace(*current_char_p
) || (*current_char_p
== '\0'))) {
354 if (vers_stage_level
> 255) {
360 if (vers_stage
== VERS_candidate
&& vers_stage_level
== 0) {
364 result
= (vers_major
* VERS_MAJOR_MULT
) +
365 (vers_minor
* VERS_MINOR_MULT
) +
366 (vers_revision
* VERS_REVISION_MULT
) +
367 (vers_stage
* VERS_STAGE_MULT
) +
373 #define VERS_STRING_MAX_LEN (16)
376 int VERS_string(char * buffer
, UInt32 length
, VERS_version vers
) {
378 VERS_version vers_major
= 0;
379 VERS_version vers_minor
= 0;
380 VERS_version vers_revision
= 0;
381 VERS_version vers_stage
= 0;
382 VERS_version vers_stage_level
= 0;
383 const char * stage_string
= NULL
; // don't free
385 /* No buffer or length less than longest possible vers string,
388 if (!buffer
|| length
< VERS_STRING_MAX_LEN
) {
392 bzero(buffer
, length
* sizeof(char));
395 strlcpy(buffer
, "(invalid)", length
);
399 vers_major
= vers
/ VERS_MAJOR_MULT
;
401 vers_minor
= vers
- (vers_major
* VERS_MAJOR_MULT
);
402 vers_minor
/= VERS_MINOR_MULT
;
404 vers_revision
= vers
-
405 ( (vers_major
* VERS_MAJOR_MULT
) + (vers_minor
* VERS_MINOR_MULT
) );
406 vers_revision
/= VERS_REVISION_MULT
;
409 ( (vers_major
* VERS_MAJOR_MULT
) + (vers_minor
* VERS_MINOR_MULT
) +
410 (vers_revision
* VERS_REVISION_MULT
));
411 vers_stage
/= VERS_STAGE_MULT
;
413 vers_stage_level
= vers
-
414 ( (vers_major
* VERS_MAJOR_MULT
) + (vers_minor
* VERS_MINOR_MULT
) +
415 (vers_revision
* VERS_REVISION_MULT
) + (vers_stage
* VERS_STAGE_MULT
));
417 cpos
= snprintf(buffer
, length
, "%lu", (UInt32
)vers_major
);
419 /* Always include the minor version; it just looks weird without.
423 cpos
+= snprintf(buffer
+cpos
, length
- cpos
, "%lu", (UInt32
)vers_minor
);
425 /* The revision is displayed only if nonzero.
430 cpos
+= snprintf(buffer
+cpos
, length
- cpos
, "%lu",
431 (UInt32
)vers_revision
);
434 stage_string
= __VERS_string_for_stage(vers_stage
);
435 if (stage_string
&& stage_string
[0]) {
436 strlcat(buffer
, stage_string
, length
);
437 cpos
+= strlen(stage_string
);
440 if (vers_stage
< VERS_release
) {
441 snprintf(buffer
+cpos
, length
- cpos
, "%lu", (UInt32
)vers_stage_level
);