changeset 7779:791231dac333

Add regexp matching to Fwho and Fclear
author David Bateman <dbateman@free.fr>
date Sun, 18 May 2008 22:14:45 +0200
parents 97b7ba81e1c3
children 08125419efcb
files liboctave/ChangeLog liboctave/Makefile.in liboctave/regex-match.cc liboctave/regex-match.h src/ChangeLog src/load-save.cc src/symtab.h src/variables.cc
diffstat 8 files changed, 515 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Mon May 19 17:35:39 2008 -0400
+++ b/liboctave/ChangeLog	Sun May 18 22:14:45 2008 +0200
@@ -1,3 +1,10 @@
+2008-05-20  David Bateman  <dbateman@free.fr>
+
+	* regex-match.cc, regex-match.h: New class for simple regular
+	expression matching
+	* Makefile.in (INCLUDES): Add regex-match.h here, and
+	(LIBOCTAVE_CXX_SOURCES): regex-match.cc here.
+
 2008-05-19  David Bateman  <dbateman@free.fr>
 
 	* dSparse.cc: Replace some DGBCON with GPBCON where they are
--- a/liboctave/Makefile.in	Mon May 19 17:35:39 2008 -0400
+++ b/liboctave/Makefile.in	Sun May 18 22:14:45 2008 +0200
@@ -85,7 +85,7 @@
 	oct-rl-hist.h oct-shlib.h oct-sort.h oct-spparms.h oct-syscalls.h \
 	oct-sparse.h oct-time.h oct-uname.h \
 	pathlen.h pathsearch.h prog-args.h \
-	randgamma.h randmtzig.h randpoisson.h \
+	randgamma.h randmtzig.h randpoisson.h regex-match.h \
 	so-array.h sparse-sort.h statdefs.h str-vec.h \
 	sparse-util.h sun-utils.h sysdir.h systime.h syswait.h \
 	$(MATRIX_INC)
@@ -136,7 +136,8 @@
 	lo-utils.cc mach-info.cc oct-alloc.cc oct-env.cc \
 	oct-fftw.cc oct-group.cc oct-md5.cc oct-passwd.cc oct-rand.cc \
 	oct-shlib.cc oct-spparms.cc oct-syscalls.cc oct-time.cc oct-uname.cc \
-	prog-args.cc so-array.cc sparse-sort.cc sparse-util.cc str-vec.cc \
+	prog-args.cc regex-match.cc \
+	so-array.cc sparse-sort.cc sparse-util.cc str-vec.cc \
 	$(TEMPLATE_SRC) \
 	$(TI_SRC) \
 	$(MATRIX_SRC)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/regex-match.cc	Sun May 18 22:14:45 2008 +0200
