A couple of small changes for master:

0001: Makes the code in log.c easiert to read.
0002: Ignore emacs backup files.
0003: Clean up a header file.
0004: Remove the unused dependency from libs/vpacket.h to fvwm/fvwm.h.
0005: Your NEW-PARSEER.md patch without the reindentation.
0006: Remove the -D command line option.  I'm not sure if we should
      really delete this.  Should probably rather be a "bugopts" option.

parser branch on top of master:

0007-0009: Current cleaned up version of the parser parches

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt
From 3f61e78201a452a69c74ccde036e371391e0dfd3 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Sat, 20 Nov 2021 14:39:54 +0100
Subject: [PATCH 1/9] Clean up log.c.

---
 libs/log.c | 39 ++++++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/libs/log.c b/libs/log.c
index 23f28dcb..877a9f74 100644
--- a/libs/log.c
+++ b/libs/log.c
@@ -55,35 +55,36 @@ void
 log_open(const char *fvwm_userdir)
 {
 	char *path, *file_name;
+	char *expanded_path;

 	if (lib_log_level == 0)
 		return;
-	if (log_file_name != NULL &&
-	    log_file_name[0] == '-' && log_file_name[1] == 0) {
+	/* determine file name or file path to use */
+	file_name = log_file_name;
+	if (file_name == NULL)
+	{
+		file_name = getenv("FVWM3_LOGFILE");
+	}
+	if (file_name == NULL)
+	{
+		file_name = FVWM3_LOGFILE_DEFAULT;
+	}
+	/* handle stderr logging */
+	if (log_file_name[0] == '-' && log_file_name[1] == 0)
+	{
 		log_file = stderr;
 		return;
 	}
-	if ((file_name = log_file_name) == NULL)
-		file_name = getenv("FVWM3_LOGFILE");
-
-	if (file_name != NULL)
+	/* handle file logging */
+	expanded_path = expand_path(file_name);
+	if (expanded_path[0] == '/')
 	{
-		char	*expanded_path;
-
-		expanded_path = expand_path(file_name);
-		if (expanded_path[0] == '/')
-		{
-			path = expanded_path;
-		}
-		else
-		{
-			xasprintf(&path, "%s/%s", fvwm_userdir, expanded_path);
-			free((char *)expanded_path);
-		}
+		path = expanded_path;
 	}
 	else
 	{
-		xasprintf(&path, "%s/%s", fvwm_userdir, FVWM3_LOGFILE_DEFAULT);
+		xasprintf(&path, "%s/%s", fvwm_userdir, expanded_path);
+		free((char *)expanded_path);
 	}

 	log_close();
--
2.30.2

From 7ff0553f89bf5b767a5f67d8bcbdc1c63363a01d Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Sat, 20 Nov 2021 11:04:03 +0100
Subject: [PATCH 2/9] .gitignore: Ignore emacs backups.

---
 .gitignore | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.gitignore b/.gitignore
index 7ec13d8d..6c538bee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@
 *.o
 *.patch
 *~
+*#
+.#*
 Makefile
 Makefile.in
 aclocal.m4
--
2.30.2

From 2021ba60dc174b9508f87d4ee7ffb800792cd0ab Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Sat, 20 Nov 2021 12:12:13 +0100
Subject: [PATCH 3/9] Header cleanup.

---
 libs/vpacket.h | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/libs/vpacket.h b/libs/vpacket.h
index d0d88b2d..bd549fab 100644
--- a/libs/vpacket.h
+++ b/libs/vpacket.h
@@ -16,7 +16,6 @@
   This is the same packet as the M_ADD_WINDOW packet, the
   only difference being the type.
 */
-/*  RBW- typedef struct config_win_packet  */
 typedef struct ConfigWinPacket
 {
 	/*** Alignment notes ***/
@@ -33,14 +32,7 @@ typedef struct ConfigWinPacket
 	unsigned long  desk;
 	unsigned long  monitor_id;
 	unsigned long  monitor_name;
-	/*
-	  Temp word for alignment - old flags used to be here.
-	  - remove before next release.
-	  RBW - 05/01/2000 - layer has usurped this slot.
-	  unsigned long  dummy;
-	*/
 	unsigned long  layer;
-
 	unsigned long  hints_base_width;
 	unsigned long  hints_base_height;
 	unsigned long  hints_width_inc;
@@ -56,8 +48,6 @@ typedef struct ConfigWinPacket
 	unsigned long  hints_win_gravity;
 	unsigned long  TextPixel;
 	unsigned long  BackPixel;
-
-	/*  Everything below this is post-GSFR  */
 	unsigned long  ewmh_hint_layer;
 	unsigned long  ewmh_hint_desktop;
 	unsigned long  ewmh_window_type;
--
2.30.2

From 500e6f4b2c532d76581ba055d216a5d63cc93a03 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Sat, 20 Nov 2021 11:50:52 +0100
Subject: [PATCH 4/9] Remove libs/vpacket.h depending on fvwm.h.

---
 libs/vpacket.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libs/vpacket.h b/libs/vpacket.h
index bd549fab..98eb590c 100644
--- a/libs/vpacket.h
+++ b/libs/vpacket.h
@@ -3,7 +3,6 @@
 #ifndef FVWMLIB_VPACKET_H
 #define FVWMLIB_VPACKET_H
 #include "fvwm_x11.h"
-#include "fvwm/fvwm.h"

 /*
   All new-style module packets (i.e., those that are not simply arrays
@@ -70,7 +69,7 @@ typedef struct MiniIconPacket
 {
 	Window         w;
 	Window         frame;
-	FvwmWindow    *fvwmwin;
+	void          *fvwmwin;
 	unsigned long  width;
 	unsigned long  height;
 	unsigned long  depth;
--
2.30.2

From 01686e05071f7fbd460c73e4e70462136b50eb29 Mon Sep 17 00:00:00 2001
From: Thomas Adam <tho...@fvwm.org>
Date: Thu, 18 Nov 2021 22:47:15 +0000
Subject: [PATCH 5/9] doc: NEW-PARSER.md

---
 dev-docs/NEW-PARSER.md | 4 ++++
 1 file changed, 4 insertions(+)
 create mode 100644 dev-docs/NEW-PARSER.md

diff --git a/dev-docs/NEW-PARSER.md b/dev-docs/NEW-PARSER.md
new file mode 100644
index 00000000..c176b245
--- /dev/null
+++ b/dev-docs/NEW-PARSER.md
@@ -0,0 +1,4 @@
+New Parser
+==========
+
+
--
2.30.2

From 1f1c1e811174bba008286022e4e9758e747a70dd Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Sat, 20 Nov 2021 14:40:12 +0100
Subject: [PATCH 6/9] Remove -D option.

---
 doc/fvwm3_manpage_source.adoc |  5 -----
 fvwm/externs.h                |  1 -
 fvwm/fvwm3.c                  | 11 -----------
 3 files changed, 17 deletions(-)

diff --git a/doc/fvwm3_manpage_source.adoc b/doc/fvwm3_manpage_source.adoc
index d78b5d22..42187d14 100644
--- a/doc/fvwm3_manpage_source.adoc
+++ b/doc/fvwm3_manpage_source.adoc
@@ -71,11 +71,6 @@ fvwm -c "AddToFunc StartFunction I Module FvwmPager"
 Manage the display called _displayname_ instead of the name obtained
 from the environment variable _$DISPLAY_.

-*-D* | *--debug*::
-
-Puts X transactions in synchronous mode, which dramatically slows things
-down, but guarantees that fvwm's internal error messages are correct.
-
 *-f* _config-file_::

 Causes fvwm to read _config-file_ instead of _~/.fvwm/config_ as its
diff --git a/fvwm/externs.h b/fvwm/externs.h
index 1fcb1597..37719341 100644
--- a/fvwm/externs.h
+++ b/fvwm/externs.h
@@ -46,7 +46,6 @@ extern int x_fd;
 extern XContext FvwmContext;
 extern Bool fFvwmInStartup;
 extern Bool DoingCommandLine;
-extern Bool debugging;
 extern Bool debugging_stack_ring;
 extern int GrabPointerState;
 extern Window JunkRoot, JunkChild;
diff --git a/fvwm/fvwm3.c b/fvwm/fvwm3.c
index fb6e8c87..d4aa8838 100644
--- a/fvwm/fvwm3.c
+++ b/fvwm/fvwm3.c
@@ -149,7 +149,6 @@ Window JunkRoot, JunkChild;             /* junk window */
 int JunkWidth, JunkHeight, JunkBW, JunkDepth;
 unsigned int JunkMask;

-Bool debugging = False;
 Bool debugging_stack_ring = False;

 Window bad_window = None;
@@ -1812,12 +1811,6 @@ int main(int argc, char **argv)
 		{
 			debugging_stack_ring = True;
 		}
-		else if (strcmp(argv[i], "-D") == 0 ||
-			 strcmp(argv[i], "-debug") == 0 ||
-			 strcmp(argv[i], "--debug") == 0)
-		{
-			debugging = True;
-		}
 		else if (strcmp(argv[i], "-i") == 0 ||
 			 strcmp(argv[i], "-clientid") == 0 ||
 			 strcmp(argv[i], "--clientid") == 0 ||
@@ -2378,10 +2371,6 @@ int main(int argc, char **argv)

 	frame_init();
 	XFlush(dpy);
-	if (debugging)
-	{
-		sync_server(1);
-	}

 	SetupICCCM2(replace_wm);
 	XSetIOErrorHandler(CatchFatal);
--
2.30.2

From eb39cff44bfb04996d09055e3189d6e364c82c73 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Wed, 17 Nov 2021 20:03:57 +0100
Subject: [PATCH 7/9] Rewrite parser framework.

---
 fvwm/Makefile.am         |   4 +-
 fvwm/add_window.c        |   9 +-
 fvwm/builtins.c          |   4 +-
 fvwm/cmdparser.h         |  65 ++++
 fvwm/cmdparser_hooks.h   |  74 ++++
 fvwm/cmdparser_old.c     | 425 +++++++++++++++++++++
 fvwm/cmdparser_old.h     |  11 +
 fvwm/colorset.c          |   2 +-
 fvwm/conditional.c       |  21 +-
 fvwm/conditional.h       |  42 +++
 fvwm/events.c            |  40 +-
 fvwm/ewmh.c              |   7 +-
 fvwm/ewmh_events.c       |  33 +-
 fvwm/expand.c            |  48 ++-
 fvwm/expand.h            |   2 +-
 fvwm/functable.c         |  66 +++-
 fvwm/functable.h         |  25 +-
 fvwm/functable_complex.c | 157 ++++++++
 fvwm/functable_complex.h |  55 +++
 fvwm/functions.c         | 792 ++++++++++++++-------------------------
 fvwm/functions.h         |  41 +-
 fvwm/fvwm.h              |  49 +--
 fvwm/fvwm3.c             |  14 +-
 fvwm/menucmd.c           |   3 +-
 fvwm/menus.c             |   4 +-
 fvwm/misc.c              |   1 +
 fvwm/module_interface.c  |   3 +-
 fvwm/move_resize.c       |  29 +-
 fvwm/placement.c         |   5 +-
 fvwm/read.c              |  14 +-
 fvwm/read.h              |   4 +-
 fvwm/repeat.c            |   6 +-
 fvwm/schedule.c          |   3 +-
 fvwm/update.c            |   7 +-
 fvwm/virtual.c           |  24 +-
 fvwm/windowlist.c        |   3 +-
 36 files changed, 1380 insertions(+), 712 deletions(-)
 create mode 100644 fvwm/cmdparser.h
 create mode 100644 fvwm/cmdparser_hooks.h
 create mode 100644 fvwm/cmdparser_old.c
 create mode 100644 fvwm/cmdparser_old.h
 create mode 100644 fvwm/functable_complex.c
 create mode 100644 fvwm/functable_complex.h

diff --git a/fvwm/Makefile.am b/fvwm/Makefile.am
index a4bb6a0b..9ae456f9 100644
--- a/fvwm/Makefile.am
+++ b/fvwm/Makefile.am
@@ -19,6 +19,7 @@ fvwm3_SOURCES = \
 	placement.h read.h repeat.h execcontext.h schedule.h screen.h \
 	session.h stack.h style.h update.h virtual.h window_flags.h frame.h \
 	infostore.h \
+	cmdparser.h cmdparser_hooks.h cmdparser_old.h functable_complex.h \
 	\
 	menus.c style.c borders.c events.c move_resize.c builtins.c \
 	add_window.c icons.c fvwm3.c frame.c placement.c virtual.c \
@@ -28,7 +29,8 @@ fvwm3_SOURCES = \
 	menubindings.c decorations.c ewmh_icons.c update.c bindings.c misc.c \
 	cursor.c colormaps.c modconf.c  ewmh_conf.c read.c schedule.c \
 	menucmd.c ewmh_names.c icccm2.c windowshade.c focus_policy.c repeat.c \
-	execcontext.c menugeometry.c menudim.c condrc.c infostore.c
+	execcontext.c menugeometry.c menudim.c condrc.c infostore.c \
+	cmdparser_old.c functable_complex.c

 fvwm3_DEPENDENCIES = $(top_builddir)/libs/libfvwm3.a

diff --git a/fvwm/add_window.c b/fvwm/add_window.c
index dbd062e2..95a18600 100644
--- a/fvwm/add_window.c
+++ b/fvwm/add_window.c
@@ -2495,7 +2495,7 @@ FvwmWindow *AddWindow(
 		char *cmd;

 		xasprintf(&cmd, "GotoDesk %s 0 %d", tm->si->name, fw->Desk);
-		execute_function_override_window(NULL, NULL, cmd, 0, fw);
+		execute_function_override_window(NULL, NULL, cmd, NULL, 0, fw);
 		free(cmd);

 		/* read the requested absolute geometry */
@@ -2695,7 +2695,8 @@ FvwmWindow *AddWindow(
 			SET_STICKY_ACROSS_PAGES(fw, 0);
 			SET_STICKY_ACROSS_DESKS(fw, 0);
 			handle_stick(
-				NULL, exc2, "", stick_page, stick_desk, 1, 0);
+				NULL, exc2, "", NULL, stick_page, stick_desk,
+				1, 0);
 			exc_destroy_context(exc2);
 		}
 	}
@@ -2727,7 +2728,7 @@ FvwmWindow *AddWindow(
 		ecc.w.wcontext = C_WINDOW;
 		exc2 = exc_clone_context(
 			exc, &ecc, ECC_ETRIGGER | ECC_FW | ECC_WCONTEXT);
-		CMD_Resize(NULL, exc2, "");
+		CMD_Resize(NULL, exc2, "", NULL);
 		exc_destroy_context(exc2);
 	}

@@ -2796,7 +2797,7 @@ FvwmWindow *AddWindow(
 			     EWMH_STATE_HAS_HINT) ? 100 : 0;
 			sprintf(cmd,"Maximize on %i %i", h, v);
 			execute_function_override_window(
-				NULL, NULL, cmd, 0, fw);
+				NULL, NULL, cmd, NULL, 0, fw);
 		}
 	}
 	if (HAS_EWMH_INIT_FULLSCREEN_STATE(fw) == EWMH_STATE_HAS_HINT)
diff --git a/fvwm/builtins.c b/fvwm/builtins.c
index 4065051d..5c6e4eba 100644
--- a/fvwm/builtins.c
+++ b/fvwm/builtins.c
@@ -544,7 +544,7 @@ static void __remove_window_decors(F_CMD_ARGS, FvwmDecor *d)
 			exc2 = exc_clone_context(
 				exc, &ecc, ECC_FW | ECC_WCONTEXT);
 			execute_function(
-				cond_rc, exc2, "ChangeDecor Default", 0);
+				cond_rc, exc2, "ChangeDecor Default", pc, 0);
 			exc_destroy_context(exc2);
 		}
 	}
@@ -2166,7 +2166,7 @@ void AddToDecor(F_CMD_ARGS, FvwmDecor *decor)
 		return;
 	}
 	Scr.cur_decor = decor;
-	execute_function(cond_rc, exc, action, 0);
+	execute_function(F_PASS_ARGS, 0);
 	Scr.cur_decor = NULL;

 	return;
