aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fs.c24
-rw-r--r--src/manifest.c49
-rw-r--r--src/spm.c79
-rw-r--r--src/strings.c18
-rw-r--r--src/version_spec.c110
5 files changed, 256 insertions, 24 deletions
diff --git a/src/fs.c b/src/fs.c
index 849ac0f..f561c84 100644
--- a/src/fs.c
+++ b/src/fs.c
@@ -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;
diff --git a/src/spm.c b/src/spm.c
index 74a11d2..65a2095 100644
--- a/src/spm.c
+++ b/src/spm.c
@@ -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;
+}