9b13731e6e466aa0f781179da2d504db2f4c15a9
tdreszer
  Wed Mar 30 11:28:34 2011 -0700
Made slPairListFromString and slPairListToString optionally handle double quotes. Finally made mdbObjReorderByCv so that priority in cv.ra typeOfTerms is used.
diff --git src/lib/common.c src/lib/common.c
index cb96a41..d9799a7 100644
--- src/lib/common.c
+++ src/lib/common.c
@@ -970,90 +970,198 @@
 for (el = list; el != NULL; el = el->next)
     if (sameString(name, el->name))
         break;
 return el;
 }
 
 void *slPairFindVal(struct slPair *list, char *name)
 /* Return value associated with name in list, or NULL if not found. */
 {
 struct slPair *el = slPairFind(list, name);
 if (el == NULL)
     return NULL;
 return el->val;
 }
 
-struct slPair *slPairFromString(char *s)
-/* Return slPair list parsed from list in string s
- * name1=val1 name2=val2 ...
- * Returns NULL if parse error.  Free this up with
- * slPairFreeValsAndList. */
+struct slPair *slPairListFromString(char *str,boolean respectQuotes)
+// Return slPair list parsed from list in string like:  [name1=val1 name2=val2 ...]
+// if respectQuotes then string can have double quotes: [name1="val 1" "name 2"=val2 ...]
+//    resulting pair strips quotes: {name1}={val 1},{name 2}={val2}
+// Returns NULL if parse error.  Free this up with slPairFreeValsAndList.
 {
+if (isEmpty(str))
+    return NULL;
+int count = countChars(str, '=') + 1; // Should have 1 more token than '=': {"name 1"},{val1 name2},{"val 2"}
+if (count < 2)
+    {
+    warn("slPairListFromString() No pairs found in string meant to contain name=value pairs [%s]\n", str);
+    return NULL;
+    }
+char *strClone = cloneString(str);
+char **tokens = needMem(sizeof(char *) * count);
+count = chopByChar(strClone, '=',tokens,count);
+
+int ix;
 struct slPair *list = NULL;
-char *name;
-char *ss = cloneString(s);
-char *word = ss;
-while((name = nextWord(&word)))
+for (ix=1; ix < count;ix++) // starting at 1 and looking back to 0
     {
-    char *val = strchr(name,'=');
-    if (!val)
+    // name comes from prev token!
+    char *name = tokens[ix -1];
+    char *val = tokens[ix];
+
+    // Parse of val and set up ptr for next name
+    char *next = NULL;
+    if (respectQuotes && val[0] == '"')
+        next = skipBeyondDelimit(tokens[ix] + 1,'"');
+    else
+        next = skipToSpaces(tokens[ix]);
+    if (next != NULL)
 	{
-	warn("missing equals sign in name=value pair: name=[%s] in string=[%s]\n", name, s);
-	return NULL;
+        *next++ = '\0';
+        tokens[ix] = next; // set up for next round.
+        }
+    else if (ix + 1 != count) // Last token should have no 'next'.
+        {
+        warn("slPairListFromString() Error parsing string meant to contain name=value pairs: [%s]\n", str);
+        break;
+        }
+
+    if (respectQuotes && name[0] == '"')
+        stripEnclosingDoubleQuotes(name);
+    else if (hasWhiteSpace(name))
+        {
+        warn("slPairListFromString() Unexpected white space in name=value pair: [%s]=[%s] in string=[%s]\n", name, val, str);
+        break;
+        }
+    if (respectQuotes && val[0] == '"')
+        stripEnclosingDoubleQuotes(val);
+    else if (hasWhiteSpace(val))
+        {
+        warn("slPairListFromString() Unexpected white space in name=value pair: [%s]=[%s] in string=[%s]\n", name, val, str);
+        break;
 	}
-    *val++ = 0;
     slPairAdd(&list, name, cloneString(val));
     }
-freez(&ss);
+freez(&strClone);
+if (ix != count) // error detected.
+    {
+    slPairFreeValsAndList(&list);
+    return NULL;
+    }
 slReverse(&list);
 return list;
 }
 