diff --git a/fvwm/cmdparser.h b/fvwm/cmdparser.h
new file mode 100644
index 00000000..53e1d2e6
--- /dev/null
+++ b/fvwm/cmdparser.h
@@ -0,0 +1,65 @@
+/* -*-c-*- */
+
+#ifndef FVWM_CMDPARSER_H
+#define FVWM_CMDPARSER_H
+
+/* ---------------------------- included header files ---------------------- */
+
+/* ---------------------------- global definitions ------------------------- */
+
+/* $0 through to $9 */
+#define CMDPARSER_NUM_POS_ARGS 10
+
+/* ---------------------------- global macros ------------------------------ */
+
+/* ---------------------------- type definitions --------------------------- */
+
+/* Enum for all the possible prefixes. */
+typedef enum
+{
+	CP_PREFIX_NONE = 0,
+	CP_PREFIX_MINUS = 0x1,
+	CP_PREFIX_SILENT = 0x2,
+	CP_PREFIX_KEEPRC = 0x4
+} cmdparser_prefix_flags_t;
+
+/* Enum for types of things to execute. */
+typedef enum
+{
+	CP_EXECTYPE_UNKNOWN = 0,
+	CP_EXECTYPE_BUILTIN_FUNCTION,
+	CP_EXECTYPE_COMPLEX_FUNCTION,
+	CP_EXECTYPE_COMPLEX_FUNCTION_DOES_NOT_EXIST,
+	CP_EXECTYPE_MODULECONFIG
+} cmdparser_execute_type_t;
+
+/* move this to the implementation file and use void* instead??? */
+
+typedef struct
+{
+	/* !!!note: need to define which bits in here may be accessed by the
+	 * user and which are internal */
+	unsigned char is_created : 1;
+	/* the original command line */
+	char *line;
+	/* the current command line */
+	char *cline;
+	/* the expanded command line */
+	char *expline;
+	unsigned char do_free_expline : 1;
+	/* the command name */
+	char *command;
+	/* name of the complex function if present */
+	char *complex_function_name;
+	/* current function nesting depth */
+	int call_depth;
+	/* A string with all positional arguments of a complex function.  May
+	 * be NULL if not in the context of a complex function. */
+	char *all_pos_args_string;
+	/* An array of the first CMDPARSER_NUM_POS_ARGS positional arguments up
+	 * to and excluding the first NULL pointer. Must (not) all be NULL if
+	 * all_pos_args_string is (not) NULL. */
+	char *pos_arg_tokens[CMDPARSER_NUM_POS_ARGS];
+} cmdparser_context_t;
+
+#endif /* FVWM_CMDPARSER_H */
diff --git a/fvwm/cmdparser_hooks.h b/fvwm/cmdparser_hooks.h
new file mode 100644
index 00000000..42330246
--- /dev/null
+++ b/fvwm/cmdparser_hooks.h
@@ -0,0 +1,74 @@
+/* -*-c-*- */
+
+#ifndef FVWM_CMDPARSER_HOOKS_H
+#define FVWM_CMDPARSER_HOOKS_H
+
+/* ---------------------------- included header files ---------------------- */
+
+/* ---------------------------- global definitions ------------------------- */
+
+/* ---------------------------- global macros ------------------------------ */
+
+/* ---------------------------- type definitions --------------------------- */
+
+typedef struct
+{
+	/* in general, functions in this structure that return int return
+	 *    0: success
+	 *  > 0: unsuccessful but not an error condition
+	 *  < 0: unsuccessful, error
+	 */
+	int (*create_context)(
+		/* context structure to initialise */
+		cmdparser_context_t *dest_context,
+		/* context structure of the caller or NULL */
+		cmdparser_context_t *caller_context,
+		/* input command line */
+		char *line,
+		/* A string with all positional arguments of a complex
+		 * function.  May be NULL if not in the context of a complex
+		 * function. */
+		char *all_pos_args_string,
+		/* An array of the first CMDPARSER_NUM_POS_ARGS positional
+		 * arguments up to and excluding the first NULL pointer. Must
+		 * (not) all be NULL if all_pos_args_string is (not) NULL. */
+		char *pos_arg_tokens[]
+		);
+	int (*handle_line_start)(cmdparser_context_t *context);
+	/* Returns a set of or'ed flags of which prefixes are present on the
+	 * command line.  The prefixes are stripped.  */
+	cmdparser_prefix_flags_t (*handle_line_prefix)(
+		cmdparser_context_t *context);
+	/* parses and returns the command name or returns a NULL pointer if not
+	 * possible */
+	const char *(*parse_command_name)(
+		cmdparser_context_t *context, void *func_rc, const void *exc);
+	/* returns 1 if the stored command is a module configuration command
+	 * and 0 otherwise */
+	int (*is_module_config)(cmdparser_context_t *context);
+	/* expands the command line */
+	void (*expand_command_line)(
+		cmdparser_context_t *context, int is_addto, void *func_rc,
+		const void *exc);
+	/* Release the expline field from the context structure and return it.
+	 * It is then the responsibility of the caller to free() it. */
+	void (*release_expanded_line)(cmdparser_context_t *context);
+	/* Tries to find a builtin function, a complex function or a module
+	 * config line to execute and returns the type found or
+	 * CP_EXECTYPE_UNKNOWN if none of the above were identified.  For a
+	 * builtin or a complex function, the pointer to the description is
+	 * returned in *ret_builtin or *ret_complex_function.  Consumes the
+	 * the "Module" or the "Function" command from the input.  Does not
+	 * consider builtin functions if *ret_builtin is != NULL when the
+	 * function is called.  */
+	cmdparser_execute_type_t (*find_something_to_execute)(
+		cmdparser_context_t *context,
+		const func_t **ret_builtin,
+		FvwmFunction **ret_complex_function);
+	/* Release the context initialised with create_context(). */
+	void (*destroy_context)(cmdparser_context_t *context);
+	/* Print the contents of the context. */
+	void (*debug)(cmdparser_context_t *context, const char *msg);
+} cmdparser_hooks_t;
+
+#endif /* FVWM_CMDPARSER_HOOKS_H */
diff --git a/fvwm/cmdparser_old.c b/fvwm/cmdparser_old.c
new file mode 100644
index 00000000..21c2074e
--- /dev/null
+++ b/fvwm/cmdparser_old.c
@@ -0,0 +1,425 @@
+/* -*-c-*- */
+/* This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* ---------------------------- included header files ---------------------- */
+
+#include "config.h"
+#include "libs/defaults.h"
+#include "libs/Parse.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "fvwm.h"
+#include "execcontext.h"
+#include "conditional.h"
+#include "functable.h"
+#include "commands.h"
+#include "functable_complex.h"
+#include "cmdparser.h"
+#include "cmdparser_hooks.h"
+#include "cmdparser_old.h"
+#include "misc.h"
+#include "expand.h"
+
+/* ---------------------------- local definitions -------------------------- */
+
+#if 0 /*!!!*/
+#define OCP_DEBUG 1
+#else
+#define OCP_DEBUG 0
+#endif
+
+/* ---------------------------- local macros ------------------------------- */
+
+/* ---------------------------- imports ------------------------------------ */
+
+/* ---------------------------- included code files ------------------------ */
+
+/* ---------------------------- local types -------------------------------- */
+
+/* ---------------------------- forward declarations ----------------------- */
+
+/* ---------------------------- local variables ---------------------------- */
+
+/* ---------------------------- exported variables (globals) --------------- */
+
+/* ---------------------------- local functions ---------------------------- */
+
+static void ocp_debug(cmdparser_context_t *c, const char *msg)
+{
+	int i;
+
+	if (!OCP_DEBUG)
+	{
+		return;
+	}
+	fprintf(stderr, "%s: %p: %s\n", __func__, c, (msg != NULL) ? msg : "");
+	if (!c->is_created)
+	{
+		fprintf(stderr, "  not created\n");
+		return;
+	}
+	fprintf(stderr, "  depth    : %d\n", c->call_depth);
+	fprintf(stderr, "  orig line: '%s'\n", c->line ? c->line : "(nil)");
+	fprintf(stderr, "  curr line: '%s'\n", c->cline ? c->cline : "(nil)");
+	fprintf(
+		stderr, "  exp  line: (do_free = %d) '%s'\n",
+		c->do_free_expline, c->expline ? c->expline : "(nil)");
+	fprintf(
+		stderr, "  command  : '%s'\n",
+		c->command ? c->command : "(nil)");
+	fprintf(
+		stderr, "  complexf : '%s'\n",
+		c->complex_function_name ? c->complex_function_name : "(nil)");
+	if (c->all_pos_args_string == NULL)
+	{
+		return;
+	}
+	fprintf(
+		stderr, "  all args : '%s'\n",
+		c->all_pos_args_string ? c->all_pos_args_string: "(nil)");
+	fprintf(stderr, "  pos args :");
+	for (
+		i = 0; i < CMDPARSER_NUM_POS_ARGS &&
+			c->pos_arg_tokens[i] != NULL; i++)
+	{
+		fprintf(stderr, " %d:'%s'", i,
+			c->pos_arg_tokens[i] ? c->pos_arg_tokens[i]: "(nil)");
+	}
+	fprintf(stderr, "\n");
+
+	return;
+}
+
+static int ocp_create_context(
+	cmdparser_context_t *dest_c, cmdparser_context_t *caller_c, char *line,
+	char *all_pos_args_string, char *pos_arg_tokens[])
+{
+	/* allocate the necessary resources */
+	memset(dest_c, 0, sizeof(*dest_c));
+	dest_c->line = line;
+	/*!!!should this be in handle_line_start instead???*/
+	if (caller_c != NULL)
+	{
+		if (caller_c->call_depth >= MAX_FUNCTION_DEPTH)
+		{
+			fvwm_debug(
+				__func__,
+				"called with a depth of %i, "
+				"stopping function execution!",
+				caller_c->call_depth);
+
+			return -1;
+		}
+		dest_c->call_depth = caller_c->call_depth + 1;
+	}
+	else
+	{
+		dest_c->call_depth = 1;
+	}
+	if (all_pos_args_string != NULL)
+	{
+		int i;
+
+		dest_c->all_pos_args_string = all_pos_args_string;
+		for (
+			i = 0; i < CMDPARSER_NUM_POS_ARGS &&
+				pos_arg_tokens[i] != NULL; i++)
+		{
+			dest_c->pos_arg_tokens[i] = pos_arg_tokens[i];
+		}
+	}
+	/*!!!allocate stuff*/
+	dest_c->is_created = 1;
+
+	return 0;
+}
+
+static void ocp_destroy_context(cmdparser_context_t *c)
+{
+	/* free the resources allocated in the create function */
+	if (!c->is_created)
+	{
+		return;
+	}
+	if (c->command != NULL)
+	{
+		free(c->command);
+	}
+	if (c->expline != NULL && c->do_free_expline)
+	{
+		free(c->expline);
+	}
+	c->is_created = 0;
+
+	return;
+}
+
+static int ocp_handle_line_start(cmdparser_context_t *c)
+{
+	/*!!! remove assertion later*/
+	assert(c->cline == NULL);
+	if (!c->line)
+	{
+		/* nothing to do */
+		return 1;
+	}
+	/* ignore whitespace at the beginning of all config lines */
+	c->cline = SkipSpaces(c->line, NULL, 0);
+	if (!c->cline || c->cline[0] == 0)
+	{
+		/* impossibly short command */
+		return -1;
+	}
+	if (c->cline[0] == '#')
+	{
+		/* a comment */
+		return 1;
+	}
+
+	return 0;
+}
+
+static cmdparser_prefix_flags_t ocp_handle_line_prefix(cmdparser_context_t *c)
+{
+	cmdparser_prefix_flags_t flags;
+	char *token;
+	char *restofline;
+
+	if (OCP_DEBUG)
+	{
+		fprintf(stderr, "%s: '%s'\n", __func__, c->cline);
+	}
+	flags = CP_PREFIX_NONE;
+	if (c->cline[0] == '-')
+	{
+		c->cline++;
+		flags |= CP_PREFIX_MINUS;
+		if (OCP_DEBUG)
+		{
+			fprintf(stderr, "minus -> '%s'\n", c->cline);
+		}
+	}
+	token = PeekToken(c->cline, &restofline);
+	if (OCP_DEBUG)
+	{
+		fprintf(
+			stderr, "cl '%s', tok '%s', rl '%s'\n", c->cline,
+			token, restofline);
+	}
+	while (token != NULL)
+	{
+		if (OCP_DEBUG)
+		{
+			fprintf(stderr, "loop: token '%s'\n", token);
+		}
+		if (StrEquals(token, PRE_SILENT))
+		{
+			flags |= CP_PREFIX_SILENT;
+			c->cline = restofline;
+			token = PeekToken(c->cline, &restofline);
+			if (OCP_DEBUG)
+			{
+				fprintf(
+					stderr,
+					"-> silent: cl '%s', tok '%s'\n",
+					c->cline, token);
+			}
+		}
+		else if (StrEquals(token, PRE_KEEPRC))
+		{
+			flags |= CP_PREFIX_KEEPRC;
+			c->cline = restofline;
+			token = PeekToken(c->cline, &restofline);
+			if (OCP_DEBUG)
+			{
+				fprintf(
+					stderr,
+					"-> keeprc: cl '%s', tok '%s'\n",
+					c->cline, token);
+			}
+		}
+		else
+		{
+			break;
+		}
+	}
+	if (OCP_DEBUG)
+	{
+		fprintf(stderr, "done: flags 0x%x\n", flags);
+	}
+
+	return flags;
+}
+
+static int ocp_is_module_config(cmdparser_context_t *c)
+{
+	return (c->command != NULL && *c->command == '*') ? 1 : 0;
+}
+
+static const char *ocp_parse_command_name(
+	cmdparser_context_t *c, void *func_rc, const void *exc)
+{
+	GetNextToken(c->cline, &c->command);
+	if (c->command != NULL)
+	{
+		char *tmp = c->command;
+
+		c->command = expand_vars(
+			c->command, c, False, False, func_rc, exc);
+		free(tmp);
+	}
+	if (c->command && !ocp_is_module_config(c))
+	{
+#if 1
+		/* DV: with this piece of code it is impossible to have a
+		 * complex function with embedded whitespace that begins with a
+		 * builtin function name, e.g. a function "echo hello". */
+		/* DV: ... and without it some of the complex functions will
+		 * fail */
+		char *tmp = c->command;
+
+		while (*tmp && !isspace(*tmp))
+		{
+			tmp++;
+		}
+		*tmp = 0;
+#endif
+		return c->command;
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
+static void ocp_expand_command_line(
+	cmdparser_context_t *c, int is_addto, void *func_rc, const void *exc)
+{
+	c->expline = expand_vars(
+		c->cline, c, is_addto, ocp_is_module_config(c), func_rc, exc);
+	c->cline = c->expline;
+	c->do_free_expline = 1;
+
+	return;
+}
+
+static void ocp_release_expanded_line(cmdparser_context_t *c)
+{
+	c->do_free_expline = 0;
+
+	return;
+}
+
+static cmdparser_execute_type_t ocp_find_something_to_execute(
+	cmdparser_context_t *c, const func_t **ret_builtin,
+	FvwmFunction **ret_complex_function)
+{
+	int is_function_builtin;
+
+	*ret_complex_function = NULL;
+	/* Note: the module config command, "*" can not be handled by the
+	 * regular command table because there is no required white space after
+	 * the asterisk. */
+	if (ocp_is_module_config(c))
+	{
+		/*!!!strip asterisk??? */
+		return CP_EXECTYPE_MODULECONFIG;
+	}
+	if (*ret_builtin == NULL)
+	{
+		/* in a new parser we would look for a builtin function here,
+		 * but in the old parser this has already been done */
+	}
+	is_function_builtin = 0;
+	if (*ret_builtin != NULL)
+	{
+		if ((*ret_builtin)->func_c == F_FUNCTION)
+		{
+			c->cline = SkipNTokens(c->cline, 1);
+			if (OCP_DEBUG)
+			{
+				fprintf(stderr, "func cline '%s'\n", c->cline);
+			}
+			free(c->command);
+			c->command = NULL;
+			is_function_builtin = 1;
+			*ret_builtin = NULL;
+		}
+		else
+		{
+			c->cline = SkipNTokens(c->cline, 1);
+			return CP_EXECTYPE_BUILTIN_FUNCTION;
+		}
+	}
+#if 1 /*!!!*/
+	assert(*ret_builtin == NULL);
+#endif
+	do
+	{
+		char *complex_function_name;
+		char *rest_of_line;
+
+		/* find_complex_function expects a token, not just a quoted
+		 * string */
+		complex_function_name = PeekToken(c->cline, &rest_of_line);
+		if (complex_function_name == NULL)
+		{
+			break;
+		}
+		*ret_complex_function =
+			find_complex_function(complex_function_name);
+		if (*ret_complex_function != NULL)
+		{
+			c->cline = rest_of_line;
+			c->complex_function_name = complex_function_name;
+			return CP_EXECTYPE_COMPLEX_FUNCTION;
+		}
+		if (is_function_builtin)
+		{
+			c->cline = rest_of_line;
+			c->complex_function_name = complex_function_name;
+			return CP_EXECTYPE_COMPLEX_FUNCTION_DOES_NOT_EXIST;
+		}
+	} while (0);
+
+	return CP_EXECTYPE_UNKNOWN;
+}
+
+/* ---------------------------- local variables ---------------------------- */
+
+static cmdparser_hooks_t old_parser_hooks =
+{
+	ocp_create_context,
+	ocp_handle_line_start,
+	ocp_handle_line_prefix,
+	ocp_parse_command_name,
+	ocp_is_module_config,
+	ocp_expand_command_line,
+	ocp_release_expanded_line,
+	ocp_find_something_to_execute,
+	ocp_destroy_context,
+	ocp_debug
+};
+
+/* ---------------------------- interface functions ------------------------ */
+
+/* return the hooks structure of the old parser */
+const cmdparser_hooks_t *cmdparser_old_get_hooks(void)
+{
+	return &old_parser_hooks;
+}
diff --git a/fvwm/cmdparser_old.h b/fvwm/cmdparser_old.h
new file mode 100644
index 00000000..d2b11b47
--- /dev/null
+++ b/fvwm/cmdparser_old.h
@@ -0,0 +1,11 @@
+/* -*-c-*- */
+
+#ifndef FVWM_CMDPARSER_OLD_H
+#define FVWM_CMDPARSER_OLD_H
+
+/* ---------------------------- interface functions ------------------------ */
+
+/* return the hooks structure of the old parser */
+const cmdparser_hooks_t *cmdparser_old_get_hooks(void);
+
+#endif /* FVWM_CMDPARSER_OLD_H */
diff --git a/fvwm/colorset.c b/fvwm/colorset.c
index 48f59c8c..5aa9bc8d 100644
--- a/fvwm/colorset.c
+++ b/fvwm/colorset.c
@@ -250,7 +250,7 @@ static void add_to_junk(Pixmap pixmap)
 		const exec_context_t *exc;

 		exc = exc_create_null_context();
-		CMD_Schedule(NULL, exc, "3000 CleanupColorsets");
+		CMD_Schedule(NULL, exc, "3000 CleanupColorsets", NULL);
 		exc_destroy_context(exc);
 		cleanup_scheduled = True;
 	}
diff --git a/fvwm/conditional.c b/fvwm/conditional.c
index e64cabf6..30bf14a3 100644
--- a/fvwm/conditional.c
+++ b/fvwm/conditional.c
@@ -28,6 +28,7 @@
 #include "libs/wcontext.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "execcontext.h"
 #include "functions.h"
 #include "conditional.h"
@@ -201,7 +202,7 @@ static void circulate_cmd(
 		ecc.w.wcontext = new_context;
 		exc2 = exc_clone_context(
 			exc, &ecc, ECC_FW | ECC_W | ECC_WCONTEXT);
-		execute_function(cond_rc, exc2, restofline, flags);
+		execute_function(cond_rc, exc2, restofline, pc, flags);
 		exc_destroy_context(exc2);
 	}

@@ -240,7 +241,7 @@ static void select_cmd(F_CMD_ARGS)
 			cond_rc->rc = COND_RC_OK;
 		}
 		execute_function_override_wcontext(
-			cond_rc, exc, restofline, 0, C_WINDOW);
+			cond_rc, exc, restofline, pc, 0, C_WINDOW);
 	}
 	else if (cond_rc != NULL)
 	{
@@ -1423,7 +1424,7 @@ static void direction_cmd(F_CMD_ARGS, Bool is_scan)
 			cond_rc->rc = COND_RC_OK;
 		}
 		execute_function_override_window(
-			cond_rc, exc, restofline, 0, fw_best);
+			cond_rc, exc, restofline, pc, 0, fw_best);
 	}
 	else if (cond_rc != NULL)
 	{
@@ -1664,7 +1665,7 @@ void CMD_All(F_CMD_ARGS)
 		for (i = num-1; i >= 0; i--)
 		{
 			execute_function_override_window(
-				cond_rc, exc, restofline, 0, g[i]);
+				cond_rc, exc, restofline, pc, 0, g[i]);
 		}
 	}
 	else
@@ -1672,7 +1673,7 @@ void CMD_All(F_CMD_ARGS)
 		for (i = 0; i < num; i++)
 		{
 			execute_function_override_window(
-				cond_rc, exc, restofline, 0, g[i]);
+				cond_rc, exc, restofline, pc, 0, g[i]);
 		}
 	}
 	if (cond_rc != NULL && cond_rc->rc != COND_RC_BREAK)
@@ -1792,7 +1793,7 @@ void CMD_WindowId(F_CMD_ARGS)
 					cond_rc->rc = COND_RC_OK;
 				}
 				execute_function_override_window(
-					cond_rc, exc, action, 0, t);
+					cond_rc, exc, action, pc, 0, t);
 			}
 			else if (cond_rc != NULL)
 			{
@@ -1836,7 +1837,7 @@ void CMD_WindowId(F_CMD_ARGS)
 					ECC_FW | ECC_W | ECC_WCONTEXT);
 				execute_function(
 					cond_rc, exc2, action,
-					FUNC_IS_UNMANAGED);
+pc, 					FUNC_IS_UNMANAGED);
 				exc_destroy_context(exc2);
 			}
 		}
@@ -1873,7 +1874,7 @@ void CMD_TestRc(F_CMD_ARGS)
 	{
 		/* execute the command in root window context; overwrite the
 		 * return code with the return code of the command */
-		execute_function(cond_rc, exc, rest, 0);
+		execute_function(cond_rc, exc, rest, pc, 0);
 	}

 	return;
@@ -1899,7 +1900,7 @@ void CMD_Break(F_CMD_ARGS)

 void CMD_NoWindow(F_CMD_ARGS)
 {
-	execute_function_override_window(cond_rc, exc, action, 0, NULL);
+	execute_function_override_window(cond_rc, exc, action, pc, 0, NULL);

 	return;
 }
@@ -2321,7 +2322,7 @@ void CMD_Test(F_CMD_ARGS)
 	}
 	if (!error && match)
 	{
-		execute_function(cond_rc, exc, restofline, 0);
+		execute_function(cond_rc, exc, restofline, pc, 0);
 	}
 	if (cond_rc != NULL)
 	{
diff --git a/fvwm/conditional.h b/fvwm/conditional.h
index c993ae8b..c58f2030 100644
--- a/fvwm/conditional.h
+++ b/fvwm/conditional.h
@@ -12,6 +12,48 @@

 /* ---------------------------- type definitions --------------------------- */

+/* Window mask for Circulate and Direction functions */
+typedef struct WindowConditionMask
+{
+	struct
+	{
+		unsigned do_accept_focus : 1;
+		unsigned do_check_desk : 1;
+		unsigned do_check_screen : 1;
+		unsigned do_check_cond_desk : 1;
+		unsigned do_check_desk_and_global_page : 1;
+		unsigned do_check_desk_and_page : 1;
+		unsigned do_check_global_page : 1;
+		unsigned do_check_overlapped : 1;
+		unsigned do_check_page : 1;
+		unsigned do_not_check_screen : 1;
+		unsigned needs_current_desk : 1;
+		unsigned needs_current_desk_and_global_page : 1;
+		unsigned needs_current_desk_and_page : 1;
+		unsigned needs_current_global_page : 1;
+		unsigned needs_current_page : 1;
+#define NEEDS_ANY   0
+#define NEEDS_TRUE  1
+#define NEEDS_FALSE 2
+		unsigned needs_focus : 2;
+		unsigned needs_overlapped : 2;
+		unsigned needs_pointer : 2;
+		unsigned needs_same_layer : 1;
+		unsigned use_circulate_hit : 1;
+		unsigned use_circulate_hit_icon : 1;
+		unsigned use_circulate_hit_shaded : 1;
+		unsigned use_do_accept_focus : 1;
+	} my_flags;
+	window_flags flags;
+	window_flags flag_mask;
+	struct name_condition *name_condition;
+	int layer;
+	int desk;
+	struct monitor *screen;
+	int placed_by_button_mask;
+	int placed_by_button_set_mask;
+} WindowConditionMask;
+
 /* ---------------------------- forward declarations ----------------------- */

 /* ---------------------------- exported variables (globals) --------------- */
diff --git a/fvwm/events.c b/fvwm/events.c
index 01102968..b490b404 100644
--- a/fvwm/events.c
+++ b/fvwm/events.c
@@ -70,6 +70,7 @@
 #include "libs/FEvent.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "cursor.h"
 #include "functions.h"
 #include "commands.h"
@@ -1622,7 +1623,7 @@ static Bool __handle_bpress_action(
 		/* release the pointer since it can't do harm over an icon */
 		XAllowEvents(dpy, AsyncPointer, CurrentTime);
 	}
-	execute_function(NULL, exc, action, 0);
+	execute_function(NULL, exc, action, NULL, 0);
 	if (exc->w.wcontext != C_WINDOW && exc->w.wcontext != C_NO_CONTEXT)
 	{
 		WaitForButtonsUp(True);
@@ -1660,7 +1661,7 @@ static void __handle_bpress_on_root(const exec_context_t *exc)

 		ecc.w.wcontext = C_ROOT;
 		exc2 = exc_clone_context(exc, &ecc, ECC_WCONTEXT);
-		execute_function(NULL, exc2, action, 0);
+		execute_function(NULL, exc2, action, NULL, 0);
 		exc_destroy_context(exc2);
 		WaitForButtonsUp(True);
 	}
@@ -1824,27 +1825,30 @@ monitor_emit_broadcast(void)

 	TAILQ_FOREACH (m, &monitor_q, entry) {
 		if (m->emit & MONITOR_CHANGED) {
-			BroadcastName(MX_MONITOR_CHANGED, -1, -1, -1, m->si->name);
+			BroadcastName(
+				MX_MONITOR_CHANGED, -1, -1, -1, m->si->name);
 			m->emit &= ~MONITOR_ALL;
 			m->flags &= ~MONITOR_CHANGED;

 			/* Run the RandRFunc in case a user has set it. */
-			execute_function_override_window(NULL, NULL, randrfunc,
-			    0, NULL);
+			execute_function_override_window(
+				NULL, NULL, randrfunc, NULL, 0, NULL);
 		}
 		if (m->emit & MONITOR_ENABLED) {
-			BroadcastName(MX_MONITOR_ENABLED, -1, -1, -1, m->si->name);
+			BroadcastName(
+				MX_MONITOR_ENABLED, -1, -1, -1, m->si->name);

 			/* Run the RandRFunc in case a user has set it. */
-			execute_function_override_window(NULL, NULL, randrfunc,
-			    0, NULL);
+			execute_function_override_window(
+				NULL, NULL, randrfunc, NULL, 0, NULL);
 		}
 		if (m->emit & MONITOR_DISABLED) {
-			BroadcastName(MX_MONITOR_DISABLED, -1, -1, -1, m->si->name);
+			BroadcastName(
+				MX_MONITOR_DISABLED, -1, -1, -1, m->si->name);

 			/* Run the RandRFunc in case a user has set it. */
-			execute_function_override_window(NULL, NULL, randrfunc,
-			    0, NULL);
+			execute_function_override_window(
+				NULL, NULL, randrfunc, NULL, 0, NULL);
 		}
 	}
 }
