[comp.sources.amiga] DME

ain@j.cc.purdue.edu (Patrick White) (01/13/88)

Program Name:	DME
Submitted By:	dillon%cory.Berkeley.EDU@ucbvax.berkeley.edu (Matt Dillon)
Summary:	DME is Matt Dillon's editor.  Features multiple windows and
		key mapping among other things... read the docs (part 2 of
		the binary posting) as they explain it much better than I
		can in a line or two.
Poster Boy:  Pat White  (ain@j.cc.purdue.edu)
Untested.

NOTES:
   Binary version posted on comp.binaries.amiga.
   Docs posted with binary version (part 2).
   Didn't test it.


-- Pat White   (co-moderator comp.sources/binaries.amiga)
UUCP: j.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM   PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906

========================================

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	defs.h
#	command.c
#	filereq.c
#	globals.c
#	keyboard.c
#	main.c
# This archive created: Tue Jan 12 02:23:20 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Makefile'" '(1080 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'

#   Note:  In terms of compiling, if you do not have my latest
#   support library you may have to do some hacking to get the
#   code to link.
#
#   The precompiled symbol table, SYMBOLS.M, is *only* the AMIGA includes
#   .. */*.h (exec/*.h, etc....).  When generating a precompiled symbol
#   table remember to use the +L compiler option.

CFLAGS= +L +Ivd0:include/symbols.m
OBJS= globals.o command.o keyboard.o main.o text1.o text2.o subs.o refs.o filereq.o menu.o
ASMS= globals.asm command.asm keyboard.asm main.asm text1.asm text2.asm subs.asm refs.asm filereq.asm menu.asm
SRCS= globals.c command.c keyboard.c main.c text1.c text2.c subs.c refs.c filereq.c menu.c
HDR=  defs.h

.c.o:
    cc $(CFLAGS) -o $@ $*.c

.c.asm:
    cc $(CFLAGS) -A -o ram:$@ $*.c


all: $(OBJS)
    ln +Q $(OBJS) -lsup32 -lc32 -O ram:dme

asm: $(ASMS)

arc:
    -delete ram:dme.arc
    arc a ram:dme DME.DOC ram:dme dme.info README sample.edrc macros.edrc dme.refs.1 dme.refs.2

srcarc:
    -delete ram:dmesrc.arc
    arc a ram:dmesrc Makefile $(SRCS) $(HDR)

clean:
    -delete $(OBJS) ram:dme

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'defs.h'" '(2078 characters)'
if test -f 'defs.h'
then
	echo shar: "will not over-write existing file 'defs.h'"
else
cat << \!Funky!Stuff! > 'defs.h'

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

#include <exec/types.h>
#include <exec/io.h>
#include <devices/keymap.h>
#include <devices/console.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <typedefs.h>
#include "xmisc.h"

#define MAXTOGGLE   256
#define QMOVE	    (0x6B|0x80)

#define COLT(n)  (XTbase + (n) * Xsize)
#define ROWT(n)  (YTbase + (n) * Ysize)
#define COL(n)   (Xbase  + (n) * Xsize)
#define ROW(n)   (Ybase  + (n) * Ysize)

typedef unsigned char ubyte;
typedef struct WBStartup  WBS;
typedef struct DiskObject DISKOBJ;

extern WBS	*Wbs;
extern DISKOBJ	*Do;

extern short Xsize, Ysize;
extern short XTbase, YTbase;
extern short Rows, Columns;
extern short Xbase, Ybase;
extern short Xpixs, Ypixs;
extern ubyte *av[];
extern char Wdisable;

typedef struct _ED {
    struct _ED *next, **prev;
    WIN *Win;
    long Topline, Topcolumn;
    long Line, Column;
    long Lines, Maxlines;
    ubyte **List;
    ubyte Name[64];
    ubyte Wtitle[130];
    char Modified;
    ubyte Tabstop;
    ubyte Margin;
    char Insertmode;
    char Wordwrap;
    char iconmode;	    /*	window in icon mode		    */
    short Winx; 	    /*	save state of non-icon window	    */
    short Winy;
    short Winwidth;
    short Winheight;
    short IWinx, IWiny;     /*	save state of icon window	    */
    long  dirlock;	    /* directory lock			    */
} ED;

extern long  BSline, BEline;
extern short BSchar, BEchar;
extern ED    *BEp;


#ifndef NULL
#define NULL 0
#endif
#ifdef E
#undef E
#endif

extern ED *Ep, *Base;
extern char	Overide;
extern char	Savetabs;
extern char	memoryfail, Nsu, Msgchk;
extern ubyte	CtlC;
extern ubyte	Current[256];
extern ubyte	Space[32];
extern short	Clen;
extern char	Abortcommand, MShowTitle;
extern char	Comlinemode;
extern RP	*Rp;
extern WIN	*Win;
extern char	*Partial;
extern char	*String;

extern ubyte	*allocl(), *allocb();
extern char	*keyspectomacro();
extern char	*menutomacro();

extern void	search_operation();
extern void	*malloc(), *AllocMem(), *strcpy();

extern long	Dirlock;

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'command.c'" '(11555 characters)'
if test -f 'command.c'
then
	echo shar: "will not over-write existing file 'command.c'"
else
cat << \!Funky!Stuff! > '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 scanf'd variable
 * $filename	     macro insert current file name
 *
 * Any string arguments not part of a command are considered to be typed
 * text.
 */

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

#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		*/

extern char *breakout();

typedef struct {
   char *name;	    /* command name	  */
   ubyte args;
   ubyte flags;
   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(),      do_arpload(),   do_arpsave();

extern int  do_menu(), do_menuclear(), do_menuadd(), do_menudel(),
	    do_menudelhdr(), do_menuon(), do_menuoff();

/*
 *  WLEFT/WRIGHT will check command line mode themselves, and thus can
 *  be marked flags=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[] = {
    "arpload",       0,      0, do_arpload,
    "arpsave",       0,      0, do_arpsave,
    "back",          0, CF_COK, do_bs,
    "backtab",       0, CF_COK, 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, CF_COK, do_bs,
    "bsave",         1, CF_COK, do_bsave,
    "bsource",       0,      0, do_bsource,
    "chfilename",    1,      0, do_chfilename,
    "del",           0, CF_COK, do_del,
    "deline",        0,      0, do_deline,
    "down",          0,      0, do_down,
    "downadd",       0,      0, do_downadd,
    "esc",           0, CF_COK, do_esc,
    "escimm",        1, CF_PAR, 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, CF_COK, do_findstr,  /* checks com name for mode */
    "first",         0, CF_COK, do_firstcolumn,
    "firstnb",       0, CF_COK, do_firstnb,
    "goto",          1,      0, do_goto,
    "height",        1, CF_COK, do_windowparm,
    "iconify",       0,      0, do_iconify,
    "if",            2, CF_COK, do_if,
    "ifelse",        3, CF_COK, do_if,
    "insertmode",    1, CF_COK, do_insertmode,
    "insfile",       1,      0, do_edit,
    "insline",       0,      0, do_insline,
    "join",          0,      0, do_join,
    "last",          0, CF_COK, do_lastcolumn,
    "left",          0, CF_COK, do_left,
    "leftedge",      1, CF_COK, do_windowparm,
    "map",           2, CF_COK, do_map,
    "margin",        1, CF_COK, do_margin,
    "menuon",        0,      0, do_menuon,
    "menuoff",       0,      0, do_menuoff,
    "menuadd",       3,      0, do_menuadd,
    "menudel",       2,      0, do_menudel,
    "menudelhdr",    1,      0, do_menudelhdr,
    "menuclear",     0,      0, do_menuclear,
    "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, CF_COK, do_recall,
    "ref",           0,      0, do_refs,
    "reformat",      0,      0, do_reformat,
    "remeol",        0, CF_COK, do_remeol,
    "repeat",        2, CF_COK, do_repeat,
    "repstr",        1, CF_COK, do_findstr,
    "resettoggle",   1, CF_COK, do_toggle,
    "resize",        2,      0, do_resize,
    "return",        0, CF_COK, do_return,   /* special meaning in command line mode */
    "right",         0, CF_COK, do_right,
    "saveas",        1, CF_COK, do_saveas,
    "savemap",       1, CF_COK, do_savemap,  /* checks com name for mode */
    "saveold",       0, CF_COK, do_save,
    "savesmap",      1, CF_COK, do_savemap,
    "savetabs",      1, CF_COK, do_savetabs,
    "scanf",         1, CF_COK, do_scanf,
    "screenbottom",  0,      0, do_screenbottom,
    "screentop",     0,      0, do_screentop,
    "scrollup",      0,      0, do_scrollup,
    "scrolldown",    0,      0, do_scrolldown,
    "settoggle",     1, CF_COK, do_toggle,
    "source",        1, CF_COK, do_source,
    "split",         0,      0, do_split,
    "tab",           0, CF_COK, do_tab,
    "tabstop",       1, CF_COK, do_tabstop,
    "tlate",         1, CF_COK, do_tlate,
    "tmpheight",     1, CF_COK, do_windowparm,
    "tmpwidth",      1, CF_COK, do_windowparm,
    "toggle",        1, CF_COK, do_toggle,
    "tomouse",       0,      0, do_tomouse,
    "top",           0,      0, do_top,
    "topedge",       1, CF_COK, do_windowparm,
    "unblock",       0,      0, do_block,
    "unmap",         1, CF_COK, do_unmap,
    "up",            0,      0, do_up,
    "while",         2, CF_COK, do_if,
    "width",         1, CF_COK, do_windowparm,
    "wleft",         0, CF_COK, do_wleft,
    "wordwrap",      1, CF_COK, do_wordwrap,
    "wright",        0, CF_COK, 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->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 */
			}
			(*comm->func)(-1);
		    }
		    if (Abortcommand)
			goto fail;
		    goto loop;
		}
	    }
	}

	/* 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);
		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()
{
    register ubyte *ptr = av[1];
    register unsigned long n;
    char buf1[256];
    char buf2[256];

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


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'filereq.c'" '(1746 characters)'
if test -f 'filereq.c'
then
	echo shar: "will not over-write existing file 'filereq.c'"
else
cat << \!Funky!Stuff! > 'filereq.c'

/*
 *  ARP interface (ARPLOAD, ARPSAVE)
 */

#include "defs.h"

void
do_arpload()
{
    char file[64];
    char dir[64];

    strcpy(file, Ep->Name);
    dir[0] = 0;
    if (arpreq("NEWFILE", file, dir, NULL)) {
	fixfile(file,dir);
	av[0] = (ubyte *)"n";
	av[1] = (ubyte *)file;
	do_edit();
    }
}

