[comp.sources.amiga] DME v1.28f, part 2 of 2

afb@j.cc.purdue.edu.UUCP (11/20/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	command.c
#	keyboard.c
#	refs.c
#	subs.c
#	text2.c
# This archive created: Thu Nov 19 16:33:10 1987
# By:	Matthew Bradburn (Purdue University)
cat << \SHAR_EOF > command.c

/*
 * 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!
 *
 * name arg arg      command name. The arguments are interpreted as strings
 *		     for the command.
 *
 * $scanf	     macro insert variable (currently only $scanf)
 *
 * Any string arguments not part of a command are considered to be typed
 * text.
 */

#include "defs.h"
#include <stdio.h>

extern char *breakout();

typedef struct {
   char *name;	    /* command name	  */
   ubyte args;
   ubyte sl;
   int (*func)();   /* function 	  */
} COMM;

extern int  do_map(),	    do_unmap(),     do_up(),	    do_down(),
	    do_left(),	    do_right(),     do_return(),    do_bs(),
	    do_del(),	    do_esc(),	    do_downadd(),   do_lastcolumn(),
	    do_firstcolumn(),do_edit(),     do_tab(),	    do_backtab(),
	    do_save(),	    do_saveas(),    do_deline(),    do_insline(),
	    do_top(),	    do_bottom(),    do_source(),    do_firstnb(),
	    do_quit(),	    do_find(),	    do_page(),	    do_savetabs(),
	    do_split(),     do_goto(),	    do_screentop(), do_screenbottom(),
	    do_join(),	    do_repeat(),    do_tabstop(),   do_insertmode(),
	    do_block(),     do_bdelete(),   do_bcopy(),     do_bmove(),
	    do_bsave(),     do_wleft(),     do_wright(),    do_remeol(),
	    do_savemap(),   do_toggle(),    do_if(),	    do_tlate(),
	    do_bsource(),   do_findr(),     do_findstr(),   do_newwindow(),
	    do_windowparm(),do_resize(),    do_margin(),    do_wordwrap(),
	    do_reformat(),  do_execute(),   do_chfilename(),do_scrollup(),
	    do_scrolldown(),do_recall(),    do_scanf(),     do_iconify(),
	    do_tomouse(),   do_refs();


/*
 *  WLEFT/WRIGHT will check command line mode themselves, and thus can
 *  be marked sl=1 even though they can change the line number.
 *
 *  No more than 255 commands may exist unless you change the type of hindex[]
 *
 *  Command names MUST be sorted by their first character
 */

unsigned char hindex[26];   /*	alpha hash into table	*/

	/*	  args flags	*/

COMM Comm[] = {
    "back",          0, 1, do_bs,
    "backtab",       0, 1, do_backtab,
    "bcopy",         0, 0, do_bcopy,
    "bdelete",       0, 0, do_bdelete,
    "block",         0, 0, do_block,    /* checks com name for mode */
    "bmove",         0, 0, do_bmove,
    "bottom",        0, 0, do_bottom,
    "bs",            0, 1, do_bs,
    "bsave",         1, 0, do_bsave,
    "bsource",       0, 0, do_bsource,
    "chfilename",    1, 0, do_chfilename,
    "del",           0, 1, do_del,
    "deline",        0, 0, do_deline,
    "down",          0, 0, do_down,
    "downadd",       0, 0, do_downadd,
    "esc",           0, 1, do_esc,
    "escimm",        1, 2, do_esc,
    "execute",       1, 0, do_execute,
    "find",          1, 0, do_find,     /* checks com name for mode */
    "findr",         2, 0, do_findr,    /* checks com name for mode */
    "findstr",       1, 1, do_findstr,  /* checks com name for mode */
    "first",         0, 1, do_firstcolumn,
    "firstnb",       0, 1, do_firstnb,
    "goto",          1, 0, do_goto,
    "height",        1, 1, do_windowparm,
    "iconify",       0, 0, do_iconify,
    "if",            2, 0, do_if,
    "ifelse",        3, 0, do_if,
    "insertmode",    1, 1, do_insertmode,
    "insfile",       1, 0, do_edit,
    "insline",       0, 0, do_insline,
    "join",          0, 0, do_join,
    "last",          0, 1, do_lastcolumn,
    "left",          0, 1, do_left,
    "leftedge",      1, 1, do_windowparm,
    "map",           2, 0, do_map,
    "margin",        1, 1, do_margin,
    "newfile",       1, 0, do_edit,     /* checks com name for mode */
    "newwindow",     0, 0, do_newwindow,
    "next",          0, 0, do_find,
    "nextr",         0, 0, do_findr,
    "pagedown",      0, 0, do_page,
    "pageset",       1, 0, do_page,
    "pageup",        0, 0, do_page,
    "prev",          0, 0, do_find,
    "prevr",         0, 0, do_findr,
    "quit",          0, 0, do_quit,
    "recall",        0, 1, do_recall,
    "ref",           0, 0, do_refs,
    "reformat",      0, 0, do_reformat,
    "remeol",        0, 1, do_remeol,
    "repeat",        2, 1, do_repeat,
    "repstr",        1, 1, do_findstr,
    "resettoggle",   1, 1, do_toggle,
    "resize",        2, 0, do_resize,
    "return",        0, 1, do_return,   /* special meaning in command line mode */
    "right",         0, 1, do_right,
    "saveas",        1, 0, do_saveas,
    "savemap",       1, 0, do_savemap,  /* checks com name for mode */
    "saveold",       0, 0, do_save,
    "savesmap",      1, 0, do_savemap,
    "savetabs",      1, 0, do_savetabs,
    "scanf",         1, 1, do_scanf,
    "screenbottom",  0, 0, do_screenbottom,
    "screentop",     0, 0, do_screentop,
    "scrollup",      0, 0, do_scrollup,
    "scrolldown",    0, 0, do_scrolldown,
    "settoggle",     1, 1, do_toggle,
    "source",        1, 0, do_source,
    "split",         0, 0, do_split,
    "tab",           0, 1, do_tab,
    "tabstop",       1, 1, do_tabstop,
    "tlate",         1, 0, do_tlate,
    "tmpheight",     1, 1, do_windowparm,
    "tmpwidth",      1, 1, do_windowparm,
    "toggle",        1, 1, do_toggle,
    "tomouse",       0, 0, do_tomouse,
    "top",           0, 0, do_top,
    "topedge",       1, 1, do_windowparm,
    "unblock",       0, 0, do_block,
    "unmap",         1, 0, do_unmap,
    "up",            0, 0, do_up,
    "while",         2, 0, do_if,
    "width",         1, 1, do_windowparm,
    "wleft",         0, 1, do_wleft,
    "wordwrap",      1, 1, do_wordwrap,
    "wright",        0, 1, do_wright,
    NULL, 0, 0, NULL
};

init_command()
{
    register short hi;
    register COMM *comm;

    hi = sizeof(Comm)/sizeof(Comm[0]) - 2;
    comm = Comm + hi;

    while (hi >= 0) {
	hindex[comm->name[0] - 'a'] = hi;
	--hi;
	--comm;
    }
}

do_command(str)
char *str;
{
    register char *arg;
    char quoted;
    register short i, j;
    static int level;

    if (++level > 20) {
	title("Recursion Too Deep!");
	--level;
	return(0);
    }
    while (arg = breakout(&str, &quoted)) {
	if (quoted) {
	    text_write(arg);
	    continue;
	}
	for (i = 0; arg[i]; ++i) {
	    if (arg[i] >= 'A' && arg[i] <= 'Z')
		arg[i] += 'a' - 'A';
	}
	if (arg[0] >= 'a' && arg[0] <= 'z') {
	    register COMM *comm = &Comm[hindex[arg[0]-'a']];
	    for (; comm->name && comm->name[0] == arg[0]; ++comm) {
		if (strcmp(arg, comm->name) == 0) {
		    av[0] = (ubyte *)comm->name;
		    for (j = 1; j <= comm->args; ++j) {
			av[j] = (ubyte *)breakout(&str, &quoted);
			if (!av[j]) {
			    title("Bad argument");
			    --level;
			    return(0);
			}
			if (av[j][0] == '$')
			    av[j] = (ubyte *)String;
		    }
		    if ((comm->sl&1) || !Comlinemode) {
			if (comm->sl & 2) {
			    if (Partial)
				free(Partial);
			    Partial = (char *)malloc(strlen(str)+1);
			    strcpy(Partial, str);
			    str += strlen(str);     /*	skip string */
			}
			(*comm->func)(-1);
		    }
		    if (Abortcommand)
			goto fail;
		    goto loop;
		}
	    }
	}

	/* Command not found, check for macro	*/

	{
	    char *str;
	    int ret;
	    str = keyspectomacro(arg);
	    if (str) {
		str = (char *)strcpy(malloc(strlen(str)+1), str);
		ret = do_command(str);
		free(str);
		if (ret)
		    goto loop;
		goto fail;
	    }
	}

	title("Unknown Command");
fail:
	--level;
	return(0);
loop:
	;
    }
    --level;
    return(1);
}


do_source()
{
    char buf[256];
    long xfi;
    register char *str;

    if (xfi = xfopen(av[1], "r", 512)) {
	while (xfgets(xfi, buf, 256) >= 0) {
	    if (buf[0] == '#')
		continue;
	    for (str = buf; *str; ++str) {
		if (*str == 9)
		    *str = ' ';
	    }
	    do_command(buf);
	}
	xfclose(xfi);
    } else {
	if (av[0])
	    title("File not found");
    }
}


do_quit()
{
    extern char Quitflag;

    Quitflag = 1;
}

do_execute()
{
    Execute(av[1], 0, 0);
}

/*
 * repeat X command
 *
 * Since repeat takes up 512+ stack, it should not be nested more than
 * twice.
 *
 * (if X is not a number it can be abbr. with 2 chars)
 *
 * X =	N     -number of repeats
 *	line  -current line # (lines begin at 1)
 *	lbot  -#lines to the bottom, inc. current
 *	cleft -column # (columns begin at 0)
 *		(thus is also chars to the left)
 *	cright-#chars to eol, including current char
 *	tr    -#char positions to get to next tab stop
 *	tl    -#char positions to get to next backtab stop
 */

#define SC(a,b) ((a)<<8|(b))

do_repeat()
{
    ubyte *ptr = av[1];
    char buf1[256];
    char buf2[256];
    unsigned long n;

    breakreset();
    strcpy(buf1, av[2]);
    switch((ptr[0]<<8)+ptr[1]) {
    case SC('l','i'):
	n = text_lineno();
	break;
    case SC('l','b'):
	n = text_lines() - text_lineno() + 1;
	break;
    case SC('c','l'):
	n = text_colno();
	break;
    case SC('c','r'):
	n = text_cols() - text_colno();
	break;
    case SC('t','r'):
	n = text_tabsize()-(text_colno() % text_tabsize());
	break;
    case SC('t','l'):
	n = text_colno() % text_tabsize();
	if (n == 0)
	    n = text_tabsize();
	break;
    default:
	n = atoi(av[1]);
	break;
    }
    while (n > 0) {
	strcpy(buf2, buf1);
	if (do_command(buf2) == 0 || breakcheck()) {
	    Abortcommand = 1;
	    break;
	}
	--n;
    }
}


char *
breakout(ptr, quoted)
register char **ptr;
char *quoted;
{
    register char *str = *ptr;
    register char *base = str;

    *quoted = 0;
    while (*str == ' ')
	++str;
    if (!*str)
	return(NULL);
    if (*str == '\'' || *str == ')') {
	if (str[1]) {
	    *quoted = 1;
	    base = str + 1;
	    if (str[2])
		++str;
	    *str = '\0';
	    *ptr = str;
	    return(base);
	}
	return(NULL);
    }
    if (*str == '`' || *str == '(') {
	short count = 1;
	char opc = *str;
	char clc = (opc == '(') ? ')' : '\'';

	base = ++str;
	while (*str && count) {
	    if (*str == opc)
		++count;
	    if (*str == clc)
		--count;
	    ++str;
	}
	if (count == 0) {
	    --str;
	    *quoted = 1;
	    *str = '\0';
	    *ptr = str + 1;
	    return(base);
	}
    }
    base = str;
    while (*str && *str != ' ')
	++str;
    if (*str) {
	*str = '\0';
	*ptr = str + 1;
	return(base);
    }
    *ptr = str;
    return(base);
}


SHAR_EOF
cat << \SHAR_EOF > keyboard.c

/*
 *  KEYBOARD.C
 *
 *	(C)Copyright 1987 by Matthew Dillon
 *
 *  Handle keyboard related stuff such as keyboard mappings.  Every time
 *  a key is pressed, KEYCTL() is called with the code.  KEYCTL() remembers
 *  which qualifier keys are currently held down, and when a non-qualifier
 *  key is pressed finds the hash entry for the key.  If no hash entry
 *  exists (e.g. you type a normal 'a') the default keymap is used.
 */

#include "defs.h"
#include <stdio.h>

extern ubyte *cqtoa();

typedef struct IOStdReq CIO;

#define QUAL_SHIFT   0x01
#define QUAL_CTRL    0x02
#define QUAL_AMIGA   0x04
#define QUAL_ALT     0x08
#define QUAL_LMB     0x10
#define QUAL_MMB     0x20
#define QUAL_RMB     0x40

#define HASHSIZE  64		    /*	power of 2  */
#define HASHMASK  (HASHSIZE-1)

typedef struct _HASH {
    struct _HASH *next;     /* next hash   */
    ubyte code; 	    /* keycode	   */
    ubyte mask; 	    /* qual. mask  */
    ubyte qual; 	    /* qual. comp  */
    ubyte stat; 	    /* string static? */
    char *str;		    /* command string */
} HASH;

HASH *Hash[HASHSIZE];

struct Device *ConsoleDevice;

ubyte	ctoa[128];
ubyte	cstoa[128];

void
keyctl(im, code, qual)
IMESS *im;
register USHORT qual;
{
    ubyte buf[256];
    ubyte c2;
    short blen = 0;

    code &= 0xFF;
    if (im) {
	blen = DeadKeyConvert(im, buf+1, 254, NULL);
	if (blen == 0)
	    return;
    }
    c2 = 0;
    if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
	c2 |= QUAL_SHIFT;
    if (qual & (IEQUALIFIER_CONTROL))
	c2 |= QUAL_CTRL;
    if (qual & (IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND))
	c2 |= QUAL_AMIGA;
    if (qual & (IEQUALIFIER_LALT|IEQUALIFIER_RALT))
	c2 |= QUAL_ALT;
    if ((qual & IEQUALIFIER_CAPSLOCK) && blen == 1 && buf[1] >= 'a' && buf[1] <= 'z')
	c2 |= QUAL_SHIFT;
    if (qual & IEQUALIFIER_LEFTBUTTON)
	c2 |= QUAL_LMB;
    if (qual & IEQUALIFIER_MIDBUTTON)
	c2 |= QUAL_MMB;
    if (qual & (IEQUALIFIER_RBUTTON))
	c2 |= QUAL_RMB;

    {
	register HASH *hash;
	for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
	    if (hash->code == code && (c2 & hash->mask) == hash->qual)
		break;
	}

	/*
	 *  Use hash entry only if not in command line mode, or if the
	 *  entry does not correspond to an alpha key.
	 */

	if (hash) {
	    if (c2 || !Comlinemode || blen > 1 || !ctoa[code]) {
		strcpy(buf, hash->str);
		do_command(buf);
		return;
	    }
	}
    }

    /*
     *	No hash entry
     */

    if (blen == 1) {
	buf[0] = '\'';
	buf[2] = 0;
    } else {
	buf[0] = '\`';
	buf[blen+1] = '\'';
    }
    if (blen)
	do_command(buf);
}