@@ -0,0 +1,153 @@
+/*
+
+Copyright (C) 2008 David Bateman
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <vector>
+#include <iostream>
+#include <string>
+
+#include "regex-match.h"
+#include "str-vec.h"
+
+regex_match& 
+regex_match::operator = (const regex_match& gm)
+{
+  if (this != &gm)
+    {
+#if HAVE_REGEX
+      for (int i = 0; i < pat.length (); i++)
+	regfree (compiled +i);
+      delete [] compiled;
+#endif
+      pat = gm.pat;
+      case_insen = gm.case_insen;
+      init ();
+    }
+  return *this;
+}
+
+regex_match::~regex_match (void)
+{
+#if HAVE_REGEX
+  for (int i = 0; i < pat.length (); i++)
+    regfree (compiled +i);
+  delete [] compiled;
+#endif
+}
+
+
+void 
+regex_match::set_pattern (const std::string& p) 
+{ 
+#if HAVE_REGEX
+  for (int i = 0; i < pat.length (); i++)
+    regfree (compiled +i);
+  delete [] compiled;
+#endif
+  pat = p; 
+  init ();
+}
+
+void 
+regex_match::set_pattern (const string_vector& p) 
+{ 
+#if HAVE_REGEX
+  for (int i = 0; i < pat.length (); i++)
+    regfree (compiled +i);
+  delete [] compiled;
+#endif
+  pat = p; 
+  init ();
+}
+
+void
+regex_match::init (void)
+{
+#ifdef HAVE_REGEX
+  int npat = pat.length ();
+  int err;
+  int i;
+
+  compiled = new regex_t [npat];
+
+  for (i = 0; i < npat; i++)
+    if (err = regcomp (compiled + i, pat(i).c_str (), 
+		       (REG_NOSUB | REG_EXTENDED |
+			(case_insen ? REG_ICASE : 0))))
+      break;
+  
+  if (err)
+    {
+      int len = regerror(err, compiled + i, 0, 0);
+      OCTAVE_LOCAL_BUFFER (char, errmsg, len);
+      regerror(err, compiled + i, errmsg, len);
+      (*current_liboctave_error_handler) ("%s in pattern (%s)", errmsg, 
+					  pat(i).c_str());
+
+      for (int j = 0; j < i + 1; j++)
+	regfree(compiled + j);
+    }
+#else
+  (*current_liboctave_error_handler) 
+    ("regex not available in this version of Octave"); 
+#endif
+}
+
+bool
+regex_match::match (const std::string& s)
+{
+#if HAVE_REGEX
+  int npat = pat.length ();
+
+  const char *str = s.c_str ();
+
+  for (int i = 0; i < npat; i++)
+    if (regexec(compiled + i, str, 0, 0, 0) == 0) 
+      return true;
+#endif
+
+  return false;
+}
+
+Array<bool>
+regex_match::match (const string_vector& s)
+{
+  int n = s.length ();
+
+  Array<bool> retval (n);
+
+  for (int i = 0; i < n; i++)
+    retval(i) = match (s[i]);
+
+  return retval;
+}
+
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/liboctave/regex-match.h	Sun May 18 22:14:45 2008 +0200
@@ -0,0 +1,90 @@
+/*
+
+Copyright (C) 2008  David Bateman
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined (octave_regex_match_h)
+#define octave_regex_match_h 1
+
+#include <string>
+
+#if defined (HAVE_REGEX)
+#if defined (__MINGW32__)
+#define __restrict
+#endif
+#if defined (HAVE_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+#include <regex.h>
+#endif
+
+#include "Array.h"
+#include "str-vec.h"
+
+class
+OCTAVE_API
+regex_match
+{
+public:
+
+  regex_match (const std::string& p, bool insen = false) 
+    : pat (p), case_insen (insen){ init (); }
+
+  regex_match (const string_vector& p = string_vector (), bool insen = false) 
+    : pat (p), case_insen (insen)  { init (); }
+
+  regex_match (const regex_match& gm) 
+    : pat (gm.pat), case_insen (gm.case_insen) { init (); }
+
+  regex_match& operator = (const regex_match& gm);
+
+  ~regex_match (void);
+
+  void set_pattern (const std::string& p);
+
+  void set_pattern (const string_vector& p);
+
+  bool match (const std::string&);
+
+  Array<bool> match (const string_vector&);
+
+private:
+
+  void init (void);
+
+  // Regex pattern(s).
+  string_vector pat;
+
+  // Should match be case insensitive
+  bool case_insen;
+
+#if HAVE_REGEX
+  regex_t *compiled;
+#endif
+
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/src/ChangeLog	Mon May 19 17:35:39 2008 -0400
+++ b/src/ChangeLog	Sun May 18 22:14:45 2008 +0200
@@ -1,3 +1,28 @@
+2008-05-20  David Bateman  <dbateman@free.fr>
+
+	* load-save.cc (do_load): Treat non verbose list_only output in
+	the same manner as Fwho.
+	* symtab.h (static void clear_variable_regexp (const
+	std::string&): New method.
+	(static std::list<symbol_record> regexp (const std::string&)): Ditto.
+	(static std::list<symbol_record> regexp_variables (const
+	std::string&)): Ditto.
+	(static std::list<symbol_record> regexp_global_variables (const
+	std::string&)): Ditto,
+	(static std::list<symbol_record> regexp_variables (const
+	string_vector&)): Ditto.
+	(void do_clear_variable_regexp (const std::string&)): Ditto.
+	(std::list<symbol_record> do_regexp (const std::string&, bool)
+	const): Ditto.
+	(do_who): Accept the "-regexp" option. Use regexp versions of
+	symbol table functions.
+	(static inline bool name_match_any_pattern (const string_vector&,
+	int, int, bool): Add regexp argument, and use regexp matching if
+	true.
+	(do_clear_variables): Add regexp option and pass to
+	name_match_any_pattern.
+	(Fclear): Accept the -regexp option.
+
 2008-05-07  John W. Eaton  <jwe@octave.org>
 
 	* pt-arg-list.cc, pt-arg-list.h (tree_argument_list::dup):
--- a/src/load-save.cc	Mon May 19 17:35:39 2008 -0400
+++ b/src/load-save.cc	Sun May 18 22:14:45 2008 +0200
@@ -334,6 +334,7 @@
   Octave_map retstruct;
 
   std::ostringstream output_buf;
+  std::list<std::string> symbol_names;
 
   octave_idx_type count = 0;
 
@@ -411,9 +412,10 @@
 			    << std::setiosflags (std::ios::right)
 			    << std::setw (7) << tc.rows ()
 			    << std::setw (7) << tc.columns ()
-			    << "   ";
+			    << "   " << name << "\n";
 			}
-		      output_buf << name << "\n";
+		      else
+			symbol_names.push_back (name);
 		    }
 		  else
 		    {
@@ -449,12 +451,28 @@
 
   if (list_only && count)
     {
-      std::string msg = output_buf.str ();
+      if (verbose)
+	{
+	  std::string msg = output_buf.str ();
 
-      if (nargout > 0)
-	retval = msg;
+	  if (nargout > 0)
+	    retval = msg;
+	  else
+	    octave_stdout << msg;
+	}
       else
-	octave_stdout << msg;
+	{
+	  if (nargout  > 0)
+	    retval = Cell (string_vector (symbol_names));
+	  else
+	    {
+	      string_vector names (symbol_names);
+
+	      names.list_in_columns (octave_stdout);
+
+	      octave_stdout << "\n";
+	    }
+	}
     }
   else if (retstruct.nfields () != 0)
     retval = retstruct;
--- a/src/symtab.h	Mon May 19 17:35:39 2008 -0400
+++ b/src/symtab.h	Sun May 18 22:14:45 2008 +0200
@@ -31,6 +31,7 @@
 #include <string>
 
 #include "glob-match.h"
+#include "regex-match.h"
 
 class tree_argument_list;
 
@@ -1337,6 +1338,14 @@
       inst->do_clear_variable_pattern (pat);
   }
 
+  static void clear_variable_regexp (const std::string& pat)
+  {
+    symbol_table *inst = get_instance (xcurrent_scope);
+
+    if (inst)
+      inst->do_clear_variable_regexp (pat);
+  }
+
   static void clear_symbol_pattern (const std::string& pat)
   {
     // FIXME -- are we supposed to do both here?
@@ -1527,6 +1536,13 @@
     return inst ? inst->do_glob (pattern) : std::list<symbol_record> ();
   }
 
+  static std::list<symbol_record> regexp (const std::string& pattern)
+  {
+    symbol_table *inst = get_instance (xcurrent_scope);
+
+    return inst ? inst->do_regexp (pattern) : std::list<symbol_record> ();
+  }
+
   static std::list<symbol_record> glob_variables (const std::string& pattern)
   {
     symbol_table *inst = get_instance (xcurrent_scope);
@@ -1534,6 +1550,13 @@
     return inst ? inst->do_glob (pattern, true) : std::list<symbol_record> ();
   }
 
+  static std::list<symbol_record> regexp_variables (const std::string& pattern)
+  {
+    symbol_table *inst = get_instance (xcurrent_scope);
+
+    return inst ? inst->do_regexp (pattern, true) : std::list<symbol_record> ();
+  }
+
   static std::list<symbol_record>
   glob_global_variables (const std::string& pattern)
   {
@@ -1556,6 +1579,28 @@
     return retval;
   }
 
+  static std::list<symbol_record>
+  regexp_global_variables (const std::string& pattern)
+  {
+    std::list<symbol_record> retval;
+
+    regex_match pat (pattern);
+
+    for (global_table_const_iterator p = global_table.begin ();
+	 p != global_table.end (); p++)
+      {
+	// We generate a list of symbol_record objects so that
+	// the results from regexp_variables and regexp_global_variables
+	// may be handled the same way.
+
+	if (pat.match (p->first))
+	  retval.push_back (symbol_record (p->first, p->second,
+					   symbol_record::global));
+      }
+
+    return retval;
+  }
+
   static std::list<symbol_record> glob_variables (const string_vector& patterns)
   {
     std::list<symbol_record> retval;
@@ -1572,6 +1617,23 @@
     return retval;
   }
 
+  static std::list<symbol_record> regexp_variables 
+    (const string_vector& patterns)
+  {
+    std::list<symbol_record> retval;
+
+    size_t len = patterns.length ();
+
+    for (size_t i = 0; i < len; i++)
+      {
+	std::list<symbol_record> tmp = regexp_variables (patterns[i]);
+
+	retval.insert (retval.begin (), tmp.begin (), tmp.end ());
+      }
+
+    return retval;
+  }
+
   static std::list<std::string> user_function_names (void)
   {
     std::list<std::string> retval;
@@ -2031,6 +2093,22 @@
       }
   }
 
+  void do_clear_variable_regexp (const std::string& pat)
+  {
+    regex_match pattern (pat);
+
+    for (table_iterator p = table.begin (); p != table.end (); p++)
+      {
+	symbol_record& sr = p->second;
+
+	if (sr.is_defined () || sr.is_global ())
+	  {
+	    if (pattern.match (sr.name ()))
+	      sr.clear ();
+	  }
+      }
+  }
+
   void do_mark_hidden (const std::string& name)
   {
     table_iterator p = table.find (name);
@@ -2088,6 +2166,29 @@
     return retval;
   }
 
+  std::list<symbol_record> do_regexp (const std::string& pattern,
+				      bool vars_only = false) const
+  {
+    std::list<symbol_record> retval;
+
+    regex_match pat (pattern);
+
+    for (table_const_iterator p = table.begin (); p != table.end (); p++)
+      {
+	if (pat.match (p->first))
+	  {
+	    const symbol_record& sr = p->second;
+
+	    if (vars_only && ! sr.is_variable ())
+	      continue;
+
+	    retval.push_back (sr);
+	  }
+      }
+
+    return retval;
+  }
+
   std::list<std::string> do_variable_names (void)
   {
     std::list<std::string> retval;
--- a/src/variables.cc	Mon May 19 17:35:39 2008 -0400
+++ b/src/variables.cc	Sun May 18 22:14:45 2008 +0200
@@ -36,6 +36,7 @@
 #include "oct-env.h"
 #include "file-ops.h"
 #include "glob-match.h"
+#include "regex-match.h"
 #include "str-vec.h"
 
 #include <defaults.h>
@@ -1637,17 +1638,15 @@
   std::string my_name = argv[0];
 
   bool global_only = false;
+  bool have_regexp = false;
 
   int i;
   for (i = 1; i < argc; i++)
     {
-      if (argv[i] == "-regexp" || argv[i] == "-file")
-	{
-	  error ("%s: `%s' option not implemented", my_name.c_str (),
-		 argv[i].c_str ());
-
-	  return retval;
-	}
+      if (argv[i] == "-file")
+	error ("%s: `-file' option not implemented", my_name.c_str ());
+      else if (argv[i] == "-regexp")
+	have_regexp = true;
       else if (argv[i] == "global")
 	global_only = true;
       else if (argv[i][0] == '-')
@@ -1678,46 +1677,11 @@
     {
       std::string pat = pats[j];
 
-      size_t pos = pat.find_first_of (".({");
-
-      if (pos != NPOS && pos > 0)
-        {
-	  if (verbose)
-	    {
-	      // NOTE: we can only display information for
-	      // expressions based on global values if the variable is
-	      // global in the current scope because we currently have
-	      // no way of looking up the base value in the global
-	      // scope and then evaluating the arguments in the
-	      // current scope.
-
-	      std::string base_name = pat.substr (0, pos);
-
-	      if (symbol_table::is_variable (base_name))
-		{
-		  symbol_table::symbol_record sr
-		    = symbol_table::find_symbol (base_name);
-
-		  if (! global_only || sr.is_global ())
-		    {
-		      int parse_status;
-
-		      octave_value expr_val
-			= eval_string (pat, true, parse_status);
-
-		      if (! error_state)
-			symbol_stats.append (sr, pat, expr_val);
-		      else
-			return retval;
-		    }
-		}
-	    }
-	}
-      else
+      if (have_regexp)
 	{
 	  std::list<symbol_table::symbol_record> tmp = global_only
-	    ? symbol_table::glob_global_variables (pats[j])
-	    : symbol_table::glob_variables (pats[j]);
+	    ? symbol_table::regexp_global_variables (pat)
+	    : symbol_table::regexp_variables (pat);
 
 	  for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin ();
 	       p != tmp.end (); p++)
@@ -1728,6 +1692,59 @@
 		symbol_names.push_back (p->name ());
 	    }
 	}
+      else
+	{
+	  size_t pos = pat.find_first_of (".({");
+
+	  if (pos != NPOS && pos > 0)
+	    {
+	      if (verbose)
+		{
+		  // NOTE: we can only display information for
+		  // expressions based on global values if the variable is
+		  // global in the current scope because we currently have
+		  // no way of looking up the base value in the global
+		  // scope and then evaluating the arguments in the
+		  // current scope.
+
+		  std::string base_name = pat.substr (0, pos);
+
+		  if (symbol_table::is_variable (base_name))
+		    {
+		      symbol_table::symbol_record sr
+			= symbol_table::find_symbol (base_name);
+
+		      if (! global_only || sr.is_global ())
+			{
+			  int parse_status;
+
+			  octave_value expr_val
+			    = eval_string (pat, true, parse_status);
+
+			  if (! error_state)
+			    symbol_stats.append (sr, pat, expr_val);
+			  else
+			    return retval;
+			}
+		    }
+		}
+	    }
+	  else
+	    {
+	      std::list<symbol_table::symbol_record> tmp = global_only
+		? symbol_table::glob_global_variables (pat)
+		: symbol_table::glob_variables (pat);
+
+	      for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin ();
+		   p != tmp.end (); p++)
+		{
+		  if (verbose)
+		    symbol_stats.append (*p);
+		  else
+		    symbol_names.push_back (p->name ());
+		}
+	    }
+	}
     }
 
   if (return_list)
@@ -1775,25 +1792,12 @@
 may not be combined.\n\
 \n\
 @table @code\n\
-@item -all\n\
-List all currently defined symbols.\n\
-\n\
-@item -builtins\n\
-List built-in functions.  This includes all currently\n\
-compiled function files, but does not include all function files that\n\
-are in the search path.\n\
-\n\
-@item -functions\n\
-List user-defined functions.\n\
-\n\
-@item -long\n\
-Print a long listing including the type and dimensions of any symbols.\n\
-The symbols in the first column of output indicate whether it is\n\
-possible to redefine the symbol, and whether it is possible for it to be\n\
-cleared.\n\
-\n\
-@item -variables\n\
-List user-defined variables.\n\
+@item global\n\
+List the variables in the global scope rather than the current scope.\n\
+@item -regexp\n\
+The patterns are considered as regular expressions and will be used\n\
+for matching the variables to display. The same pattern syntax as for\n\
+the @code{regexp} function is used.\n\
 @end table\n\
 \n\
 Valid patterns are the same as described for the @code{clear} command\n\
@@ -1802,6 +1806,7 @@
 visible in the local scope are displayed.\n\
 \n\
 The command @kbd{whos} is equivalent to @kbd{who -long}.\n\
+@seealso{regexp}\n\
 @end deffn")
 {
   octave_value retval;
@@ -2012,23 +2017,35 @@
 // Deleting names from the symbol tables.
 
 static inline bool
-name_matches_any_pattern (const std::string& nm,
-			  const string_vector& argv, int argc, int idx)
+name_matches_any_pattern (const std::string& nm, const string_vector& argv, 
+			  int argc, int idx, bool have_regexp = false)
 {
   bool retval = false;
 
   for (int k = idx; k < argc; k++)
     {
       std::string patstr = argv[k];
-
       if (! patstr.empty ())
 	{
-	  glob_match pattern (patstr);
-
-	  if (pattern.match (nm))
+	  if (have_regexp)
 	    {
-	      retval = true;
-	      break;
+	      regex_match pattern (patstr);
+
+	      if (pattern.match (nm))
+		{
+		  retval = true;
+		  break;
+		}
+	    }
+	  else
+	    {
+	      glob_match pattern (patstr);
+
+	      if (pattern.match (nm))
+		{
+		  retval = true;
+		  break;
+		}
 	    }
 	}
     }
@@ -2112,7 +2129,7 @@
 
 static void
 do_clear_variables (const string_vector& argv, int argc, int idx,
-		    bool exclusive = false)
+		    bool exclusive = false, bool have_regexp = false)
 {
   if (idx == argc)
     symbol_table::clear_variables ();
@@ -2128,14 +2145,18 @@
 	    {
 	      std::string nm = lvars[i];
 
-	      if (! name_matches_any_pattern (nm, argv, argc, idx))
+	      if (! name_matches_any_pattern (nm, argv, argc, idx, have_regexp))
 		symbol_table::clear_variable (nm);
 	    }
 	}
       else
 	{
-	  while (idx < argc)
-	    symbol_table::clear_variable_pattern (argv[idx++]);
+	  if (have_regexp)
+	    while (idx < argc)
+	      symbol_table::clear_variable_regexp (argv[idx++]);
+	  else
+	    while (idx < argc)
+	      symbol_table::clear_variable_pattern (argv[idx++]);
 	}
     }
 }
@@ -2266,6 +2287,9 @@
 Clears the global symbol names.\n\
 @item -variables, -v\n\
 Clears the local variable names.\n\
+@item -regexp, -r\n\
+The arguments are treated as regular expressions as any variables that\n\
+match will be cleared.\n\
 @end table\n\
 With the execption of @code{exclusive}, all long options can be used \n\
 without the dash as well.\n\
@@ -2292,6 +2316,7 @@
 	  bool clear_globals = false;
 	  bool clear_variables = false;
 	  bool exclusive = false;
+	  bool have_regexp = false;
 	  bool have_dash_option = false;
 
 	  while (++idx < argc)
@@ -2329,6 +2354,13 @@
 		  have_dash_option = true;
 		  clear_variables = true;
 		}
+	      else if (argv[idx] == "-regexp" || argv[idx] == "-r")
+		{
+		  CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
+
+		  have_dash_option = true;
+		  have_regexp = true;
+		}
 	      else
 		break;
 	    }
@@ -2351,6 +2383,10 @@
 
 		      symbol_table::clear_all ();
 		    }
+		  else if (have_regexp)
+		    {
+		      do_clear_variables (argv, argc, idx, exclusive, true);
+		    }
 		  else if (clear_functions)
 		    {
 		      do_clear_functions (argv, argc, idx, exclusive);