@@ -1895,7 +1899,7 @@ void HandleClientMessage(const evh_args_t *ea)

 		ecc.w.wcontext = C_WINDOW;
 		exc = exc_clone_context(ea->exc, &ecc, ECC_WCONTEXT);
-		execute_function(NULL, exc, "Iconify", 0);
+		execute_function(NULL, exc, "Iconify", NULL, 0);
 		exc_destroy_context(exc);
 		return;
 	}
@@ -2260,7 +2264,7 @@ void HandleEnterNotify(const evh_args_t *ea)
 		else if (edge_command)
 		{
 			fvwm_debug(__func__, "EC is: %s", edge_command);
-			execute_function(NULL, ea->exc, edge_command, 0);
+			execute_function(NULL, ea->exc, edge_command, NULL, 0);
 		}
 		else
 		{
@@ -2677,7 +2681,7 @@ void __handle_key(const evh_args_t *ea, Bool is_press)
 			exc = exc_clone_context(
 				ea->exc, &ecc, ECC_FW | ECC_WCONTEXT);
 		}
-		execute_function(NULL, exc, action, 0);
+		execute_function(NULL, exc, action, NULL, 0);
 		if (is_second_binding == False)
 		{
 			exc_destroy_context(exc);
@@ -2821,7 +2825,8 @@ void HandleLeaveNotify(const evh_args_t *ea)
 		}
 		else if (edge_command_leave)
 		{
-			execute_function(NULL, ea->exc, edge_command_leave, 0);
+			execute_function(
+				NULL, ea->exc, edge_command_leave, NULL, 0);
 		}
 	}

@@ -3192,7 +3197,8 @@ void HandleMapRequestKeepRaised(
 			{
 				execute_function_override_window(
 					NULL, ea->exc,
-					(char *)initial_map_command, 0, fw);
+					(char *)initial_map_command, NULL, 0,
+					fw);
 			}
 			MyXUngrabServer(dpy);

@@ -3635,7 +3641,7 @@ void HandlePropertyNotify(const evh_args_t *ea)
 			ecc.w.wcontext = C_WINDOW;
 			exc = exc_clone_context(
 				ea->exc, &ecc, ECC_FW | ECC_WCONTEXT);
-			execute_function(NULL, exc, urgency_action, 0);
+			execute_function(NULL, exc, urgency_action, NULL, 0);
 			exc_destroy_context(exc);
 		}
 		break;
diff --git a/fvwm/ewmh.c b/fvwm/ewmh.c
index e4e84800..3983ded4 100644
--- a/fvwm/ewmh.c
+++ b/fvwm/ewmh.c
@@ -58,6 +58,7 @@
 #include "libs/fvwm_x11.h"
 #include "libs/fvwmlib.h"
 #include "fvwm.h"
+#include "cmdparser.h"
 #include "execcontext.h"
 #include "functions.h"
 #include "commands.h"
@@ -2036,7 +2037,7 @@ void EWMH_fullscreen(FvwmWindow *fw)
 	{
 		fw->fullscreen.is_iconified = 1;
 		execute_function_override_window(
-			NULL, NULL, "Iconify off", 0, fw);
+			NULL, NULL, "Iconify off", NULL, 0, fw);
 	}
 	if (IS_SHADED(fw))
 	{
@@ -2045,7 +2046,7 @@ void EWMH_fullscreen(FvwmWindow *fw)
 		fw->fullscreen.is_shaded = 1;
 		fw->shade_anim_steps = 0;
 		execute_function_override_window(
-			NULL, NULL, "WindowShade off", 0, fw);
+			NULL, NULL, "WindowShade off", NULL, 0, fw);
 		fw->shade_anim_steps = sas;
 	}
 	SET_EWMH_FULLSCREEN(fw,True);
@@ -2079,7 +2080,7 @@ void EWMH_fullscreen(FvwmWindow *fw)
 	if (cmd[0] != 0)
 	{
 		SET_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw, 1);
-		execute_function_override_window(NULL, NULL, cmd, 0, fw);
+		execute_function_override_window(NULL, NULL, cmd, NULL, 0, fw);
 		SET_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw, 0);
 	}

diff --git a/fvwm/ewmh_events.c b/fvwm/ewmh_events.c
index 65b730c2..5989f40d 100644
--- a/fvwm/ewmh_events.c
+++ b/fvwm/ewmh_events.c
@@ -24,6 +24,7 @@
 #include "fvwm.h"
 #include "externs.h"
 #include "execcontext.h"
+#include "cmdparser.h"
 #include "functions.h"
 #include "misc.h"
 #include "screen.h"
@@ -92,7 +93,7 @@ int ewmh_DesktopGeometry(
 		return -1;
 	}
 	sprintf(action, "DesktopSize %ld %ld", width, height);
-	execute_function_override_window(NULL, NULL, action, 0, NULL);
+	execute_function_override_window(NULL, NULL, action, NULL, 0, NULL);

 	return -1;
 }
@@ -169,7 +170,7 @@ int ewmh_ActiveWindow(
 		return 0;
 	}
 	execute_function_override_window(
-		NULL, NULL, "EWMHActivateWindowFunc", 0, fw);
+		NULL, NULL, "EWMHActivateWindowFunc", NULL, 0, fw);

 	return 0;
 }
@@ -185,7 +186,7 @@ int ewmh_CloseWindow(
 	{
 		return 0;
 	}
-	execute_function_override_window(NULL, NULL, "Close", 0, fw);
+	execute_function_override_window(NULL, NULL, "Close", NULL, 0, fw);

 	return 0;
 }
@@ -290,7 +291,7 @@ int ewmh_WMDesktop(
 		if (d == (unsigned long)-2 || d == (unsigned long)-1)
 		{
 			execute_function_override_window(
-				NULL, NULL, "Stick on", 0, fw);
+				NULL, NULL, "Stick on", NULL, 0, fw);
 		}
 		else if (d >= 0)
 		{
@@ -298,7 +299,7 @@ int ewmh_WMDesktop(
 			    IS_STICKY_ACROSS_DESKS(fw))
 			{
 				execute_function_override_window(
-					NULL, NULL, "Stick off", 0, fw);
+					NULL, NULL, "Stick off", NULL, 0, fw);
 			}
 			if (fw->Desk != d)
 			{
@@ -449,18 +450,18 @@ int ewmh_MoveResize(
 	if (!move)
 	{
 		sprintf(cmd, "WarpToWindow %i %i",x_warp,y_warp);
-		execute_function_override_window(NULL, NULL, cmd, 0, fw);
+		execute_function_override_window(NULL, NULL, cmd, NULL, 0, fw);
 	}

 	if (move)
 	{
 		execute_function_override_window(
-			NULL, NULL, "Move", 0, fw);
+			NULL, NULL, "Move", NULL, 0, fw);
 	}
 	else
 	{
 		execute_function_override_window(
-			NULL, NULL, "Resize", 0, fw);
+			NULL, NULL, "Resize", NULL, 0, fw);
 	}

 	return 0;
@@ -558,7 +559,7 @@ int ewmh_WMState(
 			}
 			sprintf(cmd,"Maximize on %i %i", max_horiz, max_vert);
 		}
-		execute_function_override_window(NULL, NULL, cmd, 0, fw);
+		execute_function_override_window(NULL, NULL, cmd, NULL, 0, fw);
 	}
 	return 0;
 }
@@ -628,7 +629,7 @@ int ewmh_WMStateFullScreen(
 			/* unmaximize will restore is_ewmh_fullscreen,
 			 * layer and apply_decor_change */
 			execute_function_override_window(
-				NULL, NULL, "Maximize off", 0, fw);
+				NULL, NULL, "Maximize off", NULL, 0, fw);
 		}
 		if ((IS_EWMH_FULLSCREEN(fw) &&
 		     !DO_EWMH_USE_STACKING_HINTS(fw)) ||
@@ -638,7 +639,7 @@ int ewmh_WMStateFullScreen(
 			/* On: if not raised by a layer cmd raise
 			 * Off: if lowered by a layer cmd raise */
 			execute_function_override_window(
-				NULL, NULL, "Raise", 0, fw);
+				NULL, NULL, "Raise", NULL, 0, fw);
 		}
 	}

@@ -720,7 +721,7 @@ int ewmh_WMStateHidden(
 			/* deiconify */
 			sprintf(cmd, "Iconify off");
 		}
-		execute_function_override_window(NULL, NULL, cmd, 0, fw);
+		execute_function_override_window(NULL, NULL, cmd, NULL, 0, fw);
 	}
 	return 0;
 }
@@ -1042,7 +1043,7 @@ int ewmh_WMStateShaded(
 			 cmd_arg == NET_WM_STATE_ADD))
 		{
 			execute_function_override_window(
-				NULL, NULL, "Windowshade on", 0, fw);
+				NULL, NULL, "Windowshade on", NULL, 0, fw);
 		}
 		else if (
 			IS_SHADED(fw) &&
@@ -1050,7 +1051,7 @@ int ewmh_WMStateShaded(
 			 cmd_arg == NET_WM_STATE_REMOVE))
 		{
 			execute_function_override_window(
-				NULL, NULL, "Windowshade off", 0, fw);
+				NULL, NULL, "Windowshade off", NULL, 0, fw);
 		}
 	}
 	return 0;
@@ -1441,7 +1442,7 @@ int ewmh_WMStateSticky(
 		    bool_arg == NET_WM_STATE_ADD)
 		{
 			execute_function_override_window(
-				NULL, NULL, "Stick on", 0, fw);
+				NULL, NULL, "Stick on", NULL, 0, fw);
 		}
 		else if ((IS_STICKY_ACROSS_PAGES(fw) ||
 			  IS_STICKY_ACROSS_DESKS(fw)) &&
@@ -1449,7 +1450,7 @@ int ewmh_WMStateSticky(
 			  bool_arg == NET_WM_STATE_REMOVE))
 		{
 			execute_function_override_window(
-				NULL, NULL, "Stick off", 1, fw);
+				NULL, NULL, "Stick off", NULL, 1, fw);
 		}
 	}
 	return 0;
diff --git a/fvwm/expand.c b/fvwm/expand.c
index 3d366bb5..4d9e6b19 100644
--- a/fvwm/expand.c
+++ b/fvwm/expand.c
@@ -28,7 +28,9 @@
 #include "fvwm.h"
 #include "externs.h"
 #include "cursor.h"
+#include "cmdparser.h"
 #include "functions.h"
+#include "expand.h"
 #include "misc.h"
 #include "move_resize.h"
 #include "screen.h"
@@ -1206,7 +1208,7 @@ GOT_STRING:
 /* ---------------------------- interface functions ------------------------ */

 char *expand_vars(
-	char *input, char *arguments[], Bool addto, Bool ismod,
+	char *input, cmdparser_context_t *pc, Bool addto, Bool ismod,
 	cond_rc_t *cond_rc, const exec_context_t *exc)
 {
 	int l, i, l2, n, k, j, m;
@@ -1280,12 +1282,12 @@ char *expand_vars(
 					if (name_has_dollar)
 					{
 						var = expand_vars(
-							var, arguments, addto,
-							ismod, cond_rc, exc);
+							var, pc, addto, ismod,
+							cond_rc, exc);
 					}
 					xlen = expand_args_extended(
-						var, arguments ? arguments[0] :
-						NULL, NULL);
+						var, pc->all_pos_args_string,
+						NULL);
 					if (xlen < 0)
 					{
 						xlen = expand_vars_extended(
@@ -1315,20 +1317,26 @@ char *expand_vars(
 			case '8':
 			case '9':
 			case '*':
+			{
+				char *s;
+
 				if (input[i + 1] == '*')
 				{
-					n = 0;
+					s = pc->all_pos_args_string;
 				}
 				else
 				{
-					n = input[i + 1] - '0' + 1;
+					n = input[i + 1] - '0';
+					s = pc->pos_arg_tokens[n];
 				}
-				if (arguments[n] != NULL)
+				n = input[i + 1] - '0';
+				if (s != NULL)
 				{
-					l2 += strlen(arguments[n]) - 2;
+					l2 += strlen(s) - 2;
 					i++;
 				}
 				break;
+			}
 			case '.':
 				string = get_current_read_dir();
 				break;
@@ -1459,12 +1467,11 @@ char *expand_vars(
 					if (name_has_dollar)
 					{
 						var = expand_vars(
-							var, arguments,	addto,
-							ismod, cond_rc,	exc);
+							var, pc, addto, ismod,
+							cond_rc, exc);
 					}
 					xlen = expand_args_extended(
-						var, arguments ?
-						arguments[0] : NULL,
+						var, pc->all_pos_args_string,
 						&out[j]);
 					if (xlen < 0)
 					{
@@ -1509,19 +1516,23 @@ char *expand_vars(
 			case '8':
 			case '9':
 			case '*':
+			{
+				char *s;
+
 				if (input[i + 1] == '*')
 				{
-					n = 0;
+					s = pc->all_pos_args_string;
 				}
 				else
 				{
-					n = input[i + 1] - '0' + 1;
+					n = input[i + 1] - '0';
+					s = pc->pos_arg_tokens[n];
 				}
-				if (arguments[n] != NULL)
+				if (s != NULL)
 				{
-					for (k = 0; arguments[n][k]; k++)
+					for (k = 0; s[k]; k++)
 					{
-						out[j++] = arguments[n][k];
+						out[j++] = s[k];
 					}
 					i++;
 				}
@@ -1534,6 +1545,7 @@ char *expand_vars(
 					i++;
 				}
 				break;
+			}
 			case '.':
 				string = get_current_read_dir();
 				is_string = True;
diff --git a/fvwm/expand.h b/fvwm/expand.h
index 087c3723..b1ec03fa 100644
--- a/fvwm/expand.h
+++ b/fvwm/expand.h
@@ -18,7 +18,7 @@
 /* ---------------------------- interface functions ------------------------ */

 char *expand_vars(
-	char *input, char *arguments[], Bool addto, Bool ismod,
+	char *input, cmdparser_context_t *pc, Bool addto, Bool ismod,
 	cond_rc_t *cond_rc, const exec_context_t *exc);

 #endif /* FVWM_EXPAND_H */
diff --git a/fvwm/functable.c b/fvwm/functable.c
index aa53a045..f003184b 100644
--- a/fvwm/functable.c
+++ b/fvwm/functable.c
@@ -84,7 +84,7 @@ const func_t func_table[] =
 	/* - Operate on all windows matching the given condition */

 	CMD_ENT("animatedmove", CMD_AnimatedMove, F_ANIMATED_MOVE,
-		FUNC_NEEDS_WINDOW, CRS_MOVE),
+		FUNC_NEEDS_WINDOW | FUNC_IS_MOVE_TYPE, CRS_MOVE),
 	/* - Like Move, but uses animation to move windows */

 	CMD_ENT("any", CMD_Any, F_ANY, 0, 0),
@@ -381,7 +381,7 @@ const func_t func_table[] =
 	/* - Bind or unbind a mouse button press to an fvwm action */

 	CMD_ENT("move", CMD_Move, F_MOVE,
-		FUNC_NEEDS_WINDOW, CRS_MOVE),
+		FUNC_NEEDS_WINDOW | FUNC_IS_MOVE_TYPE, CRS_MOVE),
 	/* - Move a window */

 	CMD_ENT("movethreshold", CMD_MoveThreshold, F_MOVE_THRESHOLD, 0, 0),
@@ -479,19 +479,20 @@ const func_t func_table[] =
 	/* - Repeat (very unreliably) the last command, don't use */

 	CMD_ENT("resize", CMD_Resize, F_RESIZE,
-		FUNC_NEEDS_WINDOW, CRS_RESIZE),
+		FUNC_NEEDS_WINDOW | FUNC_IS_MOVE_TYPE, CRS_RESIZE),
 	/* - Cause a window to be resized */

 	CMD_ENT("resizemaximize", CMD_ResizeMaximize, F_RESIZE_MAXIMIZE,
-		FUNC_NEEDS_WINDOW, CRS_RESIZE),
+		FUNC_NEEDS_WINDOW | FUNC_IS_MOVE_TYPE, CRS_RESIZE),
 	/* - Resize a window and mark window as maximized */

 	CMD_ENT("resizemove", CMD_ResizeMove, F_RESIZEMOVE,
-		FUNC_NEEDS_WINDOW, CRS_RESIZE),
+		FUNC_NEEDS_WINDOW | FUNC_IS_MOVE_TYPE, CRS_RESIZE),
 	/* - Resize and move in one operation */

 	CMD_ENT("resizemovemaximize", CMD_ResizeMoveMaximize,
-		F_RESIZEMOVE_MAXIMIZE, FUNC_NEEDS_WINDOW, CRS_RESIZE),
+		F_RESIZEMOVE_MAXIMIZE, FUNC_NEEDS_WINDOW | FUNC_IS_MOVE_TYPE,
+		CRS_RESIZE),
 	/* - Resize and move in one operation and mark maximized */

 	CMD_ENT("restacktransients", CMD_RestackTransients, F_RESTACKTRANSIENTS,
@@ -651,3 +652,56 @@ const func_t func_table[] =

 	{ "", 0, 0, 0, 0 }
 };
+
+/* ---------------------------- local functions ---------------------------- */
+
+/*
+ * do binary search on func list
+ */
+static int func_comp(const void *a, const void *b)
+{
+	return (strcmp((char *)a, ((func_t *)b)->keyword));
+}
+
+/* ---------------------------- interface functions ------------------------ */
+
+const func_t *find_builtin_function(const char *func)
+{
+	static int nfuncs = 0;
+	func_t *ret_func;
+	char *temp;
+	char *s;
+
+	if (!func || func[0] == 0)
+	{
+		return NULL;
+	}
+
+	/* since a lot of lines in a typical rc are probably menu/func
+	 * continues: */
+	if (func[0]=='+' || (func[0] == ' ' && func[1] == '+'))
+	{
+		return &(func_table[0]);
+	}
+
+	temp = fxstrdup(func);
+	for (s = temp; *s != 0; s++)
+	{
+		if (isupper(*s))
+		{
+			*s = tolower(*s);
+		}
+	}
+	if (nfuncs == 0)
+	{
+		for ( ; (func_table[nfuncs]).action != NULL; nfuncs++)
+		{
+			/* nothing to do here */
+		}
+	}
+	ret_func = (func_t *)bsearch(
+		temp, func_table, nfuncs, sizeof(func_t), func_comp);
+	free(temp);
+
+	return ret_func;
+}
diff --git a/fvwm/functable.h b/fvwm/functable.h
index 8f0ba7fb..c5bf6b9b 100644
--- a/fvwm/functable.h
+++ b/fvwm/functable.h
@@ -4,22 +4,39 @@
 #define FVWM_FUNCTABLE_H

 /* ---------------------------- included header files ---------------------- */
-#include "functions.h"

 /* ---------------------------- global definitions ------------------------- */

-#define PRE_KEEPRC       "keeprc"
-#define PRE_REPEAT       "repeat"
-#define PRE_SILENT       "silent"
+#define PRE_KEEPRC "keeprc"
+#define PRE_REPEAT "repeat"
+#define PRE_SILENT "silent"

 /* ---------------------------- global macros ------------------------------ */

 /* ---------------------------- type definitions --------------------------- */

