/******************************************************************************

    MODUL
	command.c

    DESCRIPTION
	)c		  single character (typing)
	'c                single character (typing)
	`string'          string of characters w/ embedded `' allowed!
	(string)             same thing w/ embedded () allowed!
	\c		  override

	name arg arg	  command name. The arguments are interpreted as
			  strings for the command.

	$scanf		  macro insert scanf'd variable
	$filename	  macro insert current file name with the complete path
	$file		  macro insert current name filename
	$path		  macro insert complete path of current file
	$currentdir	  macro insert the base dir of XDME
	$currentline	  macro insert entire contents of current line
	$colno		  macro insert column number of cursor
	$lineno 	  macro insert line number of cursor
	$margin 	  macro insert current margin setting
	$modified	  macro insert 0/1 modified flag
	$rexxport	  macro insert rexx port name

	Any string arguments not part of a command are considered to be typed
	text.

    NOTES

    BUGS

    TODO

    EXAMPLES

    SEE ALSO

    INDEX

    HISTORY
	06. Dec 1992	ada created

******************************************************************************/

/**************************************
		Includes
**************************************/
#include "defs.h"


/**************************************
	    Globale Variable
**************************************/
Prototype int	 do_command   (char *);
Prototype void	 do_null      (void);
Prototype void	 do_source    (long);
Prototype void	 do_quit      (void);
Prototype void	 do_quitall   (void);
Prototype void	 do_execute   (void);
Prototype char * breakout     (char **, char *, char **);

extern int foundcmd;	   /* control for implicit ARexx macro invocation   */
extern int cmderr;	   /* global command error flag for do_rexx()'s use */


/**************************************
      Interne Defines & Strukturen
**************************************/
#define CF_COK	1   /*	Can be executed while in command line mode	*/
#define CF_PAR	2   /*	ESCIMM special flag.. save rest of command line */
		    /*	so it can be executed after user entry		*/
#define CF_ICO	4   /*	OK to execute if iconified, else uniconify first*/
#define CF_VWM	8   /*	OK to execute if in viewmode, else abort	*/

#define BTOCP(val, type)    ((type)((long)val << 2))

typedef void (*FPTR)(long);

typedef struct
{
    const char * name;	/* command name 	*/
    UBYTE args; 	/* number of arguments	*/
    UBYTE flags;	/* flags		*/
    FPTR func;		/* c-function		*/
} COMM;

#define MAXIA	    5


/**************************************
	    Interne Variable
**************************************/
	    /*	  args		 flags	  */

