aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@users.noreply.github.com>2020-05-21 19:10:14 -0400
committerGitHub <noreply@github.com>2020-05-21 19:10:14 -0400
commit03e39ae5dcd4002ac9657a550c48b8e9f85c449c (patch)
tree7c266ca17a16d4c9ca297fa402a0a9d2ee6f871f /lib
parent3b323fcc82d3d06d671c55c2b77f74558706420e (diff)
parent86b2a55574f53c6e175de8cf745d2e67308b612e (diff)
downloadspmc-03e39ae5dcd4002ac9657a550c48b8e9f85c449c.tar.gz
Merge pull request #36 from jhunkeler/messing-around
Version parsing and Darwin bugfix
Diffstat (limited to 'lib')
-rw-r--r--lib/mime.c52
-rw-r--r--lib/strlist.c22
-rw-r--r--lib/version_spec.c144
3 files changed, 199 insertions, 19 deletions
diff --git a/lib/mime.c b/lib/mime.c
index 9d0205c..12e8cf4 100644
--- a/lib/mime.c
+++ b/lib/mime.c
@@ -51,25 +51,51 @@ Mime *file_mimetype(const char *filename) {
shell_free(proc);
return NULL;
}
+
+#if OS_DARWIN
+ if (proc->output) {
+ // Universal binaries spit out multiple lines, but we only require the first
+ char *terminate_multi_part = strchr(proc->output, '\n');
+ if (terminate_multi_part != NULL) {
+ *(terminate_multi_part + 1) = '\0';
+ }
+ }
+#endif
+
output = split(proc->output, ":");
if (!output || output[1] == NULL) {
shell_free(proc);
return NULL;
}
- parts = split(output[1], ";");
- if (!parts || !parts[0] || !parts[1]) {
- shell_free(proc);
- return NULL;
- }
- char *what = strdup(parts[0]);
- what = lstrip(what);
+ char *origin = NULL;
+ char *what = NULL;
+ char *charset = NULL;
+
+ if (strchr(output[1], ';')) {
+ parts = split(output[1], ";");
+ if (!parts || !parts[0] || !parts[1]) {
+ shell_free(proc);
+ return NULL;
+ }
- char *charset = strdup(strchr(parts[1], '=') + 1);
- charset = lstrip(charset);
- charset[strlen(charset) - 1] = '\0';
+ what = strdup(parts[0]);
+ what = lstrip(what);
- char *origin = realpath(filename, NULL);
+ charset = strdup(strchr(parts[1], '=') + 1);
+ charset = lstrip(charset);
+ charset[strlen(charset) - 1] = '\0';
+ } else {
+ // this branch is for Darwin; the 'charset=' string is not guaranteed to exist using argument `-I`
+ what = strdup(output[1]);
+ what = lstrip(what);
+ what = strip(what);
+ if (strstr(output[1], "binary") != NULL) {
+ charset = strdup("binary");
+ }
+ }
+
+ origin = realpath(filename, NULL);
type = (Mime *)calloc(1, sizeof(Mime));
type->origin = origin;
@@ -77,7 +103,9 @@ Mime *file_mimetype(const char *filename) {
type->charset = charset;
split_free(output);
- split_free(parts);
+ if (parts != NULL) {
+ split_free(parts);
+ }
shell_free(proc);
return type;
}
diff --git a/lib/strlist.c b/lib/strlist.c
index 3de10dd..aac2755 100644
--- a/lib/strlist.c
+++ b/lib/strlist.c
@@ -83,6 +83,28 @@ void strlist_append_strlist(StrList *pStrList1, StrList *pStrList2) {
}
/**
+ * Remove a record by index from a `StrList`
+ * @param pStrList
+ * @param index
+ */
+void strlist_remove(StrList *pStrList, size_t index) {
+ size_t count = strlist_count(pStrList);
+ if (count == 0) {
+ return;
+ }
+
+ for (size_t i = index; i < count; i++) {
+ char *next = pStrList->data[i + 1];
+ pStrList->data[i] = next;
+ if (next == NULL) {
+ break;
+ }
+ }
+
+ pStrList->num_inuse--;
+}
+
+/**
* Compare two `StrList`s
* @param a `StrList` structure
* @param b `StrList` structure
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;