+typedef unsigned int func_flags_t;
+
+/* used for parsing commands*/
+typedef struct
+{
+	char *keyword;
+#ifdef __STDC__
+	void (*action)(F_CMD_ARGS);
+#else
+	void (*action)();
+#endif
+	short func_c;
+	func_flags_t flags;
+	int cursor;
+} func_t;
+
 /* ---------------------------- exported variables (globals) --------------- */

 extern const func_t func_table[];

 /* ---------------------------- interface functions ------------------------ */

+const func_t *find_builtin_function(const char *func);
+
 #endif /* FVWM_FUNCTABLE_H */
diff --git a/fvwm/functable_complex.c b/fvwm/functable_complex.c
new file mode 100644
index 00000000..34539014
--- /dev/null
+++ b/fvwm/functable_complex.c
@@ -0,0 +1,157 @@
+/* -*-c-*- */
+/* This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* ---------------------------- included header files ---------------------- */
+
+#include "config.h"
+
+#include "libs/fvwmlib.h"
+#include "libs/Picture.h"
+#include "libs/Strings.h"
+
+#include "fvwm.h"
+#include "cmdparser.h"
+#include "execcontext.h"
+#include "functable.h"
+#include "functable.h"
+#include "functable_complex.h"
+#include "misc.h"
+#include "screen.h"
+
+/* ---------------------------- local definitions -------------------------- */
+
+/* ---------------------------- local macros ------------------------------- */
+
+/* ---------------------------- imports ------------------------------------ */
+
+/* ---------------------------- included code files ------------------------ */
+
+/* ---------------------------- local types -------------------------------- */
+
+/* ---------------------------- local variables ---------------------------- */
+
+/* ---------------------------- exported variables (globals) --------------- */
+
+/* ---------------------------- local functions ---------------------------- */
+
+FvwmFunction *NewFvwmFunction(const char *name)
+{
+	FvwmFunction *tmp;
+
+	tmp = fxmalloc(sizeof *tmp);
+	tmp->next_func = Scr.functions;
+	tmp->first_item = NULL;
+	tmp->last_item = NULL;
+	tmp->name = stripcpy(name);
+	tmp->use_depth = 0;
+	Scr.functions = tmp;
+
+	return tmp;
+}
+
+void DestroyFunction(FvwmFunction *func)
+{
+	FunctionItem *fi,*tmp2;
+	FvwmFunction *tmp, *prev;
+
+	if (func == NULL)
+	{
+		return;
+	}
+
+	tmp = Scr.functions;
+	prev = NULL;
+	while (tmp && tmp != func)
+	{
+		prev = tmp;
+		tmp = tmp->next_func;
+	}
+	if (tmp != func)
+	{
+		return;
+	}
+
+	if (func->use_depth != 0)
+	{
+		fvwm_debug(
+			"Function %s is in use (depth %d)", func->name,
+			func->use_depth);
+		return;
+	}
+
+	if (prev == NULL)
+	{
+		Scr.functions = func->next_func;
+	}
+	else
+	{
+		prev->next_func = func->next_func;
+	}
+
+	free(func->name);
+
+	fi = func->first_item;
+	while (fi != NULL)
+	{
+		tmp2 = fi->next_item;
+		if (fi->action != NULL)
+		{
+			free(fi->action);
+		}
+		free(fi);
+		fi = tmp2;
+	}
+	free(func);
+
+	return;
+}
+
+/* ---------------------------- interface functions ------------------------ */
+
+/* find_complex_function expects a token as the input. Make sure you have used
+ * GetNextToken before passing a function name to remove quotes */
+FvwmFunction *find_complex_function(const char *function_name)
+{
+	FvwmFunction *func;
+
+	if (function_name == NULL || *function_name == 0)
+	{
+		return NULL;
+	}
+	func = Scr.functions;
+	while (func != NULL)
+	{
+		if (func->name != NULL)
+		{
+			if (strcasecmp(function_name, func->name) == 0)
+			{
+				return func;
+			}
+		}
+		func = func->next_func;
+	}
+
+	return NULL;
+}
+Bool functions_is_complex_function(const char *function_name)
+{
+	if (find_complex_function(function_name) != NULL)
+	{
+		return True;
+	}
+
+	return False;
+}
diff --git a/fvwm/functable_complex.h b/fvwm/functable_complex.h
new file mode 100644
index 00000000..f3d50483
--- /dev/null
+++ b/fvwm/functable_complex.h
@@ -0,0 +1,55 @@
+/* -*-c-*- */
+
+#ifndef FVWM_FUNCTABLE_COMPLEX_H
+#define FVWM_FUNCTABLE_COMPLEX_H
+
+/* ---------------------------- included header files ---------------------- */
+
+/* ---------------------------- global definitions ------------------------- */
+
+/* ---------------------------- global macros ------------------------------ */
+
+/* ---------------------------- type definitions --------------------------- */
+
+typedef struct FunctionItem
+{
+	struct FvwmFunction *func;       /* the function this item is in */
+	struct FunctionItem *next_item;  /* next function item */
+	char condition;                  /* the character string displayed on
+					  * left*/
+	char *action;                    /* action to be performed */
+	short type;                      /* type of built in function */
+	func_flags_t flags;
+} FunctionItem;
+
+typedef struct FvwmFunction
+{
+	struct FvwmFunction *next_func;  /* next in list of root menus */
+	FunctionItem *first_item;        /* first item in function */
+	FunctionItem *last_item;         /* last item in function */
+	char *name;                      /* function name */
+	int use_depth;
+} FvwmFunction;
+
+/* Types of events for the FUNCTION builtin */
+typedef enum
+{
+	CF_IMMEDIATE =      'i',
+	CF_LATE_IMMEDIATE = 'j',
+	CF_MOTION =         'm',
+	CF_HOLD =           'h',
+	CF_CLICK =          'c',
+	CF_DOUBLE_CLICK =   'd',
+	CF_TIMEOUT =        '-'
+} cfunc_action_t;
+
+/* ---------------------------- exported variables (globals) --------------- */
+
+/* ---------------------------- interface functions ------------------------ */
+
+FvwmFunction *NewFvwmFunction(const char *name);
+void DestroyFunction(FvwmFunction *func);
+FvwmFunction *find_complex_function(const char *function_name);
+Bool functions_is_complex_function(const char *function_name);
+
+#endif /* FVWM_FUNCTABLE_COMPLEX_H */
diff --git a/fvwm/functions.c b/fvwm/functions.c
index a40718cd..060eaff3 100644
--- a/fvwm/functions.c
+++ b/fvwm/functions.c
@@ -22,6 +22,9 @@
 #include "config.h"

 #include <stdio.h>
+#if 1 /*!!!*/
+#include <assert.h>
+#endif

 #include "libs/fvwm_x11.h"
 #include "libs/fvwmlib.h"
@@ -36,9 +39,13 @@
 #include "externs.h"
 #include "cursor.h"
 #include "execcontext.h"
+#include "functable.h"
+#include "functable_complex.h"
+#include "cmdparser.h"
+#include "cmdparser_hooks.h"
+#include "cmdparser_old.h"
 #include "functions.h"
 #include "commands.h"
-#include "functable.h"
 #include "events.h"
 #include "modconf.h"
 #include "module_list.h"
@@ -58,45 +65,19 @@

 /* ---------------------------- local types -------------------------------- */

-typedef struct FunctionItem
-{
-	struct FvwmFunction *func;       /* the function this item is in */
-	struct FunctionItem *next_item;  /* next function item */
-	char condition;                  /* the character string displayed on
-					  * left*/
-	char *action;                    /* action to be performed */
-	short type;                      /* type of built in function */
-	FUNC_FLAGS_TYPE flags;
-} FunctionItem;
-
-typedef struct FvwmFunction
-{
-	struct FvwmFunction *next_func;  /* next in list of root menus */
-	FunctionItem *first_item;        /* first item in function */
-	FunctionItem *last_item;         /* last item in function */
-	char *name;                      /* function name */
-	int use_depth;
-} FvwmFunction;
-
-/* Types of events for the FUNCTION builtin */
-typedef enum
-{
-	CF_IMMEDIATE =      'i',
-	CF_LATE_IMMEDIATE = 'j',
-	CF_MOTION =         'm',
-	CF_HOLD =           'h',
-	CF_CLICK =          'c',
-	CF_DOUBLE_CLICK =   'd',
-	CF_TIMEOUT =        '-'
-} cfunc_action_t;
-
 /* ---------------------------- forward declarations ----------------------- */

 static void execute_complex_function(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	Bool *desperate, Bool has_ref_window_moved);
+	cond_rc_t *cond_rc, const exec_context_t *exc, cmdparser_context_t *pc,
+	FvwmFunction *func, Bool has_ref_window_moved);
+
+ /* ---------------------------- local variables ---------------------------- */

-/* ---------------------------- local variables ---------------------------- */
+/* Temporary instance of the hooks functions used in this file.  The goal is
+ * to remove all parsing and expansion from functions.c and move it into a
+ * separate, replaceable file.  */
+
+static const cmdparser_hooks_t *cmdparser_hooks = NULL;

 /* ---------------------------- exported variables (globals) --------------- */

@@ -294,120 +275,85 @@ static Bool DeferExecution(
 	return False;
 }

-/*
-** do binary search on func list
-*/
-static int func_comp(const void *a, const void *b)
-{
-	return (strcmp((char *)a, ((func_t *)b)->keyword));
-}
-
-static const func_t *find_builtin_function(char *func)
-{
-	static int nfuncs = 0;
-	func_t *ret_func;
-	char *temp;
-	char *s;
-
-	if (!func || func[0] == 0)
-	{
-		return NULL;
-	}
-
-	/* since a lot of lines in a typical rc are probably menu/func
-	 * continues: */
-	if (func[0]=='+' || (func[0] == ' ' && func[1] == '+'))
-	{
-		return &(func_table[0]);
-	}
-
-	temp = fxstrdup(func);
-	for (s = temp; *s != 0; s++)
-	{
-		if (isupper(*s))
-		{
-			*s = tolower(*s);
-		}
-	}
-	if (nfuncs == 0)
-	{
-		for ( ; (func_table[nfuncs]).action != NULL; nfuncs++)
-		{
-			/* nothing to do here */
-		}
-	}
-	ret_func = (func_t *)bsearch(
-		temp, func_table, nfuncs, sizeof(func_t), func_comp);
-	free(temp);
-
-	return ret_func;
-}
-
-static void __execute_function(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	FUNC_FLAGS_TYPE exec_flags, char *args[], Bool has_ref_window_moved)
+static void __execute_command_line(
+	cond_rc_t *cond_rc, const exec_context_t *exc, char *xaction,
+	cmdparser_context_t *caller_pc,
+	func_flags_t exec_flags, char *all_pos_args_string,
+	char *pos_arg_tokens[], Bool has_ref_window_moved)
 {
-	static int func_depth = 0;
+	cmdparser_context_t pc;
 	cond_rc_t *func_rc = NULL;
 	cond_rc_t dummy_rc;
 	Window w;
-	int j;
-	char *function;
-	char *taction;
-	char *trash;
-	char *trash2;
-	char *expaction = NULL;
-	char *arguments[11];
+	char *err_cline;
+	const char *err_func;
+	cmdparser_execute_type_t exec_type;
 	const func_t *bif;
-	Bool set_silent;
-	Bool must_free_function = False;
-	Bool must_free_expaction = False;
-	Bool do_keep_rc = False;
+	FvwmFunction *complex_function;
+	int set_silent;
+	int do_keep_rc = 0;
 	/* needed to be able to avoid resize to use moved windows for base */
 	extern Window PressedW;
 	Window dummy_w;
+	int rc;

-	if (!action)
-	{
-		return;
-	}
-	/* ignore whitespace at the beginning of all config lines */
-	action = SkipSpaces(action, NULL, 0);
-	if (!action || action[0] == 0)
+#if 1 /*!!!*/
+	fprintf(stderr, "%s: cpc %p, xaction '%s'\n", __func__, caller_pc, xaction);
+#endif
+	set_silent = 0;
+	/* generate a parsing context; this *must* be destroyed before
+	 * returning */
+	rc = cmdparser_hooks->create_context(
+		&pc, caller_pc, xaction, all_pos_args_string, pos_arg_tokens);
+	if (rc != 0)
 	{
-		/* impossibly short command */
-		return;
+		goto fn_exit;
 	}
-	if (action[0] == '#')
+cmdparser_hooks->debug(&pc, "!!!A");
+	rc = cmdparser_hooks->handle_line_start(&pc);
+	if (rc != 0)
 	{
-		/* a comment */
-		return;
+		goto fn_exit;
 	}
+cmdparser_hooks->debug(&pc, "!!!B");

-	func_depth++;
-	if (func_depth > MAX_FUNCTION_DEPTH)
-	{
-		fvwm_debug(__func__,
-			   "Function '%s' called with a depth of %i, "
-			   "stopping function execution!",
-			   action, func_depth);
-		func_depth--;
-		return;
-	}
-	if (args)
 	{
-		for (j = 0; j < 11; j++)
+		cmdparser_prefix_flags_t flags;
+
+		flags = cmdparser_hooks->handle_line_prefix(&pc);
+cmdparser_hooks->debug(&pc, "!!!BA");
+		if (flags & CP_PREFIX_MINUS)
 		{
-			arguments[j] = args[j];
+#if 1 /*!!!*/
+fprintf(stderr, "!!!do not expand\n");
+#endif
+			exec_flags |= FUNC_DONT_EXPAND_COMMAND;
 		}
-	}
-	else
-	{
-		for (j = 0; j < 11; j++)
+		if (flags & CP_PREFIX_SILENT)
+		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!is silent\n");
+#endif
+			if (Scr.flags.are_functions_silent == 0)
+			{
+				set_silent = 1;
+				Scr.flags.are_functions_silent = 1;
+			}
+		}
+		if (flags & CP_PREFIX_KEEPRC)
+		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!do keeprc\n");
+#endif
+			do_keep_rc = 1;
+		}
+		if (pc.cline == NULL)
 		{
-			arguments[j] = NULL;
+			goto fn_exit;
 		}
+		err_cline = pc.cline;
 	}
+cmdparser_hooks->debug(&pc, "!!!C");

 	if (exc->w.fw == NULL || IS_EWMH_DESKTOP(FW_W(exc->w.fw)))
 	{
@@ -444,50 +390,7 @@ static void __execute_function(
 			w = FW_W(exc->w.fw);
 		}
 	}