void
do_arpsave()
{
    char file[64];
    char dir[64];

    strcpy(file, Ep->Name);
    dir[0] = 0;

    if (arpreq("SAVEAS", file, dir, NULL)) {
	fixfile(file,dir);
	av[1] = (ubyte *)file;
	do_saveas();
    }
}

fixfile(file,dir)
char *file,*dir;
{
    register char *ptr;
    register short hasdev = 0;
    register short len = strlen(dir);
    for (ptr = file; *ptr; ++ptr) {
	if (ptr[0] == ':')
	    hasdev = 1;
    }
    if (!hasdev) {
	movmem(file,file+len,strlen(file)+1);
	movmem(dir,file,len);
    }
}

#asm

		;   arpreq(hail,file,dir,window)

		FAR DATA
		FAR CODE

		public	_arpreq
		public	_LVOOldOpenLibrary
		public	_LVOCloseLibrary
		public	_SysBase

_LVOFileRequest equ	-294

arp_name_text	dc.b 'arp.library',0

fs		ds.l	1   ;hailing text
		ds.l	1   ;file name
		ds.l	1   ;directory
		ds.l	1   ;window requesting
		ds.w	1   ;LONG Align, idiots!  set to 0
		ds.l	1   ;func for wildcards
		ds.l	1   ;func to call w/intuimessages

_arpreq:
		lea.l	fs,A0
		movem.l 4(sp),D0-D3             ;setup fields
		movem.l D0-D3,(A0)
		clr.w	fs+16
		move.l	_SysBase,A6

		lea.l	arp_name_text,a1	;open library
		jsr	_LVOOldOpenLibrary(a6)
		tst.l	d0
		beq.s	done
		move.l	d0,a6
		lea.l	fs,a0
		jsr	_LVOFileRequest(A6)     ;call requestor
		move.l	D0,-(sp)                ;return value
		move.l	A6,A1			;CloseLibrary(arpbase)
		move.l	_SysBase,A6
		jsr	_LVOCloseLibrary(A6)
		move.l	(sp)+,D0                ;return value
done		rts

#endasm


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'globals.c'" '(912 characters)'
if test -f 'globals.c'
then
	echo shar: "will not over-write existing file 'globals.c'"
else
cat << \!Funky!Stuff! > 'globals.c'

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

#include "defs.h"

ED *Ep; 		/* Current Window		*/
ED *Base;		/* Doubly linked list of Files	*/

char	Nsu;		/* Used in formatter to disable screen updates	*/
char	Msgchk; 	/* Force message queue check for break		*/
ubyte	CtlC;		/* Keycode for 'c'                              */
char	Savetabs;	/* SaveTabs mode?				*/
char	memoryfail;	/* out of memory flag				*/
ubyte	Current[256];	/* Current Line buffer and length		*/
ubyte	Space[32] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
		    32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32 };
short	Clen;
char	*Partial;	/* Partial command line when executing ESCIMM	*/
char	*String;	/* String Capture variable			*/

char	Comlinemode;
char	Abortcommand;

long	BSline = -1;
long	BEline = -1;
short	BSchar;
short	BEchar;

ED	*BEp;

long	Dirlock;	/* base directory lock				*/

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'keyboard.c'" '(14427 characters)'
if test -f 'keyboard.c'
then
	echo shar: "will not over-write existing file 'keyboard.c'"
else
cat << \!Funky!Stuff! > '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) {
	im->Qualifier &= ~IEQUALIFIER_REPEAT;
	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  ), /*34-36*/
    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];
    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)
		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[34] |= i; break;
	    case ')': if (i > 0x3A) lname[35] |= i; break;
	    case '/': if (i > 0x3A) lname[36] |= i; break;
	    case '*': if (i > 0x3A) lname[37] |= i; break;
	    case '-': if (i > 0x3A) lname[22] |= i; break;
	    case '+': if (i > 0x3A) lname[38] |= 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 code, qual;
	get_codequal("c", &code, &qual);
	CtlC = code;
    }
}


ubyte *
cqtoa(code, qual)
register int 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;
register ubyte *str;
{
    register 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:
    if (strlen(str) != 1) {           /* long name   */
	register short shift = 24;
	register long mult = 0;

	*pqual = qual;
	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;
		*pqual = qual;
		return(1);
	    }
	}
	for (i = 0; i < sizeof(cstoa); ++i) {
	    if (*str == cstoa[i]) {
		*pcode = i;
		*pqual = qual|QUAL_SHIFT;
		return(1);
	    }
	}
    }
    return(0);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'main.c'" '(15834 characters)'
if test -f 'main.c'
then
	echo shar: "will not over-write existing file 'main.c'"
else
cat << \!Funky!Stuff! > 'main.c'

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

#include "defs.h"

#define IDCMPFLAGS   CLOSEWINDOW|NEWSIZE|RAWKEY|MOUSEBUTTONS|ACTIVEWINDOW|MOUSEMOVE|MENUPICK

extern WIN *OpenWindow();
extern char *menu_cmd();

NW Nw = {
   0, 1, 0  , 0  , -1, -1,  /*	width, height filled in by program */
   IDCMPFLAGS,
   ACTIVATE|WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|RMBTRAP,
   NULL, NULL, (ubyte *)"   WAIT   ",
   NULL, NULL,
   32, 32, -1, -1,
   WBENCHSCREEN
};

short Sharedrefs;
short Oldtlen = 999;	  /*  Old Title Length	  */
struct MsgPort *Sharedport;
DISKOBJ *Do;
WBS	*Wbs;

WIN *Win;
RP  *Rp;

short Xsize,  Ysize;		/* font character sizes        */
short Rows,  Columns;		/* character rows/cols available       */
short Xbase,  Ybase;		/* offset pixel base for display       */
short XTbase,YTbase;		/* used for text display	       */
short Xpixs,  Ypixs;		/* actual # X/Y pixels available       */
short Mx, My;

ubyte *av[8];
char Quitflag;
char Overide;
char SizeOveride;
char Wdisable = 1;		/* Disable icon save		       */
char MShowTitle, MForceTitle;
short Nwwidth, Nwheight, Nwtopedge, Nwleftedge, Nwtmpwidth, Nwtmpheight;

int Enable_Abort;

extern WIN   *opensharedwindow();
extern IMESS *GetMsg();

static char *Ffile;

main(mac, mav)
char *mav[];
{
    register IMESS *im;     /*	intuition message	    */
    char nf, ni;	    /*	# files on command line     */
    char notdone;	    /*	for endless loop	    */
    char iawm = 0;	    /*	overide mouse buttons	    */
    char dontwait = 0;	    /*	don't wait for a message    */
    short i;
    short Code;

    if (!openlibs(INTUITION_LIB|GRAPHICS_LIB))
	exiterr("cannot open intuition or graphics library");
    {
	SCR scr;
	GetScreenData(&scr, sizeof(scr), WBENCHSCREEN, NULL);
	Nw.Width = (scr.Width > 640) ? 640 : scr.Width;
	Nw.Height= scr.Height - ((scr.Height > 200) ? 40 : 1);
    }

    init_command();

    Nwwidth	= Nw.Width;	/*  Parameters for new windows	*/
    Nwheight	= Nw.Height;
    Nwtopedge	= Nw.TopEdge;
    Nwleftedge	= Nw.LeftEdge;

    Enable_Abort= 0;		/*  disable break		*/

    String  = (char *)malloc(1);        /*  initialize scanf variable   */
    *String = 0;


    if (mac == 0) {             /*  WORKBENCH STARTUP           */
	long oldlock;

	Wdisable = 0;		/*  allow icon save		*/
	Wbs = (WBS *)mav;
	if (!openlibs(ICON_LIB))
	    exiterr("unable to open icon library");
	oldlock = CurrentDir(Wbs->sm_ArgList[0].wa_Lock);   /* Tool */
	Do = GetDiskObject(Wbs->sm_ArgList[0].wa_Name);
	CurrentDir(oldlock);
	if (Do == NULL)
	    exiterr("unable to get disk object");
	mac = 99;
    }

    resethash();

    if (Do) {
	ops(Do->do_ToolTypes, 1);
	nf = Wbs->sm_NumArgs - 1;
	Dirlock = Wbs->sm_ArgList[0].wa_Lock;
    } else {
	nf = ops(mav+1, 0);
    }

    for (ni = 0, i = 1; i < mac; ++i) {
	register char *str;
	register DISKOBJ *dso;
	long oldlock;
	if (Wbs) {
	    if (i > nf)
		break;
	    str = Wbs->sm_ArgList[i].wa_Name;
	    oldlock = CurrentDir(Wbs->sm_ArgList[i].wa_Lock);
	    if (dso = GetDiskObject(Wbs->sm_ArgList[i].wa_Name)) {
		ops(dso->do_ToolTypes, 1);
		FreeDiskObject(dso);
	    }
	    Dirlock = CurrentDir(oldlock);
	} else {
	    str = mav[i];
	    if (*str == '-')
		continue;
	}
	do_newwindow(nf > 1, ni * 10);
	++ni;
	av[0] = (ubyte *)"newfile";
	av[1] = (ubyte *)str;
	do_edit();
	MForceTitle = 1;
	window_title();
    }
    if (nf == 0)                     /* no files to edit */
	do_newwindow(nf > 1, ni * 10);

    mountrequest(0);
    av[0] = NULL;
    av[1] = (ubyte *)"s:.edrc";
    do_source();
    av[0] = NULL;
    av[1] = (ubyte *)((Ffile) ? Ffile : ".edrc");
    do_source();
    mountrequest(1);
    title("DME V1.29  \251Copyright 1988 Matthew Dillon,  All Rights Reserved                  ");
loop:
    if (!Ep->iconmode)
	text_cursor(1);
    for (notdone = 1; !Quitflag && notdone;) {
	char mmove = 0;
	short mqual;

	if (!Ep->iconmode)
	    window_title();
	if (dontwait)
	    --dontwait;
	else
	    WaitPort(Win->UserPort);

	/*
	 *  NOTE: due to operation of breakcheck(), the userport signal
	 *  may not be set even if there are messages pending.
	 */

	while (im = (IMESS *)GetMsg(Win->UserPort)) {
	    Msgchk = 1;
	    Abortcommand = 0;
	    Code = im->Code;
	    if (im->IDCMPWindow != Win) {
		Overide = 0;
		if (Comlinemode)
		    escapecomlinemode();
		text_sync();
		MShowTitle = 0;
		if (!Ep->iconmode)
		    window_title();
		if (text_switch(im->IDCMPWindow) == 0) {
		    ReplyMsg(im);
		    continue;
		}
	    }
	    Mx = im->MouseX;
	    My = im->MouseY;
	    switch(im->Class) {
	    case NEWSIZE:
		if (!Ep->iconmode) {
		    if (Comlinemode)
			escapecomlinemode();
		    set_window_params();
		    if (!text_sync())
		       text_redisplay();
		    text_cursor(1);
		}
		break;
	    case MOUSEBUTTONS:
		switch(Code) {
		case SELECTDOWN:
		case MENUDOWN:
		    if (Ep->iconmode || iawm) {
			uniconify();
			break;
		    }
		    ReportMouse(-1, Win);
		    uniconify();
		    text_cursor(0);
		    keyctl(NULL, im->Code|0x80, im->Qualifier);
		    text_cursor(1);
		    break;
		case SELECTUP:
		case MENUUP:
		    ReportMouse(0, Win);
		    break;
		}
		break;
	    case RAWKEY:
		if ((im->Code & 0x80) == 0) {
		    if (Ep->iconmode) {
			uniconify();
			break;
		    }
		    text_cursor(0);
		    keyctl(im, im->Code, im->Qualifier);
		    text_cursor(1);
		}
		break;
	    case MENUPICK:
		{
		    register char *str = menu_cmd(im);
		    if (str) {
			str = strcpy(malloc(strlen(str)+1), str);
			text_cursor(0);
			do_command(str);
			free(str);
			text_cursor(1);
		    }
		}
		break;
	    case CLOSEWINDOW:
		if (Comlinemode)
		    escapecomlinemode();
		text_sync();
		notdone = 0;
		break;
	    case ACTIVEWINDOW:
		if (!Ep->iconmode)
		    iawm = 1;
		break;
	    case MOUSEMOVE:
		mmove = 1;
		mqual = im->Qualifier;
		break;
	    }
	    if (im)
		ReplyMsg(im);
	    if (notdone == 0 || Quitflag) {
		dontwait = 2;
		goto boom;
	    }
	}
	iawm = 0;
	if (mmove) {
	    uniconify();
	    mmove = 0;
	    text_cursor(0);
	    keyctl(NULL, QMOVE, mqual);
	    text_cursor(1);
	}
	closesharedwindow(NULL);
    }
boom:
    if (Ep->Modified && !Overide) {
	uniconify();
	Overide = 1;
	title("*** File has been modified ***");
	Quitflag = 0;
	goto loop;
    }
    SetWindowTitles(Win, "", -1);
    text_uninit();                        /* uninitialize text portion    */
    closesharedwindow(Win);
    if (Base) {
	Quitflag = 0;
	Win = Ep->Win;			  /* make arbitrary other window act. */
	Rp = Win->RPort;
	if (!Ep->iconmode)
	    set_window_params();
	text_load();
	MShowTitle = 0;
	goto loop;
    }
    closesharedwindow(NULL);
    if (Do)
	FreeDiskObject(Do);
    closelibs(-1);
    dealloc_hash();
}