dealloc_hash()
{
    register HASH *hash, *hnext = NULL;
    register short i;

    for (i = 0; i < HASHSIZE; ++i) {
	for (hash = Hash[i]; hash; hash = hnext) {
	    hnext = hash->next;
	    if (!hash->stat)
		FreeMem(hash->str, strlen(hash->str)+1);
	    FreeMem(hash, sizeof(HASH));
	}
	Hash[i] = NULL;
    }
}

resethash()
{
    register short i;
    CIO cio;
    static struct {
	char *from, *to;
    } defmap[] = {
	"esc",      "esc",
	"c-esc",    "recall",
	"return",   "return insline up firstnb down",
	"enter",    "return",
	"up",       "up",
	"down",     "down",
	"right",    "right",
	"left",     "left",
	"bs",       "bs",
	"del",      "del",
	"tab",      "tab",
	"a-up",     "scrollup",
	"a-down",   "scrolldown",
	"a-r",      "nextr",
	"a-u",      "while cl (tlate -32 right)",
	"a-l",      "while cu (tlate +32 right)",
	"s-up",     "top",
	"s-down",   "bottom",
	"s-right",  "last",
	"s-left",   "first",
	"s-tab",    "backtab",
	"s-del",    "deline",
	"s- ",      "( )",              /* shift space to space */
	"c-1",      "goto block",
	"c-c",      "",                 /* break.. map to a nop */
	"c-l",      "wleft",
	"c-r",      "wright",
	"c-i",      "insertmode on",
	"c-o",      "insertmode off",
	"c-j",      "join",
	"c-s",      "split first down",
	"c-del",    "remeol",
	"c-n",      "next",
	"c-p",      "prev",
	"c-/",      "escimm (find )",
	"c-]",      "ref",
	"c-g",      "escimm (goto )",
	"c-up",     "pageup",
	"c-down",   "pagedown",
	"c-q",      "quit",
	"c-f",      "reformat",
	"c-w",      "wordwrap toggle",
	"f1",       "escimm (insfile )",
	"f2",       "escimm (newfile )",
	"f3",       "escimm (newwindow newfile )",
	"f6",       "saveold iconify",
	"f7",       "escimm (bsave )",
	"f8",       "saveold escimm (newfile )",
	"f9",       "saveold",
	"f10",      "saveold quit",
	"c-b",      "block",
	"c-u",      "unblock",
	"a-d",      "bdelete",
	"a-c",      "bcopy",
	"a-m",      "bmove",
	"a-s",      "bsource",
	"a-S",      "unblock block block bsource",
	"L-lmb",    "tomouse",      /*  left button                 */
	"L-mmo",    "tomouse",      /*  mouse move w/left held down */
	"R-rmb",    "iconify",      /*  right button                */
	NULL, NULL
    };

    dealloc_hash();
    OpenDevice("console.device", -1, &cio, 0);
    ConsoleDevice = cio.io_Device;
    keyboard_init();
    for (i = 0; defmap[i].from; ++i) {
	ubyte code, qual;
	if (get_codequal(defmap[i].from, &code, &qual))
	    addhash(code, 1, 0xFF, qual, defmap[i].to);
    }
}

