Index: /trunk/ippTools/src/Makefile.am
===================================================================
--- /trunk/ippTools/src/Makefile.am	(revision 10641)
+++ /trunk/ippTools/src/Makefile.am	(revision 10642)
@@ -5,4 +5,5 @@
 	p2tool\
 	p3tool\
+	p4tool\
 	pxadmin \
 	pxinject \
@@ -68,4 +69,10 @@
     p3toolConfig.c
 
+p4tool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS) $(pxtools_CFLAGS)
+p4tool_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
+p4tool_SOURCES = \
+    p4tool.c \
+    p4toolConfig.c
+
 pxadmin_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS) $(pxtools_CFLAGS)
 pxadmin_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
Index: /trunk/ippTools/src/warptool.c
===================================================================
--- /trunk/ippTools/src/warptool.c	(revision 10642)
+++ /trunk/ippTools/src/warptool.c	(revision 10642)
@@ -0,0 +1,164 @@
+/*
+ * p4tool.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVB_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ippdb.h>
+
+#include "pxtools.h"
+#include "p4tool.h"
+
+static bool definerunMode(pxConfig *config);
+static bool addinputimfileMode(pxConfig *config);
+static bool towarpedimfileMode(pxConfig *config);
+static bool addwarpedimfileMode(pxConfig *config);
+static bool warpedimfileMode(pxConfig *config);
+static bool tostackedimfileMode(pxConfig *config);
+static bool addstackedimfileMode(pxConfig *config);
+static bool stackedimfileMode(pxConfig *config);
+static bool todiffimfileMode(pxConfig *config);
+static bool adddiffimfileMode(pxConfig *config);
+static bool diffimfileMode(pxConfig *config);
+
+# define MODECASE(caseName, func) \
+    case caseName: \
+    if (!func(config)) { \
+        goto FAIL; \
+    } \
+    break;
+
+int main(int argc, char **argv)
+{
+    psLibInit(NULL);
+
+    pxConfig *config = p4toolConfig(NULL, argc, argv);
+
+    switch (config->mode) {
+        MODECASE(P4TOOL_MODE_DEFINERUN,         definerunMode);
+        MODECASE(P4TOOL_MODE_ADDINPUTIMFILE,    addinputimfileMode);
+        MODECASE(P4TOOL_MODE_TOWARPEDIMFILE,    towarpedimfileMode);
+        MODECASE(P4TOOL_MODE_ADDWARPEDIMFILE,   addwarpedimfileMode);
+        MODECASE(P4TOOL_MODE_WARPEDIMFILE,      warpedimfileMode);
+        MODECASE(P4TOOL_MODE_TOSTACKEDIMFILE,   tostackedimfileMode);
+        MODECASE(P4TOOL_MODE_ADDSTACKEDIMFILE,  addstackedimfileMode);
+        MODECASE(P4TOOL_MODE_STACKEDIMFILE,     stackedimfileMode);
+        MODECASE(P4TOOL_MODE_TODIFFIMFILE,      todiffimfileMode);
+        MODECASE(P4TOOL_MODE_ADDDIFFIMFILE,     adddiffimfileMode);
+        MODECASE(P4TOOL_MODE_DIFFIMFILE,        diffimfileMode);
+        default:
+            psAbort(argv[0], "invalid option (this should not happen)");
+    }
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(EXIT_SUCCESS);
+
+FAIL:
+    psErrorStackPrint(stderr, "\n");
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(EXIT_FAILURE);
+}
+
+static bool definerunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool addinputimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool towarpedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool addwarpedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool warpedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool tostackedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool addstackedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool stackedimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool todiffimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool adddiffimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
+
+static bool diffimfileMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    return true;
+}
Index: /trunk/ippTools/src/warptool.h
===================================================================
--- /trunk/ippTools/src/warptool.h	(revision 10642)
+++ /trunk/ippTools/src/warptool.h	(revision 10642)
@@ -0,0 +1,42 @@
+/*
+ * p4tool.h
+ *
+ * Copyright (C) 2006  Joshua Hoblitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef P4TOOL_H
+#define P4TOOL_H 1
+
+#include "pxtools.h"
+
+typedef enum {
+    P4TOOL_MODE_NONE           = 0x0,
+    P4TOOL_MODE_DEFINERUN,
+    P4TOOL_MODE_ADDINPUTIMFILE,
+    P4TOOL_MODE_TOWARPEDIMFILE,
+    P4TOOL_MODE_ADDWARPEDIMFILE,
+    P4TOOL_MODE_WARPEDIMFILE,
+    P4TOOL_MODE_TOSTACKEDIMFILE,
+    P4TOOL_MODE_ADDSTACKEDIMFILE,
+    P4TOOL_MODE_STACKEDIMFILE,
+    P4TOOL_MODE_TODIFFIMFILE,
+    P4TOOL_MODE_ADDDIFFIMFILE,
+    P4TOOL_MODE_DIFFIMFILE
+} p4toolMode;
+
+pxConfig *p4toolConfig(pxConfig *config, int argc, char **argv);
+
+#endif // P4TOOL_H
Index: /trunk/ippTools/src/warptoolConfig.c
===================================================================
--- /trunk/ippTools/src/warptoolConfig.c	(revision 10642)
+++ /trunk/ippTools/src/warptoolConfig.c	(revision 10642)
@@ -0,0 +1,248 @@
+/*
+ * p4toolConfig.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <psmodules.h>
+
+#include "pxtools.h"
+#include "p4tool.h"
+
+// this function can not fail -- exits on error
+pxConfig *p4toolConfig(pxConfig *config, int argc, char **argv) {
+    if (!config) {
+        config = pxConfigAlloc();
+    }
+
+    // setup site config
+    config->modules = pmConfigRead(&argc, argv, NULL);
+    if (!config->modules) {
+        psError(PS_ERR_UNKNOWN, false, "Can't find site configuration");
+        goto FAIL;
+    }
+
+    psTime *time = psTimeGetNow(PS_TIME_TAI);
+    psString now = psTimeToISO(time);
+    psFree(time);
+
+    // -definerun
+    psMetadata *definerunArgs = psMetadataAlloc();
+
+    // -addinputimfile
+    psMetadata *addinputimfileArgs = psMetadataAlloc();
+   
+    // -towarpedimfile
+    psMetadata *towarpedimfileArgs = psMetadataAlloc();
+ 
+    // -addwarpedimfile
+    psMetadata *addwarpedimfileArgs = psMetadataAlloc();
+ 
+    // -warpedimfile
+    psMetadata *warpedimfileArgs = psMetadataAlloc();
+
+    // -tostackedimfile
+    psMetadata *tostackedimfileArgs = psMetadataAlloc();
+
+    // -addstackedimfile
+    psMetadata *addstackedimfileArgs = psMetadataAlloc();
+
+    // -stackedimfile
+    psMetadata *stackedimfileArgs = psMetadataAlloc();
+ 
+    // -todiffimfile
+    psMetadata *todiffimfileArgs = psMetadataAlloc();
+ 
+    // -adddiffimfile
+    psMetadata *adddiffimfileArgs = psMetadataAlloc();
+
+    // -diffimfile
+    psMetadata *diffimfileArgs = psMetadataAlloc();
+
+    psFree(now);
+
+#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("-definerun",       P4TOOL_MODE_DEFINERUN,   definerunArgs);
+    PXTOOL_MODE("-addinputimfile",  P4TOOL_MODE_ADDINPUTIMFILE, addinputimfileArgs);
+    PXTOOL_MODE("-towarpedimfile",  P4TOOL_MODE_TOWARPEDIMFILE, towarpedimfileArgs);
+    PXTOOL_MODE("-addwarpedimfile", P4TOOL_MODE_ADDWARPEDIMFILE, addwarpedimfileArgs);
+    PXTOOL_MODE("-warpedimfile",    P4TOOL_MODE_WARPEDIMFILE,   warpedimfileArgs);
+    PXTOOL_MODE("-tostackedimfile", P4TOOL_MODE_TOSTACKEDIMFILE, tostackedimfileArgs);
+    PXTOOL_MODE("-addstackedimfile", P4TOOL_MODE_ADDSTACKEDIMFILE, addstackedimfileArgs);
+    PXTOOL_MODE("-stackedimfile",   P4TOOL_MODE_STACKEDIMFILE, stackedimfileArgs);
+    PXTOOL_MODE("-todiffimfile", P4TOOL_MODE_TODIFFIMFILE, todiffimfileArgs);
+    PXTOOL_MODE("-adddiffimfile", P4TOOL_MODE_ADDDIFFIMFILE, adddiffimfileArgs);
+    PXTOOL_MODE("-diffimfile",   P4TOOL_MODE_DIFFIMFILE, diffimfileArgs);
+
+    bool argErr = false;
+    if (config->mode == P4TOOL_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 Phase 4 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(det_id);
+    {
+        int n = 0;
+        bool status = false;
+        if ((n = psMetadataLookupS32(&status, config->args, "-iteration"))) {
+            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "iteration", 0, "==", n)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to add item iteration");
+                goto FAIL;
+            }
+        }
+    }
+    addWhereStr(det_type);
+    addWhereStr(exp_tag);
+    addWhereStr(class_id);
+    // 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 n = 0;
+        bool status = false;
+        if ((n = psMetadataLookupS32(&status, config->args, "-imfiles"))) {
+            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "imfiles", 0, "==", n)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to add item imfiles");
+                goto FAIL;
+            }
+        }
+    }
+    addWhereStr(filter);
+    addWhereStr(recipe);
+    {
+        int n = 0;
+        bool status = false;
+        if ((n = psMetadataLookupS32(&status, config->args, "-p1_version"))) {
+            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "p1_version", 0, "==", n)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to add item p1_version");
+                goto FAIL;
+            }
+        }
+    }
+    {
+        bool boolean = false;
+        bool status = false;
+
+        // map reject -> !accept
+        if ((boolean = psMetadataLookupBool(&status, config->args, "-reject"))) {
+            if (!psMetadataAddBool(config->where, PS_LIST_TAIL, "accept", 0, "==", !boolean)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to add item reject");
+                goto FAIL;
+            }
+        }
+    }
+
+    if (config->where->list->n < 1) {
+        psFree(config->where);
+        config->where = NULL;
+    }
+
+    // define Database handle, if used
+    // do this last so we don't setup a connection before CLI options are
+    // validated
+    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);
+}