do_iconify()
{
    if (!Comlinemode)
	iconify();
}

do_tomouse()
{
    text_position((Mx-Xbase)/Xsize, (My-Ybase)/Ysize);
}

iconify()
{
    if (!Ep->iconmode) {
	Ep->Winx      = Win->LeftEdge;
	Ep->Winy      = Win->TopEdge;
	Ep->Winwidth  = Win->Width;
	Ep->Winheight = Win->Height;
	Nw.Height = 10;
	Nw.Width  = 20 + 5*8 + strlen(Ep->Name)*8;
	Nw.LeftEdge= Ep->IWinx;
	Nw.TopEdge = Ep->IWiny;
	if (Nw.LeftEdge + Nw.Width > Win->WScreen->Width)
	    Nw.LeftEdge = Win->WScreen->Width - Nw.Width;
	if (Nw.TopEdge + Nw.Height > Win->WScreen->Height)
	    Nw.TopEdge = Win->WScreen->Height - Nw.Height;
	Nw.Title = Ep->Wtitle;
	Nw.Flags &= ~(WINDOWSIZING|WINDOWDEPTH);
	Nw.Flags |= BORDERLESS;
	sprintf(Ep->Wtitle, "%s %s    ", Ep->Name, ((Ep->Modified) ? "(mod)":""));
	closesharedwindow(Win);
	Win = Ep->Win = opensharedwindow(&Nw);
	Nw.Flags |= WINDOWSIZING|WINDOWDEPTH;
	Nw.Flags &= ~BORDERLESS;
	Rp = Win->RPort;
    }
    Ep->iconmode = 1;
}

uniconify()
{
    if (Ep->iconmode) {
	Ep->IWinx = Win->LeftEdge;
	Ep->IWiny = Win->TopEdge;
	closesharedwindow(Win);
	Nw.LeftEdge = Ep->Winx;
	Nw.TopEdge  = Ep->Winy;
	Nw.Width    = Ep->Winwidth;
	Nw.Height   = Ep->Winheight;
	Nw.Title = Ep->Wtitle;
	Win = Ep->Win = opensharedwindow(&Nw);
	menu_strip(Win);
	Rp = Win->RPort;
	set_window_params();
	if (!text_sync())
	    text_redisplay();
	text_cursor(1);
	MShowTitle = 0;
	window_title();
    }
    Ep->iconmode = 0;
}


do_newwindow(makesmall, deltaheight)
{
    WIN *win;
    int msadj = makesmall;

    if (SizeOveride)
	msadj = 0;
    if (Ep)
	text_sync();
    Nw.Title = (ubyte *)"    OK    ";
    Nw.Width = (Nwtmpwidth) ? Nwtmpwidth : Nwwidth;
    Nw.Height= (Nwtmpheight)? Nwtmpheight: Nwheight;
    Nwtmpwidth = Nwtmpheight = 0;
    Nw.LeftEdge = Nwleftedge;
    Nw.TopEdge	= Nwtopedge;
    if (msadj > 0) {                    /* deltaheight must be valid    */
	Nw.TopEdge = deltaheight + 16;
	Nw.LeftEdge= 10*8;
	Nw.Flags &= ~ACTIVATE;
	Nw.Width = 40*8;
	Nw.Height= 10*8;
	if (Nw.TopEdge + Nw.Height > 200)
	    Nw.TopEdge = deltaheight = 200 - Nw.Height;
    }
    win = opensharedwindow(&Nw);
    menu_strip(win);
    Nw.Flags |= ACTIVATE;
    if (win) {
	Win = win;			/* set new window   */
	Rp = Win->RPort;
	set_window_params();
	text_init();                    /* initialize       */
	text_load();
	if (makesmall != -1)            /* if deltaheight valid */
	    Ep->IWiny = deltaheight + 16;
    }
}

WIN *
TOpenWindow(nw)
NW *nw;
{
    WIN *win;

    while ((win = OpenWindow(nw)) == NULL) {
	if (nw->Width < 50 || nw->Height < 50)
	    break;
	nw->Width -= 10;
	nw->Height-= 10;
    }
    return(win);
}


WIN *
opensharedwindow(nw)
NW *nw;
{
    WIN *win;

    if (Sharedport)
	nw->IDCMPFlags = NULL;
    else
	nw->IDCMPFlags = IDCMPFLAGS;
    win = TOpenWindow(nw);
    if (win) {
	if (Sharedport) {
	    win->UserPort = Sharedport;
	    ModifyIDCMP(win, IDCMPFLAGS);
	} else {
	    Sharedport = win->UserPort;
	}
	++Sharedrefs;
    }
    return(win);
}


closesharedwindow(win)
WIN *win;
{
    static WIN *wunlink;
    register IMESS *im;
    char notoktoclosenow = 0;

    if (win) {
	SetWindowTitles(win, "", -1);
	ClearMenuStrip(win);
	Forbid();
	win->UserPort = NULL;
	ModifyIDCMP(win, GADGETUP);     /* NEVER occurs */

	notoktoclosenow = 1;

	Permit();
	if (notoktoclosenow) {
	    win->UserData = (char *)wunlink;
	    wunlink = win;
	} else {
	    CloseWindow(win);
	}
	--Sharedrefs;
    } else {
	if (Sharedrefs == 0 && Sharedport) {
	    DeletePort(Sharedport);
	    Sharedport = NULL;
	}
	for (win = wunlink; win; win = wunlink) {
	    wunlink = (WIN *)win->UserData;
	    CloseWindow(win);
	}
	wunlink = NULL;
    }
}


getyn(text)
char *text;
{
    int result;
    ITEXT *body, *pos, *neg;

    body = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    pos  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    neg  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
    bzero(body, sizeof(ITEXT));
    bzero(pos , sizeof(ITEXT));
    bzero(neg , sizeof(ITEXT));
    body->BackPen = pos->BackPen = neg->BackPen = 1;
    body->DrawMode= pos->DrawMode= neg->DrawMode= AUTODRAWMODE;
    body->LeftEdge = 10;
    body->TopEdge  = 12;
    body->IText    = (ubyte *)text;
    pos->LeftEdge = AUTOLEFTEDGE;
    pos->TopEdge = AUTOTOPEDGE;
    pos->IText = (ubyte *)"OK";
    neg->LeftEdge = AUTOLEFTEDGE;
    neg->TopEdge = AUTOTOPEDGE;
    neg->IText = (ubyte *)"CANCEL";
    result = AutoRequest(Win,body,pos,neg,0,0,320,58);
    FreeMem(body, sizeof(ITEXT));
    FreeMem(pos , sizeof(ITEXT));
    FreeMem(neg , sizeof(ITEXT));
    return(result);
}


title(buf)
char *buf;
{
    SetWindowTitles(Win, buf, -1);
    Oldtlen = 999;
    MShowTitle = 3;
}