returnoveride(n)
{
    HASH *hash;
    static ubyte *str;
    static int stat;

    for (hash = Hash[0x44&HASHMASK]; hash; hash = hash->next) {
	if (hash->code == 0x44 && hash->qual == 0) {
	    if (n) {
		str = (ubyte *)hash->str;
		stat= hash->stat;
		hash->str = "return";
		hash->stat = 1;
	    } else {
		if (str == NULL) {
		    remhash(0x44, -1, 0);
		} else {
		    hash->str = (char *)str;
		    hash->stat= stat;
		}
	    }
	    return(0);
	}
    }
    if (n) {
	addhash(0x44, 1, 0xFF, 0, "return");
	str = NULL;
    }
}


addhash(code, stat, mask, qual, str)
ubyte code, stat, mask, qual;
ubyte *str;
{
    register HASH **p, *hash;

    hash = *(p = &Hash[code&HASHMASK]);
    while (hash) {
	if (hash->code == code && hash->qual == qual && hash->mask == mask) {
	    if (!hash->stat)
		FreeMem(hash->str, strlen(hash->str)+1);
	    goto newstr;
	}
	hash = *(p = &hash->next);
    }
    *p = hash = (HASH *)AllocMem(sizeof(HASH), 0);
    hash->next = NULL;
newstr:
    hash->code = code;
    hash->stat = stat;
    hash->mask = mask;
    hash->qual = qual;
    hash->str = (char *)str;
    if (!stat)                  /* if not static */
	hash->str = (char *)strcpy(AllocMem(strlen(str)+1, 0), str);
}


remhash(code, mask, qual)
ubyte code, mask, qual;
{
    register HASH *hash, **p;

    hash = *(p = &Hash[code&HASHMASK]);
    while (hash) {
	if (hash->code == code && hash->qual == qual && hash->mask == mask) {
	    if (!hash->stat)
		FreeMem(hash->str, strlen(hash->str)+1);
	    *p = hash->next;
	    FreeMem(hash, sizeof(HASH));
	    return(1);
	}
	hash = *(p = &hash->next);
    }
    return(0);
}

char *
keyspectomacro(str)
char *str;
{
    HASH *hash;
    ubyte code, qual;

    if (get_codequal(str, &code, &qual)) {
	for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
	    if (hash->code == code) {
		if (hash->qual == (qual & hash->mask)) {
		    return(hash->str);
		}
	    }
	}
    }
    return(NULL);
}


do_map()
{
    ubyte code, qual;

    if (get_codequal(av[1], &code, &qual)) {
	addhash(code, 0, 0xFF, qual, av[2]);
    } else {
	title("Unknown Key");
    }
}

do_unmap()        /* key   */
{
    ubyte code, qual;

    if (get_codequal(av[1], &code, &qual)) {
	remhash(code, -1, qual);
    } else {
	title("Unknown Command");
    }
}

do_clearmap()
{
    resethash();
}

/*
 * SAVEMAP  file
 * SAVESMAP file
 */

do_savemap()
{
    char sysalso;
    char err = 0;
    char buf[256];
    long xfi;
    register int i;
    register HASH *hash;
    register ubyte *ptr;

    xfi = xfopen(av[1], "w", 512);
    if (xfi) {
	sysalso = av[0][4] == 's';
	for (i = 0; i < HASHSIZE; ++i) {
	    for (hash = Hash[i]; hash; hash = hash->next) {
		if (hash->stat == 0 || sysalso) {
		    char soc = '(';
		    char eoc = ')';
		    char ksoc = '(';
		    char keoc = ')';
		    short len;

		    for (ptr = (ubyte *)hash->str; *ptr; ++ptr) {
			if (*ptr == '(')
			    break;
			if (*ptr == '\`') {
			    soc = '\`';
			    eoc = '\'';
			    break;
			}
		    }
		    len = strlen(ptr = cqtoa(hash->code, hash->qual)) - 1;
		    if (ptr[len] == '(' || ptr[len] == ')') {
			ksoc = '\`';
			keoc = '\'';
		    }
		    sprintf(buf, "map %c%s%c %c%s%c\n", ksoc, cqtoa(hash->code, hash->qual), keoc, soc, hash->str, eoc);
		    xfwrite(xfi, buf, strlen(buf));
		}
	    }
	}
	xfclose(xfi);
	if (err)
	    title ("Unable to Write");
	else
	    title ("OK");
    } else {
	title("Unable to open file");
    }
}


DeadKeyConvert(msg,buf,bufsize,keymap)
struct IntuiMessage *msg;
UBYTE *buf;
int bufsize;
struct KeyMap *keymap;
{
    static struct InputEvent ievent = { NULL, IECLASS_RAWKEY };
    if (msg->Class != RAWKEY)
	return(-2);
    ievent.ie_Code = msg->Code;
    ievent.ie_Qualifier = msg->Qualifier;
    ievent.ie_position.ie_addr = *((APTR *)msg->IAddress);
    return(RawKeyConvert(&ievent,buf,bufsize,keymap));
}


/*
 *  Nitty Gritty.
 *
 *  keyboard_init:  initialize for get_codequal() and cqtoa()
 *  get_codequal:   convert a qualifier-string combo to a keycode and qual.
 *  cqtoa:	    convert a keycode and qual to a qual & string
 */

#define LN(a,b,c,d)  ((a<<24)|(b<<16)|(c<<8)|d)

long lname[] = {
    LN('e','s','c', 0  ), LN('f','1', 0 , 0  ), LN('f','2', 0 , 0  ),
    LN('f','3', 0 , 0  ), LN('f','4', 0 , 0  ), LN('f','5', 0 , 0  ),
    LN('f','6', 0 , 0  ), LN('f','7', 0 , 0  ), LN('f','8', 0 , 0  ),
    LN('f','9', 0 , 0  ), LN('f','1','0', 0  ), LN('d','e','l', 0  ),
    LN('b','a','c', 0  ), LN('b','s', 0 , 0  ), LN('t','a','b', 0  ),
    LN('h','e','l', 0  ), LN('r','e','t', 0  ), LN('u','p', 0 , 0  ),
    LN('d','o','w', 0  ), LN('r','i','g', 0  ), LN('l','e','f', 0  ),
    LN('e','n','t', 0  ), LN('n','k','-', 0  ), LN('n','k','.', 0  ),
    LN('n','k','0', 0  ),   /* 24 */
    LN('n','k','1', 0  ), LN('n','k','2', 0  ), LN('n','k','3', 0  ),
    LN('n','k','4', 0  ), LN('n','k','5', 0  ), LN('n','k','6', 0  ),
    LN('n','k','7', 0  ), LN('n','k','8', 0  ), LN('n','k','9', 0  ),
    LN('n','k','(', 0  ), LN('n','k',')', 0  ), LN('n','k','/', 0  ), /*37-39*/
    LN('n','k','*', 0  ), LN('n','k','+', 0  ),
    LN('l','m','b',0xE8), LN('m','m','b',0xEA), LN('r','m','b',0xE9),
    LN('m','m','o',QMOVE),
    0
};


