49eebbfade7874bd516ceb6f138e16111837bc33
galt
  Mon May 7 12:57:31 2012 -0700
Make sqlList.c dynamic arrays thread-safe.  Fixes bug in bigBed reported by user #7850.
diff --git src/lib/sqlNum.c src/lib/sqlNum.c
index 51c4431..de24c13 100644
--- src/lib/sqlNum.c
+++ src/lib/sqlNum.c
@@ -1,125 +1,296 @@
 /* sqlnum.c - Routines to convert from ascii to integer
  * representation of numbers. 
  *
  * This file is copyright 2002 Jim Kent, but license is hereby
  * granted for all use - public, private or commercial. */
 
 #include "common.h"
 #include "sqlNum.h"
 
+/* The sql<Type>InList functions allow for fast thread-safe processing of dynamic arrays in sqlList */
+
 
 unsigned sqlUnsigned(char *s)
 /* Convert series of digits to unsigned integer about
  * twice as fast as atoi (by not having to skip white 
  * space or stop except at the null byte.) */
 {
 unsigned res = 0;
 char *p = s;
 char c;
 
 while (((c = *(p++)) >= '0') && (c <= '9'))
     {
     res *= 10;
     res += c - '0';
     }
 if (c != '\0')
     errAbort("invalid unsigned integer: \"%s\"", s);
 return res;
 }
 
+unsigned sqlUnsignedInList(char **pS)
+/* Convert series of digits to unsigned integer about
+ * twice as fast as atoi (by not having to skip white 
+ * space or stop except at the null byte.) 
+ * All of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+unsigned res = 0;
+char *p = s;
+char c;
+
+while (((c = *(p++)) >= '0') && (c <= '9'))
+    {
+    res *= 10;
+    res += c - '0';
+    }
+if (!(c == '\0' || c == ','))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid unsigned integer: \"%s\"", s);
+    }
+*pS = p;
+return res;
+}
+
 unsigned long sqlUnsignedLong(char *s)
 /* Convert series of digits to unsigned long about
  * twice as fast as atol (by not having to skip white 
  * space or stop except at the null byte.) */
 {
 unsigned long res = 0;
 char *p = s;
 char c;
 
 while (((c = *(p++)) >= '0') && (c <= '9'))
     {
     res *= 10;
     res += c - '0';
     }
 if (c != '\0')
-    errAbort("invalid unsigned integer: \"%s\"", s);
+    errAbort("invalid unsigned long: \"%s\"", s);
+return res;
+}
+
+unsigned long sqlUnsignedLongInList(char **pS)
+/* Convert series of digits to unsigned long about
+ * twice as fast as atol (by not having to skip white 
+ * space or stop except at the null byte.) 
+ * All of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+unsigned long res = 0;
+char *p = s;
+char c;
+
+while (((c = *(p++)) >= '0') && (c <= '9'))
+    {
+    res *= 10;
+    res += c - '0';
+    }
+if (!(c == '\0' || c == ','))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid unsigned long: \"%s\"", s);
+    }
+*pS = p;
 return res;
 }
 
 int sqlSigned(char *s)
 /* Convert string to signed integer.  Unlike atol assumes 
  * all of string is number. */
 {
 int res = 0;
 char *p, *p0 = s;
 
 if (*p0 == '-')
     p0++;
 p = p0;
 while ((*p >= '0') && (*p <= '9'))
     {
     res *= 10;
     res += *p - '0';
     p++;
     }
 /* test for invalid character, empty, or just a minus */
 if ((*p != '\0') || (p == p0))
     errAbort("invalid signed integer: \"%s\"", s);
 if (*s == '-')
     return -res;
 else
     return res;
 }
 
+int sqlSignedInList(char **pS)
+/* Convert string to signed integer.  Unlike atol assumes 
+ * all of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+int res = 0;
+char *p, *p0 = s;
+
+if (*p0 == '-')
+    p0++;
+p = p0;
+while ((*p >= '0') && (*p <= '9'))
+    {
+    res *= 10;
+    res += *p - '0';
+    p++;
+}
+/* test for invalid character, empty, or just a minus */
+if (!(*p == '\0' || *p == ',') || (p == p0))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid signed integer: \"%s\"", s);
+    }
+*pS = p;
+if (*s == '-')
+    return -res;
+else
+    return res;
+}
+
 long long sqlLongLong(char *s)
 /* Convert string to a long long.  Unlike atol assumes all of string is
  * number. */
 {
 long long res = 0;
 char *p, *p0 = s;
 
 if (*p0 == '-')
     p0++;
 p = p0;
 while ((*p >= '0') && (*p <= '9'))
     {
     res *= 10;
     res += *p - '0';
     p++;
     }
 /* test for invalid character, empty, or just a minus */
 if ((*p != '\0') || (p == p0))
-    errAbort("invalid signed integer: \"%s\"", s);
+    errAbort("invalid signed long long: \"%s\"", s);
+if (*s == '-')
+    return -res;
+else
+    return res;
+}
+
+long long sqlLongLongInList(char **pS)
+/* Convert string to a long long.  Unlike atol, assumes 
+ * all of string is number. Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+long long res = 0;
+char *p, *p0 = s;
+
+if (*p0 == '-')
+    p0++;
+p = p0;
+while ((*p >= '0') && (*p <= '9'))
+    {
+    res *= 10;
+    res += *p - '0';
+    p++;
+    }
+/* test for invalid character, empty, or just a minus */
+if (!(*p == '\0' || *p == ',') || (p == p0))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid signed long long: \"%s\"", s);
+    }
+*pS = p;
 if (*s == '-')
     return -res;
 else
     return res;
 }
 
 float sqlFloat(char *s)
 /* Convert string to a float.  Assumes all of string is number
  * and aborts on an error. */
 {
 char* end;
 /*	used to have an ifdef here to use strtof() but that doesn't
  *	actually exist on all systems and since strtod() does, may as
  *	well use it since it will do the job here.
  */
 float val = (float) strtod(s, &end);
 
 if ((end == s) || (*end != '\0'))
     errAbort("invalid float: %s", s);
 return val;
 }
 
+float sqlFloatInList(char **pS)
+/* Convert string to a float.  Assumes all of string is number
+ * and aborts on an error. 
+ * Number may be delimited by a comma. 
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+char* end;
+/*	used to have an ifdef here to use strtof() but that doesn't
+ *	actually exist on all systems and since strtod() does, may as
+ *	well use it since it will do the job here.
+ */
+float val = (float) strtod(s, &end);
+
+if ((end == s) || !(*end == '\0' || *end == ','))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+	*e = 0;
+    errAbort("invalid float: %s", s);
+    }
+*pS = end;
+return val;
+}
+
 double sqlDouble(char *s)
 /* Convert string to a double.  Assumes all of string is number
  * and aborts on an error. */
 {
 char* end;
 double val = strtod(s, &end);
 
 if ((end == s) || (*end != '\0'))
     errAbort("invalid double: %s", s);
 return val;
 }
+
+double sqlDoubleInList(char **pS)
+/* Convert string to a double.  Assumes all of string is number
+ * and aborts on an error.
+ * Number may be delimited by a comma.
+ * Returns the position of the delimiter or the terminating 0. */
+{
+char *s = *pS;
+char* end;
+double val = strtod(s, &end);
+
+if ((end == s) || !(*end == '\0' || *end == ','))
+    {
+    char *e = strchr(s, ',');
+    if (e)
+        *e = 0;
+    errAbort("invalid double: %s", s);
+    }
+*pS = end;
+return val;
+}
+