static CONST COMM Comm[] =
{
    "abort",         0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_abort,
    "activatefront", 1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_activefront,
    "add",           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "addpath",       1,        CF_VWM|CF_ICO, (FPTR)do_addpath,
    "appendsave",    1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_appendsave,
    "arpfont",       0,               CF_VWM, (FPTR)do_aslfont,
    "arpinsfile",    0,                    0, (FPTR)do_aslinsfile,
    "arpload",       0,               CF_VWM, (FPTR)do_aslload,
    "arpsave",       0,        CF_VWM|CF_ICO, (FPTR)do_aslsave,
    "autoindent",    1,        CF_VWM|CF_ICO, (FPTR)do_autoindent,
    "autosplit",     1,        CF_VWM|CF_ICO, (FPTR)do_autosplit,
    "autounblock",   1,        CF_VWM|CF_ICO, (FPTR)do_autounblock,
    "back",          0,               CF_COK, (FPTR)do_bs,
    "backtab",       0,        CF_VWM|CF_COK, (FPTR)do_backtab,
    "bappendsave",   1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_bappendsave,
    "barpsave",      0,        CF_VWM|CF_ICO, (FPTR)do_barpsave,
    "bbpen",         1,               CF_VWM, (FPTR)do_bbpen,
    "bcopy",         0,                    0, (FPTR)do_bcopy,
    "bdelete",       0,                    0, (FPTR)do_bdelete,
    "bend",          0,               CF_VWM, (FPTR)do_block,    /* checks com name for mode */
    "bgpen",         1,               CF_VWM, (FPTR)do_bgpen,
    "block",         0,               CF_VWM, (FPTR)do_block,    /* checks com name for mode */
    "blocktype",     1,               CF_VWM, (FPTR)do_blocktype,
    "bmove",         0,                    0, (FPTR)do_bmove,
    "bottom",        0,               CF_VWM, (FPTR)do_bottom,
    "break",         0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_break,
    "bs",            0,               CF_COK, (FPTR)do_bs,
    "bsave",         1,        CF_VWM|CF_ICO, (FPTR)do_bsave,
    "bsource",       0,        CF_VWM|CF_ICO, (FPTR)do_bsource,
    "bstart",        0,               CF_VWM, (FPTR)do_block,    /* checks com name for mode */
    "cd",            1,        CF_VWM|CF_ICO, (FPTR)do_cd,
    "chfilename",    1,        CF_VWM|CF_ICO, (FPTR)do_chfilename,
    "clipins",       0,               CF_COK, (FPTR)do_clipins,
    "col",           1,        CF_VWM|CF_COK, (FPTR)do_col,
    "continue",      0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_continue,
    "copy",          0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_copy,
    "ctags",         0,               CF_VWM, (FPTR)do_ctags,
    "debug",         1,        CF_VWM|CF_ICO, (FPTR)do_debug,
    "dec",           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "del",           0,               CF_COK, (FPTR)do_bs,
    "delete",        0,               CF_COK, (FPTR)do_delete,
    "deline",        0,                    0, (FPTR)do_deline,
    "delines",       1,                    0, (FPTR)do_delines,
    "div",           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "down",          0,        CF_VWM|CF_COK, (FPTR)do_down,
    "downadd",       0,                    0, (FPTR)do_downadd,
    "esc",           0,        CF_VWM|CF_COK, (FPTR)do_esc,
    "escimm",        1,        CF_VWM|CF_PAR, (FPTR)do_esc,
    "eval",          1,        CF_VWM|CF_COK, (FPTR)do_eval,
    "execute",       1,        CF_VWM|CF_ICO, (FPTR)do_execute,
    "fgpen",         1,               CF_VWM, (FPTR)do_fgpen,
#ifdef PATCH_FILTER
    "filter",        4, CF_VWM|CF_COK|CF_PAR, (FPTR)do_filter,
#endif
    "find",          1,               CF_VWM, (FPTR)do_find,     /* checks com name for mode */
    "findr",         2,                    0, (FPTR)do_findr,    /* checks com name for mode */
    "findstr",       1,               CF_VWM, (FPTR)do_findstr,  /* checks com name for mode */
    "first",         0,        CF_VWM|CF_COK, (FPTR)do_firstcolumn,
    "firstnb",       0,        CF_VWM|CF_COK, (FPTR)do_firstnb,
    "followcursor",  1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_followcursor,
    "force",         2,        CF_VWM|CF_COK, (FPTR)do_force,
    "global",        1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_global,
    "goto",          1,               CF_VWM, (FPTR)do_goto,
    "hgpen",         1,               CF_VWM, (FPTR)do_hgpen,
    "iconify",       0,        CF_VWM|CF_ICO, (FPTR)do_iconify,
    "if",            2, CF_VWM|CF_COK|CF_ICO, (FPTR)do_if,
    "ifelse",        3, CF_VWM|CF_COK|CF_ICO, (FPTR)do_if,
    "ignorecase",    1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_ignorecase,
    "inc",           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "indent",        2,                    0, (FPTR)do_indent,
    "infixmode",     1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_infixmode,
    "insert",        1,               CF_COK, (FPTR)do_insertwrite,
    "insertmode",    1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_insertmode,
    "insfile",       1,                    0, (FPTR)do_edit,
    "insline",       0,                    0, (FPTR)do_insline,
    "inslines",      1,                    0, (FPTR)do_inslines,
    "join",          0,                    0, (FPTR)do_join,
    "justify",       1,                    0, (FPTR)do_justify,
    "keyload",       1,        CF_VWM|CF_ICO, (FPTR)do_keyload, /* tester */
    "keysave",       1,        CF_VWM|CF_ICO, (FPTR)do_keysave, /* tester */
    "last",          0,        CF_VWM|CF_COK, (FPTR)do_lastcolumn,
    "left",          0,        CF_VWM|CF_COK, (FPTR)do_left,
    "lineblock",     0,        CF_VWM|CF_ICO, (FPTR)do_block,
    "macroload",     1,        CF_VWM|CF_ICO, (FPTR)do_macroload, /* tester */
    "macrosave",     1,        CF_VWM|CF_ICO, (FPTR)do_macrosave, /* tester */
    "makecursorvisible", 0,    CF_VWM|CF_COK, (FPTR)do_makecursorvisible,
    "map",           2,        CF_VWM|CF_ICO, (FPTR)do_map,
    "margin",        1,        CF_VWM|CF_ICO, (FPTR)do_margin,
    "match",         0,        CF_VWM|CF_COK, (FPTR)do_match,
    "math1",         2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unnamedmathfunc,
    "math2",         3, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unnamedmathfunc,
    "menuadd",       3,        CF_VWM|CF_ICO, (FPTR)do_itemadd,
    "menubar",       1,        CF_VWM|CF_ICO, (FPTR)do_itembar,
    "menucheck",     3,        CF_VWM|CF_ICO, (FPTR)do_itemcheck,
    "menuclear",     0,        CF_VWM|CF_ICO, (FPTR)do_menuclear,
    "menudel",       2,        CF_VWM|CF_ICO, (FPTR)do_delitem,
    "menudelbar",    1,        CF_VWM|CF_ICO, (FPTR)do_delitembar,
    "menudelhdr",    1,        CF_VWM|CF_ICO, (FPTR)do_delmenu,
    "menudelsub",    3,        CF_VWM|CF_ICO, (FPTR)do_delsub,
    "menudelsubar",  2,        CF_VWM|CF_ICO, (FPTR)do_delsubbar,
    "menugetcheck",  3,        CF_VWM|CF_ICO, (FPTR)do_getcheckitem,
    "menugetscheck", 4,        CF_VWM|CF_ICO, (FPTR)do_getchecksub,
    "menuload",      1,        CF_VWM|CF_ICO, (FPTR)do_menuload, /* tester */
    "menuoff",       0,        CF_VWM|CF_ICO, (FPTR)do_menuoff,
    "menuon",        0,        CF_VWM|CF_ICO, (FPTR)do_menuon,
    "menusave",      1,        CF_VWM|CF_ICO, (FPTR)do_menusave, /* tester */
    "menusetcheck",  3,        CF_VWM|CF_ICO, (FPTR)do_setcheckitem,
    "menusetscheck", 4,        CF_VWM|CF_ICO, (FPTR)do_setchecksub,
    "menusubadd",    4,        CF_VWM|CF_ICO, (FPTR)do_subadd,
    "menusubbar",    2,        CF_VWM|CF_ICO, (FPTR)do_subbar,
    "menusubcheck",  4,        CF_VWM|CF_ICO, (FPTR)do_subcheck,
    "mod",           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "modified",      1,               CF_ICO, (FPTR)do_modified,
    "mul",           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "neg",           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "newfile",       1,               CF_VWM, (FPTR)do_edit,   /* checks com name for mode */
    "newkeytable",   1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_new_keytable,
    "newmenustrip",  1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_new_menustrip,
    "newwindow",     0,        CF_VWM|CF_ICO, (FPTR)do_newwindow,
    "next",          0,               CF_VWM, (FPTR)do_find,
    "nextr",         0,                    0, (FPTR)do_findr,
    "not",           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "null",          0,        CF_VWM|CF_COK, (FPTR)do_null,
    "openwindow",    1,        CF_VWM|CF_ICO, (FPTR)do_openwindow,
    "overwrite",     1,               CF_COK, (FPTR)do_insertwrite,
    "pagedown",      0,               CF_VWM, (FPTR)do_page,
    "pageleft",      0,               CF_VWM, (FPTR)do_page,
    "pageright",     0,               CF_VWM, (FPTR)do_page,
    "pageset",       1,        CF_VWM|CF_ICO, (FPTR)do_page,
    "pageup",        0,               CF_VWM, (FPTR)do_page,
    "pattern",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_pattern,
    "peek",          1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_pop,
    "pickvar",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_pickVAR,
    "ping",          1,        CF_VWM|CF_ICO, (FPTR)do_ping,
    "pong",          1,               CF_VWM, (FPTR)do_pong,
    "pop",           1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_pop,
    "popvar",        1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_popVAR,
    "port",          2,        CF_VWM|CF_ICO, (FPTR)to_port,          /* HD Rexx */
    "prev",          0,               CF_VWM, (FPTR)do_find,
    "prevr",         0,                    0, (FPTR)do_findr,
    "projectinfo",   0,        CF_VWM|CF_ICO, (FPTR)project_info,     /* HD */
    "projectload",   0,        CF_VWM|CF_ICO, (FPTR)load_project,     /* HD */
    "projectsave",   0,        CF_VWM|CF_ICO, (FPTR)save_project,     /* HD */
    "pubscreen",     1,        CF_VWM|CF_ICO, (FPTR)set_pubscreen,
    "purgevar",      1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_purgeVAR,
    "push",          1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_push,
    "pushvar",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_pushVAR,
    "qualifier",     1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_qualifier,
    "quiet",         1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_quiet,
    "quit",          0,        CF_VWM|CF_ICO, (FPTR)do_quit,
    "quitall",       0,        CF_VWM|CF_ICO, (FPTR)do_quitall,
    "recall",        0,               CF_VWM, (FPTR)do_recall,
    "recend",        0, CF_VWM|CF_ICO|CF_COK, (FPTR)end_recording, /* it is recommended to end a record by pressing Ctl-C */
    "recplay",       0, CF_VWM|CF_ICO|CF_COK, (FPTR)replay_record,
    "recsave",       1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_saverecord,
    "recstart",      0, CF_VWM|CF_ICO|CF_COK, (FPTR)start_recording,
    "redisplay",     0,               CF_VWM, (FPTR)do_redisplay,
    "ref",           0,        CF_VWM|CF_ICO, (FPTR)do_refs,
    "refctags",      0,        CF_VWM|CF_ICO, (FPTR)do_refctags,
    "reformat",      0,                    0, (FPTR)do_reformat,
    "rem",           1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_null,    /* comments in lines */
    "remeol",        0,        CF_VWM|CF_COK, (FPTR)do_remeol,
    "remkeytable",   1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_del_keytable,
 /* "remmenustrip",  1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_del_menustrip, */ /* that function is not stable yet */
    "rempath",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_rempath,
    "repeat",        2, CF_VWM|CF_COK|CF_ICO, (FPTR)do_repeat,
    "replace",       0,                    0, (FPTR)do_replace,
    "repstr",        1,        CF_VWM|CF_ICO, (FPTR)do_findstr,
    "reqfont",       0,               CF_VWM, (FPTR)do_reqfont,
    "reqinsfile",    0,                    0, (FPTR)do_reqinsfile,
    "reqload",       0,               CF_VWM, (FPTR)do_reqload,
    "reqsave",       0,        CF_VWM|CF_ICO, (FPTR)do_reqsave,
    "resettoggle",   1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_toggle,
    "resize",        2,               CF_VWM, (FPTR)do_resize,
    "ret",           0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_retmacro,
    "return",        0,               CF_COK, (FPTR)do_return,   /* special meaning in command line mode */
    "right",         0,        CF_VWM|CF_COK, (FPTR)do_right,
    "rx",            1,        CF_VWM|CF_ICO, (FPTR)do_rx,       /* explicit ARexx macro invocation      */
    "rx1",           2,        CF_VWM|CF_ICO, (FPTR)do_rx1,      /* explicit, with 1 arg  to ARexx macro */
    "rx2",           3,        CF_VWM|CF_ICO, (FPTR)do_rx2,      /* explicit, with 2 args to ARexx macro */
    "rxresult",      1,        CF_VWM|CF_ICO, (FPTR)put_rexx_result,
#ifdef PATCH_RXVARS
    "rxset",         2, CF_VWM|CF_COK|CF_ICO, (FPTR)do_setrexx,      /* explicit, with 1 arg  to ARexx macro */
#endif /* PATCH_RXVARS */
    "saveas",        1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_saveas,
    "saveconfig",    0, CF_VWM|CF_COK|CF_ICO, (FPTR)do_saveconfig,
//  "savemap",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_savemap,         /* checks com name for mode */
    "saveold",       0, CF_VWM|CF_COK|CF_ICO, (FPTR)do_save,
//  "savesmap",      1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_savemap,
    "savetabs",      1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_savetabs,
    "scanf",         1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_scanf,
    "screenbottom",  0,               CF_VWM, (FPTR)do_screenbottom,
    "screentop",     0,               CF_VWM, (FPTR)do_screentop,
    "scrolldown",    0,               CF_VWM, (FPTR)do_scrolldown,
    "scrollleft",    0,               CF_VWM, (FPTR)do_scroll,
    "scrollright",   0,               CF_VWM, (FPTR)do_scroll,
    "scrollup",      0,               CF_VWM, (FPTR)do_scrollup,
    "select",        1,        CF_VWM|CF_ICO, (FPTR)select_window,      /* HD Rexx */
    "set",           2, CF_VWM|CF_COK|CF_ICO, (FPTR)do_set,
    "setenv",        2, CF_VWM|CF_COK|CF_ICO, (FPTR)do_setenv,
    "setfont",       2,               CF_VWM, (FPTR)do_setfont,
    "setgeometry",   4,               CF_VWM, (FPTR)do_setgeometry,
    "setmacro",      3, CF_VWM|CF_ICO|CF_COK, (FPTR)do_setmacro,
    "setmacrovar",   2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_setmacrovar,
    "setparcol",     1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_setparcol,
    "settoggle",     1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_toggle,
    "settvar",       2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_settvar,
    "sizewindow",    1,        CF_VWM|CF_COK, (FPTR)do_sizewindow,
    "showlog",       0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_showlog,
    "smv",           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_setmacrovar,
    "source",        1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_source,
    "sourcebreaks",  1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_sourcebreak,
    "spacing",       1,               CF_VWM, (FPTR)do_setlinedistance,
    "split",         0,                    0, (FPTR)do_split,
    "sub",           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_namedmathfunc,
    "swap",          1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_swap,
    "swapvar",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_swapVAR,
    "tab",           0,        CF_VWM|CF_COK, (FPTR)do_tab,
    "tabstop",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_tabstop,
    "taskpri",       1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_taskpri,
    "title",         1,        CF_VWM|CF_ICO, (FPTR)do_title,
    "tlate",         1,               CF_COK, (FPTR)do_tlate,
    "toback",        0, CF_VWM|CF_COK|CF_ICO, (FPTR)do_toback,
    "tofront",       0, CF_VWM|CF_COK|CF_ICO, (FPTR)do_tofront,
    "toggle",        1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_toggle,
    "tomouse",       0,               CF_VWM, (FPTR)do_tomouse,
    "top",           0,               CF_VWM, (FPTR)do_top,
    "tpen",          1,               CF_VWM, (FPTR)do_tpen,
    "unabort",       0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unabort,
    "unblock",       0,        CF_VWM|CF_ICO, (FPTR)do_block,
    "undeline",      0,                    0, (FPTR)do_undeline,
    "undo",          0,                    0, (FPTR)do_undo,
    "uniconify",     0,        CF_VWM|CF_ICO, (FPTR) uniconify,     /* PATCH_NULL [14 Feb 1993] : added */
    "unjustify",     0,                    0, (FPTR)do_unjustify,
    "unmap",         1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_unmap,
    "unset",         1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_unset,
    "unsetenv",      1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_unsetenv,
    "unsetmacro",    1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unsetmacro,
    "unsetmacrovar", 1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unsetmacrovar,
    "unsettvar",     1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unsettvar,
    "up",            0,        CF_VWM|CF_COK, (FPTR)do_up,
    "usekeytable",   1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_use_keytable,
    "usemenustrip",  1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_use_menustrip,
    "vctags",        1,        CF_VWM|CF_ICO, (FPTR)do_ctags,
    "viewmode",      1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_viewmode,
    "vref",          1,        CF_VWM|CF_ICO, (FPTR)do_refs,
    "vrefctags",     1,        CF_VWM|CF_ICO, (FPTR)do_refctags,
    "while",         2, CF_VWM|CF_COK|CF_ICO, (FPTR)do_if,
    "windowcycling", 1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_windowcyc,
    "wleft",         0,        CF_VWM|CF_COK, (FPTR)do_wleft,
    "wordwrap",      1, CF_VWM|CF_COK|CF_ICO, (FPTR)do_wordwrap,
    "wright",        0,        CF_VWM|CF_COK, (FPTR)do_wright
};

