atoll() is a terrible function -- you can't do any error checking with it.
Some of our option processing code uses it.  This means that eg.
'--log-fd=9xxx' logs to fd 9, and '--log-fd=blahblahblah' logs to 0 (because
atoll() returns 0 if the string doesn't contain a number!)

It turns out that most of our option processing uses VG_(strtoll*) instead
of VG_(atoll).  The reason that not all of it does is that the
option-processing macros are underpowered -- they currently work well if you
just want to assign the value to a variable, eg:

        VG_BOOL_CLO(arg, "--heap",   clo_heap)
   else VG_BOOL_CLO(arg, "--stacks", clo_stacks)

   else VG_NUM_CLO(arg, "--heap-admin", clo_heap_admin)
   else VG_NUM_CLO(arg, "--depth",      clo_depth)

(This works because they are actually an if-statement, but it looks odd.)

VG_NUM_CLO uses VG_(stroll10).  But if you want to do any checking or
processing, you can't use those macros, leading to code like this:

      else if (VG_CLO_STREQN(9,  arg, "--log-fd=")) {
         log_to            = VgLogTo_Fd;
         VG_(clo_log_name) = NULL;
         tmp_log_fd        = (Int)VG_(atoll)(&arg[9]);
      }

So this commit:
- Improves the *_CLO_* macros so that they can be used in all circumstances.
  They're now just expressions (albeit ones with side-effects, setting the
  named variable appropriately).  Thus they can be used as if-conditions,
  and any post-checking or processing can occur in the then-statement.  And
  malformed numeric arguments (eg. --log-fd=foo) aren't accepted.  This also
  means you don't have to specify the lengths of any option strings anywhere
  (eg.  the 9 in the --log-fd example above).  The use of a wrong number
  caused at least one bug, in Massif.
