+#define _POSIX_C_SOURCE 2
+
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+
#include "zpm.h"
+static int found = 0;
+
+void usage(void) {
+ fprintf(stderr, "zpm-findpkg [-I] [-s <status> ...] [-S <status>] [package]\n");
+}
+
static int prow(void *f, int ncols, char **vals, char **cols) {
FILE *out = f;
int i;
- cols = 0; /* suppress warning */
+ if (cols == 0) {
+ fprintf(stderr, "sqlite can't get column names\n");
+ }
for (i=3;i<ncols;i++) {
if (i>3) fprintf(out, "\t");
fprintf(out, "%s", vals[i]);
}
fprintf(out, "\n");
+ found++;
return 0;
}
+void parse_package(char *pstr, char *name, char *ver, int *rel) {
+ if (name) *name = 0;
+ if (ver) *ver = 0;
+ if (rel) *rel = -1;
+
+ /* 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 == '-' && isdigit(*(pstr+1))) {
+ break;
+ }
+ if (name) {
+ *name++ = *pstr;
+ }
+ pstr++;
+ }
+ if (name) *name = 0;
+ if (*pstr == '-') {
+ pstr++;
+ }
+ while (*pstr && *pstr != '-') {
+ if (ver) {
+ *ver++ = *pstr;
+ }
+ pstr++;
+ }
+ if (ver) *ver = 0;
+ if (*pstr == '-') {
+ pstr++;
+ }
+ if (rel && *pstr) {
+ *rel = atoi(pstr);
+ }
+}
+
int main(int ac, char **av){
+ int opt;
struct zpm pkg;
+ char *dbfile, *pkgstr;
char *select = "select package, version, release, package||'-'||version||'-'||release as pkgid from packages";
char *group = "group by package having max( version||'-'||release collate vercmp) order by length(package), package, version||'-'||release collate vercmp";
-// char *select = "select package, version, release, package||'-'||version||'-'||release as pkgid from packages";
-// char *order = "order by package, version collate vercmp, cast(release as integer)";
- char sql[2048];
+ char *sql;
+ sqlite3_str *include;
+ sqlite3_str *exclude;
+ sqlite3_str *query;
- if (ac < 2) {
- fprintf(stderr, "usage: db path\n");
- return 1;
+ dbfile = getenv("ZPMDB");
+
+ query = sqlite3_str_new(NULL);
+ include = sqlite3_str_new(NULL);
+ exclude = sqlite3_str_new(NULL);
+
+ while ((opt = getopt(ac, av, "f:s:S:I")) != -1) {
+ switch (opt) {
+ case 'f': dbfile = optarg; break;
+ case 's': sqlite3_str_appendf(include,",%Q", optarg);
+ break;
+ case 'S': sqlite3_str_appendf(exclude,",%Q", optarg);
+ break;
+ case 'I': sqlite3_str_appendall(include,",'installed'");
+ break;
+ default:
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
}
+ int argn = optind;
- /* this is really just read env */
- zpm_readopts(&pkg, ac, av);
+ if (!dbfile) {
+ fprintf(stderr, "must specify db\n");
+ return 1;
+ }
/* given a package name, get the packages */
/* no package name, get all */
- if (zpm_open(&pkg, av[1])) {
+#ifdef DEBUG
+ fprintf(stderr, "opening db %s\n", dbfile);
+#endif
+
+ if (zpm_open(&pkg, dbfile)) {
char *errmsg;
-// char where[1024] = "";
+ char *excludes, *includes;
- /* TODO allow more args to nail down version and release */
- if (ac >= 3) {
- sprintf(sql, "%s where package = '%s' %s;",
- select, av[2], group);
- } else {
- sprintf(sql, "%s %s;", select, group);
+ excludes = sqlite3_str_value(exclude);
+ includes = sqlite3_str_value(include);
+
+ sqlite3_str_appendall(query, " ");
+ sqlite3_str_appendall(query, select);
+ sqlite3_str_appendall(query, " where true");
+
+ if (includes) {
+ sqlite3_str_appendf(query, " and status in (%s)", includes+1);
+ }
+ if (excludes) {
+ sqlite3_str_appendf(query, " and status not in (%s)", excludes+1);
}
- /* install a collation function */
- zpm_addvercmp(&pkg);
- /* sqlite seems to need the columns in the result to
- * do the sort right */
-// zpm_exec(&pkg, "select package, version, release, package||'-'||version||'-'||release as pkgid from packages order by package, version collate vercmp, cast(release as integer)", prow, stdout, &errmsg);
-// fprintf(stdout, "\n");
+ if (ac >= argn) {
+ int release;
+ char version[32];
+ char package[32];
+
+ pkgstr = av[argn];
+
+ parse_package(pkgstr, package, version, &release);
+ if (*package != 0) {
+ sqlite3_str_appendf(query, " and package = %Q",
+ package);
+ }
+ if (*version != 0) {
+ sqlite3_str_appendf(query, " and version = %Q",
+ version);
+ }
+ if (release != -1) {
+ sqlite3_str_appendf(query, " and release = %d",
+ release);
+ }
+ }
- zpm_exec(&pkg, sql, prow, stdout, &errmsg);
+ sqlite3_str_appendall(query, " ");
+ sqlite3_str_appendall(query, group);
+ sqlite3_str_appendall(query, ";");
+
+ sql = sqlite3_str_value(query);
+ if (sql) {
+#ifdef DEBUG
+ fprintf(stderr, "q: %s\n", sql);
+#endif
+ zpm_exec(&pkg, sql, prow, stdout, &errmsg);
+ } else {
+ fprintf(stderr, "unable to form database query\n");
+ }
}
zpm_close(&pkg);
- return 0;
+ return found ? 0 : 1;
}