-
-	set_silent = False;
-	if (action[0] == '-')
-	{
-		exec_flags |= FUNC_DONT_EXPAND_COMMAND;
-		action++;
-	}
-
-	taction = action;
-	/* parse prefixes */
-	trash = PeekToken(taction, &trash2);
-	while (trash)
-	{
-		if (StrEquals(trash, PRE_SILENT))
-		{
-			if (Scr.flags.are_functions_silent == 0)
-			{
-				set_silent = 1;
-				Scr.flags.are_functions_silent = 1;
-			}
-			taction = trash2;
-			trash = PeekToken(taction, &trash2);
-		}
-		else if (StrEquals(trash, PRE_KEEPRC))
-		{
-			do_keep_rc = True;
-			taction = trash2;
-			trash = PeekToken(taction, &trash2);
-		}
-		else
-		{
-			break;
-		}
-	}
-	if (taction == NULL)
-	{
-		if (set_silent)
-		{
-			Scr.flags.are_functions_silent = 0;
-		}
-		func_depth--;
-		return;
-	}
-	if (cond_rc == NULL || do_keep_rc == True)
+	if (cond_rc == NULL || do_keep_rc)
 	{
 		condrc_init(&dummy_rc);
 		func_rc = &dummy_rc;
@@ -496,42 +399,22 @@ static void __execute_function(
 	{
 		func_rc = cond_rc;
 	}
-
-	GetNextToken(taction, &function);
-	if (function)
-	{
-		char *tmp = function;
-		function = expand_vars(
-			function, arguments, False, False, func_rc, exc);
-		free(tmp);
-	}
-	if (function && function[0] != '*')
 	{
-#if 1
-		/* DV: with this piece of code it is impossible to have a
-		 * complex function with embedded whitespace that begins with a
-		 * builtin function name, e.g. a function "echo hello". */
-		/* DV: ... and without it some of the complex functions will
-		 * fail */
-		char *tmp = function;
+		const char *func;

-		while (*tmp && !isspace(*tmp))
+		func = cmdparser_hooks->parse_command_name(&pc, func_rc, exc);
+		if (func != NULL)
 		{
-			tmp++;
+cmdparser_hooks->debug(&pc, "!!!D");
+			bif = find_builtin_function(func);
+			err_func = func;
 		}
-		*tmp = 0;
-#endif
-		bif = find_builtin_function(function);
-		must_free_function = True;
-	}
-	else
-	{
-		bif = NULL;
-		if (function)
+		else
 		{
-			free(function);
+cmdparser_hooks->debug(&pc, "!!!E");
+			bif = NULL;
+			err_func = "";
 		}
-		function = "";
 	}

 	if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor &&
@@ -539,177 +422,163 @@ static void __execute_function(
 	{
 		fvwm_debug(__func__,
 			   "Command can not be added to a decor; executing"
-			   " command now: '%s'", action);
+			   " command now: '%s'", err_cline);
 	}

 	if (!(exec_flags & FUNC_DONT_EXPAND_COMMAND))
 	{
-		expaction = expand_vars(
-			taction, arguments, (bif) ?
-			!!(bif->flags & FUNC_ADD_TO) :
-			False, (taction[0] == '*'), func_rc, exc);
-		must_free_expaction = True;
-		if (func_depth <= 1)
+		cmdparser_hooks->expand_command_line(
+			&pc, (bif) ? !!(bif->flags & FUNC_ADD_TO) : False,
+			func_rc, exc);
+cmdparser_hooks->debug(&pc, "!!!F");
+		if (pc.call_depth <= 1)
 		{
-			must_free_expaction = set_repeat_data(expaction, REPEAT_COMMAND, bif);
+			Bool do_free_string_ourselves;
+
+			do_free_string_ourselves = set_repeat_data(
+				pc.expline, REPEAT_COMMAND, bif);
+			if (do_free_string_ourselves == False)
+			{
+				cmdparser_hooks->release_expanded_line(&pc);
+cmdparser_hooks->debug(&pc, "!!!F");
+			}
 		}
 	}
-	else
-	{
-		expaction = taction;
-		must_free_expaction = False;
-	}
+#if 1 /*!!!*/
+fprintf(stderr, "!!!pc.cline: '%s'\n", pc.cline);
+#endif

-	/* Note: the module config command, "*" can not be handled by the
-	 * regular command table because there is no required white space after
-	 * the asterisk. */
-	if (expaction[0] == '*')
+	exec_type = cmdparser_hooks->find_something_to_execute(
+		&pc, &bif, &complex_function);
+cmdparser_hooks->debug(&pc, "!!!H");
+fprintf(stderr, "!!!exec_type %d\n", exec_type);
+	switch (exec_type)
 	{
-		if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
-		{
-			fvwm_debug(__func__,
-				   "Command can not be added to a decor;"
-				   " executing command now: '%s'", expaction);
-		}
-
-		/* process a module config command */
-		ModuleConfig(expaction);
-	}
-	else
+	case CP_EXECTYPE_BUILTIN_FUNCTION:
 	{
 		const exec_context_t *exc2;
 		exec_context_changes_t ecc;
 		exec_context_change_mask_t mask;

+cmdparser_hooks->debug(&pc, "!!!J");
+#if 1 /*!!!*/
+		assert(bif && bif->func_c != F_FUNCTION);
+#endif
+#if 1 /*!!!*/
+fprintf(stderr, "!!!pc.cline: '%s'\n", pc.cline);
+#endif
 		mask = (w != exc->w.w) ? ECC_W : 0;
 		ecc.w.fw = exc->w.fw;
 		ecc.w.w = w;
 		ecc.w.wcontext = exc->w.wcontext;
-		if (bif && bif->func_t != F_FUNCTION)
+		if (
+			(bif->flags & FUNC_NEEDS_WINDOW) &&
+			!(exec_flags & FUNC_DONT_DEFER))
 		{
-			char *runaction;
-			Bool rc = False;
+			Bool rc;

-			runaction = SkipNTokens(expaction, 1);
-			if ((bif->flags & FUNC_NEEDS_WINDOW) &&
-			    !(exec_flags & FUNC_DONT_DEFER))
-			{
-				rc = DeferExecution(
-					&ecc, &mask, bif->cursor,
-					exc->x.elast->type,
-					(bif->flags & FUNC_ALLOW_UNMANAGED));
-			}
-			else if ((bif->flags & FUNC_NEEDS_WINDOW) &&
-				 !__context_has_window(
-					 exc,
-					 bif->flags & FUNC_ALLOW_UNMANAGED))
+			rc = DeferExecution(
+				&ecc, &mask, bif->cursor, exc->x.elast->type,
+				(bif->flags & FUNC_ALLOW_UNMANAGED));
+			if (rc == True)
 			{
-				/* no context window and not allowed to defer,
-				 * skip command */
-				rc = True;
-			}
-			if (rc == False)
-			{
-				exc2 = exc_clone_context(exc, &ecc, mask);
-				if (has_ref_window_moved &&
-				    (bif->func_t == F_ANIMATED_MOVE ||
-				     bif->func_t == F_MOVE ||
-				     bif->func_t == F_RESIZE ||
-				     bif->func_t == F_RESIZEMOVE ||
-				     bif->func_t == F_RESIZE_MAXIMIZE ||
-				     bif->func_t == F_RESIZEMOVE_MAXIMIZE))
-				{
-					dummy_w = PressedW;
-					PressedW = None;
-					bif->action(func_rc, exc2, runaction);
-					PressedW = dummy_w;
-				}
-				else
-				{
-					bif->action(func_rc, exc2, runaction);
-				}
-				exc_destroy_context(exc2);
+				break;
 			}
+#if 1 /*!!!*/
+fprintf(stderr, "!!!deferred: %d\n", rc);
+#endif
 		}
-		else
+		else if (
+			(bif->flags & FUNC_NEEDS_WINDOW) &&
+			!__context_has_window(
+				exc, bif->flags & FUNC_ALLOW_UNMANAGED))
 		{
-			Bool desperate = 1;
-			char *runaction;
-
-			if (bif)
-			{
-				/* strip "function" command */
-				runaction = SkipNTokens(expaction, 1);
-			}
-			else
-			{
-				runaction = expaction;
-			}
-			exc2 = exc_clone_context(exc, &ecc, mask);
-			execute_complex_function(
-				func_rc, exc2, runaction, &desperate,
-				has_ref_window_moved);
-			if (!bif && desperate)
-			{
-				if (executeModuleDesperate(
-					    func_rc, exc, runaction) == NULL &&
-				    *function != 0 && !set_silent)
-				{
-					fvwm_debug(__func__,
-						   "No such command '%s'",
-						   function);
-				}
-			}
-			exc_destroy_context(exc2);
+#if 1 /*!!!*/
+fprintf(stderr, "!!!skip no-defer\n");
+#endif
+			/* no context window and not allowed to defer,
+			 * skip command */
+			break;
 		}
+		exc2 = exc_clone_context(exc, &ecc, mask);
+		dummy_w = PressedW;
+		if (
+			has_ref_window_moved &&
+			(bif->flags & FUNC_IS_MOVE_TYPE))
+		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!erase PressedW\n");
+#endif
+			PressedW = None;
+		}
+#if 1 /*!!!*/
+fprintf(stderr, "!!!execute '%s'\n", bif->keyword);
+#endif
+		bif->action(func_rc, exc2, pc.cline, &pc);
+		PressedW = dummy_w;
+		exc_destroy_context(exc2);
+		break;
 	}
-
-	if (set_silent)
-	{
-		Scr.flags.are_functions_silent = 0;
-	}
-	if (cond_rc != NULL)
-	{
-		cond_rc->break_levels = func_rc->break_levels;
-	}
-	if (must_free_function)
+	case CP_EXECTYPE_COMPLEX_FUNCTION:
 	{
-		free(function);
+		const exec_context_t *exc2;
+		exec_context_changes_t ecc;
+		exec_context_change_mask_t mask;
+
+		mask = (w != exc->w.w) ? ECC_W : 0;
+		ecc.w.fw = exc->w.fw;
+		ecc.w.w = w;
+		ecc.w.wcontext = exc->w.wcontext;
+		exc2 = exc_clone_context(exc, &ecc, mask);
+		execute_complex_function(
+			func_rc, exc2, &pc, complex_function,
+			has_ref_window_moved);
+		exc_destroy_context(exc2);
+		break;
 	}
-	/* Free the string allocated by expand_vars earlier in this function. */
-	if (must_free_expaction)
-	{
-		free(expaction);
+	case CP_EXECTYPE_COMPLEX_FUNCTION_DOES_NOT_EXIST:
+		fvwm_debug(
+			__func__, "No such function %s",
+			pc.complex_function_name);
+		break;
+	case CP_EXECTYPE_MODULECONFIG:
+		/* Note: the module config command, "*" can not be handled by
+		 * the regular command table because there is no required
+		 * white space after the asterisk. */
+		if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
+		{
+			fvwm_debug(
+				__func__, "Command can not be added to a decor;"
+				" executing command now: '%s'", pc.expline);
+		}
+		/* process a module config command */
+		ModuleConfig(pc.expline);
+		goto fn_exit;
+	case CP_EXECTYPE_UNKNOWN:
+		if (executeModuleDesperate(func_rc, exc, pc.cline, &pc) ==
+		    NULL && *err_func != 0 && !set_silent)
+		{
+			fvwm_debug(__func__, "No such command '%s'", err_func);
+		}
+		break;
+#if 1 /*!!!*/
+	default:
+		assert(!"bad exec_type");
+#endif
 	}
-	func_depth--;
-
-	return;
-}
-
-/* find_complex_function expects a token as the input. Make sure you have used
- * GetNextToken before passing a function name to remove quotes */
-static FvwmFunction *find_complex_function(const char *function_name)
-{
-	FvwmFunction *func;

-	if (function_name == NULL || *function_name == 0)
+  fn_exit:
+	if (func_rc != NULL && cond_rc != NULL)
 	{
-		return NULL;
+		cond_rc->break_levels = func_rc->break_levels;
 	}
-	func = Scr.functions;
-	while (func != NULL)
+	if (set_silent)
 	{
-		if (func->name != NULL)
-		{
-			if (strcasecmp(function_name, func->name) == 0)
-			{
-				return func;
-			}
-		}
-		func = func->next_func;
+		Scr.flags.are_functions_silent = 0;
 	}
+	cmdparser_hooks->destroy_context(&pc);

-	return NULL;
+	return;
 }

 /*
@@ -801,7 +670,9 @@ static cfunc_action_t CheckActionType(

 static void __run_complex_function_items(
 	cond_rc_t *cond_rc, char cond, FvwmFunction *func,
-	const exec_context_t *exc, char *args[], Bool has_ref_window_moved)
+	const exec_context_t *exc, cmdparser_context_t *caller_pc,
+	char *all_pos_args_string, char *pos_arg_tokens[],
+	Bool has_ref_window_moved)
 {
 	char c;
 	FunctionItem *fi;
@@ -825,9 +696,10 @@ static void __run_complex_function_items(
 		}
 		if (c == cond)
 		{
-			__execute_function(
-				cond_rc, exc, fi->action, FUNC_DONT_DEFER,
-				args, has_ref_window_moved);
+			__execute_command_line(
+				cond_rc, exc, fi->action, caller_pc,
+				FUNC_DONT_DEFER, all_pos_args_string,
+				pos_arg_tokens, has_ref_window_moved);
 			if (!has_ref_window_moved && PressedW &&
 			    XTranslateCoordinates(
 				  dpy, PressedW , Scr.Root, 0, 0, &x, &y,
@@ -843,7 +715,8 @@ static void __run_complex_function_items(
 }

 static void __cf_cleanup(
-	int *depth, char **arguments, cond_rc_t *cond_rc)
+	FvwmFunction *func, int *depth, char *all_pos_args_string,
+	char **pos_arg_tokens, cond_rc_t *cond_rc)
 {
 	int i;

@@ -852,11 +725,15 @@ static void __cf_cleanup(
 	{
 		Scr.flags.is_executing_complex_function = 0;
 	}
-	for (i = 0; i < 11; i++)
+	if (all_pos_args_string != NULL)
+	{
+		free(all_pos_args_string);
+	}
+	for (i = 0; i < CMDPARSER_NUM_POS_ARGS; i++)
 	{
-		if (arguments[i] != NULL)
+		if (pos_arg_tokens[i] != NULL)
 		{
-			free(arguments[i]);
+			free(pos_arg_tokens[i]);
 		}
 	}
 	if (cond_rc->break_levels > 0)
@@ -868,8 +745,8 @@ static void __cf_cleanup(
 }

 static void execute_complex_function(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	Bool *desperate, Bool has_ref_window_moved)
+	cond_rc_t *cond_rc, const exec_context_t *exc, cmdparser_context_t *pc,
+	FvwmFunction *func, Bool has_ref_window_moved)
 {
 	cond_rc_t tmp_rc;
 	cfunc_action_t type = CF_MOTION;
@@ -881,14 +758,15 @@ static void execute_complex_function(
 	Bool NeedsTarget = False;
 	Bool ImmediateNeedsTarget = False;
 	int has_immediate = 0;
+	int do_ungrab = 1;
 	int do_run_late_immediate = 0;
 	int do_allow_unmanaged = FUNC_ALLOW_UNMANAGED;
 	int do_allow_unmanaged_immediate = FUNC_ALLOW_UNMANAGED;
-	char *arguments[11], *taction;
-	char *func_name;
+	char *all_pos_args_string;
+	char *pos_arg_tokens[CMDPARSER_NUM_POS_ARGS];
+	char *taction;
 	int x, y ,i;
 	XEvent d;
-	FvwmFunction *func;
 	static int depth = 0;
 	const exec_context_t *exc2;
 	exec_context_changes_t ecc;
@@ -897,6 +775,9 @@ static void execute_complex_function(
 	int button;
 	XEvent *te;

+#if 1 /*!!!*/
+	assert(func != NULL);
+#endif
 	if (cond_rc == NULL)
 	{
 		condrc_init(&tmp_rc);
@@ -908,54 +789,33 @@ static void execute_complex_function(
 	ecc.w.fw = exc->w.fw;
 	ecc.w.w = exc->w.w;
 	ecc.w.wcontext = exc->w.wcontext;
-	/* find_complex_function expects a token, not just a quoted string */
-	func_name = PeekToken(action, &taction);
-	if (!func_name)
-	{
-		return;
-	}
-	func = find_complex_function(func_name);
-	if (func == NULL)
-	{
-		if (*desperate == 0)
-		{
-			fvwm_debug(__func__, "No such function %s",
-				   action);
-		}
-		return;
-	}
-	if (!depth)
-	{
-		Scr.flags.is_executing_complex_function = 1;
-	}
+	Scr.flags.is_executing_complex_function = 1;
 	depth++;
-	*desperate = 0;
 	/* duplicate the whole argument list for use as '$*' */
-	if (taction)
+	taction = pc->cline;
+	if (taction && *taction)
 	{
-		arguments[0] = fxstrdup(taction);
+		all_pos_args_string = fxstrdup(taction);
 		/* strip trailing newline */
-		if (arguments[0][0])
+		if (all_pos_args_string[0])
 		{
-			int l= strlen(arguments[0]);
+			int l = strlen(all_pos_args_string);

-			if (arguments[0][l - 1] == '\n')
+			if (all_pos_args_string[l - 1] == '\n')
 			{
-				arguments[0][l - 1] = 0;
+				all_pos_args_string[l - 1] = 0;
 			}
 		}
 		/* Get the argument list */
-		for (i = 1; i < 11; i++)
+		for (i = 0; i < CMDPARSER_NUM_POS_ARGS; i++)
 		{
-			taction = GetNextToken(taction, &arguments[i]);
+			taction = GetNextToken(taction, &pos_arg_tokens[i]);
 		}
 	}
 	else
 	{
-		for (i = 0; i < 11; i++)
-		{
-			arguments[i] = NULL;
-		}
+		all_pos_args_string = 0;
+		memset(pos_arg_tokens, 0, sizeof(pos_arg_tokens));
 	}
 	/* In case we want to perform an action on a button press, we
 	 * need to fool other routines */
@@ -992,11 +852,9 @@ static void execute_complex_function(
 	{
 		if (DeferExecution(
 			    &ecc, &mask, CRS_SELECT, trigger_evtype,
-			    do_allow_unmanaged_immediate))
+			    do_allow_unmanaged_immediate) == True)
 		{
-			func->use_depth--;
-			__cf_cleanup(&depth, arguments, cond_rc);
-			return;
+			goto ungrab_exit;
 		}
 		NeedsTarget = False;
 	}
@@ -1011,17 +869,18 @@ static void execute_complex_function(
 	 * button release would go to the application below. */
 	if (!GrabEm(CRS_NONE, GRAB_NORMAL))
 	{
-		func->use_depth--;
-		fvwm_debug(__func__, "Grab failed in function %s,"
-			   " unable to execute immediate action", action);
-		__cf_cleanup(&depth, arguments, cond_rc);
-		return;
+		fvwm_debug(
+			__func__,
+			"Grab failed, unable to execute immediate action");
+		goto ungrab_exit;
 	}
+	do_ungrab = 1;
 	if (has_immediate)
 	{
 		exc2 = exc_clone_context(exc, &ecc, mask);
 		__run_complex_function_items(
-			cond_rc, CF_IMMEDIATE, func, exc2, arguments,
+			cond_rc, CF_IMMEDIATE, func, exc2, pc,
+			all_pos_args_string, pos_arg_tokens,
 			has_ref_window_moved);
 		exc_destroy_context(exc2);
 	}
@@ -1054,10 +913,7 @@ static void execute_complex_function(

 	if (!Persist || cond_rc->break_levels != 0)
 	{
-		func->use_depth--;
-		__cf_cleanup(&depth, arguments, cond_rc);
-		UngrabEm(GRAB_NORMAL);
-		return;
+		goto ungrab_exit;
 	}

 	/* Only defer execution if there is a possibility of needing
@@ -1066,12 +922,9 @@ static void execute_complex_function(
 	{
 		if (DeferExecution(
 			    &ecc, &mask, CRS_SELECT, trigger_evtype,
-			    do_allow_unmanaged))
+			    do_allow_unmanaged) == True)
 		{
-			func->use_depth--;
-			__cf_cleanup(&depth, arguments, cond_rc);
-			UngrabEm(GRAB_NORMAL);
-			return;
+			goto ungrab_exit;
 		}
 	}

@@ -1107,7 +960,8 @@ static void execute_complex_function(
 	{
 		exc2 = exc_clone_context(exc, &ecc, mask);
 		__run_complex_function_items(
-			cond_rc, CF_LATE_IMMEDIATE, func, exc2, arguments,
+			cond_rc, CF_LATE_IMMEDIATE, func, exc2, pc,
+			all_pos_args_string, pos_arg_tokens,
 			has_ref_window_moved);
 		exc_destroy_context(exc2);
 		do_run_late_immediate = 0;
@@ -1162,14 +1016,11 @@ static void execute_complex_function(
 		}
 	}

-#ifdef BUGGY_CODE
 	/* domivogt (11-Apr-2000): The pointer ***must not*** be ungrabbed
 	 * here.  If it is, any window that the mouse enters during the
 	 * function will receive MotionNotify events with a button held down!
 	 * The results are unpredictable.  E.g. rxvt interprets the
 	 * ButtonMotion as user input to select text. */
-	UngrabEm(GRAB_NORMAL);
-#endif
 	fev_set_evpos(&d, x, y);
 	fev_fake_event(&d);
 	ecc.x.etrigger = &d;
@@ -1179,135 +1030,58 @@ static void execute_complex_function(
 	if (do_run_late_immediate)
 	{
 		__run_complex_function_items(
-			cond_rc, CF_LATE_IMMEDIATE, func, exc2, arguments,
+			cond_rc, CF_LATE_IMMEDIATE, func, exc2, pc,
+			all_pos_args_string, pos_arg_tokens,
 			has_ref_window_moved);
 	}
 	__run_complex_function_items(
-		cond_rc, type, func, exc2, arguments, has_ref_window_moved);
+		cond_rc, type, func, exc2, pc, all_pos_args_string,
+		pos_arg_tokens, has_ref_window_moved);
 	exc_destroy_context(exc2);
-	/* This is the right place to ungrab the pointer (see comment above).
-	 */
-	func->use_depth--;
-	__cf_cleanup(&depth, arguments, cond_rc);
-	UngrabEm(GRAB_NORMAL);
-
-	return;
-}
-
-/*
- * create a new FvwmFunction
- */
-static FvwmFunction *NewFvwmFunction(const char *name)
-{
-	FvwmFunction *tmp;
-
-	tmp = fxmalloc(sizeof *tmp);
-	tmp->next_func = Scr.functions;
-	tmp->first_item = NULL;
-	tmp->last_item = NULL;
-	tmp->name = stripcpy(name);
-	tmp->use_depth = 0;
-	Scr.functions = tmp;
-
-	return tmp;
-}
-
-static void DestroyFunction(FvwmFunction *func)
-{
-	FunctionItem *fi,*tmp2;
-	FvwmFunction *tmp, *prev;

-	if (func == NULL)
-	{
-		return;
-	}
-
-	tmp = Scr.functions;
-	prev = NULL;
-	while (tmp && tmp != func)
-	{
-		prev = tmp;
-		tmp = tmp->next_func;
-	}
-	if (tmp != func)
-	{
-		return;
-	}
-
-	if (func->use_depth != 0)
-	{
-		fvwm_debug(__func__,
-			   "Function %s is in use (depth %d)", func->name,
-			   func->use_depth);
-		return;
-	}
-
-	if (prev == NULL)
+  ungrab_exit:
+	__cf_cleanup(
+		func, &depth, all_pos_args_string, pos_arg_tokens, cond_rc);
+	if (do_ungrab)
 	{
-		Scr.functions = func->next_func;
-	}
-	else
-	{
-		prev->next_func = func->next_func;
-	}
-
-	free(func->name);
-
-	fi = func->first_item;
-	while (fi != NULL)
-	{
-		tmp2 = fi->next_item;
-		if (fi->action != NULL)
-		{
-			free(fi->action);
-		}
-		free(fi);
-		fi = tmp2;
+		UngrabEm(GRAB_NORMAL);
 	}
-	free(func);

 	return;
 }

 /* ---------------------------- interface functions ------------------------ */

-Bool functions_is_complex_function(const char *function_name)
+void functions_init(void)
 {
-	if (find_complex_function(function_name) != NULL)
-	{
-		return True;
-	}
+	cmdparser_hooks = cmdparser_old_get_hooks();

-	return False;
+	return;
 }

-void execute_function(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	FUNC_FLAGS_TYPE exec_flags)
+void execute_function(F_CMD_ARGS, func_flags_t exec_flags)
 {
-	__execute_function(cond_rc, exc, action, exec_flags, NULL, False);
+	__execute_command_line(F_PASS_ARGS, exec_flags, NULL, NULL, False);

 	return;
 }

 void execute_function_override_wcontext(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	FUNC_FLAGS_TYPE exec_flags, int wcontext)
+	F_CMD_ARGS, func_flags_t exec_flags, int wcontext)
 {
 	const exec_context_t *exc2;
 	exec_context_changes_t ecc;

 	ecc.w.wcontext = wcontext;
 	exc2 = exc_clone_context(exc, &ecc, ECC_WCONTEXT);
-	execute_function(cond_rc, exc2, action, exec_flags);
+	execute_function(F_PASS_ARGS_WITH_EXC(exc2), exec_flags);
 	exc_destroy_context(exc2);

 	return;
 }

 void execute_function_override_window(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	FUNC_FLAGS_TYPE exec_flags, FvwmWindow *fw)
+	F_CMD_ARGS, func_flags_t exec_flags, FvwmWindow *fw)
 {
 	const exec_context_t *exc2;
 	exec_context_changes_t ecc;
@@ -1335,13 +1109,13 @@ void execute_function_override_window(
 		exc2 = exc_create_context(
 			&ecc, ECC_TYPE | ECC_FW | ECC_W | ECC_WCONTEXT);
 	}
-	execute_function(cond_rc, exc2, action, exec_flags);
+	execute_function(F_PASS_ARGS_WITH_EXC(exc2), exec_flags);
 	exc_destroy_context(exc2);

 	return;
 }