- Updates all places where the macros were used.
- Updates Helgrind to use the *_CLO_* macros (it didn't use them).
- Updates Callgrind to use the *_CLO_* macros (it didn't use them), except
  for the more esoteric option names (those with numbers in the option
  name).  This allowed getUInt() and getUWord() to be removed.
- Improves the cache option parsing in Cachegrind and Callgrind -- now uses
  VG_(strtoll10)(), detects overflow, and is shorter.
- Uses INT instead of NUM in the macro names, to distinguish better vs. the
  DBL macro.
- Removes VG_(atoll*) and the few remaining uses -- they're wretched
  functions and VG_(strtoll*) should be used instead.
- Adds the VG_STREQN macro.
- Changes VG_BINT_CLO and VG_BHEX_CLO to abort if the given value is outside
  the range -- the current silent truncation is likely to cause confusion as
  much as anything.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@9255 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c
index 36ddbab..e356d0e 100644
--- a/cachegrind/cg_main.c
+++ b/cachegrind/cg_main.c
@@ -1645,50 +1645,48 @@
 
 static void parse_cache_opt ( cache_t* cache, Char* opt )
 {
-   Int i = 0, i2, i3;
+   Long i1, i2, i3;
+   Char* endptr;
 
-   // Option argument looks like "65536,2,64".
-   // Find commas, replace with NULs to make three independent 
-   // strings, then extract numbers, put NULs back.  Yuck.
-   while (VG_(isdigit)(opt[i])) i++;
-   if (',' == opt[i]) {
-      opt[i++] = '\0';
-      i2 = i;
-   } else goto bad;
-   while (VG_(isdigit)(opt[i])) i++;
-   if (',' == opt[i]) {
-      opt[i++] = '\0';
-      i3 = i;
-   } else goto bad;
-   while (VG_(isdigit)(opt[i])) i++;
-   if ('\0' != opt[i]) goto bad;
+   // Option argument looks like "65536,2,64".  Extract them.
+   i1 = VG_(strtoll10)(opt,      &endptr); if (*endptr != ',')  goto bad;
+   i2 = VG_(strtoll10)(endptr+1, &endptr); if (*endptr != ',')  goto bad;
+   i3 = VG_(strtoll10)(endptr+1, &endptr); if (*endptr != '\0') goto bad;
 
-   cache->size      = (Int)VG_(atoll)(opt);
-   cache->assoc     = (Int)VG_(atoll)(opt + i2);
-   cache->line_size = (Int)VG_(atoll)(opt + i3);
+   // Check for overflow.
+   cache->size      = (Int)i1;
+   cache->assoc     = (Int)i2;
+   cache->line_size = (Int)i3;
+   if (cache->size      != i1) goto overflow;
+   if (cache->assoc     != i2) goto overflow;
+   if (cache->line_size != i3) goto overflow;
 
-   opt[i2-1] = ',';
-   opt[i3-1] = ',';
    return;
 
+  overflow:
+   VG_(message)(Vg_UserMsg,
+                "one of the cache parameters was too large and overflowed\n");
   bad:
+   // XXX: this omits the "--I1/D1/L2=" part from the message, but that's
+   // not a big deal.
    VG_(err_bad_option)(opt);
 }
 
 static Bool cg_process_cmd_line_option(Char* arg)
 {
+   Char* tmp_str;
+
    // 5 is length of "--I1="
-   if      (VG_CLO_STREQN(5, arg, "--I1="))
-      parse_cache_opt(&clo_I1_cache, &arg[5]);
-   else if (VG_CLO_STREQN(5, arg, "--D1="))
-      parse_cache_opt(&clo_D1_cache, &arg[5]);
-   else if (VG_CLO_STREQN(5, arg, "--L2="))
-      parse_cache_opt(&clo_L2_cache, &arg[5]);
-   else if (VG_CLO_STREQN(22, arg, "--cachegrind-out-file=")) {
-      clo_cachegrind_out_file = &arg[22];
-   }
-   else VG_BOOL_CLO(arg, "--cache-sim",  clo_cache_sim)
-   else VG_BOOL_CLO(arg, "--branch-sim", clo_branch_sim)
+   if      VG_STR_CLO(arg, "--I1", tmp_str)
+      parse_cache_opt(&clo_I1_cache, tmp_str);
+   else if VG_STR_CLO(arg, "--D1", tmp_str)
+      parse_cache_opt(&clo_D1_cache, tmp_str);
+   else if VG_STR_CLO(arg, "--L2", tmp_str)
+      parse_cache_opt(&clo_L2_cache, tmp_str);
+
+   else if VG_STR_CLO( arg, "--cachegrind-out-file", clo_cachegrind_out_file) {}
+   else if VG_BOOL_CLO(arg, "--cache-sim",  clo_cache_sim)  {}
+   else if VG_BOOL_CLO(arg, "--branch-sim", clo_branch_sim) {}
    else
       return False;
 
diff --git a/callgrind/clo.c b/callgrind/clo.c
index 238d872..7058926 100644
--- a/callgrind/clo.c
+++ b/callgrind/clo.c
@@ -395,251 +395,127 @@
 /*--- Command line processing                                      ---*/
 /*--------------------------------------------------------------------*/
 
-static Char* getUInt(Char* s, UInt* pn)
-{
-    UInt n = 0;
-    while((*s >='0') && (*s <='9')) {
-	n = 10*n + (*s-'0');
-	s++;
-    }
-    if (pn) *pn = n;
-    return s;
-}
-
-__attribute__((unused))
-static UWord getUWord(Char* s)
-{
-    UWord n = 0;
-    Bool isHex = False;
-
-    if ((s[0] == '0') && (s[1] == 'x')) {
-	isHex = True;
-	s += 2;
-    }
-
-    if (!isHex) {
-	while((*s >='0') && (*s <='9')) {
-	    n = 10*n + (*s-'0');
-	    s++;
-	}
-    }
-    else {
-	while(1) {
-	    if ((*s >='0') && (*s <='9')) {
-		n = 16*n + (*s-'0');
-		s++;
-		continue;
-	    }
-	    if ((*s >='a') && (*s <='f')) {
-		n = 16*n + (*s-'a'+10);
-		s++;
-		continue;
-	    }
-	    if ((*s >='A') && (*s <='F')) {
-		n = 16*n + (*s-'A'+10);
-		s++;
-		continue;
-	    }
-	    break;
-	}
-    }
-
-    return n;
-}
-
 Bool CLG_(process_cmd_line_option)(Char* arg)
 {
-   if (0 == VG_(strcmp)(arg, "--skip-plt=yes"))
-       CLG_(clo).skip_plt = True;
-   else if (0 == VG_(strcmp)(arg, "--skip-plt=no"))
-       CLG_(clo).skip_plt = False;
+   Char* tmp_str;
 
-   else if (0 == VG_(strcmp)(arg, "--collect-jumps=yes"))
-       CLG_(clo).collect_jumps = True;
-   else if (0 == VG_(strcmp)(arg, "--collect-jumps=no"))
-       CLG_(clo).collect_jumps = False;
+   if      VG_BOOL_CLO(arg, "--skip-plt", CLG_(clo).skip_plt) {}
+
+   else if VG_BOOL_CLO(arg, "--collect-jumps", CLG_(clo).collect_jumps) {}
    /* compatibility alias, deprecated option */
-   else if (0 == VG_(strcmp)(arg, "--trace-jump=yes"))
-       CLG_(clo).collect_jumps = True;
-   else if (0 == VG_(strcmp)(arg, "--trace-jump=no"))
-       CLG_(clo).collect_jumps = False;
+   else if VG_BOOL_CLO(arg, "--trace-jump",    CLG_(clo).collect_jumps) {}
 
-   else if (0 == VG_(strcmp)(arg, "--combine-dumps=yes"))
-       CLG_(clo).combine_dumps = True;
-   else if (0 == VG_(strcmp)(arg, "--combine-dumps=no"))
-       CLG_(clo).combine_dumps = False;
+   else if VG_BOOL_CLO(arg, "--combine-dumps", CLG_(clo).combine_dumps) {}
 
-   else if (0 == VG_(strcmp)(arg, "--collect-atstart=yes"))
-       CLG_(clo).collect_atstart = True;
-   else if (0 == VG_(strcmp)(arg, "--collect-atstart=no"))
-       CLG_(clo).collect_atstart = False;
+   else if VG_BOOL_CLO(arg, "--collect-atstart", CLG_(clo).collect_atstart) {}
 
-   else if (0 == VG_(strcmp)(arg, "--instr-atstart=yes"))
-       CLG_(clo).instrument_atstart = True;
-   else if (0 == VG_(strcmp)(arg, "--instr-atstart=no"))
-       CLG_(clo).instrument_atstart = False;
+   else if VG_BOOL_CLO(arg, "--instr-atstart", CLG_(clo).instrument_atstart) {}
 
-   else if (0 == VG_(strcmp)(arg, "--separate-threads=yes"))
-       CLG_(clo).separate_threads = True;
-   else if (0 == VG_(strcmp)(arg, "--separate-threads=no"))
-       CLG_(clo).separate_threads = False;
+   else if VG_BOOL_CLO(arg, "--separate-threads", CLG_(clo).separate_threads) {}
 
-   else if (0 == VG_(strcmp)(arg, "--compress-strings=yes"))
-       CLG_(clo).compress_strings = True;
-   else if (0 == VG_(strcmp)(arg, "--compress-strings=no"))
-       CLG_(clo).compress_strings = False;
+   else if VG_BOOL_CLO(arg, "--compress-strings", CLG_(clo).compress_strings) {}
+   else if VG_BOOL_CLO(arg, "--compress-mangled", CLG_(clo).compress_mangled) {}
+   else if VG_BOOL_CLO(arg, "--compress-pos",     CLG_(clo).compress_pos) {}
 
-   else if (0 == VG_(strcmp)(arg, "--compress-mangled=yes"))
-       CLG_(clo).compress_mangled = True;
-   else if (0 == VG_(strcmp)(arg, "--compress-mangled=no"))
-       CLG_(clo).compress_mangled = False;
-
-   else if (0 == VG_(strcmp)(arg, "--compress-pos=yes"))
-       CLG_(clo).compress_pos = True;
-   else if (0 == VG_(strcmp)(arg, "--compress-pos=no"))
-       CLG_(clo).compress_pos = False;
-
-   else if (0 == VG_(strncmp)(arg, "--fn-skip=", 10)) {
-       fn_config* fnc = get_fnc(arg+10);
+   else if VG_STR_CLO(arg, "--fn-skip", tmp_str) {
+       fn_config* fnc = get_fnc(tmp_str);
        fnc->skip = CONFIG_TRUE;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--dump-before=", 14)) {
-       fn_config* fnc = get_fnc(arg+14);
+   else if VG_STR_CLO(arg, "--dump-before", tmp_str) {
+       fn_config* fnc = get_fnc(tmp_str);
        fnc->dump_before = CONFIG_TRUE;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--zero-before=", 14)) {
-       fn_config* fnc = get_fnc(arg+14);
+   else if VG_STR_CLO(arg, "--zero-before", tmp_str) {
+       fn_config* fnc = get_fnc(tmp_str);
        fnc->zero_before = CONFIG_TRUE;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--dump-after=", 13)) {
-       fn_config* fnc = get_fnc(arg+13);
+   else if VG_STR_CLO(arg, "--dump-after", tmp_str) {
+       fn_config* fnc = get_fnc(tmp_str);
        fnc->dump_after = CONFIG_TRUE;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--toggle-collect=", 17)) {
-       fn_config* fnc = get_fnc(arg+17);
+   else if VG_STR_CLO(arg, "--toggle-collect", tmp_str) {
+       fn_config* fnc = get_fnc(tmp_str);
        fnc->toggle_collect = CONFIG_TRUE;
        /* defaults to initial collection off */
        CLG_(clo).collect_atstart = False;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--separate-recs=", 16))
-        CLG_(clo).separate_recursions = (Int)VG_(atoll)(&arg[16]);
+   else if VG_INT_CLO(arg, "--separate-recs", CLG_(clo).separate_recursions) {}
 
    /* change handling of a jump between functions to ret+call */
-   else if (0 == VG_(strcmp)(arg, "--pop-on-jump")) {
-        CLG_(clo).pop_on_jump = True;
-   }
-   else if (0 == VG_(strncmp)(arg, "--pop-on-jump=", 14)) {
-       fn_config* fnc = get_fnc(arg+14);
+   else if VG_XACT_CLO(arg, "--pop-on-jump", CLG_(clo).pop_on_jump, True) {}
+   else if VG_STR_CLO( arg, "--pop-on-jump", tmp_str) {
+       fn_config* fnc = get_fnc(tmp_str);
        fnc->pop_on_jump = CONFIG_TRUE;
    }
 
 #if CLG_ENABLE_DEBUG
-   else if (0 == VG_(strncmp)(arg, "--ct-verbose=", 13))
-        CLG_(clo).verbose = (Int)VG_(atoll)(&arg[13]);
+   else if VG_INT_CLO(arg, "--ct-verbose", CLG_(clo).verbose) {}
+   else if VG_INT_CLO(arg, "--ct-vstart",  CLG_(clo).verbose_start) {}
 
-   else if (0 == VG_(strncmp)(arg, "--ct-vstart=", 12))
-        CLG_(clo).verbose_start = (ULong)VG_(atoll)(&arg[12]);
-
-   else if (0 == VG_(strncmp)(arg, "--ct-verbose", 12)) {
-       UInt n;
+   else if VG_STREQN(12, arg, "--ct-verbose") {
        fn_config* fnc;
-       Char* s = getUInt(arg+12, &n);
-       if ((n == 0) || *s != '=') return False;
+       Char* s;
+       UInt n = VG_(strtoll10)(arg+12, &s);
+       if ((n <= 0) || *s != '=') return False;
        fnc = get_fnc(s+1);
        fnc->verbosity = n;
    }
 #endif
 
-   else if (0 == VG_(strncmp)(arg, "--separate-callers=", 19)) {
-     if (0 == VG_(strcmp)(arg+19, "auto"))
-       CLG_(clo).separate_callers = CONFIG_AUTO;
-     else
-       CLG_(clo).separate_callers = (Int)VG_(atoll)(&arg[19]);
-   }
+   else if VG_XACT_CLO(arg, "--separate-callers=auto", 
+                            CLG_(clo).separate_callers, CONFIG_AUTO) {}
+   else if VG_INT_CLO( arg, "--separate-callers", 
+                            CLG_(clo).separate_callers) {}
 
-   else if (0 == VG_(strncmp)(arg, "--fn-group", 10)) {
-       UInt n;
+   else if VG_STREQN(10, arg, "--fn-group") {
        fn_config* fnc;
-       Char* s = getUInt(arg+10, &n);
-       if ((n == 0) || *s != '=') return False;
+       Char* s;
+       UInt n = VG_(strtoll10)(arg+10, &s);
+       if ((n <= 0) || *s != '=') return False;
        fnc = get_fnc(s+1);
        fnc->group = n;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--separate-callers", 18)) {
-       UInt n;
+   else if VG_STREQN(18, arg, "--separate-callers") {
        fn_config* fnc;
-       Char* s = getUInt(arg+18, &n);
-       if ((n == 0) || *s != '=') return False;
+       Char* s;
+       UInt n = VG_(strtoll10)(arg+18, &s);
+       if ((n <= 0) || *s != '=') return False;
        fnc = get_fnc(s+1);
        fnc->separate_callers = n;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--separate-recs", 15)) {
-       UInt n;
+   else if VG_STREQN(15, arg, "--separate-recs") {
        fn_config* fnc;
-       Char* s = getUInt(arg+15, &n);
-       if ((n == 0) || *s != '=') return False;
+       Char* s;
+       UInt n = VG_(strtoll10)(arg+15, &s);
+       if ((n <= 0) || *s != '=') return False;
        fnc = get_fnc(s+1);
        fnc->separate_recursions = n;
    }
 
-   else if (0 == VG_(strncmp)(arg, "--callgrind-out-file=", 21))
-       CLG_(clo).out_format = VG_(strdup)("cl.clo.pclo.1", arg+21);
+   else if VG_STR_CLO(arg, "--callgrind-out-file", CLG_(clo).out_format) {}
 
-   else if (0 == VG_(strcmp)(arg, "--mangle-names=yes"))
-       CLG_(clo).mangle_names = True;
-   else if (0 == VG_(strcmp)(arg, "--mangle-names=no"))
-       CLG_(clo).mangle_names = False;
+   else if VG_BOOL_CLO(arg, "--mangle-names", CLG_(clo).mangle_names) {}
 
-   else if (0 == VG_(strcmp)(arg, "--skip-direct-rec=yes"))
-       CLG_(clo).skip_direct_recursion = True;
-   else if (0 == VG_(strcmp)(arg, "--skip-direct-rec=no"))
-       CLG_(clo).skip_direct_recursion = False;
+   else if VG_BOOL_CLO(arg, "--skip-direct-rec",
+                            CLG_(clo).skip_direct_recursion) {}
 
-   else if (0 == VG_(strcmp)(arg, "--dump-bbs=yes"))
-       CLG_(clo).dump_bbs = True;
-   else if (0 == VG_(strcmp)(arg, "--dump-bbs=no"))
-       CLG_(clo).dump_bbs = False;
+   else if VG_BOOL_CLO(arg, "--dump-bbs",   CLG_(clo).dump_bbs) {}
+   else if VG_BOOL_CLO(arg, "--dump-line",  CLG_(clo).dump_line) {}
+   else if VG_BOOL_CLO(arg, "--dump-instr", CLG_(clo).dump_instr) {}
+   else if VG_BOOL_CLO(arg, "--dump-bb",    CLG_(clo).dump_bb) {}
 
-   else if (0 == VG_(strcmp)(arg, "--dump-line=yes"))
-       CLG_(clo).dump_line = True;
-   else if (0 == VG_(strcmp)(arg, "--dump-line=no"))
-       CLG_(clo).dump_line = False;
+   else if VG_INT_CLO( arg, "--dump-every-bb", CLG_(clo).dump_every_bb) {}
 
-   else if (0 == VG_(strcmp)(arg, "--dump-instr=yes"))
-       CLG_(clo).dump_instr = True;
-   else if (0 == VG_(strcmp)(arg, "--dump-instr=no"))
-       CLG_(clo).dump_instr = False;
-
-   else if (0 == VG_(strcmp)(arg, "--dump-bb=yes"))
-       CLG_(clo).dump_bb = True;
-   else if (0 == VG_(strcmp)(arg, "--dump-bb=no"))
-       CLG_(clo).dump_bb = False;
-
-   else if (0 == VG_(strncmp)(arg, "--dump-every-bb=", 16))
-        CLG_(clo).dump_every_bb = (ULong)VG_(atoll)(&arg[16]);
-
-
-   else if (0 == VG_(strcmp)(arg, "--collect-alloc=yes"))
-       CLG_(clo).collect_alloc = True;
-   else if (0 == VG_(strcmp)(arg, "--collect-alloc=no"))
-       CLG_(clo).collect_alloc = False;
-
-   else if (0 == VG_(strcmp)(arg, "--collect-systime=yes"))
-       CLG_(clo).collect_systime = True;
-   else if (0 == VG_(strcmp)(arg, "--collect-systime=no"))
-       CLG_(clo).collect_systime = False;
-
-   else if (0 == VG_(strcmp)(arg, "--simulate-cache=yes"))
-       CLG_(clo).simulate_cache = True;
-   else if (0 == VG_(strcmp)(arg, "--simulate-cache=no"))
-       CLG_(clo).simulate_cache = False;
+   else if VG_BOOL_CLO(arg, "--collect-alloc",   CLG_(clo).collect_alloc) {}
+   else if VG_BOOL_CLO(arg, "--collect-systime", CLG_(clo).collect_systime) {}
+   else if VG_BOOL_CLO(arg, "--simulate-cache",  CLG_(clo).simulate_cache) {}
 
    else {
        Bool isCachesimOption = (*CLG_(cachesim).parse_opt)(arg);
diff --git a/callgrind/sim.c b/callgrind/sim.c
index 5208a72..d6c1211 100644
--- a/callgrind/sim.c
+++ b/callgrind/sim.c
@@ -1506,40 +1506,33 @@
 	      );
 }
 
-static void parse_opt ( cache_t* cache, char* orig_opt, int opt_len )
+static void parse_opt ( cache_t* cache, char* opt )
 {
-   int   i1, i2, i3;
-   int   i;
-   char *opt = VG_(strdup)("cl.sim.po.1", orig_opt);
+   Long i1, i2, i3;
+   Char* endptr;
 
-   i = i1 = opt_len;
+   // Option argument looks like "65536,2,64".  Extract them.
+   i1 = VG_(strtoll10)(opt,      &endptr); if (*endptr != ',')  goto bad;
+   i2 = VG_(strtoll10)(endptr+1, &endptr); if (*endptr != ',')  goto bad;
+   i3 = VG_(strtoll10)(endptr+1, &endptr); if (*endptr != '\0') goto bad;
 
-   /* Option looks like "--I1=65536,2,64".
-    * Find commas, replace with NULs to make three independent 
-    * strings, then extract numbers.  Yuck. */
-   while (VG_(isdigit)(opt[i])) i++;
-   if (',' == opt[i]) {
-      opt[i++] = '\0';
-      i2 = i;
-   } else goto bad;
-   while (VG_(isdigit)(opt[i])) i++;
-   if (',' == opt[i]) {
-      opt[i++] = '\0';
-      i3 = i;
-   } else goto bad;
-   while (VG_(isdigit)(opt[i])) i++;
-   if ('\0' != opt[i]) goto bad;
-
-   cache->size      = (Int)VG_(atoll)(opt + i1);
-   cache->assoc     = (Int)VG_(atoll)(opt + i2);
-   cache->line_size = (Int)VG_(atoll)(opt + i3);
-
-   VG_(free)(opt);
+   // Check for overflow.
+   cache->size      = (Int)i1;
+   cache->assoc     = (Int)i2;
+   cache->line_size = (Int)i3;
+   if (cache->size      != i1) goto overflow;
+   if (cache->assoc     != i2) goto overflow;
+   if (cache->line_size != i3) goto overflow;
 
    return;
 
+  overflow:
+   VG_(message)(Vg_UserMsg,
+                "one of the cache parameters was too large and overflowed\n");
   bad:
-   VG_(err_bad_option)(orig_opt);
+   // XXX: this omits the "--I1/D1/L2=" part from the message, but that's
+   // not a big deal.
+   VG_(err_bad_option)(opt);
 }
 
 /* Check for command line option for cache configuration.
@@ -1549,36 +1542,25 @@
  */
 static Bool cachesim_parse_opt(Char* arg)
 {
-  if (0 == VG_(strcmp)(arg, "--simulate-wb=yes"))
-    clo_simulate_writeback = True;
-  else if (0 == VG_(strcmp)(arg, "--simulate-wb=no"))
-    clo_simulate_writeback = False;
+   Char* tmp_str;
 
-  else if (0 == VG_(strcmp)(arg, "--simulate-hwpref=yes"))
-    clo_simulate_hwpref = True;
-  else if (0 == VG_(strcmp)(arg, "--simulate-hwpref=no"))
-    clo_simulate_hwpref = False;
+   if      VG_BOOL_CLO(arg, "--simulate-wb",      clo_simulate_writeback) {}
+   else if VG_BOOL_CLO(arg, "--simulate-hwpref",  clo_simulate_hwpref)    {}
+   else if VG_BOOL_CLO(arg, "--simulate-sectors", clo_simulate_sectors)   {}
 
-  else if (0 == VG_(strcmp)(arg, "--simulate-sectors=yes"))
-    clo_simulate_sectors = True;
-  else if (0 == VG_(strcmp)(arg, "--simulate-sectors=no"))
-    clo_simulate_sectors = False;
+   else if VG_BOOL_CLO(arg, "--cacheuse", clo_collect_cacheuse) {
+      if (clo_collect_cacheuse) {
+         /* Use counters only make sense with fine dumping */
+         CLG_(clo).dump_instr = True;
+      }
+   }
 
-  else if (0 == VG_(strcmp)(arg, "--cacheuse=yes")) {
-    clo_collect_cacheuse = True;
-    /* Use counters only make sense with fine dumping */
-    CLG_(clo).dump_instr = True;
-  }
-  else if (0 == VG_(strcmp)(arg, "--cacheuse=no"))
-    clo_collect_cacheuse = False;
-
-  /* 5 is length of "--I1=" */
-  else if (0 == VG_(strncmp)(arg, "--I1=", 5))
-    parse_opt(&clo_I1_cache, arg,   5);
-  else if (0 == VG_(strncmp)(arg, "--D1=", 5))
-    parse_opt(&clo_D1_cache, arg,   5);
-  else if (0 == VG_(strncmp)(arg, "--L2=", 5))
-    parse_opt(&clo_L2_cache, arg,   5);
+   else if VG_STR_CLO(arg, "--I1", tmp_str)
+      parse_opt(&clo_I1_cache, tmp_str);
+   else if VG_STR_CLO(arg, "--D1", tmp_str)
+      parse_opt(&clo_D1_cache, tmp_str);
+   else if VG_STR_CLO(arg, "--L2", tmp_str)
+      parse_opt(&clo_L2_cache, tmp_str);
   else
     return False;
 
diff --git a/coregrind/m_demangle/vg_libciface.h b/coregrind/m_demangle/vg_libciface.h
index a4bb105..44ca0c5 100644
--- a/coregrind/m_demangle/vg_libciface.h
+++ b/coregrind/m_demangle/vg_libciface.h
@@ -45,7 +45,7 @@
 
 
 #define abort()              vg_assert(0)
-#define atoi(_str)           VG_(atoll)((_str))
+#define atoi(_str)           VG_(strtoll10)((_str), NULL)
 #define free(_pt)            VG_(arena_free)   (VG_AR_DEMANGLE,(_pt))
 #define memcmp(_s1,_s2,_sz)  VG_(memcmp)((_s1),(_s2),(_sz))
 #define memcpy(_dd,_ss,_sz)  VG_(memcpy)((_dd),(_ss),(_sz))
diff --git a/coregrind/m_libcbase.c b/coregrind/m_libcbase.c
index cf98350..abce99a 100644
--- a/coregrind/m_libcbase.c
+++ b/coregrind/m_libcbase.c
@@ -155,16 +155,6 @@
    return n;
 }
 
-Long VG_(atoll) ( Char* str )
-{
-   return VG_(strtoll10)(str, NULL);
-}
-
-Long VG_(atoll16) ( Char* str )
-{
-   return VG_(strtoll16)(str, NULL);
-}
-
 /* ---------------------------------------------------------------------
    String functions
    ------------------------------------------------------------------ */
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index 9e4cd3e..bd31d63 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -401,8 +401,13 @@
       res = VG_(do_syscall3)(__NR_readlink, (UWord)"/proc/self",
                              (UWord)pid, sizeof(pid));
       if (!res.isError && res.res > 0) {
+         Char* s;
          pid[res.res] = '\0';
-         res.res = VG_(atoll)(pid);
+         res.res = VG_(strtoll10)(pid, &s);
+         if (*s != '\0') {
+            VG_(message)(Vg_DebugMsg, 
+               "Warning: invalid file name linked to by /proc/self: %s", pid);
+         }
       }
    }
 
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 8322da5..f8258d4 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -273,31 +273,25 @@
       str = * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i );
       vg_assert(str);
 
-      if (VG_STREQ(str, "--version")) {
-         // Ensure the version string goes to stdout
-         VG_(clo_log_fd) = 1;
+      // Nb: the version string goes to stdout.
+      if VG_XACT_CLO(str, "--version", VG_(clo_log_fd), 1) {
          VG_(printf)("valgrind-" VERSION "\n");
          VG_(exit)(0);
+      }
+      else if VG_XACT_CLO(str, "--help", *need_help, 1) {}
+      else if VG_XACT_CLO(str, "-h",     *need_help, 1) {}
 
-      } else if (VG_CLO_STREQ(str, "--help") ||
-                 VG_CLO_STREQ(str, "-h")) {
-         *need_help = 1;
-
-      } else if (VG_CLO_STREQ(str, "--help-debug")) {
-         *need_help = 2;
+      else if VG_XACT_CLO(str, "--help-debug", *need_help, 2) {}
 
       // The tool has already been determined, but we need to know the name
       // here.
-      } else if (VG_CLO_STREQN(7, str, "--tool=")) {
-         *tool = &str[7];
+      else if VG_STR_CLO(str, "--tool", *tool) {} 
 
       // Set up VG_(clo_max_stackframe) and VG_(clo_main_stacksize).
       // These are needed by VG_(ii_create_image), which happens
       // before main_process_cmd_line_options().
-      } 
-      else VG_NUM_CLO(str, "--max-stackframe", VG_(clo_max_stackframe))
-      else VG_NUM_CLO(str, "--main-stacksize", VG_(clo_main_stacksize));
-
+      else if VG_INT_CLO(str, "--max-stackframe", VG_(clo_max_stackframe)) {}
+      else if VG_INT_CLO(str, "--main-stacksize", VG_(clo_main_stacksize)) {}
    }
 }
 
@@ -312,6 +306,7 @@
    SysRes sres;
    Int    i, tmp_log_fd;
    Int    toolname_len = VG_(strlen)(toolname);
+   Char*  tmp_str;         // Used in a couple of places.
    enum {
       VgLogTo_Fd,
       VgLogTo_File,
@@ -341,9 +336,9 @@
       // in case someone has combined a prefix with a core-specific option,
       // eg.  "--memcheck:verbose".
       if (*colon == ':') {
-         if (VG_CLO_STREQN(2,            arg,                "--") && 
-             VG_CLO_STREQN(toolname_len, arg+2,              toolname) &&
-             VG_CLO_STREQN(1,            arg+2+toolname_len, ":"))
+         if (VG_STREQN(2,            arg,                "--") && 
+             VG_STREQN(toolname_len, arg+2,              toolname) &&
+             VG_STREQN(1,            arg+2+toolname_len, ":"))
          {
             // Prefix matches, convert "--toolname:foo" to "--foo".
             // Two things to note:
@@ -373,134 +368,124 @@
       }
       
       /* Ignore these options - they've already been handled */
-      if      (VG_CLO_STREQN( 7, arg, "--tool="))              { }
-      else if (VG_CLO_STREQN(20, arg, "--command-line-only=")) { }
-      else if (VG_CLO_STREQ(arg, "--"))                        { }
-      else if (VG_CLO_STREQ(arg, "-d"))                        { }
+      if      VG_STREQN( 7, arg, "--tool=")              {}
+      else if VG_STREQN(20, arg, "--command-line-only=") {}
+      else if VG_STREQ(     arg, "--")                   {}
+      else if VG_STREQ(     arg, "-d")                   {}
+      else if VG_STREQN(16, arg, "--max-stackframe")     {}
+      else if VG_STREQN(16, arg, "--main-stacksize")     {}
+      else if VG_STREQN(14, arg, "--profile-heap")       {}
 
-      else if (VG_CLO_STREQ(arg, "-v") ||
-               VG_CLO_STREQ(arg, "--verbose"))
+      // These options are new.
+      else if (VG_STREQ(arg, "-v") ||
+               VG_STREQ(arg, "--verbose"))
          VG_(clo_verbosity)++;
 
-      else if (VG_CLO_STREQ(arg, "-q") ||
-               VG_CLO_STREQ(arg, "--quiet"))
+      else if (VG_STREQ(arg, "-q") ||
+               VG_STREQ(arg, "--quiet"))
          VG_(clo_verbosity)--;
 
-      else VG_BOOL_CLO(arg, "--xml",              VG_(clo_xml))
-      else VG_BOOL_CLO(arg, "--db-attach",        VG_(clo_db_attach))
-      else VG_BOOL_CLO(arg, "--demangle",         VG_(clo_demangle))
-      else VG_BOOL_CLO(arg, "--error-limit",      VG_(clo_error_limit))
-      else VG_NUM_CLO (arg, "--error-exitcode",   VG_(clo_error_exitcode))
-      else VG_BOOL_CLO(arg, "--show-emwarns",     VG_(clo_show_emwarns))
+      else if VG_BOOL_CLO(arg, "--xml",            VG_(clo_xml)) {}
+      else if VG_BOOL_CLO(arg, "--db-attach",      VG_(clo_db_attach)) {}
+      else if VG_BOOL_CLO(arg, "--demangle",       VG_(clo_demangle)) {}
+      else if VG_BOOL_CLO(arg, "--error-limit",    VG_(clo_error_limit)) {}
+      else if VG_INT_CLO (arg, "--error-exitcode", VG_(clo_error_exitcode)) {}
+      else if VG_BOOL_CLO(arg, "--show-emwarns",   VG_(clo_show_emwarns)) {}
 
-      /* The next two are already done in
-         early_process_cmd_line_options, but we need to redundantly
-         handle them again, so they do not get rejected as invalid. */
-      else VG_NUM_CLO (arg, "--max-stackframe",   VG_(clo_max_stackframe))
-      else VG_NUM_CLO (arg, "--main-stacksize",   VG_(clo_main_stacksize))
+      else if VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres)) {}
+      else if VG_BOOL_CLO(arg, "--show-below-main",  VG_(clo_show_below_main)) {}
+      else if VG_BOOL_CLO(arg, "--time-stamp",       VG_(clo_time_stamp)) {}
+      else if VG_BOOL_CLO(arg, "--track-fds",        VG_(clo_track_fds)) {}
+      else if VG_BOOL_CLO(arg, "--trace-children",   VG_(clo_trace_children)) {}
+      else if VG_BOOL_CLO(arg, "--child-silent-after-fork",
+                            VG_(clo_child_silent_after_fork)) {}
+      else if VG_BOOL_CLO(arg, "--trace-sched",      VG_(clo_trace_sched)) {}
+      else if VG_BOOL_CLO(arg, "--trace-signals",    VG_(clo_trace_signals)) {}
+      else if VG_BOOL_CLO(arg, "--trace-symtab",     VG_(clo_trace_symtab)) {}
+      else if VG_STR_CLO (arg, "--trace-symtab-patt", VG_(clo_trace_symtab_patt)) {}
+      else if VG_BOOL_CLO(arg, "--trace-cfi",        VG_(clo_trace_cfi)) {}
+      else if VG_XACT_CLO(arg, "--debug-dump=syms",  VG_(clo_debug_dump_syms),
+                                                     True) {}
+      else if VG_XACT_CLO(arg, "--debug-dump=line",  VG_(clo_debug_dump_line),
+                                                     True) {}
+      else if VG_XACT_CLO(arg, "--debug-dump=frames",
+                               VG_(clo_debug_dump_frames), True) {}
+      else if VG_BOOL_CLO(arg, "--trace-redir",      VG_(clo_trace_redir)) {}
 
-      else VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres))
-      else VG_BOOL_CLO(arg, "--show-below-main",  VG_(clo_show_below_main))
-      else VG_BOOL_CLO(arg, "--time-stamp",       VG_(clo_time_stamp))
-      else VG_BOOL_CLO(arg, "--track-fds",        VG_(clo_track_fds))
-      else VG_BOOL_CLO(arg, "--trace-children",   VG_(clo_trace_children))
-      else VG_BOOL_CLO(arg, "--child-silent-after-fork",
-                            VG_(clo_child_silent_after_fork))
-      else VG_BOOL_CLO(arg, "--trace-sched",      VG_(clo_trace_sched))
-      else VG_BOOL_CLO(arg, "--trace-signals",    VG_(clo_trace_signals))
-      else VG_BOOL_CLO(arg, "--trace-symtab",     VG_(clo_trace_symtab))
-      else VG_STR_CLO (arg, "--trace-symtab-patt", VG_(clo_trace_symtab_patt))
-      else VG_BOOL_CLO(arg, "--trace-cfi",        VG_(clo_trace_cfi))
-      else VG_XACT_CLO(arg, "--debug-dump=syms",  VG_(clo_debug_dump_syms))
-      else VG_XACT_CLO(arg, "--debug-dump=line",  VG_(clo_debug_dump_line))
-      else VG_XACT_CLO(arg, "--debug-dump=frames", VG_(clo_debug_dump_frames))
-      else VG_BOOL_CLO(arg, "--trace-redir",      VG_(clo_trace_redir))
+      else if VG_BOOL_CLO(arg, "--trace-syscalls",   VG_(clo_trace_syscalls)) {}
+      else if VG_BOOL_CLO(arg, "--wait-for-gdb",     VG_(clo_wait_for_gdb)) {}
+      else if VG_STR_CLO (arg, "--db-command",       VG_(clo_db_command)) {}
+      else if VG_STR_CLO (arg, "--sim-hints",        VG_(clo_sim_hints)) {}
+      else if VG_BOOL_CLO(arg, "--sym-offsets",      VG_(clo_sym_offsets)) {}
+      else if VG_BOOL_CLO(arg, "--read-var-info",    VG_(clo_read_var_info)) {}
 
-      else VG_BOOL_CLO(arg, "--trace-syscalls",   VG_(clo_trace_syscalls))
-      else VG_BOOL_CLO(arg, "--wait-for-gdb",     VG_(clo_wait_for_gdb))
-      else VG_STR_CLO (arg, "--db-command",       VG_(clo_db_command))
-      else VG_STR_CLO (arg, "--sim-hints",        VG_(clo_sim_hints))
-      else VG_BOOL_CLO(arg, "--sym-offsets",      VG_(clo_sym_offsets))
-      else VG_BOOL_CLO(arg, "--read-var-info",    VG_(clo_read_var_info))
+      else if VG_INT_CLO (arg, "--dump-error",       VG_(clo_dump_error))   {}
+      else if VG_INT_CLO (arg, "--input-fd",         VG_(clo_input_fd))     {}
+      else if VG_INT_CLO (arg, "--sanity-level",     VG_(clo_sanity_level)) {}
+      else if VG_BINT_CLO(arg, "--num-callers",      VG_(clo_backtrace_size), 1,
+                                                     VG_DEEPEST_BACKTRACE) {}
 
-      else VG_NUM_CLO (arg, "--dump-error",       VG_(clo_dump_error))
-      else VG_NUM_CLO (arg, "--input-fd",         VG_(clo_input_fd))
-      else VG_NUM_CLO (arg, "--sanity-level",     VG_(clo_sanity_level))
-      else VG_BNUM_CLO(arg, "--num-callers",      VG_(clo_backtrace_size), 1,
-                                                  VG_DEEPEST_BACKTRACE)
+      else if VG_XACT_CLO(arg, "--smc-check=none",  VG_(clo_smc_check),
+                                                    Vg_SmcNone);
+      else if VG_XACT_CLO(arg, "--smc-check=stack", VG_(clo_smc_check),
+                                                    Vg_SmcStack);
+      else if VG_XACT_CLO(arg, "--smc-check=all",   VG_(clo_smc_check),
+                                                    Vg_SmcAll);
 
-      else if (VG_CLO_STREQ(arg, "--smc-check=none"))
-         VG_(clo_smc_check) = Vg_SmcNone;
-      else if (VG_CLO_STREQ(arg, "--smc-check=stack"))
-         VG_(clo_smc_check) = Vg_SmcStack;
-      else if (VG_CLO_STREQ(arg, "--smc-check=all"))
-         VG_(clo_smc_check) = Vg_SmcAll;
+      else if VG_STR_CLO (arg, "--kernel-variant",   VG_(clo_kernel_variant)) {}
 
-      else if (VG_CLO_STREQ(arg, "--profile-heap=no"))
-         ; /* We already handled it right at the top of valgrind_main.
-              Just ignore. */
-      else if (VG_CLO_STREQ(arg, "--profile-heap=yes"))
-         ; /* ditto */
+      else if VG_BINT_CLO(arg, "--vex-iropt-verbosity",
+                       VG_(clo_vex_control).iropt_verbosity, 0, 10) {}
+      else if VG_BINT_CLO(arg, "--vex-iropt-level",
+                       VG_(clo_vex_control).iropt_level, 0, 2) {}
+      else if VG_BOOL_CLO(arg, "--vex-iropt-precise-memory-exns",
+                       VG_(clo_vex_control).iropt_precise_memory_exns) {}
+      else if VG_BINT_CLO(arg, "--vex-iropt-unroll-thresh",
+                       VG_(clo_vex_control).iropt_unroll_thresh, 0, 400) {}
+      else if VG_BINT_CLO(arg, "--vex-guest-max-insns",
+                       VG_(clo_vex_control).guest_max_insns, 1, 100) {}
+      else if VG_BINT_CLO(arg, "--vex-guest-chase-thresh",
+                       VG_(clo_vex_control).guest_chase_thresh, 0, 99) {}
 
-      else VG_STR_CLO (arg, "--kernel-variant",   VG_(clo_kernel_variant))
-
-      else VG_BNUM_CLO(arg, "--vex-iropt-verbosity",
-                       VG_(clo_vex_control).iropt_verbosity, 0, 10)
-      else VG_BNUM_CLO(arg, "--vex-iropt-level",
-                       VG_(clo_vex_control).iropt_level, 0, 2)
-      else VG_BOOL_CLO(arg, "--vex-iropt-precise-memory-exns",
-                       VG_(clo_vex_control).iropt_precise_memory_exns)
-      else VG_BNUM_CLO(arg, "--vex-iropt-unroll-thresh",
-                       VG_(clo_vex_control).iropt_unroll_thresh, 0, 400)
-      else VG_BNUM_CLO(arg, "--vex-guest-max-insns",
-                       VG_(clo_vex_control).guest_max_insns, 1, 100)
-      else VG_BNUM_CLO(arg, "--vex-guest-chase-thresh",
-                       VG_(clo_vex_control).guest_chase_thresh, 0, 99)
-
-      else if (VG_CLO_STREQN(9,  arg, "--log-fd=")) {
-         log_to            = VgLogTo_Fd;
+      else if VG_INT_CLO(arg, "--log-fd", tmp_log_fd) {
+         log_to = VgLogTo_Fd;
          VG_(clo_log_name) = NULL;
-         tmp_log_fd        = (Int)VG_(atoll)(&arg[9]);
       }
 
-      else if (VG_CLO_STREQN(11, arg, "--log-file=")) {
-         log_to            = VgLogTo_File;
-         VG_(clo_log_name) = &arg[11];
+      else if VG_STR_CLO(arg, "--log-file", VG_(clo_log_name)) {
+         log_to = VgLogTo_File;
       }
 
-      else if (VG_CLO_STREQN(13, arg, "--log-socket=")) {
-         log_to            = VgLogTo_Socket;
-         VG_(clo_log_name) = &arg[13];
+      else if VG_STR_CLO(arg, "--log-socket", VG_(clo_log_name)) {
+         log_to = VgLogTo_Socket;
       }
 
-      else if (VG_CLO_STREQN(19, arg, "--xml-user-comment=")) {
-         VG_(clo_xml_user_comment) = &arg[19];
-      }
+      else if VG_STR_CLO(arg, "--xml-user-comment",
+                              VG_(clo_xml_user_comment)) {}
 
-      else if (VG_CLO_STREQN(15, arg, "--suppressions=")) {
+      else if VG_STR_CLO(arg, "--suppressions", tmp_str) {
          if (VG_(clo_n_suppressions) >= VG_CLO_MAX_SFILES) {
             VG_(message)(Vg_UserMsg, "Too many suppression files specified.");
             VG_(message)(Vg_UserMsg, 
                          "Increase VG_CLO_MAX_SFILES and recompile.");
             VG_(err_bad_option)(arg);
          }
-         VG_(clo_suppressions)[VG_(clo_n_suppressions)] = &arg[15];
+         VG_(clo_suppressions)[VG_(clo_n_suppressions)] = tmp_str;
          VG_(clo_n_suppressions)++;
       }
 
       /* "stuvwxyz" --> stuvwxyz (binary) */
-      else if (VG_CLO_STREQN(14, arg, "--trace-flags=")) {
+      else if VG_STR_CLO(arg, "--trace-flags", tmp_str) {
          Int j;
-         char* opt = & arg[14];
    
-         if (8 != VG_(strlen)(opt)) {
+         if (8 != VG_(strlen)(tmp_str)) {
             VG_(message)(Vg_UserMsg, 
                          "--trace-flags argument must have 8 digits");
             VG_(err_bad_option)(arg);
          }
          for (j = 0; j < 8; j++) {
-            if      ('0' == opt[j]) { /* do nothing */ }
-            else if ('1' == opt[j]) VG_(clo_trace_flags) |= (1 << (7-j));
+            if      ('0' == tmp_str[j]) { /* do nothing */ }
+            else if ('1' == tmp_str[j]) VG_(clo_trace_flags) |= (1 << (7-j));
             else {
                VG_(message)(Vg_UserMsg, "--trace-flags argument can only "
                                         "contain 0s and 1s");
@@ -510,18 +495,17 @@
       }
 
       /* "stuvwxyz" --> stuvwxyz (binary) */
-      else if (VG_CLO_STREQN(16, arg, "--profile-flags=")) {
+      else if VG_STR_CLO(arg, "--profile-flags", tmp_str) {
          Int j;
-         char* opt = & arg[16];
    
-         if (8 != VG_(strlen)(opt)) {
+         if (8 != VG_(strlen)(tmp_str)) {
             VG_(message)(Vg_UserMsg, 
                          "--profile-flags argument must have 8 digits");
             VG_(err_bad_option)(arg);
          }
          for (j = 0; j < 8; j++) {
-            if      ('0' == opt[j]) { /* do nothing */ }
-            else if ('1' == opt[j]) VG_(clo_profile_flags) |= (1 << (7-j));
+            if      ('0' == tmp_str[j]) { /* do nothing */ }
+            else if ('1' == tmp_str[j]) VG_(clo_profile_flags) |= (1 << (7-j));
             else {
                VG_(message)(Vg_UserMsg, "--profile-flags argument can only "
                                         "contain 0s and 1s");
@@ -530,14 +514,14 @@
          }
       }
 
-      else VG_NUM_CLO (arg, "--trace-notbelow",   VG_(clo_trace_notbelow))
+      else if VG_INT_CLO (arg, "--trace-notbelow", VG_(clo_trace_notbelow)) {}
 
-      else if (VG_CLO_STREQ(arg, "--gen-suppressions=no"))
-         VG_(clo_gen_suppressions) = 0;
-      else if (VG_CLO_STREQ(arg, "--gen-suppressions=yes"))
-         VG_(clo_gen_suppressions) = 1;
-      else if (VG_CLO_STREQ(arg, "--gen-suppressions=all"))
-         VG_(clo_gen_suppressions) = 2;
+      else if VG_XACT_CLO(arg, "--gen-suppressions=no",
+                               VG_(clo_gen_suppressions), 0) {}
+      else if VG_XACT_CLO(arg, "--gen-suppressions=yes",
+                               VG_(clo_gen_suppressions), 1) {}
+      else if VG_XACT_CLO(arg, "--gen-suppressions=all",
+                               VG_(clo_gen_suppressions), 2) {}
 
       else if ( ! VG_(needs).command_line_options
              || ! VG_TDICT_CALL(tool_process_cmd_line_option, arg) ) {
@@ -1206,19 +1190,15 @@
    //   p: none
    //--------------------------------------------------------------
    /* Start the debugging-log system ASAP.  First find out how many 
-      "-d"s were specified.  This is a pre-scan of the command line. */
+      "-d"s were specified.  This is a pre-scan of the command line.  Also
+      get --profile-heap=yes which is needed by the time we start up dynamic
+      memory management.  */
    loglevel = 0;
    for (i = 1; i < argc; i++) {
-      if (argv[i][0] != '-')
-         break;
-      if (VG_STREQ(argv[i], "--")) 
-         break;
-      if (VG_STREQ(argv[i], "-d")) 
-         loglevel++;
-      if (VG_STREQ(argv[i], "--profile-heap=yes"))
-         VG_(clo_profile_heap) = True;
-      if (VG_STREQ(argv[i], "--profile-heap=no"))
-         VG_(clo_profile_heap) = False;
+      if (argv[i][0] != '-') break;
+      if VG_STREQ(argv[i], "--") break;
+      if VG_STREQ(argv[i], "-d") loglevel++;
+      if VG_BOOL_CLO(argv[i], "--profile-heap", VG_(clo_profile_heap)) {}
    }
 
    /* ... and start the debug logger.  Now we can safely emit logging
@@ -1330,6 +1310,7 @@
    //--------------------------------------------------------------
    // Start up the dynamic memory manager
    //   p: address space management
+   //   p: getting --profile-heap
    //   In fact m_mallocfree is self-initialising, so there's no
    //   initialisation call to do.  Instead, try a simple malloc/
    //   free pair right now to check that nothing is broken.
@@ -1481,7 +1462,9 @@
 
    //--------------------------------------------------------------
    // Load client executable, finding in $PATH if necessary
-   //   p: early_process_cmd_line_options()  [for 'exec', 'need_help']
+   //   p: early_process_cmd_line_options()  [for 'exec', 'need_help',
+   //                                         clo_max_stackframe,
+   //                                         clo_main_stacksize]
    //   p: layout_remaining_space            [so there's space]
    //
    // Set up client's environment
diff --git a/coregrind/m_replacemalloc/replacemalloc_core.c b/coregrind/m_replacemalloc/replacemalloc_core.c
index 175402b..4373232 100644
--- a/coregrind/m_replacemalloc/replacemalloc_core.c
+++ b/coregrind/m_replacemalloc/replacemalloc_core.c
@@ -53,13 +53,11 @@
 
 Bool VG_(replacement_malloc_process_cmd_line_option)(Char* arg)
 {
-   if (VG_CLO_STREQN(12, arg, "--alignment=")) {
-      VG_(clo_alignment) = (UInt)VG_(atoll)(&arg[12]);
-
-      if (VG_(clo_alignment) < VG_MIN_MALLOC_SZB
-          || VG_(clo_alignment) > 4096
-          || VG_(log2)( VG_(clo_alignment) ) == -1 /* not a power of 2 */) {
-         VG_(message)(Vg_UserMsg, "");
+   if VG_INT_CLO(arg, "--alignment", VG_(clo_alignment)) {
+      if (VG_(clo_alignment) < VG_MIN_MALLOC_SZB ||
+          VG_(clo_alignment) > 4096 ||
+          VG_(log2)( VG_(clo_alignment) ) == -1 /* not a power of 2 */)
+      {
          VG_(message)(Vg_UserMsg, 
             "Invalid --alignment= setting.  "
             "Should be a power of 2, >= %d, <= 4096.", VG_MIN_MALLOC_SZB);
@@ -67,7 +65,7 @@
       }
    }
 
-   else VG_BOOL_CLO(arg, "--trace-malloc",  VG_(clo_trace_malloc))
+   else if VG_BOOL_CLO(arg, "--trace-malloc",  VG_(clo_trace_malloc)) {}
    else 
       return False;
 
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index ca07ffe..9e26c58 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -750,11 +750,16 @@
          goto out;
 
       if (VG_(strcmp)(d.d_name, ".") && VG_(strcmp)(d.d_name, "..")) {
-         Int fno = VG_(atoll)(d.d_name);
-
-         if (fno != f.res)
-            if (VG_(clo_track_fds))
-               ML_(record_fd_open_named)(-1, fno);
+         Char* s;
+         Int fno = VG_(strtoll10)(d.d_name, &s);
+         if (*s == '\0') {
+            if (fno != f.res)
+               if (VG_(clo_track_fds))
+                  ML_(record_fd_open_named)(-1, fno);
+         } else {
+            VG_(message)(Vg_DebugMsg, 
+               "Warning: invalid file name in /proc/self/fd: %s", d.d_name);
+         }
       }
 
       VG_(lseek)(f.res, d.d_off, VKI_SEEK_SET);
diff --git a/drd/drd_main.c b/drd/drd_main.c
index 4792ffd..4ef3bb5 100644
--- a/drd/drd_main.c
+++ b/drd/drd_main.c
@@ -83,27 +83,27 @@
   int trace_suppression      = -1;
   Char* trace_address        = 0;
 
-  VG_BOOL_CLO     (arg, "--check-stack-var",     check_stack_accesses)
-  else VG_BOOL_CLO(arg, "--drd-stats",           DRD_(s_print_stats))
-  else VG_BOOL_CLO(arg,"--report-signal-unlocked",report_signal_unlocked)
-  else VG_BOOL_CLO(arg, "--segment-merging",     segment_merging)
-  else VG_BOOL_CLO(arg, "--show-confl-seg",      show_confl_seg)
-  else VG_BOOL_CLO(arg, "--show-stack-usage",    DRD_(s_show_stack_usage))
-  else VG_BOOL_CLO(arg, "--trace-barrier",       trace_barrier)
-  else VG_BOOL_CLO(arg, "--trace-clientobj",     trace_clientobj)
-  else VG_BOOL_CLO(arg, "--trace-cond",          trace_cond)
-  else VG_BOOL_CLO(arg, "--trace-conflict-set",  trace_conflict_set)
-  else VG_BOOL_CLO(arg, "--trace-csw",           trace_csw)
-  else VG_BOOL_CLO(arg, "--trace-fork-join",     trace_fork_join)
-  else VG_BOOL_CLO(arg, "--trace-mutex",         trace_mutex)
-  else VG_BOOL_CLO(arg, "--trace-rwlock",        trace_rwlock)
-  else VG_BOOL_CLO(arg, "--trace-segment",       trace_segment)
-  else VG_BOOL_CLO(arg, "--trace-semaphore",     trace_semaphore)
-  else VG_BOOL_CLO(arg, "--trace-suppr",         trace_suppression)
-  else VG_BOOL_CLO(arg, "--var-info",            DRD_(s_var_info))
-  else VG_NUM_CLO (arg, "--exclusive-threshold", exclusive_threshold_ms)
-  else VG_NUM_CLO (arg, "--shared-threshold",    shared_threshold_ms)
-  else VG_STR_CLO (arg, "--trace-addr",          trace_address)
+  if     VG_BOOL_CLO(arg, "--check-stack-var",     check_stack_accesses) {}
+  else if VG_BOOL_CLO(arg, "--drd-stats",           DRD_(s_print_stats)) {}
+  else if VG_BOOL_CLO(arg,"--report-signal-unlocked",report_signal_unlocked) {}
+  else if VG_BOOL_CLO(arg, "--segment-merging",     segment_merging) {}
+  else if VG_BOOL_CLO(arg, "--show-confl-seg",      show_confl_seg) {}
+  else if VG_BOOL_CLO(arg, "--show-stack-usage",    DRD_(s_show_stack_usage)) {}
+  else if VG_BOOL_CLO(arg, "--trace-barrier",       trace_barrier) {}
+  else if VG_BOOL_CLO(arg, "--trace-clientobj",     trace_clientobj) {}
+  else if VG_BOOL_CLO(arg, "--trace-cond",          trace_cond) {}
+  else if VG_BOOL_CLO(arg, "--trace-conflict-set",  trace_conflict_set) {}
+  else if VG_BOOL_CLO(arg, "--trace-csw",           trace_csw) {}
+  else if VG_BOOL_CLO(arg, "--trace-fork-join",     trace_fork_join) {}
+  else if VG_BOOL_CLO(arg, "--trace-mutex",         trace_mutex) {}
+  else if VG_BOOL_CLO(arg, "--trace-rwlock",        trace_rwlock) {}
+  else if VG_BOOL_CLO(arg, "--trace-segment",       trace_segment) {}
+  else if VG_BOOL_CLO(arg, "--trace-semaphore",     trace_semaphore) {}
+  else if VG_BOOL_CLO(arg, "--trace-suppr",         trace_suppression) {}
+  else if VG_BOOL_CLO(arg, "--var-info",            DRD_(s_var_info)) {}
+  else if VG_INT_CLO (arg, "--exclusive-threshold", exclusive_threshold_ms) {}
+  else if VG_INT_CLO (arg, "--shared-threshold",    shared_threshold_ms)    {}
+  else if VG_STR_CLO (arg, "--trace-addr",          trace_address) {}
   else
     return VG_(replacement_malloc_process_cmd_line_option)(arg);
 
diff --git a/exp-ptrcheck/pc_common.c b/exp-ptrcheck/pc_common.c
index 8f9bef6..dc4b622 100644
--- a/exp-ptrcheck/pc_common.c
+++ b/exp-ptrcheck/pc_common.c
@@ -64,9 +64,9 @@
 
 Bool pc_process_cmd_line_options(Char* arg)
 {
-        VG_BOOL_CLO(arg, "--partial-loads-ok", h_clo_partial_loads_ok)
-   /* else VG_BOOL_CLO(arg, "--lossage-check",    h_clo_lossage_check) */
-   else VG_BOOL_CLO(arg, "--enable-sg-checks", sg_clo_enable_sg_checks)
+        if VG_BOOL_CLO(arg, "--partial-loads-ok", h_clo_partial_loads_ok) {}
+   /* else if VG_BOOL_CLO(arg, "--lossage-check",    h_clo_lossage_check) {} */
+   else if VG_BOOL_CLO(arg, "--enable-sg-checks", sg_clo_enable_sg_checks) {}
    else
       return VG_(replacement_malloc_process_cmd_line_option)(arg);
 
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index be0d408..d2915e4 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -4009,39 +4009,32 @@
 
 static Bool hg_process_cmd_line_option ( Char* arg )
 {
-   if      (VG_CLO_STREQ(arg, "--track-lockorders=no"))
-      HG_(clo_track_lockorders) = False;
-   else if (VG_CLO_STREQ(arg, "--track-lockorders=yes"))
-      HG_(clo_track_lockorders) = True;
+   Char* tmp_str;
 
-   else if (VG_CLO_STREQ(arg, "--cmp-race-err-addrs=no"))
-      HG_(clo_cmp_race_err_addrs) = False;
-   else if (VG_CLO_STREQ(arg, "--cmp-race-err-addrs=yes"))
-      HG_(clo_cmp_race_err_addrs) = True;
-
-   else if (VG_CLO_STREQ(arg, "--show-conflicts=no"))
-      HG_(clo_show_conflicts) = False;
-   else if (VG_CLO_STREQ(arg, "--show-conflicts=yes"))
-      HG_(clo_show_conflicts) = True;
+   if      VG_BOOL_CLO(arg, "--track-lockorders",
+                            HG_(clo_track_lockorders)) {}
+   else if VG_BOOL_CLO(arg, "--cmp-race-err-addrs",
+                            HG_(clo_cmp_race_err_addrs)) {}
+   else if VG_BOOL_CLO(arg, "--show-conflicts",
+                            HG_(clo_show_conflicts)) {}
 
    /* If you change the 10k/10mill limits, remember to also change
       them in assertions at the top of event_map_maybe_GC. */
-   else VG_BNUM_CLO(arg, "--conflict-cache-size",
-                         HG_(clo_conflict_cache_size), 10*1000, 10*1000*1000)
+   else if VG_BINT_CLO(arg, "--conflict-cache-size",
+                       HG_(clo_conflict_cache_size), 10*1000, 10*1000*1000) {}
 
    /* "stuvwx" --> stuvwx (binary) */
-   else if (VG_CLO_STREQN(18, arg, "--hg-sanity-flags=")) {
+   else if VG_STR_CLO(arg, "--hg-sanity-flags", tmp_str) {
       Int j;
-      Char* opt = & arg[18];
    
-      if (6 != VG_(strlen)(opt)) {
+      if (6 != VG_(strlen)(tmp_str)) {
          VG_(message)(Vg_UserMsg, 
                       "--hg-sanity-flags argument must have 6 digits");
          return False;
       }
       for (j = 0; j < 6; j++) {
-         if      ('0' == opt[j]) { /* do nothing */ }
-         else if ('1' == opt[j]) HG_(clo_sanity_flags) |= (1 << (6-1-j));
+         if      ('0' == tmp_str[j]) { /* do nothing */ }
+         else if ('1' == tmp_str[j]) HG_(clo_sanity_flags) |= (1 << (6-1-j));
          else {
             VG_(message)(Vg_UserMsg, "--hg-sanity-flags argument can "
                                      "only contain 0s and 1s");
diff --git a/include/pub_tool_libcbase.h b/include/pub_tool_libcbase.h
index bc224ac..96eae4c 100644
--- a/include/pub_tool_libcbase.h
+++ b/include/pub_tool_libcbase.h
@@ -51,32 +51,33 @@
 // is set to the start of the string.  None of them test that the number
 // fits into 64 bits.
 //
-// Nb: if you're wondering why we don't just have a single VG_(strtol) which
+// Nb: if you're wondering why we don't just have a single VG_(strtoll) which
 // takes a base, it's because I wanted it to assert if it was given a bogus
 // base (the standard glibc one sets 'errno' in this case).  But
 // m_libcbase.c doesn't import any code, not even vg_assert. --njn
+// 
+// Nb: we also don't provide VG_(atoll*);  these functions are worse than
+// useless because they don't do any error checking and so accept malformed
+// numbers and non-numbers -- eg. "123xyz" gives 123, and "foo" gives 0!
+// If you really want that behaviour, you can use "VG_(strtoll10)(str, NULL)".
 extern Long  VG_(strtoll10) ( Char* str, Char** endptr );
 extern Long  VG_(strtoll16) ( Char* str, Char** endptr );
 
-   // Convert a string to a double.  After leading whitespace is ignored, a
-   // '+' or '-' is allowed, and then it accepts a non-empty sequence of
-   // decimal digits possibly containing a '.'.  Hexadecimal floats are not
-   // accepted, nor are "fancy" floats (eg. "3.4e-5", "NAN").
+// Convert a string to a double.  After leading whitespace is ignored, a
+// '+' or '-' is allowed, and then it accepts a non-empty sequence of
+// decimal digits possibly containing a '.'.  Hexadecimal floats are not
+// accepted, nor are "fancy" floats (eg. "3.4e-5", "NAN").
 extern double VG_(strtod)  ( Char* str, Char** endptr );
 
-   // These are just like their VG_(strtoll*) counterparts, except that you
-   // cannot tell if an error occurred (because 0 is returned) or if there
-   // is any trailing non-numeric characterws (eg. in "123xyz").
-extern Long  VG_(atoll)   ( Char* str ); // base 10
-extern Long  VG_(atoll16) ( Char* str ); // base 16; leading 0x accepted
-
 /* ---------------------------------------------------------------------
    String functions and macros
    ------------------------------------------------------------------ */
 
-/* Use this for normal null-termination-style string comparison */
+/* Use this for normal null-termination-style string comparison. */
 #define VG_STREQ(s1,s2) ( (s1 != NULL && s2 != NULL \
                            && VG_(strcmp)((s1),(s2))==0) ? True : False )
+#define VG_STREQN(n,s1,s2) ( (s1 != NULL && s2 != NULL \
+                             && VG_(strncmp)((s1),(s2),(n))==0) ? True : False )
 
 extern SizeT VG_(strlen)         ( const Char* str );
 extern Char* VG_(strcat)         ( Char* dest, const Char* src );
diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h
index a45ce25..89e0ca6 100644
--- a/include/pub_tool_options.h
+++ b/include/pub_tool_options.h
@@ -34,71 +34,110 @@
 #include "libvex.h"              // for VexControl
 
 
-/* Use these for recognising tool command line options -- stops comparing
-   once whitespace is reached. */
-#define VG_CLO_STREQ(s1,s2)     (0==VG_(strcmp_ws)((s1),(s2)))
-#define VG_CLO_STREQN(nn,s1,s2) (0==VG_(strncmp_ws)((s1),(s2),(nn)))
+// Higher-level command-line option recognisers;  use in if/else chains. 
+// Note that they assign a value to the 'qq_var' argument.  So often they
+// can be used like this:
+//
+//   if VG_STR_CLO(arg, "--foo", clo_foo) { }
+//
+// But if you want to do further checking or processing, you can do this:
+//
+//   if VG_STR_CLO(arg, "--foo", clo_foo) { <further checking or processing> }
+//
+// They use GNU statement expressions to do the qq_var assignment within a
+// conditional expression.
 
-/* Higher-level command-line option recognisers;  use in if/else chains */
-
+// String argument, eg. --foo=yes or --foo=no
 #define VG_BOOL_CLO(qq_arg, qq_option, qq_var) \
-        if (VG_CLO_STREQ(qq_arg, qq_option"=yes")) { (qq_var) = True; } \
-   else if (VG_CLO_STREQ(qq_arg, qq_option"=no"))  { (qq_var) = False; }
+   (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \
+    ({ \
+      Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \
+      if      VG_STREQ(val, "yes") (qq_var) = True; \
+      else if VG_STREQ(val, "no")  (qq_var) = False; \
+      True; \
+    }) \
+   )
 
+// String argument, eg. --foo=bar
 #define VG_STR_CLO(qq_arg, qq_option, qq_var) \
-   if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
-      (qq_var) = &qq_arg[ VG_(strlen)(qq_option)+1 ]; \
-   }
+   (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \
+    ({ \
+      Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \
+      (qq_var) = val; \
+      True; \
+    }) \
+   )
 
-/* Unbounded integer arg */
-#define VG_NUM_CLO(qq_arg, qq_option, qq_var) \
-   if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
+// Unbounded integer arg, eg. --foo=10
+#define VG_INT_CLO(qq_arg, qq_option, qq_var) \
+   (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \
+    ({ \
+      Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \
       Char* s; \
-      Long n = VG_(strtoll10)( &qq_arg[ VG_(strlen)(qq_option)+1 ], &s );\
+      Long n = VG_(strtoll10)( val, &s ); \
       (qq_var) = n; \
-      /* Check for non-numeralness, or overflow */ \
+      /* Check for non-numeralness, or overflow. */ \
       if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \
-   }
+      True; \
+     }) \
+    )
 
-/* Bounded integer arg */
-#define VG_BNUM_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \
-   if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
+// Bounded integer arg, eg. --foo=10 ;  if the value exceeds the bounds it
+// causes an abort.  'qq_base' can be 10 or 16.
+#define VG_BINTN_CLO(qq_base, qq_arg, qq_option, qq_var, qq_lo, qq_hi) \
+   (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \
+    ({ \
+      Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \
       Char* s; \
-      Long n = VG_(strtoll10)( &qq_arg[ VG_(strlen)(qq_option)+1 ], &s );\
+      Long n = VG_(strtoll##qq_base)( val, &s ); \
       (qq_var) = n; \
-      /* Check for non-numeralness, or overflow */ \
+      /* Check for non-numeralness, or overflow. */ \
+      /* Nb: it will overflow if qq_var is unsigned and qq_val is negative! */ \
       if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \
-      if ((qq_var) < (qq_lo)) (qq_var) = (qq_lo); \
-      if ((qq_var) > (qq_hi)) (qq_var) = (qq_hi); \
-   }
+      /* Check bounds. */ \
+      if ((qq_var) < (qq_lo) || (qq_var) > (qq_hi)) { \
+         VG_(message)(Vg_UserMsg, \
+                      "'%s' argument must be between %lld and %lld", \
+                      (qq_option), (Long)(qq_lo), (Long)(qq_hi)); \
+         VG_(err_bad_option)(qq_arg); \
+      } \
+      True; \
+     }) \
+    )
 
-/* Bounded hexadecimal arg */
+// Bounded decimal integer arg, eg. --foo=100
+#define VG_BINT_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \
+   VG_BINTN_CLO(10, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi))
+
+// Bounded hexadecimal integer arg, eg. --foo=0x1fa8
 #define VG_BHEX_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \
-   if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
-      Char* s; \
-      Long n = VG_(strtoll16)( &qq_arg[ VG_(strlen)(qq_option)+1 ], &s );\
-      (qq_var) = n; \
-      /* Check for non-numeralness, or overflow */ \
-      if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \
-      if ((qq_var) < (qq_lo)) (qq_var) = (qq_lo); \
-      if ((qq_var) > (qq_hi)) (qq_var) = (qq_hi); \
-   }
+   VG_BINTN_CLO(16, (qq_arg), qq_option, (qq_var), (qq_lo), (qq_hi))
 
-/* Double arg */
+// Double (decimal) arg, eg. --foo=4.6
+// XXX: there's not VG_BDBL_CLO because we don't have a good way of printing
+// floats at the moment!
 #define VG_DBL_CLO(qq_arg, qq_option, qq_var) \
-   if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
+   (VG_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=") && \
+    ({ \
+      Char* val = &(qq_arg)[ VG_(strlen)(qq_option)+1 ]; \
       Char* s; \
-      double n = VG_(strtod)( &qq_arg[ VG_(strlen)(qq_option)+1 ], &s );\
+      double n = VG_(strtod)( val, &s ); \
       (qq_var) = n; \
       /* Check for non-numeralness */ \
       if ('\0' != s[0]) VG_(err_bad_option)(qq_arg); \
-   }
+      True; \
+     }) \
+    )
 
-/* Bool arg whose value is denoted by the exact presence of the given string. */
-#define VG_XACT_CLO(qq_arg, qq_option, qq_var) \
-   if (VG_CLO_STREQ(qq_arg, qq_option)) { \
-      (qq_var) = True; \
-   } /* else leave it alone */
+// Arg whose value is denoted by the exact presence of the given string;
+// if it matches, qq_var is assigned the value in qq_val.
+#define VG_XACT_CLO(qq_arg, qq_option, qq_var, qq_val) \
+   (VG_STREQ((qq_arg), (qq_option)) && \
+    ({ \
+      (qq_var) = (qq_val); \
+      True; \
+    }) \
+   )
 
 /* Verbosity level: 0 = silent, 1 (default), > 1 = more verbose. */
 extern Int  VG_(clo_verbosity);
@@ -125,9 +164,10 @@
 
 /* Call this if a recognised option was bad for some reason.  Note:
    don't use it just because an option was unrecognised -- return
-   'False' from VG_(tdict).tool_process_cmd_line_option) to indicate
-   that.  This function prints an error message, then shuts down the
-   entire system. */
+   'False' from VG_(tdict).tool_process_cmd_line_option) to indicate that --
+   use it if eg. an option was given an inappropriate argument.
+   This function prints an error message, then shuts down the entire system.
+   It returns a Bool so it can be used in the _CLO_ macros. */
 __attribute__((noreturn))
 extern void VG_(err_bad_option) ( Char* opt );
 
diff --git a/lackey/lk_main.c b/lackey/lk_main.c
index 737e92c..dd502c5 100644
--- a/lackey/lk_main.c
+++ b/lackey/lk_main.c
@@ -196,11 +196,11 @@
 
 static Bool lk_process_cmd_line_option(Char* arg)
 {
-   VG_STR_CLO(arg, "--fnname", clo_fnname)
-   else VG_BOOL_CLO(arg, "--basic-counts",      clo_basic_counts)
-   else VG_BOOL_CLO(arg, "--detailed-counts",   clo_detailed_counts)
-   else VG_BOOL_CLO(arg, "--trace-mem",         clo_trace_mem)
-   else VG_BOOL_CLO(arg, "--trace-superblocks", clo_trace_sbs)
+   if VG_STR_CLO(arg, "--fnname", clo_fnname) {}
+   else if VG_BOOL_CLO(arg, "--basic-counts",      clo_basic_counts) {}
+   else if VG_BOOL_CLO(arg, "--detailed-counts",   clo_detailed_counts) {}
+   else if VG_BOOL_CLO(arg, "--trace-mem",         clo_trace_mem) {}
+   else if VG_BOOL_CLO(arg, "--trace-superblocks", clo_trace_sbs) {}
    else
       return False;
    
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 32b6eec..2d8c26a 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -358,46 +358,45 @@
    // word-sized type -- it ended up with a value of 4.2 billion.  Sigh.
 static SSizeT clo_heap_admin      = 8;
 static Bool   clo_stacks          = False;
-static UInt   clo_depth           = 30;
+static Int    clo_depth           = 30;
 static double clo_threshold       = 1.0;  // percentage
 static double clo_peak_inaccuracy = 1.0;  // percentage
-static UInt   clo_time_unit       = TimeI;
-static UInt   clo_detailed_freq   = 10;
-static UInt   clo_max_snapshots   = 100;
+static Int    clo_time_unit       = TimeI;
+static Int    clo_detailed_freq   = 10;
+static Int    clo_max_snapshots   = 100;
 static Char*  clo_massif_out_file = "massif.out.%p";
 
 static XArray* args_for_massif;
 
 static Bool ms_process_cmd_line_option(Char* arg)
 {
+   Char* tmp_str;
+
    // Remember the arg for later use.
    VG_(addToXA)(args_for_massif, &arg);
 
-        VG_BOOL_CLO(arg, "--heap",   clo_heap)
-   else VG_BOOL_CLO(arg, "--stacks", clo_stacks)
+        if VG_BOOL_CLO(arg, "--heap",   clo_heap)   {}
+   else if VG_BOOL_CLO(arg, "--stacks", clo_stacks) {}
 
-   else VG_NUM_CLO(arg, "--heap-admin", clo_heap_admin)
-   else VG_NUM_CLO(arg, "--depth",      clo_depth)
+   else if VG_BINT_CLO(arg, "--heap-admin", clo_heap_admin, 0, 1024) {}
+   else if VG_BINT_CLO(arg, "--depth",      clo_depth, 1, MAX_DEPTH) {}
 
-   else VG_DBL_CLO(arg, "--threshold",  clo_threshold)
+   else if VG_DBL_CLO(arg, "--threshold",  clo_threshold) {}
 
-   else VG_DBL_CLO(arg, "--peak-inaccuracy", clo_peak_inaccuracy)
+   else if VG_DBL_CLO(arg, "--peak-inaccuracy", clo_peak_inaccuracy) {}
 
-   else VG_NUM_CLO(arg, "--detailed-freq", clo_detailed_freq)
-   else VG_NUM_CLO(arg, "--max-snapshots", clo_max_snapshots)
+   else if VG_BINT_CLO(arg, "--detailed-freq", clo_detailed_freq, 1, 10000) {}
+   else if VG_BINT_CLO(arg, "--max-snapshots", clo_max_snapshots, 10, 1000) {}
 
-   else if (VG_CLO_STREQ(arg, "--time-unit=i"))  clo_time_unit = TimeI;
-   else if (VG_CLO_STREQ(arg, "--time-unit=ms")) clo_time_unit = TimeMS;
-   else if (VG_CLO_STREQ(arg, "--time-unit=B"))  clo_time_unit = TimeB;
+   else if VG_XACT_CLO(arg, "--time-unit=i",  clo_time_unit, TimeI)  {}
+   else if VG_XACT_CLO(arg, "--time-unit=ms", clo_time_unit, TimeMS) {}
+   else if VG_XACT_CLO(arg, "--time-unit=B",  clo_time_unit, TimeB)  {}
 
-   else if (VG_CLO_STREQN(11, arg, "--alloc-fn=")) {
-      Char* alloc_fn = &arg[11];
-      VG_(addToXA)(alloc_fns, &alloc_fn);
+   else if VG_STR_CLO(arg, "--alloc-fn", tmp_str) {
+      VG_(addToXA)(alloc_fns, &tmp_str);
    }
 
-   else if (VG_CLO_STREQN(18, arg, "--massif-out-file=")) {
-      clo_massif_out_file = &arg[18];
-   }
+   else if VG_STR_CLO(arg, "--massif-out-file", clo_massif_out_file) {}
 
    else
       return VG_(replacement_malloc_process_cmd_line_option)(arg);
@@ -2164,26 +2163,10 @@
    Int i;
 
    // Check options.
-   if (clo_heap_admin < 0 || clo_heap_admin > 1024) {
-      VG_(message)(Vg_UserMsg, "--heap-admin must be between 0 and 1024");
-      VG_(err_bad_option)("--heap-admin");
-   }
-   if (clo_depth < 1 || clo_depth > MAX_DEPTH) {
-      VG_(message)(Vg_UserMsg, "--depth must be between 1 and %d", MAX_DEPTH);
-      VG_(err_bad_option)("--depth");
-   }
    if (clo_threshold < 0 || clo_threshold > 100) {
       VG_(message)(Vg_UserMsg, "--threshold must be between 0.0 and 100.0");
       VG_(err_bad_option)("--threshold");
    }
-   if (clo_detailed_freq < 1 || clo_detailed_freq > 10000) {
-      VG_(message)(Vg_UserMsg, "--detailed-freq must be between 1 and 10000");
-      VG_(err_bad_option)("--detailed-freq");
-   }
-   if (clo_max_snapshots < 10 || clo_max_snapshots > 1000) {
-      VG_(message)(Vg_UserMsg, "--max-snapshots must be between 10 and 1000");
-      VG_(err_bad_option)("--max-snapshots");
-   }
 
    // If we have --heap=no, set --heap-admin to zero, just to make sure we
    // don't accidentally use a non-zero heap-admin size somewhere.
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index b363835..4c474d4 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -4672,6 +4672,10 @@
 
 static Bool mc_process_cmd_line_options(Char* arg)
 {
+   Char* tmp_str;
+   Char* bad_level_msg =
+      "ERROR: --track-origins=yes has no effect when --undef-value-errors=no";
+
    tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
 
    /* Set MC_(clo_mc_level):
@@ -4684,10 +4688,13 @@
       --track-origins=yes as meaningless.
    */
    if (0 == VG_(strcmp)(arg, "--undef-value-errors=no")) {
-      if (MC_(clo_mc_level) == 3)
-         goto mc_level_error;
-      MC_(clo_mc_level) = 1;
-      return True;
+      if (MC_(clo_mc_level) == 3) {
+         VG_(message)(Vg_DebugMsg, "%s", bad_level_msg);
+         return False;
+      } else {
+         MC_(clo_mc_level) = 1;
+         return True;
+      }
    }
    if (0 == VG_(strcmp)(arg, "--undef-value-errors=yes")) {
       if (MC_(clo_mc_level) == 1)
@@ -4700,38 +4707,42 @@
       return True;
    }
    if (0 == VG_(strcmp)(arg, "--track-origins=yes")) {
-      if (MC_(clo_mc_level) == 1)
-         goto mc_level_error;
-      MC_(clo_mc_level) = 3;
-      return True;
+      if (MC_(clo_mc_level) == 1) {
+         VG_(message)(Vg_DebugMsg, "%s", bad_level_msg);
+         return False;
+      } else {
+         MC_(clo_mc_level) = 3;
+         return True;
+      }
    }
 
-	VG_BOOL_CLO(arg, "--partial-loads-ok",      MC_(clo_partial_loads_ok))
-   else VG_BOOL_CLO(arg, "--show-reachable",        MC_(clo_show_reachable))
-   else VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",MC_(clo_workaround_gcc296_bugs))
+	if VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok)) {}
+   else if VG_BOOL_CLO(arg, "--show-reachable",   MC_(clo_show_reachable))   {}
+   else if VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",
+                                            MC_(clo_workaround_gcc296_bugs)) {}
 
-   else VG_BNUM_CLO(arg, "--freelist-vol",  MC_(clo_freelist_vol), 
-                                            0, 10*1000*1000*1000LL)
+   else if VG_BINT_CLO(arg, "--freelist-vol",  MC_(clo_freelist_vol), 
+                                               0, 10*1000*1000*1000LL) {}
    
-   else if (VG_CLO_STREQ(arg, "--leak-check=no"))
-      MC_(clo_leak_check) = LC_Off;
-   else if (VG_CLO_STREQ(arg, "--leak-check=summary"))
-      MC_(clo_leak_check) = LC_Summary;
-   else if (VG_CLO_STREQ(arg, "--leak-check=yes") ||
-	    VG_CLO_STREQ(arg, "--leak-check=full"))
-      MC_(clo_leak_check) = LC_Full;
+   else if VG_XACT_CLO(arg, "--leak-check=no",
+                            MC_(clo_leak_check), LC_Off) {}
+   else if VG_XACT_CLO(arg, "--leak-check=summary",
+                            MC_(clo_leak_check), LC_Summary) {}
+   else if VG_XACT_CLO(arg, "--leak-check=yes",
+                            MC_(clo_leak_check), LC_Full) {}
+   else if VG_XACT_CLO(arg, "--leak-check=full",
+                            MC_(clo_leak_check), LC_Full) {}
 
-   else if (VG_CLO_STREQ(arg, "--leak-resolution=low"))
-      MC_(clo_leak_resolution) = Vg_LowRes;
-   else if (VG_CLO_STREQ(arg, "--leak-resolution=med"))
-      MC_(clo_leak_resolution) = Vg_MedRes;
-   else if (VG_CLO_STREQ(arg, "--leak-resolution=high"))
-      MC_(clo_leak_resolution) = Vg_HighRes;
+   else if VG_XACT_CLO(arg, "--leak-resolution=low",
+                            MC_(clo_leak_resolution), Vg_LowRes) {}
+   else if VG_XACT_CLO(arg, "--leak-resolution=med",
+                            MC_(clo_leak_resolution), Vg_MedRes) {}
+   else if VG_XACT_CLO(arg, "--leak-resolution=high",
+                            MC_(clo_leak_resolution), Vg_HighRes) {}
 
-   else if (VG_CLO_STREQN(16,arg,"--ignore-ranges=")) {
-      Int    i;
-      UChar* txt = (UChar*)(arg+16);
-      Bool   ok  = parse_ignore_ranges(txt);
+   else if VG_STR_CLO(arg, "--ignore-ranges", tmp_str) {
+      Int  i;
+      Bool ok  = parse_ignore_ranges(tmp_str);
       if (!ok)
         return False;
       tl_assert(ignoreRanges.used >= 0);
@@ -4757,19 +4768,13 @@
       }
    }
 
-   else VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00, 0xFF)
-   else VG_BHEX_CLO(arg, "--free-fill",   MC_(clo_free_fill), 0x00, 0xFF)
+   else if VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00,0xFF) {}
+   else if VG_BHEX_CLO(arg, "--free-fill",   MC_(clo_free_fill),   0x00,0xFF) {}
 
    else
       return VG_(replacement_malloc_process_cmd_line_option)(arg);
 
    return True;
-   /*NOTREACHED*/
-
-  mc_level_error:
-   VG_(message)(Vg_DebugMsg, "ERROR: --track-origins=yes has no effect "
-                             "when --undef-value-errors=no");
-   return False;
 }
 
 static void mc_print_usage(void)