-char *slPairListToString(struct slPair *list)
-// Returns an allocated string of pairs in form of
-// name1=val1 name2=val2 ...
-// Will wrap vals in quotes if contain spaces: name3="val 3"
+char *slPairListToString(struct slPair *list,boolean quoteIfSpaces)
+// Returns an allocated string of pairs in form of [name1=val1 name2=val2 ...]
+// If requested, will wrap name or val in quotes if contain spaces: [name1="val 1" "name 2"=val2]
 {
-// Don't rely on dyString.  We can do the accounting ourselves.
+// Don't rely on dyString.  We should do the accounting ourselves and not create extra dependencies.
 int count = 0;
 struct slPair *pair = list;
 for(;pair != NULL; pair = pair->next)
     {
-    if (pair->name == NULL || pair->val == NULL)
-        continue;
+    assert(pair->name != NULL && pair->val != NULL); // Better assert and get this over with, complete with stack
     count += strlen(pair->name);
     count += strlen((char *)(pair->val));
     count += 2; // = and ' ' delimit
+    if (quoteIfSpaces)
+        {
+        if (hasWhiteSpace(pair->name))
+            count += 2; // " and "
     if (hasWhiteSpace((char *)(pair->val)))
         count += 2; // " and "
     }
+    }
 if (count == 0)
     return NULL;
+
 char *str = needMem(count+5); // A bit of slop
 
-char *s = str;
-for(pair = list;pair != NULL; pair = pair->next)
+char *strPtr = str;
+for(pair = list; pair != NULL; pair = pair->next, strPtr += strlen(strPtr))
     {
-    if (pair->name == NULL || pair->val == NULL)
-        continue;
+    if (pair != list) // Not first cycle
+        *strPtr++ = ' ';
+    if (hasWhiteSpace(pair->name))
+        {
+        if (quoteIfSpaces)
+            sprintf(strPtr,"\"%s\"=",pair->name);
+        else
+            {
+            warn("slPairListToString() Unexpected white space in name: [%s]\n", pair->name);
+            sprintf(strPtr,"%s=",pair->name); // warn but still make string
+            }
+        }
+    else
+        sprintf(strPtr,"%s=",pair->name);
+    strPtr += strlen(strPtr);
     if (hasWhiteSpace((char *)(pair->val)))
-        sprintf(s,"%s=\"%s\" ",pair->name,(char *)(pair->val));
+        {
+        if (quoteIfSpaces)
+            sprintf(strPtr,"\"%s\"",(char *)(pair->val));
     else
-        sprintf(s,"%s=%s ",pair->name,(char *)(pair->val));
-    s += strlen(s);
+            {
+            warn("slPairListToString() Unexpected white space in val: [%s]\n", (char *)(pair->val));
+            sprintf(strPtr,"%s",(char *)(pair->val)); // warn but still make string
+            }
+        }
+    else
+        sprintf(strPtr,"%s",(char *)(pair->val));
+    }
+return str;
+}
+
+char *slPairNameToString(struct slPair *list, char delimiter,boolean quoteIfSpaces)
+// Return string created by joining all names (ignoring vals) with the delimiter.
+// If requested, will wrap name in quotes if contain spaces: [name1,"name 2" ...]
+{
+int elCount = 0;
+int count = 0;
+struct slPair *pair = list;
+for (; pair != NULL; pair = pair->next, elCount++)
+    {
+    assert(pair->name != NULL);
+    count += strlen(pair->name);
+    if (quoteIfSpaces && hasWhiteSpace(pair->name))
+        count += 2;
+    }
+count += elCount;
+if (count == 0)
+    return NULL;
+
+char *str = needMem(count+5); // A bit of slop
+
+char *strPtr = str;
+for(pair = list; pair != NULL; pair = pair->next, strPtr += strlen(strPtr))
+    {
+    if (pair != list)
+        *strPtr++ = delimiter;
+    if (hasWhiteSpace(pair->name))
+        {
+        if (quoteIfSpaces)
+            sprintf(strPtr,"\"%s\"",pair->name);
+        else
+            {
+            if (delimiter == ' ')  // if delimied by commas, this is entirely okay!
+                warn("slPairListToString() Unexpected white space in name delimied by space: [%s]\n", pair->name);
+            sprintf(strPtr,"%s",pair->name); // warn but still make string
+            }
+        }
+    else
+        sprintf(strPtr,"%s",pair->name);
     }
-str[strlen(str) - 1] = '\0'; // For sweetness, remove the trailing space.
 return str;
 }
 
 int slPairCmpCase(const void *va, const void *vb)
 /* Compare two slPairs, ignore case. */
 {
 const struct slPair *a = *((struct slPair **)va);
 const struct slPair *b = *((struct slPair **)vb);
 return strcasecmp(a->name, b->name);
 }
 
 void slPairSortCase(struct slPair **pList)
 /* Sort slPair list, ignore case. */
 {
 slSort(pList, slPairCmpCase);
@@ -1084,30 +1192,44 @@
 return strcmp((char *)(a->val), (char *)(b->val));
 }
 
 void slPairValSortCase(struct slPair **pList)
 /* Sort slPair list on values (must be string), ignore case. */
 {
 slSort(pList, slPairValCmpCase);
 }
 
 void slPairValSort(struct slPair **pList)
 /* Sort slPair list on values (must be string). */
 {
 slSort(pList, slPairValCmp);
 }
 
+int slPairIntCmp(const void *va, const void *vb)
+// Compare two slPairs on their integer values.
+{
+const struct slPair *a = *((struct slPair **)va);
+const struct slPair *b = *((struct slPair **)vb);
+return ((char *)(a->val) - (char *)(b->val)); // cast works and val is 0 vased integer
+}
+
+void slPairIntSort(struct slPair **pList)
+// Sort slPair list on integer values.
+{
+slSort(pList, slPairIntCmp);
+}
+
 
 void gentleFree(void *pt)
 {
 if (pt != NULL) freeMem((char*)pt);
 }
 
 int differentWord(char *s1, char *s2)
 /* strcmp ignoring case - returns zero if strings are
  * the same (ignoring case) otherwise returns difference
  * between first non-matching characters. */
 {
 char c1, c2;
 for (;;)
     {
     c1 = toupper(*s1++);