diff options
Diffstat (limited to 'src/apk_adb.c')
-rw-r--r-- | src/apk_adb.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/apk_adb.c b/src/apk_adb.c new file mode 100644 index 0000000000..7dc077f89b --- /dev/null +++ b/src/apk_adb.c @@ -0,0 +1,203 @@ +#include "apk_adb.h" +#include "apk_version.h" + +#define APK_VERSION_CONFLICT 16 + +adb_val_t adb_w_dependency(struct adb *db, apk_blob_t *b) +{ + extern const apk_spn_match_def apk_spn_dependency_comparer; + extern const apk_spn_match_def apk_spn_dependency_separator; + extern const apk_spn_match_def apk_spn_repotag_separator; + struct adb_obj obj; + apk_blob_t bdep, bname, bop, bver = APK_BLOB_NULL, btag; + int mask = APK_DEPMASK_ANY; + + adb_wo_alloca(&obj, &schema_dependency, db); + + /* [!]name[<,<=,<~,=,~,>~,>=,>,><]ver */ + if (APK_BLOB_IS_NULL(*b)) + goto fail; + + /* grap one token */ + if (!apk_blob_cspn(*b, apk_spn_dependency_separator, &bdep, NULL)) + bdep = *b; + b->ptr += bdep.len; + b->len -= bdep.len; + + /* skip also all separator chars */ + if (!apk_blob_spn(*b, apk_spn_dependency_separator, NULL, b)) { + b->ptr += b->len; + b->len = 0; + } + + /* parse the version */ + if (bdep.ptr[0] == '!') { + bdep.ptr++; + bdep.len--; + mask |= APK_VERSION_CONFLICT; + } + + if (apk_blob_cspn(bdep, apk_spn_dependency_comparer, &bname, &bop)) { + int i; + + if (mask == 0) + goto fail; + if (!apk_blob_spn(bop, apk_spn_dependency_comparer, &bop, &bver)) + goto fail; + + mask = 0; + for (i = 0; i < bop.len; i++) { + switch (bop.ptr[i]) { + case '<': + mask |= APK_VERSION_LESS; + break; + case '>': + mask |= APK_VERSION_GREATER; + break; + case '~': + mask |= APK_VERSION_FUZZY|APK_VERSION_EQUAL; + break; + case '=': + mask |= APK_VERSION_EQUAL; + break; + } + } + if ((mask & APK_DEPMASK_CHECKSUM) != APK_DEPMASK_CHECKSUM && + !apk_version_validate(bver)) + goto fail; + } else { + bname = bdep; + bop = APK_BLOB_NULL; + bver = APK_BLOB_NULL; + } + + if (apk_blob_cspn(bname, apk_spn_repotag_separator, &bname, &btag)) + ; /* tag = repository tag */ + + adb_wo_blob(&obj, ADBI_DEP_NAME, bname); + if (mask != APK_DEPMASK_ANY) { + adb_wo_blob(&obj, ADBI_DEP_VERSION, bver); + if (mask != APK_VERSION_EQUAL) + adb_wo_int(&obj, ADBI_DEP_MATCH, mask); + } + return adb_w_obj(&obj); + +fail: + return ADB_NULL; +} + +adb_val_t adb_w_pkginfo(struct adb *db, unsigned int f, apk_blob_t *val) +{ + struct apk_checksum csum; + struct adb_obj deps; + + switch (f) { + case ADBI_PI_INSTALLED_SIZE: + case ADBI_PI_FILE_SIZE: + case ADBI_PI_BUILD_TIME: + case ADBI_PI_PRIORITY:; + uint32_t n = apk_blob_pull_uint(val, 10); + if (!n) break; + return adb_w_int(db, n); + + case ADBI_PI_DEPENDS: + case ADBI_PI_INSTALL_IF: + case ADBI_PI_PROVIDES: + case ADBI_PI_REPLACES: + /* array of package names */ + adb_wo_alloca(&deps, &schema_dependency_array, db); + while (val->len) + adb_wa_append(&deps, adb_w_dependency(db, val)); + return adb_w_arr(&deps); + + case ADBI_PI_UNIQUE_ID: + if (!val->ptr || val->len < 4) break; + apk_blob_pull_csum(val, &csum); + return adb_w_int(db, get_unaligned32(csum.data) & ADB_VALUE_MASK); + + case ADBI_PI_REPO_COMMIT: + if (val->len < 40) break; + csum.type = 20; + apk_blob_pull_hexdump(val, APK_BLOB_CSUM(csum)); + if (val->ptr) return adb_w_blob(db, APK_BLOB_CSUM(csum)); + break; + default: + if (!val->len) break; + return adb_w_blob(db, *val); + } + + return ADB_ERROR(EAPKFORMAT); +} + +static struct adb *__db1, *__db2; + +static int pkginfo_cmp(const void *p1, const void *p2) +{ + struct adb_obj o1, o2; + int r; + + adb_r_obj(__db1, *(adb_val_t *)p1, &o1, &schema_pkginfo); + adb_r_obj(__db2, *(adb_val_t *)p2, &o2, &schema_pkginfo); + + r = apk_blob_sort( + adb_ro_blob(&o1, ADBI_PI_NAME), + adb_ro_blob(&o2, ADBI_PI_NAME)); + if (r) return r; + + r = apk_version_compare_blob( + adb_ro_blob(&o1, ADBI_PI_VERSION), + adb_ro_blob(&o2, ADBI_PI_VERSION)); + switch (r) { + case APK_VERSION_LESS: return -1; + case APK_VERSION_GREATER: return 1; + default: return 0; + } +} + +int adb_r_pkgindex_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val) +{ + adb_val_t *ndx; + + __db1 = db; + __db2 = arr->db; + + if (cur == 0) { + ndx = bsearch(&val, &arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), pkginfo_cmp); + if (!ndx) return -1; + cur = ndx - arr->obj; + while (cur > 1 && pkginfo_cmp(&val, &arr->obj[cur-1]) == 0) cur--; + } else { + cur++; + if (pkginfo_cmp(&val, &arr->obj[cur]) != 0) + return -1; + } + return cur; + +} + +unsigned int adb_pkg_field_index(char f) +{ +#define MAP(ch, ndx) [ch - 'A'] = ndx + static unsigned char map[] = { + MAP('C', ADBI_PI_UNIQUE_ID), + MAP('P', ADBI_PI_NAME), + MAP('V', ADBI_PI_VERSION), + MAP('T', ADBI_PI_DESCRIPTION), + MAP('U', ADBI_PI_URL), + MAP('I', ADBI_PI_INSTALLED_SIZE), + MAP('S', ADBI_PI_FILE_SIZE), + MAP('L', ADBI_PI_LICENSE), + MAP('A', ADBI_PI_ARCH), + MAP('D', ADBI_PI_DEPENDS), + MAP('i', ADBI_PI_INSTALL_IF), + MAP('p', ADBI_PI_PROVIDES), + MAP('o', ADBI_PI_ORIGIN), + MAP('m', ADBI_PI_MAINTAINER), + MAP('t', ADBI_PI_BUILD_TIME), + MAP('c', ADBI_PI_REPO_COMMIT), + MAP('r', ADBI_PI_REPLACES), + MAP('k', ADBI_PI_PRIORITY), + }; + if (f < 'A' || f-'A' >= ARRAY_SIZE(map)) return 0; + return map[(unsigned char)f - 'A']; +} |