/*
 *  ESC:	x1B
 *  FUNCKEYS:	x9B 30 7E to x9B 39 7E
 *  DEL:	x7E
 *  BS: 	x08
 *  TAB:	x09
 *  RETURN:	x0D
 *  HELP	x9B 3F 7E
 *  UP/D/L/R	x9B 41/42/44/43
 *  NK0-9,-,.,ENTER
 *
 *  Mouse buttons
 */

keyboard_init()
{
    static struct InputEvent ievent = { NULL, IECLASS_RAWKEY };
    ubyte buf[32];
    short j;
    register short i, q, len;

    lname[16] |= 0x44;
    lname[21] |= 0x43;

    for (i = 0; i < 128; ++i) {
	ievent.ie_Code = i;
	ievent.ie_Qualifier = 0;
	ievent.ie_position.ie_addr = NULL;
	len = RawKeyConvert(&ievent,buf,32,NULL);
	switch(len) {
	case 1:     /*	ESC/DEL/BS/TAB/NKx  */
	    if (buf[0] > 32 && buf[0] < 0x7F)
		ctoa[i] = buf[0];
	    switch(buf[0]) {
	    case 0x1B:	lname[ 0] |= i; break;
	    case 0x7F:	lname[11] |= i; break;
	    case 0x09:	lname[14] |= i; break;
	    case 0x08:	lname[12] |= i; lname[13] |= i; break;
	    case '(': if (i > 0x3A) lname[37] |= i; break;
	    case ')': if (i > 0x3A) lname[38] |= i; break;
	    case '/': if (i > 0x3A) lname[39] |= i; break;
	    case '*': if (i > 0x3A) lname[40] |= i; break;
	    case '-': if (i > 0x3A) lname[22] |= i; break;
	    case '+': if (i > 0x3A) lname[41] |= i; break;
	    case '.': if (i > 0x3A) lname[23] |= i; break;
	    default:
		if (i > 0x0F && buf[0] >= '0' && buf[0] <= '9')
		    lname[24+buf[0]-'0'] |= i;
	    }
	    break;
	case 2:     /*	cursor		    */
	    if (buf[0] == 0x9B) {
		switch(buf[1]) {
		case 0x41:  lname[17] |= i;  break;
		case 0x42:  lname[18] |= i;  break;
		case 0x43:  lname[19] |= i;  break;
		case 0x44:  lname[20] |= i;  break;
		}
	    }
	    break;
	case 3:     /*	function/help	    */
	    if (buf[0] == 0x9B && buf[2] == 0x7E) {
		if (buf[1] == 0x3F)
		    lname[15] |= i;
		if (buf[1] >= 0x30 && buf[1] <= 0x39)
		    lname[buf[1]-0x30+1] |= i;
	    }
	    break;
	}
    }
    for (i = 0; i < 128; ++i) {
	ievent.ie_Code = i;
	ievent.ie_Qualifier = IEQUALIFIER_LSHIFT;
	ievent.ie_position.ie_addr = NULL;
	len = RawKeyConvert(&ievent,buf,32,NULL);
	if (len == 1)
	    cstoa[i] = buf[0];
    }
}


ubyte *
cqtoa(code, qual)
{
    static ubyte buf[32];
    register ubyte *ptr = buf;
    register int i;

    if (qual & QUAL_SHIFT)
	*ptr++ = 's';
    if (qual & QUAL_CTRL)
	*ptr++ = 'c';
    if (qual & QUAL_ALT)
	*ptr++ = 'a';
    if (qual & QUAL_AMIGA)
	*ptr++ = 'A';
    if (qual & QUAL_LMB)
	*ptr++ = 'L';
    if (qual & QUAL_MMB)
	*ptr++ = 'M';
    if (qual & QUAL_RMB)
	*ptr++ = 'R';
    if (qual)
	*ptr++ = '-';
    for (i = 0; i < sizeof(lname)/sizeof(lname[0]); ++i) {
	if ((lname[i]&0xFF) == code) {
	    *ptr++ = (lname[i]>>24);
	    *ptr++ = (lname[i]>>16);
	    *ptr++ = (lname[i]>>8);
	    break;
	}
    }
    if (i == sizeof(lname)/sizeof(lname[0]))
	*ptr++ = ctoa[code];
    *ptr++ = 0;
    return(buf);
}


get_codequal(str, pcode, pqual)
ubyte *pcode, *pqual;
ubyte *str;
{
    ubyte qual;
    register short i;

    qual = 0;
    if (strlen(str) > 1) {
	for (; *str && *str != '-'; ++str) {
	    if (*str == 's')
		qual |= QUAL_SHIFT;
	    if (*str == 'c')
		qual |= QUAL_CTRL;
	    if (*str == 'a')
		qual |= QUAL_ALT;
	    if (*str == 'A')
		qual |= QUAL_AMIGA;
	    if (*str == 'L')
		qual |= QUAL_LMB;
	    if (*str == 'M')
		qual |= QUAL_MMB;
	    if (*str == 'R')
		qual |= QUAL_RMB;
	    if (!qual)
		goto notqual;
	}
	if (*str)
	    ++str;
    }
notqual:
    *pqual = qual;
    if (strlen(str) != 1) {           /* long name   */
	register short shift = 24;
	register long mult = 0;

	while (*str && shift >= 8) {
	    if (*str >= 'A' && *str <= 'Z')
		*str = *str - 'A' + 'a';
	    mult |= *str << shift;
	    shift -= 8;
	    ++str;
	}
	for (i = 0; lname[i]; ++i) {
	    if (mult == (lname[i] & 0xFFFFFF00)) {
		*pcode = lname[i] & 0xFF;
		return(1);
	    }
	}
    } else {		    /*	single character keycap */
	for (i = 0; i < sizeof(ctoa); ++i) {
	    if (*str == ctoa[i]) {
		*pcode = i;
		return(1);
	    }
	}
	for (i = 0; i < sizeof(cstoa); ++i) {
	    if (*str == cstoa[i]) {
		*pcode = i;
		*pqual |= QUAL_SHIFT;
		return(1);
	    }
	}
    }
    return(0);
}

SHAR_EOF
cat << \SHAR_EOF > refs.c

/*
 *  REFS.C
 *
 *  Bringup a cross reference editor window.  The file S:dme.refs and
 *  dme.refs in the current directory are searched for the reference.
 *  If found, the file specified is searched and the segment specified
 *  loaded as a new file in a new window.
 */

#include "defs.h"
#include <stdio.h>

extern char *breakout();

void
do_refs()
{
    char str[256];
    char *srch;
    char *file;
    char *estr;
    long len;
    int bcnt = 10;
    register short i, j;
    short slen, elen;
    long xfi, xfj;
    short tmph, tmpw;

    for (i = E.Column; Current[i] == ' '; ++i);     /*  skip spaces     */
    for (j = i	     ; ; ++j) { 		    /*	alpha-num only	*/
	register short c = Current[j];
	if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
	    continue;
	break;
    }
    j -= i;
    if (j > 63)
	j = 63;
    bmov(Current+i, str, j);
    str[j] = 0;
    title("search .refs");
    if (!searchref("s:dme.refs",    str,&srch,&file,&len,&estr) &&
	!searchref("dme.refs",      str,&srch,&file,&len,&estr) &&
	!searchref("df0:s/dme.refs",str,&srch,&file,&len,&estr) &&
	!searchref("df1:s/dme.refs",str,&srch,&file,&len,&estr) &&
	!searchref("df2:s/dme.refs",str,&srch,&file,&len,&estr) &&
	!searchref("df3:s/dme.refs",str,&srch,&file,&len,&estr)
    ) {
	title("Reference not found");
	return;
    }
    title("search file");
    slen = strlen(srch);
    if (estr)
	elen = strlen(estr);
    if (xfi = xfopen(file, "r", 4096)) {
	short lenstr;
	while ((lenstr = xefgets(xfi, str, 256)) >= 0) {
	    if (strncmp(str, srch, slen) == 0) {
		title("load..");
		if (xfj = xfopen("t:dme_ref", "w", 1024)) {
		    tmph = 0;
		    tmpw = 0;
		    do {
			if (lenstr > tmpw)
			    tmpw = strlen(str);
			++tmph;
			xfwrite(xfj, str, strlen(str));
			xfwrite(xfj, "\n", 1);
			if (estr && strncmp(str,estr,elen) == 0)
			    break;
			--len;
		    } while ((lenstr=xefgets(xfi, str, 256)) >= 0 && len);
		    xfclose(xfj);
		    if (tmph > 23)
			tmph = 23;
		    if (tmpw > 80)
			tmpw = 80;
		    sprintf(str, "tmpheight %ld tmpwidth %ld newwindow newfile t:dme_ref", (tmph<<3)+16, (tmpw<<3)+16);
		    do_command(str);
		    unlink("t:dme_ref");
		} else {
		    title("Unable to open t:dme_ref for write");
		}
		xfclose(xfi);
		free(srch);
		free(file);
		if (estr)
		    free(estr);
		return;
	    }
	    if (--bcnt == 0) {	    /* check break every so so	*/
		bcnt = 50;
		if (breakcheck())
		    break;
	    }
	}
	xfclose(xfi);
	title("Search failed");
    } else {
	title("Unable to open sub document");
    }
    free(srch);
    free(file);
    if (estr)
	free(estr);
}

