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