
/*
 * COMMAND.C
 *
 *	(C)Copyright 1987 by Matthew Dillon, All Rights Reserved
 *
 * )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.
 */

#include "defs.h"

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 **);


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

#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 BTOCP(val, type)    ((type)((long)val << 2))

typedef void (*FPTR)(long);

typedef struct {
    const char * name;	  /* command name	*/
    ubyte args;
    ubyte flags;
    FPTR func;	/* function	      */
} COMM;


/*============================================================================*/
/*
 *  WLEFT/WRIGHT will check command line mode themselves, and thus can
 *  be marked flags=1 even though they can change the line number.
 *
 *  Command names MUST be sorted alphabetically
 */

	/*	  args flags	*/

static const COMM Comm[] = {
#ifndef NO_DO2
    "addpath",       1,        CF_ICO, (FPTR)do_addpath,
#endif
    "appendsave",    1, CF_COK|CF_ICO, (FPTR)do_appendsave,
    "arpfont",       0,             0, (FPTR)do_aslfont,
    "arpinsfile",    0,             0, (FPTR)do_aslinsfile,
    "arpload",       0,             0, (FPTR)do_aslload,
    "arpsave",       0,        CF_ICO, (FPTR)do_aslsave,
    "autoindent",    1,        CF_ICO, (FPTR)do_autoindent,
    "autosplit",     1,        CF_ICO, (FPTR)do_autosplit,
    "autounblock",   1,        CF_ICO, (FPTR)do_autounblock,
    "back",          0,        CF_COK, (FPTR)do_bs,
    "backtab",       0,        CF_COK, (FPTR)do_backtab,
    "barpsave",      0,        CF_ICO, (FPTR)do_barpsave,
    "bappendsave",   0, CF_COK|CF_ICO, (FPTR)do_bappendsave,
    "bcopy",         0,             0, (FPTR)do_bcopy,
    "bdelete",       0,             0, (FPTR)do_bdelete,
    "bgpen",         1,             0, (FPTR)do_bgpen,
    "bend",          0,             0, (FPTR)do_block,    /* checks com name for mode */
    "block",         0,             0, (FPTR)do_block,    /* checks com name for mode */
    "bmove",         0,             0, (FPTR)do_bmove,
    "bottom",        0,             0, (FPTR)do_bottom,
    "bs",            0,        CF_COK, (FPTR)do_bs,
    "bsave",         1,        CF_ICO, (FPTR)do_bsave,
    "bsource",       0,        CF_ICO, (FPTR)do_bsource,
    "bstart",        0,             0, (FPTR)do_block,    /* checks com name for mode */
    "cd",            1,        CF_ICO, (FPTR)do_cd,
    "chfilename",    1,        CF_ICO, (FPTR)do_chfilename,
    "clipins",       0,        CF_COK, (FPTR)do_clipins,
    "col",           1,        CF_COK, (FPTR)do_col,
#ifndef NO_DO_CTAGS
    "ctags",         0,             0, (FPTR)do_ctags,
#endif
    "debug",         1,        CF_ICO, (FPTR)do_debug,
    "del",           0,        CF_COK, (FPTR)do_del,
    "delete",        0,        CF_COK, (FPTR)do_delete,
    "deline",        0,             0, (FPTR)do_deline,
    "delines",       1,             0, (FPTR)do_delines,
    "down",          0,        CF_COK, (FPTR)do_down,
    "downadd",       0,             0, (FPTR)do_downadd,
    "esc",           0,        CF_COK, (FPTR)do_esc,
    "escimm",        1,        CF_PAR, (FPTR)do_esc,
    "execute",       1,        CF_ICO, (FPTR)do_execute,
    "fgpen",         1,             0, (FPTR)do_fgpen,
    "find",          1,             0, (FPTR)do_find,     /* checks com name for mode */
    "findr",         2,             0, (FPTR)do_findr,    /* checks com name for mode */
    "findstr",       1,             0, (FPTR)do_findstr,  /* checks com name for mode */
    "first",         0,        CF_COK, (FPTR)do_firstcolumn,
    "firstnb",       0,        CF_COK, (FPTR)do_firstnb,
    "global",        1, CF_COK|CF_ICO, (FPTR)do_global,
    "goto",          1,             0, (FPTR)do_goto,
    "hgpen",         1,             0, (FPTR)do_hgpen,
    "iconify",       0,        CF_ICO, (FPTR)do_iconify,
    "if",            2, CF_COK|CF_ICO, (FPTR)do_if,
    "ifelse",        3, CF_COK|CF_ICO, (FPTR)do_if,
    "ignorecase",    1, CF_COK|CF_ICO, (FPTR)do_ignorecase,
    "indent",        2,             0, (FPTR)do_indent,
    "insertmode",    1, 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,
    "last",          0,        CF_COK, (FPTR)do_lastcolumn,
    "left",          0,        CF_COK, (FPTR)do_left,
    "map",           2,        CF_ICO, (FPTR)do_map,
    "margin",        1,        CF_ICO, (FPTR)do_margin,
    "match",         0,        CF_COK, (FPTR)do_match,
    "menuadd",       3,        CF_ICO, (FPTR)do_menuadd,
    "menuclear",     0,        CF_ICO, (FPTR)do_menuclear,
    "menudel",       2,        CF_ICO, (FPTR)do_menudel,
    "menudelhdr",    1,        CF_ICO, (FPTR)do_menudelhdr,
    "menuoff",       0,        CF_ICO, (FPTR)do_menuoff,
    "menuon",        0,        CF_ICO, (FPTR)do_menuon,
    "modified",      1,        CF_ICO, (FPTR)do_modified,
    "newfile",       1,             0, (FPTR)do_edit,   /* checks com name for mode */
    "newwindow",     0,        CF_ICO, (FPTR)do_newwindow,
    "next",          0,             0, (FPTR)do_find,
    "nextr",         0,             0, (FPTR)do_findr,
    "null",          0,        CF_COK, (FPTR)do_null,
    "openwindow",    1,        CF_ICO, (FPTR)do_openwindow,
    "pagedown",      0,             0, (FPTR)do_page,
    "pageleft",      0,             0, (FPTR)do_page,
    "pageright",     0,             0, (FPTR)do_page,
    "pageset",       1,        CF_ICO, (FPTR)do_page,
    "pageup",        0,             0, (FPTR)do_page,
    "pick",          1, CF_COK|CF_ICO, (FPTR)do_pop,
    "ping",          1,        CF_ICO, (FPTR)do_ping,
    "pong",          1,             0, (FPTR)do_pong,
    "pop",           1, CF_COK|CF_ICO, (FPTR)do_pop,
    "port",          2,        CF_ICO, (FPTR)to_port,          /* HD Rexx */
    "prev",          0,             0, (FPTR)do_find,
    "prevr",         0,             0, (FPTR)do_findr,
    "projectinfo",   0,        CF_ICO, (FPTR)project_info,     /* HD */
    "projectload",   0,        CF_ICO, (FPTR)load_project,     /* HD */
    "projectsave",   0,        CF_ICO, (FPTR)save_project,     /* HD */
    "pubscreen",     1,        CF_ICO, (FPTR)set_pubscreen,
    "push",          1, CF_COK|CF_ICO, (FPTR)do_push,
    "quit",          0,        CF_ICO, (FPTR)do_quit,
    "quitall",       0,        CF_ICO, (FPTR)do_quitall,
    "recall",        0,             0, (FPTR)do_recall,
    "redisplay",     0,             0, (FPTR)text_redisplay,
    "ref",           0,        CF_ICO, (FPTR)do_refs,
    "reformat",      0,             0, (FPTR)do_reformat,
    "remeol",        0,        CF_COK, (FPTR)do_remeol,
#ifndef NO_DO2
    "rempath",       1, CF_COK|CF_ICO, (FPTR)do_rempath,
#endif
    "repeat",        2, CF_COK|CF_ICO, (FPTR)do_repeat,
    "repstr",        1,        CF_ICO, (FPTR)do_findstr,
    "reqfont",       0,             0, (FPTR)do_reqfont,
    "reqinsfile",    0,             0, (FPTR)do_reqinsfile,
    "reqload",       0,             0, (FPTR)do_reqload,
    "reqsave",       0,        CF_ICO, (FPTR)do_reqsave,
    "resettoggle",   1, CF_COK|CF_ICO, (FPTR)do_toggle,
    "resize",        2,             0, (FPTR)do_resize,
    "return",        0,        CF_COK, (FPTR)do_return,   /* special meaning in command line mode */
    "right",         0,        CF_COK, (FPTR)do_right,
#ifdef AREXX
    "rx",            1,        CF_ICO, (FPTR)do_rx,       /* explicit ARexx macro invocation      */
    "rx1",           2,        CF_ICO, (FPTR)do_rx1,      /* explicit, with 1 arg  to ARexx macro */
    "rx2",           3,        CF_ICO, (FPTR)do_rx2,      /* explicit, with 2 args to ARexx macro */
    "rxresult",      1,        CF_ICO, (FPTR)put_rexx_result,
#endif
    "saveas",        1, CF_COK|CF_ICO, (FPTR)do_saveas,
    "saveconfig",    0, CF_COK|CF_ICO, (FPTR)do_saveconfig,
    "savemap",       1, CF_COK|CF_ICO, (FPTR)do_savemap,         /* checks com name for mode */
    "saveold",       0, CF_COK|CF_ICO, (FPTR)do_save,
    "savesmap",      1, CF_COK|CF_ICO, (FPTR)do_savemap,
    "savetabs",      1, CF_COK|CF_ICO, (FPTR)do_savetabs,
    "scanf",         1, CF_COK|CF_ICO, (FPTR)do_scanf,
    "screenbottom",  0,             0, (FPTR)do_screenbottom,
    "screentop",     0,             0, (FPTR)do_screentop,
    "scrolldown",    0,             0, (FPTR)do_scrolldown,
    "scrollleft",    0,             0, (FPTR)do_scrollleft,
    "scrollright",   0,             0, (FPTR)do_scrollright,
    "scrollup",      0,             0, (FPTR)do_scrollup,
    "select",        1,        CF_ICO, (FPTR)select_window,      /* HD Rexx */
    "set",           2, CF_COK|CF_ICO, (FPTR)do_set,
    "setenv",        2, CF_COK|CF_ICO, (FPTR)do_setenv,
    "setfont",       2,             0, (FPTR)do_setfont,
    "setparcol",     1, CF_COK|CF_ICO, (FPTR)do_setparcol,
    "settoggle",     1, CF_COK|CF_ICO, (FPTR)do_toggle,
    "sizewindow",    1,        CF_COK, (FPTR)do_sizewindow,
    "source",        1, CF_COK|CF_ICO, (FPTR)do_source,
    "split",         0,             0, (FPTR)do_split,
    "swap",          1, CF_COK|CF_ICO, (FPTR)do_swap,
    "tab",           0,        CF_COK, (FPTR)do_tab,
    "tabstop",       1, CF_COK|CF_ICO, (FPTR)do_tabstop,
    "taskpri",       1, CF_COK|CF_ICO, (FPTR)do_taskpri,
    "title",         1,        CF_ICO, (FPTR)do_title,
    "tlate",         1,        CF_COK, (FPTR)do_tlate,
    "toggle",        1, CF_COK|CF_ICO, (FPTR)do_toggle,
    "tomouse",       0,             0, (FPTR)do_tomouse,
    "top",           0,             0, (FPTR)do_top,
    "tpen",          1,             0, (FPTR)do_tpen,
    "unblock",       0,        CF_ICO, (FPTR)do_block,
    "undeline",      0,             0, (FPTR)do_undeline,
    "undo",          0,             0, (FPTR)do_undo,
    "unjustify",     0,             0, (FPTR)do_unjustify,
    "unmap",         1, CF_COK|CF_ICO, (FPTR)do_unmap,
    "unset",         1, CF_COK|CF_ICO, (FPTR)do_unmap,
    "unsetenv",      1, CF_COK|CF_ICO, (FPTR)do_unsetenv,
    "up",            0,        CF_COK, (FPTR)do_up,
    "while",         2, CF_COK|CF_ICO, (FPTR)do_if,
    "wleft",         0,        CF_COK, (FPTR)do_wleft,
    "wordwrap",      1, CF_COK|CF_ICO, (FPTR)do_wordwrap,
    "wright",        0,        CF_COK, (FPTR)do_wright
};