static CONST COMM repcmd =
{
    "repeat",        2, CF_COK|CF_ICO, (FPTR)do_repeat,
};


/**************************************
	   Interne Prototypes
**************************************/


int do_command (char * str)
{
    char     * arg;
    char     * aux1,
	     * aux2,
	     * repstr[MAXIA];
    char       quoted;
    WORD       repi = 0;
    long       j;
    WORD       low;
    WORD       high;
    WORD       diff;
    static int level = 0;
    COMM     * comm;
#define DEBUG_FILE  /* Logging on ? */
#ifdef DEBUG_FILE
    static FILE * debug_file = NULL;

    if (!debug_file && globalflags.debug)
	debug_file = fopen ("t:XDME.debug", "w");
#endif

    if (!str || !*str)
	return (1);

#ifdef DEBUG_FILE
    if (debug_file && globalflags.debug)
	fprintf (debug_file, "%s\n", str);
#endif

/* if (debug) printf("dcom[%2d|%d]: %s\n", level+1, globalflags.Abortcommand, str); */

    if (MacroRecord != 0 && level == 0) {       /* PATCH_NULL [14 Feb 1993] : added */
	add_record (str);                       /* PATCH_NULL [14 Feb 1993] : added */
    } /* if */					/* PATCH_NULL [14 Feb 1993] : added */

    if (++level > 20)
    {
	error ("command:\nRecursion too deep");
	--level;

	foundcmd = 1;	/* to prevent us from trying an ARexx macro */

	return (0);
    }

    while ((arg = breakout (&str, &quoted, &aux1)) &&
	    !(LoopBreak || LoopCont) )                      /* PATCH_BREAK - should be put together */
    {
/* if (globalflags.debug) printf("loop[%2d|%d] CHECK %s\n",level, globalflags.Abortcommand, arg); */
	if (quoted)
	{
/* if (debug) printf("loop[%2d|%d] write %s\n",level, globalflags.Abortcommand, arg); */
	    if (Ep->viewmode && !globalflags.Comlinemode)               /* PATCH_NULL */
	    {
/* if (debug) printf("-- viewmode"); */
		goto fail;				    /* PATCH_NULL */
	    } /* if */					    /* PATCH_NULL */

	    if (Ep->iconmode)
		uniconify ();

	    text_write (arg);
	    goto loop;
	} /* if (quoted) */

	if (isalpha (*arg))
	{
	    low  = 0;
	    high = sizeof(Comm)/sizeof(Comm[0]) - 1;

	    do
	    {
		j = (low + high)/2;

		diff = stricmp (arg, Comm[j].name);

		if (!diff)
		    break;

		if (diff < 0)
		    high = j-1;
		else
		    low = j+1;
	    } while (low <= high);

	    if (!diff)
	    {
/* if (debug) printf("loop[%2d|%d] comm %s\n",level, globalflags.Abortcommand, arg); */

		comm = &Comm[j];

		foundcmd = 1;

		av[0] = (UBYTE *)comm->name;

		for (j=1; j<=comm->args; j++)
		{
		    av[j] = (UBYTE *)breakout (&str, &quoted, &aux2);

		    if (aux2)
		    {
			if (repi == MAXIA)
			{
			    free (aux2);

			    error ("command:\nToo many args for\n%s", av[0]);

/* if (debug) printf("-- varargs Oflow"); */

			    goto fail;
			} else
			{
			    repstr[repi ++] = aux2;
			}
		    }

		    if (!av[j])
		    {
			if (j < 2)
			    error ("command:\nBad argument %ld of\n%s", j, av[0]);
			else
			    error ("command:\nBad argument %ld of\n%s %s", j, av[0], av[1]);

/* if (debug) printf("-- less args"); */
			goto fail;
		    }
		} /* for all args */

		av[j] = NULL;	/* end of arglist */

process:
		if ((comm->flags & CF_COK) || !globalflags.Comlinemode)
		{
		    if (Ep->viewmode && !globalflags.Comlinemode && !(comm->flags & CF_VWM))   /* PATCH_NULL */
		    {
/* if (debug) printf("-- viewmode"); */
			goto fail;				    /* PATCH_NULL */
		    } /* if */					    /* PATCH_NULL */

		    if (comm->flags & CF_PAR)
		    {
			if (Partial)
			    free (Partial);

			Partial = (char *)malloc (strlen (str) + 1);
			strcpy (Partial, str);
			str += strlen(str);     /*  skip string */
		    } /* if CF_PAR */

		    if (Ep->iconmode && !(comm->flags & CF_ICO))
			uniconify ();

/* if (debug) printf ("comm[%2d|%d] %s/%s\n", level, globalflags.Abortcommand, av[0], av[1]); */

		    (*comm->func)(-1);
		} /* if CF_COK or Not Comlinemode */

		if (globalflags.Abortcommand)
		{
/* if (debug) printf("-- aborted"); */
		    goto fail;
		}

		goto loop;
	    } /* if arg == command */
	} else if (isdigit(*arg))
	{
	    av[0] = "repeat";
	    av[1] = arg;
	    av[2] = (UBYTE *)breakout(&str, &quoted, &aux2);

	    if (aux2)
	    {
		repstr[repi ++] = aux2;
	    }

	    if (!av[2])
	    {
		error ("command:\nBad second argument\nfor short-repeat");
/* if (debug) printf("-- repeat"); */
		goto fail;
	    }

	    av[3] = 0;
	    comm = &repcmd;

	    goto process;
	} /* Repeat */

	{
	    /*
	    **	Search for a macro - we had to put that scan
	    **	before the checks for menus and keys, as
	    **	keys are only checked up to 3 chars
	    */

	    void * macro;
	    int    ret;

	    if (macro = (void*)getmacro(arg))
	    {
		int narg = nummacroargs (macro);

		/* av[0] = (CHAR *)((NODE*)macro)->ln_Name; */
/* if (debug) printf("loop[%2d|%d] macro %s\n",level, Abortcommand, arg); */

		av[0] = NULL;

		foundcmd = 1;

		for (j = 1; j <= narg; ++j)
		{
		    av[j] = (UBYTE *)breakout (&str, &quoted, &aux2);

		    if (aux2)
		    {
			if (repi == MAXIA)
			{
			    free(aux2);
			    error ("macro:\nToo many args for\n%s", av[0]);
/* if (debug) printf("-- M:varargs Oflow"); */
			    goto fail;
			} else
			{
			    repstr[repi++] = aux2;
			}
		    }

		    if (!av[j])
		    {
			error ("macro:\nBad argument %ld of\n%s", j, av[0]);
/* if (debug) printf("-- M:less args"); */
			goto fail;
		    }
		}

		av[j] = NULL;	/* end of arglist */

/* if (debug) printf ("mac [%2d|%d] %s/%s\n", level, Abortcommand, arg, av[1]); */
		ret = callmacro(macro);

		if (!ret)
		{
/* if (debug) printf("-- M:abort"); */
		    goto fail;
		} /* if no succ */

		goto loop;
	    } /* if */
	} /* block */

	/* Command not found, check for macro	*/
	{
	    char * cmdstr;
	    int    ret;

	    if ((cmdstr = keyspectomacro(arg)) || (cmdstr = menutomacro(arg)))
	    {
		cmdstr = strdup (cmdstr);

/* if (debug) printf ("loop[%2d|%d] key %s\n", level, Abortcommand, cmdstr); */

		ret = do_command (cmdstr);

		free (cmdstr);

		if (ret)
		{
		    foundcmd = 1;
		    goto loop;
		}

/* if (debug) printf("-- K:abort"); */

		goto fail;
	    } /* if arg is macro or menu */
	}


/*
*!  PATCH_JUX (reine gaudi)
*!
*!    Direct assignments of existing vars
*! With that patch something is possible like:
*!    set abc 1 ... abc = 3 (instead of set abc 3)
*!
*! if arg1 is a "=" we search for a variable of the name in arg0
*! if there is such a variable, we assign its value to the value
*! in arg2  (the correct types are used)
*!
*!  But what shall we do, if there was not such a variable???
*/
	{
	    char * dummy = NULL;
	    int    type  = VAR_NEX;

	    dummy = str;

	    while (*dummy && *dummy <33)
	    {
		dummy ++;
	    } /* while */

	    if (*dummy == '=')
	    {
		dummy ++;

		str = dummy;

		dummy = GetTypedVar (arg, &type);

		if (dummy)
		{
		    free (dummy);

		    dummy = breakout (&str, &quoted, &aux2);

		    if (!dummy)
		    {
			error ("Assignment without value");
			goto fail;
		    } /* if */

		    SetTypedVar (arg, dummy, type);

		    if (aux2)
		    {
			free (aux2);
		    } /* if */

		    goto loop;
		} else
		{ /* there is no variable of the given name  - WAS sollen wir jetzt machen ? einen Default verwenden ??? */

		} /* if */
	    } /* if */
	} /* block direct assignment */

	/* Command still not found, check for public macro  */
	/* code to be added */

	if (do_rxImplied (arg, str))
	    error ("command:\nUnknown command\n`%s'", arg);

/* if (debug) printf("running into fail"); */

fail:
/* if (debug) printf ("fail[%2d|%d]\n", level, Abortcommand); */
	--level;

	while (--repi >= 0)
	    free (repstr[repi]);

	if (aux1) free (aux1);

	return(0);

loop:
	if (aux1) free (aux1);

	// aux1 = NULL;      /* PATCH_BREAK - is not necessary */
    } /* while (arg) */

/* ret_ok: - point is not necessary */
/* if (debug) printf ("ret1[%2d|%d]\n", level, Abortcommand); */

    --level;

    while (--repi >= 0)
	free (repstr[repi]);

    // if (aux1) free (aux1); /* PATCH_BREAK - is not necessary */

    return(1);
} /* do_command */


