-#include <libsa/vers_rsrc.h>
+#ifndef KERNEL
+#include <libc.h>
+#include "vers_rsrc.h"
+#else
#include <sys/systm.h>
-
-
-int isdigit(char c) {
+#include <libsa/vers_rsrc.h>
+#endif /* not KERNEL */
+
+#ifndef KERNEL
+#define PRIV_EXT
+#else
+#define PRIV_EXT __private_extern__
+#endif /* not KERNEL */
+
+#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');
}
-int isspace(char c) {
+static int __vers_isspace(char c) {
return (c == ' ' ||
c == '\t' ||
c == '\r' ||
c == '\n');
}
-
-int isreleasestate(char c) {
- return (c == 'd' || c == 'a' || c == 'b' || c == 'f');
-}
-
-
-UInt8 BCD_digit_for_char(char c) {
+static int __vers_digit_for_char(char c) {
switch (c) {
case '0': return 0; break;
case '1': return 1; break;
case '7': return 7; break;
case '8': return 8; break;
case '9': return 9; break;
- default: return BCD_illegal; break;
+ default: return -1; break;
}
- return BCD_illegal;
-}
+ return -1;
+}
-char BCD_char_for_digit(UInt8 digit) {
- switch (digit) {
- 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 '?'; break;
- }
- return '?';
+static int __VERS_isreleasestate(char c) {
+ return (c == 'd' || c == 'a' || c == 'b' || c == 'f');
}
-VERS_revision VERS_revision_for_string(char ** string_p) {
+static VERS_stage __VERS_stage_for_string(char ** string_p) {
char * string;
if (!string_p || !*string_p) {
string = *string_p;
- if (isspace(string[0]) || string[0] == '\0') {
+ if (__vers_isspace(string[0]) || string[0] == '\0') {
return VERS_release;
} else {
switch (string[0]) {
case 'd':
- if (isdigit(string[1])) {
+ if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_development;
}
break;
case 'a':
- if (isdigit(string[1])) {
+ if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_alpha;
}
break;
case 'b':
- if (isdigit(string[1])) {
+ if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_beta;
}
break;
case 'f':
- if (isdigit(string[1])) {
+ if (__vers_isdigit(string[1])) {
*string_p = &string[1];
return VERS_candidate;
- } else if (string[1] == 'c' && isdigit(string[2])) {
+ } else if (string[1] == 'c' && __vers_isdigit(string[2])) {
*string_p = &string[2];
return VERS_candidate;
} else {
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;
+ }
-int VERS_parse_string(const char * vers_string, UInt32 * version_num) {
- int result = 1;
- VERS_version vers;
+ 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;
- UInt8 scratch;
if (!vers_string || *vers_string == '\0') {
- return 0;
+ return -1;
}
- vers.vnum = 0;
-
- current_char_p = &vers_string[0];
-
+ current_char_p = (char *)&vers_string[0];
/*****
* Check for an initial digit of the major release number.
*/
- vers.bytes[0] = BCD_digit_for_char(*current_char_p);
- if (vers.bytes[0] == BCD_illegal) {
- return 0;
+ vers_major = __vers_digit_for_char(*current_char_p);
+ if (vers_major < 0) {
+ return -1;
}
current_char_p++;
+ num_digits_scanned = 1;
-
- /*****
- * Check for a second digit of the major release number.
+ /* Complete scan for major version number. Legal characters are
+ * any digit, period, any buildstage letter.
*/
- if (*current_char_p == '\0') {
- vers.bytes[2] = VERS_release;
- vers.bytes[3] = 0xff;
- goto finish;
- } else if (isdigit(*current_char_p)) {
- scratch = BCD_digit_for_char(*current_char_p);
- if (scratch == BCD_illegal) {
- return 0;
- }
- vers.bytes[0] = BCD_combine(vers.bytes[0], scratch);
- current_char_p++;
-
- if (*current_char_p == '\0') {
- vers.bytes[2] = VERS_release;
- vers.bytes[3] = 0xff;
+ 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 (isreleasestate(*current_char_p)) {
+ } 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 0;
+ return -1;
}
- } else if (isreleasestate(*current_char_p)) {
- goto release_state;
- } else if (*current_char_p == '.') {
- current_char_p++;
- } else {
- return 0;
}
-
- /*****
- * Check for the minor release number.
+ /* Check for too many digits.
*/
- if (*current_char_p == '\0') {
- vers.bytes[2] = VERS_release;
- vers.bytes[3] = 0xff;
- goto finish;
- } else if (isdigit(*current_char_p)) {
- vers.bytes[1] = BCD_digit_for_char(*current_char_p);
- if (vers.bytes[1] == BCD_illegal) {
- return 0;
+ if (num_digits_scanned == VERS_MAJOR_DIGITS) {
+ if (*current_char_p == '.') {
+ current_char_p++;
+ } else if (__vers_isdigit(*current_char_p)) {
+ return -1;
}
+ }
- // Make sure its the first nibble of byte 1!
- vers.bytes[1] = BCD_combine(vers.bytes[1], 0);
+minor_version:
- current_char_p++;
+ num_digits_scanned = 0;
- if (*current_char_p == '\0') {
- vers.bytes[2] = VERS_release;
- vers.bytes[3] = 0xff;
+ /* Scan for minor version number. Legal characters are
+ * any digit, period, any buildstage letter.
+ */
+ 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 (isreleasestate(*current_char_p)) {
+ } 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 0;
+ return -1;
}
- } else {
- return 0;
}
-
- /*****
- * Check for the bugfix number.
+ /* Check for too many digits.
*/
- if (*current_char_p == '\0') {
- vers.bytes[2] = VERS_release;
- vers.bytes[3] = 0xff;
- goto finish;
- } else if (isdigit(*current_char_p)) {
- scratch = BCD_digit_for_char(*current_char_p);
- if (scratch == BCD_illegal) {
- return 0;
+ if (num_digits_scanned == VERS_MINOR_DIGITS) {
+ if (*current_char_p == '.') {
+ current_char_p++;
+ } else if (__vers_isdigit(*current_char_p)) {
+ return -1;
}
+ }
- /* vers.bytes[1] has its left nibble set already */
- vers.bytes[1] = vers.bytes[1] | scratch;
+revision:
- current_char_p++;
+ num_digits_scanned = 0;
- if (*current_char_p == '\0') {
- vers.bytes[2] = VERS_release;
- vers.bytes[3] = 0xff;
+ /* Scan for revision version number. Legal characters are
+ * any digit, any buildstage letter (NOT PERIOD).
+ */
+ 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 (isreleasestate(*current_char_p)) {
+ } 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 0;
+ return -1;
}
- } else {
- return 0;
}
+ /* Check for too many digits.
+ */
+ 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:
/*****
* Check for the release state.
*/
- if (*current_char_p == '\0') {
- vers.bytes[2] = VERS_release;
- vers.bytes[3] = 0xff;
+ if (__vers_isspace(*current_char_p) || *current_char_p == '\0') {
+ vers_stage = VERS_release;
goto finish;
} else {
- vers.bytes[2] = VERS_revision_for_string(¤t_char_p);
- if (vers.bytes[2] == VERS_invalid) {
- return 0;
+ vers_stage = __VERS_stage_for_string(¤t_char_p);
+ if (vers_stage == VERS_invalid) {
+ return -1;
}
}
- /*****
- * Get the nonrelease revision number (0..255).
- */
- if (vers.bytes[2] != VERS_release) {
- UInt32 revision_num = 0;
- int i;
+// stage level
- if (*current_char_p == '\0' || !isdigit(*current_char_p)) {
- return 0;
- }
- for (i = 0; i < 3 && *current_char_p != '\0'; i++, current_char_p++) {
- UInt8 scratch_digit;
- scratch_digit = BCD_digit_for_char(*current_char_p);
- if (scratch_digit == BCD_illegal) {
- return 0;
- }
- revision_num *= 10;
- revision_num += scratch_digit;
- }
- if (isdigit(*current_char_p) || revision_num > 255) {
- return 0;
- }
- vers.bytes[3] = (UInt8)revision_num;
- }
+ num_digits_scanned = 0;
- if (vers.bytes[2] == VERS_release) {
- vers.bytes[3] = 0xff;
- } else {
- if (vers.bytes[2] == VERS_candidate) {
- if (vers.bytes[3] == 0) {
- return 0;
+ /* Scan for stage level number. Legal characters are
+ * any digit only.
+ */
+ 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 {
- vers.bytes[2] = VERS_release;
- vers.bytes[3]--;
+ 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;
}
}
-finish:
- *version_num = vers.vnum;
- return result;
-}
+ /* Check for too many digits.
+ */
+ if ((num_digits_scanned == VERS_STAGE_LEVEL_DIGITS) &&
+ ! (__vers_isspace(*current_char_p) || (*current_char_p == '\0'))) {
+ return -1;
+ }
-#define VERS_STRING_MAX_LEN (12)
+ if (vers_stage_level > 255) {
+ return -1;
+ }
-int VERS_string(char * buffer, UInt32 length, UInt32 vers) {
- VERS_version version;
- int cpos = 0;
- int result = 1;
+finish:
- char major1;
- char major2;
- char minor;
- char bugfix;
+ if (vers_stage == VERS_candidate && vers_stage_level == 0) {
+ return -1;
+ }
- version.vnum = vers;
+ result = (vers_major * VERS_MAJOR_MULT) +
+ (vers_minor * VERS_MINOR_MULT) +
+ (vers_revision * VERS_REVISION_MULT) +
+ (vers_stage * VERS_STAGE_MULT) +
+ vers_stage_level;
- /* No buffer, length less than longest possible vers string,
+ 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; // don't free
+
+ /* No buffer or length less than longest possible vers string,
* return 0.
*/
if (!buffer || length < VERS_STRING_MAX_LEN) {
- result = -1;
- goto finish;
+ return 0;
}
bzero(buffer, length * sizeof(char));
-
- /*****
- * Major version number.
- */
- major1 = BCD_char_for_digit(BCD_get_left(version.bytes[0]));
- if (major1 == '?') {
- result = 0;
- } /* this is not an 'else' situation */
- if (major1 != '0') {
- buffer[cpos] = major1;
- cpos++;
+ if (vers < 0) {
+ strcpy(buffer, "(invalid)");
+ return 1;
}
- major2 = BCD_char_for_digit(BCD_get_right(version.bytes[0]));
- if (major2 == '?') {
- result = 0;
- }
+ vers_major = vers / VERS_MAJOR_MULT;
- buffer[cpos] = major2;
- cpos++;
+ 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;
- /*****
- * Minor & bug-fix version numbers.
- */
- minor = BCD_char_for_digit(BCD_get_left(version.bytes[1]));
- if (minor == '?') {
- result = 0;
- }
- bugfix = BCD_char_for_digit(BCD_get_right(version.bytes[1]));
- if (bugfix == '?') {
- result = 0;
- }
+ 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);
- /* Always display the minor version number.
+ /* Always include the minor version; it just looks weird without.
*/
buffer[cpos] = '.';
cpos++;
- buffer[cpos] = minor;
- cpos++;
+ cpos += sprintf(buffer+cpos, "%lu", (UInt32)vers_minor);
-
- /* Only display the bugfix version number if it's nonzero.
+ /* The revision is displayed only if nonzero.
*/
- if (bugfix != '0') {
+ if (vers_revision) {
buffer[cpos] = '.';
cpos++;
- buffer[cpos] = bugfix;
- cpos++;
- }
-
-
- /* If the release state is final, we're done!
- */
- if (version.bytes[2] == VERS_release && version.bytes[3] == 255) {
- result = 0;
- goto finish;
+ cpos += sprintf(buffer+cpos, "%lu", (UInt32)vers_revision);
}
-
- /*****
- * Do the release state and update level.
- */
- switch (version.bytes[2]) {
- case VERS_development:
- buffer[cpos] = 'd';
- cpos++;
- break;
- case VERS_alpha:
- buffer[cpos] = 'a';
- cpos++;
- break;
- case VERS_beta:
- buffer[cpos] = 'b';
- cpos++;
- break;
- case VERS_release:
- if (version.bytes[3] < 255) {
- buffer[cpos] = 'f';
- buffer[cpos+1] = 'c';
- cpos += 2;
- } else {
- result = 1;
- goto finish;
- }
- break;
- default:
- result = 0;
- buffer[cpos] = '?';
- cpos++;
- break;
+ stage_string = __VERS_string_for_stage(vers_stage);
+ if (stage_string && stage_string[0]) {
+ strcat(buffer, stage_string);
+ cpos += strlen(stage_string);
}
- if (version.bytes[2] != VERS_release) {
- sprintf(&buffer[cpos], "%d", version.bytes[3]);
- } else {
- if (version.bytes[3] < 255) {
- sprintf(&buffer[cpos], "%d", version.bytes[3] + 1);
- }
+ if (vers_stage < VERS_release) {
+ sprintf(buffer+cpos, "%lu", (UInt32)vers_stage_level);
}
-finish:
- return result;
+ return 1;
}