window_title()
{
    register int len, maxlen;

    if (memoryfail) {
	title(" -- NO MEMORY -- ");
	memoryfail = 0;
	text_redisplay();
    }
    if (MForceTitle) {
	MShowTitle = 0;
	MForceTitle = 0;
    }
    if (MShowTitle) {
	--MShowTitle;
	return(0);
    }
    {
	register char *mod;
	mod = (Ep->Modified) ? " (modified)" : "          ";
	sprintf(Ep->Wtitle, "%3ld/%-3ld %3ld %s%s  ", text_lineno(), text_lines(), text_colno()+1, text_name(), mod);
	if (!text_imode())
	    strcat(Ep->Wtitle, "Ovr ");
	len = strlen(Ep->Wtitle);
	if (len < Columns && Columns < 128) {
	    bset(Ep->Wtitle+len, Columns - len + 1, ' ');
	    Ep->Wtitle[Columns + 1] = 0;
	}

	Win->Title = Ep->Wtitle;
	SetAPen(Rp, 0);
	SetBPen(Rp, 1);
	Move(Rp, 30, Win->RPort->Font->tf_Baseline+1);
	maxlen = (Win->Width-96)/Win->RPort->Font->tf_XSize;
	if (maxlen < 0)
	    maxlen = 0;
	if (len > maxlen)
	    len = Oldtlen = maxlen;
	if (Oldtlen > maxlen)
	    Oldtlen = maxlen;
	Text(Rp, Ep->Wtitle, len);      /*  No flash                    */
	while (Oldtlen - len >= (int)sizeof(Space)) {
	    Text(Rp, Space, sizeof(Space));
	    Oldtlen -= sizeof(Space);
	}
	if (Oldtlen - len > 0)
	    Text(Rp, Space, Oldtlen - len);
	Oldtlen = len;			/*  Oldtlen might have been <	*/
	SetAPen(Rp, 1);
	SetBPen(Rp, 0);
    }
}

set_window_params()
{
    Xsize = Rp->Font->tf_XSize;
    Ysize = Rp->Font->tf_YSize;
    Xbase = Win->BorderLeft;
    Ybase = Win->BorderTop;
    Xpixs   = Win->Width - Win->BorderRight - Xbase;
    Ypixs   = Win->Height- Win->BorderBottom- Ybase;
    Columns = Xpixs / Xsize;
    Rows    = Ypixs / Ysize;
    XTbase  =  Xbase;
    YTbase  =  Ybase + Rp->Font->tf_Baseline;
}


exiterr(str)
char *str;
{
    if (Output()) {
	Write(Output(),str,strlen(str));
	Write(Output(),"\n",1);
    }
    exit(1);
}


/*
 *  Check break by scanning pending messages in the I stream for a ^C.
 *  Msgchk forces a check, else the check is only made if the signal is
 *  set in the I stream (the signal is reset).
 */

breakcheck()
{
    IMESS *im;
    register struct List *list = &Win->UserPort->mp_MsgList;

    if (Msgchk || (SetSignal(0,0) & (1<<Win->UserPort->mp_SigBit))) {
	Msgchk = 0;
	SetSignal(0,1<<Win->UserPort->mp_SigBit);

	im = (IMESS *)list->lh_Head;
	Forbid();
	for (; im != &list->lh_Tail; im = (IMESS *)im->ExecMessage.mn_Node.ln_Succ) {
	    if (im->Class == RAWKEY && (im->Qualifier & 0xFB) == 0x08 &&
		im->Code == CtlC) {

		Permit();
		SetSignal(SIGBREAKF_CTRL_C,SIGBREAKF_CTRL_C);
		return(1);
	    }
	}
	Permit();
    }
    return(0);
}

breakreset()
{
    SetSignal(0, SIGBREAKF_CTRL_C);
}

/*
 *  leftedge n
 *  topedge  n
 *  width    n
 *  height   n
 *  tmpwidth  n
 *  tmpheight n
 */

void
do_windowparm()
{
    int val = atoi(av[1]);

    if (av[0][0] == 't' && av[0][1] == 'm') {   /*  tmpwidth/tmpheight  */
	if (av[0][3] == 'w')
	    Nwtmpwidth = val;
	if (av[0][3] == 'h')
	    Nwtmpheight= val;
	return;
    }
    switch(av[0][0]) {
    case 'l':
	Nwleftedge = val;
	break;
    case 't':
	Nwtopedge = val;
	break;
    case 'w':
	Nwwidth = val;
	break;
    case 'h':
	Nwheight = val;
	break;
    }
}

/*
 *  resize cols rows
 */

do_resize()
{
    int cols = atoi(av[1]);
    int rows = atoi(av[2]);
    short width = (cols*Win->RPort->Font->tf_XSize) + Win->BorderLeft + Win->BorderRight;
    short height= (rows*Win->RPort->Font->tf_YSize) + Win->BorderTop + Win->BorderBottom;

    if (width < 16 || height < 16 ||
    width > Win->WScreen->Width - Win->LeftEdge ||
    height > Win->WScreen->Height - Win->TopEdge) {
	title ("window too big (try moving to upper left corner and retrying)");
	return(0);
    }
    SizeWindow(Win, width - Win->Width, height - Win->Height);
    Delay(50*2);    /* wait 2 seconds */
}

ops(av, iswb)
register char *av[];
{
    register short nonops;
    register short i;
    register long val;
    register char *str;

    for (i = nonops = 0; str = av[i]; ++i) {
	if (iswb) {
	    if (strncmp(str, "ARG", 3) == 0) {
		while (*str && *str != '-')
		    ++str;
	    }
	}
	if (*str == '-') {
	    val = atoi(str+2);
	    switch(str[1]) {
	    case 'f':
		Ffile = str+2;
		break;
	    case 'b':
		SizeOveride = 1;
		break;
	    case 't':
		Nwtopedge = val;
		break;
	    case 'l':
		Nwleftedge= val;
		break;
	    case 'w':
		SizeOveride = 1;
		Nwwidth   = val;
		break;
	    case 'h':
		SizeOveride = 1;
		Nwheight  = val;
		break;
	    }
	} else {
	    ++nonops;
	}
    }
    return(nonops);
}



!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive

ain@j.cc.purdue.edu (Patrick White) (01/13/88)

Program Name:	DME
Submitted By:	dillon%cory.Berkeley.EDU@ucbvax.berkeley.edu (Matt Dillon)
Summary:	DME is Matt Dillon's editor.  Features multiple windows and
		key mapping among other things... read the docs (part 2 of
		the binary posting) as they explain it much better than I
		can in a line or two.
Poster Boy:  Pat White  (ain@j.cc.purdue.edu)
Untested.

NOTES:
   Binary version posted on comp.binaries.amiga.
   Docs posted with binary version (part 2).
   Didn't test it.


-- Pat White   (co-moderator comp.sources/binaries.amiga)
UUCP: j.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM   PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906

========================================

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	menu.c
#	refs.c
#	subs.c
#	text1.c
#	text2.c
# This archive created: Tue Jan 12 02:23:36 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'menu.c'" '(5316 characters)'
if test -f 'menu.c'
then
	echo shar: "will not over-write existing file 'menu.c'"
else
cat << \!Funky!Stuff! > 'menu.c'

/*
 *  MENU.C
 *
 *  Menu routines... made to take up as little space as possible, and
 *  thus uses many tricks which you should watch out for.
 */

#include "defs.h"

typedef struct {
    ITEM item;
    char *com;
} XITEM;

short Menuoff;
short DoMenuoff;

MENU *Menu;

extern XITEM *ItemAddress();

menu_strip(win)
WIN *win;
{
    if (!Menuoff && Menu) {
	SetMenuStrip(win,Menu);
	Forbid();
	win->Flags &= ~RMBTRAP;
	Permit();
    }
}

menu_off()
{
    register ED *ed;
    if (Menuoff == 0) {
	for (ed = Base; ed; ed = ed->next) {
	    ClearMenuStrip(ed->Win);
	    Forbid();
	    ed->Win->Flags |= RMBTRAP;
	    Permit();
	}
    }
    ++Menuoff;
}

menu_on()
{
    register ED *ed;
    if (Menu && Menuoff == 1) {
	fixmenu();
	for (ed = Base; ed; ed = ed->next) {
	    SetMenuStrip(ed->Win,Menu);
	    Forbid();
	    ed->Win->Flags &= ~RMBTRAP;
	    Permit();
	}
    }
    --Menuoff;
}

do_menuoff()
{
    menu_off();
    ++DoMenuoff;
}

do_menuon()
{
    if (DoMenuoff) {
	--DoMenuoff;
	menu_on();
    }
}

char *
menutomacro(str)
char *str;
{
    char header[64];
    char itembuf[64];
    register short i;
    register char *ptr;
    register MENU *menu;
    register ITEM *item;

    for (i = 0; str[i] && str[i] != '-'; ++i);
    if (str[i] == '-') {
	strncpy(header, str, i);
	header[i] = 0;
	strcpy(itembuf, str + i + 1);
	for (menu = Menu; menu; menu = menu->NextMenu) {
	    if (ncstrcmp(header, menu->MenuName) == 0) {
		for (item = menu->FirstItem; item; item = item->NextItem) {
		    ptr = (char *)((ITEXT *)item->ItemFill)->IText;
		    if (ncstrcmp(itembuf, ptr) == 0) {
			ptr = ((XITEM *)item)->com;
			goto done;
		    }
		}
	    }
	}
    }
    ptr = NULL;
done:
    return(ptr);
}

char *
menu_cmd(im)
IMESS *im;
{
    XITEM *item;
    char *ptr;

    if (item = ItemAddress(Menu, im->Code))
	return(item->com);
    return(NULL);
}

fixmenu()
{
    register MENU *menu;
    register ITEM *item;
    register ITEXT *it;
    register int row, col, maxc, scr;

    col = 0;
    for (menu = Menu; menu; menu = menu->NextMenu) {
	maxc = strlen(menu->MenuName);
	row = 0;
	for (item = menu->FirstItem; item; item = item->NextItem) {
	    it = (ITEXT *)item->ItemFill;
	    item->TopEdge = row;
	    scr = strlen(((ITEXT *)item->ItemFill)->IText);
	    if (scr > maxc)
		maxc = scr;
	    item->Height = 10;
	    row += item->Height;
	}
	maxc = (maxc * 8) + 16;
	for (item = menu->FirstItem; item; item = item->NextItem)
	    item->Width = maxc;
	menu->Width = maxc;
	menu->LeftEdge = col;
	menu->Height = row;
	col += maxc;
    }
}

/*
 *  menuclear
 *  menuadd	header	item	command
 *  menudel	header	item
 *  menudelhdr	header
 */

do_menuclear()
{
    menu_off();
    while (Menu) {
	av[1] = (ubyte *)Menu->MenuName;
	do_menudelhdr();
    }
    menu_on();
}