void do_null (void)
{
} /* do_null */


void do_source (long do_err)
{
    char   buf[MAXLINELEN];
    FILE * fi;
    char * str;
    BPTR   oldlock = CurrentDir(DupLock(Ep->dirlock));

    if (fi = fopen(av[1], "r"))
    {
	while (fgets(buf, MAXLINELEN, fi))
	{
	    if (buf[0] == '#')
		continue;
	    for (str = buf; *str; ++str)
	    {
		if (*str == 9)
		    *str = ' ';
	    }

	    if (str > buf && str[-1] == '\n')
		str[-1] = 0;

	    do_command(buf);

	    if (globalflags.SourceBreaks)                                   /* PATCH_NULL */
	    {
		if (globalflags.Abortcommand || LoopBreak || LoopCont)      /* PATCH_NULL */
		{
		    break;					/* PATCH_NULL */
		} /* if */					/* PATCH_NULL */
	    } else						/* PATCH_NULL */
	    {
		globalflags.Abortcommand = 0;	    /* PATCH_NULL */
		LoopBreak    = 0;		    /* PATCH_NULL */
		LoopCont     = 0;		    /* PATCH_NULL */
	    } /* if */						/* PATCH_NULL */
	}
	fclose(fi);
    } else
    {
	if (do_err)
	{
	    error ("source:\nFile `%s'\nnot found", av[1]);
	}
    }

    UnLock(CurrentDir(oldlock));
} /* do_source */