-void find_func_t(char *action, short *func_t, unsigned char *flags)
+void find_func_t(char *action, short *ret_func_c, func_flags_t *flags)
 {
 	int j, len = 0;
 	char *endtok = action;
@@ -1365,9 +1139,9 @@ void find_func_t(char *action, short *func_t, unsigned char *flags)
 			{
 				matched=True;
 				/* found key word */
-				if (func_t)
+				if (ret_func_c)
 				{
-					*func_t = func_table[j].func_t;
+					*ret_func_c = func_table[j].func_c;
 				}
 				if (flags)
 				{
@@ -1382,9 +1156,9 @@ void find_func_t(char *action, short *func_t, unsigned char *flags)
 		}
 		/* No clue what the function is. Just return "BEEP" */
 	}
-	if (func_t)
+	if (ret_func_c)
 	{
-		*func_t = F_BEEP;
+		*ret_func_c = F_BEEP;
 	}
 	if (flags)
 	{
diff --git a/fvwm/functions.h b/fvwm/functions.h
index b127626f..b87256a8 100644
--- a/fvwm/functions.h
+++ b/fvwm/functions.h
@@ -6,6 +6,8 @@
 /* ---------------------------- included header files ---------------------- */

 #include "execcontext.h"
+#include "functable.h"
+#include "functable_complex.h"

 /* ---------------------------- global definitions ------------------------- */

@@ -17,10 +19,12 @@ typedef enum
 	FUNC_ADD_TO              = 0x04,
 	FUNC_DECOR               = 0x08,
 	FUNC_ALLOW_UNMANAGED     = 0x10,
+	/* only used in __execute_command_line */
+	FUNC_IS_MOVE_TYPE        = 0x20,
 	/* only to be passed to execute_function() */
-	FUNC_IS_UNMANAGED        = 0x20,
-	FUNC_DONT_EXPAND_COMMAND = 0x40,
-	FUNC_DONT_DEFER          = 0x80,
+	FUNC_IS_UNMANAGED        = 0x40,
+	FUNC_DONT_EXPAND_COMMAND = 0x80,
+	FUNC_DONT_DEFER          = 0x100,

 	/* The values are not used internally but by external scripts parsing
 	 * functable.  Hence all the values below are 0
@@ -51,36 +55,17 @@ typedef enum

 /* ---------------------------- type definitions --------------------------- */

-/* used for parsing commands*/
-typedef struct
-{
-	char *keyword;
-#ifdef __STDC__
-	void (*action)(F_CMD_ARGS);
-#else
-	void (*action)();
-#endif
-	short func_t;
-	FUNC_FLAGS_TYPE flags;
-	int cursor;
-} func_t;
-
 /* ---------------------------- exported variables (globals) --------------- */

 /* ---------------------------- interface functions ------------------------ */

-void find_func_t(
-	char *action, short *func_t, FUNC_FLAGS_TYPE *flags);
-Bool functions_is_complex_function(
-	const char *function_name);
-void execute_function(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	FUNC_FLAGS_TYPE exec_flags);
+/* needs to be called before any command line can be executed */
+void functions_init(void);
+void find_func_t(char *action, short *func_t, func_flags_t *flags);
+void execute_function(F_CMD_ARGS, func_flags_t exec_flags);
 void execute_function_override_wcontext(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	FUNC_FLAGS_TYPE exec_flags, int wcontext);
+	F_CMD_ARGS, func_flags_t exec_flags, int wcontext);
 void execute_function_override_window(
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action,
-	FUNC_FLAGS_TYPE exec_flags, FvwmWindow *fw);
+	F_CMD_ARGS, func_flags_t exec_flags, FvwmWindow *fw);

 #endif /* FVWM_FUNCTIONS_H */
diff --git a/fvwm/fvwm.h b/fvwm/fvwm.h
index bdc04ee8..4013f1db 100644
--- a/fvwm/fvwm.h
+++ b/fvwm/fvwm.h
@@ -41,6 +41,7 @@
 #include "libs/FScreen.h"
 #include "window_flags.h"
 #include "condrc.h"
+#include "cmdparser.h"

 /* ---------------------------- global definitions ------------------------- */

@@ -59,9 +60,9 @@

 /* Macro for args passed to fvwm commands... */
 #define F_CMD_ARGS \
-	cond_rc_t *cond_rc, const exec_context_t *exc, char *action
-#define F_PASS_ARGS cond_rc, exc, action
-#define FUNC_FLAGS_TYPE unsigned char
+	cond_rc_t *cond_rc, const exec_context_t *exc, char *action, cmdparser_context_t *pc
+#define F_PASS_ARGS cond_rc, exc, action, pc
+#define F_PASS_ARGS_WITH_EXC(new_exc) cond_rc, (new_exc), action, pc

 /* access macros */
 #define FW_W_FRAME(fw)        ((fw)->wins.frame)
@@ -426,48 +427,6 @@ struct name_condition		/* matches to namelists in this list are
 	struct name_condition *next;
 };

-/* Window mask for Circulate and Direction functions */
-typedef struct WindowConditionMask
-{
-	struct
-	{
-		unsigned do_accept_focus : 1;
-		unsigned do_check_desk : 1;
-		unsigned do_check_screen : 1;
-		unsigned do_check_cond_desk : 1;
-		unsigned do_check_desk_and_global_page : 1;
-		unsigned do_check_desk_and_page : 1;
-		unsigned do_check_global_page : 1;
-		unsigned do_check_overlapped : 1;
-		unsigned do_check_page : 1;
-		unsigned do_not_check_screen : 1;
-		unsigned needs_current_desk : 1;
-		unsigned needs_current_desk_and_global_page : 1;
-		unsigned needs_current_desk_and_page : 1;
-		unsigned needs_current_global_page : 1;
-		unsigned needs_current_page : 1;
-#define NEEDS_ANY   0
-#define NEEDS_TRUE  1
-#define NEEDS_FALSE 2
-		unsigned needs_focus : 2;
-		unsigned needs_overlapped : 2;
-		unsigned needs_pointer : 2;
-		unsigned needs_same_layer : 1;
-		unsigned use_circulate_hit : 1;
-		unsigned use_circulate_hit_icon : 1;
-		unsigned use_circulate_hit_shaded : 1;
-		unsigned use_do_accept_focus : 1;
-	} my_flags;
-	window_flags flags;
-	window_flags flag_mask;
-	struct name_condition *name_condition;
-	int layer;
-	int desk;
-	struct monitor *screen;
-	int placed_by_button_mask;
-	int placed_by_button_set_mask;
-} WindowConditionMask;
-
 typedef struct pl_penalty_struct
 {
 	float normal;
diff --git a/fvwm/fvwm3.c b/fvwm/fvwm3.c
index d4aa8838..8ac80a06 100644
--- a/fvwm/fvwm3.c
+++ b/fvwm/fvwm3.c
@@ -555,7 +555,7 @@ void Done(int restart, char *command)
 		ecc.type = restart ? EXCT_TORESTART : EXCT_QUIT;
 		ecc.w.wcontext = C_ROOT;
 		exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
-		execute_function(NULL, exc, action, 0);
+		execute_function(NULL, exc, action, NULL, 0);
 		exc_destroy_context(exc);
 		free(action);
 	}
@@ -1402,7 +1402,7 @@ static void SetRCDefaults(void)
 		exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
 		xasprintf(&cmd, "%s%s%s", defaults[i][0], defaults[i][1],
 			defaults[i][2]);
-		execute_function(NULL, exc, cmd, 0);
+		execute_function(NULL, exc, cmd, NULL, 0);
 		free(cmd);
 		exc_destroy_context(exc);
 	}
@@ -1526,7 +1526,7 @@ void StartupStuff(void)
 	{
 		char *action = "Function " start_func_name;

-		execute_function(NULL, exc, action, 0);
+		execute_function(NULL, exc, action, NULL, 0);
 	}

 	/* migo (03-Jul-1999): execute [Session]{Init|Restart}Function */
@@ -1536,7 +1536,7 @@ void StartupStuff(void)
 		char *action;

 		xasprintf(&action, "Function %s", init_func_name);
-		execute_function(NULL, exc, action, 0);
+		execute_function(NULL, exc, action, NULL, 0);
 		free(action);
 	}
 	/* see comment above */
@@ -1739,6 +1739,7 @@ int main(int argc, char **argv)
 	exec_context_changes_t ecc;
 	struct monitor	*m = NULL;

+	functions_init();
 	fvwmlib_init_max_fd();
 	/* Tell the FEvent module an event type that is not used by fvwm. */
 	fev_init_invalid_event_type(KeymapNotify);
@@ -2457,7 +2458,8 @@ int main(int argc, char **argv)
 		for (i = 0; i < num_config_commands; i++)
 		{
 			DoingCommandLine = True;
-			execute_function(NULL, exc, config_commands[i], 0);
+			execute_function(
+				NULL, exc, config_commands[i], NULL, 0);
 			free(config_commands[i]);
 		}
 		DoingCommandLine = False;
@@ -2489,7 +2491,7 @@ int main(int argc, char **argv)
 		xasprintf(&cfg_loc[++nl], "%s/default-config/config", FVWM_DATADIR);

 		for (nl = 0; nl < upper; nl++) {
-			if (!run_command_file(cfg_loc[nl], exc)) {
+			if (!run_command_file(cfg_loc[nl], exc, NULL)) {
 				fvwm_debug(__func__,
 				    "couldn't find/load [%d]: %s\n", nl, cfg_loc[nl]);
 				tries++;
diff --git a/fvwm/menucmd.c b/fvwm/menucmd.c
index fb7ea219..e4dfd6f9 100644
--- a/fvwm/menucmd.c
+++ b/fvwm/menucmd.c
@@ -27,6 +27,7 @@
 #include "libs/Strings.h"
 #include "fvwm.h"
 #include "functions.h"
+#include "cmdparser.h"
 #include "repeat.h"
 #include "misc.h"
 #include "move_resize.h"
@@ -113,7 +114,7 @@ static void menu_func(F_CMD_ARGS, Bool fStaysUp)
 	do_menu(&mp, &mret);
 	if (mret.rc == MENU_DOUBLE_CLICKED && action)
 	{
-		execute_function(cond_rc, exc2, action, 0);
+		execute_function(cond_rc, exc2, action, NULL, 0);
 	}
 	if (ret_action != NULL)
 	{
diff --git a/fvwm/menus.c b/fvwm/menus.c
index 520befa0..bd7d6542 100644
--- a/fvwm/menus.c
+++ b/fvwm/menus.c
@@ -37,6 +37,7 @@
 #include "libs/wcontext.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "execcontext.h"
 #include "events.h"
 #include "eventhandler.h"
@@ -242,7 +243,7 @@ static void __menu_execute_function(const exec_context_t **pexc, char *action)
 	exc = exc_clone_context(*pexc, &ecc, ECC_W);
 	old_emf = Scr.flags.is_executing_menu_function;
 	Scr.flags.is_executing_menu_function = 1;
-	execute_function(NULL, exc, action, FUNC_DONT_EXPAND_COMMAND);
+	execute_function(NULL, exc, action, NULL, FUNC_DONT_EXPAND_COMMAND);
 	Scr.flags.is_executing_menu_function = old_emf;
 	exc_destroy_context(exc);
 	/* See if the window has been deleted */
@@ -5610,6 +5611,7 @@ static void menu_tear_off(MenuRoot *mr_to_copy)
 	char *action;
 	cond_rc_t *cond_rc = NULL;
 	const exec_context_t *exc = NULL;
+	cmdparser_context_t *pc = NULL;

 	/* keep the menu open */
 	if (MR_WINDOW(mr_to_copy) != None)
diff --git a/fvwm/misc.c b/fvwm/misc.c
index bd8e483a..a44eedeb 100644
--- a/fvwm/misc.c
+++ b/fvwm/misc.c
@@ -24,6 +24,7 @@
 #include "libs/ftime.h"
 #include "libs/Parse.h"
 #include "libs/Target.h"
+#include "libs/fvwmrect.h"
 #include "libs/FEvent.h"
 #include "fvwm.h"
 #include "externs.h"
diff --git a/fvwm/module_interface.c b/fvwm/module_interface.c
index fdcb493c..c140c59a 100644
--- a/fvwm/module_interface.c
+++ b/fvwm/module_interface.c
@@ -33,6 +33,7 @@
 #include "libs/FEvent.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "functions.h"
 #include "bindings.h"
 #include "misc.h"
@@ -727,7 +728,7 @@ void module_input_execute(struct fmodule_input *input)
 	exc = exc_create_context(
 		&ecc, ECC_TYPE | ECC_ETRIGGER | ECC_FW | ECC_W | ECC_WCONTEXT |
 		ECC_MODULE);
-	execute_function(NULL, exc, input->command, flags);
+	execute_function(NULL, exc, input->command, NULL, flags);
 	exc_destroy_context(exc);
 	module_input_discard(input);

diff --git a/fvwm/move_resize.c b/fvwm/move_resize.c
index 7091a984..c10d7d35 100644
--- a/fvwm/move_resize.c
+++ b/fvwm/move_resize.c
@@ -33,6 +33,7 @@
 #include "libs/FEvent.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "cursor.h"
 #include "execcontext.h"
 #include "commands.h"
@@ -2193,7 +2194,8 @@ static void __move_window(F_CMD_ARGS, Bool do_animate, int mode)
 		if (fWarp & !do_animate)
 		{
 			char *cmd = "WarpToWindow 50 50";
-			execute_function_override_window(NULL, exc, cmd, 0, fw);
+			execute_function_override_window(
+				NULL, exc, cmd, NULL, 0, fw);
 		}
 		if (IS_MAXIMIZED(fw))
 		{
@@ -3397,7 +3399,7 @@ void CMD_HideGeometryWindow(F_CMD_ARGS)
 	    "Converting to use: GeometryWindow hide %s", action);

 	xasprintf(&cmd, "GeometryWindow hide %s", action);
-	execute_function_override_window(NULL, NULL, cmd, 0, NULL);
+	execute_function_override_window(NULL, NULL, cmd, NULL, 0, NULL);
 	free(cmd);
 }

@@ -3415,7 +3417,7 @@ void CMD_SnapAttraction(F_CMD_ARGS)
 		   "The command SnapAttraction is obsolete. Please use the"
 		   " following command instead:\n\n%s", cmd);
 	execute_function(
-		cond_rc, exc, cmd,
+		cond_rc, exc, cmd, pc,
 		FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
 	free(cmd);

@@ -3436,7 +3438,7 @@ void CMD_SnapGrid(F_CMD_ARGS)
 		   "The command SnapGrid is obsolete. Please use the following"
 		   " command instead:\n\n%s", cmd);
 	execute_function(
-		cond_rc, exc, cmd,
+		cond_rc, exc, cmd, pc,
 		FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
 	free(cmd);

@@ -4997,7 +4999,7 @@ static void grow_to_closest_type(
 }

 static void unmaximize_fvwm_window(
-	FvwmWindow *fw)
+	FvwmWindow *fw, cmdparser_context_t *pc)
 {
 	char	*cmd;
 	rectangle new_g;
@@ -5016,8 +5018,9 @@ static void unmaximize_fvwm_window(
 	 * If the window was not maximized, then we use the window's normal
 	 * geometry.
 	 */
-	get_relative_geometry(fw, &new_g, fw->fullscreen.was_maximized ?
-			&fw->fullscreen.g.max : &fw->g.normal);
+	get_relative_geometry(
+		fw, &new_g, fw->fullscreen.was_maximized ?
+		&fw->fullscreen.g.max : &fw->g.normal);

 	if (fw->fullscreen.was_maximized)
 	{
@@ -5049,7 +5052,7 @@ static void unmaximize_fvwm_window(
 		fw, new_g.x, new_g.y, new_g.width, new_g.height, True);

 	xasprintf(&cmd, "MoveToScreen %s", fw->m->si->name);
-	execute_function_override_window(NULL, NULL, cmd, 0, fw);
+	execute_function_override_window(NULL, NULL, cmd, NULL, 0, fw);
 	free(cmd);

 	border_draw_decorations(
@@ -5058,14 +5061,14 @@ static void unmaximize_fvwm_window(
 	if (fw->fullscreen.is_shaded)
 	{
 		execute_function_override_window(
-			NULL, NULL, "WindowShade on", 0, fw);
+			NULL, NULL, "WindowShade on", NULL, 0, fw);

 		fw->fullscreen.is_shaded = 0;
 	}

 	if (fw->fullscreen.is_iconified) {
 		execute_function_override_window(
-			NULL, NULL, "Iconify on", 0, fw);
+			NULL, NULL, "Iconify on", NULL, 0, fw);
 		fw->fullscreen.is_iconified = 0;
 	}

@@ -5216,7 +5219,7 @@ void CMD_Maximize(F_CMD_ARGS)
 		}

 		if (toggle == 0 && IS_EWMH_FULLSCREEN(fw)) {
-			unmaximize_fvwm_window(fw);
+			unmaximize_fvwm_window(fw, pc);
 			return;
 		}
 		return;
@@ -5368,11 +5371,11 @@ void CMD_Maximize(F_CMD_ARGS)
 	if (do_forget == True)
 	{
 		fw->g.normal = fw->g.max;
-		unmaximize_fvwm_window(fw);
+		unmaximize_fvwm_window(fw, pc);
 	}
 	else if (IS_MAXIMIZED(fw) && !do_force_maximize)
 	{
-		unmaximize_fvwm_window(fw);
+		unmaximize_fvwm_window(fw, pc);
 	}
 	else /* maximize */
 	{
diff --git a/fvwm/placement.c b/fvwm/placement.c
index ee404906..a6cce055 100644
--- a/fvwm/placement.c
+++ b/fvwm/placement.c
@@ -367,14 +367,15 @@ adjust_for_shared_placement(FvwmWindow *fw, const exec_context_t *exc)

 		xasprintf(&cmd, "GotoDesk %s 0 %d", m_style->si->name,
 				fw->Desk);
-		execute_function_override_window(NULL, NULL, cmd, 0, fw);
+		execute_function_override_window(NULL, NULL, cmd, NULL, 0, fw);
 		free(cmd);
 	}
 done:
 	TAILQ_FOREACH(m, &monitor_q, entry) {
 		if (m->virtual_scr.CurrentDesk == fw->Desk) {
 			xasprintf(&cmd, "MoveToScreen %s", m->si->name);
-			execute_function_override_window(NULL, exc, cmd, 0, fw);
+			execute_function_override_window(
+				NULL, exc, cmd, NULL, 0, fw);
 			free(cmd);

 			break;
diff --git a/fvwm/read.c b/fvwm/read.c
index d71a2efb..dc4d6e4b 100644
--- a/fvwm/read.c
+++ b/fvwm/read.c
@@ -28,6 +28,7 @@
 #include "libs/Strings.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "cursor.h"
 #include "functions.h"
 #include "events.h"
@@ -112,7 +113,8 @@ const char *get_current_read_dir(void)
  * Read and execute each line from stream.
  */
 void run_command_stream(
-	cond_rc_t *cond_rc, FILE *f, const exec_context_t *exc)
+	cond_rc_t *cond_rc, FILE *f, const exec_context_t *exc,
+	cmdparser_context_t *pc)
 {
 	char *tline;
 	char line[1024];
@@ -143,7 +145,7 @@ void run_command_stream(
 		{
 			tline[l - 1] = '\0';
 		}
-		execute_function(cond_rc, exc, tline, 0);
+		execute_function(cond_rc, exc, tline, pc, 0);
 		tline = fgets(line, (sizeof line) - 1, f);
 	}

@@ -192,7 +194,7 @@ static int parse_filename(
  * Returns 0 if file not found
  **/
 int run_command_file(
-	char *filename, const exec_context_t *exc)
+	char *filename, const exec_context_t *exc, cmdparser_context_t *pc)
 {
 	char *full_filename;
 	FILE *f = NULL;
@@ -251,7 +253,7 @@ int run_command_file(
 		fclose(f);
 		return 0;
 	}
-	run_command_stream(NULL, f, exc);
+	run_command_stream(NULL, f, exc, pc);
 	fclose(f);
 	pop_read_file();

@@ -317,7 +319,7 @@ void CMD_Read(F_CMD_ARGS)
 		return;
 	}
 	cursor_control(True);
-	if (!run_command_file(filename, exc))
+	if (!run_command_file(filename, exc, pc))
 	{
 		if (!read_quietly)
 		{
@@ -384,7 +386,7 @@ void CMD_PipeRead(F_CMD_ARGS)
 	}
 	free(command);

-	run_command_stream(cond_rc,f, exc);
+	run_command_stream(cond_rc, f, exc, pc);
 	pclose(f);
 	cursor_control(False);

diff --git a/fvwm/read.h b/fvwm/read.h
index 0b7d2618..d42f9ca6 100644
--- a/fvwm/read.h
+++ b/fvwm/read.h
@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include "condrc.h"
 #include "execcontext.h"
+#include "cmdparser.h"

 /**
  * Full pathname of file read in progress, or NULL.
@@ -30,6 +31,7 @@ void run_command_stream(
  * fvwm_userdir (set in main()) or in FVWM_DATADIR.  Return 1
  * if the file was found and executed.
  **/
-int run_command_file(char *filename, const exec_context_t *exc);
+int run_command_file(
+	char *filename, const exec_context_t *exc, cmdparser_context_t *pc);

 #endif
diff --git a/fvwm/repeat.c b/fvwm/repeat.c
index 92b02b64..3c3b24a4 100644
--- a/fvwm/repeat.c
+++ b/fvwm/repeat.c
@@ -21,6 +21,7 @@
 #include "libs/fvwmlib.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "cursor.h"
 #include "functions.h"
 #include "repeat.h"
@@ -85,6 +86,9 @@ FvwmWindow *repeat_last_fvwm_window = NULL;
  * from within this function have depth 2 and higher, this may be applicable
  * to future enhancements like menus).
  *
+ * Returns True if the caller needs to free the string himself and False if
+ * the repeat module will take care of freeing the string.
+ *
  * TODO: [finish and update description]
  */
 Bool set_repeat_data(void *data, repeat_t type, const func_t *builtin)
@@ -157,7 +161,7 @@ void CMD_Repeat(F_CMD_ARGS)
 	default:
 		action = last.command_line;
 		execute_function(
-			cond_rc, exc, action, FUNC_DONT_EXPAND_COMMAND);
+			cond_rc, exc, action, pc, FUNC_DONT_EXPAND_COMMAND);
 		break;
 	}
 	repeat_depth--;
diff --git a/fvwm/schedule.c b/fvwm/schedule.c
index b1f13223..33bfaf1e 100644
--- a/fvwm/schedule.c
+++ b/fvwm/schedule.c
@@ -25,6 +25,7 @@
 #include "libs/FEvent.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "colorset.h"
 #include "bindings.h"
 #include "misc.h"
@@ -189,7 +190,7 @@ static void execute_obj_func(void *object, void *args)
 			mask |= ECC_FW;
 		}
 		exc = exc_create_context(&ecc, mask);
-		execute_function(NULL, exc, obj->command, 0);
+		execute_function(NULL, exc, obj->command, NULL, 0);
 		exc_destroy_context(exc);
 	}
 	if (obj->period > 0)
diff --git a/fvwm/update.c b/fvwm/update.c
index c3399de2..8cc8ed75 100644
--- a/fvwm/update.c
+++ b/fvwm/update.c
@@ -147,17 +147,18 @@ static void apply_window_updates(
 			/* stick and unstick the window to force the icon on
 			 * the current page */
 			handle_stick(
-				NULL, exc, "",
+				NULL, exc, "", NULL,
 				S_IS_STICKY_ACROSS_PAGES(SCF(*pstyle)),
 				S_IS_STICKY_ACROSS_DESKS(SCF(*pstyle)), 1, 1);
-			handle_stick(NULL, exc, "", 0, 0, 1, 0);
+			handle_stick(NULL, exc, "", NULL, 0, 0, 1, 0);
 		}
 		flags->do_update_icon_title = True;
 	}
 	else if (flags->do_update_stick)
 	{
 		handle_stick(
-			NULL, exc, "", S_IS_STICKY_ACROSS_PAGES(SCF(*pstyle)),
+			NULL, exc, "", NULL,
+			S_IS_STICKY_ACROSS_PAGES(SCF(*pstyle)),
 			S_IS_STICKY_ACROSS_DESKS(SCF(*pstyle)), 0, 0);
 	}
 	exc_destroy_context(exc);
diff --git a/fvwm/virtual.c b/fvwm/virtual.c
index cfe1ec17..27f728cb 100644
--- a/fvwm/virtual.c
+++ b/fvwm/virtual.c
@@ -28,6 +28,7 @@
 #include "libs/FScreen.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "execcontext.h"
 #include "expand.h"
 #include "cursor.h"
@@ -64,7 +65,8 @@
 	do {								    \
 		char	*cmd;						    \
 		xasprintf(&cmd, "GotoDesk %s 0 %d", (m)->si->name, (d));    \
-		execute_function_override_window(NULL, NULL, cmd, 0, NULL); \
+		execute_function_override_window(			    \
+			NULL, NULL, cmd, NULL, 0, NULL);		    \
 		free(cmd);						    \
 	} while (0)

@@ -74,7 +76,8 @@
 		xasprintf(&cmd, "All (!Screen %s, Desk %d, !CirculateHit) " \
 		    "MoveToPage %s $[w.pagex] $[w.pagey]",		    \
 		    (m)->si->name, (d), (m)->si->name);			    \
-		execute_function_override_window(NULL, NULL, cmd, 0, NULL); \
+		execute_function_override_window(			    \
+			NULL, NULL, cmd, NULL, 0, NULL);		    \
 		free(cmd);                                                  \
 	} while (0)

