#define _POSIX_C_SOURCE 2 #include #include #include #include #include "zpm.h" static int found = 0; void usage(void) { fprintf(stderr, "zpm-findpkg [-I] [-s ...] [-S ] [package]\n"); } static int prow(void *f, int ncols, char **vals, char **cols) { FILE *out = f; int i; if (cols == 0) { fprintf(stderr, "sqlite can't get column names\n"); } for (i=3;i3) 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 *sql; sqlite3_str *include; sqlite3_str *exclude; sqlite3_str *query; 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; if (!dbfile) { fprintf(stderr, "must specify db\n"); return 1; } /* given a package name, get the packages */ /* no package name, get all */ #ifdef DEBUG fprintf(stderr, "opening db %s\n", dbfile); #endif if (zpm_open(&pkg, dbfile)) { char *errmsg; char *excludes, *includes; 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); } 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); } } 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 found ? 0 : 1; }