diff options
-rw-r--r-- | include/install.h | 5 | ||||
-rw-r--r-- | lib/install.c | 189 | ||||
-rw-r--r-- | src/spm.c | 72 | ||||
-rw-r--r-- | tests/test_spm_get_package_info_str.c | 38 |
4 files changed, 240 insertions, 64 deletions
diff --git a/include/install.h b/include/install.h index bc1fe19..08fe5d8 100644 --- a/include/install.h +++ b/include/install.h @@ -6,7 +6,10 @@ int spm_hierarchy_is_root(SPM_Hierarchy *fs); int spm_hierarchy_make_root(SPM_Hierarchy *fs); -void spm_install_show_package(ManifestPackage *package); +char *spm_get_package_info_str(ManifestPackage *package, const char *fmt); +void spm_show_package(ManifestPackage *package); +void spm_show_package_manifest(Manifest *info); +void spm_show_packages(ManifestList *info); int spm_install(SPM_Hierarchy *fs, const char *tmpdir, const char *_package); int spm_install_package_record(SPM_Hierarchy *fs, char *tmpdir, char *package_name); int spm_check_installed(SPM_Hierarchy *fs, char *package_name); diff --git a/lib/install.c b/lib/install.c index a2fdf9f..8930362 100644 --- a/lib/install.c +++ b/lib/install.c @@ -35,12 +35,191 @@ int spm_hierarchy_make_root(SPM_Hierarchy *fs) { return 0; } -void spm_install_show_package(ManifestPackage *package) { +/** + * Generates a formatted string containing package information + * + * `%n` = Package name + * `%v` = Package version + * `%V` = Package version and revision (separated by a hyphen (`-`)) + * `%r` = Package revision + * `%o` = Package origin + * `%a` = Package filename on disk + * `%c` = Package checksum (sha256) + * `%s` = Package size (byte) + * `%S` = Package size (human readable) + * + * @param package Pointer to `ManifestPackage` + * @param fmt Format string + * @return `malloc()`ed string + */ +char *spm_get_package_info_str(ManifestPackage *package, const char *fmt) { + // Allocate at least enough space for the character arrays in ManifestPackage (there are several) + char *output = calloc(1, sizeof(ManifestPackage)); + + // Stores raw record data + char tmp[SPM_PACKAGE_MEMBER_SIZE]; + + // Stores width string (i.e. '%-12n' is parsed as '12') + char str_width[10]; + + // Record the maximum number of bytes to read + size_t len_fmt = strlen(fmt); + + // Begin reading format string + for (size_t i = 0; i < len_fmt; i++) { + size_t width = 0; // Default string padding amount + int when = -1; // When string padding is applied (-1 = none, 0 = before, 1 = after) + char *hrs = NULL; // Buffer for human_readable_size + + // Truncate temporary strings + tmp[0] = '\0'; + str_width[0] = '\0'; + + // Begin parsing formatter + if (fmt[i] == '%') { + // Advance to next character + i++; + + // When the next character is a hyphen write string padding after the requested value + if (fmt[i] == '-') { + when = 1; + i++; + } + + // Is the next character a number? + if (isdigit(fmt[i])) { + if (when != 1) { // read as: "if padding not altered already" + when = 0; // got no '-' but landed on some digits, so pad "before" + } + + // Consume the numerical string and convert it to an integer + int j = 0; + while (isdigit(fmt[i])) { + memcpy(&str_width[j], &fmt[i], 1); + j++; + i++; + } + str_width[j] = 0; + width = strtoul(str_width, NULL, 10); + } + + // Retrieve information based on requested format character' + switch (fmt[i]) { + case 'n': + strcpy(tmp, package->name); + break; + case 'v': + strcpy(tmp, package->version); + break; + case 'V': + strcpy(tmp, package->version); + strcat(tmp, "-"); + strcat(tmp, package->revision); + break; + case 'r': + strcpy(tmp, package->revision); + break; + case 'o': + strcpy(tmp, package->origin); + break; + case 'a': + strcpy(tmp, package->archive); + break; + case 'c': + strcpy(tmp, package->checksum_sha256); + break; + case 's': + sprintf(tmp, "%zu", package->size); + break; + case 'S': + hrs = human_readable_size(package->size); + strcpy(tmp, hrs); + free(hrs); + break; + default: + // Formatter is not registered above. Oh well. + continue; + } + + // Pad the string up to the length of the length of `tmp` + int width_final = ((int)width - (int)strlen(tmp)); + + // When `tmp` is longer than the requested width, use the original width + if (width_final < 0) { + width_final = width; + } + + // Write padding "before" appending `tmp` to the output string + if (when == 0) { + for (size_t m = 0; m < width_final; m++) { + strcat(output, " "); + } + } + + // Append data to output string + strcat(output, tmp); + + // Write padding "after" appending `tmp` to the output string + if (when == 1) { + for (size_t m = 0; m < width_final; m++) { + strcat(output, " "); + } + } + } else { + // Data was not parsed as a formatter, so append it to the output string as-is + strncat(output, &fmt[i], 1); + } + } + + return output; +} + +void spm_show_package(ManifestPackage *package) { + char *output = NULL; + if (package == NULL) { - fprintf(stderr, "ERROR: package was NULL\n"); + spmerrno = SPM_ERR_MANIFEST_INVALID; + spmerrno_cause("ManifestPackage was NULL\n"); + return; + } + + output = spm_get_package_info_str(package, "%-20n %-10V %8S %4o"); + + if (output == NULL) { + spmerrno = SPM_ERR_PKG_INVALID; + spmerrno_cause("spm_get_package_info_str did not succeed"); return; } - printf(" -> %-20s %-10s (origin: %s)\n", package->name, package->version, package->origin); + puts(output); + free(output); +} + +void spm_show_package_manifest(Manifest *info) { + char *output = NULL; + + if (info == NULL) { + spmerrno = SPM_ERR_MANIFEST_INVALID; + spmerrno_cause("Manifest was NULL\n"); + return; + } + + for (size_t m = 0; m < info->records; m++) { + spm_show_package(info->packages[m]); + } + +} +void spm_show_packages(ManifestList *info) { + char *output = NULL; + + if (info == NULL) { + spmerrno = SPM_ERR_MANIFEST_INVALID; + spmerrno_cause("ManifestList was NULL"); + return; + } + + for (size_t i = 0; i < manifestlist_count(info); i++) { + spm_show_package_manifest(manifestlist_item(info, i)); + } } /** @@ -249,7 +428,7 @@ int spm_do_install(SPM_Hierarchy *fs, ManifestList *mf, StrList *packages) { // Install packages printf("Requested package(s):\n"); for (size_t i = 0; requirements !=NULL && requirements[i] != NULL; i++) { - spm_install_show_package(requirements[i]); + spm_show_package(requirements[i]); } if (SPM_GLOBAL.prompt_user) { @@ -333,7 +512,7 @@ int spm_do_install(SPM_Hierarchy *fs, ManifestList *mf, StrList *packages) { continue; } - spm_install_show_package(requirements[i]); + spm_show_package(requirements[i]); spm_install(fs, tmpdir, package_path); // Relocate installation root @@ -288,74 +288,30 @@ int main(int argc, char *argv[], char *arge[]) { } if (RUNTIME_SEARCH || RUNTIME_LIST) { - 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 c = 0; - - // Populate name - for (int j = 0; package_search_str[c] != '\0'; j++, c++) { - if (isrelational(package_search_str[c])) { - break; - } - name[j] = package_search_str[c]; - } - - if (RUNTIME_SEARCH) { - // Populate op - for (int j = 0; package_search_str[c] != '\0'; j++, c++) { - if (!isrelational(package_search_str[c])) { - break; - } - op[j] = package_search_str[c]; - } - - if (strlen(op)) { - // Populate version - for (int j = 0; package_search_str[c] != '\0'; j++, c++) { - ver[j] = package_search_str[c]; - } - } else { - // No operator, so find all versions instead - strcpy(op, ">="); - ver[0] = '0'; - } - - } - int banner_size = 79; putchar('#'); print_banner("-", banner_size); - printf("# %-20s %-10s %-10s %-10s %-20s\n", "name", "version", "revision", "size", "origin"); + printf("# %-18s %s %11s %10s\n", "name", "version", "size", "origin"); putchar('#'); print_banner("-", banner_size); - for (size_t m = 0; m < manifestlist_count(mf); m++) { - Manifest *info = manifestlist_item(mf, m); - if (RUNTIME_SEARCH) { - ManifestPackage **package = find_by_spec(info, name, op, ver); - for (int p = 0; package[p] != NULL; p++) { - char *package_hsize = human_readable_size(package[p]->size); - printf(" %-20s %-10s %-10s %-10s %20s\n", package[p]->name, package[p]->version, package[p]->revision, - package_hsize, info->packages[p]->origin); - free(package_hsize); - } - } else if (RUNTIME_LIST) { - for (size_t p = 0; p < info->records; p++) { - char *package_hsize = human_readable_size(info->packages[p]->size); - printf(" %-20s %-10s %-10s %-10s %20s\n", info->packages[p]->name, info->packages[p]->version, - info->packages[p]->revision, package_hsize, info->packages[p]->origin); - free(package_hsize); - } + if (RUNTIME_SEARCH) { + // Search all known packages + for (size_t m = 0; m < manifestlist_count(mf); m++) { + Manifest *info = manifestlist_item(mf, m); + ManifestPackage *package = find_by_strspec(info, package_search_str); + spm_show_package(package); } + } else if (RUNTIME_LIST) { + // List all known packages + spm_show_packages(mf); } } + if (spmerrno != 0) { + spm_perror("Last error"); + } + runtime_free(rt); free_global_config(); strlist_free(packages); diff --git a/tests/test_spm_get_package_info_str.c b/tests/test_spm_get_package_info_str.c new file mode 100644 index 0000000..c228ccb --- /dev/null +++ b/tests/test_spm_get_package_info_str.c @@ -0,0 +1,38 @@ +#include "spm.h" +#include "framework.h" + +ManifestPackage TESTPKG = {.name = "test", .version = "1.0.0", .revision = "1", .archive = "test-1.0.0-1.tar.gz", .origin = "test_land", .size = 1234}; +const char *testFmt = "returned '%s', expected '%s'\n"; +char *truth[] = { + "test 1.0.0 1 test-1.0.0-1.tar.gz test_land 1234 1.21K", + " test 1.0.0 1 test-1.0.0-1.tar.gz test_land 1234 1.21K", + "test 1.0.0 1 test-1.0.0-1.tar.gz test_land 1234 1.21K", + "test 1.0.0-1 ", + " test 1.0.0-1", +}; +size_t numCases = 0; + +int main(int argc, char *argv[]) { + ManifestPackage *package = &TESTPKG; + char *data[] = { + spm_get_package_info_str(package, "%n %v %r %a %o %s %S"), + spm_get_package_info_str(package, "%10n %v %r %a %o %s %S"), + spm_get_package_info_str(package, "%-10n %v %r %a %o %s %S"), + spm_get_package_info_str(package, "%-10n %-10V"), + spm_get_package_info_str(package, "%10n %10V"), + }; + numCases = sizeof(data) / sizeof(char *); + + if (numCases != (sizeof(truth) / sizeof(char *))) { + fprintf(stderr, "Number of test cases does not match number of truth cases\n"); + return 1; + } + + for (size_t i = 0; i < numCases; i++) { + puts(data[i]); + myassert(strcmp(data[i], truth[i]) == 0, testFmt, data[i], truth[i]); + free(data[i]); + } + + return 0; +}
\ No newline at end of file |