]> git.saurik.com Git - apple/xnu.git/blob - libsa/vers_rsrc.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / libsa / vers_rsrc.c
1 #ifndef KERNEL
2 #include <libc.h>
3 #include "vers_rsrc.h"
4 #else
5 #include <sys/systm.h>
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
26 typedef 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
36 static int __vers_isdigit(char c) {
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
43 static int __vers_isspace(char c) {
44 return (c == ' ' ||
45 c == '\t' ||
46 c == '\r' ||
47 c == '\n');
48 }
49
50 static int __vers_digit_for_char(char c) {
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;
62 default: return -1; break;
63 }
64
65 return -1;
66 }
67
68 static int __VERS_isreleasestate(char c) {
69 return (c == 'd' || c == 'a' || c == 'b' || c == 'f');
70 }
71
72
73 static VERS_stage __VERS_stage_for_string(char ** string_p) {
74 char * string;
75
76 if (!string_p || !*string_p) {
77 return VERS_invalid;
78 }
79
80 string = *string_p;
81
82 if (__vers_isspace(string[0]) || string[0] == '\0') {
83 return VERS_release;
84 } else {
85 switch (string[0]) {
86 case 'd':
87 if (__vers_isdigit(string[1])) {
88 *string_p = &string[1];
89 return VERS_development;
90 }
91 break;
92 case 'a':
93 if (__vers_isdigit(string[1])) {
94 *string_p = &string[1];
95 return VERS_alpha;
96 }
97 break;
98 case 'b':
99 if (__vers_isdigit(string[1])) {
100 *string_p = &string[1];
101 return VERS_beta;
102 }
103 break;
104 case 'f':
105 if (__vers_isdigit(string[1])) {
106 *string_p = &string[1];
107 return VERS_candidate;
108 } else if (string[1] == 'c' && __vers_isdigit(string[2])) {
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
124 static 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 }
133
134 return "?";
135 }
136
137 PRIV_EXT
138 VERS_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;
148
149 if (!vers_string || *vers_string == '\0') {
150 return -1;
151 }
152
153 current_char_p = (char *)&vers_string[0];
154
155 /*****
156 * Check for an initial digit of the major release number.
157 */
158 vers_major = __vers_digit_for_char(*current_char_p);
159 if (vers_major < 0) {
160 return -1;
161 }
162
163 current_char_p++;
164 num_digits_scanned = 1;
165
166 /* Complete scan for major version number. Legal characters are
167 * any digit, period, any buildstage letter.
168 */
169 while (num_digits_scanned < VERS_MAJOR_DIGITS) {
170 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
171 vers_stage = VERS_release;
172 goto finish;
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)) {
182 goto release_state;
183 } else if (*current_char_p == '.') {
184 current_char_p++;
185 goto minor_version;
186 } else {
187 return -1;
188 }
189 }
190
191 /* Check for too many digits.
192 */
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;
198 }
199 }
200
201 minor_version:
202
203 num_digits_scanned = 0;
204
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;
211 goto finish;
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)) {
221 goto release_state;
222 } else if (*current_char_p == '.') {
223 current_char_p++;
224 goto revision;
225 } else {
226 return -1;
227 }
228 }
229
230 /* Check for too many digits.
231 */
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;
237 }
238 }
239
240 revision:
241
242 num_digits_scanned = 0;
243
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;
250 goto finish;
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)) {
260 goto release_state;
261 } else {
262 return -1;
263 }
264 }
265
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 }
275
276 release_state:
277
278 /*****
279 * Check for the release state.
280 */
281 if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
282 vers_stage = VERS_release;
283 goto finish;
284 } else {
285 vers_stage = __VERS_stage_for_string(&current_char_p);
286 if (vers_stage == VERS_invalid) {
287 return -1;
288 }
289 }
290
291
292 // stage level
293
294 num_digits_scanned = 0;
295
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;
303 } else {
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;
310 }
311 vers_stage_level = (vers_stage_level) * 10 + vers_digit;
312 current_char_p++;
313 num_digits_scanned++;
314 } else {
315 return -1;
316 }
317 }
318
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'))) {
323
324 return -1;
325 }
326
327 if (vers_stage_level > 255) {
328 return -1;
329 }
330
331 finish:
332
333 if (vers_stage == VERS_candidate && vers_stage_level == 0) {
334 return -1;
335 }
336
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;
342
343 return result;
344 }
345
346 #define VERS_STRING_MAX_LEN (16)
347
348 PRIV_EXT
349 int 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,
359 * return 0.
360 */
361 if (!buffer || length < VERS_STRING_MAX_LEN) {
362 return 0;
363 }
364
365 bzero(buffer, length * sizeof(char));
366
367 if (vers < 0) {
368 strcpy(buffer, "(invalid)");
369 return 1;
370 }
371
372 vers_major = vers / VERS_MAJOR_MULT;
373
374 vers_minor = vers - (vers_major * VERS_MAJOR_MULT);
375 vers_minor /= VERS_MINOR_MULT;
376
377 vers_revision = vers -
378 ( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) );
379 vers_revision /= VERS_REVISION_MULT;
380
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));
389
390 cpos = sprintf(buffer, "%lu", (UInt32)vers_major);
391
392 /* Always include the minor version; it just looks weird without.
393 */
394 buffer[cpos] = '.';
395 cpos++;
396 cpos += sprintf(buffer+cpos, "%lu", (UInt32)vers_minor);
397
398 /* The revision is displayed only if nonzero.
399 */
400 if (vers_revision) {
401 buffer[cpos] = '.';
402 cpos++;
403 cpos += sprintf(buffer+cpos, "%lu", (UInt32)vers_revision);
404 }
405
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);
410 }
411
412 if (vers_stage < VERS_release) {
413 sprintf(buffer+cpos, "%lu", (UInt32)vers_stage_level);
414 }
415
416 return 1;
417 }