56c5a21bd036712b38873f830b46b33351fbb5e4
giardine
  Fri Nov 5 13:21:35 2010 -0700
Added error checking for pgSnp and bedDetail custom track loaders, issue #1595
diff --git src/hg/lib/pgSnp.c src/hg/lib/pgSnp.c
index d6149f3..44e0ba0 100644
--- src/hg/lib/pgSnp.c
+++ src/hg/lib/pgSnp.c
@@ -1,27 +1,28 @@
 /* pgSnp.c was originally generated by the autoSql program, which also 
  * generated pgSnp.h and pgSnp.sql.  This module links the database and
  * the RAM representation of objects. */
 
 #include "common.h"
 #include "linefile.h"
 #include "dystring.h"
 #include "jksql.h"
 #include "pgSnp.h"
 #include "hdb.h"
 #include "dnaseq.h"
 #include "pgPhenoAssoc.h"
+#include "hgFindSpec.h"
 
 static char const rcsid[] = "$Id: pgSnp.c,v 1.8 2010/03/08 17:45:41 giardine Exp $";
 
 void pgSnpStaticLoad(char **row, struct pgSnp *ret)
 /* Load a row from pgSnp table into ret.  The contents of ret will
  * be replaced at the next call to this function. */
 {
 
 ret->bin = sqlUnsigned(row[0]);
 ret->chrom = row[1];
 ret->chromStart = sqlUnsigned(row[2]);
 ret->chromEnd = sqlUnsigned(row[3]);
 ret->name = row[4];
 ret->alleleCount = sqlSigned(row[5]);
 ret->alleleFreq = row[6];
@@ -640,15 +641,51 @@
 {
 struct pgSnp *ret;
 
 AllocVar(ret);
 ret->bin = 0;
 ret->chrom = cloneString(row[0]);
 ret->chromStart = sqlUnsigned(row[1]);
 ret->chromEnd = sqlUnsigned(row[2]);
 ret->name = cloneString(row[3]);
 ret->alleleCount = sqlSigned(row[4]);
 ret->alleleFreq = cloneString(row[5]);
 ret->alleleScores = cloneString(row[6]);
 return ret;
 }
 
+struct pgSnp *pgSnpLineFileLoad(char **row, struct lineFile *lf)
+/* Load pgSnp from a lineFile line, with error checking. */
+/* Requires comma separated zeroes for frequency and scores. */
+{
+struct pgSnp *item;
+AllocVar(item);
+item->chrom = cloneString(row[0]);
+item->chromStart = lineFileNeedNum(lf, row, 1);
+item->chromEnd = lineFileNeedNum(lf, row, 2);
+if (item->chromEnd < 1)
+    lineFileAbort(lf, "chromEnd less than 1 (%d)", item->chromEnd);
+if (item->chromEnd < item->chromStart)
+    lineFileAbort(lf, "chromStart after chromEnd (%d > %d)",
+        item->chromStart, item->chromEnd);
+/* use pattern match to check values and counts both */
+/* alleles are separated by / and can be ACTG- */
+item->name = cloneString(row[3]);
+/* allele count, positive integer matching # of alleles */
+item->alleleCount = lineFileNeedNum(lf, row, 4);
+char alleles[128]; /* pattern to match alleles */
+safef(alleles, sizeof(alleles), "^[ACTG-]+(\\/[ACTG-]+){%d}$", item->alleleCount - 1);
+if (! matchRegex(row[3], alleles))
+    errAbort("invalid alleles %s", row[3]);
+/* read count, comma separated list of numbers with above # of items */
+item->alleleFreq = cloneString(row[5]);
+char pattern[128];
+safef(pattern, sizeof(pattern), "^[0-9]+(,[0-9]+){%d}$", item->alleleCount - 1);
+if (! matchRegex(row[5], pattern))
+    errAbort("invalid allele frequency, %s with count of %d", row[5], item->alleleCount);
+/* scores, comma separated list of numbers with above # of items */
+item->alleleScores = cloneString(row[6]);
+safef(pattern, sizeof(pattern), "^[0-9.]+(,[0-9.]+){%d}$", item->alleleCount - 1);
+if (! matchRegex(row[6], pattern))
+    errAbort("invalid allele scores, %s with count of %d", row[6], item->alleleCount);
+return item;
+}