void do_quit (void)
{
    globalflags.Quitflag = 1;

    ActivateWindow (Ep->win);                    /* HD damit aus AREXX */
} /* do_quit */


void do_quitall (void)
{
    globalflags.Quitflag = 1;
    globalflags.QuitAll = 1;

    ActivateWindow (Ep->win);                    /* HD damit aus AREXX */
} /* do_quitall */


void do_execute (void)
{
    BPTR   oldlock = CurrentDir (Ep->dirlock);
    BPTR   NilFH;
    PROC * proc    = (PROC *)FindTask (NULL);

    NilFH = Open ("NIL:", 1006);

    if (NilFH)
    {
	void *oldConsoleTask = proc->pr_ConsoleTask;

	proc->pr_ConsoleTask = (APTR)BTOCP(NilFH, struct FileHandle *)->fh_Port;

	Execute (av[1], NilFH, NilFH);

	proc->pr_ConsoleTask = oldConsoleTask;

	Close(NilFH);
    } else
    {
	error ("execute:\nNIL:-device required");
    }

    CurrentDir(oldlock);
} /* do_execute */


/*
 *  BREAKOUT()
 *
 *  Break out the next argument.  The argument is space delimited and
 *  might be quoted with `' or (), or single quoted as 'c or )c
 *
 *  Also:	$var	    -variable insertion
 *		^c	    -control character
 */