/*
 *  Reference file format:
 *
 *  `key' `lines' `file' `searchstring'
 *
 *  where `lines' can be a string instead ... like a read-until, otherwise
 *  the number of lines to read from the reference.
 */

searchref(file, find, psstr, pfile, plines, pestr)
char *file, *find;
char **psstr, **pfile, **pestr;
long *plines;
{
    long xfi;
    char buf[256];
    char *ptr, *base;
    char quoted;

    mountrequest(0);
    if (xfi = xfopen(file, "r", 4096)) {
	while (xefgets(xfi,(base=buf), 256) >= 0) {
	    ptr = breakout(&base, &quoted);
	    if (ptr && strcmp(ptr, find) == 0) {
		if (ptr = breakout(&base, &quoted)) {
		    *pestr = NULL;
		    *plines = atoi(ptr);
		    if (*plines == 0) {
			*pestr = (char *)malloc(strlen(ptr)+1);
			strcpy(*pestr, ptr);
		    }
		    if (ptr = breakout(&base, &quoted)) {
			*pfile = (char *)malloc(strlen(ptr)+1);
			strcpy(*pfile, ptr);
			if (ptr = breakout(&base, &quoted)) {
			    *psstr = (char *)malloc(strlen(ptr)+1);
			    strcpy(*psstr, ptr);
			    xfclose(xfi);
			    mountrequest(1);
			    return(1);
			}
			free(*pfile);
		    }
		    if (pestr)
			free (*pestr);
		}
	    }
	}
	xfclose(xfi);
    }
    mountrequest(1);
    return(0);
}


SHAR_EOF
cat << \SHAR_EOF > subs.c

/*
 *  SUBS.C
 *
 *	(C)Copyright 1987 by Matthew Dillon, All Rights Reserved
 *
 *  Subroutines.
 */

#include "defs.h"

/*
 *  Create DME's text icon.
 */

makemygadget(gad)
register struct Gadget *gad;
{
    static unsigned long ga[] = {
	0xFFFFFFFF,	/* 32 pixels across */
	0x80FDCBFD,
	0xFFFDDFFD,
	0x80000001,
	0x80DFDDDF,
	0x80000001,
	0xBC0EF00B,
	0x80000001,
	0xBFC00CDD,
	0x80000001,
	0xA00DF00F,
	0x80000001,
	0x80000001,

	0x80000001,
	0x80FDCBFD,
	0xFFFDDFFD,
	0x80000001,
	0x80DFDDDF,
	0x80000001,
	0xBC0EF00B,
	0x80000001,
	0xBFC00CDD,
	0x80000001,
	0xA00DF00F,
	0x80000001,
	0xFFFFFFFF
    };
    static struct Image image = {
	0, 0, 20, sizeof(ga)/4/2, 2, (unsigned short *)ga, 3, 0, NULL
    };
    bzero(gad, sizeof(struct Gadget));
    gad->Width = 20;
    gad->Height = sizeof(ga)/4/2 + 1;
    gad->Flags	= GADGIMAGE|GADGHCOMP;
    gad->GadgetType   = BOOLGADGET;
    gad->Activation = RELVERIFY|GADGIMMEDIATE;
    gad->GadgetRender = (APTR)&image;
}

/*
 * return index of first non space.  Returns 0 if no spaces found.
 */

firstns(str)
register char *str;
{
    register short i;

    for (i = 0; str[i] && str[i] == ' '; ++i);
    if (str[i] == 0)
	i = 0;
    return(i);
}

/*
 *  Return index of last non-space, 0 if no spaces.
 */

lastns(str)
register char *str;
{
    register short i;

    for (i = strlen(str) - 1; i > 0 && str[i] == ' '; --i);
    if (i < 0)
	i = 0;
    return(i);
}

/*
 *  Return length of word under cursor
 */

wordlen(str)
register char *str;
{
    register short i;

    for (i = 0; *str && *str != ' '; ++i, ++str);
    return(i);
}

/*
 *  Find the path from some root device to a specific filename (src), and
 *  stick the result in (dest).  If unable to backtrace along directories,
 *  simply copy (src) into (dest)
 *
 *  Returns (1) if able to backtrace, (0) if not.
 */

getpath(src, dest)
char *src, *dest;
{
    register long flock, pflock;
    register short len, total;
    register FIB *fib = (FIB *)malloc(sizeof(FIB));
    char c;

    dest[0] = 0;
    total = 1;
    flock = Lock(src, ACCESS_READ);
    if (flock == NULL) {			   /* missing file?    */
	for (len = strlen(src); len >= 0; --len) {
	    if (src[len] == '/') {
		--len;
		break;
	    }
	    if (src[len] == ':')
		break;
	}
	if (c = src[len + 1]) {
	    strcpy(dest, src+len+2);
	    total = strlen(dest)+1;
	}
	src[len + 1] = 0;
	flock = Lock(src, ACCESS_READ);
	src[len + 1] = c;
    }
    if (flock) {
	do {
	    pflock = ParentDir(flock);
	    if (Examine(flock, fib) == 0)
		fib->fib_FileName[0] = 0;
	    if (fib->fib_FileName[0] == 0)
		strcpy(fib->fib_FileName, "ram");
	    len = strlen(fib->fib_FileName);
	    bmov(dest, dest + len + 1, total);
	    dest[len] = (pflock) ? '/' : ':';
	    bmov(fib->fib_FileName, dest, len);
	    total += len + 1;
	    UnLock(flock);
	    flock = pflock;
	} while(pflock);
	len = strlen(dest) - 1;
	if (dest[len] == '/')
	    dest[len] = 0;
	return(1);
    }
    strcpy(dest, src);
    return(0);
}

/*
 *  Allocation routines and other shortcuts
 */

ubyte *
allocb(bytes)
{
    return(AllocMem(bytes, MEMF_CLEAR|MEMF_PUBLIC));
}

ubyte *
allocl(lwords)
{
    return(AllocMem(lwords<<2, MEMF_CLEAR|MEMF_PUBLIC));
}

bmovl(s,d,n)
char *s,*d;
{
    bmov(s,d,n<<2);
}

/*
 *  Remove tabs in a buffer
 */

detab(ibuf, obuf, maxlen)
register char *ibuf, *obuf;
{
    register short i, j;

    maxlen -= 2;
    for (i = j = 0; ibuf[i] && j < maxlen; ++i) {
	if (ibuf[i] == 9) {
	    do {
		obuf[j++] = ' ';
	    } while ((j & 7) && j < maxlen);
	} else {
	    obuf[j++] = ibuf[i];
	}
    }
    while (j && obuf[j-1] == ' ')
	--j;
    obuf[j] = 0;
    return(j);
}

xefgets(xfi, buf, max)
char *buf;
long xfi;
{
    char ebuf[256];
    if (xfgets(xfi, ebuf, max) >= 0)
	return(detab(ebuf, buf, max));
    return(-1);
}

SHAR_EOF
cat << \SHAR_EOF > text2.c

/*
 * TEXT2.C
 *
 *	(C)Copyright 1987 by Matthew Dillon, All Rights Reserved
 */

#include "defs.h"
#include <stdio.h>

#define nomemory()  {memoryfail = 1;}

extern char MForceTitle;

do_remeol()
{
    Current[Clen = E.Column] = 0;
    text_sync();
    text_redisplaycurrline();
}

do_wleft()
{
    register ubyte *ptr;
    register int i;

    for (;;) {
	i = E.Column;
	if (i == 0)
	    goto prevline;
	--i;
	while (i && Current[i] == ' ')
	    --i;
	if (i == 0 && Current[0] == ' ') {
prevline:
	    if (Comlinemode || E.Line == 0) {
		i = E.Column;
		break;
	    }
	    text_sync();
	    --E.Line;
	    text_load();
	    E.Column = Clen;
	    continue;
	}
	while (i && Current[i] != ' ')
	    --i;
	if (Current[i] == ' ')
	    ++i;
	break;
    }
    E.Column = i;
    text_sync();
}