@@ -628,8 +631,8 @@ static void MapDesk(struct monitor *m, int desk, Bool grab)
 					/* execute_function_override_window()
 					 * will expand cmd's variables.
 					 */
-					execute_function_override_window(NULL,
-					    NULL, cmd, 0, t);
+					execute_function_override_window(
+						NULL, NULL, cmd, NULL, 0, t);
 					free(cmd);

 					/* No need to map the window as it's
@@ -2204,13 +2207,13 @@ void CMD_EdgeResistance(F_CMD_ARGS)
 			   " instead:\n%s\n%s\n%s\n", cmd, stylecmd,
 			   stylecmd2);
 		execute_function(
-			cond_rc, exc, cmd,
+			cond_rc, exc, cmd, pc,
 			FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
 		execute_function(
-			cond_rc, exc, stylecmd,
+			cond_rc, exc, stylecmd, pc,
 			FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
 		execute_function(
-			cond_rc, exc, stylecmd2,
+			cond_rc, exc, stylecmd2, pc,
 			FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
 	}
 	else
@@ -2249,7 +2252,8 @@ void CMD_DesktopConfiguration(F_CMD_ARGS)
 				m->virtual_scr.Vx / monitor_get_all_widths(),
 				m->virtual_scr.Vy / monitor_get_all_heights());

-			execute_function_override_window(NULL, NULL, cmd, 0, NULL);
+			execute_function_override_window(
+				NULL, NULL, cmd, NULL, 0, NULL);
 			free(cmd);
 		}
 		monitor_mode = MONITOR_TRACKING_G;
@@ -2660,8 +2664,8 @@ void CMD_MoveToDesk(F_CMD_ARGS)
 				xasprintf(&cmd,
 				    "MoveToPage %s $[w.pagex] $[w.pagey]",
 				    m->si->name);
-				execute_function_override_window(NULL, NULL,
-				    cmd, 0, fw);
+				execute_function_override_window(
+					NULL, NULL, cmd, NULL, 0, fw);
 				free(cmd);

 				return;
diff --git a/fvwm/windowlist.c b/fvwm/windowlist.c
index f77cf675..d4be0dba 100644
--- a/fvwm/windowlist.c
+++ b/fvwm/windowlist.c
@@ -30,6 +30,7 @@
 #include "libs/Strings.h"
 #include "fvwm.h"
 #include "externs.h"
+#include "cmdparser.h"
 #include "functions.h"
 #include "misc.h"
 #include "screen.h"
@@ -1085,7 +1086,7 @@ void CMD_WindowList(F_CMD_ARGS)
 	if (mret.rc == MENU_DOUBLE_CLICKED &&
 	    default_action && *default_action)
 	{
-		execute_function(cond_rc, exc2, default_action, 0);
+		execute_function(cond_rc, exc2, default_action, pc, 0);
 	}
 	if (default_action != NULL)
 	{
--
2.30.2

From 97cb16222d94a3352fbb3dec69b8003abc1992f7 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Sat, 20 Nov 2021 15:10:36 +0100
Subject: [PATCH 8/9] Remove Repeat command prefix.

---
 doc/fvwm3_manpage_source.adoc |   9 --
 fvwm/Makefile.am              |   4 +-
 fvwm/commands.h               |   1 -
 fvwm/functable.c              |  23 ++---
 fvwm/functable.h              |   1 -
 fvwm/functions.c              |  15 +--
 fvwm/functions.h              |   2 +-
 fvwm/menucmd.c                |   6 +-
 fvwm/move_resize.c            |   8 +-
 fvwm/repeat.c                 | 170 ----------------------------------
 fvwm/repeat.h                 |  37 --------
 fvwm/virtual.c                |   9 +-
 12 files changed, 19 insertions(+), 266 deletions(-)
 delete mode 100644 fvwm/repeat.c
 delete mode 100644 fvwm/repeat.h

diff --git a/doc/fvwm3_manpage_source.adoc b/doc/fvwm3_manpage_source.adoc
index 42187d14..6578cb2b 100644
--- a/doc/fvwm3_manpage_source.adoc
+++ b/doc/fvwm3_manpage_source.adoc
@@ -3655,15 +3655,6 @@ _infostore_ which prints information on all entries in the infostore,
 listing the key and its value. _verbose_ has no effect with this
 option.

-*Repeat*::
-	When the *Repeat* command is invoked, the last command that was
-	executed by fvwm is executed again. This happens regardless of whether
-	it was triggered by user interaction, a module or by an X event.
-	Commands that are executed from a function defined with the *Function*
-	command, from the *Read* or *PipeRead* commands or by a menu are not
-	repeated. Instead, the function, menu or the *Read* or *PipeRead*
-	command is executed again.
-
 *Schedule* [Periodic] _delay_ms_ [_command_id_] _command_::
 	The _command_ is executed after about _delay_ms_ milliseconds. This
 	may be useful in some tricky setups. The _command_ is executed in the
diff --git a/fvwm/Makefile.am b/fvwm/Makefile.am
index 9ae456f9..bb04b6d2 100644
--- a/fvwm/Makefile.am
+++ b/fvwm/Makefile.am
@@ -16,7 +16,7 @@ fvwm3_SOURCES = \
 	icccm2.h icons.h menubindings.h menudim.h menugeometry.h \
 	menuitem.h menuroot.h menuparameters.h menus.h menustyle.h misc.h \
 	modconf.h module_interface.h module_list.h move_resize.h \
-	placement.h read.h repeat.h execcontext.h schedule.h screen.h \
+	placement.h read.h execcontext.h schedule.h screen.h \
 	session.h stack.h style.h update.h virtual.h window_flags.h frame.h \
 	infostore.h \
 	cmdparser.h cmdparser_hooks.h cmdparser_old.h functable_complex.h \
@@ -28,7 +28,7 @@ fvwm3_SOURCES = \
 	windowlist.c functable.c menuitem.c expand.c module_interface.c \
 	menubindings.c decorations.c ewmh_icons.c update.c bindings.c misc.c \
 	cursor.c colormaps.c modconf.c  ewmh_conf.c read.c schedule.c \
-	menucmd.c ewmh_names.c icccm2.c windowshade.c focus_policy.c repeat.c \
+	menucmd.c ewmh_names.c icccm2.c windowshade.c focus_policy.c \
 	execcontext.c menugeometry.c menudim.c condrc.c infostore.c \
 	cmdparser_old.c functable_complex.c

diff --git a/fvwm/commands.h b/fvwm/commands.h
index 4663111a..9f9739f9 100644
--- a/fvwm/commands.h
+++ b/fvwm/commands.h
@@ -112,7 +112,6 @@ enum
 	F_RECAPTURE,
 	F_RECAPTURE_WINDOW,
 	F_REFRESH,
-	F_REPEAT,
 	F_RESTART,
 	F_SAVE_SESSION,
 	F_SAVE_QUIT_SESSION,
diff --git a/fvwm/functable.c b/fvwm/functable.c
index f003184b..0d328a06 100644
--- a/fvwm/functable.c
+++ b/fvwm/functable.c
@@ -405,7 +405,7 @@ const func_t func_table[] =
 	CMD_ENT("none", CMD_None, F_NONE, 0, 0),
 	/* - Perform command if no window matches conditions */

-	CMD_ENT("nop", CMD_Nop, F_NOP, FUNC_DONT_REPEAT, 0),
+	CMD_ENT("nop", CMD_Nop, F_NOP, 0, 0),
 	/* - Do nothing (used internally) */

 	CMD_ENT("nowindow", CMD_NoWindow, F_NOP, 0, 0),
@@ -475,9 +475,6 @@ const func_t func_table[] =
 		FUNC_NEEDS_WINDOW, CRS_SELECT),
 	/* - Cause one window to redraw itself */

-	CMD_ENT(PRE_REPEAT, CMD_Repeat, F_REPEAT, FUNC_DONT_REPEAT, 0),
-	/* - Repeat (very unreliably) the last command, don't use */
-
 	CMD_ENT("resize", CMD_Resize, F_RESIZE,
 		FUNC_NEEDS_WINDOW | FUNC_IS_MOVE_TYPE, CRS_RESIZE),
 	/* - Cause a window to be resized */
@@ -518,31 +515,27 @@ const func_t func_table[] =
 	CMD_ENT("scroll", CMD_Scroll, F_SCROLL, 0, 0),
 	/* - Scroll the desktop viewport */

-	CMD_ENT("send_configinfo", CMD_Send_ConfigInfo, F_CONFIG_LIST,
-		FUNC_DONT_REPEAT, 0),
+	CMD_ENT("send_configinfo", CMD_Send_ConfigInfo, F_CONFIG_LIST, 0, 0),
 	/* - Internal, used for module communication */

-	CMD_ENT("send_reply", CMD_Send_Reply, F_SEND_REPLY,
-		FUNC_DONT_REPEAT, 0),
+	CMD_ENT("send_reply", CMD_Send_Reply, F_SEND_REPLY, 0, 0),
 	/* - Internal, used for module communication */

 	CMD_ENT("send_windowlist", CMD_Send_WindowList, F_SEND_WINDOW_LIST,
-		FUNC_DONT_REPEAT, 0),
+		0, 0),
 	/* - Internal, used for module communication */

-	CMD_ENT("sendtomodule", CMD_SendToModule, F_SEND_STRING,
-		FUNC_DONT_REPEAT, 0),
+	CMD_ENT("sendtomodule", CMD_SendToModule, F_SEND_STRING, 0, 0),
 	/* - Send a string (action) to a module */

-	CMD_ENT("set_mask", CMD_set_mask, F_SET_MASK, FUNC_DONT_REPEAT, 0),
+	CMD_ENT("set_mask", CMD_set_mask, F_SET_MASK, 0, 0),
 	/* - Internal, used for module communication */

 	CMD_ENT("set_nograb_mask", CMD_set_nograb_mask, F_SET_NOGRAB_MASK,
-		FUNC_DONT_REPEAT, 0),
+		0, 0),
 	/* - Internal, used for module communication */

-	CMD_ENT("set_sync_mask", CMD_set_sync_mask, F_SET_SYNC_MASK,
-		FUNC_DONT_REPEAT, 0),
+	CMD_ENT("set_sync_mask", CMD_set_sync_mask, F_SET_SYNC_MASK, 0, 0),
 	/* - Internal, used for module communication */

 	CMD_ENT("setanimation", CMD_SetAnimation, F_SET_ANIMATION, 0, 0),
diff --git a/fvwm/functable.h b/fvwm/functable.h
index c5bf6b9b..e0e21da6 100644
--- a/fvwm/functable.h
+++ b/fvwm/functable.h
@@ -8,7 +8,6 @@
 /* ---------------------------- global definitions ------------------------- */

 #define PRE_KEEPRC "keeprc"
-#define PRE_REPEAT "repeat"
 #define PRE_SILENT "silent"

 /* ---------------------------- global macros ------------------------------ */
diff --git a/fvwm/functions.c b/fvwm/functions.c
index 060eaff3..6c4ae468 100644
--- a/fvwm/functions.c
+++ b/fvwm/functions.c
@@ -51,7 +51,6 @@
 #include "module_list.h"
 #include "misc.h"
 #include "screen.h"
-#include "repeat.h"
 #include "expand.h"
 #include "menus.h"

@@ -427,22 +426,10 @@ cmdparser_hooks->debug(&pc, "!!!E");

 	if (!(exec_flags & FUNC_DONT_EXPAND_COMMAND))
 	{
+cmdparser_hooks->debug(&pc, "!!!F");
 		cmdparser_hooks->expand_command_line(
 			&pc, (bif) ? !!(bif->flags & FUNC_ADD_TO) : False,
 			func_rc, exc);
-cmdparser_hooks->debug(&pc, "!!!F");
-		if (pc.call_depth <= 1)
-		{
-			Bool do_free_string_ourselves;
-
-			do_free_string_ourselves = set_repeat_data(
-				pc.expline, REPEAT_COMMAND, bif);
-			if (do_free_string_ourselves == False)
-			{
-				cmdparser_hooks->release_expanded_line(&pc);
-cmdparser_hooks->debug(&pc, "!!!F");
-			}
-		}
 	}
 #if 1 /*!!!*/
 fprintf(stderr, "!!!pc.cline: '%s'\n", pc.cline);
diff --git a/fvwm/functions.h b/fvwm/functions.h
index b87256a8..9a7c7796 100644
--- a/fvwm/functions.h
+++ b/fvwm/functions.h
@@ -15,7 +15,7 @@
 typedef enum
 {
 	FUNC_NEEDS_WINDOW        = 0x01,
-	FUNC_DONT_REPEAT         = 0x02,
+	/*free                   = 0x02,*/
 	FUNC_ADD_TO              = 0x04,
 	FUNC_DECOR               = 0x08,
 	FUNC_ALLOW_UNMANAGED     = 0x10,
diff --git a/fvwm/menucmd.c b/fvwm/menucmd.c
index e4dfd6f9..f6300cc9 100644
--- a/fvwm/menucmd.c
+++ b/fvwm/menucmd.c
@@ -28,7 +28,6 @@
 #include "fvwm.h"
 #include "functions.h"
 #include "cmdparser.h"
-#include "repeat.h"
 #include "misc.h"
 #include "move_resize.h"
 #include "screen.h"
@@ -91,11 +90,10 @@ static void menu_func(F_CMD_ARGS, Bool fStaysUp)
 		}
 		return;
 	}
-	if (menu_name &&
-	    set_repeat_data(
-		    menu_name, (fStaysUp) ? REPEAT_MENU : REPEAT_POPUP,NULL))
+	if (menu_name)
 	{
 		free(menu_name);
+		menu_name = NULL;
 	}

 	memset(&mp, 0, sizeof(mp));
diff --git a/fvwm/move_resize.c b/fvwm/move_resize.c
index c10d7d35..ab3af0f5 100644
--- a/fvwm/move_resize.c
+++ b/fvwm/move_resize.c
@@ -3416,9 +3416,7 @@ void CMD_SnapAttraction(F_CMD_ARGS)
 	fvwm_debug(__func__,
 		   "The command SnapAttraction is obsolete. Please use the"
 		   " following command instead:\n\n%s", cmd);