do_menuadd()
{
    register MENU *menu, **mpr;
    register ITEM *item, **ipr;
    register ITEXT *it;

    menu_off();
    mpr = &Menu;
    for (menu = *mpr; menu; menu = *mpr) {
	if (strcmp(av[1], menu->MenuName) == 0) {
	    ipr = &menu->FirstItem;
	    for (item = *ipr; item; item = *ipr) {
		if (strcmp(av[2], ((ITEXT *)item->ItemFill)->IText) == 0)
		    goto newname;
		ipr = &item->NextItem;
	    }
	    goto newitem;
	}
	mpr = &menu->NextMenu;
    }
newmenu:    /*	create new menu */
    menu = malloc(sizeof(MENU));
    bzero(menu, sizeof(MENU));
    menu->NextMenu = *mpr;
    *mpr = menu;
    menu->Flags = MENUENABLED;
    menu->MenuName = malloc(strlen(av[1])+1);
    strcpy(menu->MenuName, av[1]);
    ipr = &menu->FirstItem;
    *ipr = NULL;
newitem:    /*	create new item */
    it = malloc(sizeof(ITEXT));
    bzero(it, sizeof(ITEXT));
    it->BackPen = 1;
    it->DrawMode = JAM2;
    it->IText = malloc(strlen(av[2])+1);
    strcpy(it->IText, av[2]);
    item = malloc(sizeof(XITEM));
    bzero(item, sizeof(XITEM));
    item->NextItem = *ipr;
    *ipr = item;
    item->ItemFill = (APTR)it;
    item->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
newname:    /*	create new name */
    if (((XITEM *)item)->com)
	free(((XITEM *)item)->com);
    ((XITEM *)item)->com = malloc(strlen(av[3])+1);
    strcpy(((XITEM *)item)->com, av[3]);
    menu_on();
}

do_menudelhdr()
{
    register MENU *menu;
    register MENU **mpr;

    menu_off();
    mpr = &Menu;
    for (menu = *mpr; menu; menu = *mpr) {
	if (strcmp(av[1], menu->MenuName) == 0) {
	    if (menu->FirstItem) {
		while (menu->FirstItem) {
		    av[2] = ((ITEXT *)menu->FirstItem->ItemFill)->IText;
		    if (do_menudel())
			break;
		}
		break;
	    }
	    *mpr = menu->NextMenu;
	    free(menu->MenuName);
	    free(menu);
	    break;
	}
	mpr = &menu->NextMenu;
    }
    menu_on();
}

