diff options
author | Joseph Hunkeler <jhunkeler@users.noreply.github.com> | 2020-05-21 19:10:14 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-21 19:10:14 -0400 |
commit | 03e39ae5dcd4002ac9657a550c48b8e9f85c449c (patch) | |
tree | 7c266ca17a16d4c9ca297fa402a0a9d2ee6f871f /lib | |
parent | 3b323fcc82d3d06d671c55c2b77f74558706420e (diff) | |
parent | 86b2a55574f53c6e175de8cf745d2e67308b612e (diff) | |
download | spmc-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.c | 52 | ||||
-rw-r--r-- | lib/strlist.c | 22 | ||||
-rw-r--r-- | lib/version_spec.c | 144 |
3 files changed, 199 insertions, 19 deletions
@@ -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; |