#define MAXIA	    5

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


int do_command (char * str)
{
    char     * arg;
    char     * aux1,
	     * aux2,
	     * repstr[MAXIA],
	     * oldstr;
    char       quoted;
    short      repi = 0;
    long       j;
    short      low;
    short      high;
    short      diff;
    static int level = 0;
    COMM     * comm;

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

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

#ifdef AREXX
	foundcmd = 1;	/* to prevent us from trying an ARexx macro */
#endif
	return (0);
    }

    while (arg = breakout (&str, &quoted, &aux1)) {
	if (quoted) {
	    if (Ep->iconmode)
		uniconify ();

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

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

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

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

		if (!diff)
		    break;

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

	    if (!diff) {
		comm = &Comm[j];
#ifdef AREXX
		foundcmd = 1;
#endif
		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]);

			    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]);
			goto fail;
		    }
		} /* for all args */

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

process:
		if ((comm->flags & CF_COK) || !Comlinemode) {
		    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 ();

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

		if (Abortcommand)
		    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");
		goto fail;
	    }

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

	    goto process;
	} /* Repeat */

	/* Command not found, check for macro	*/

	{
	    char * str;
	    int    ret;

	    if ((str = keyspectomacro(arg)) || (str = menutomacro(arg))) {
		str = (char *)strcpy(malloc(strlen(str)+1), str);

		ret = do_command(str);

		free(str);
#ifdef AREXX
		if (ret) {
		    foundcmd = 1;
		    goto loop;
		}
#else
		if (ret)
		    goto loop;
#endif
		goto fail;
	    } /* if arg is macro or menu */
	}

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

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

