]> git.saurik.com Git - apple/xnu.git/blame - libsa/vers_rsrc.c
xnu-1228.7.58.tar.gz
[apple/xnu.git] / libsa / vers_rsrc.c
CommitLineData
2d21ac55
A
1/*
2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
55e303ae
A
28#ifndef KERNEL
29#include <libc.h>
30#include "vers_rsrc.h"
31#else
1c79356b 32#include <sys/systm.h>
55e303ae
A
33#include <libsa/vers_rsrc.h>
34#endif /* not KERNEL */
35
36#ifndef KERNEL
37#define PRIV_EXT
38#else
39#define PRIV_EXT __private_extern__
40#endif /* not KERNEL */
41
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)
47
48#define VERS_MAJOR_MULT (100000000)
49#define VERS_MINOR_MULT (1000000)
50#define VERS_REVISION_MULT (10000)
51#define VERS_STAGE_MULT (1000)
52
53typedef enum {
54 VERS_invalid = 0,
55 VERS_development = 1,
56 VERS_alpha = 3,
57 VERS_beta = 5,
58 VERS_candidate = 7,
59 VERS_release = 9,
60} VERS_stage;
61
62
63static int __vers_isdigit(char c) {
1c79356b
A
64 return (c == '0' ||
65 c == '1' || c == '2' || c == '3' ||
66 c == '4' || c == '5' || c == '6' ||
67 c == '7' || c == '8' || c == '9');
68}
69
55e303ae 70static int __vers_isspace(char c) {
1c79356b
A
71 return (c == ' ' ||
72 c == '\t' ||
73 c == '\r' ||
74 c == '\n');
75}
76
55e303ae 77static int __vers_digit_for_char(char c) {
1c79356b
A
78 switch (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;
55e303ae 89 default: return -1; break;
1c79356b 90 }
1c79356b 91
55e303ae
A
92 return -1;
93}
1c79356b 94
55e303ae
A
95static int __VERS_isreleasestate(char c) {
96 return (c == 'd' || c == 'a' || c == 'b' || c == 'f');
1c79356b
A
97}
98
99
2d21ac55
A
100static VERS_stage __VERS_stage_for_string(const char ** string_p) {
101 const char * string;
1c79356b
A
102
103 if (!string_p || !*string_p) {
104 return VERS_invalid;
105 }
106
107 string = *string_p;
108
55e303ae 109 if (__vers_isspace(string[0]) || string[0] == '\0') {
1c79356b
A
110 return VERS_release;
111 } else {
112 switch (string[0]) {
113 case 'd':
55e303ae 114 if (__vers_isdigit(string[1])) {
1c79356b
A
115 *string_p = &string[1];
116 return VERS_development;
117 }
118 break;
119 case 'a':
55e303ae 120 if (__vers_isdigit(string[1])) {
1c79356b
A
121 *string_p = &string[1];
122 return VERS_alpha;
123 }
124 break;
125 case 'b':
55e303ae 126 if (__vers_isdigit(string[1])) {
1c79356b
A
127 *string_p = &string[1];
128 return VERS_beta;
129 }
130 break;
131 case 'f':
55e303ae 132 if (__vers_isdigit(string[1])) {
1c79356b
A
133 *string_p = &string[1];
134 return VERS_candidate;
55e303ae 135 } else if (string[1] == 'c' && __vers_isdigit(string[2])) {
1c79356b
A
136 *string_p = &string[2];
137 return VERS_candidate;
138 } else {
139 return VERS_invalid;
140 }
141 break;
142 default:
143 return VERS_invalid;
144 break;
145 }
146 }
147
148 return VERS_invalid;
149}
150
2d21ac55 151static const char * __VERS_string_for_stage(VERS_stage stage) {
55e303ae
A
152 switch (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;
159 }
1c79356b 160
55e303ae
A
161 return "?";
162}
163
164PRIV_EXT
165VERS_version VERS_parse_string(const char * vers_string) {
166 VERS_version result = -1;
167 int vers_digit = -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;
2d21ac55 174 const char * current_char_p;
1c79356b
A
175
176 if (!vers_string || *vers_string == '\0') {
55e303ae 177 return -1;
1c79356b
A
178 }
179
2d21ac55 180 current_char_p = (const char *)&vers_string[0];
1c79356b
A
181
182 /*****
183 * Check for an initial digit of the major release number.
184 */
55e303ae
A
185 vers_major = __vers_digit_for_char(*current_char_p);
186 if (vers_major < 0) {
187 return -1;
1c79356b
A
188 }
189
190 current_char_p++;
55e303ae 191 num_digits_scanned = 1;
1c79356b 192
55e303ae
A
193 /* Complete scan for major version number. Legal characters are
194 * any digit, period, any buildstage letter.
1c79356b 195 */
55e303ae
A
196 while (num_digits_scanned < VERS_MAJOR_DIGITS) {
197 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
198 vers_stage = VERS_release;
1c79356b 199 goto finish;
55e303ae
A
200 } else if (__vers_isdigit(*current_char_p)) {
201 vers_digit = __vers_digit_for_char(*current_char_p);
202 if (vers_digit < 0) {
203 return -1;
204 }
205 vers_major = (vers_major) * 10 + vers_digit;
206 current_char_p++;
207 num_digits_scanned++;
208 } else if (__VERS_isreleasestate(*current_char_p)) {
1c79356b
A
209 goto release_state;
210 } else if (*current_char_p == '.') {
211 current_char_p++;
55e303ae 212 goto minor_version;
1c79356b 213 } else {
55e303ae 214 return -1;
1c79356b 215 }
1c79356b
A
216 }
217
55e303ae 218 /* Check for too many digits.
1c79356b 219 */
55e303ae
A
220 if (num_digits_scanned == VERS_MAJOR_DIGITS) {
221 if (*current_char_p == '.') {
222 current_char_p++;
223 } else if (__vers_isdigit(*current_char_p)) {
224 return -1;
1c79356b 225 }
55e303ae 226 }
1c79356b 227
55e303ae 228minor_version:
1c79356b 229
55e303ae 230 num_digits_scanned = 0;
1c79356b 231
55e303ae
A
232 /* Scan for minor version number. Legal characters are
233 * any digit, period, any buildstage letter.
234 */
235 while (num_digits_scanned < VERS_MINOR_DIGITS) {
236 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
237 vers_stage = VERS_release;
1c79356b 238 goto finish;
55e303ae
A
239 } else if (__vers_isdigit(*current_char_p)) {
240 vers_digit = __vers_digit_for_char(*current_char_p);
241 if (vers_digit < 0) {
242 return -1;
243 }
244 vers_minor = (vers_minor) * 10 + vers_digit;
245 current_char_p++;
246 num_digits_scanned++;
247 } else if (__VERS_isreleasestate(*current_char_p)) {
1c79356b
A
248 goto release_state;
249 } else if (*current_char_p == '.') {
250 current_char_p++;
55e303ae 251 goto revision;
1c79356b 252 } else {
55e303ae 253 return -1;
1c79356b 254 }
1c79356b
A
255 }
256
55e303ae 257 /* Check for too many digits.
1c79356b 258 */
55e303ae
A
259 if (num_digits_scanned == VERS_MINOR_DIGITS) {
260 if (*current_char_p == '.') {
261 current_char_p++;
262 } else if (__vers_isdigit(*current_char_p)) {
263 return -1;
1c79356b 264 }
55e303ae 265 }
1c79356b 266
55e303ae 267revision:
1c79356b 268
55e303ae 269 num_digits_scanned = 0;
1c79356b 270
55e303ae
A
271 /* Scan for revision version number. Legal characters are
272 * any digit, any buildstage letter (NOT PERIOD).
273 */
274 while (num_digits_scanned < VERS_REVISION_DIGITS) {
275 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
276 vers_stage = VERS_release;
1c79356b 277 goto finish;
55e303ae
A
278 } else if (__vers_isdigit(*current_char_p)) {
279 vers_digit = __vers_digit_for_char(*current_char_p);
280 if (vers_digit < 0) {
281 return -1;
282 }
283 vers_revision = (vers_revision) * 10 + vers_digit;
284 current_char_p++;
285 num_digits_scanned++;
286 } else if (__VERS_isreleasestate(*current_char_p)) {
1c79356b
A
287 goto release_state;
288 } else {
55e303ae 289 return -1;
1c79356b 290 }
1c79356b
A
291 }
292
55e303ae
A
293 /* Check for too many digits.
294 */
295 if (num_digits_scanned == VERS_REVISION_DIGITS) {
296 if (*current_char_p == '.') {
297 current_char_p++;
298 } else if (__vers_isdigit(*current_char_p)) {
299 return -1;
300 }
301 }
1c79356b
A
302
303release_state:
304
305 /*****
306 * Check for the release state.
307 */
55e303ae
A
308 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
309 vers_stage = VERS_release;
1c79356b
A
310 goto finish;
311 } else {
55e303ae
A
312 vers_stage = __VERS_stage_for_string(&current_char_p);
313 if (vers_stage == VERS_invalid) {
314 return -1;
1c79356b
A
315 }
316 }
317
318
55e303ae 319// stage level
1c79356b 320
55e303ae 321 num_digits_scanned = 0;
1c79356b 322
55e303ae
A
323 /* Scan for stage level number. Legal characters are
324 * any digit only.
325 */
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) {
329 goto finish;
1c79356b 330 } else {
55e303ae
A
331 return -1;
332 }
333 } else if (__vers_isdigit(*current_char_p)) {
334 vers_digit = __vers_digit_for_char(*current_char_p);
335 if (vers_digit < 0) {
336 return -1;
1c79356b 337 }
55e303ae
A
338 vers_stage_level = (vers_stage_level) * 10 + vers_digit;
339 current_char_p++;
340 num_digits_scanned++;
341 } else {
342 return -1;
1c79356b
A
343 }
344 }
345
55e303ae
A
346 /* Check for too many digits.
347 */
348 if ((num_digits_scanned == VERS_STAGE_LEVEL_DIGITS) &&
349 ! (__vers_isspace(*current_char_p) || (*current_char_p == '\0'))) {
1c79356b 350
55e303ae
A
351 return -1;
352 }
1c79356b 353
55e303ae
A
354 if (vers_stage_level > 255) {
355 return -1;
356 }
1c79356b 357
55e303ae 358finish:
1c79356b 359
55e303ae
A
360 if (vers_stage == VERS_candidate && vers_stage_level == 0) {
361 return -1;
362 }
1c79356b 363
55e303ae
A
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) +
368 vers_stage_level;
1c79356b 369
55e303ae
A
370 return result;
371}
372
373#define VERS_STRING_MAX_LEN (16)
374
375PRIV_EXT
376int VERS_string(char * buffer, UInt32 length, VERS_version vers) {
377 int cpos = 0;
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;
2d21ac55 383 const char * stage_string = NULL; // don't free
55e303ae
A
384
385 /* No buffer or length less than longest possible vers string,
1c79356b
A
386 * return 0.
387 */
388 if (!buffer || length < VERS_STRING_MAX_LEN) {
55e303ae 389 return 0;
1c79356b
A
390 }
391
392 bzero(buffer, length * sizeof(char));
393
55e303ae 394 if (vers < 0) {
2d21ac55 395 strlcpy(buffer, "(invalid)", length);
55e303ae 396 return 1;
1c79356b
A
397 }
398
55e303ae 399 vers_major = vers / VERS_MAJOR_MULT;
1c79356b 400
55e303ae
A
401 vers_minor = vers - (vers_major * VERS_MAJOR_MULT);
402 vers_minor /= VERS_MINOR_MULT;
1c79356b 403
55e303ae
A
404 vers_revision = vers -
405 ( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) );
406 vers_revision /= VERS_REVISION_MULT;
1c79356b 407
55e303ae
A
408 vers_stage = vers -
409 ( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) +
410 (vers_revision * VERS_REVISION_MULT));
411 vers_stage /= VERS_STAGE_MULT;
412
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));
1c79356b 416
2d21ac55 417 cpos = snprintf(buffer, length, "%lu", (UInt32)vers_major);
1c79356b 418
55e303ae 419 /* Always include the minor version; it just looks weird without.
1c79356b
A
420 */
421 buffer[cpos] = '.';
422 cpos++;
2d21ac55 423 cpos += snprintf(buffer+cpos, length - cpos, "%lu", (UInt32)vers_minor);
1c79356b 424
55e303ae 425 /* The revision is displayed only if nonzero.
1c79356b 426 */
55e303ae 427 if (vers_revision) {
1c79356b
A
428 buffer[cpos] = '.';
429 cpos++;
2d21ac55
A
430 cpos += snprintf(buffer+cpos, length - cpos, "%lu",
431 (UInt32)vers_revision);
1c79356b
A
432 }
433
55e303ae
A
434 stage_string = __VERS_string_for_stage(vers_stage);
435 if (stage_string && stage_string[0]) {
2d21ac55 436 strlcat(buffer, stage_string, length);
55e303ae 437 cpos += strlen(stage_string);
1c79356b
A
438 }
439
55e303ae 440 if (vers_stage < VERS_release) {
2d21ac55 441 snprintf(buffer+cpos, length - cpos, "%lu", (UInt32)vers_stage_level);
1c79356b
A
442 }
443
55e303ae 444 return 1;
1c79356b 445}