do_wright()
{
    register ubyte *ptr;
    register int i;

    for (;;) {
	i = E.Column;
	if (i == Clen)
	    goto nextline;
	while (i != Clen && Current[i] != ' ')  /* skip past current word */
	    ++i;
	while (i != Clen && Current[i] == ' ')  /* to beg. of next word   */
	    ++i;
	if (i == Clen) {
nextline:
	    if (Comlinemode || E.Line == E.Lines - 1) {
		i = E.Column;
		break;
	    }
	    text_sync();
	    ++E.Line;
	    text_load();
	    E.Column = i = 0;
	    if (Current[0] != ' ')
		break;
	    continue;
	}
	break;
    }
    E.Column = i;
    text_sync();
}


do_split()		/* split line in two at cursor pos */
{
    ubyte buf[256];

    strcpy(buf, Current+E.Column);
    Current[Clen = E.Column] = '\0';
    text_sync();
    SetAPen(Rp, 0);
    if (Nsu == 0)
	RectFill(Rp, COL(0), ROW(E.Line-E.Topline), Xbase+Xpixs, ROW(E.Line-E.Topline+1)-1);
    SetAPen(Rp, 1);
    text_displayseg(E.Line - E.Topline, 1);
    do_downadd();
    do_insline();
    strcpy(Current, buf);
    Clen = strlen(Current);
    text_sync();
    text_displayseg(E.Line - E.Topline, 1);
    do_up();
}

do_join()
{
    register int i = Clen, j;

    if (E.Line + 1 < E.Lines && strlen(E.List[E.Line+1])+i <= 253) {
	if (i && Current[i-1] != ' ')
	    Current[i++] = ' ';
	strcpy(Current+i, E.List[E.Line+1]);
	for (j = i; Current[j] == ' '; ++j);
	for (; i >= 0 && Current[i] == ' '; --i);
	if (j > i+2)
	    bmov(Current+j, Current+i+2, strlen(Current+j)+1);
	Clen = strlen(Current);
	text_sync();
	text_displayseg(E.Line - E.Topline, 1);
	do_down();
	do_deline();
	do_up();
	return(1);
    }
    return(0);
}

do_margin()
{
    E.Margin = atoi(av[1]);
}

do_wordwrap()
{
    if (av[1][1] == 'n')
	E.Wordwrap = 1;
    if (av[1][1] == 'f')
	E.Wordwrap = 0;
    if (av[1][0] == 't')
	E.Wordwrap = 1 - E.Wordwrap;
    if (E.Wordwrap)
	title("Wordwrap ON");
    else
	title("Wordwrap OFF");
}

/*
 * n == -1  :	force reformat entire paragraph
 * n ==  0  :	only until line equalizes (from text_write())
 *
 * What is a paragraph?   A paragraph ends whenever the left justification
 * gets larger, or on a blank line.
 */

do_reformat(n)
{
    register char *str;
    int nlok, lnsc, fnst, fnsc;
    int column = E.Column;
    int srow   = E.Line;
    int crow   = srow;
    int erow   = srow;
    short dins = 0;	    /* relative insert lines/delete lines   */
    char moded = 0;	    /* any modifications done at all?	    */
    char checked = 0;	    /* for cursor positioning.		    */

    if (E.Margin == 0)
	E.Margin = 75;

    ++Nsu;
    for (;;) {
	str = (char *)E.List[E.Line+1];
	fnst = 0;
	fnsc = firstns(Current);
	nlok = (E.Line + 1 < E.Lines && fnsc >= (fnst=firstns(str)));
	if (nlok && str[0] == 0)
	    nlok = 0;
	lnsc = lastns(Current);
	if (lnsc < E.Margin) {	  /* space at end of line for marg-lnsc-2 letter word	*/
	    if (nlok == 0)	  /* but no more data to joinup   */
		break;		  /* done */
	    if (E.Margin - lnsc - 2 >= wordlen(str+fnst)) {
		E.Column = 0;
		Clen = lastns(Current);
		if (Current[Clen])
		    ++Clen;
		moded = 1;
		--dins;
		if (do_join())
		    continue;
		++dins;
		title("Error, Margin > 124");
		break;
	    }
	    if (n == 0)        /* if couldn't mod line, and text_write, don't update any more */
		break;
	    do_down();
	    erow = E.Line;
	    continue;
	}
				/* no space, need to split	*/
				/* find start of prev word	*/
	for (;;) {
	    register int i = lnsc;
	    while (i && Current[i] != ' ')
		--i;
	    lnsc = i;
	    if (i >= E.Margin) {
		while (i && Current[i] == ' ')
		    --i;
		if (i < E.Margin)
		    break;
		lnsc = i;
		continue;
	    }
	    break;
	}
	if (lnsc) {		/* ok to split at word		*/
	    ++lnsc;
	    ++dins;
	    E.Column = lnsc;
	    do_split(); /* Split at point LNSC		*/
	    do_down();		/* must insert proper amount?	*/
	    {
		int indent = (nlok == 0) ? fnsc : fnst;
		if (!checked) {
		    checked = 1;
		    if (lnsc <= column) {   /* if split before cursor	*/
			column = column - E.Column + indent;
			++crow;
		    }
		}
		if (Clen + indent < 253) {
		    bmov(Current, Current + indent, strlen(Current)+1);
		    bset(Current, indent, ' ');
		    Clen += indent;
		}
	    }
	    erow = E.Line;
	    continue;
	}
	if (n == 0)
	    break;
	do_down();
    }
    if (column < 0 || column > 200)
	column = 0;
    if (srow >= E.Lines) {
	srow = E.Lines - 1;
	goto ra;
    }
    if (dins || srow < E.Topline || srow >= E.Topline + Rows) {
ra:
	text_sync();
	--Nsu;
	E.Line = crow;
	E.Column = column;
	text_load();
	if (!text_sync())
	    text_redisplay();
    } else {
	text_sync();
	--Nsu;
	E.Line = crow;
	E.Column = column;
	text_load();
	if (erow != srow) {
	    if (!text_sync()) {
		++erow;
		if (erow - E.Topline > Rows)
		    erow = E.Topline + Rows;
		SetAPen(Rp, 0);
		RectFill(Rp, COL(0), ROW(srow - E.Topline), Xbase+Xpixs, ROW(erow - E.Topline)-1);
		SetAPen(Rp, 1);
		text_displayseg(srow - E.Topline, erow - srow);
	    }
	} else {
	    text_sync();
	    if (moded)
		text_redisplaycurrline();
	}
    }
    if (column > Clen) {
	bset(Current+Clen, column - Clen, ' ');
	Current[column] = 0;
    }
    E.Column = column;
}


do_tabstop()
{
    E.Tabstop = atoi(av[1]);
}


do_insertmode()
{
    if (av[1][0]) {
	switch(av[1][1] & 0x1F) {
	case 'n'&0x1F:
	    E.Insertmode = 1;
	    break;
	case 'f'&0x1F:
	    E.Insertmode = 0;
	    break;
	case 'o'&0x1F:
	    E.Insertmode = 1 - E.Insertmode;
	    break;
	}
	if (E.Insertmode)
	    title("Insert mode on");
	else
	    title("Insert mode off");
    }
}

do_insline()
{
    register ubyte *ptr;

    E.Modified = 1;
    text_sync();
    if (makeroom(32) && (ptr = allocb(1))) {
	bmovl(E.List+E.Line, E.List+E.Line+1,E.Lines-E.Line);
	E.List[E.Line] = ptr;
	*ptr = 0;
	++E.Lines;
	if (E.Line < E.BSline)
	    ++E.BSline;
	if (E.Line <= E.BEline)
	    ++E.BEline;
    } else {
	nomemory();
    }
    text_load();
    if (Nsu == 0)
	ScrollRaster(Rp,0,-Ysize, COL(0), ROW(E.Line-E.Topline), COL(Columns)-1, ROW(Rows)-1);
    text_displayseg(E.Line - E.Topline, 1);
}