char * breakout (char ** ptr, char * quoted, char ** paux)
{
    char * str = *ptr;
    char * base;
    WORD   count;	    /* Level of brace */
    char   opc; 	    /* Open-Char */
    char   clc; 	    /* Close-Char */
    char   immode;
    char   isaux;
    char   buf[MAXLINELEN];
    WORD   di, i;

/* if (debug) printf("bout[  |%d] ? %s\n", globalflags.Abortcommand, str); */

    count =
	opc   =
	clc   =
	immode=
	isaux =
	di    = 0;

    *quoted = 0;
    if (paux)
	*paux = NULL;

    while (*str == ' ')
	++str;

    if (!*str)
	return (NULL);

    *ptr = str;
    base = str;

    while (*str)
    {
	if (immode)
	{
	    if (di != sizeof(buf)-1)
		buf[di++] = *str;

	    str ++;
	    continue;
	}

	if (count == 0)
	{
	    if (*str == ' ')
		break;

	    if (*str == '\'' || *str == ')')
		clc = *str;
	    else if (*str == '`')
	    {
		opc = '`';
		clc = '\'';
	    } else if (*str == '(')
	    {
		opc = '(';
		clc = ')';
	    }
	}

	if (*str == opc)
	{
	    count ++;

	    if (str == *ptr)
	    {
		*quoted = 1;
		base = ++ str;
		continue;
	    }
	}

	if (*str == clc)
	{
	    count --;

	    if (count == 0 && *quoted)     /*  end of argument     */
		break;

	    if (str == *ptr && count < 0)
	    {
		immode = 1;
		*quoted = 1;
		base = ++str;

		continue;
	    }
	}

	/*
	 *  $varname $(varname) $`varname'.  I.E. three forms are allowed,
	 *  which allows one to insert the string almost anywhere.  The
	 *  first form names are limited to alpha-numerics, '-', and '_'.
	 */

	if (*str == '$')
	{
	    char * ptr2;
	    char * tmpptr;
	    char   c,
		   ce;
	    WORD   len;

/* if (debug) printf("bout[  |%d] $ %s\n", globalflags.Abortcommand, str); */

	    ce = 0;			    /*	first form  */
	    str ++;			    /*	skip $	    */

	    if (*str == '(')                /*  second form */
	    {
		ce = ')';
		++str;
	    } else if (*str == '`')         /*  third form  */
	    {
		ce = '\'';
		++str;
	    }

	    ptr2 = str; 		    /*	start of varname    */

	    if (ce)                         /*  until end char OR   */
	    {
		while (*ptr2 && *ptr2 != ce)
		    ptr2 ++;
	    } else			    /*	smart end-varname   */
	    {
		while (isalnum(*ptr2) || *ptr2 == '-' || *ptr2 == '_' )
		{
		    ptr2 ++;
		}
	    }

	    len = ptr2 - str;		    /*	length of variable  */
	    c = *ptr2; *ptr2 = 0;	    /*	temp. terminate \0  */

/* if (debug) printf("bout[  |%d] var '%s'\n", globalflags.Abortcommand, str); */

	    if (stricmp(str, "currentdir") == 0)
	    {
		*ptr2  = c;
		isaux = 1;

		if (NameFromLock(Ep->dirlock, tmp_buffer, sizeof(tmp_buffer)))
		{
		    i = strlen(tmp_buffer);

		    if (di + i < sizeof(buf)-1)
		    {
			strcpy (buf + di, tmp_buffer);
			di += i;
		    }
		}

		str += len;

		if (ce)
		    ++str;

		continue;
	    } else if (stricmp(str, "path") == 0)
	    {
		*ptr2 = c;
		isaux = 1;

		if (NameFromLock(Ep->dirlock, tmp_buffer, sizeof(tmp_buffer)))
		{
		    i = strlen (tmp_buffer);

		    if (di + i < sizeof(buf)-1)
		    {
			strcpy (buf+di, tmp_buffer);
			di += i;
		    }
		}

		str += len;
		if (ce)
		    ++str;

		continue;
	    } else if (stricmp(str, "file") == 0)
	    {
		i = strlen(Ep->name);
		*ptr2 = c;
		isaux = 1;
		if (di + i < sizeof(buf)-1)
		{
		    movmem(Ep->name, buf + di, i);
		    di += i;
		    buf[di] = 0;
		}
		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (stricmp(str, "filename") == 0)
	    {
		*ptr2 = c;
		isaux = 1;

		if (NameFromLock(Ep->dirlock, tmp_buffer, sizeof(tmp_buffer)))
		{
		    if (AddPart (tmp_buffer, Ep->name, sizeof(tmp_buffer)))
		    {
			i = strlen (tmp_buffer);

			if (di + i < sizeof(buf)-1)
			{
			    strcpy(buf + di, tmp_buffer);
			    di += i;
			}
		    }
		}

		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (!stricmp(str, "rexxport"))           /* TJM */
	    {
		*ptr2 = c;
		isaux = 1;

		if (di + strlen(RexxPortName) < sizeof(buf)-1)
		{
		    strcpy(buf + di, RexxPortName);
		    di += strlen(buf + di);
		}

		str += len;

		if (ce)
		    ++str;
		continue;
	    } else if (!stricmp(str, "rxresult"))
	    {
		*ptr2 = c;
		isaux = 1;

		if (di + strlen(get_rexx_result()) < sizeof(buf)-1)
		{
		    strcpy(buf + di, get_rexx_result());
		    di += strlen(buf + di);
		}

		str += len;

		if (ce)
		    ++str;
		continue;
	    } else if (tmpptr = getvar(str))
	    {
		ptr2 = tmpptr;
		str[len] = c;
		isaux = 1;

		if (di + strlen(ptr2) < sizeof(buf)-1)
		{
		    strcpy(buf + di, ptr2);
		    di += strlen(buf + di);
		}

		str += len;

		if (ce)
		    ++str;

		free(ptr2);
		continue;
	    }

	    *ptr2 = c;
	    str --;

	    if (ce)
		str --;
	} else if (*str == '^' && (str[1] & 0x1F))   /* CTRL-sequence */
	{
	    str ++;
	    *str &= 0x1F;
	    isaux = 1;
	} else if (*str == '\\' && str[1])
	{
	    /* reverted to old code */
#ifdef NOTDEF
	    if (!count) /* ignore \ */
	    {
		str ++;
	    } else if (*quoted && count == 1) /* remove it, but check next char */
	    {
#endif
		str ++;
#ifdef NOTDEF
		isaux = 1;
		continue;
	    } else /* don't remove it, but also ignore next char */
	    {
		buf[di ++] = *str ++;
	    }
#endif
	    isaux = 1;
	}

	buf[di ++] = *str ++;
    } /* while (*str) */

    buf[di ++] = 0;

    if (isaux)
    {
	*paux = malloc (di);
	strcpy (*paux, buf);
	base = *paux;
    }

    if (*str)               /*  space ended */
    {
	*str = '\0';
	*ptr = str + 1;     /*	next arg    */
    } else
    {
	*ptr = str;	    /*	last arg    */
    }

    return (base);
} /* breakout */


/******************************************************************************
*****  ENDE command.c
******************************************************************************/