fail:
	--level;

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

	if (aux1) free (aux1);

	return(0);

loop:
	if (aux1) free (aux1);
    } /* while (arg) */

    --level;

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

    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((BPTR)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);
	}
	fclose(fi);
    } else {
	if (do_err) {
	    error ("source:\nFile `%s'\nnot found", av[1]);
	}
    }

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


void do_quit (void)
{
    Quitflag = 1;

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


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

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


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

    if (IntuitionBase->LibNode.lib_Version >= 36)
	NilFH = Open ("NIL:", 1006);
    else
	NilFH = Open ("NULL:", 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:\nNULL:-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;
    short  count;	    /* Level of brace */
    char   opc; 	    /* Open-Char */
    char   clc; 	    /* Close-Char */
    char   immode;
    char   isaux;
    char   buf[MAXLINELEN];
    short  di;

    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 * ptr;
	    char * tmpptr;
	    char   c,
		   ce;
	    short  len;

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

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

	    ptr = str;			    /*	start of varname    */

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

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

	    if (stricmp(str, "scanf") == 0) {
		*ptr = c;
		isaux = 1;

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

		str += len;		    /*	next string pos     */

		if (ce)
		    ++str;

		continue;
	    } else if (stricmp(str, "currentdir") == 0) {
		char localbuf[256];

		*ptr  = c;
		isaux = 1;

		if (getpathto(Ep->dirlock, "", localbuf)) {
		    if (di + strlen(localbuf) < sizeof(buf)-1) {
			strcpy(buf + di, localbuf);
			di += strlen(buf + di);
		    }
		}

		str += len;

		if (ce)
		    ++str;

		continue;
	    } else if (stricmp(str, "path") == 0) {
		char  localbuf[256];
		short i;
		BPTR  lock;

		*ptr  = c;
		isaux = 1;

		lock = Lock (Ep->Name, ACCESS_READ);

		if (getpathto(lock, "", localbuf)) {
		    for (i = strlen(localbuf); i >= 0; --i) {
			if (localbuf[i] == ':' || localbuf[i] == '/')
			    break;
		    }

		    ++i;

		    if (di + i < sizeof(buf)-1) {
			movmem(localbuf, buf + di, i);
			di += i;
			buf[di] = 0;
		    }
		}

		UnLock (lock);

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

		continue;
	    } else if (stricmp(str, "file") == 0) {
		short i;
		short j;

		for (i = strlen(Ep->Name); i >= 0; --i) {
		    if (Ep->Name[i] == ':' || Ep->Name[i] == '/')
			break;
		}

		++i;
		j = strlen(Ep->Name + i);
		*ptr = c;
		isaux = 1;
		if (di + j < sizeof(buf)-1) {
		    movmem(Ep->Name + i, buf + di, j);
		    di += j;
		    buf[di] = 0;
		}
		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (stricmp(str, "filename") == 0) {
		char  localbuf[256];
		BPTR  lock;
		short i;

		*ptr = c;
		isaux = 1;

		lock = Lock (Ep->Name, ACCESS_READ);

		if (getpathto(Ep->dirlock, "", localbuf)) {
		    for (i = strlen(Ep->Name); i >= 0; --i) {
			if (Ep->Name[i] == ':' || Ep->Name[i] == '/')
			    break;
		    }

		    ++i;

		    strcat (localbuf, Ep->Name + i);

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

		UnLock (lock);

		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (stricmp(str, "colno") == 0) {
		*ptr = c;
		isaux = 1;
		if (di < sizeof(buf)-8) {
		    sprintf(buf + di, "%ld", Ep->Column + 1);
		    di += strlen(buf + di);
		}
		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (stricmp(str, "lineno") == 0) {
		*ptr = c;
		isaux = 1;
		if (di < sizeof(buf)-8) {
		    sprintf(buf + di, "%ld", Ep->Line + 1);
		    di += strlen(buf + di);
		}
		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (stricmp(str, "margin") == 0) {          /* MMW */
		*ptr = c;
		isaux = 1;
		if (di < sizeof(buf)-8) {
		    sprintf(buf + di, "%ld", Ep->Margin);
		    di += strlen(buf + di);
		}
		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (stricmp(str, "modified") == 0) {       /* MMW */
		*ptr = c;
		isaux = 1;
		if (di < sizeof(buf)-8) {
		    sprintf(buf + di, "%ld", Ep->Modified ? 1 : 0);
		    di += strlen(buf + di);
		}
		str += len;
		if (ce)
		    ++str;
		continue;
	    } else if (stricmp(str, "currentline") == 0) {
		short i;

		*ptr = c;
		isaux = 1;
		if (di < sizeof(buf)-8) {
		    for (i = strlen(Current) - 1; i >= 0 && Current[i] == ' '; --i);
		    ++i;
		    if (i > 0)
			strncpy(buf + di, Current, i);
		    *(buf + di + i) = 0;
		    di += strlen(buf + di);
		}
		str += len;
		if (ce)
		    ++str;
		continue;
#ifdef AREXX
	    } else if (!stricmp(str, "rexxport")) {         /* TJM */
		*ptr = 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")) {         /* TJM */
		*ptr = 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;
#endif
	    } else if (tmpptr = getvar(str)) {
		ptr = tmpptr;
		str[len] = c;
		isaux = 1;

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

		str += len;

		if (ce)
		    ++str;

		free(ptr);
		continue;
	    } else if (tmpptr = keyspectomacro(str)) {
		*ptr = c;
		isaux = 1;

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

		str += len;

		if (ce)
		    ++str;

		continue;
	    }

	    *ptr = c;
	    str --;

	    if (ce)
		str --;
	} else if (*str == '^' && (str[1] & 0x1F)) { /* CTRL-sequence */
	    str ++;
	    *str &= 0x1F;
	    isaux = 1;
	} else if (*str == '\\' && str[1]) {
	    if (!count || (*quoted && count == 1)) {
		str ++;
		isaux = 1;
		continue;
	    } else {
		buf[di ++] = *str ++;
	    }
	    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 */