do_menudel()
{
    register MENU *menu;
    register ITEM *item, **ipr;
    register ITEXT *it;
    short ret = 0;

    menu_off();
    for (menu = Menu; menu; menu = menu->NextMenu) {
	if (strcmp(av[1], menu->MenuName) == 0) {
	    ipr = &menu->FirstItem;
	    for (item = *ipr; item; item = *ipr) {
		it = (ITEXT *)item->ItemFill;
		if (strcmp(av[2], it->IText) == 0) {
		    *ipr = item->NextItem;
		    free(it->IText);
		    free(it);
		    free(((XITEM *)item)->com);
		    free(item);
		    if (!menu->FirstItem) {
			do_menudelhdr();
			ret = 1;
		    }
		    menu_on();
		    return(ret);
		}
		ipr = &item->NextItem;
	    }
	}
    }
    menu_on();
    return(ret);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'refs.c'" '(3782 characters)'
if test -f 'refs.c'
then
	echo shar: "will not over-write existing file 'refs.c'"
else
cat << \!Funky!Stuff! > '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 = Ep->Column; Current[i] == ' '; ++i);     /*  skip spaces     */
    for (j = i       ; ; ++j) {
	if (Current[j] && Current[j] != ' ')
	    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) {
	    if (buf[0]=='#')
		continue;
	    ptr = breakout(&base, &quoted);
	    if (ptr && *ptr && strncmp(ptr, find, strlen(ptr)) == 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);
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'subs.c'" '(4150 characters)'
if test -f 'subs.c'
then
	echo shar: "will not over-write existing file 'subs.c'"
else
cat << \!Funky!Stuff! > '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);
}

ncstrcmp(s1, s2)
register ubyte *s1, *s2;
{
    register ubyte c1, c2;

    for (;;) {
	c1 = *s1;
	c2 = *s2;
	if (c1 >= 'A' && c1 <= 'Z') c1 |= 0x20;
	if (c2 >= 'A' && c2 <= 'Z') c2 |= 0x20;
	if (c1 != c2)
	    break;
	if ((c1|c2) == 0)
	    return(0);
	++s1;
	++s2;
    }
    if (c1 < c2)
	return(-1);
    if (c1 > c2)
	return(1);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'text1.c'" '(16337 characters)'
if test -f 'text1.c'
then
	echo shar: "will not over-write existing file 'text1.c'"
else
cat << \!Funky!Stuff! > 'text1.c'

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

#include "defs.h"

#define nomemory()  { memoryfail = 1; }

char RecallBuf[256];

setpen(line)
{
    register short pen = (Ep == BEp && line >= BSline && line <= BEline) ? 2 : 1;
    if (Comlinemode)
	pen = 1;
    if (pen != Rp->FgPen)
	SetAPen(Rp, pen);
}

text_init()
{
    register ED *e;
    register ED *ep = Ep;

    text_switch(NULL);
    e = (ED *)allocb(sizeof(ED));
    if (e == NULL)
	return(0);
    bzero(e, sizeof(ED));
    e->Win = Win;
    if (ep) {
	e->Insertmode = ep->Insertmode;
	e->Tabstop    = ep->Tabstop;
	e->Wordwrap   = ep->Wordwrap;
    } else {
	e->Insertmode = 1;
	e->Tabstop = 4;
    }
    e->Lines = 1;
    e->Maxlines = 32;
    e->List = (ubyte **)allocl(e->Maxlines);
    e->List[0] = allocb(1);
    e->List[0][0] = Current[0] = Clen = 0;
    e->IWiny = 16;
    e->dirlock = (ep) ? ep->dirlock : Dirlock;
    llink(&Base, e);
    strcpy(e->Name, "unnamed");
    Ep = e;
    text_cursor(1);
    return(1);
}


text_switch(win)
WIN *win;
{
    register ED *e;

    if (win)
	text_sync();
    if (win) {
	for (e = Base; e; e = e->next) {
	    if (e->Win == win) {
		Ep = e;
		Win = win;
		Rp = Win->RPort;
		text_load();
		if (!Ep->iconmode) {
		    set_window_params();
		    window_title();
		}
		return(1);
	    }
	}
	return(0);
    }
}


text_sync()
{
    register ED *ep = Ep;
    char redraw = 0;
    short len;
    ubyte *ptr;

    for (len = strlen(Current) - 1; len >= 0 && Current[len] == ' '; --len)
	Current[len] = '\0';
    Clen = len + 1;
    if (!Comlinemode) {
	if (strlen(ep->List[ep->Line]) != Clen) {
	    if (ptr = allocb(Clen+1)) {
		ep->Modified = 1;
		Overide = 0;
		FreeMem(ep->List[ep->Line], strlen(ep->List[ep->Line])+1);
		ep->List[ep->Line] = ptr;
	    } else {
		nomemory();
		strcpy(Current, ep->List[ep->Line]);
		Clen = strlen(Current);
	    }
	} else {
	    if (strcmp(ep->List[ep->Line], Current)) {
		ep->Modified = 1;
		Overide = 0;
	    }
	}
	strcpy(ep->List[ep->Line], Current);
    }
    if (Nsu == 0) {
	if (ep->Column - ep->Topcolumn >= Columns || ep->Column < ep->Topcolumn) {
	    redraw = 1;
	    ep->Topcolumn = ep->Column - (Columns>>1);
	    if (ep->Topcolumn < 0)
		ep->Topcolumn = 0;
	}
	if (ep->Line - ep->Topline >= Rows || ep->Line < ep->Topline) {
	    redraw = 1;
	    ep->Topline = ep->Line - (Rows>>1);
	    if (ep->Topline < 0)
		ep->Topline = 0;
	}
    }
    while (ep->Column > Clen)
	Current[Clen++] = ' ';
    Current[Clen] = '\0';
    if (redraw)
	text_redisplay();
    return((int)redraw);
}

text_load()
{
    if (Comlinemode)
	return(0);
    strcpy(Current, Ep->List[Ep->Line]);
    Clen = strlen(Current);
    while (Ep->Column > Clen)
	Current[Clen++] = ' ';
    Current[Clen] = '\0';
}

text_colno()
{
    return(Ep->Column);
}

text_lineno()
{
    return(Ep->Line+1);
}

text_lines()
{
    return(Ep->Lines);
}

text_cols()
{
    return((int)Clen);
}

text_imode()
{
    return(Ep->Insertmode);
}

text_tabsize()
{
    return((int)Ep->Tabstop);
}

ubyte *
text_name()
{
    return(Ep->Name);
}

text_uninit()
{
    register int i;
    register ED *ep = Ep;

    freelist(ep->List, ep->Lines);
    FreeMem(ep->List, ep->Maxlines * sizeof(char *));

    if (BEp == ep) {
	BEp = NULL;
	BSline = BEline = -1;
    }
    lunlink(ep);
    FreeMem(ep, sizeof(ED));
    if (Base) {
	Ep = Base;
	text_load();
    } else {
	Ep = NULL;
    }
}

inversemode(n)
{
    if (n) {
	SetAPen(Rp, 3);
	SetDrMd(Rp, JAM2|INVERSVID);
    } else {
	setpen(Ep->Line);
	SetDrMd(Rp, JAM2);
    }
}

text_cursor(n)
{
    movetocursor();
    inversemode(n);
    if (Current[Ep->Column])
	Text(Rp, Current+Ep->Column, 1);
    else
	Text(Rp, " ", 1);
    inversemode(0);
}


text_position(col, row)
{
    register ED *ep = Ep;
    text_sync();
    if (col == 0)
	col = -1;
    ep->Column = ep->Topcolumn + col;
    if (ep->Column > 254)
	ep->Column = 254;
    if (ep->Column < 0)
	ep->Column = 0;
    ep->Line = ep->Topline + row;
    if (ep->Line >= ep->Lines)
	ep->Line = ep->Lines - 1;
    if (ep->Line < 0)
	ep->Line = 0;
    text_load();
    text_sync();
}

displayblock(on)
{
    register long start = Ep->Topline;
    register long lines = BEline - BSline + 1;

    if (start < BSline)
	start = BSline;
    if (!on) {
	BSline = BEline = -1;
	BEp = NULL;
    }
    if (Ep == BEp)
	text_displayseg(start - Ep->Topline, lines);
}

text_redrawblock(ok)
{
    WIN *savewin = NULL;

    if (BEp) {
	if (BEp != Ep) {
	    savewin = Ep->Win;
	    text_switch(BEp->Win);
	}
	if (BSline <= BEline && BSline >= 0 && BEline < Ep->Lines) {
	    if (!ok) {
		BEp = NULL;
		BSline = BEline = -1;
	    }
	    text_displayseg(0, Rows);
	}
	if (savewin)
	    text_switch(savewin);
    }
    if (!ok) {
	BEp = NULL;
	BSline = BEline = -1;
    }
}

text_displayseg(start, n)
{
    register short i, c;
    register ubyte *ptr;
    register ED *ep = Ep;
    char ib;

    if (Nsu)
	return(0);
    for (i = start; i < start + n && i < Rows && ep->Topline + i < ep->Lines; ++i) {
	if (Comlinemode) {
	    if (ep->Topline + i != ep->Line)
		continue;
	    ptr = Current;
	    SetAPen(Rp, 1);
	} else {
	    ptr = ep->List[ep->Topline + i];
	    setpen(i+ep->Topline);
	}
	for (c = ep->Topcolumn; c && *ptr; ++ptr, --c);
	c = strlen(ptr);
	if (c) {
	    Move(Rp, COLT(0), ROWT(i));
	    Text(Rp, ptr, (c > Columns) ? Columns : c);
	}
    }
}

text_redisplay()
{
    if (Nsu)
	return(0);
    SetAPen(Rp, 0);
    if (Comlinemode)
	RectFill(Rp, COL(0), ROW(Rows-1), Xbase+Xpixs, Ybase+Ypixs);
    else
	RectFill(Rp, Xbase, Ybase, Xbase + Xpixs, Ybase + Ypixs);
    text_displayseg(0,Rows);
}

text_redisplaycurrline()
{
    int row = Ep->Line - Ep->Topline;

    if (Nsu)
	return(0);
    SetAPen(Rp, 0);
    RectFill(Rp, COL(0), ROW(row), Xbase+Xpixs, ROW(row+1)-1);
    text_displayseg(row, 1);
}

text_write(str)
ubyte *str;
{
    register short len = strlen(str);
    register short i;
    register ED *ep = Ep;

    if (Clen + len >= 255) {
	text_sync();
	text_load();
    }
    if (ep->Insertmode == 0) {
	i = len;
	if (ep->Column + len < 255) {
	    bmov(str, Current + ep->Column, len);
	    if (ep->Column + len >= Clen)
		Clen = ep->Column + len;
	    Current[Clen] = 0;
	    goto bin;
	}
	goto ok;
    }
    if (Clen + len < 255) {
	bmov(Current + ep->Column, Current + ep->Column + len, Clen+1-ep->Column);
	bmov(str, Current + ep->Column, len);
	Clen += len;
	ScrollRaster(Rp, -len * Xsize, 0 ,
		COL(ep->Column - ep->Topcolumn), ROW(ep->Line - ep->Topline),
		COL(Columns) - 1, ROW(ep->Line - ep->Topline + 1) - 1
	);
	i = (ep->Column - ep->Topcolumn + len > Columns) ? Columns - ep->Column + ep->Topcolumn : len;
bin:
	setpen(ep->Line);
	Move(Rp, COLT(ep->Column - ep->Topcolumn), ROWT(ep->Line - ep->Topline));
	Text(Rp, str, i);
	ep->Column += len;
	if (ep->Column - ep->Topcolumn >= Columns)
	    text_sync();
    }
ok:
    if (Comlinemode == 0 && ep->Wordwrap)
	do_reformat(0);
}


do_up()
{
    if (Ep->Line) {
	text_sync();
	--Ep->Line;
	text_load();
	if (Ep->Line < Ep->Topline) {
	    if (Nsu == 0) {
		ScrollRaster(Rp,0,-Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
		--Ep->Topline;
		text_displayseg(0, 1);
	    }
	}
    } else {
	Abortcommand = 1;
    }
}

do_scrolldown()
{
    if (Ep->Topline + Rows < Ep->Lines) {
	if (Nsu == 0) {
	    text_sync();
	    ScrollRaster(Rp,0,Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
	    ++Ep->Topline;
	    ++Ep->Line;
	    text_load();
	    text_displayseg(Rows-1, 1);
	}
    } else {
	Abortcommand = 1;
    }
}

do_scrollup()
{
    if (Ep->Topline) {
	if (Nsu == 0) {
	    text_sync();
	    ScrollRaster(Rp,0,-Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
	    --Ep->Topline;
	    --Ep->Line;
	    text_load();
	    text_displayseg(0, 1);
	}
    } else {
	Abortcommand = 1;
    }
}

do_down()
{
    if (Ep->Line + 1 < Ep->Lines) {
	text_sync();
	++Ep->Line;
	text_load();
	if (Ep->Line - Ep->Topline >= Rows) {
	    if (Nsu == 0) {
		ScrollRaster(Rp,0,Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
		++Ep->Topline;
		text_displayseg(Rows-1, 1);
	    }
	}
    } else {
	Abortcommand = 1;
    }
}

/*
 *  PAGEUP
 *  PAGEDOWN
 *  PAGESET n	(n = 0 to 100 for percentage of #rows to scroll, minimum 1)
 *		can be > 100.
 */

do_page()
{
    register int n, multiplier = 1;
    register ED *ep = Ep;
    static short pctg = 80;

    switch(av[0][4]) {
    case 'u':
	multiplier = -1;
    case 'd':
	n = multiplier * Rows * pctg / 100;
	if (!n)
	    n = multiplier;
	if (n > 0 && ep->Topline >= ep->Lines - Rows)
	    return(0);
	text_sync();
	ep->Line += n;
	ep->Topline += n;
	if (ep->Line >= ep->Lines)
	    ep->Line = ep->Lines - 1;
	if (ep->Line < 0)
	    ep->Line = 0;
	if (ep->Topline >= ep->Lines)
	    ep->Topline = ep->Lines - Rows - 1;
	if (ep->Topline < 0)
	    ep->Topline = 0;
	text_load();
	if (!text_sync())
	    text_redisplay();
	break;
    case 's':
	pctg = atoi(av[1]);
	break;
    }
}


do_downadd()
{
    ubyte *ptr;

    if (Ep->Line + 1 == Ep->Lines) {
	Ep->Modified = 1;
	if (makeroom(32) && (ptr = allocb(1))) {
	    Ep->List[Ep->Lines] = ptr;
	    *ptr = 0;
	    ++Ep->Lines;
	} else {
	    nomemory();
	}
    }
    do_down();
}


do_left()
{
    if (Ep->Column) {
	--Ep->Column;
	if (Ep->Column < Ep->Topcolumn)
	    text_sync();
    } else {
	Abortcommand = 1;
    }
}

do_right()
{
    if (Ep->Column != 254) {
	if (Current[Ep->Column] == 0) {
	    Current[Ep->Column] = ' ';
	    Current[Ep->Column+1]= '\0';
	    ++Clen;
	}
	++Ep->Column;
	if (Ep->Column - Ep->Topcolumn >= Columns)
	    text_sync();
    } else {
	Abortcommand = 1;
    }
}

do_tab()
{
    register short n;

    for (n = Ep->Tabstop-(Ep->Column % Ep->Tabstop); n > 0; --n)
	do_right();
}

do_backtab()
{
    register short n;

    n = Ep->Column % Ep->Tabstop;
    if (!n)
	n = Ep->Tabstop;
    for (; n > 0; --n)
	do_left();
}

do_return()
{
    ubyte buf[256];
    char *partial;

    if (Comlinemode) {
	strcpy(buf, Current);
	strcpy(RecallBuf, Current);
	partial = Partial;
	Partial = NULL;
	escapecomlinemode();
	if (partial) {
	    if (do_command(buf))
		do_command(partial);
	    free(partial);
	} else {
	    do_command(buf);
	}
    } else {
	Ep->Column = 0;
	text_sync();
	do_downadd();
    }
}

do_bs()
{
    register ED *ep = Ep;
    if (ep->Column) {
	bmov(Current + ep->Column, Current + ep->Column - 1, Clen - ep->Column + 1);
	--ep->Column;
	--Clen;
	if (ep->Column < ep->Topcolumn) {
	    text_sync();
	} else {
	    ScrollRaster(Rp, Xsize, 0,
		COL(ep->Column - ep->Topcolumn),
		ROW(ep->Line   - ep->Topline),
		COL(Columns)-1,
		ROW(ep->Line - ep->Topline + 1)-1
	    );
	    if (Clen >= ep->Topcolumn + Columns) {
		setpen(ep->Line);
		Move(Rp, COLT(Columns-1), ROWT(ep->Line - ep->Topline));
		Text(Rp, Current + ep->Topcolumn + Columns - 1, 1);
	    }
	}
	if (Comlinemode == 0 && ep->Wordwrap)
	    do_reformat(0);
    } else {
	Abortcommand = 1;
    }
}


/*
 * esc, escimm
 */

int Savetopline, Savecolumn, Savetopcolumn;

do_recall()
{
    av[0] = (ubyte *)"escimm";
    av[1] = (ubyte *)RecallBuf;
    do_esc();
}

do_esc()
{
    register ED *ep = Ep;

    if (Comlinemode)
	return(escapecomlinemode());
    text_sync();
    if (av[0][3] == 'i')
	strcpy(Current, av[1]);
    else
	Current[0] = 0;
    Clen = strlen(Current);
    Comlinemode = 1;
    returnoveride(1);
    Savetopline = ep->Topline;
    Savecolumn	= ep->Column;
    Savetopcolumn = ep->Topcolumn;
    ep->Column	  = Clen;
    ep->Topcolumn = 0;
    ep->Topline   = ep->Line - Rows + 1;
    SetAPen(Rp, 0);
    RectFill(Rp, COL(0), ROW(Rows-1), Xbase+Xpixs, Ybase+Ypixs);
    SetAPen(Rp, 1);
    Move(Rp, COL(0), ROW(Rows-1) - 1);
    Draw(Rp, Xbase + Xpixs, ROW(Rows-1) - 1);
    text_displayseg(Rows-1,1);
}


escapecomlinemode()
{
    register ED *ep = Ep;

    if (Partial) {
	free(Partial);
	Partial = NULL;
    }
    if (Comlinemode) {
	strcpy(RecallBuf, Current);
	Comlinemode = 0;
	returnoveride(0);
	ep->Topline = Savetopline;
	ep->Column  = Savecolumn;
	ep->Topcolumn = Savetopcolumn;
	text_load();
	SetAPen(Rp, 0);
	RectFill(Rp, COL(0), ROW(Rows-1)-1, Xbase+Xpixs, Ybase+Ypixs);
	SetAPen(Rp, 1);
	text_displayseg(Rows-2,2);
    }
}


do_del()
{
    register ED *ep = Ep;

    if (Current[ep->Column]) {
	bmov(Current + ep->Column + 1, Current + ep->Column, Clen - ep->Column);
	--Clen;
	ScrollRaster(Rp, Xsize, 0,
	    COL(ep->Column - ep->Topcolumn),
	    ROW(ep->Line - ep->Topline),
	    COL(Columns)-1,
	    ROW(ep->Line - ep->Topline + 1) - 1
	);
	if (Clen >= ep->Topcolumn + Columns) {
	    setpen(ep->Line);
	    Move(Rp, COLT(Columns-1), ROWT(ep->Line-ep->Topline));
	    Text(Rp, Current+ep->Topcolumn+Columns-1, 1);
	}
	if (Comlinemode == 0 && ep->Wordwrap)
	    do_reformat(0);
    }
}

do_top()
{
    text_sync();
    Ep->Line = 0;
    text_load();
    text_sync();
}

do_bottom()
{
    text_sync();
    Ep->Line = Ep->Lines - 1;
    text_load();
    text_sync();
}

do_firstcolumn()
{
    if (Ep->Column) {
	Ep->Column = 0;
	text_sync();
    }
}

do_firstnb()
{
    for (Ep->Column = 0; Current[Ep->Column] == ' '; ++Ep->Column);
    if (Current[Ep->Column] == 0)
	Ep->Column = 0;
    text_sync();
}

do_lastcolumn()
{
    short i;

    text_sync();
    i = (Comlinemode) ? Clen : strlen(Ep->List[Ep->Line]);
    if (i != Ep->Column) {
	Ep->Column = i;
	text_sync();
    }
}

/*
 * GOTO [+/-]N
 * GOTO BLOCK	start of block
 * GOTO START	start of block
 * GOTO END	end of block
 */

do_goto()
{
    register short n, i;
    register ubyte *ptr = av[1];

    i = 0;
    n = -1;

    switch(*ptr) {
    case 'b':
    case 's':
    case 'B':
    case 'S':
	n = -1;
	if (Ep == BEp)
	    n = BSline;
	break;
    case 'e':
    case 'E':
	n = -1;
	if (Ep == BEp)
	    n = BEline;
	break;
    case '+':
	i = 1;
    case '-':
	n = Ep->Line;
    default:
	n += atoi(ptr+i);
    }
    if (n >= Ep->Lines)
	n = Ep->Lines - 1;
    if (n < 0)
	n = 0;
    text_sync();
    Ep->Line = n;
    text_load();
    text_sync();
}

do_screentop()
{
    text_sync();
    Ep->Line = Ep->Topline;
    text_load();
    text_sync();
}

do_screenbottom()
{
    text_sync();
    Ep->Line = Ep->Topline + Rows - 1;
    if (Ep->Line < 0 || Ep->Line >= Ep->Lines)
	Ep->Line = Ep->Lines - 1;
    text_load();
    text_sync();
}

static ubyte Fstr[256];
static ubyte Rstr[256];
static short Srch_sign;
static char Doreplace;

/*
 * findstr, repstr
 */

do_findstr()
{
    if (av[0][0] == 'f')
	strcpy(Fstr, av[1]);
    else
	strcpy(Rstr, av[1]);
}

/*
 * findr, nextr, prevr
 */

do_findr()
{
    Doreplace = 1;
    Srch_sign = 1;
    switch(av[0][0]) {
    case 'f':
	strcpy(Fstr, av[1]);
	strcpy(Rstr, av[2]);
	break;
    case 'p':
	Srch_sign = -1;
	break;
    }
    search_operation();
}

/*
 * find, next, prev
 */

do_find()
{
    Doreplace = 0;
    Srch_sign = 1;
    switch(av[0][0]) {
    case 'f':
	strcpy(Fstr, av[1]);
	break;
    case 'p':
	Srch_sign = -1;
	break;
    }
    search_operation();
}


void
search_operation()
{
    int flen = strlen(Fstr);
    int rlen = strlen(Rstr);
    char senabled = 0;
    register ubyte *ptr;
    register int i, col;
    register ED *ep = Ep;

    text_sync();
    if (!flen) {
	title("No find pattern");
	Abortcommand = 1;
	return;
    }

    col = ep->Column;
    if (col >= strlen(ep->List[ep->Line]))
	col = strlen(ep->List[ep->Line]);
    for (i = ep->Line;;) {
	ptr = ep->List[i];
	if (Srch_sign > 0) {
	    while (ptr[col]) {
		if (Fstr[0] == ptr[col] &&
		strncmp(Fstr,ptr+col,flen) == 0 &&
		senabled) {
		    goto found;
		}
		senabled = 1;
		++col;
	    }
	    senabled = 1;
	    if (++i >= ep->Lines)
		break;
	    col = 0;
	} else {
	    while (col >= 0) {
		if (Fstr[0] == ptr[col] &&
		strncmp(Fstr,ptr+col,flen) == 0 &&
		senabled) {
		    goto found;
		}
		senabled = 1;
		--col;
	    }
	    senabled = 1;
	    if (--i < 0)
		break;
	    col = strlen(ep->List[i]);
	}
    }
    title("Pattern Not Found");
    Abortcommand = 1;
    return;

found:
    ep->Line = i;
    ep->Column = col;

    text_load();
    if (Doreplace) {
	if (rlen > flen && rlen-flen+strlen(ptr) > 254) {
	    title("Replace: Line Too Long");
	    Abortcommand = 1;
	    return;
	}
	if (Clen-col-flen >= 0) {
	    bmov(Current+col+flen, Current+col+rlen, Clen-col-flen+1);
	    bmov(Rstr, Current+col, rlen);
	    Clen += rlen-flen;
	}
	text_sync();
	text_redisplaycurrline();
    } else {
	text_sync();
    }
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'text2.c'" '(22408 characters)'
if test -f 'text2.c'
then
	echo shar: "will not over-write existing file 'text2.c'"
else
cat << \!Funky!Stuff! > '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;
extern void do_bmove();

do_remeol()
{
    Current[Clen = Ep->Column] = 0;
    text_sync();
    text_redisplaycurrline();
}

do_wleft()
{
    register ED *ep = Ep;
    register ubyte *ptr;
    register int i;

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


do_wright()
{
    register ubyte *ptr;
    register ED *ep = Ep;
    register int i;

    for (;;) {
	i = ep->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 || ep->Line == ep->Lines - 1) {
		i = ep->Column;
		break;
	    }
	    text_sync();
	    ++ep->Line;
	    text_load();
	    ep->Column = i = 0;
	    if (Current[0] != ' ')
		break;
	    continue;
	}
	break;
    }
    ep->Column = i;
    text_sync();
}


do_split()              /* split line in two at cursor pos */
{
    ubyte buf[256];
    register ED *ep = Ep;

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

do_join()
{
    register int i = Clen, j;
    register ED *ep = Ep;

    if (ep->Line + 1 < ep->Lines && strlen(ep->List[ep->Line+1])+i <= 253) {
	if (i && Current[i-1] != ' ')
	    Current[i++] = ' ';
	strcpy(Current+i, ep->List[ep->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(ep->Line - ep->Topline, 1);
	do_down();
	do_deline();
	do_up();
	return(1);
    }
    return(0);
}

do_margin()
{
    Ep->Margin = atoi(av[1]);
}

do_wordwrap()
{
    register ED *ep = Ep;

    if (av[1][1] == 'n')
	ep->Wordwrap = 1;
    if (av[1][1] == 'f')
	ep->Wordwrap = 0;
    if (av[1][0] == 't')
	ep->Wordwrap = 1 - ep->Wordwrap;
    if (ep->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;
    register ED *ep = Ep;
    int nlok, lnsc, fnst, fnsc;
    int column = ep->Column;
    int srow   = ep->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 (ep->Margin == 0)
	ep->Margin = 75;

    ++Nsu;
    for (;;) {
	str = (char *)ep->List[ep->Line+1];
	fnst = 0;
	fnsc = firstns(Current);
	nlok = (ep->Line + 1 < ep->Lines && fnsc >= (fnst=firstns(str)));
	if (nlok && str[0] == 0)
	    nlok = 0;
	lnsc = lastns(Current);
	if (lnsc < ep->Margin) {    /* space at end of line for marg-lnsc-2 letter word   */
	    if (nlok == 0)        /* but no more data to joinup   */
		break;		  /* done */
	    if (ep->Margin - lnsc - 2 >= wordlen(str+fnst)) {
		ep->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 = ep->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 >= ep->Margin) {
		while (i && Current[i] == ' ')
		    --i;
		if (i < ep->Margin)
		    break;
		lnsc = i;
		continue;
	    }
	    break;
	}
	if (lnsc) {             /* ok to split at word          */
	    ++lnsc;
	    ++dins;
	    ep->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 - ep->Column + indent;
			++crow;
		    }
		}
		if (Clen + indent < 253) {
		    bmov(Current, Current + indent, strlen(Current)+1);
		    bset(Current, indent, ' ');
		    Clen += indent;
		}
	    }
	    erow = ep->Line;
	    continue;
	}
	if (n == 0)
	    break;
	do_down();
    }
    if (column < 0 || column > 200)
	column = 0;
    if (srow >= ep->Lines) {
	srow = ep->Lines - 1;
	goto ra;
    }
    if (dins || srow < ep->Topline || srow >= ep->Topline + Rows) {
ra:
	text_sync();
	--Nsu;
	ep->Line = crow;
	ep->Column = column;
	text_load();
	if (!text_sync())
	    text_redisplay();
    } else {
	text_sync();
	--Nsu;
	ep->Line = crow;
	ep->Column = column;
	text_load();
	if (erow != srow) {
	    if (!text_sync()) {
		++erow;
		if (erow - ep->Topline > Rows)
		    erow = ep->Topline + Rows;
		SetAPen(Rp, 0);
		RectFill(Rp, COL(0), ROW(srow - ep->Topline), Xbase+Xpixs, ROW(erow - ep->Topline)-1);
		SetAPen(Rp, 1);
		text_displayseg(srow - ep->Topline, erow - srow);
	    }
	} else {
	    text_sync();
	    if (moded)
		text_redisplaycurrline();
	}
    }
    if (column > Clen) {
	bset(Current+Clen, column - Clen, ' ');
	Current[column] = 0;
    }
    ep->Column = column;
}


do_tabstop()
{
    Ep->Tabstop = atoi(av[1]);
}


do_insertmode()
{
    register ED *ep = Ep;

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

do_insline()
{
    register ubyte *ptr;
    register ED *ep = Ep;

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

do_deline()
{
    register int delline;
    register ED *ep = Ep;

    if (ep->Lines > 1) {
	ep->Modified = 1;
	text_sync();

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

do_chfilename()
{
    text_sync();
    strncpy(Ep->Name, av[1], 63);
    MForceTitle = 1;
}

do_edit()
{
    long xfi;
    long oldlock;
    long lines;
    ubyte buf[256];
    ubyte *ptr;
    char failed = 1;
    short iwinx, iwiny;
    char  tabstop, margin, insertmode, wordwrap;
    register ED *ep = Ep;

    text_sync();
    if (*av[0] == 'n') {        /* newfile or insfile   */
	if (ep->Modified && getyn("Delete modified Image?") == 0)
	    return(0);
	iwinx = ep->IWinx;
	iwiny = ep->IWiny;
	tabstop= ep->Tabstop;
	margin = ep->Margin;
	insertmode = ep->Insertmode;
	wordwrap = ep->Wordwrap;
	text_uninit();
	text_init();
	ep = Ep;
	ep->IWiny = iwiny;
	ep->IWinx = iwinx;
	ep->Tabstop = tabstop;
	ep->Margin  = margin;
	ep->Insertmode = insertmode;
	ep->Wordwrap = wordwrap;
	ep->Modified = 0;
	ep->Line = ep->Topline = 0;
	strncpy(ep->Name, av[1], 63);
    } else {
	ep->Modified = 1;
    }
    lines = ep->Lines;
    if (Wbs && Wdisable == 0)
	oldlock = CurrentDir(ep->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))) {
		ep->List[ep->Lines++] = ptr;
		bmov(buf, ptr, len+1);
	    } else {
		set_window_params();
		nomemory();
		oktitle = 0;
		break;
	    }
	}
	set_window_params();
	if (oktitle)
	    title("OK");
    } else {
	title("File Not Found");
    }
    xfclose(xfi);
    if (Wbs && Wdisable == 0)
	CurrentDir(oldlock);
    if (ep->Lines != 1 && lines == 1 && ep->List[0][0] == 0) {
	ep->Modified = 0;
	ep->Line = 0;
	FreeMem(ep->List[0], strlen(ep->List[0])+1);
	bmovl(ep->List+1, ep->List,--ep->Lines);
    } else {
	if (!failed && lines <= ep->Lines - 1) {
	    BEp = ep;
	    BSline = lines;
	    BEline = ep->Lines - 1;
	    do_bmove();
	}
    }
    set_window_params();
    text_load();
    text_redisplay();
}

static char blockmode;

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

do_save()
{
    av[1] = Ep->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;
    ED *ep;

    bm = blockmode;
    if (blockmode && blockok()) {
	xs = BSline;
	xe = BEline + 1;
	ep = BEp;
    } else {
	xs = 0;
	xe = Ep->Lines;
	ep = Ep;
    }
    blockmode = 0;
    text_sync();
    if (Wbs && Wdisable == 0) {     /* Write out .info file */
	DISKOBJ sdo, *d;
	bzero(&sdo, sizeof(sdo));
	oldlock = CurrentDir(Ep->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 = ep->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 {
	    ep->Modified &= bm;
	    title("OK");
	}
	if (Wbs && Wdisable == 0)
	    CurrentDir(oldlock);
    } else {
	title("Unable to open write file");
	Abortcommand = 1;
    }
}


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

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


do_bdelete()
{
    register long i, n;
    register ED *bep = BEp;
    register WIN *savewin = Ep->Win;

    if (blockok()) {
	text_switch(bep->Win);
	n = BEline - BSline + 1;
	if (bep->Line >= BSline && bep->Line <= BEline)
	    bep->Line = BSline;
	if (bep->Line > BEline)
	    bep->Line -= n;
	freelist(bep->List + BSline, BEline - BSline + 1);
	bmovl(bep->List+BEline+1,bep->List+BSline,(bep->Lines-BEline-1));
	bep->Lines -= n;
	bep->Modified = 1;
	if (bep->Line >= bep->Lines)
	    bep->Line = bep->Lines - 1;
	if (bep->Line < 0)
	    bep->Line = 0;
	if (bep->Lines == 0) {
	    text_uninit();
	    text_init();
	}
	text_load();
	BEp = NULL;
	BSline = BEline = -1;
	if (!text_sync())
	    text_redisplay();
	text_switch(savewin);
    }
}

void
do_bcopy()
{
    register ubyte **list;
    register long lines, i;
    register ED *ep = Ep;

    text_sync();
    if (!blockok())
	return;
    if (ep == BEp && ep->Line > BSline && ep->Line <= BEline) {
	title("Cannot Move into self");
	return;
    }
    lines = BEline - BSline + 1;
    if (extend(ep, lines)) {
	if (list = (ubyte **)allocl(lines)) {
	    bmovl(BEp->List+BSline,list,lines);
	    bmovl(ep->List+ep->Line, ep->List+ep->Line+lines, ep->Lines-ep->Line);
	    for (i = 0; i < lines; ++i) {
		ubyte *str = allocb(strlen(list[i])+1);
		if (!str) {
		    nomemory();
		    FreeMem(list, lines * sizeof(char *));
		    freelist(ep->List + Ep->Line, i);
		    bmovl(ep->List+ep->Line+lines, ep->List+ep->Line, ep->Lines-ep->Line);
		    return;
		}
		strcpy(str, list[i]);
		ep->List[ep->Line+i] = str;
	    }
	    FreeMem(list, lines * sizeof(char *));
	}
    }
    if (ep == BEp && ep->Line <= BSline) {
	BSline += lines;
	BEline += lines;
    }
    ep->Modified = 1;
    ep->Lines += lines;
    text_load();
    if (!text_sync())
	text_redisplay();
}


void
do_bmove()
{
    register long lines;
    register ubyte **list;
    register ED *ep = Ep;

    text_sync();
    if (!blockok())
	return;
    if (BEp == ep && ep->Line >= BSline && ep->Line <= BEline) {
	title("Cannot Move into self");
	return;
    }
    lines = BEline - BSline + 1;
    if (!(list = (ubyte **)allocl(lines))) {
	nomemory();
	return;
    }
    bmovl(BEp->List + BSline, list, lines);
    if (ep == BEp) {
	if (ep->Line > BSline) {
	    bmovl(ep->List+BEline+1, ep->List+BSline, ep->Line-BEline-1);
	    bmovl(list, ep->List + ep->Line - lines, lines);
	} else {
	    bmovl(ep->List+ep->Line, ep->List+ep->Line+lines, BSline-ep->Line);
	    bmovl(list, ep->List + ep->Line, lines);
	}
    } else {
	WIN *savewin = ep->Win;
	if (extend(ep, lines)) {
	    bmovl(BEp->List+BEline+1, BEp->List+BSline, BEp->Lines-BEline-1);
	    bmovl(ep->List+ep->Line, ep->List+ep->Line+lines, ep->Lines-ep->Line);
	    bmovl(list, ep->List+ep->Line, lines);
	    ep->Lines += lines;
	    BEp->Lines -= lines;
	    if (BEp->Line >= BSline && BEp->Line <= BEline)
		BEp->Line = BSline - 1;
	    if (BEp->Line > BEline)
		BEp->Line -= lines;
	    if (BEp->Line < 0)
		BEp->Line = 0;
	    BSline = BEline = -1;
	    text_load();
	    text_switch(BEp->Win);
	    BEp = NULL;
	    ep = Ep;
	    if (!ep->iconmode) {
		if (!text_sync())
		    text_redisplay();
	    }
	    text_switch(savewin);
	    ep = Ep;
	}
    }
    BSline = BEline = -1;
    BEp = NULL;
    FreeMem(list, lines * sizeof(char *));
    BEp->Modified = 1;
    ep->Modified = 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;
    register ED *ep = Ep;
    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 = ep->Column + 1;
    case 'y':
	if (!i)
	    i = ep->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 = ep->Line == 0;
	break;
    case 'b':
	istrue = ep->Line == ep->Lines-1;
	break;
    case 'l':
	istrue = ep->Column == 0;
	break;
    case 'r':
	istrue = ep->Column == Clen;
	break;
    case 'm':
	text_sync();
	istrue = ep->Modified != 0;
	break;
    case 'i':
	istrue = ep->Insertmode != 0;
	break;
    case 'c':
	cc = Current[ep->Column];
	switch(cx) {
	case 'b':
	    istrue = BEp == ep && ep->Line >= BSline && ep->Line <= 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[ep->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];
    register 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 ED *ep = Ep;
    register char c = Current[ep->Column];

    if (c == 0)
	c = ' ';
    if (ptr[0] == '+')
	c += atoi(ptr+1);
    else
    if (ptr[0] == '-')
	c -= atoi(ptr+1);
    else
	c = atoi(ptr);
    if (c) {
	if (Current[ep->Column] == 0) {
	    Clen = ep->Column + 1;
	    Current[Clen] = 0;
	}
	Current[ep->Column] = c;
	if (Nsu == 0) {
	    movetocursor();
	    setpen(ep->Line);
	    Text(Rp, Current+ep->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 = BSline;
	se = BEline + 1;
	for (i = sl; BEp && i < se && i < BEp->Lines; ++i) {
	    text_sync();        /* make sure we are using latest text */
	    strcpy(buf, BEp->List[i]);
	    if (do_command(buf) == 0)
		break;
	}
	text_redrawblock(0);
    }
}

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

void
do_scanf()
{
    char buf[256];

    buf[0] = 0;
    sscanf(Current+Ep->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()
{
    register ED *ep = Ep;
    Move(Rp, XTbase+(ep->Column-ep->Topcolumn)*Xsize, YTbase+(ep->Line-ep->Topline)*Ysize);
}

extend(ep, lines)
register ED *ep;
{
    register long extra = ep->Maxlines - ep->Lines;
    register ubyte **list;

    if (lines > extra) {
	lines += ep->Lines;
	if (list = (ubyte **)allocl(lines)) {
	    bmovl(ep->List, list, ep->Lines);
	    FreeMem(ep->List, sizeof(char *) * ep->Maxlines);
	    ep->Maxlines = lines;
	    ep->List = list;
	    return(1);
	}
	nomemory();
	return(0);
    }
    return(1);
}

makeroom(n)
{
    register ED *ep = Ep;
    if (ep->Lines >= ep->Maxlines)
	return(extend(ep, n));
    return(1);
}

freelist(list, n)
register char **list;
{
    while (n) {
	FreeMem(list[0], strlen(list[0])+1);
	++list;
	--n;
    }
}

!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive