#define _POSIX_C_SOURCE 200809L #include #include #include #include #include "zpm.h" #include "sqlite3.h" int zpm_parse_package(char *pstr, char *name, char *ver, int *rel) { if (name) *name = 0; if (ver) *ver = 0; if (rel) *rel = 0; int havename = 0; int havever = 0; int haverel = 0; /* string - ver - rel */ /* rel is all digits */ /* possible forms: * ^(.+)-([0-9][^-]*)-([\d+])$ * ^(.+)-([0-9][^-]*)$ * ^(.+)$ * The main problem in parsing is that the package name itself * can contain a '-', so you can't just split on '-' * Also, the version can be just digits. */ /* everything up to the first '-' is in the name */ while (*pstr) { if (*pstr == '\'' || !isgraph(*pstr)) { return 0; } if (*pstr == '-' && isdigit(*(pstr+1))) { break; } if (name) { *name++ = *pstr; } pstr++; havename = 1; } if (name) *name = 0; if (*pstr == '-') { pstr++; } while (*pstr && *pstr != '-') { if (*pstr == '\'' || !isgraph(*pstr)) { return 0; } if (ver) { *ver++ = *pstr; } pstr++; havever = 1; } if (ver) *ver = 0; if (*pstr == '-') { pstr++; } /* TODO use strtol */ if (rel && *pstr) { haverel = 1; *rel = atoi(pstr); } return havename + havever + haverel; } /* * flags 0 = find installed * flags 1 = skip installed * flags 2 = skip not installed */ struct zpm_package *zpm_package_alloc(struct zpm *zpm) { struct zpm_package *pkg; pkg = malloc(sizeof *pkg); if (pkg) { pkg->zpm = zpm; pkg->release = 0; } return pkg; } void zpm_sqlite_error(struct zpm *zpm) { zpm->error = 1; if (zpm->errmsg) free(zpm->errmsg); zpm->errmsg = strdup((const char *)sqlite3_errmsg(zpm->db)); } char *zpm_findpkg(struct zpm *zpm, char *pkgstr) { char *select = "select pkgid, package, version, release from packages_pkgid"; char *group = "group by package having max( version||'-'||release collate vercmp) order by length(package), package, version||'-'||release collate vercmp limit 1"; #if 0 char *sstr[] = { "status = 'installed'", "", "status != 'installed'" }; #endif // char *order = "order by package, version collate vercmp, cast(release as integer)"; sqlite3_str *sql; sqlite3_stmt *stmt; char *query; char package[32]; char version[32]; int release; /* null pkgstr find "best" package * best is shortest complete package if any are complete * shortest incomplete if any are incomplete * where more than one version is in those sets, best is * latest as determined by vercmp */ /* given a package name, get the packages */ /* no package name, get all */ // char where[1024] = ""; zpm_parse_package(pkgstr, package, version, &release); /* install a collation function */ zpm_addvercmp(zpm); /* TODO allow more args to nail down version and release */ sql = sqlite3_str_new(zpm->db); sqlite3_str_appendall(sql, select); sqlite3_str_appendf(sql, " where package = %q", package); if (*version) { sqlite3_str_appendf(sql, " and version = %q", version); } if (release) { sqlite3_str_appendf(sql, " and release = %d", release); } sqlite3_str_appendf(sql, " %s", group); sqlite3_str_appendf(sql, " limit 1"); if (sqlite3_str_errcode(sql)) { zpm->error = 1; sqlite3_free(sqlite3_str_finish(sql)); return 0; } query = sqlite3_str_finish(sql); sqlite3_prepare_v2(zpm->db, query, strlen(query), &stmt, NULL); sqlite3_free(query); free(zpm->pkgid); zpm->pkgid = 0; switch (sqlite3_step(stmt)) { case SQLITE_ROW: zpm->pkgid = strdup((const char *)sqlite3_column_text(stmt, 0)); break; case SQLITE_DONE: /* not found */ break; default: zpm_sqlite_error(zpm); break; } sqlite3_finalize(stmt); return zpm->pkgid; }