--- /dev/null
+#define _POSIX_C_SOURCE 2
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <string.h>
+
+#include "sqlite3.h"
+#include "zpm.h"
+
+struct config {
+ char *dbfile;
+ char *cmd;
+ char *program;
+ char *pkgid;
+ char *nullstr;
+ char *filter;
+ int errcontinue;
+ int errors;
+ int (*callback)(void*,int,char**,char**);
+};
+
+static void usage() {
+ printf("usage: zpm foreach-path [-fncC] args ...\n");
+}
+
+static int run_program(void *f, int ncols, char **vals, char **cols) {
+ struct config *conf = f;
+ int i;
+ char *argv[ncols+1];
+ pid_t pid;
+ int status;
+ int rv;
+
+ argv[0] = conf->program;
+
+ for (i=0;i<ncols;i++) {
+ argv[i+1] = vals[i] ? vals[i] : conf->nullstr;
+ }
+ argv[i+1] = 0;
+
+ pid = fork();
+
+ if (pid == -1) {
+ perror("cannot fork");
+ return 1;
+ }
+
+ if (pid == 0) {
+ /* child */
+ rv = execvp(conf->program, argv);
+ if (rv == -1) {
+ perror("cannot exec");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ rv = wait(&status);
+ if (rv == -1) {
+ perror("error waiting for child");
+ exit(EXIT_FAILURE);
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ return 0;
+ } else if (conf->errcontinue) {
+ conf->errors++;
+ return 0;
+ }
+ return 1;
+}
+
+static int run_shell(void *f, int ncols, char **vals, char **cols) {
+ struct config *conf = f;
+ int i;
+ char *argv[ncols+4];
+ pid_t pid;
+ int status;
+ int rv;
+
+ argv[0] = "sh";
+ argv[1] = "-c";
+ argv[2] = conf->cmd;
+ argv[3] = "sh";
+
+ for (i=0;i<ncols;i++) {
+ argv[i+4] = vals[i] ? vals[i] : conf->nullstr;
+ }
+ argv[i+4] = 0;
+
+ pid = fork();
+
+ if (pid == -1) {
+ perror("cannot fork");
+ return 1;
+ }
+
+ if (pid == 0) {
+ /* child */
+ rv = execvp("sh", argv);
+ if (rv == -1) {
+ perror("cannot exec");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ rv = wait(&status);
+ if (rv == -1) {
+ perror("error waiting for child");
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ return 0;
+ } else if (conf->errcontinue) {
+ conf->errors++;
+ return 0;
+ }
+ return 1;
+}
+
+static int printpaths(void *f, int ncols, char **vals, char **cols) {
+
+ /* suppress unused warnings */
+
+ if (ncols < 6) {
+ fprintf(stderr, "can't find path names\n");
+ return 1;
+ }
+// printf("path cols %d %p %p\n", ncols, vals, cols);
+ fprintf(stdout, "%s\n", vals[5]);
+#if 0
+ cols = 0;
+ f = 0;
+ int i;
+ if (cols == 0) {
+ fprintf(stderr, "sqlite can't get column names\n");
+ }
+ for (i=0;i<ncols;i++) {
+// if (i>3) fprintf(out, "\t");
+ fprintf(stdout, "%s\n", vals[i]);
+ }
+#endif
+ return 0;
+}
+
+#ifdef PATH_MAX
+#define PATHLEN PATH_MAX
+#else
+#define PATHLEN 4096
+#endif
+
+int main(int ac, char **av){
+ struct zpm pkg;
+ int opt;
+
+ struct config conf = { 0 };
+
+ conf.dbfile = getenv("ZPMDB");
+ conf.callback = printpaths;
+ conf.nullstr = "";
+
+ if (!conf.dbfile) {
+ conf.dbfile = "/var/lib/zpm/local.db";
+ }
+
+ /*
+ * -c 'shell command'
+ * -f 'package database', otherwise regular default of env ZPMDB,
+ * or /var/lib/zpm/zpm.db, or die
+ *
+ * arg 1: pkgid triple, but will do a pkg find
+ * arg 2: program to run. equivalent of 'printf "%s\n" "$path"
+ * otherwise'
+ */
+
+ while ((opt = getopt(ac, av, "f:c:n:Cp:F:")) != -1) {
+ switch (opt) {
+ case 'f': conf.dbfile = optarg;
+ break;
+ case 'c': conf.cmd = optarg;
+ conf.callback = run_shell;
+ break;
+ case 'C':
+ conf.errcontinue = 1;
+ break;
+ case 'n':
+ conf.nullstr = optarg;
+ break;
+ case 'p':
+ conf.pkgid = optarg;
+ break;
+ case 'F': conf.filter = optarg;
+ break;
+ default:
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+ int argn = optind;
+
+ if (!zpm_open(&pkg, conf.dbfile)) {
+ fprintf(stderr, "can't open zpm db %s\n", conf.dbfile);
+ exit(EXIT_FAILURE);
+ }
+ char *errmsg = 0;
+
+ /* TODO lookup pkgid via zpm-findpkg equivalent */
+
+ if (argn < ac) {
+ conf.program = av[argn];
+ conf.callback = run_program;
+ argn++;
+ /* TODO set conf.args to remaining arguments */
+ }
+
+ if (!zpm_foreach_path(&pkg, conf.pkgid, conf.filter, conf.callback, &conf, &errmsg)) {
+ if (errmsg) {
+ fprintf(stderr, "database error: %s\n", errmsg);
+ exit(EXIT_FAILURE);
+ }
+ if (pkg.error == 1) {
+ fprintf(stderr, "unable to allocate memory\n");
+ }
+ exit(EXIT_FAILURE);
+ }
+
+ zpm_close(&pkg);
+ return conf.errors ? 1 : 0;
+}