do_deline()
{
    int delline;

    if (E.Lines > 1) {
	E.Modified = 1;
	text_sync();
	FreeMem(E.List[E.Line], strlen(E.List[E.Line])+1);
	bmovl(E.List+E.Line+1, E.List+E.Line,E.Lines-E.Line-1);
	if (E.Line < E.BSline)
	    --E.BSline;
	if (E.Line <= E.BEline)
	    --E.BEline;
	delline = E.Line;
	if (E.Line >= --E.Lines) {
	    --E.Line;
	    text_load();
	    if (E.Line < E.Topline) {
		if (Nsu == 0) {
		    E.Topline = E.Line - (Rows>>1);
		    if (E.Topline < 0)
			E.Topline = 0;
		    text_redisplay();
		}
		return(0);
	    }
	}
	text_load();
	if (Nsu == 0)
	    ScrollRaster(Rp,0,Ysize, COL(0), ROW(delline-E.Topline), COL(Columns)-1, ROW(Rows)-1);
	text_displayseg(Rows-1, 1);
    } else {
	do_firstcolumn();
	do_remeol();
	E.Modified = 0;
    }
}

do_chfilename()
{
    text_sync();
    strncpy(E.Name, av[1], 63);
    MForceTitle = 1;
}

do_edit()
{
    long xfi;
    long oldlock;
    long lines;
    ubyte buf[256];
    ubyte *ptr;
    char failed = 1;
    short iwiny;

    text_sync();
    if (*av[0] == 'n') {        /* newfile or insfile   */
	if (E.Modified && getyn("Delete modified Image?") == 0)
	    return(0);
	iwiny = E.IWiny;
	text_uninit();
	text_init();
	E.IWiny = iwiny;
	E.Modified = 0;
	E.Line = E.Topline = 0;
	strncpy(E.Name, av[1], 63);
    } else {
	E.Modified = 1;
    }
    lines = E.Lines;
    if (Wbs && Wdisable == 0)
	oldlock = CurrentDir(E.dirlock);
    if (xfi = xfopen(av[1], "r", 4096)) {
	register int len;
	char oktitle = 1;

	title("Loading...");
	while ((len = xefgets(xfi, buf, 255)) >= 0) {
	    failed = 0;
	    if (makeroom(256) && (ptr = allocb(len+1))) {
		E.List[E.Lines++] = ptr;
		bmov(buf, ptr, len+1);
	    } else {
		nomemory();
		oktitle = 0;
		break;
	    }
	}
	if (oktitle)
	    title("OK");
    } else {
	title("File Not Found");
    }
    xfclose(xfi);
    if (Wbs && Wdisable == 0)
	CurrentDir(oldlock);
    if (E.Lines != 1 && lines == 1 && E.List[0][0] == 0) {
	E.Modified = 0;
	E.Line = 0;
	FreeMem(E.List[0], strlen(E.List[0])+1);
	bmovl(E.List+1, E.List,--E.Lines);
    } else {
	if (!failed && lines <= E.Lines - 1) {
	    E.BSline = lines;
	    E.BEline = E.Lines-1;
	    do_bmove();
	}
    }
    text_load();
    text_redisplay();
}

static char blockmode;

do_bsave()
{
    blockmode = 1;
    do_saveas();
}

do_save()
{
    av[1] = E.Name;
    do_saveas();
}

do_savetabs()
{
    Savetabs = (av[1][0] && av[1][1] == 'n') ? 1 : 0;
}

do_saveas()
{
    long oldlock;
    long xfi;
    register long i;
    register short j, k;
    register ubyte *ptr, *bp;
    long xs, xe;
    ubyte buf[256];
    char bm;

    bm = blockmode;
    if (blockmode && blockok()) {
	xs = E.BSline;
	xe = E.BEline + 1;
    } else {
	xs = 0;
	xe = E.Lines;
    }
    blockmode = 0;
    text_sync();
    if (Wbs && Wdisable == 0) {     /* Write out .info file */
	DISKOBJ sdo, *d;
	bzero(&sdo, sizeof(sdo));
	oldlock = CurrentDir(E.dirlock);
	if ((d = GetDiskObject(av[1])) == NULL) {
	    if (getpath(Wbs->sm_ArgList[0].wa_Name, buf)) {
		sdo.do_Magic = WB_DISKMAGIC;
		sdo.do_Version = WB_DISKVERSION;
		makemygadget(&sdo.do_Gadget);
		sdo.do_Type = WBPROJECT;
		sdo.do_DefaultTool = (char *)buf;
		sdo.do_ToolTypes = NULL;
		sdo.do_CurrentX = NO_ICON_POSITION;
		sdo.do_CurrentY = NO_ICON_POSITION;
		sdo.do_DrawerData = NULL;
		sdo.do_ToolWindow = NULL;
		sdo.do_StackSize = 8192;
		PutDiskObject(av[1], &sdo);
	    }
	} else {
	    FreeDiskObject(d);
	}
    }
    if (xfi = xfopen(av[1], "w", 4096)) {
	title("Saving...");
	for (i = xs; i < xe; ++i) {
	    ptr = E.List[i];
	    if (Savetabs) {
		for (bp = buf, j = 0; *ptr; ++ptr, ++bp, j = (j+1)&7) {
		    *bp = *ptr;
		    if (j == 7 && *bp == ' ' && *(bp-1) == ' ') {
			k = j;
			while (k-- >= 0 && *bp == ' ')
			    --bp;
			*++bp = 9;
		    } else {
			if (*bp == '\"' || *bp == '\'' || *bp == '\`' || *bp == '(')
			    break;
		    }
		}
		strcpy(bp, ptr);
		ptr = buf;
	    }
	    xfwrite(xfi, ptr, strlen(ptr));
	    if (xfwrite(xfi, "\n", 1)) {
		xfclose(xfi);
		goto err;
	    }
	}
	if (xfclose(xfi)) {
err:	    Abortcommand = 1;
	    title("WRITE FAILED!");
	} else {
	    E.Modified &= bm;
	    title("OK");
	}
	if (Wbs && Wdisable == 0)
	    CurrentDir(oldlock);
    } else {
	title("Unable to open write file");
	Abortcommand = 1;
    }
}


do_block()	    /* block, unblock	*/
{
    switch(av[0][0]) {
    case 'b':
	if (E.BSline < 0) {
	    E.BSline = E.Line;
	    title("Block Begin");
	} else {
	    if (E.BEline >= 0) {
		title("Block Already Marked");
		break;
	    }
	    title("Block End");
	    E.BEline = E.Line;
	    if (E.BSline > E.BEline) {
		E.BEline = E.BSline;
		E.BSline = E.Line;
	    }
	}
	break;
    case 'u':
	E.BSline = E.BEline = -1;
	title ("Block Unmarked");
	break;
    }
}

static
blockok()
{
    if (E.BSline >= 0 && E.BEline >= 0 && E.BSline <= E.BEline && E.BEline < E.Lines)
	return(1);
    E.BSline = E.BEline = -1;
    title("Block Not Specified");
    return(0);
}


do_bdelete()
{
    register long i, n;

    if (blockok()) {
	text_sync();
	n = E.BEline - E.BSline + 1;
	if (E.Line >= E.BSline && E.Line <= E.BEline)
	    E.Line = E.BSline;
	if (E.Line > E.BEline)
	    E.Line -= n;
	for (i = E.BSline; i < E.BEline; ++i)
	    FreeMem(E.List[i], strlen(E.List[i])+1);
	bmovl(E.List+E.BEline+1,E.List+E.BSline,(E.Lines-E.BEline-1));
	E.Lines -= n;
	E.Modified = 1;
	if (E.Line >= E.Lines)
	    E.Line = E.Lines - 1;
	if (E.Line < 0)
	    E.Line = 0;
	if (E.Lines == 0) {
	    text_uninit();
	    text_init();
	}
	text_load();
	E.BSline = E.BEline = -1;
	if (!text_sync())
	    text_redisplay();
    }
}

void
do_bcopy()
{
    register ubyte **list;
    register long lines, i, scr;
    register ED *e;

    if (!blockok())
	return;
    text_sync();
    lines = E.BEline - E.BSline + 1;
    list = (ubyte **)allocl(E.Lines+lines);
    if (!list) {
	nomemory();
	return;
    }
    for (i = 0; i < lines; ++i) {
	register ubyte *ptr = E.List[E.BSline+i];
	if (!(list[E.Line+i] = allocb(strlen(ptr)+1))) {
	    nomemory();
	    while (--i >= 0)
		FreeMem(list[E.Line+i], strlen(E.List[E.BSline+i])+1);
	    FreeMem(list, sizeof(char *)*(E.Lines+lines));
	    return;
	}
	strcpy(list[E.Line+i], ptr);
    }
    bmovl(E.List, list, E.Line);
    bmovl(E.List+E.Line, list + E.Line + lines, E.Lines-E.Line);
    if (E.Line < E.BSline) {
	E.BSline += lines;
	E.BEline += lines;
    }
    E.Modified = 1;
    FreeMem(E.List, E.Maxlines * sizeof(char *));
    E.List = list;
    E.Lines += lines;
    E.Maxlines = E.Lines;
    text_load();
    if (!text_sync())
	text_redisplay();
}


