]> git.saurik.com Git - apple/system_cmds.git/blob - kmodload.tproj/vers_rsrc.c
c10f288b5e3071974b70d9b2aac070a957dbf8da
[apple/system_cmds.git] / kmodload.tproj / vers_rsrc.c
1 #include "vers_rsrc.h"
2
3 int vers_isdigit(char c) {
4 return (c == '0' ||
5 c == '1' || c == '2' || c == '3' ||
6 c == '4' || c == '5' || c == '6' ||
7 c == '7' || c == '8' || c == '9');
8 }
9
10 int vers_isspace(char c) {
11 return (c == ' ' ||
12 c == '\t' ||
13 c == '\r' ||
14 c == '\n');
15 }
16
17
18 int isreleasestate(char c) {
19 return (c == 'd' || c == 'a' || c == 'b' || c == 'f');
20 }
21
22
23 UInt8 BCD_digit_for_char(char c) {
24 switch (c) {
25 case '0': return 0; break;
26 case '1': return 1; break;
27 case '2': return 2; break;
28 case '3': return 3; break;
29 case '4': return 4; break;
30 case '5': return 5; break;
31 case '6': return 6; break;
32 case '7': return 7; break;
33 case '8': return 8; break;
34 case '9': return 9; break;
35 default: return BCD_illegal; break;
36 }
37 return BCD_illegal;
38 }
39
40
41 char BCD_char_for_digit(UInt8 digit) {
42 switch (digit) {
43 case 0: return '0'; break;
44 case 1: return '1'; break;
45 case 2: return '2'; break;
46 case 3: return '3'; break;
47 case 4: return '4'; break;
48 case 5: return '5'; break;
49 case 6: return '6'; break;
50 case 7: return '7'; break;
51 case 8: return '8'; break;
52 case 9: return '9'; break;
53 default: return '?'; break;
54 }
55 return '?';
56 }
57
58
59 VERS_revision VERS_revision_for_string(char ** string_p) {
60 char * string;
61
62 if (!string_p || !*string_p) {
63 return VERS_invalid;
64 }
65
66 string = *string_p;
67
68 if (vers_isspace(string[0]) || string[0] == '\0') {
69 return VERS_release;
70 } else {
71 switch (string[0]) {
72 case 'd':
73 if (vers_isdigit(string[1])) {
74 *string_p = &string[1];
75 return VERS_development;
76 }
77 break;
78 case 'a':
79 if (vers_isdigit(string[1])) {
80 *string_p = &string[1];
81 return VERS_alpha;
82 }
83 break;
84 case 'b':
85 if (vers_isdigit(string[1])) {
86 *string_p = &string[1];
87 return VERS_beta;
88 }
89 break;
90 case 'f':
91 if (vers_isdigit(string[1])) {
92 *string_p = &string[1];
93 return VERS_candidate;
94 } else if (string[1] == 'c' && vers_isdigit(string[2])) {
95 *string_p = &string[2];
96 return VERS_candidate;
97 } else {
98 return VERS_invalid;
99 }
100 break;
101 default:
102 return VERS_invalid;
103 break;
104 }
105 }
106
107 return VERS_invalid;
108 }
109
110
111 int VERS_parse_string(char * vers_string, UInt32 * version_num) {
112 int result = 1;
113 VERS_version vers;
114 char * current_char_p;
115 UInt8 scratch;
116
117 if (!vers_string || *vers_string == '\0') {
118 return 0;
119 }
120
121 vers.vnum = 0;
122
123 current_char_p = &vers_string[0];
124
125
126 /*****
127 * Check for an initial digit of the major release number.
128 */
129 vers.bytes[0] = BCD_digit_for_char(*current_char_p);
130 if (vers.bytes[0] == BCD_illegal) {
131 return 0;
132 }
133
134 current_char_p++;
135
136
137 /*****
138 * Check for a second digit of the major release number.
139 */
140 if (*current_char_p == '\0') {
141 vers.bytes[2] = VERS_release;
142 vers.bytes[3] = 0xff;
143 goto finish;
144 } else if (vers_isdigit(*current_char_p)) {
145 scratch = BCD_digit_for_char(*current_char_p);
146 if (scratch == BCD_illegal) {
147 return 0;
148 }
149 vers.bytes[0] = BCD_combine(vers.bytes[0], scratch);
150 current_char_p++;
151
152 if (*current_char_p == '\0') {
153 vers.bytes[2] = VERS_release;
154 vers.bytes[3] = 0xff;
155 goto finish;
156 } else if (isreleasestate(*current_char_p)) {
157 goto release_state;
158 } else if (*current_char_p == '.') {
159 current_char_p++;
160 } else {
161 return 0;
162 }
163 } else if (isreleasestate(*current_char_p)) {
164 goto release_state;
165 } else if (*current_char_p == '.') {
166 current_char_p++;
167 } else {
168 return 0;
169 }
170
171
172 /*****
173 * Check for the minor release number.
174 */
175 if (*current_char_p == '\0') {
176 vers.bytes[2] = VERS_release;
177 vers.bytes[3] = 0xff;
178 goto finish;
179 } else if (vers_isdigit(*current_char_p)) {
180 vers.bytes[1] = BCD_digit_for_char(*current_char_p);
181 if (vers.bytes[1] == BCD_illegal) {
182 return 0;
183 }
184
185 // Make sure its the first nibble of byte 1!
186 vers.bytes[1] = BCD_combine(vers.bytes[1], 0);
187
188 current_char_p++;
189
190 if (*current_char_p == '\0') {
191 vers.bytes[2] = VERS_release;
192 vers.bytes[3] = 0xff;
193 goto finish;
194 } else if (isreleasestate(*current_char_p)) {
195 goto release_state;
196 } else if (*current_char_p == '.') {
197 current_char_p++;
198 } else {
199 return 0;
200 }
201 } else {
202 return 0;
203 }
204
205
206 /*****
207 * Check for the bugfix number.
208 */
209 if (*current_char_p == '\0') {
210 vers.bytes[2] = VERS_release;
211 vers.bytes[3] = 0xff;
212 goto finish;
213 } else if (vers_isdigit(*current_char_p)) {
214 scratch = BCD_digit_for_char(*current_char_p);
215 if (scratch == BCD_illegal) {
216 return 0;
217 }
218
219 /* vers.bytes[1] has its left nibble set already */
220 vers.bytes[1] = vers.bytes[1] | scratch;
221
222 current_char_p++;
223
224 if (*current_char_p == '\0') {
225 vers.bytes[2] = VERS_release;
226 vers.bytes[3] = 0xff;
227 goto finish;
228 } else if (isreleasestate(*current_char_p)) {
229 goto release_state;
230 } else {
231 return 0;
232 }
233 } else {
234 return 0;
235 }
236
237
238 release_state:
239
240 /*****
241 * Check for the release state.
242 */
243 if (*current_char_p == '\0') {
244 vers.bytes[2] = VERS_release;
245 vers.bytes[3] = 0xff;
246 goto finish;
247 } else {
248 vers.bytes[2] = VERS_revision_for_string(&current_char_p);
249 if (vers.bytes[2] == VERS_invalid) {
250 return 0;
251 }
252 }
253
254
255 /*****
256 * Get the nonrelease revision number (0..255).
257 */
258 if (vers.bytes[2] != VERS_release) {
259 UInt32 revision_num = 0;
260 int i;
261
262 if (*current_char_p == '\0' || !vers_isdigit(*current_char_p)) {
263 return 0;
264 }
265 for (i = 0; i < 3 && *current_char_p != '\0'; i++, current_char_p++) {
266 UInt8 scratch_digit;
267 scratch_digit = BCD_digit_for_char(*current_char_p);
268 if (scratch_digit == BCD_illegal) {
269 return 0;
270 }
271 revision_num *= 10;
272 revision_num += scratch_digit;
273 }
274 if (vers_isdigit(*current_char_p) || revision_num > 255) {
275 return 0;
276 }
277 vers.bytes[3] = (UInt8)revision_num;
278 }
279
280 if (vers.bytes[2] == VERS_release) {
281 vers.bytes[3] = 0xff;
282 } else {
283 if (vers.bytes[2] == VERS_candidate) {
284 if (vers.bytes[3] == 0) {
285 return 0;
286 } else {
287 vers.bytes[2] = VERS_release;
288 vers.bytes[3]--;
289 }
290 }
291 }
292
293 finish:
294 *version_num = CFSwapInt32BigToHost(vers.vnum);
295 return result;
296 }
297
298
299 #define VERS_STRING_MAX_LEN (12)
300
301 int VERS_string(char * buffer, UInt32 length, UInt32 vers) {
302 VERS_version version;
303 int cpos = 0;
304 int result = 1; // assume success
305
306 char major1;
307 char major2;
308 char minor;
309 char bugfix;
310
311 version.vnum = CFSwapInt32HostToBig(vers);
312
313 /* No buffer or length less than longest possible vers string,
314 * return 0.
315 */
316 if (!buffer || length < VERS_STRING_MAX_LEN) {
317 result = 0;
318 goto finish;
319 }
320
321 bzero(buffer, length * sizeof(char));
322
323
324 /*****
325 * Major version number.
326 */
327 major1 = BCD_char_for_digit(BCD_get_left(version.bytes[0]));
328 if (major1 == '?') {
329 result = 0;
330 } /* this is not an 'else' situation */
331 if (major1 != '0') {
332 buffer[cpos] = major1;
333 cpos++;
334 }
335
336 major2 = BCD_char_for_digit(BCD_get_right(version.bytes[0]));
337 if (major2 == '?') {
338 result = 0;
339 }
340
341 buffer[cpos] = major2;
342 cpos++;
343
344
345 /*****
346 * Minor & bug-fix version numbers.
347 */
348 minor = BCD_char_for_digit(BCD_get_left(version.bytes[1]));
349 if (minor == '?') {
350 result = 0;
351 }
352 bugfix = BCD_char_for_digit(BCD_get_right(version.bytes[1]));
353 if (bugfix == '?') {
354 result = 0;
355 }
356
357
358 /* Always display the minor version number.
359 */
360 buffer[cpos] = '.';
361 cpos++;
362 buffer[cpos] = minor;
363 cpos++;
364
365
366 /* Only display the bugfix version number if it's nonzero.
367 */
368 if (bugfix != '0') {
369 buffer[cpos] = '.';
370 cpos++;
371 buffer[cpos] = bugfix;
372 cpos++;
373 }
374
375
376 /* If the release state is final, we're done!
377 */
378 if (version.bytes[2] == VERS_release && version.bytes[3] == 255) {
379 goto finish;
380 }
381
382
383 /*****
384 * Do the release state and update level.
385 */
386 switch (version.bytes[2]) {
387 case VERS_development:
388 buffer[cpos] = 'd';
389 cpos++;
390 break;
391 case VERS_alpha:
392 buffer[cpos] = 'a';
393 cpos++;
394 break;
395 case VERS_beta:
396 buffer[cpos] = 'b';
397 cpos++;
398 break;
399 case VERS_release:
400 if (version.bytes[3] < 255) {
401 buffer[cpos] = 'f';
402 buffer[cpos+1] = 'c';
403 cpos += 2;
404 } else {
405 goto finish;
406 }
407 break;
408 default:
409 result = 0;
410 buffer[cpos] = '?';
411 cpos++;
412 break;
413 }
414
415 if (version.bytes[2] != VERS_release) {
416 sprintf(&buffer[cpos], "%d", version.bytes[3]);
417 } else {
418 if (version.bytes[3] < 255) {
419 sprintf(&buffer[cpos], "%d", version.bytes[3] + 1);
420 }
421 }
422
423 finish:
424 return result;
425 }