-	execute_function(
-		cond_rc, exc, cmd, pc,
-		FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
+	execute_function(cond_rc, exc, cmd, pc, FUNC_DONT_EXPAND_COMMAND);
 	free(cmd);

 	return;
@@ -3437,9 +3435,7 @@ void CMD_SnapGrid(F_CMD_ARGS)
 	fvwm_debug(__func__,
 		   "The command SnapGrid is obsolete. Please use the following"
 		   " command instead:\n\n%s", cmd);
-	execute_function(
-		cond_rc, exc, cmd, pc,
-		FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
+	execute_function(cond_rc, exc, cmd, pc, FUNC_DONT_EXPAND_COMMAND);
 	free(cmd);

 	return;
diff --git a/fvwm/repeat.c b/fvwm/repeat.c
deleted file mode 100644
index 3c3b24a4..00000000
--- a/fvwm/repeat.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* -*-c-*- */
-/* Copyright (C) 1999  Dominik Vogt */
-/* This program 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 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 this program; if not, see: <http://www.gnu.org/licenses/>
- */
-
-#include "config.h"
-
-#include <stdio.h>
-
-#include "libs/fvwmlib.h"
-#include "fvwm.h"
-#include "externs.h"
-#include "cmdparser.h"
-#include "cursor.h"
-#include "functions.h"
-#include "repeat.h"
-#include "libs/Parse.h"
-
-
-/* If non-zero we are already repeating a function, so don't record the
- * command again. */
-static int repeat_depth = 0;
-
-#if 0
-typedef struct
-{
-	char *start;
-	char *end;
-} double_ended_string;
-
-static struct
-{
-	double_ended_string string;
-	double_ended_string old;
-	double_ended_string builtin;
-	double_ended_string function;
-	double_ended_string top_function;
-	double_ended_string module;
-	double_ended_string menu;
-	double_ended_string popup;
-	double_ended_string menu_or_popup;
-	int page_x;
-	int page_y;
-	int desk;
-	FvwmWindow *fvwm_window;
-} last;
-#endif
-
-static struct
-{
-	char *command_line;
-	char *menu_name;
-} last = {
-	NULL,
-	NULL
-};
-
-#if 0
-char *repeat_last_function = NULL;
-char *repeat_last_complex_function = NULL;
-char *repeat_last_builtin_function = NULL;
-char *repeat_last_module = NULL;
-char *repeat_last_top_function = NULL;
-char *repeat_last_menu = NULL;
-FvwmWindow *repeat_last_fvwm_window = NULL;
-#endif
-
-/* Stores the contents of the data pointer internally for the repeat command.
- * The type of data is determined by the 'type' parameter. If this function is
- * called to set a string value representing an fvwm builtin function the
- * 'builtin' can be set to the F_... value in the function table in
- * functions.c. If this value is set certain functions are not recorded.
- * The 'depth' parameter indicates the recursion depth of the current data
- * pointer (i.e. the first function call has a depth of one, functions called
- * from within this function have depth 2 and higher, this may be applicable
- * to future enhancements like menus).
- *
- * Returns True if the caller needs to free the string himself and False if
- * the repeat module will take care of freeing the string.
- *
- * TODO: [finish and update description]
- */
-Bool set_repeat_data(void *data, repeat_t type, const func_t *builtin)
-{
-	/* No history recording during startup. */
-	if (fFvwmInStartup)
-	{
-		return True;
-	}
-
-	switch(type)
-	{
-	case REPEAT_COMMAND:
-		if (last.command_line == (char *)data)
-		{
-			/* Already stored, no need to free the data pointer. */
-			return False;
-		}
-		if (data == NULL || repeat_depth != 0)
-		{
-			/* Ignoring the data, must free it outside of this
-			 * call. */
-			return True;
-		}
-		if (builtin && (builtin->flags & FUNC_DONT_REPEAT))
-		{
-			/* Dont' record functions that have the
-			 * FUNC_DONT_REPEAT flag set. */
-			return True;
-		}
-		/* Store a backup. */
-		free(last.command_line);
-		last.command_line = (char *)data;
-		/* Since we stored the pointer the caller must not free it. */
-		return False;
-	case REPEAT_MENU:
-	case REPEAT_POPUP:
-		if (last.menu_name != (char*)data)
-		{
-			free(last.menu_name);
-		}
-		last.menu_name = (char *)data;
-		return False;
-	case REPEAT_PAGE:
-	case REPEAT_DESK:
-	case REPEAT_DESK_AND_PAGE:
-		return True;
-	case REPEAT_FVWM_WINDOW:
-		return True;
-	case REPEAT_NONE:
-	default:
-		return True;
-	}
-}
-
-void CMD_Repeat(F_CMD_ARGS)
-{
-	int index;
-	char *optlist[] = {
-		"command",
-		NULL
-	};
-
-	repeat_depth++;
-	/* Replay the backup, we don't want the repeat command recorded. */
-	GetNextTokenIndex(action, optlist, 0, &index);
-	switch (index)
-	{
-	case 0: /* command */
-	default:
-		action = last.command_line;
-		execute_function(
-			cond_rc, exc, action, pc, FUNC_DONT_EXPAND_COMMAND);
-		break;
-	}
-	repeat_depth--;
-
-	return;
-}
diff --git a/fvwm/repeat.h b/fvwm/repeat.h
deleted file mode 100644
index a8138b8b..00000000
--- a/fvwm/repeat.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*-c-*- */
-
-#ifndef FVWM_REPEAT_H
-#define FVWM_REPEAT_H
-#include "functions.h"
-
-typedef enum
-{
-	REPEAT_NONE = 0,
-	REPEAT_COMMAND,
-	/* I think we don't need all these
-	   REPEAT_BUILTIN,
-	   REPEAT_FUNCTION,
-	   REPEAT_TOP_FUNCTION,
-	   REPEAT_MODULE,
-	*/
-	REPEAT_MENU,
-	REPEAT_POPUP,
-	REPEAT_PAGE,
-	REPEAT_DESK,
-	REPEAT_DESK_AND_PAGE,
-	REPEAT_FVWM_WINDOW
-} repeat_t;
-
-extern char *repeat_last_function;
-extern char *repeat_last_complex_function;
-extern char *repeat_last_builtin_function;
-extern char *repeat_last_module;
-/*
-  extern char *repeat_last_top_function;
-  extern char *repeat_last_menu;
-  extern FvwmWindow *repeat_last_fvwm_window;
-*/
-
-Bool set_repeat_data(void *data, repeat_t type, const func_t *builtin);
-
-#endif /* FVWM_REPEAT_H */
diff --git a/fvwm/virtual.c b/fvwm/virtual.c
index 27f728cb..94ad4418 100644
--- a/fvwm/virtual.c
+++ b/fvwm/virtual.c
@@ -2207,14 +2207,11 @@ void CMD_EdgeResistance(F_CMD_ARGS)
 			   " instead:\n%s\n%s\n%s\n", cmd, stylecmd,
 			   stylecmd2);
 		execute_function(
-			cond_rc, exc, cmd, pc,
-			FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
+			cond_rc, exc, cmd, pc, FUNC_DONT_EXPAND_COMMAND);
 		execute_function(
-			cond_rc, exc, stylecmd, pc,
-			FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
+			cond_rc, exc, stylecmd, pc, FUNC_DONT_EXPAND_COMMAND);
 		execute_function(
-			cond_rc, exc, stylecmd2, pc,
-			FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
+			cond_rc, exc, stylecmd2, pc, FUNC_DONT_EXPAND_COMMAND);
 	}
 	else
 	{
--
2.30.2

From af9bac8eed6ddf7920cff4017a84927c3e6f3a40 Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Wed, 17 Nov 2021 19:53:39 +0100
Subject: [PATCH 9/9] !!!debug fprintfs

---
 fvwm/cmdparser_old.c          | 55 ++++++++++++++++++--
 fvwm/functions.c              | 95 +++++++++++++++++++++++++++++++++--
 fvwm/modconf.c                | 17 ++++++-
 libs/defaults.h               |  4 ++
 modules/FvwmButtons/dynamic.c | 23 +++++++++
 5 files changed, 184 insertions(+), 10 deletions(-)

diff --git a/fvwm/cmdparser_old.c b/fvwm/cmdparser_old.c
index 21c2074e..b53ac5d6 100644
--- a/fvwm/cmdparser_old.c
+++ b/fvwm/cmdparser_old.c
@@ -37,7 +37,7 @@

 /* ---------------------------- local definitions -------------------------- */

-#if 0 /*!!!*/
+#if 1 /*!!!*/
 #define OCP_DEBUG 1
 #else
 #define OCP_DEBUG 0
@@ -275,12 +275,28 @@ static const char *ocp_parse_command_name(
 	cmdparser_context_t *c, void *func_rc, const void *exc)
 {
 	GetNextToken(c->cline, &c->command);
+	if (OCP_DEBUG)
+	{
+		fprintf(
+			stderr, "%s: c->command '%s'\n", __func__,
+			(c->command) ? c->command : "(nil)");
+	}
 	if (c->command != NULL)
 	{
 		char *tmp = c->command;

+		if (OCP_DEBUG)
+		{
+			fprintf(stderr, "%s: expand c->command\n", __func__);
+		}
 		c->command = expand_vars(
 			c->command, c, False, False, func_rc, exc);
+		if (OCP_DEBUG)
+		{
+			fprintf(
+				stderr, "%s: c->command '%s'\n", __func__,
+				(c->command) ? c->command : "(nil)");
+		}
 		free(tmp);
 	}
 	if (c->command && !ocp_is_module_config(c))
@@ -293,11 +309,23 @@ static const char *ocp_parse_command_name(
 		 * fail */
 		char *tmp = c->command;

+		if (OCP_DEBUG)
+		{
+			fprintf(
+				stderr, "%s: remove trailing spaces\n",
+				__func__);
+		}
 		while (*tmp && !isspace(*tmp))
 		{
 			tmp++;
 		}
 		*tmp = 0;
+		if (OCP_DEBUG)
+		{
+			fprintf(
+				stderr, "%s: c->command '%s'\n", __func__,
+				(c->command) ? c->command : "(nil)");
+		}
 #endif
 		return c->command;
 	}
@@ -331,6 +359,12 @@ static cmdparser_execute_type_t ocp_find_something_to_execute(
 {
 	int is_function_builtin;

+	if (OCP_DEBUG)
+	{
+		fprintf(
+			stderr, "%s: c->command '%s'\n", __func__,
+			(c->command) ? c->command : "(nil)");
+	}
 	*ret_complex_function = NULL;
 	/* Note: the module config command, "*" can not be handled by the
 	 * regular command table because there is no required white space after
@@ -366,9 +400,10 @@ static cmdparser_execute_type_t ocp_find_something_to_execute(
 			return CP_EXECTYPE_BUILTIN_FUNCTION;
 		}
 	}
-#if 1 /*!!!*/
-	assert(*ret_builtin == NULL);
-#endif
+	if (OCP_DEBUG)
+	{
+		assert(*ret_builtin == NULL);
+	}
 	do
 	{
 		char *complex_function_name;
@@ -381,8 +416,20 @@ static cmdparser_execute_type_t ocp_find_something_to_execute(
 		{
 			break;
 		}
+		if (OCP_DEBUG)
+		{
+			fprintf(
+				stderr, "%s: lookup cf '%s'\n", __func__,
+				complex_function_name);
+		}
 		*ret_complex_function =
 			find_complex_function(complex_function_name);
+		if (OCP_DEBUG)
+		{
+			fprintf(
+				stderr, "%s: lookup cf '%s' -> %p\n", __func__,
+				complex_function_name, *ret_complex_function);
+		}
 		if (*ret_complex_function != NULL)
 		{
 			c->cline = rest_of_line;
diff --git a/fvwm/functions.c b/fvwm/functions.c
index 6c4ae468..694a8c17 100644
--- a/fvwm/functions.c
+++ b/fvwm/functions.c
@@ -124,21 +124,36 @@ static Bool DeferExecution(
 	original_w = w;
 	wcontext = ret_ecc->w.wcontext;
 	FinishEvent = ((fw != NULL) ? ButtonRelease : ButtonPress);
+#if 1 /*!!!*/
+	fprintf(stderr, "!!!%s: A wc 0x%x\n", __func__, wcontext);
+#endif
 	if (wcontext == C_UNMANAGED && do_allow_unmanaged)
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Bf\n", __func__);
+#endif
 		return False;
 	}
 	if (wcontext != C_ROOT && wcontext != C_NO_CONTEXT && fw != NULL &&
 	    wcontext != C_EWMH_DESKTOP)
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: C\n", __func__);
+#endif
 		if (FinishEvent == ButtonPress ||
 		    (FinishEvent == ButtonRelease &&
 		     trigger_evtype != ButtonPress))
 		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Df\n", __func__);
+#endif
 			return False;
 		}
 		else if (FinishEvent == ButtonRelease)
 		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: E\n", __func__);
+#endif
 			/* We are only waiting until the user releases the
 			 * button. Do not change the cursor. */
 			cursor = CRS_NONE;
@@ -147,16 +162,25 @@ static Bool DeferExecution(
 	}
 	if (Scr.flags.are_functions_silent)
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Ft\n", __func__);
+#endif
 		return True;
 	}
 	if (!GrabEm(cursor, GRAB_NORMAL))
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Gt\n", __func__);
+#endif
 		XBell(dpy, 0);
 		return True;
 	}
 	MyXGrabKeyboard(dpy);
 	while (!finished)
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: H\n", __func__);
+#endif
 		done = 0;
 		/* block until there is an event */
 		FMaskEvent(
@@ -167,9 +191,15 @@ static Bool DeferExecution(

 		if (e.type == KeyPress)
 		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: I\n", __func__);
+#endif
 			KeySym keysym = XLookupKeysym(&e.xkey, 0);
 			if (keysym == XK_Escape)
 			{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Jt\n", __func__);
+#endif
 				ret_ecc->x.etrigger = &e;
 				*ret_mask |= ECC_ETRIGGER;
 				UngrabEm(GRAB_NORMAL);
@@ -180,33 +210,57 @@ static Bool DeferExecution(
 		}
 		if (e.type == FinishEvent)
 		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: K\n", __func__);
+#endif
 			finished = 1;
 		}
 		switch (e.type)
 		{
 		case KeyPress:
 		case ButtonPress:
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: L\n", __func__);
+#endif
 			if (e.type != FinishEvent)
 			{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: M\n", __func__);
+#endif
 				original_w = e.xany.window;
 			}
 			done = 1;
 			break;
 		case ButtonRelease:
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: N\n", __func__);
+#endif
 			done = 1;
 			break;
 		default:
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: O\n", __func__);
+#endif
 			break;
 		}
 		if (!done)
 		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: P\n", __func__);
+#endif
 			dispatch_event(&e);
 		}
 	}
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Q\n", __func__);
+#endif
 	MyXUngrabKeyboard(dpy);
 	UngrabEm(GRAB_NORMAL);
 	if (just_waiting_for_finish)
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Rf\n", __func__);
+#endif
 		return False;
 	}
 	w = e.xany.window;
@@ -215,11 +269,17 @@ static Bool DeferExecution(
 	if ((w == Scr.Root || w == Scr.NoFocusWin) &&
 	    e.xbutton.subwindow != None)
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: S\n", __func__);
+#endif
 		w = e.xbutton.subwindow;
 		e.xany.window = w;
 	}
 	if (w == Scr.Root || IS_EWMH_DESKTOP(w))
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Tt\n", __func__);
+#endif
 		ret_ecc->w.w = w;
 		ret_ecc->w.wcontext = C_ROOT;
 		XBell(dpy, 0);
@@ -228,6 +288,9 @@ static Bool DeferExecution(
 	*ret_mask |= ECC_FW;
 	if (XFindContext(dpy, w, FvwmContext, (caddr_t *)&fw) == XCNOENT)
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Ut\n", __func__);
+#endif
 		ret_ecc->w.fw = NULL;
 		ret_ecc->w.w = w;
 		ret_ecc->w.wcontext = C_ROOT;
@@ -236,10 +299,16 @@ static Bool DeferExecution(
 	}
 	if (w == FW_W_PARENT(fw))
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: V\n", __func__);
+#endif
 		w = FW_W(fw);
 	}
 	if (original_w == FW_W_PARENT(fw))
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: W\n", __func__);
+#endif
 		original_w = FW_W(fw);
 	}
 	/* this ugly mess attempts to ensure that the release and press
@@ -248,8 +317,14 @@ static Bool DeferExecution(
 	    original_w != None && original_w != Scr.NoFocusWin &&
 	    !IS_EWMH_DESKTOP(original_w))
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: X\n", __func__);
+#endif
 		if (w != FW_W_FRAME(fw) || original_w != FW_W(fw))
 		{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Yt\n", __func__);
+#endif
 			ret_ecc->w.fw = fw;
 			ret_ecc->w.w = w;
 			ret_ecc->w.wcontext = C_ROOT;
@@ -260,12 +335,18 @@ static Bool DeferExecution(

 	if (IS_EWMH_DESKTOP(FW_W(fw)))
 	{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: Zt\n", __func__);
+#endif
 		ret_ecc->w.fw = fw;
 		ret_ecc->w.w = w;
 		ret_ecc->w.wcontext = C_ROOT;
 		XBell(dpy, 0);
 		return True;
 	}
+#if 1 /*!!!*/
+fprintf(stderr, "!!!%s: @f\n", __func__);
+#endif
 	wcontext = GetContext(NULL, fw, &e, &dummy);
 	ret_ecc->w.fw = fw;
 	ret_ecc->w.w = w;
@@ -296,9 +377,6 @@ static void __execute_command_line(
 	Window dummy_w;
 	int rc;

-#if 1 /*!!!*/
-	fprintf(stderr, "%s: cpc %p, xaction '%s'\n", __func__, caller_pc, xaction);
-#endif
 	set_silent = 0;
 	/* generate a parsing context; this *must* be destroyed before
 	 * returning */
@@ -358,10 +436,12 @@ cmdparser_hooks->debug(&pc, "!!!C");
 	{
 		if (exec_flags & FUNC_IS_UNMANAGED)
 		{
+fprintf(stderr, "!!!AAA unmanaged\n");
 			w = exc->w.w;
 		}
 		else
 		{
+fprintf(stderr, "!!!BBB root\n");
 			w = Scr.Root;
 		}
 	}
@@ -406,11 +486,12 @@ cmdparser_hooks->debug(&pc, "!!!C");
 		{
 cmdparser_hooks->debug(&pc, "!!!D");
 			bif = find_builtin_function(func);
+fprintf(stderr, "!!! --> find bif '%s' -> %p\n", func, bif);
 			err_func = func;
 		}
 		else
 		{
-cmdparser_hooks->debug(&pc, "!!!E");
+cmdparser_hooks->debug(&pc, "!!!E no command name");
 			bif = NULL;
 			err_func = "";
 		}
@@ -453,6 +534,7 @@ cmdparser_hooks->debug(&pc, "!!!J");
 #endif
 #if 1 /*!!!*/
 fprintf(stderr, "!!!pc.cline: '%s'\n", pc.cline);
+fprintf(stderr, "!!!bif: '%s' 0x%x\n", bif->keyword, bif->flags);
 #endif
 		mask = (w != exc->w.w) ? ECC_W : 0;
 		ecc.w.fw = exc->w.fw;
@@ -469,6 +551,9 @@ fprintf(stderr, "!!!pc.cline: '%s'\n", pc.cline);
 				(bif->flags & FUNC_ALLOW_UNMANAGED));
 			if (rc == True)
 			{
+#if 1 /*!!!*/
+fprintf(stderr, "!!!not deferred: %d\n", rc);
+#endif
 				break;
 			}
 #if 1 /*!!!*/
@@ -499,7 +584,7 @@ fprintf(stderr, "!!!erase PressedW\n");
 			PressedW = None;
 		}
 #if 1 /*!!!*/
-fprintf(stderr, "!!!execute '%s'\n", bif->keyword);
+fprintf(stderr, "!!!execute '%s' (fw %p)\n", bif->keyword, exc2->w.fw);
 #endif
 		bif->action(func_rc, exc2, pc.cline, &pc);
 		PressedW = dummy_w;
diff --git a/fvwm/modconf.c b/fvwm/modconf.c
index 8726df83..ab17b9d8 100644
--- a/fvwm/modconf.c
+++ b/fvwm/modconf.c
@@ -90,6 +90,9 @@ void ModuleConfig(char *action)
 	fmodule *module;
 	struct moduleInfoList *new_entry;

+#if 1 /*!!!*/
+fprintf(stderr, "%s: action '%s'\n", __func__, (action) ? action : "(nil)");
+#endif
 	end = strlen(action) - 1;
 	if (action[end] == '\n')
 		action[end] = '\0';
@@ -143,8 +146,16 @@ static struct moduleInfoList *AddToModList(char *tline)
 	{
 		/* migo (01-Sep-2000): construct an old-style config line */
 		char *conf_start = alias_end + 1;
+#if 1 /*!!!*/
+fprintf(stderr, "%s: conf_start '%s'\n", __func__, conf_start);
+#endif
 		while (isspace(*conf_start)) conf_start++;
 		*alias_end = '\0';
+#if 1 /*!!!*/
+fprintf(stderr, "%s: alias '%s'\n", __func__, tline ? tline : "(nil)");
+fprintf(stderr, "%s: conf_start '%s'\n", __func__, conf_start);
+#endif
+
 		xasprintf(&rline, "%s%s", tline, conf_start);
 		*alias_end = MODULE_CONFIG_DELIM;
 		this->alias_len = alias_end - tline;
@@ -152,9 +163,13 @@ static struct moduleInfoList *AddToModList(char *tline)

 	exc = exc_create_null_context();
 	this->data = expand_vars(rline, NULL, False, True, NULL, exc);
+#if 1 /*!!!*/
+fprintf(stderr, "%s: mldata '%s', mlaliaslen %d\n", __func__, this->data, this->alias_len);
+#endif
 	exc_destroy_context(exc);
 	/* Free rline only if it is xasprintf'd memory (not pointing at tline
-	 * anymore). If we free our tline argument it causes a crash in __execute_function. */
+	 * anymore). If we free our tline argument it causes a crash in
+	 * __execute_function. */
 	if (rline != tline)
 		free(rline);

diff --git a/libs/defaults.h b/libs/defaults.h
index 643b1f24..2dcb0fc6 100644
--- a/libs/defaults.h
+++ b/libs/defaults.h
@@ -362,7 +362,11 @@
 #define DEF_FP_SORT_WINDOWLIST_BY               0

 /* Function execution */
+#if 0 /*!!!*/
 #define MAX_FUNCTION_DEPTH    512
+#else
+#define MAX_FUNCTION_DEPTH    20
+#endif

 /* Tips */
 #define FTIPS_DEFAULT_PLACEMENT FTIPS_PLACEMENT_AUTO_UPDOWN
diff --git a/modules/FvwmButtons/dynamic.c b/modules/FvwmButtons/dynamic.c
index 2739e291..e6d53c8b 100644
--- a/modules/FvwmButtons/dynamic.c
+++ b/modules/FvwmButtons/dynamic.c
@@ -242,6 +242,9 @@ void parse_message_line(char *line)
 		return;
 	}

+#if 1 /*!!!*/
+fprintf(stderr, "action: '%d'\n", action);
+#endif
 	switch (action)
 	{
 	case 1:
@@ -259,18 +262,32 @@ void parse_message_line(char *line)
 			char *value0, *value;
 			FvwmPicture *icon;

+#if 1 /*!!!*/
+fprintf(stderr, "loop: rest: '%s'\n", rest);
+#endif
 			/* parse option and value and give diagnostics */
 			rest = GetQuotedString(
 				rest, &option_pair, ",", NULL, NULL, NULL);
+#if 1 /*!!!*/
+fprintf(stderr, "l2  : rest: '%s'\n", rest);
+fprintf(stderr, "l2  : opt : '%s'\n", option_pair);
+#endif
 			while (isspace(*rest))
 			{
 				rest++;
 			}
+#if 1 /*!!!*/
+fprintf(stderr, "l3  : rest: '%s'\n", rest);
+#endif
 			if (!option_pair)
 				continue;

 			option = GetTokenIndex(
 				option_pair, button_options, -1, &value0);
+#if 1 /*!!!*/
+fprintf(stderr, "4   : opt : '%d'\n", option);
+fprintf(stderr, "4   : v0  : '%s'\n", value0);
+#endif
 			if (option < 0)
 			{
 				show_error(
@@ -281,6 +298,9 @@ void parse_message_line(char *line)
 			}

 			GetNextToken(value0, &value);
+#if 1 /*!!!*/
+fprintf(stderr, "5   : tok : '%s'\n", value);
+#endif
 			free(option_pair);

 			if (value == NULL)
@@ -306,6 +326,9 @@ void parse_message_line(char *line)
 				b->flags.b_ActiveTitle = 1;
 				b->title = value;
 				value = NULL;
+#if 1 /*!!!*/
+fprintf(stderr, "6   : copy: '%s'\n", b->title);
+#endif
 				break;
 			case 4:
 				/* PressTitle */
--
2.30.2

Reply via email to