do_bmove()
{
    register long lines;
    register ubyte **temp;

    if (blockok()) {
	if (E.Line >= E.BSline && E.Line <= E.BEline) {
	    title("Cannot Move into self");
	    return(0);
	}
	text_sync();
	lines = E.BEline - E.BSline + 1;
	temp = (ubyte **)allocl(lines);
	bmovl(E.List + E.BSline, temp, lines);
	if (E.Line > E.BSline) {
	    bmovl(E.List+E.BEline+1, E.List+E.BSline, E.Line-E.BEline-1);
	    bmovl(temp, E.List + E.Line - lines, lines);
	} else {
	    bmovl(E.List+E.Line, E.List+E.Line+lines, E.BSline-E.Line);
	    bmovl(temp, E.List + E.Line, lines);
	}
	E.Modified = 1;
	FreeMem(temp, lines * sizeof(char *));
	E.BSline = E.BEline = -1;
	text_load();
	if (!text_sync())
	    text_redisplay();
    }
}


/*
 * IF condition trueaction, IFELSE condition trueaction falseaction
 *
 *  condition:	!condition NOT the specified condition.
 *		#	   toggle number is SET
 *		top	   top of file (on first line)
 *		bot	   end of file (on last line)
 *		left	   start of line (leftmost column)
 *		right	   end of line (nothing but spaces under and to the right)
 *		modified   text has been modified
 *		insert	   currently in insert mode
 *		y[<=>]#    cursor is (any OR combo of <,>,=) row #  (line numbers start at 1)
 *		x[<=>]#    cursor is (<,>,<=,>=,<>) column #	    (columns start at 1)
 *			    <> means 'not equal'
 *
 *		cl	   char under cursor is lower case
 *		cu	   char under cursor is upper case
 *		ca	   char under cursor is alpha
 *		cn	   char under cursor is numeric
 *		cb	   char within selected block
 *		c[<=>]#    char under cursor is (combo of <,>,and =) #
 */

do_if()
{
    char haselse = (av[0][2] == 'e');
    char iswhile = (av[0][0] == 'w');
    char istrue, notop = 0;
    char c, cx, cc;
    ubyte *buf1, *buf2;
    register ubyte *ptr;
    int i, cxn, cn;

    buf1 = (ubyte *)malloc(256);
    buf2 = (ubyte *)malloc(256);
    if (buf1 == NULL || buf2 == NULL) {
	if (buf1) free(buf1);
	if (buf2) free(buf2);
	title("No Memory!");
	return(0);
    }
    breakreset();
    ptr = av[1];
    if (*ptr == '!') {
	notop = 1;
	++ptr;
    }
    c = ptr[0];
    cn= atoi(ptr);
    cx= ptr[1];
    cxn=atoi(ptr+1);
    strcpy(buf1, av[2]);

loop:
    istrue = 0;
    i = 0;
    switch(c) {
    case 'x':
	i = E.Column + 1;
    case 'y':
	if (!i)
	    i = E.Line + 1;
conditional:
	{
	    register int j, n;
	    char any = 0;

	    for (j = 1; ptr[j] && (ptr[j]<'0'||ptr[j]>'9'); ++j);
	    n = atoi(ptr+j);
	    for (j = 1; ptr[j]; ++j) {
		switch(ptr[j]) {
		case '<':
		    any = 1;
		    if (i < n)
			istrue = 1;
		    break;
		case '=':
		    any = 1;
		    if (i == n)
			istrue = 1;
		    break;
		case '>':
		    any = 1;
		    if (i > n)
			istrue = 1;
		    break;
		}
	    }
	    if (!any && i == n)  /* default is equivalence   */
		istrue = 1;
	}
	break;
    case 't':
	istrue = E.Line == 0;
	break;
    case 'b':
	istrue = E.Line == E.Lines-1;
	break;
    case 'l':
	istrue = E.Column == 0;
	break;
    case 'r':
	istrue = E.Column == Clen;
	break;
    case 'm':
	text_sync();
	istrue = E.Modified != 0;
	break;
    case 'i':
	istrue = E.Insertmode != 0;
	break;
    case 'c':
	cc = Current[E.Column];
	switch(cx) {
	case 'b':
	    istrue = E.Line >= E.BSline && E.Line <= E.BEline;
	    break;
	case 'l':
	    istrue = cc >= 'a' && cc <= 'z';
	    break;
	case 'u':
	    istrue = cc >= 'A' && cc <= 'Z';
	    break;
	case 'a':
	    istrue = (cc>='a'&&cc<='z')||(cc>='A'&&cc<='Z')||(cc>='0'&&cc<='9');
	    break;
	case 'n':
	    istrue = (cc >= '0' && cc <= '9');
	    break;
	default:		/* c[<=>]#  */
	    i = Current[E.Column];
	    goto conditional;
	    break;
	}
	break;
    default:
	if (c >= '0' && c <= '9')
	    istrue = do_toggle(cn) != 0;
	else
	    title("bad conditional");
	break;
    }
    istrue ^= notop;
    if (istrue) {
	strcpy(buf2, buf1);	/* could be executed multiple times */
	if (do_command(buf2) == 0)
	    goto done;
	if (iswhile) {
	    if (breakcheck())
		Abortcommand = 1;
	    else
		goto loop;
	}
    } else {
	if (haselse) {		/* only executed once */
	    strcpy(buf2, av[3]);
	    do_command(buf2);
	}
    }
done:
    free(buf1);
    free(buf2);
}


/*
 * TOGGLE #, SETTOGGLE #, RESETTOGGLE #
 */

do_toggle(n)
{
    static char tg[MAXTOGGLE];
    int i;

    if (n >= 0) {
	if (n >= MAXTOGGLE)
	    return(0);
	return(tg[n]);
    }
    i = atoi(av[1]);
    if (i >= 0 && i < MAXTOGGLE) {
	switch(av[0][0]) {
	case 't':
	    tg[i] = !tg[i];
	    break;
	case 's':
	    tg[i] = 1;
	    break;
	case 'r':
	    tg[i] = 0;
	    break;
	}
    }
}


do_tlate()
{
    register ubyte *ptr = av[1];
    register int n;
    char c = Current[E.Column];

    if (ptr[0] == '+')
	c += atoi(ptr+1);
    else
    if (ptr[0] == '-')
	c -= atoi(ptr+1);
    else
	c = atoi(ptr);
    if (c) {
	if (Current[E.Column] == 0)
	    Current[E.Column+1] = 0;
	Current[E.Column] = c;
	if (Nsu == 0) {
	    movetocursor();
	    Text(Rp, Current+E.Column, 1);
	}
    }
}

/*
 *  BSOURCE
 *
 *  note that since the start and end lines are loaded immediately and the
 *  block unblock'd before execution starts, you can theoretically have
 *  another BSOURCE as part of this BSOURCE (but be carefull!).
 */

do_bsource()
{
    ubyte buf[256];
    register int i, sl, se;

    if (blockok()) {
	sl = E.BSline;
	se = E.BEline + 1;
	E.BSline = E.BEline = -1;

	for (i = sl; i < se && i < E.Lines; ++i) {
	    text_sync();	/* make sure we are using latest text */
	    strcpy(buf, E.List[i]);
	    if (do_command(buf) == 0)
		break;
	}
    }
}

/*
 *  SCANF controlstring
 *
 *  The C scanf routine.  Only one variable, a string, is allowed in the
 *  control string.
 */

void
do_scanf()
{
    char buf[256];
    short i;
    short ovr;
    register char *ptr;

    buf[0] = 0;
    sscanf(Current+E.Column,av[1],buf,buf,buf,buf,buf,buf,buf);
    if (String)
	free(String);
    String = (char *)malloc(strlen(buf)+1);
    strcpy(String,buf);
    title(String);
}

movetocursor()
{
    Move(Rp, XTbase+(E.Column-E.Topcolumn)*Xsize, YTbase+(E.Line-E.Topline)*Ysize);
}

makeroom(n)
{
    register ubyte **Newlist;

    if (E.Lines >= E.Maxlines) {
	Newlist = (ubyte **)allocl(E.Maxlines + n);
	if (Newlist) {
	    bmovl(E.List, Newlist, E.Maxlines);
	    FreeMem(E.List, sizeof(char *) * E.Maxlines);
	    E.List = Newlist;
	    E.Maxlines += n;
	    return(1);
	} else {
	    nomemory();
	}
	return(0);
    }
    return(1);
}

SHAR_EOF
#	End of shell archive
exit 0