Index: trunk/ippTools/src/Makefile.am
===================================================================
--- trunk/ippTools/src/Makefile.am	(revision 9319)
+++ trunk/ippTools/src/Makefile.am	(revision 9320)
@@ -6,4 +6,5 @@
 	p3tool\
 	dettool \
+	detselect \
 	pzgetexp \
 	pzgetimfiles \
@@ -90,4 +91,10 @@
     dettoolConfig.c
 
+detselect_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS) $(pxtools_CFLAGS)
+detselect_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
+detselect_SOURCES = \
+    detselect.c \
+    detselectConfig.c
+
 pxinject_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS) $(pxtools_CFLAGS)
 pxinject_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
Index: trunk/ippTools/src/detselect.c
===================================================================
--- trunk/ippTools/src/detselect.c	(revision 9320)
+++ trunk/ippTools/src/detselect.c	(revision 9320)
@@ -0,0 +1,105 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "pxtools.h"
+#include "detselect.h"
+
+static bool searchMode(pxConfig *config);
+
+# define MODECASE(caseName, func) \
+    case caseName: \
+    if (!func(config)) { \
+        goto FAIL; \
+    } \
+    break;
+
+int main(int argc, char **argv)
+{
+    psLibInit(NULL);
+
+    pxConfig *config = detselectConfig(NULL, argc, argv);
+
+    switch (config->mode) {
+        MODECASE(DETSELECT_MODE_SEARCH,        searchMode);
+        default:
+            psAbort(argv[0], "invalid option (this should not happen)");
+    }
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(EXIT_SUCCESS);
+
+FAIL:
+    psFree(config);
+    pmConfigDone();
+    psErrorStackPrint(stderr, "\n");
+    psLibFinalize();
+
+    exit(EXIT_FAILURE);
+}
+
+static bool searchMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psString query = psStringCopy(
+            "SELECT p3PendingExp.*"
+            " FROM p3PendingExp"
+            " LEFT JOIN p3ProcessedExp"
+            "   USING(exp_tag)"
+            " WHERE"
+            "   p3ProcessedExp.exp_tag IS NULL"
+    );
+
+    if (config->where) {
+        psString whereClause = psDBGenerateWhereConditionSQL(config->where, NULL);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        // XXX check psError here
+        psError(PS_ERR_UNKNOWN, false, "no p3PendingExp rows found");
+        psFree(output);
+        return true;
+    }
+
+    bool simple = false;
+    {
+        bool status = false;
+        simple = psMetadataLookupBool(&status, config->args, "-simple");
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -simple");
+            return false;
+        }
+    }
+
+    // negate simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "p3PendingExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
Index: trunk/ippTools/src/detselect.h
===================================================================
--- trunk/ippTools/src/detselect.h	(revision 9320)
+++ trunk/ippTools/src/detselect.h	(revision 9320)
@@ -0,0 +1,13 @@
+#ifndef DETSELECT_H
+#define DETSELECT_H 1
+
+#include "pxtools.h"
+
+typedef enum {
+    DETSELECT_MODE_NONE      = 0x0,
+    DETSELECT_MODE_SEARCH,
+} detselectMode;
+
+pxConfig *detselectConfig(pxConfig *config, int argc, char **argv);
+
+#endif // DETSELECT_H
Index: trunk/ippTools/src/detselectConfig.c
===================================================================
--- trunk/ippTools/src/detselectConfig.c	(revision 9320)
+++ trunk/ippTools/src/detselectConfig.c	(revision 9320)
@@ -0,0 +1,149 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pmConfig.h>
+#include <math.h>
+
+#include "pxtools.h"
+#include "detselect.h"
+
+// this function can not fail -- exits on error
+pxConfig *detselectConfig(pxConfig *config, int argc, char **argv) {
+    if (!config) {
+        config = pxConfigAlloc();
+    }
+
+    // setup site config
+    config->modules = pmConfigRead(&argc, argv);
+    if (!config->modules) {
+        psError(PS_ERR_UNKNOWN, false, "Can't find site configuration");
+        goto FAIL;
+    }
+
+    // -search
+    psMetadata *searchArgs = psMetadataAlloc();
+    
+#define PXTOOL_MODE(option, modeval, argset) \
+{ \
+    int N = 0; \
+    if ((N = psArgumentGet (argc, argv, option))) { \
+        psArgumentRemove (N, &argc, argv); \
+        if (config->mode) { \
+            psError(PS_ERR_UNKNOWN, true, "only one mode selection is allowed"); \
+            goto FAIL; \
+        } \
+        config->mode = modeval; \
+        config->args = psMemIncrRefCounter(argset); \
+    } \
+    if (!psMetadataAddMetadata(argSets, PS_LIST_TAIL, option, 0, NULL, argset)) {;\
+        psError(PS_ERR_UNKNOWN, false, "failed to add argset for %s", option);\
+    } \
+    psFree(argset); \
+}
+
+    psMetadata *argSets = psMetadataAlloc();
+    // find which mode we're running under
+    PXTOOL_MODE("-search", DETSELECT_MODE_SEARCH, searchArgs);
+
+    bool argErr = false;
+    if (config->mode == DETSELECT_MODE_NONE) {
+        argErr = true;
+        fprintf (stderr, "mode argument is required\n");
+    } else if (! psArgumentParse(config->args, &argc, argv) || argc != 1) {
+        argErr = true;
+        fprintf (stderr, "error parsing arguments\n");
+    }
+
+    if (argErr) {
+        printf("\nPan-STARRS detrend select Tool\n");
+        printf("Usage: %s <mode> [<options>]\n\n", argv[0]);
+        printf(" <mode> :\n\n");
+
+        psMetadataIterator *iter = psMetadataIteratorAlloc(argSets, 0, NULL);
+        psMetadataItem *item = NULL;
+        while ((item = psMetadataGetAndIncrement(iter))) {
+            if (!item->type == PS_DATA_METADATA) {
+                psAbort(argv[0], "all options must be specified as a metadata");            }
+
+            fprintf(stdout, "%s ", item->name);
+            psArgumentHelp(item->data.md);
+        }
+        psFree(iter);
+
+        psFree(argSets);
+        goto FAIL;
+    }
+
+    psFree(argSets);
+
+    // setup search criterion
+#define addWhereStr(name) \
+{ \
+    psString str = NULL; \
+    bool status = false; \
+    if ((str = psMetadataLookupStr(&status, config->args, "-" #name))) { \
+        if (!psMetadataAddStr(config->where, PS_LIST_TAIL, #name, 0, "==", str)) {\
+            psError(PS_ERR_UNKNOWN, false, "failed to add item " #name); \
+            goto FAIL; \
+        } \
+    } \
+}
+
+    // generate SQL where clause
+    config->where = psMetadataAlloc();
+
+    addWhereStr(exp_tag);
+    // convert '-inst' to 'camera'
+    {
+        psString str = NULL; 
+        bool status = false;
+        if ((str = psMetadataLookupStr(&status, config->args, "-inst"))) {
+            if (!psMetadataAddStr(config->where, PS_LIST_TAIL, "camera", 0, "==", str)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to add item camera");
+                goto FAIL;
+            }
+        }
+    }
+    addWhereStr(telescope);
+    addWhereStr(exp_type);
+    {
+        int imfiles = 0; 
+        bool status = false;
+        if ((imfiles = psMetadataLookupS32(&status, config->args, "-imfiles"))) {
+            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "imfiles", 0, "==", imfiles)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to add item imfiles");
+                goto FAIL;
+            }
+        }
+    }
+    addWhereStr(class);
+    addWhereStr(class_id);
+    addWhereStr(filter);
+
+    if (config->where->list->n < 1) {
+        psFree(config->where);
+        config->where = NULL;
+    }
+
+
+    // define Database handle, if used
+    config->dbh = pmConfigDB(config->modules);
+    if (!config->dbh) {
+        psError(PS_ERR_UNKNOWN, false, "Can't configure database");
+        goto FAIL;
+    }
+
+    // save argv/argc
+    config->argv = argv;
+    config->argc = argc;
+
+
+    return config;
+
+FAIL:
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+    exit(EXIT_FAILURE);
+}
