Factorise enum set parsing code
* add a function Bool VG_(parse_enum_set) in pub_tool_libcbase.h/m_libcbase.c
  (close to Bool VG_(parse_Addr)
* Implement Bool MC_(parse_leak_heuristics) and MC_(parse_leak_kinds)
  as a call to VG_(parse_enum_set)



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13898 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_libcbase.c b/coregrind/m_libcbase.c
index 0c334ed..61f6fef 100644
--- a/coregrind/m_libcbase.c
+++ b/coregrind/m_libcbase.c
@@ -492,6 +492,82 @@
    return True;
 }
 
+Bool VG_(parse_enum_set) ( const HChar *tokens,
+                           const HChar *input,
+                           UInt *enum_set)
+{
+   const SizeT tokens_len = VG_(strlen)(tokens);
+   if (tokens_len > 1000) return False; /* "obviously invalid" */
+   HChar  tok_tokens[tokens_len+1];
+   HChar *tokens_saveptr;
+   HChar *token;
+   UInt token_nr = 0;
+   UInt all_set = 0;
+
+   const SizeT input_len = VG_(strlen)(input);
+   if (input_len > 1000) return False; /* "obviously invalid" */
+   HChar  tok_input[input_len+1];
+   HChar *input_saveptr;
+   HChar *input_word;
+   UInt word_nr = 0;
+   UInt known_words = 0;
+   Bool seen_all_kw = False;
+   Bool seen_none_kw = False;
+
+   *enum_set = 0;
+
+   VG_(strcpy) (tok_input, input);
+   for (input_word = VG_(strtok_r)(tok_input, ",", &input_saveptr);
+        input_word;
+        input_word = VG_(strtok_r)(NULL, ",", &input_saveptr)) {
+      word_nr++;
+      if (0 == VG_(strcmp)(input_word, "all")) {
+         seen_all_kw = True;
+         known_words++;
+      } else if (0 == VG_(strcmp)(input_word, "none")) {
+         seen_none_kw = True;
+         known_words++;
+      }
+
+      // Scan tokens + compute all_set. Do that even if all or none was
+      // recognised to have a correct value for all_set when exiting
+      // of the 'input' loop.
+      all_set = 0;
+      token_nr = 0;
+      VG_(strcpy) (tok_tokens, tokens);
+      for (token = VG_(strtok_r)(tok_tokens, ",", &tokens_saveptr);
+           token;
+           token = VG_(strtok_r)(NULL, ",", &tokens_saveptr)) {
+         if (0 != VG_(strcmp)(token, "-")) {
+            if (0 == VG_(strcmp)(input_word, token)) {
+               *enum_set |= 1 << token_nr;
+               known_words++;
+            }
+            all_set |= 1 << token_nr;
+         }
+         token_nr++;
+      }
+   }
+
+   if (known_words != word_nr)
+      return False; // One or more input_words not recognised.
+   if (seen_all_kw) {
+      if (seen_none_kw || *enum_set)
+         return False; // mixing all with either none or a specific value.
+      *enum_set = all_set;
+   } else if (seen_none_kw) {
+      if (seen_all_kw || *enum_set)
+         return False; // mixing none with either all or a specific value.
+      *enum_set = 0;
+   } else {
+      // seen neither all or none, we must see at least one value
+      if (*enum_set == 0)
+         return False;
+   }
+
+   return True;
+}
+
 SizeT VG_(strspn) ( const HChar* s, const HChar* accpt )
 {
    const HChar *p, *a;
diff --git a/include/pub_tool_libcbase.h b/include/pub_tool_libcbase.h
index fcc0ed1..951a702 100644
--- a/include/pub_tool_libcbase.h
+++ b/include/pub_tool_libcbase.h
@@ -111,6 +111,24 @@
    False. */
 extern Bool VG_(parse_Addr) ( const HChar** ppc, Addr* result );
 
+/* Parse an "enum set" made of one or more words comma separated.
+   The allowed word values are given in tokens, separated
+   by comma.
+   If a word in tokens is found in input,
+   the corresponding bit will be set in *enum_set
+   (words in tokens are numbered starting from 0).
+   The special token - in tokens can be used to indicate
+   that the corresponding bit position cannot be set.
+   The words none and all can be used to indicate an empty
+   enum_set (0) or an enum_set with all bits corresponding
+   to tokens set. If none or all is given, no other word
+   can be given in input.
+   If parsing is successful, returns True and sets *enum_set.
+   If parsing fails, returns False. */
+extern Bool VG_(parse_enum_set) ( const HChar *tokens,
+                                  const HChar *input,
+                                  UInt *enum_set);
+
 /* Like strncpy(), but if 'src' is longer than 'ndest' inserts a '\0' as the
    last character. */
 extern void  VG_(strncpy_safely) ( HChar* dest, const HChar* src, SizeT ndest );
diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c
index 5f1dd1e..424e512 100644
--- a/memcheck/mc_errors.c
+++ b/memcheck/mc_errors.c
@@ -434,50 +434,8 @@
 
 Bool MC_(parse_leak_kinds) ( const HChar* str0, UInt* lks )
 {
-   HChar  tok_str0[VG_(strlen)(str0)+1];
-   HChar* saveptr;
-   HChar* token;
-
-   Bool seen_all_kw = False;
-   Bool seen_none_kw = False;
-
-   VG_(strcpy) (tok_str0, str0);
-   *lks = 0;
-
-   for (token = VG_(strtok_r)(tok_str0, ",", &saveptr);
-        token;
-        token = VG_(strtok_r)(NULL, ",", &saveptr)) {
-      if      (0 == VG_(strcmp)(token, "reachable"))
-         *lks |= R2S(Reachable);
-      else if (0 == VG_(strcmp)(token, "possible"))
-         *lks |= R2S(Possible);
-      else if (0 == VG_(strcmp)(token, "indirect"))
-         *lks |= R2S(IndirectLeak);
-      else if (0 == VG_(strcmp)(token, "definite"))
-         *lks |= R2S(Unreached);
-      else if (0 == VG_(strcmp)(token, "all"))
-         seen_all_kw = True;
-      else if (0 == VG_(strcmp)(token, "none"))
-         seen_none_kw = True;
-      else
-         return False;
-   }
-
-   if (seen_all_kw) {
-      if (seen_none_kw || *lks)
-         return False; // mixing all with either none or a specific value.
-      *lks = RallS;
-   } else if (seen_none_kw) {
-      if (seen_all_kw || *lks)
-         return False; // mixing none with either all or a specific value.
-      *lks = 0;
-   } else {
-      // seen neither all or none, we must see at least one value
-      if (*lks == 0)
-         return False;
-   }
-
-   return True;
+   return VG_(parse_enum_set)("reachable,possible,indirect,definite",
+                              str0, lks);
 }
 
 static const HChar* pp_Reachedness_for_leak_kinds(Reachedness r)
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 5eda4ff..619aeb5 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -5114,50 +5114,8 @@
 
 static Bool MC_(parse_leak_heuristics) ( const HChar *str0, UInt *lhs )
 {
-   SizeT str0len = VG_(strlen)(str0);
-   if (str0len > 1000) return False; /* "obviously invalid" */
-   HChar  tok_str0[str0len+1];
-   HChar *saveptr;
-   HChar *token;
-
-   Bool seen_all_kw = False;
-   Bool seen_none_kw = False;
-
-   VG_(strcpy) (tok_str0, str0);
-   *lhs = 0;
-
-   for (token = VG_(strtok_r)(tok_str0, ",", &saveptr);
-        token;
-        token = VG_(strtok_r)(NULL, ",", &saveptr)) {
-      if      (0 == VG_(strcmp)(token, "stdstring"))
-         *lhs |= H2S(LchStdString);
-      else if (0 == VG_(strcmp)(token, "newarray"))
-         *lhs |= H2S(LchNewArray);
-      else if (0 == VG_(strcmp)(token, "multipleinheritance"))
-         *lhs |= H2S(LchMultipleInheritance);
-      else if (0 == VG_(strcmp)(token, "all"))
-         seen_all_kw = True;
-      else if (0 == VG_(strcmp)(token, "none"))
-         seen_none_kw = True;
-      else
-         return False;
-   }
-
-   if (seen_all_kw) {
-      if (seen_none_kw || *lhs)
-         return False; // mixing all with either none or a specific value.
-      *lhs = HallS;
-   } else if (seen_none_kw) {
-      if (seen_all_kw || *lhs)
-         return False; // mixing none with either all or a specific value.
-      *lhs = 0;
-   } else {
-      // seen neither all or none, we must see at least one value
-      if (*lhs == 0)
-         return False;
-   }
-
-   return True;
+   return  VG_(parse_enum_set) ("-,stdstring,newarray,multipleinheritance",
+                                str0, lhs);
 }
 
 
@@ -6624,6 +6582,8 @@
 {
    SizeT max_secVBit_szB, max_SMs_szB, max_shmem_szB;
 
+   VG_(message)(Vg_DebugMsg, " memcheck: freelist: vol %lld length %lld\n",
+                VG_(free_queue_volume), VG_(free_queue_length));
    VG_(message)(Vg_DebugMsg,
       " memcheck: sanity checks: %d cheap, %d expensive\n",
       n_sanity_cheap, n_sanity_expensive );