diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/fs.c | 24 | ||||
-rw-r--r-- | src/manifest.c | 49 | ||||
-rw-r--r-- | src/spm.c | 79 | ||||
-rw-r--r-- | src/strings.c | 18 | ||||
-rw-r--r-- | src/version_spec.c | 110 |
5 files changed, 256 insertions, 24 deletions
@@ -336,3 +336,27 @@ int mkdirs(const char *_path, mode_t mode) { split_free(parts); return result; } + +char *human_readable_size(uint64_t n) { + int i; + double result = (double)n; + char *unit[] = {"B", "K", "M", "G", "T", "P", "E"}; + char r[255]; + memset(r, '\0', sizeof(r)); + + for (i = 0; i < sizeof(unit); i++) { + if (labs(result) < 1024) { + break; + } + result /= 1024.0; + } + + if (unit[i][0] == 'B') { + sprintf(r, "%0.0lf%s", result, unit[i]); + } + else { + sprintf(r, "%0.2lf%s", result, unit[i]); + } + + return strdup(r); +}
\ No newline at end of file diff --git a/src/manifest.c b/src/manifest.c index 7e6802c..d917470 100644 --- a/src/manifest.c +++ b/src/manifest.c @@ -3,6 +3,7 @@ // #include "spm.h" #include <fnmatch.h> +#define PACKAGE_MIN_DELIM 2 Manifest *manifest_from(const char *package_dir) { FSTree *fsdata = NULL; @@ -27,14 +28,31 @@ Manifest *manifest_from(const char *package_dir) { // Copy dependencies if (deps->records) { info->packages[i]->requirements = (char **) calloc(deps->__size, sizeof(char *)); - for (int j = 0; j < deps->records; j++) { + info->packages[i]->requirements_records = deps->records; + int j; + for (j = 0; j < deps->records; j++) { info->packages[i]->requirements[j] = (char *) calloc(strlen(deps->list[j]) + 1, sizeof(char)); strncpy(info->packages[i]->requirements[j], deps->list[j], strlen(deps->list[j])); } } dep_free(&deps); + int delims = num_chars(fsdata->files[i], '-'); + if (delims > PACKAGE_MIN_DELIM) { + for (int t = strlen(fsdata->files[i]); t != 0; t--) { + if (fsdata->files[i][t] == '-') { + delims--; + if (delims == 0) { + fsdata->files[i][t] = '*'; + } + } + } + } + char **parts = split(fsdata->files[i], "-"); + replace_text(parts[0], "*", "-"); + replace_text(fsdata->files[i], "*", "-"); + info->packages[i]->size = get_file_size(fsdata->files[i]); strncpy(info->packages[i]->archive, basename(fsdata->files[i]), PACKAGE_MEMBER_SIZE); strncpy(info->packages[i]->name, basename(parts[0]), PACKAGE_MEMBER_SIZE); @@ -75,12 +93,14 @@ int manifest_write(Manifest *info) { "%-20s: %lu\n" "%-20s: %s\n" "%-20s: %s\n" - "%-20s: %s\n", + "%-20s: %s\n" + "%-20s: %d\n", "archive", info->packages[i]->archive, "size", info->packages[i]->size, "name", info->packages[i]->name, "version", info->packages[i]->version, - "revision", info->packages[i]->revision + "revision", info->packages[i]->revision, + "requirements_records", info->packages[i]->requirements_records ); reqs = join(info->packages[i]->requirements, ", "); printf("%-20s: %s\n", "requirements", reqs ? reqs : "NONE"); @@ -100,11 +120,18 @@ int manifest_write(Manifest *info) { reqs = join(info->packages[i]->requirements, ","); sprintf(dptr, "%s|" // archive "%lu|" // size - "%s|" // name - "%s|" // version - "%s|" // revision - "%s" // requirements - , info->packages[i]->archive, info->packages[i]->size, info->packages[i]->name, info->packages[i]->version, info->packages[i]->revision, reqs ? reqs : "*"); + "%s|" // name + "%s|" // version + "%s|" // revision + "%d|" // requirements_records + "%s" // requirements + , info->packages[i]->archive, + info->packages[i]->size, + info->packages[i]->name, + info->packages[i]->version, + info->packages[i]->revision, + info->packages[i]->requirements_records, + reqs ? reqs : "*"); fprintf(fp, "%s\n", dptr); free(reqs); } @@ -147,10 +174,12 @@ Manifest *manifest_read(void) { strncpy(info->packages[i]->name, parts[2], strlen(parts[2])); strncpy(info->packages[i]->version, parts[3], strlen(parts[3])); strncpy(info->packages[i]->revision, parts[4], strlen(parts[4])); + info->packages[i]->requirements_records = atoi(parts[5]); info->packages[i]->requirements = NULL; - if (strncmp(parts[5], "*", 2) != 0) { - info->packages[i]->requirements = split(parts[5], ","); + if (strncmp(parts[6], "*", 2) != 0) { + info->packages[i]->requirements = split(parts[6], ","); + } split_free(parts); info->records = i; @@ -7,6 +7,7 @@ int RUNTIME_INSTALL = 0; int RUNTIME_ROOTDIR = 0; +int RUNTIME_SEARCH = 0; const int PACKAGE_MAX = 0xff; void usage(const char *program_name) { @@ -16,6 +17,7 @@ void usage(const char *program_name) { " -V, --version show version\n" " -v, --verbose show more information\n" " -I, --install install package(s)\n" + " -S --search search for a package\n" " -r --root installation prefix (requires --install)\n" , program_name ); @@ -42,6 +44,9 @@ int main(int argc, char *argv[]) { char *packages[PACKAGE_MAX]; memset(packages, '\0', sizeof(char *)); + char package_search_str[PATH_MAX]; + memset(package_search_str, '\0', PATH_MAX); + if (argc < 2) { usage(program_name); exit(1); @@ -70,6 +75,16 @@ int main(int argc, char *argv[]) { manifest_free(info); exit(0); } + else if (strcmp(arg, "--search") == 0) { + RUNTIME_SEARCH = 1; + if (arg_next == NULL) { + fprintf(stderr, "--search requires a package name\n"); + usage(program_name); + exit(1); + } + strncpy(package_search_str, arg_next, strlen(arg_next)); + i++; + } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "--root") == 0) { RUNTIME_ROOTDIR = 1; if (!arg_next) { @@ -156,18 +171,8 @@ int main(int argc, char *argv[]) { dep_append(&deps, package->requirements[p]); } } - /* - if ((match = find_package(packages[i])) == NULL) { - fprintf(SYSERROR); - exit(1); - } - - if ((package = basename(match)) == NULL) { - fprintf(stderr, "Unable to derive package name from package path:\n\t-> %s\n", match); - exit(1); - } - */ + // Process any additional dependencies the package requires if (dep_all(&deps, package->archive) < 0) { dep_free(&deps); free_global_config(); @@ -224,6 +229,58 @@ int main(int argc, char *argv[]) { } dep_free(&deps); } + + if (RUNTIME_SEARCH) { + Manifest *info = manifest_read(); + char name[255]; + char op[25]; + char ver[255]; + memset(name, '\0', sizeof(name)); + memset(op, '\0', sizeof(op)); + memset(ver, '\0', sizeof(ver)); + + // Parse the argument string + int p = 0; + + // Populate name + for (int j = 0; package_search_str[p] != '\0'; j++, p++) { + if (isrelational(package_search_str[p])) { + break; + } + name[j] = package_search_str[p]; + } + + // Populate op + for (int j = 0; package_search_str[p] != '\0'; j++, p++) { + if (!isrelational(package_search_str[p])) { + break; + } + op[j] = package_search_str[p]; + } + + if (strlen(op)) { + // Populate version + for (int j = 0; package_search_str[p] != '\0'; j++, p++) { + ver[j] = package_search_str[p]; + } + } + else { + // No operator, so find all versions instead + strcpy(op, ">="); + ver[0] = '0'; + } + + ManifestPackage **package = find_by_spec(info, name, op, ver); + + printf("# %-20s %-20s %-20s %-20s\n", "name", "version", "revision", "size"); + for (int p = 0; package[p] != NULL; p++) { + char *package_hsize = human_readable_size(package[p]->size); + printf(" %-20s %-20s %-20s %-20s\n", package[p]->name, package[p]->version, package[p]->revision, package_hsize); + free(package_hsize); + } + + exit(0); + } free_global_config(); return 0; } diff --git a/src/strings.c b/src/strings.c index 52f81b5..e50daeb 100644 --- a/src/strings.c +++ b/src/strings.c @@ -485,3 +485,21 @@ int isquoted(char *sptr) { } return 1; } + +/** + * Determine whether the input character is a relational operator + * Note: `~` is non-standard + * @param ch + * @return 0=no, 1=yes + */ +int isrelational(char ch) { + char symbols[] = "~!=<>"; + char *symbol = symbols; + while (*symbol != '\0') { + if (ch == *symbol) { + return 1; + } + symbol++; + } + return 0; +} diff --git a/src/version_spec.c b/src/version_spec.c index 7669608..af20fae 100644 --- a/src/version_spec.c +++ b/src/version_spec.c @@ -80,15 +80,21 @@ int64_t version_suffix_modifier_calc(char *str) { } int version_suffix_alpha_calc(char *str) { - if (version_suffix_get_modifier(str) != NULL) { - return 0; - } int x = 0; char chs[255]; char *ch = chs; memset(chs, '\0', sizeof(chs)); strncpy(chs, str, strlen(str)); + // Handle cases where the two suffixes are not delimited by anything + // Start scanning one character ahead of the alphabetic suffix and terminate the string + // when/if we reach another alphabetic character (presumably a version modifer) + for (int i = 1; chs[i] != '\0'; i++) { + if (isalpha(chs[i])) { + chs[i] = '\0'; + } + } + // Convert character to hex-ish x = (*ch - 'a') + 0xa; @@ -192,3 +198,101 @@ int64_t version_from(const char *version_str) { free(vstr); return result; } + +int version_spec_from(const char *op) { + int flags = VERSION_NOOP; + size_t len = strlen(op); + for (int i = 0; i < len; i++) { + if (op[i] == '>') { + flags |= VERSION_GT; + } + else if (op[i] == '<') { + flags |= VERSION_LT; + } + else if (op[i] == '=' || (len > 1 && strncmp(&op[i], "==", 2) == 0)) { + flags |= VERSION_EQ; + } + else if (op[i] == '!') { + flags |= VERSION_NE; + } + else if (op[i] == '~') { + flags |= VERSION_COMPAT; + } + } + return flags; +}; + +static int _find_by_spec_compare(const void *a, const void *b) { + const ManifestPackage *aa = *(const ManifestPackage**)a; + const ManifestPackage *bb = *(const ManifestPackage**)b; + int64_t version_a = version_from(aa->version); + int64_t version_b = version_from(bb->version); + return version_a > version_b; +} + +ManifestPackage **find_by_spec(Manifest *manifest, const char *name, const char *op, const char *version_str) { + int64_t version_a = 0; + int64_t version_b = 0; + int spec = VERSION_NOOP; + int record = 0; + ManifestPackage **list = (ManifestPackage **) calloc(manifest->records + 1, sizeof(ManifestPackage *)); + + for (int i = 0; i < manifest->records; i++) { + if (strcmp(manifest->packages[i]->name, name) == 0) { + int is_equal = 0, + is_not_equal = 0, + is_less_than = 0, + is_greater_than = 0, + is_compat = 0; + + version_a = version_from(manifest->packages[i]->version); + version_b = version_from(version_str); + + spec = version_spec_from(op); + + int res = 0; + if (spec & VERSION_GT && spec & VERSION_EQ) { + res = version_a >= version_b; + } + else if (spec & VERSION_LT && spec & VERSION_EQ) { + res = version_a <= version_b; + } + else if (spec & VERSION_NE && spec & VERSION_EQ) { + res = version_a != version_b; + } + else if (spec & VERSION_GT) { + res = version_a > version_b; + } + else if (spec & VERSION_LT) { + res = version_a < version_b; + } + else if (spec & VERSION_COMPAT) { + // TODO + } + else if (spec & VERSION_EQ) { + res = version_a == version_b; + } + + if (res > 0 || res < 0) { + list[record] = (ManifestPackage *)calloc(1, sizeof(ManifestPackage)); + if (!list[record]) { + perror("Unable to allocate memory for manifest record"); + fprintf(SYSERROR); + return NULL; + } + + memcpy(list[record], manifest->packages[i], sizeof(ManifestPackage)); + list[record]->requirements = (char **) calloc(manifest->packages[i]->requirements_records, sizeof(char *)); + + for (int j = 0; j < manifest->packages[i]->requirements_records; j++) { + list[record]->requirements[j] = (char *) calloc(strlen(manifest->packages[i]->requirements[j]) + 1, sizeof(char)); + strncpy(list[record]->requirements[j], manifest->packages[i]->requirements[j], strlen(manifest->packages[i]->requirements[j])); + } + record++; + } + } + } + qsort(list, record, sizeof(ManifestPackage *), _find_by_spec_compare); + + return list; +} |