#ifndef KERNEL
#include <libc.h>
#include "vers_rsrc.h"
#else
#include <sys/systm.h>
#include <libsa/vers_rsrc.h>
#endif
#ifndef KERNEL
#define PRIV_EXT
#else
#define PRIV_EXT __private_extern__
#endif
#define VERS_MAJOR_DIGITS (4)
#define VERS_MINOR_DIGITS (2)
#define VERS_REVISION_DIGITS (2)
#define VERS_STAGE_DIGITS (1)
#define VERS_STAGE_LEVEL_DIGITS (3)
#define VERS_MAJOR_MULT (100000000)
#define VERS_MINOR_MULT (1000000)
#define VERS_REVISION_MULT (10000)
#define VERS_STAGE_MULT (1000)
typedef enum {
VERS_invalid = 0,
VERS_development = 1,
VERS_alpha = 3,
VERS_beta = 5,
VERS_candidate = 7,
VERS_release = 9,
} VERS_stage;
static int __vers_isdigit(char c) {
return (c == '0' ||
c == '1' || c == '2' || c == '3' ||
c == '4' || c == '5' || c == '6' ||
c == '7' || c == '8' || c == '9');
}
static int __vers_isspace(char c) {
return (c == ' ' ||
c == '\t' ||
c == '\r' ||
c == '\n');
}
static int __vers_digit_for_char(char c) {
switch (c) {
case '0': return 0; break;
case '1': return 1; break;
case '2': return 2; break;
case '3': return 3; break;
case '4': return 4; break;
case '5': return 5; break;
case '6': return 6; break;
case '7': return 7; break;
case '8': return 8; break;
case '9': return 9; break;
default: return -1; break;
}
return -1;
}
static int __VERS_isreleasestate(char c) {
return (c == 'd' || c == 'a' || c == 'b' || c == 'f');
}
static VERS_stage __VERS_stage_for_string(char ** string_p) {
char * string;
if (!string_p || !*string_p) {
return VERS_invalid;
}
string = *string_p;
if (__vers_isspace(string[0]) || string[0] == '\0') {
return VERS_release;
} else {
switch (string[0]) {
case 'd':
if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_development;
}
break;
case 'a':
if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_alpha;
}
break;
case 'b':
if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_beta;
}
break;
case 'f':
if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_candidate;
} else if (string[1] == 'c' && __vers_isdigit(string[2])) {
*string_p = &string[2];
return VERS_candidate;
} else {
return VERS_invalid;
}
break;
default:
return VERS_invalid;
break;
}
}
return VERS_invalid;
}
static char * __VERS_string_for_stage(VERS_stage stage) {
switch (stage) {
case VERS_invalid: return "?"; break;
case VERS_development: return "d"; break;
case VERS_alpha: return "a"; break;
case VERS_beta: return "b"; break;
case VERS_candidate: return "f"; break;
case VERS_release: return ""; break;
}
return "?";
}
PRIV_EXT
VERS_version VERS_parse_string(const char * vers_string) {
VERS_version result = -1;
int vers_digit = -1;
int num_digits_scanned = 0;
VERS_version vers_major = 0;
VERS_version vers_minor = 0;
VERS_version vers_revision = 0;
VERS_version vers_stage = 0;
VERS_version vers_stage_level = 0;
char * current_char_p;
if (!vers_string || *vers_string == '\0') {
return -1;
}
current_char_p = (char *)&vers_string[0];
vers_major = __vers_digit_for_char(*current_char_p);
if (vers_major < 0) {
return -1;
}
current_char_p++;
num_digits_scanned = 1;
while (num_digits_scanned < VERS_MAJOR_DIGITS) {
if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
vers_stage = VERS_release;
goto finish;
} else if (__vers_isdigit(*current_char_p)) {
vers_digit = __vers_digit_for_char(*current_char_p);
if (vers_digit < 0) {
return -1;
}
vers_major = (vers_major) * 10 + vers_digit;
current_char_p++;
num_digits_scanned++;
} else if (__VERS_isreleasestate(*current_char_p)) {
goto release_state;
} else if (*current_char_p == '.') {
current_char_p++;
goto minor_version;
} else {
return -1;
}
}
if (num_digits_scanned == VERS_MAJOR_DIGITS) {
if (*current_char_p == '.') {
current_char_p++;
} else if (__vers_isdigit(*current_char_p)) {
return -1;
}
}
minor_version:
num_digits_scanned = 0;
while (num_digits_scanned < VERS_MINOR_DIGITS) {
if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
vers_stage = VERS_release;
goto finish;
} else if (__vers_isdigit(*current_char_p)) {
vers_digit = __vers_digit_for_char(*current_char_p);
if (vers_digit < 0) {
return -1;
}
vers_minor = (vers_minor) * 10 + vers_digit;
current_char_p++;
num_digits_scanned++;
} else if (__VERS_isreleasestate(*current_char_p)) {
goto release_state;
} else if (*current_char_p == '.') {
current_char_p++;
goto revision;
} else {
return -1;
}
}
if (num_digits_scanned == VERS_MINOR_DIGITS) {
if (*current_char_p == '.') {
current_char_p++;
} else if (__vers_isdigit(*current_char_p)) {
return -1;
}
}
revision:
num_digits_scanned = 0;
while (num_digits_scanned < VERS_REVISION_DIGITS) {
if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
vers_stage = VERS_release;
goto finish;
} else if (__vers_isdigit(*current_char_p)) {
vers_digit = __vers_digit_for_char(*current_char_p);
if (vers_digit < 0) {
return -1;
}
vers_revision = (vers_revision) * 10 + vers_digit;
current_char_p++;
num_digits_scanned++;
} else if (__VERS_isreleasestate(*current_char_p)) {
goto release_state;
} else {
return -1;
}
}
if (num_digits_scanned == VERS_REVISION_DIGITS) {
if (*current_char_p == '.') {
current_char_p++;
} else if (__vers_isdigit(*current_char_p)) {
return -1;
}
}
release_state:
if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
vers_stage = VERS_release;
goto finish;
} else {
vers_stage = __VERS_stage_for_string(¤t_char_p);
if (vers_stage == VERS_invalid) {
return -1;
}
}
num_digits_scanned = 0;
while (num_digits_scanned < VERS_STAGE_LEVEL_DIGITS) {
if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
if (num_digits_scanned) {
goto finish;
} else {
return -1;
}
} else if (__vers_isdigit(*current_char_p)) {
vers_digit = __vers_digit_for_char(*current_char_p);
if (vers_digit < 0) {
return -1;
}
vers_stage_level = (vers_stage_level) * 10 + vers_digit;
current_char_p++;
num_digits_scanned++;
} else {
return -1;
}
}
if ((num_digits_scanned == VERS_STAGE_LEVEL_DIGITS) &&
! (__vers_isspace(*current_char_p) || (*current_char_p == '\0'))) {
return -1;
}
if (vers_stage_level > 255) {
return -1;
}
finish:
if (vers_stage == VERS_candidate && vers_stage_level == 0) {
return -1;
}
result = (vers_major * VERS_MAJOR_MULT) +
(vers_minor * VERS_MINOR_MULT) +
(vers_revision * VERS_REVISION_MULT) +
(vers_stage * VERS_STAGE_MULT) +
vers_stage_level;
return result;
}
#define VERS_STRING_MAX_LEN (16)
PRIV_EXT
int VERS_string(char * buffer, UInt32 length, VERS_version vers) {
int cpos = 0;
VERS_version vers_major = 0;
VERS_version vers_minor = 0;
VERS_version vers_revision = 0;
VERS_version vers_stage = 0;
VERS_version vers_stage_level = 0;
char * stage_string = NULL;
if (!buffer || length < VERS_STRING_MAX_LEN) {
return 0;
}
bzero(buffer, length * sizeof(char));
if (vers < 0) {
strcpy(buffer, "(invalid)");
return 1;
}
vers_major = vers / VERS_MAJOR_MULT;
vers_minor = vers - (vers_major * VERS_MAJOR_MULT);
vers_minor /= VERS_MINOR_MULT;
vers_revision = vers -
( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) );
vers_revision /= VERS_REVISION_MULT;
vers_stage = vers -
( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) +
(vers_revision * VERS_REVISION_MULT));
vers_stage /= VERS_STAGE_MULT;
vers_stage_level = vers -
( (vers_major * VERS_MAJOR_MULT) + (vers_minor * VERS_MINOR_MULT) +
(vers_revision * VERS_REVISION_MULT) + (vers_stage * VERS_STAGE_MULT));
cpos = sprintf(buffer, "%lu", (UInt32)vers_major);
buffer[cpos] = '.';
cpos++;
cpos += sprintf(buffer+cpos, "%lu", (UInt32)vers_minor);
if (vers_revision) {
buffer[cpos] = '.';
cpos++;
cpos += sprintf(buffer+cpos, "%lu", (UInt32)vers_revision);
}
stage_string = __VERS_string_for_stage(vers_stage);
if (stage_string && stage_string[0]) {
strcat(buffer, stage_string);
cpos += strlen(stage_string);
}
if (vers_stage < VERS_release) {
sprintf(buffer+cpos, "%lu", (UInt32)vers_stage_level);
}
return 1;
}