aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2020-05-21 17:26:05 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2020-05-21 17:26:05 -0400
commite5efe3dfa398113914e64b5a0f9ee336ed078c62 (patch)
treefbd03136c5507763aa85c8f953d562233a404d3d /lib
parent9bea6ce0c5afd40b4c6dfd2b9d935dab4408e2eb (diff)
downloadspmc-e5efe3dfa398113914e64b5a0f9ee336ed078c62.tar.gz
Rewrite version_from() to be input agnostic
Diffstat (limited to 'lib')
-rw-r--r--lib/version_spec.c144
1 files changed, 137 insertions, 7 deletions
diff --git a/lib/version_spec.c b/lib/version_spec.c
index 48273ef..928fc0f 100644
--- a/lib/version_spec.c
+++ b/lib/version_spec.c
@@ -28,10 +28,11 @@ char *version_suffix_get_alpha(char *str) {
char *version_suffix_get_modifier(char *str) {
size_t i;
char *modifiers[] = {
- "rc",
- "pre",
- "dev",
- "post",
+ "r", // VCS revision
+ "rc", // Release Candidate
+ "pre", // Pre-Release
+ "dev", // Development
+ "post", // Post-Release
NULL,
};
for (i = 0; i < strlen(str); i++) {
@@ -132,19 +133,145 @@ int version_suffix_alpha_calc(char *str) {
ch++;
continue;
}
- x += atoi(ch);
+ x += (int)strtol(ch, NULL, 10);
break;
}
return x;
}
+static int isdigits(char *s) {
+ for (size_t i = 0; s[i] != '\0'; i++) {
+ if (isdigit(s[i]) == 0) {
+ return 0; // non-digit found, fail
+ }
+ }
+ return 1; // all digits, succeed
+}
+
+static int reindex(char c) {
+ int result = c - '0';
+ return result;
+}
+
+static char *tolower_s(char *s) {
+ for (size_t i = 0; s[i] != '\0'; i++) {
+ s[i] = tolower(s[i]);
+ }
+ return s;
+}
+
+/**
+ * Convert a string (`x.y.z.nnnn` or `1abcdefg2` - doesn't matter) to an integer
+ * @param s
+ * @return
+ */
+uint64_t version_from(const char *str) {
+ uint64_t result;
+ uint64_t addendum;
+ char *vstr;
+ char *result_tmp;
+ char **part;
+ StrList *vconv;
+
+ // Check input string isn't NULL
+ if (str == NULL) {
+ return 0;
+ }
+
+ // Make a copy of the input string
+ vstr = strdup(str);
+ if (vstr == NULL) {
+ spmerrno = errno;
+ return 0;
+ }
+
+ // Initialize StrList
+ vconv = strlist_init();
+ if (vconv == NULL) {
+ spmerrno = errno;
+ return 0;
+ }
+
+ // Convert any uppercase letters to lowercase
+ vstr = tolower_s(vstr);
+
+ // Pop local version suffix
+ char *local_version = strstr(vstr, VERSION_LOCAL);
+ if (local_version != NULL) {
+ *local_version = '\0';
+ }
+
+ // Split version string on periods, if any
+ part = split(vstr, VERSION_DELIM);
+ if (part == NULL) {
+ spmerrno = errno;
+ return 0;
+ }
+
+ // Populate our StrList with version information
+ for (size_t i = 0; part[i] != NULL; i++) {
+ char tmp[255] = {0};
+ memset(tmp, '\0', sizeof(tmp));
+
+ if (isdigits(part[i])) {
+ // Every character in the string is a digit, so append it as-is
+ strlist_append(vconv, part[i]);
+ } else {
+ // Not all characters were digits
+ char *data = part[i];
+ int digit = isdigit(*data);
+
+ // The first character is a digit. Try to consume the whole value
+ if (digit > 0) {
+ for (size_t ch = 0; *data != '\0' && isdigit(*data) > 0; ch++, data++) {
+ tmp[ch] = *data;
+ }
+ strlist_append(vconv, tmp);
+ }
+
+ while (*data != '\0') {
+ // The "+" prefix below indicates the value shall be added to the addendum
+ // Not a digit so subtract its ASCII value from '0' with reindex
+ // Calculate character index + 1 (i.e. a=1, b=2, ..., z=25)
+ sprintf(tmp, "+%d", reindex(*data) + 1);
+
+ strlist_append(vconv, tmp);
+ data++;
+ }
+ }
+ }
+ split_free(part);
+
+ // Construct the suffix portion of the version. This value is added to the result to maximize
+ // the resolution between different versions (making (1.1.0a > 1.1.0 && 1.1.1 > 1.1.0a) possible)
+ addendum = 0L;
+ for (size_t i = 0; i < strlist_count(vconv); i++) {
+ char *item = strlist_item(vconv, i);
+ if (*item == '+') {
+ addendum += strtoull(&item[1], NULL, VERSION_BASE);
+ // Purge this record from the StrList now that it has fulfilled its purpose
+ strlist_remove(vconv, i);
+ i--;
+ }
+ }
+
+ result_tmp = join(vconv->data, "");
+
+ result = strtoull(result_tmp, NULL, VERSION_BASE);
+ result <<= VERSION_ADDENDUM_BITS;
+ result += addendum + strlen(result_tmp);
+
+ free(vstr);
+ strlist_free(vconv);
+ return result;
+}
/**
*
* @param version_str
* @return
*/
-int64_t version_from(const char *version_str) {
+int64_t version_from_old(const char *version_str) {
const char *delim = ".";
int64_t result = 0;
if (version_str == NULL) {
@@ -172,6 +299,9 @@ int64_t version_from(const char *version_str) {
int64_t tmp = 0;
// populate the head (numeric characters)
+ int has_digit = isdigit(*x);
+ int has_alpha = isalpha(*x);
+
strncpy(head, x, strlen(x));
for (size_t i = 0; i < strlen(head); i++) {
if (isalpha(head[i])) {
@@ -202,7 +332,7 @@ int64_t version_from(const char *version_str) {
}
// Convert the head to an integer
- tmp = atoi(head);
+ tmp = strtoul(head, NULL, 10);
// Update result. Each portion of the numeric version is its own byte
// Version PARTS are limited to 255
result = result << 8 | tmp;