Index: trunk/ippTools/src/chiptool.c
===================================================================
--- trunk/ippTools/src/chiptool.c	(revision 23865)
+++ trunk/ippTools/src/chiptool.c	(revision 23868)
@@ -204,8 +204,8 @@
         bool status;
         char *end_stage = psMetadataLookupStr(&status, md, "end_stage");
-	if (end_stage && strcasecmp(end_stage, "warp")) continue;
+        if (end_stage && strcasecmp(end_stage, "warp")) continue;
 
         char *raw_tess_id   = psMetadataLookupStr(&status, md, "tess_id");
-	if (raw_tess_id || tess_id) continue;
+        if (raw_tess_id || tess_id) continue;
 
         char *label  = psMetadataLookupStr(&status, md, "label");
@@ -213,5 +213,5 @@
 
         if (!status) {
-	    psError(PS_ERR_UNKNOWN, false, "cannot queue analysis to WARP without a defined tess id: label: %s, exp_id %" PRId64, label, exp_id);
+            psError(PS_ERR_UNKNOWN, false, "cannot queue analysis to WARP without a defined tess id: label: %s, exp_id %" PRId64, label, exp_id);
             psFree(output);
             return false;
@@ -263,6 +263,6 @@
     PXOPT_COPY_STR(config->args,  where, "-state",   "chipRun.state",   "==");
 
-    if (!psListLength(where->list) && 
-	!psMetadataLookupBool(NULL, config->args, "-all")) {
+    if (!psListLength(where->list) &&
+        !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
         where = NULL;
@@ -566,6 +566,6 @@
     PXOPT_COPY_S32(config->args, where, "-magicked", "chipRun.magicked", "==");
 
-    if (!psListLength(where->list) && 
-	!psMetadataLookupBool(NULL, config->args, "-all")) {
+    if (!psListLength(where->list) &&
+        !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
         psError(PXTOOLS_ERR_DATA, false, "search parameters (or -all) are required");
@@ -1382,68 +1382,46 @@
 bool importrunMode(pxConfig *config)
 {
-  unsigned int nFail;
-
-  int numImportTables = 2;
-
-  char tables[2] [80] = {"chipImfile", "chipProcessedImfile"};
-
-  PS_ASSERT_PTR_NON_NULL(config, NULL);
-
-  PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
-
-  psMetadata *input = psMetadataConfigRead (NULL, &nFail, infile, false);
-
-  fprintf (stdout, "---- input ----\n");
-  psMetadataPrint (stderr, input, 1);
-
-  psMetadataItem *item = psMetadataLookup (input, "chipRun");
-  psAssert (item, "entry not in input?");
-  psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
-
-  psMetadataItem *entry = psListGet (item->data.list, 0);
-  assert (entry);
-  assert (entry->type == PS_DATA_METADATA);
-  chipRunRow *chipRun = chipRunObjectFromMetadata (entry->data.md);
-  chipRunInsertObject (config->dbh, chipRun);
-
-  // fprintf (stdout, "---- chip run ----\n");
-  // psMetadataPrint (stderr, entry->data.md, 1);
-
-  for (int i = 0; i < numImportTables; i++) {
-    psMetadataItem *item = psMetadataLookup (input, tables[i]);
-    psAssert (item, "entry not in input?");
-    psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
-
-    switch (i) {
-      case 0:
-        for (int i = 0; i < item->data.list->n; i++) {
-          psMetadataItem *entry = psListGet (item->data.list, i);
-          assert (entry);
-          assert (entry->type == PS_DATA_METADATA);
-          chipImfileRow *chipImfile = chipImfileObjectFromMetadata (entry->data.md);
-          chipImfileInsertObject (config->dbh, chipImfile);
-
-          // fprintf (stdout, "---- row %d ----\n", i);
-          // psMetadataPrint (stderr, entry->data.md, 1);
-        }
-        break;
-
-      case 1:
-        for (int i = 0; i < item->data.list->n; i++) {
-          psMetadataItem *entry = psListGet (item->data.list, i);
-          assert (entry);
-          assert (entry->type == PS_DATA_METADATA);
-          chipProcessedImfileRow *chipProcessedImfile = chipProcessedImfileObjectFromMetadata (entry->data.md);
-          chipProcessedImfileInsertObject (config->dbh, chipProcessedImfile);
-
-          // fprintf (stdout, "---- row %d ----\n", i);
-          // psMetadataPrint (stderr, entry->data.md, 1);
-        }
-        break;
-    }
-  }
-
-  return true;
-}
-
-
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_STR(infile, config->args, "-infile", true, false);
+    unsigned int nFail = 0;               // Number of failed lines
+    psMetadata *input = psMetadataConfigRead(NULL, &nFail, infile, false);
+    if (nFail) {
+        psError(PS_ERR_IO, false, "%d failed lines in input", nFail);
+        psFree(input);
+        return false;
+    }
+
+    psVector *identifiers = psVectorAllocEmpty(16, PS_TYPE_U64); // Identifiers inserted
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    psMetadataIterator *iter = psMetadataIteratorAlloc(input, PS_LIST_HEAD, NULL);       // Iterator
+    psMetadataItem *item;               // Item from iteration
+    while ((item = psMetadataGetAndIncrement(iter))) {
+        PXMIRROR_PRIMARY(item, "chipRun", chipRunRow, chipRunObjectFromMetadata, identifiers, chip_id,
+                         chipRunInsertObject, config->dbh,
+                         { psFree(iter); psFree(identifiers); psFree(input); });
+
+        PXMIRROR_OTHER(item, "chipImfile", chipImfileRow, chipImfileObjectFromMetadata, identifiers, chip_id,
+                       chipImfileInsertObject, config->dbh,
+                       { psFree(iter); psFree(identifiers); psFree(input); });
+
+        PXMIRROR_OTHER(item, "chipProcessedImfile", chipProcessedImfileRow,
+                       chipProcessedImfileObjectFromMetadata, identifiers, chip_id,
+                       chipProcessedImfileInsertObject, config->dbh,
+                       { psErrorStackPrint(stderr, "Error:"); psMetadataPrint(stderr, item->data.md, 0); psFree(iter); psFree(identifiers); psFree(input); });
+    }
+    psFree(iter);
+    psFree(input);
+
+    psLogMsg("chiptool", PS_LOG_INFO, "%ld chipRuns added", identifiers->n);
+    psFree(identifiers);
+
+    return true;
+}
+
+
Index: trunk/ippTools/src/pxtools.h
===================================================================
--- trunk/ippTools/src/pxtools.h	(revision 23865)
+++ trunk/ippTools/src/pxtools.h	(revision 23868)
@@ -478,3 +478,85 @@
 }
 
+
+/// Add a primary item to the mirror database
+///
+/// ITEM: Item to add (if it is of the correct type)
+/// NAME: Name for table, to match item name
+/// ROWTYPE: Type of the row (type returned by PARSEFUNC)
+/// PARSEFUNC: Function to parse ITEM and return a ROWTYPE
+/// IDENTIFIERS: Vector (of type U64) to store identifiers
+/// IDNAME: Element of the row with U64 identifier
+/// INSERTFUNC: Function to insert a row into the database
+/// DATABASE: Database handle
+/// CLEANUP: Operation(s) to perform to cleanup in case of an error
+#define PXMIRROR_PRIMARY(ITEM, NAME, ROWTYPE, PARSEFUNC, IDENTIFIERS, IDNAME, INSERTFUNC, DATABASE, CLEANUP) \
+    if (strcmp((ITEM)->name, NAME) == 0) { \
+        if ((ITEM)->type != PS_DATA_METADATA) { \
+            psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Entry %s is not of type METADATA", (ITEM)->name); \
+            CLEANUP; \
+            return false; \
+        } \
+        ROWTYPE *row = PARSEFUNC((ITEM)->data.md); /* Row to insert */ \
+        if (!row) { \
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate %s row from metadata", (ITEM)->name); \
+            CLEANUP; \
+            return false; \
+        } \
+        if (!INSERTFUNC(DATABASE, row)) { \
+            psError(PS_ERR_UNKNOWN, false, "Unable to add %s %" PRIu64, (ITEM)->name, row->IDNAME); \
+            psFree(row); \
+            CLEANUP; \
+            return false; \
+        } \
+        psVectorAppend((IDENTIFIERS), row->IDNAME); \
+        psFree(row); \
+    }
+
+/// Add a dependent item to the mirror database
+///
+/// ITEM: Item to add (if it is of the correct type)
+/// NAME: Name for table, to match item name
+/// ROWTYPE: Type of the row (type returned by PARSEFUNC)
+/// PARSEFUNC: Function to parse ITEM and return a ROWTYPE
+/// IDENTIFIERS: Vector (of type U64) to check identifiers
+/// IDNAME: Element of the row with U64 identifier
+/// INSERTFUNC: Function to insert a row into the database
+/// DATABASE: Database handle
+/// CLEANUP: Operation(s) to perform to cleanup in case of an error
+#define PXMIRROR_OTHER(ITEM, NAME, ROWTYPE, PARSEFUNC, IDENTIFIERS, IDNAME, INSERTFUNC, DATABASE, CLEANUP) \
+    if (strcmp((ITEM)->name, NAME) == 0) { \
+        if ((ITEM)->type != PS_DATA_METADATA) { \
+            psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Entry %s is not of type METADATA", (ITEM)->name); \
+            CLEANUP; \
+            return false; \
+        } \
+        ROWTYPE *row = PARSEFUNC(item->data.md); /* Row to insert */ \
+        if (!row) { \
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate %s row from metadata", (ITEM)->name); \
+            CLEANUP; \
+            return false; \
+        } \
+        bool found = false;         /* Found the identifier? */ \
+        for (int i = 0; i < (IDENTIFIERS)->n && !found; i++) { \
+            if (row->IDNAME == (IDENTIFIERS)->data.U64[i]) { \
+                found = true; \
+                break; \
+            } \
+        } \
+        if (!found) { \
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Identifier not found for %s %" PRIu64, \
+                    (ITEM)->name, row->IDNAME); \
+            psFree(row); \
+            CLEANUP; \
+            return false; \
+        } \
+        if (!INSERTFUNC(DATABASE, row)) { \
+            psError(PS_ERR_UNKNOWN, false, "Unable to add %s %" PRIu64, (ITEM)->name, row->IDNAME); \
+            psFree(row); \
+            CLEANUP; \
+            return false; \
+        } \
+        psFree(row); \
+    }
+
 #endif // PXTOOLS_H
