[comp.sources.amiga] DME V1.27

dillon%cory.berkeley.edu@berkeley.edu (Matt Dillon) (07/01/87)

	Here is the documetation for DME, which can be found both in 
    comp.binaries.amiga and comp.sources.amiga...
	Enjoy!
	    Doc
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This archive created: Wed Jul  1 07:28:18 1987
# By: Craig Norborg (Purdue University Computing Center)
#	Run the following text with /bin/sh to create:
#	TODO
#	dme.doc
cat << \SHAR_EOF > TODO

ni = not implemented yet

STATUS	ITEM

DONE	TLATE bug when tlate'ing char at end of line (major bug fixed)
ni	ascii-numeric variable support
ni	command line variable expansion.
ni	exception handling  (abort if, repeat, keymap, etc..... trap vector?)
DONE	workbench support
DONE	mouse keymaps
ni	kill/string buffer
ni	position marking
ni	character oriented blocks
ni	highlight blocks
ni	block move across windows
ni	stackable search/replace strings
DONE	move to end of block	(GOTO END)
ni	cancel all user keymaps
NO	paren instead of `'?
NO	clipboard support
ni	anchored search as opposed to normal search
DONE	toggle max should be larger	(NOW 256)
DONE	Execute
ni	keyboard repeat buffering too many repeats.
SORTA	help! key... now semi implemented
ni	provision to show mapping for a single key
DONE	default icon			(not fantastic, though)
DONE	close gadget should sync text first.

DONE	(I think). each keypress when window iconified caused loss of 280
	bytes memory.. reclaimed when the window is iconified/de-iconified,
	but things start slowing down after a while.

DONE	child windows should inherit tab stops, insert mode, word wrap mode
ni	slave the editor to a shell.
ni	change directory
ni	GETTSTRING
ni	menu add
DONE	window resize
ni	break key   (currently must BREAK from a CLI)

SHAR_EOF
cat << \SHAR_EOF > dme.doc

DOC.TXT

DME V1.27 (C)CopyRight 1987, Matthew Dillon.  All Rights Reserved. This
software may be distributed for non-profit only.  This software is
NOT shareware.

    Matthew Dillon	    contribute if you wish.
    891 Regal Rd
    Berkeley, Ca. 94708

    Source is available on request or by anonymous FTP.  Source requests
    can ONLY be made via electronic mail to the following address:

    USENET   ...!ihnp4!ucbvax!dillon
    ARPANET  dillon@ucbvax.berkeley.edu

---------------------------------------------------------------------------

I   Overview
II  Keymapping		key and mouse mapping
III Command Sequences	DME commands
IV  File Particulars	notes on loading and saving files
V   Workbench Support
VI  Revision Summary	revision numbering, changes made, etc...
VII Compiling		compiling instructions

				    I
				 OVERVIEW

See REVISIONS section for revisions.  DME is a WYSIWYG editor designed
mainly for programmers.  Although it is not a word processor, it does
include many word processing features such as Word-Wrap and automatic
paragraph formatting.  Here is a quick 'features' list:

	-control language based on a rich command set accessed manually
	 or via arbitrary mapping of keys.  (Every key may be mapped to 16
	 different things)

	-fast visual response (it scrolls quickly)

	-title-line statistics showing your current position in the file,
	 file name, whether the file has been modified or not, etc...

	-Multiple Windows, ability to iconify windows

	-Word Wrap and automatic paragraph formatting.

	-ability to map any KEY or MOUSE BUTTON combination.

DME has been designed to allow easy expansion, and I intend to make many
future improvments.  It has not been designed for user friendliness, but is
straight forward if you read this document fully.

DME can take any number of arguments.  Any argument without a '-' in front
of it is considered to be a file.   Normally, DME will automatically SOURCE
two script file, S:.EDRC, and the .EDRC in your current directory. These
files do not have to exist. These script files usually contain mappings and
do things like turn on word wrap and set the right margin.

    FLAGS:
	    -ffilename	    -source this script file instead of .EDRC

	    -b		    -normally when multiple files are specified,
			     DME opens them with small windows.  This opens
			     them with normal sized windows.

	    -tN     -Open the window on scan line N
	    -lN     -Open the window offset N scan columns
	    -wN     -Make the window N pixels wide
	    -hN     -Make the window N pixels high


				    II
				 KEYMAPPING

MOUSE BUTTONS:

    The mouse buttons and combinations thereof may now be mapped.  The
    default mappings for the mouse buttons are as follows:

    Left-button:    Move cursor to current mouse position
    Right-button:   Iconify window
    Left-button held down while moving mouse tracks the cursor

    The iconification features:
	-Remembers original window size and placement
	-Remembers placement of iconified window when you re-iconify later.

    Currently, you will crash the machine if you run out of memory and DME
    is unable to open the icon window or original window, so be careful.

    see below for mapping the mouse buttons and mouse movement.


KEYBOARD:

The rest of the Functional interface for DME is based on key/mouse mappings
and a rich command set.  Unlike other text editors, any non-qualifier key
in DME may have any meaning whatsoever.  It just so happens that the
default keymappings assign such things as the `return' key to the RETURN
function, the `up' key to the UP function, etc...  Keys are named by their
keycap labels with the following exceptions:

    the name for Back-Space is	BS
    the name for numeric keypad keys are prepended with an NK, except for
    the Enter key which is named 'ENTER'.
    The four cursor control keys are labeled UP, DOWN, LEFT, and RIGHT
    The three mouse buttons are labeled RMB, MMB, and LMB.

*NOTE*	the normal Amiga mouse has only two buttons, the Left and the Right
mouse buttons (LMB, RMB).  A properly installed three-button mouse is
also supported.

*NOTE*	You must type commands in lower-case, except for text, which can be
either lower or upper case, and for upper-case alpha keys when specifying
keymaps (i.e.  A and s-a are the same key).  The exception is the AMIGA
qualifier key, which uses 'A' instead of 'a'(Alt).

Each key may be qualified with any combination of CTRL, ALT, SHIFT, AMIGA,
or any of the MOUSE buttons.  With 6 qualifiers (7 if your mouse has a
middle button), you can assign up to 64 (128) different maps to each
physical key on the keyboard.

NOTE: The CAPS-LOCK, when lit, is equivalent to SHIFT only for Alpha keys.

NOTE: The AMIGA-ALT (aA) combination isn't very usable since Intuition uses
the sequence to duplicate a Mouse SELECT.  Other AMIGA sequences are used
by intuition for mouse movement and other things.  Some other qualifier
combinations may not be usable due to other special sequences.

    ***EXAMPLES:***

    tab tab
    a-a ALT a
    A-a AMIGA a
    sA-a	SHIFT AMIGA a
    s-tab	SHIFT tab
    c-tab	CTRL tab
    ac-?	ALT-CTRL ?
    s-f5	SHIFT F5
    nk0 Numeric Keypad 0
    cs-nk0	CTRL SHIFT Numeric Keypad 0
    L-lmb	Left Mouse button pressed
    L-mmove	Mouse moved while left mouse button held down
    LR-lmb	left mouse button hit while right mouse button held down

    ***************

MAPPING MOUSE BUTTONS

    Mouse buttons serve both as QUALIFIERS and as KEYS.  Thus, you can map
    both normal keystrokes which require a mouse button to be held down:

	map L-a ``left button and an a''

    as well as the mouse keys themselves:

	map L-lmb   ``left mouse key''

    note that you had to specify the left mouse button down qualifier L as
    well as the left mouse button LMB.

    If you map the left mouse button, and also map a sequence such as left
    mouse button + a:

	map L-lmb   tomouse
	map L-a     ``hello''

    Note that the first mapping will always get executed even if you
    intended L-a (that is, BOTH mappings would get executed).  In order
    to avoid confusion you might want to UNMAP the system default mapping
    for the right mouse button (mapped to ICONIFY) if you wish to apply
    combinations to the right mouse button.

    MOUSE MOVEMENT is mapped with one or more mouse qualifiers (L, R, M),
    plus 'MMOVE' for the key.  That is:

	map LR-mmove ``moving the mouse with both buttons held down''


DEFAULT KEYMAP:

    All Printable Ascii keys mapped to their ascii equivalent
    BS, DEL, UP, DOWN, LEFT, RIGHT, TAB, S-TAB, ENTER mapped properly

    `s- '       Shift Space is Mapped to space
    backspace	Back Space
    tab Tab
    s-tab	Back tab
    enter	the RETURN command
    return	`return insline up firstnb down'
    esc Escape into command mode
    del Delete character
    s-del	Delete line
    c-del	Remove to end of line
    up		cursor up
    down	cursor down
    left	cursor left
    right	cursor right
    s-up	top of text
    s-down	bottom of text
    s-left	first column
    s-right	last column (one past the last non-blank on a line)
    c-up	page up
    c-down	page down
    c-q Quit
    c-w TOGGLE WORD WRAP MODE
    f1		Prompts for file to insert
    f2		Prompts for new file to replace current text with
    f3		Prompts for new file to place into new window
    f7		Prompts for filename to save marked block to
    f8		Saves current text and then does an 'f2'
    f9		Saves current text, but does not quit
    f10 	Saves current text and quits.
    c-r 	Word Right
    c-l 	Word Left
    c-i 	insert mode on
    c-o 	insert mode off
    c-/ 	Prompts for search pattern
    c-p 	search previous occurance
    c-n 	search next occurance
    c-s 	`split first down' ... fancy split line
    c-u 	Unblock a block
    c-b 	Mark start/end of a block
    a-s 	SOURCE a block of text as if it were a script file
    sa-s	SOURCE the current line of text as if it were a script file
    a-d 	delete block
    a-c 	copy block
    a-m 	move block
    c-f 	reformat paragraph
    c-g 	Prompts for line to GOTO to.
    c-j 	join next line to this line.
    L-lmb	move cursor to mouse position (tomouse)
    L-mmove	move cursor to mouse position (tomouse)
    R-rmb	iconify window
    help	`newwindow newfile s:DME.DOC escimm `find ''


				    III
			     COMMAND SEQUENCES

DME has a rich command set which allows you to embed commands within
commands, or specify multiple commands in a row.  A command consists of a
KEYWORD followed by a FIXED number of arguments (0, 1, 2...).  The argument
delimeter in DME is a SPACE.  Therefore, to embed strings containing spaces
as a single argument, you must surround the string with `string'
(backquote-string-quote).  TEXT to be written as if typed is also specified
via a string in backquote-quotes.  For example:

    right right `hello' right right `hello' enter down
    map f4 `right right' map f5 `left left'
    map f4 ``hello''

Reiterating (because this is important!)... If a command expects ONE
argument, then it really does expect a single argument, and any remaining
arguments are thought to be the next command... so:

    map f4 right
				    -right is only one word, so no need
				     for `'.
    map f4 `right right'
				    -we want to map f4 to two rights... we
				     need the `' or the second right will
				     not be part of the map.

    map c-del `repeat cright del'
				    -this is already implimented as REMEOL,
				     but shown here for clarity.

Some arguments will eventually be fed through the command interpreter more
than once.  The MAP command is a good example.	When you execute a MAP
command, the first run through the command interpreter installs the map
string minus a set of quotes.  So, if you want to specify text, you must
enclose the text in two sets of ``text'' because the map string gets passed
through the command interpreter again when you hit the mapped key.  Here
are some more complex examples:

    map f4 `right right `hello' left left'      *RIGHT*
    map f4 right right hello left left		*WRONG*

    map f4 `map f4 ``hello'''
				    -the first time you hit F4, it's command
				     is to re-map itself to the TEXT `hello'.
				     (gads!).

    map c-i `repeat tr `` '''
				    -example of how to embed a space in a
				     map and repeat (goes through command
				     interpreter three times!).


An easy way to fool around executing commands or making maps is either to
use the ESC key (which enters command mode), or  a-S (alt-shift-s), which
EXECUTES the current DME line that the cursor is on.... so you can use DME
to edit and test your new keymappings.


!!!!!!!!!! NOTE NOTE NOTE NOTE NOTE !!!!!!!!!!!!!! You must type commands
in LOWER case. They are in upper case here for visibility.

    COMMAND LIST

    `text'          -enter text as if typed.
    key 	    -execute a keymap as a macro (example:  c-a)
    BACK	    -same as BS
    BACKTAB	    -backward tab
    BCOPY	    -copy block before cursor line
    BDELETE	    -delete the block
    BLOCK	    -Set start or end of block
    BMOVE	    -move block before cursor line
    BOTTOM	    -Move to Bottom of File
    BS		    -backspace, (delete char to left of cursor)
    BSAVE file	    -save the block to a file
    BSOURCE	    -source current text block as if it were a script file
    DEL 	    -delete, (deletes char under cursor)
    DELINE	    -delete line
    DOWN	    -cursor down
    DOWNADD	    -cursor down.  If at bottom of text, add a line.
    ESC 	    -toggle manual command entry mode
    ESCIMM arg	    -go into command entry mode prompting with a
		     predefined string.
    EXECUTE comm    -Execute a CLI command
    FIND string     -SET the search pattern and do a NEXT
    FINDR s1 s2     -Set find and replace patterns and do one find/rep.
    FINDSTR string  -SET the search string pattern
    FIRST	    -move to column 1
    FIRSTNB	    -Move to first non-blank in line.
    GOTO BLOCK	    -Goto the beginning of the marked block.
    GOTO START	    -same as GOTO BLOCK.  undefined if no block
    GOTO END	    -goes to the END of the marked block.  undef. if no blk.
    GOTO [+/-]N     -Goto an absolute or relative line number
    HEIGHT N	    -set height in pixels for any new window
    ICONIFY	    -iconify the window
    IF cnd act	    -IF/WHILE/IFELSE.. SEE BELOW
    IFELSE cnd ifact elseact
    INSERTMODE what -set INSERTMODE.  what = on, off, or toggle
    INSFILE name    -insert a file into the current text.
    INSLINE	    -insert line
    JOIN	    -join next line to line at cursor
    LAST	    -move one beyond the last non-space in a line.
    LEFT	    -cursor left
    LEFTEDGE N	    -set leftedge in pixels for any new window
    MAP key map     -map a key to a keymap
    MARGIN N	    -set WordWrap and paragraph formatting margin
		     (related to WORDWRAP and REFORMAT)
    NEWFILE name    -replace current text with new file
    NEWWINDOW	    -open newwindow
    NEXT	    -find next occurance of search pattern
    NEXTR	    -find next occurance and replace
    PAGEDOWN	    -pagedown a partial page (see PAGESET)
    PAGESET n	    -n PERCENT (0 to 100). page step size relative to the
		     current number of rows in the window.
    PAGEUP	    -pageup a partial page (see PAGESET)
    PREV	    -find previous occurance of search pattern
    PREVR	    -find previous occurance and replace
    QUIT	    -quit
    REFORMAT	    -reformat paragraph using the margin.
    REMEOL	    -Remove text under and beyond the cursor.
    REPEAT cnt comm -SEE BELOW
    REPSTR string   -SET the replace string pattern
    RESETTOGGLE N   -clear toggle array entry N(0..31)
    RESIZE cols rows-Resize current window. E.G:  `resize 70 23'
    RETURN	    -same as `FIRST DOWNADD'
    RIGHT	    -cursor right
    SAVEAS file     -save current text under a different name (title
		     line name does not change)
    SAVEMAP file    -save user keymappings
    SAVEOLD	    -save current text under current name
    SAVESMAP file   -save all keymappings, including system keymaps
    SAVETABS on/off -Optimize file saves by crunching spaces to tabs.
		     The default is OFF.
    SCREENBOTTOM    -Move cursor to the bottom of the screen.
    SCREENTOP	    -Move cursor to the top of the screen
    SETTOGGLE N     -set toggle array entry N  (0..255)
    SOURCE file     -source a script file
    SPLIT	    -Split line at cursor
    TAB 	    -forward tab
    TABSTOP N	    -Set tab stops every N.  does not effect text load
    TLATE [+/-]N    -translate character by +N or -N, or set character
		     to exactly N if no + or -. (e.g. TLATE +65 TLATE 3)
    TOGGLE N	    -flip toggle array entry N (0..255)  (See IF)
    TOMOUSE	    -moves cursor to mouse position
    TOP 	    -Move to Top of File
    TOPEDGE N	    -set topedge in pixels for any new window
    UNBLOCK	    -clear the block markers for the current window
    UNMAP key	    -unmap a key
    UP		    -cursor up
    WHILE cnd act   -(see below)
    WIDTH N	    -set width in pixels for any new window
    WLEFT	    -move to beginning of previous word.  If in the
		     middle of a word, move to beginning of current word.
    WORDWRAP on/off/toggle
		    -Word Wrap mode (related to MARGIN)
    WRIGHT	    -move to beginning of next word



    -------------------------------------------------------------------
    Command which cause a command line to abort (e.g. in repeat, while):

    FIND[R]/NEXT[R]/PREV[R]  when the string is not found.  NEXT stops at
    the end of the file, PREV stops at the beginning.

    DOWN,LEFT,RIGHT,UP	when the operation cannot be done.
    -------------------------------------------------------------------


    REPEAT N arg    -Repeat `arg' N times.  Apart from being a number, N
		     can also be one of:

			line	Current line # (lines begin at 1)
			lbot	#lines to the bottom, including current line
			cleft	column # (cols begin at 0)
			cright	#chars to eol, including current char under cursor
			tr	#char positions to next tab
			tl	#char positions to next back tab

		    Certain commands can abort a REPEAT loop.
		    Specifically, any FIND[R], NEXT[R], or PREV[R] in which
		    the search string is NOT found will abort a REPEAT.
		    Most operations which can go out of bounds, such as
		    UP, LEFT, RIGHT, DOWN, also abort a repeat.

		    Specifying -1 as N causes REPEAT to go on forever
		    (well, actually, 0xFFFFFFFF times) or until an abort.
		    To abort an accidentel infinite loop, you must use the
		    CLI BREAK command.

    IF [!]condition arg
    WHILE [!]condition arg
    IFELSE [!]condition arg else arg

	    If the specified condition is true, execute the argument.  For
	    WHILE, the argument is executed until the condition is false
	    (be careful!).

	    the optional '!' inverts the logic.

	    Conditions:

	    #	    if toggle entry # is SET.  there are 256 toggles (0..255)
	    t	    if On line 1
	    b	    if On last line
	    l	    if At column 0
	    r	    if At end of line (spaces below and beyond)
	    m	    if Text has been modified
	    i	    if in insert mode
	    x[<=>]# if column position (starts at 1) is (any OR combo of
		    <, =, or >) than some number.  Example:   x<=20
	    y[<=>]# if Line number (starts at 1) is (same as for x)
	    cl	    character under cursor is lower case alpha
	    cu	    character under cursor is upper case alpha
	    ca	    character under cursor is alpha-numeric
	    cn	    character under cursor is numeric
	    c[<=>]# character under cursor is ascii code # (# in decimal)
		    optional conditionals as in 'x' and 'y'.
	    cb	    cursor within a block

	Example: simulating an insert mode toggle: ALT-i (not CTL-i)

     map a-i `ifelse 0 `toggle 0 insertmode OFF' `toggle 0 insertmode ON''

	Example: while lower case, map to upper case and move right.

     map c-U `while cl `tlate -32 right''

     if c<32 ``char under cursor is smaller than 32''
     if c<>32 ``char under cursor is not equal to 32''
     while !b down


    WARNING:	It is possible to get into infinite loops with REPEAT and
		WHILE.	Currently, BREAK is *not* handled by the open
		window, but by whatever executed DME.  That is, you must
		either Ctl-C from your CLI, or send a BREAK to the DME
		process.  I hope to fix this soon.


				    IV
			     FILE PARTICULARS

No Matter what you set internal tabs to, tabs in disk files will be 8.
This allows you to use your favorite tabs stops (mine are 4) and still
have your disk files compatible with TYPE, a printer, etc...  DME by
default doesn't bother to optimize when writing out files and simply uses
spaces. If you `SAVETABS on' before saving (or in your S:.EDRC, etc...),
DME will attempt to optimize the file by placing TABS in appropriate
places.  DME will not place any TABS after the first single, back, or
double quote is encountered in a line.	If this does not cover every
situation in your particular application that you want to be *sure* no tabs
will occur in sensitive sections, then you should not use `SAVETABS on'.

It should be noted that since DME removes spaces at the end of the line,
editing UUENCODED ascii files will not work for uuencoded lines which end
with a space.  The nominal fix is to add an extra character after each
uuencoded line (anything), which is ignored by the UUDECODE program.

The command to save the current document under the default name is SAVEOLD,
*not* SAVE.  SAVE is not a valid command.  This is to prevent people who
have not read the documentation from assuming 'save' takes an argument (and
screwing up their work).  SAVEOLD does NOT take an argument, SAVEAS does.

SAVEOLD/SAVEAS does not automatically backup the destination file.  If you
are working in an enviroment where you are worried about ensuring a viable
copy can be recovered if your Amiga crashes in the middle of the save, you
can write a macro to save the file into two places.  Usually, people backup
their working disks so this is not neccesary.

Workbench Support:  If DME is run from the workbench, it will automatically
construct an icon file when you save a document.  If run from a CLI, no
icon file is generated.

				    V
			      WORKBENCH SUPPORT

DME V1.26 and beyond support the workbench in the following way:  (1) you
can click on the DME icon to bring up DME with ram:unnamed.  (2) you can
select one or more standard ascii documents which have DME as the default
tool.  If DME has no knowlege of a text icon, it uses its own.	Command
line arguments are passed to DME via the tooltypes entries for DME's
application icon or via individual document icons.  The following format is
used:

    ARG=flag

    See the OVERVIEW section for allowed flags.  Only one argument per line
    is allowed (sorry).  The tooltypes for the application icon are
    processed first, then the tooltypes for each document icon are
    processed before each file is loaded.

    ARG= -t10
    ARG= -l10

				    VI
			      REVISION SUMMARY

V1.27 RELEASE
    -macros run about 20% faster due to hashing of the command table
    -Maximum # of toggles raised to 256 (see IF/WHILE)
    -small fixes to the code (nothing major)
    -child windows inherit tab stops, insert mode, and wordwrap mode
    -MOUSE BUTTONS AND MOVEMENT CAN NOW BE MAPPED
    -New Commands: ICONIFY	(used to be hardwired.	Is now a command)
    -Extended Commands: GOTO	(GOTO END)
V1.26 Beta, minimal Release
    -Workbench support
    -New Command:   EXECUTE
V1.25 RELEASE
    -BSAVE does NOT UNBLOCK after saving (switch in functionality yet again)
    -various bugs fixed (IF, tabs on file save)
    -New Commands: MARGIN, REFORMAT, WORDWRAP, RESIZE,
		   TOPEDGE, LEFTEDGE, WIDTH, HEIGHT
    -Command line options added for setting the window size and an optional
     specified script file (when specified, local .EDRC not sourced).

    -Enhanced Commands: IF  ..more control with conditions, addition of
			      a couple more specifications.
		       JOIN .. functionality slightly changed
    -keymaps may now be used as macros in other commands. (macros)
    -New keymaps added to the default set.
    -Mouse movement cleaned up a little.

V1.24 Internal

V1.23 RELEASE
    -S:.EDRC now sourced instead of C:.EDRC
    -User keymappings now work in COMMAND mode (when you hit ESC).
    -You can now map the Amiga keys ('A' for Amiga, since 'a' is alt).
    -Enhanced Commands: IF/IFELSE/WHILE (optional '!' in front of cond)
			new condition 'cb' 'character in selected block'
			GOTO (can now say `goto block')
    -NewCommands:    PAGESET SAVETABS
    -Writing TABS (always 8) out to disk to save space now supported.

V1.22 RELEASE (BUF FIXES FROM 1.20)
    -'newfile' fixed
V1.21 RELEASE (BUG FIXES FROM 1.20)
    -iconify and window handling fixed
    -left mouse button now tracks the mouse.
V1.20 RELEASE
    -bug fixes: bsave now unmarks the block, bdelete now sets 'modified' flag.
	    (other small fixes).
    -enhancements: overwrite mode status indicator, find, find-replace now
	    completely implemented (yahhoo!!!)
    -changed commands:	FIND NEXT PREV: no longer loop back to the top of
	    file or top->bottom in the case of PREV.  DELINE will now delete
	    text on the line if there is only one line of text.
    -enhanced commands: GOTO REPEAT
    -new commands: SAVEMAP SAVESMAP TOGGLE SETTOGGLE RESETTOGGLE TLATE
		   IF IFELSE WHILE BSOURCE
		   FINDSTR REPSTR FINDR NEXTR PREVR
		   NEWWINDOW
    -new keymappings: (see a-s, a-S, f3)
    -window iconification with mouse menu button.


V1.12 RELEASE
    -cursor is now pen #3 rather than #1.
    -changeover to AZTEC C, smaller executable.
    -now maps shift space to a space.
    -new commands: REMEOL, WLEFT, WRIGHT
    -display bug fixes (SPLIT)
    -FIND/PREV/NEXT will now abort a REPEAT if string not found.

V1.11 RELEASE NOTES
    -Bug fixes (mainly graphical mistakes).
    -User keymappings are disabled in command mode (so you can unmap
      single ascii characters you may have mapped).
    -Illegal key combinations no longer give garbage (e.g. ALT-CURSOR-DOWN)
      you can, of course, still map them to anything you wish.
    -Save now checks for error conditions on write.
    -Uses Default Console Keymap (i.e. no longer assumes USA)... but there
      *is* some stangeness.

V1.00 RELEASE NOTES
    -has find, but no replace function
    -marked blocks are not highlighted
    -assumes USA keyboard		    (fixed 1.11)
    -disk files written out use spaces instead of tabs&spaces
    -No scroll bar yet.


				    VII
				COMPILING

DME now compiles only under AZTEC.  You must compile with the 32 bit int
option, but may use the small code/data model.	You must use V3.00 or above
of MY.LIB  (MY[L]32.LIB, dated no sooner than MARCH 1987).  I use a
precompiled symbol file containing ALL the amiga includes (but not any
aztec standard includes).  Look at the MAKEFILE for further information



SHAR_EOF

dillon%cory.berkeley.edu@berkeley.edu (Matt Dillon) (07/01/87)

	This is part 1 of 2 of the sources to dme.
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This is part  1 out of  2.
# This archive created: Wed Jul  1 07:25:23 1987
# By: Craig Norborg (Purdue University Computing Center)
#	Run the following text with /bin/sh to create:
#	command.c
#	globals.c
#	main.c
#	makefile
#	text1.c
cat << \SHAR_EOF > command.c

/*
 * COMMAND.C
 *
 *	(C)Copyright 1987 by Matthew Dillon, All Rights Reserved
 *
 * 'c                single character (typing)
 * `string'          string of characters w/ embedded `' allowed!
 *
 * name arg arg      command name. The arguments are interpreted as strings
 *		     for the command.
 *
 * Any string arguments not part of a command are considered to be typed
 * text.
 */

#include "defs.h"

extern char *breakout();

short ComLineMode;
char Abortcommand;

typedef struct {
   char *name;	  /* command name					*/
   short args;	  /* # of arguments					*/
   short sl;	  /* 1 if stays within bounds of the current line	*/
   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();

extern int do_iconify(), do_tomouse();


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

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

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

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


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

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

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

    if (++level > 20) {
	title("Recursion Too Deep!");
	--level;
	return(0);
    }
    while (arg = breakout(&str, &quoted)) {
	if (quoted) {
	    text_write(arg);
	    continue;
	}
	for (i = 0; arg[i]; ++i) {
	    if (arg[i] >= 'A' && arg[i] <= 'Z')
		arg[i] += 'a' - 'A';
	}
	if (arg[0] >= 'a' && arg[0] <= 'z') {
	    register COMM *comm = &Comm[hindex[arg[0]-'a']];
	    for (; comm->name && comm->name[0] == arg[0]; ++comm) {
		if (strcmp(arg, comm->name) == 0) {
		    av[0] = (u_char *)comm->name;
		    for (j = 1; j <= comm->args; ++j) {
			av[j] = (u_char *)breakout(&str, &quoted);
			if (!av[j]) {
			    title("Bad argument");
			    --level;
			    return(0);
			}
		    }
		    if (comm->sl || !ComLineMode)
			(*comm->func)(-1);
		    if (Abortcommand)
			goto fail;
		    goto loop;
		}
	    }
	}
	/* Command not found, check for macro	*/

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

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


do_source()
{
    char buf[256];
    long fi;
    register short i;

    if (fi = xopen(av[1], "r", 256)) {
	while (xgets(fi, buf, 255)) {
	    for (i = 0; buf[i]; ++i) {
		if (buf[i] == 9)
		    buf[i] = ' ';
	    }
	    do_command(buf);
	}
	xclose(fi);
    } 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()
{
    u_char *ptr = av[1];
    char buf1[256];
    char buf2[256];
    unsigned long n;

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


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

    *quoted = 0;
    while (*str == ' ')
	++str;
    if (!*str)
	return(NULL);
    if (*str == '\'') {
	if (str[1]) {
	    *quoted = 1;
	    base = str + 1;
	    if (str[2])
		++str;
	    *str = '\0';
	    *ptr = str;
	    return(base);
	}
	return(NULL);
    }
    if (*str == '`') {
	short count = 1;
	base = ++str;
	while (*str && count) {
	    if (*str == '`')
		++count;
	    if (*str == '\'')
		--count;
	    ++str;
	}
	if (count == 0) {
	    --str;
	    *quoted = 1;
	    *str = '\0';
	    *ptr = str + 1;
	    return(base);
	}
    }
    base = str;
    while (*str && *str != ' ')
	++str;
    if (*str) {
	*str = '\0';
	*ptr = str + 1;
	return(base);
    }
    *ptr = str;
    return(base);
}


SHAR_EOF
cat << \SHAR_EOF > globals.c

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

#include "defs.h"

#define TU	    titleupdate = 1
#define nomemory()  {memoryfail = 1; TU;}

ED E, *Ep;			/* Current File */
ED *Base;			/* doubly linked list of Files	*/

char Nsu;
char Savetabs;
char titleupdate;
char memoryfail;
u_char Current[256];
short Clen;


SHAR_EOF
cat << \SHAR_EOF > main.c

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

#include "defs.h"

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


NW Nw = {
   0, 1, 640, 199, -1, -1,
   IDCMPFLAGS,
   ACTIVATE|WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|RMBTRAP,
   NULL, NULL, (u_char *)"   WAIT   ",
   NULL, NULL,
   32, 32, -1, -1,
   WBENCHSCREEN
};

short Sharedrefs;
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;

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

int Enable_Abort;

extern ED E, *Ep, *Base;
extern char memoryfail;
extern WIN *opensharedwindow();
extern IMESS *GetMsg();

static char *Ffile;

main(mac, mav)
char *mav[];
{
    register IMESS *im;
    register WIN *win;
    char nf, ni;	    /* # files on command line	*/
    char notdone;
    char iawm = 0;
    char dontwait = 0;
    short i;
    short Code;

    init_command();
    Nwwidth = Nw.Width;
    Nwheight= Nw.Height;
    Nwtopedge=Nw.TopEdge;
    Nwleftedge=Nw.LeftEdge;
    Enable_Abort = 0;
    if (!openlibs(INTUITION_LIB|GRAPHICS_LIB))
	exiterr("cannot open intuition or graphics library");
    if (mac == 0) {
	long oldlock;
	Wdisable = 0;
	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;
	E.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);
	    }
	    E.dirlock = CurrentDir(oldlock);
	} else {
	    str = mav[i];
	    if (*str == '-')
		continue;
	}
	do_newwindow(nf > 1, ni * 10);
	++ni;
	av[0] = (u_char *)"newfile";
	av[1] = (u_char *)str;
	do_edit();
	MForceTitle = 1;
	window_title();
    }
    if (i == 1) 		    /* no files to edit */
	do_newwindow(nf > 1, ni * 10);

    mountrequest(0);
    av[0] = NULL;
    av[1] = (u_char *)"s:.edrc";
    do_source();
    av[0] = NULL;
    av[1] = (u_char *)((Ffile) ? Ffile : ".edrc");
    do_source();
    mountrequest(1);
    title("DME V1.27 (c)CopyRight 1987 Matthew Dillon,  All Rights Reserved                  ");
    text_titleupdate();
loop:
    if (!E.iconmode)
	text_cursor(1);
    for (notdone = 1; !Quitflag && notdone;) {
	char mmove = 0;
	short mqual;

	if (!E.iconmode)
	    window_title();
	if (dontwait)
	    --dontwait;
	else
	    WaitPort(Win->UserPort);
	while (im = (IMESS *)GetMsg(Win->UserPort)) {
	    Abortcommand = 0;
	    Code = im->Code;
	    if (im->IDCMPWindow != Win) {
		Overide = 0;
		if (ComLineMode)
		    escapecomlinemode();
		text_sync();
		MShowTitle = 0;
		if (!E.iconmode)
		    window_title();
		if (text_switch(im->IDCMPWindow) == 0) {
		    ReplyMsg(im);
		    continue;
		}
		if (!E.iconmode) {
		    set_window_params();
		    window_title();
		}
	    }
	    Mx = im->MouseX;
	    My = im->MouseY;
	    switch(im->Class) {
	    case NEWSIZE:
		if (!E.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 (E.iconmode || iawm) {
			uniconify();
			break;
		    }
		    ReportMouse(-1, Win);
		    uniconify();
		    text_cursor(0);
		    keyctl(im->Code, im->Qualifier);
		    text_cursor(1);
		    break;
		case SELECTUP:
		case MENUUP:
		    ReportMouse(0, Win);
		    break;
		}
		break;
	    case RAWKEY:
		if (E.iconmode) {
		    uniconify();
		    break;
		}
		text_cursor(0);
		keyctl(im->Code, im->Qualifier);
		text_cursor(1);
		break;
	    case CLOSEWINDOW:
		if (ComLineMode)
		    escapecomlinemode();
		text_sync();
		notdone = 0;
		break;
	    case ACTIVEWINDOW:
		if (!E.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(QMOVE, mqual);
	    text_cursor(1);
	}
	closesharedwindow(NULL);
    }
boom:
    if (E.Modified && !Overide) {
	uniconify();
	Overide = 1;
	SetWindowTitles(Win, "*** File has been modified ***", NULL);
	Quitflag = 0;
	goto loop;
    }
    SetWindowTitles(Win, "", -1);
    text_uninit();			/* uninitialize text portion	*/
    closesharedwindow(Win);
    if (Base) {
	Quitflag = 0;
	Win = E.Win;			/* make arbitrary other window act. */
	Rp = Win->RPort;
	if (!E.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 (!E.iconmode) {
	E.Winx	    = Win->LeftEdge;
	E.Winy	    = Win->TopEdge;
	E.Winwidth  = Win->Width;
	E.Winheight = Win->Height;
	Nw.Height = 10;
	Nw.Width  = 20 + 5*8 + strlen(E.Name)*8;
	Nw.LeftEdge= E.IWinx;
	Nw.TopEdge = E.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    ", E.Name, ((E.Modified) ? "(mod)":""));
	closesharedwindow(Win);
	Win = E.Win = Ep->Win = opensharedwindow(&Nw);
	Nw.Flags |= WINDOWSIZING|WINDOWDEPTH;
	Nw.Flags &= ~BORDERLESS;
	Rp = Win->RPort;
    }
    E.iconmode = 1;
}

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


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

    if (SizeOveride)
	msadj = 0;
    if (Ep)
	text_sync();
    Nw.Title = (u_char *)"    OK    ";
    Nw.Width = Nwwidth;
    Nw.Height= Nwheight;
    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);
    Nw.Flags |= ACTIVATE;
    if (win) {
	Win = win;			/* set new window   */
	Rp = Win->RPort;
	text_init();			/* initialize	    */
	text_load();
	set_window_params();
	if (makesmall != -1)		/* if deltaheight valid */
	    E.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);
	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    = (u_char *)text;
    pos->LeftEdge = AUTOLEFTEDGE;
    pos->TopEdge = AUTOTOPEDGE;
    pos->IText = (u_char *)"OK";
    neg->LeftEdge = AUTOLEFTEDGE;
    neg->TopEdge = AUTOTOPEDGE;
    neg->IText = (u_char *)"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);
    MShowTitle = 1;
}

window_title()
{
    static char cmodified;
    int len;
    char *mod;

    if (memoryfail) {
	SetWindowTitles(Win, " -- NO MEMORY -- ", -1);
	text_redisplay();
	memoryfail = 0;
	return(0);
    }
    if (MForceTitle) {
	cmodified = -1;
	MShowTitle = 0;
	MForceTitle = 0;
    }
    if (MShowTitle) {
	MShowTitle = 0;
	return(0);
    }
    if (text_titleupdate() || cmodified != E.Modified) {
	cmodified = E.Modified;
	mod = (E.Modified) ? " (modified)" : "";
	sprintf(Ep->Wtitle, "%3ld/%-3ld %s%s ", text_lineno(), text_lines(), 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;
	}
	SetWindowTitles(Win, Ep->Wtitle, -1);
    }
}

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())
	puts(str);
    exit(1);
}

breakcheck()
{
   if (SetSignal(0,0) & SIGBREAKF_CTRL_C)
      return (1);
   else
      return (0);
}

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

/*
 *  leftedge n
 *  topedge  n
 *  width    n
 *  height   n
 */

do_windowparm()
{
    switch(av[0][0]) {
    case 'l':
	Nwleftedge = atoi(av[1]);
	break;
    case 't':
	Nwtopedge = atoi(av[1]);
	break;
    case 'w':
	Nwwidth = atoi(av[1]);
	break;
    case 'h':
	Nwheight = atoi(av[1]);
	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);
}



SHAR_EOF
cat << \SHAR_EOF > 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

CFLAGS= +L +Ivd0:include/symbols.m
OBJS= globals.o command.o keyboard.o main.o text1.o text2.o subs.o

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

all: $(OBJS)
    ln +Q $(OBJS) -lmyl32 -lc32 -O c:dme

arc:
    -delete ram:dme.arc
    arc a ram:dme.arc dme.doc TODO c:dme

src:
    -delete ram:dmesrc.arc
    arc a ram:dmesrc makefile defs.h globals.c command.c keyboard.c main.c text1.c text2.c subs.c

SHAR_EOF
cat << \SHAR_EOF > text1.c

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

#include "defs.h"

#define TU	    titleupdate = 1
#define nomemory()  {memoryfail = 1; TU;}

text_init()
{
    register ED *e;
    long dirlock;

    text_switch(NULL);
    dirlock = E.dirlock;
    e = (ED *)MAllocate(sizeof(ED));
    if (e == NULL)
	return(0);
    bzero(&E, sizeof(E));
    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 = (u_char **)MAllocate(sizeof(char *) * E.Maxlines);
    E.List[0] = MAllocate(1);
    E.List[0][0] = Current[0] = Clen = 0;
    E.BSline = E.BEline = -1;
    E.IWiny = 16;
    E.dirlock = dirlock;	/* workbench support	*/
    *e = E;
    llink(&Base, e);
    strcpy(E.Name, "ram:unnamed");
    Ep = e;
    text_cursor(1);
    return(1);
}


text_switch(win)
WIN *win;
{
    register ED *e;
    register ED *next, **prev;

    if (Ep) {
	text_sync();
	E.next = Ep->next;
	E.prev = Ep->prev;
	strcpy(E.Wtitle, Ep->Wtitle);
	*Ep = E;
    }
    if (win) {
	for (e = Base; e; e = e->next) {
	    if (e->Win == win) {
		Ep = e;
		Win = win;
		Rp = Win->RPort;
		E = *e;
		text_load();
		return(1);
	    }
	}
	return(0);
    }
}


text_sync()
{
    char redraw = 0;
    short len;
    u_char *ptr;

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

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

text_titleupdate()
{
    int r = titleupdate;

    titleupdate = 0;
    return(r);
}

text_lineno()
{
    return(E.Line + 1);
}

text_lines()
{
    return(E.Lines);
}

text_colno()
{
    return(E.Column);
}

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

text_imode()
{
    return(E.Insertmode);
}

text_tabsize()
{
    return((int)E.Tabstop);
}

u_char *
text_name()
{
    return(E.Name);
}


text_uninit()
{
    register int i;
    register ED *e;

    for (i = 0; i < E.Lines; ++i)
	FreeMem(E.List[i], strlen(E.List[i])+1);
    FreeMem(E.List, E.Maxlines * sizeof(char *));

    lunlink(Ep);
    FreeMem(Ep, sizeof(ED));
    if (Base) {
	E = *Base;
	Ep= Base;
	text_load();
    } else {
	Ep = NULL;
    }
}

inversemode(n)
{
    if (n) {
	SetAPen(Rp, 3);
	SetDrMd(Rp, JAM2|INVERSVID);
    } else {
	SetAPen(Rp, 1);
	SetDrMd(Rp, JAM2);
    }
}

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


text_position(col, row)
{
    TU;
    text_sync();
    if (col == 0)
	col = -1;
    E.Column = E.Topcolumn + col;
    if (E.Column > 254)
	E.Column = 254;
    if (E.Column < 0)
	E.Column = 0;
    E.Line = E.Topline + row;
    if (E.Line >= E.Lines)
	E.Line = E.Lines - 1;
    if (E.Line < 0)
	E.Line = 0;
    text_load();
    text_sync();
}


text_displayseg(start, n)
{
    register short i, c;
    register u_char *ptr;
    char ib;

    if (Nsu)
	return(0);
    for (i = start; i < start+n && E.Topline + i < E.Lines; ++i) {
	if (ComLineMode) {
	    if (E.Topline + i != E.Line)
		continue;
	    ptr = Current;
	} else {
	    ptr = E.List[E.Topline + i];
	}
	for (c = E.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);
    SetAPen(Rp, 1);
    text_displayseg(0,Rows);
}

text_redisplaycurrline()
{
    int row = E.Line - E.Topline;

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

text_write(str)
u_char *str;
{
    short len = strlen(str);
    short i;

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


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

do_down()
{
    if (E.Line + 1 < E.Lines) {
	TU;
	text_sync();
	++E.Line;
	text_load();
	if (E.Line - E.Topline >= Rows) {
	    if (Nsu == 0) {
		ScrollRaster(Rp,0,Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
		++E.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;
    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 && E.Topline >= E.Lines - Rows)
	    return(0);
	text_sync();
	TU;
	E.Line += n;
	E.Topline += n;
	if (E.Line >= E.Lines)
	    E.Line = E.Lines - 1;
	if (E.Line < 0)
	    E.Line = 0;
	if (E.Topline >= E.Lines)
	    E.Topline = E.Lines - Rows - 1;
	if (E.Topline < 0)
	    E.Topline = 0;
	text_load();
	if (!text_sync())
	    text_redisplay();
	break;
    case 's':
	pctg = atoi(av[1]);
	break;
    }
}


do_downadd()
{
    u_char *ptr;

    if (E.Line + 1 == E.Lines) {
	E.Modified = 1;
	if (makeroom(32) && (ptr = MAllocate(1))) {
	    E.List[E.Lines] = ptr;
	    *ptr = 0;
	    ++E.Lines;
	} else {
	    nomemory();
	}
    }
    do_down();
}


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

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

do_tab()
{
    register short n;

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

do_backtab()
{
    register short n;

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

do_return()
{
    u_char buf[256];

    if (ComLineMode) {
	strcpy(buf, Current);
	escapecomlinemode();
	do_command(buf);
    } else {
	E.Column = 0;
	text_sync();
	do_downadd();
    }
}

do_bs()
{
    if (E.Column) {
	bmov(Current + E.Column, Current + E.Column - 1, Clen - E.Column + 1);
	--E.Column;
	--Clen;
	if (E.Column < E.Topcolumn) {
	    text_sync();
	} else {
	    ScrollRaster(Rp, Xsize, 0,
		COL(E.Column - E.Topcolumn),
		ROW(E.Line   - E.Topline),
		COL(Columns)-1,
		ROW(E.Line - E.Topline + 1)-1
	    );
	    if (Clen >= E.Topcolumn + Columns) {
		Move(Rp, COLT(Columns-1), ROWT(E.Line - E.Topline));
		Text(Rp, Current + E.Topcolumn + Columns - 1, 1);
	    }
	}
	if (ComLineMode == 0 && E.Wordwrap)
	    do_reformat(0);
    } else {
	Abortcommand = 1;
    }
}


/*
 * esc, escimm
 */

int Savetopline, Savecolumn, Savetopcolumn;

do_esc()
{
    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 = E.Topline;
    Savecolumn	= E.Column;
    Savetopcolumn = E.Topcolumn;
    E.Column	= Clen;
    E.Topcolumn = 0;
    E.Topline	= E.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()
{
    if (ComLineMode) {
	ComLineMode = 0;
	returnoveride(0);
	E.Topline = Savetopline;
	E.Column  = Savecolumn;
	E.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()
{
    if (Current[E.Column]) {
	bmov(Current + E.Column + 1, Current + E.Column, Clen - E.Column);
	--Clen;
	ScrollRaster(Rp, Xsize, 0,
	    COL(E.Column - E.Topcolumn),
	    ROW(E.Line - E.Topline),
	    COL(Columns)-1,
	    ROW(E.Line - E.Topline + 1) - 1
	);
	if (Clen >= E.Topcolumn + Columns) {
	    Move(Rp, COLT(Columns-1), ROWT(E.Line-E.Topline));
	    Text(Rp, Current+E.Topcolumn+Columns-1, 1);
	}
	if (ComLineMode == 0 && E.Wordwrap)
	    do_reformat(0);
    }
}

do_top()
{
    text_sync();
    E.Line = 0;
    TU;
    text_load();
    text_sync();
}

do_bottom()
{
    text_sync();
    E.Line = E.Lines - 1;
    TU;
    text_load();
    text_sync();
}

do_firstcolumn()
{
    if (E.Column) {
	E.Column = 0;
	text_sync();
    }
}

do_firstnb()
{
    for (E.Column = 0; Current[E.Column] == ' '; ++E.Column);
    if (Current[E.Column] == 0)
	E.Column = 0;
    text_sync();
}

do_lastcolumn()
{
    short i;

    text_sync();
    i = (ComLineMode) ? Clen : strlen(E.List[E.Line]);
    if (i != E.Column) {
	E.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 u_char *ptr = av[1];

    i = 0;
    n = -1;

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

do_screentop()
{
    text_sync();
    TU;
    E.Line = E.Topline;
    text_load();
    text_sync();
}

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

static u_char Fstr[256];
static u_char 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 u_char *ptr;
    register int i, col;

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

    col = E.Column;
    if (col >= strlen(E.List[E.Line]))
	col = strlen(E.List[E.Line]);
    for (i = E.Line;;) {
	ptr = E.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 >= E.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(E.List[i]);
	}
    }
    MShowTitle = 1;
    title("Pattern Not Found");
    Abortcommand = 1;
    return;

found:
    E.Line = i;
    E.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();
    }
}


SHAR_En"b

dillon%cory.berkeley.edu@berkeley.edu (Matt Dillon) (07/01/87)

	This is part 2 of 2 of the sources to dme.

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This is part  2 out of  2.
# This archive created: Wed Jul  1 07:25:23 1987
# By: Craig Norborg (Purdue University Computing Center)
#	Run the following text with /bin/sh to create:
#	defs.h
#	keyboard.c
#	subs.c
#	text2.c
cat << \SHAR_EOF > 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

#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 u_char;
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 u_char *av[];
extern char Wdisable;


typedef struct _ED {
    struct _ED *next, **prev;
    WIN *Win;
    long Topline, Topcolumn;
    long Line, Column;
    long Lines, Maxlines;
    u_char **List;
    u_char Name[64];
    u_char Wtitle[130];
    char Modified;
    u_char Tabstop;
    u_char Margin;
    char Insertmode;
    char Wordwrap;
    char iconmode;	    /* window in icon mode		    */
    short Winx, Winy, Winwidth, Winheight;
    short IWinx, IWiny;
    long BSline, BEline;    /* block start and end lines	    */
    short BSchar, BEchar;   /* char start on BSline, end on BEline  */
    long dirlock;	    /* directory lock			    */
} ED;


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

extern ED E, *Ep, *Base;
extern char Savetabs, titleupdate;
extern char memoryfail, Nsu;
extern u_char Current[256];
extern short Clen;
extern char  Abortcommand, MShowTitle;
extern short ComLineMode;
extern RP *Rp;
extern WIN *Win;

extern u_char *MAllocate();
extern u_char *AllocMem(), *strcpy(), *malloc();
extern char *keyspectomacro();

extern void search_operation();



SHAR_EOF
cat << \SHAR_EOF > keyboard.c

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

#include "defs.h"

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 XBITSET(array,bit)   (array[(bit)>>3] |= 1<<((bit)&7))
#define XBITTEST(array,bit)  (array[(bit)>>3] & 1<<((bit)&7))


#define HASHSIZE  64

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

HASH *Hash[HASHSIZE];

static u_char isascii[0x80/8];	/* is printable ascii	*/
static u_char isalpha[0x80/8];	/* is alpha a-z/A-Z	*/
static u_char ctoa[0x80];	/* cvt to character	    */
static u_char cstoa[0x80];	/* cvt to shifted chacter   */

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;

    static struct {
	char *from, *to;
    } defmap[] = {
	"esc",      "esc",
	"return",   "return insline up firstnb down",
	"enter",    "return",
	"up",       "up",
	"down",     "down",
	"right",    "right",
	"left",     "left",
	"bs",       "bs",
	"del",      "del",
	"help",     "newwindow newfile s:DME.DOC escimm `find '",
	"tab",      "tab",
	"s-up",     "top",
	"s-down",   "bottom",
	"s-right",  "last",
	"s-left",   "first",
	"s-tab",    "backtab",
	"s-del",    "deline",
	"s- ",      "` '",              /* shift space to space */
	"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-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 '",
	"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();
    loaddefaultkeymap();
    for (i = 0; defmap[i].from; ++i) {
	u_char code, qual;
	if (get_codequal(defmap[i].from, &code, &qual))
	    addhash(code, 1, 0xFF, qual, defmap[i].to);
    }
}

/*
 *  Go through keycodes $00 to $4F and load the ctoa[], cstoa[], and
 *  isalpha[] char tables from the default console keymap.
 */

loaddefaultkeymap()
{
    CIO cio;
    struct KeyMap km;

    /*
     * Note: -1 specification for unit # means that we are not openning
     * a real console.	We can only execute a CD_ASKDEFAULTKEYMAP through
     * it.
     */

    if (!OpenDevice("console.device", -1, &cio, 0)) {
	cio.io_Command = CD_ASKDEFAULTKEYMAP;
	cio.io_Data = (APTR)&km;
	cio.io_Length = sizeof(km);
	DoIO(&cio);
	loadhilo(km.km_LoKeyMapTypes, km.km_LoKeyMap, km.km_LoCapsable, 0, 0x40, 0x00);
	loadhilo(km.km_HiKeyMapTypes, km.km_HiKeyMap, km.km_HiCapsable, 0, 0x10, 0x40);
	CloseDevice(&cio);
    } else {
	if (Output())
	    puts ("Unable to get console keymap");
    }
}


/*
 *  Decode plain and shifted keys only.  Ignore strings larger than
 *  a single character (thus things like the cursor keys do not get
 *  mapped)
 */

loadhilo(types, map, caps, is, ie, ia)
u_char *types;
u_char *caps;
long *map;
{
    register long n;
    register int idx;
    register u_char *ptr;
    u_char c;

    for (; is < ie; ++is) {
	n = map[is];
	if (n && (types[is] & 0x60)) {	    /*	STRING 0x40 or BUG 0x20 */
	    ptr = (u_char *)n;
	    n = 0;
	    if (ptr[0] == 0)
		n = ptr[1];
	    if (ptr[0] == 1)
		n = ptr[ptr[1]];
	    if (types[is] & KCF_SHIFT) {
		if (ptr[2] == 0)
		    n |= ptr[3] << 8;
		if (ptr[2] == 1)
		    n |= ptr[ptr[3]] << 8;
	    }
	}
	idx = is + ia;
	c = n;
	ctoa[idx] = c;
	cstoa[idx] = (n>>8) & 0xFF;
	if (caps[is>>3] & (1 << (is&7)))
	    XBITSET(isalpha,idx);
	if (c >= 32 && c != 0x7F && ctoa[idx])
	    XBITSET(isascii,idx);
    }
}


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

    for (hash = Hash[0x44 % HASHSIZE]; hash; hash = hash->next) {
	if (hash->code == 0x44 && hash->qual == 0) {
	    if (n) {
		str = (u_char *)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)
u_char code, stat, mask, qual;
u_char *str;
{
    register HASH **p, *hash;

    hash = *(p = &Hash[code % HASHSIZE]);
    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)
u_char code, mask, qual;
{
    register HASH *hash, **p;

    hash = *(p = &Hash[code % HASHSIZE]);
    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);
}


keyctl(code, qual)
register USHORT qual;
{
    register u_char c, c2;
    register HASH *hash;

    code &= 0xFF;

    if ((code & 0x78) == 0x60)	    /*	forget qualifier keys	*/
	return(0);
    if (code & 0x80)		    /*	forget upstrokes	*/
	return(0);

    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) && (code <= 0x37) && XBITTEST(isalpha,code))
	c2 |= QUAL_SHIFT;
    if (qual & IEQUALIFIER_LEFTBUTTON)
	c2 |= QUAL_LMB;
    if (qual & IEQUALIFIER_MIDBUTTON)
	c2 |= QUAL_MMB;
    if (qual & (IEQUALIFIER_RBUTTON))
	c2 |= QUAL_RMB;
    for (hash = Hash[code % HASHSIZE]; hash; hash = hash->next) {
	if (hash->code == code) {
	    if ((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) {
	char buf[256];
	/*printf ("c2 %lx BIT: %lx\n", c2, XBITTEST(isascii,code));*/
	if (c2 || !ComLineMode || !XBITTEST(isascii,code)) {
	    strcpy(buf, hash->str);
	    do_command(buf);
	    return(0);
	}
    }

    if (code < 0x50) {
	c = (c2 & QUAL_SHIFT) ? cstoa[code] : ctoa[code];
	if (c2 & QUAL_CTRL)
	    c &= 0x1F;
	if (c && (c2 & QUAL_ALT))
	    c |= 0x80;
	if (c && (c2 & QUAL_AMIGA))
	    c |= 0xC0;
	if (c) {
	    u_char buf[3];
	    buf[0] = '\'';
	    buf[1] = c;
	    buf[2] = 0;
	    do_command(buf);
	}
    }
}

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

long lname[] = {
    LN('e','s','c',0x45), LN('f','1', 0 ,0x50), LN('f','2', 0 ,0x51),
    LN('f','3', 0 ,0x52), LN('f','4', 0 ,0x53), LN('f','5', 0 ,0x54),
    LN('f','6', 0 ,0x55), LN('f','7', 0 ,0x56), LN('f','8', 0 ,0x57),
    LN('f','9', 0 ,0x58), LN('f','1','0',0x59), LN('d','e','l',0x46),
    LN('b','a','c',0x41), LN('b','s', 0 ,0x41), LN('t','a','b',0x42),
    LN('h','e','l',0x5F), LN('r','e','t',0x44), LN('u','p', 0 ,0x4C),
    LN('d','o','w',0x4D), LN('r','i','g',0x4E), LN('l','e','f',0x4F),
    LN('e','n','t',0x43), LN('n','k','-',0x4A), LN('n','k','.',0x3C),
    LN('n','k','0',0x0F),
    LN('n','k','1',0x1D), LN('n','k','2',0x1E), LN('n','k','3',0x1F),
    LN('n','k','4',0x2D), LN('n','k','5',0x2E), LN('n','k','6',0x2F),
    LN('n','k','7',0x3D), LN('n','k','8',0x3E), LN('n','k','9',0x3F),
    LN('l','m','b',0x68), LN('m','m','b',0x6A), LN('r','m','b',0x69),
    LN('m','m','o',QMOVE),
    0
};


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

    if (get_codequal(str, &code, &qual)) {
	for (hash = Hash[code % HASHSIZE]; hash; hash = hash->next) {
	    if (hash->code == code) {
		if (hash->qual == (qual & hash->mask))
		    return(hash->str);
	    }
	}
    }
    title ("Bad command or unmapped key");
    return(NULL);
}


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

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

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

u_char *
cqtoa(code, qual)
{
    static u_char buf[32];
    register u_char *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);
}


do_map()
{
    u_char code, qual;

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

do_unmap()	  /* key   */
{
    u_char 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;
    u_char buf[256];
    long fi;
    register int i;
    register HASH *hash;

    fi = xopen(av[1], "w", 512);
    if (fi) {
	sysalso = av[0][4] == 's';
	for (i = 0; i < HASHSIZE; ++i) {
	    for (hash = Hash[i]; hash; hash = hash->next) {
		if (hash->stat == 0 || sysalso) {
		    sprintf(buf, "map `%s' `%s'", cqtoa(hash->code, hash->qual), hash->str);
		    xputs(fi, buf);
		}
	    }
	}
	xclose(fi);
	if (err)
	    title ("Unable to Write");
	else
	    title ("OK");
    } else {
	title("Unable to open file");
    }
}


SHAR_EOF
cat << \SHAR_EOF > subs.c

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


#include "defs.h"

makemygadget(gad)
register struct Gadget *gad;
{
    static unsigned long ga[] = {
	0x00000000,	/* 32 pixels across */
	0x00FDCBFD,
	0xFFFDDFFD,
	0x00000000,
	0x00DFDDDF,
	0x00000000,
	0xBC0EF00B,
	0x00000000,
	0xBFC00CDC,
	0x00000000,
	0xA00DF00F,
	0x00000000,
	0x00000000,

	0x00000000,
	0x00FDCBFD,
	0xFFFDDFFD,
	0x00000000,
	0x00DFDDDF,
	0x00000000,
	0xBC0EF00B,
	0x00000000,
	0xBFC00CDC,
	0x00000000,
	0xA00DF00F,
	0x00000000,
	0x00000000
    };
    static struct Image image = {
	0, 0, 20, sizeof(ga)/4/2, 2, (APTR)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 255 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);
}

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

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) {
		puts ("Examine failed");
		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);
}



SHAR_EOF
cat << \SHAR_EOF > text2.c

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

#include "defs.h"

#define TU	    titleupdate = 1
#define nomemory()  {memoryfail = 1; TU;}

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

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

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


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

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


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

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

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

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

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

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

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

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

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

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


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


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

do_insline()
{
    register u_char *ptr;

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

do_deline()
{
    int delline;

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

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

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

	title("Loading...");
	while (xgets(fi, buf, 255)) {
	    failed = 0;
	    for(i = j = 0; buf[i] && j < 254; ++i) {
		if (buf[i] == 9) {		    /* expand tabs (always 8)	*/
		    do {
			ebuf[j++] = ' ';
		    } while ((j % 8) && j < 254);
		} else {
		    ebuf[j++] = buf[i];
		}
	    }
	    while (j && ebuf[j-1] == ' ')
		--j;
	    ebuf[j] = 0;
	    if (makeroom(256) && (ptr = MAllocate(j+1))) {
		E.List[E.Lines++] = ptr;
		bmov(ebuf, ptr, j+1);
	    } else {
		nomemory();
		oktitle = 0;
		break;
	    }
	}
	if (oktitle)
	    title("OK");
    } else {
	title("File Not Found");
    }
    xclose(fi);
    if (Wbs && Wdisable == 0)
	CurrentDir(oldlock);
    if (E.Lines != 1 && lines == 1 && E.List[0][0] == 0) {
	E.Modified = 0;
	E.Line = 0;
	FreeMem(E.List[0], strlen(E.List[0])+1);
	bmov(E.List+1, E.List, sizeof(char *) * (--E.Lines));
    } else {
	if (!failed && lines <= E.Lines - 1) {
	    E.BSline = lines;
	    E.BEline = E.Lines-1;
	    do_bmove();
	}
    }
    text_load();
    text_redisplay();
}

static char blockmode;

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

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

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

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

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


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

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


do_bdelete()
{
    register long i, n;

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


do_bcopy()
{
    register u_char **list;
    register long lines, i;
    register ED *e;

    if (blockok()) {
	text_sync();
	lines = E.BEline - E.BSline + 1;
	list = (u_char **)MAllocate(sizeof(char *) * (E.Lines+lines));
	if (list) {
	    for (i = 0; i < lines; ++i) {
		list[E.Line + i] = MAllocate(strlen(E.List[E.BSline+i])+1);
		strcpy(list[E.Line + i], E.List[E.BSline+i]);
	    }
	    bmov(E.List+0, list, E.Line * sizeof(char *));
	    bmov(E.List+E.Line, list + E.Line + lines, (E.Lines-E.Line)*sizeof(char *));
	}
	FreeMem(E.List, E.Maxlines * 4);
	E.List = list;
	E.Lines += lines;
	E.Maxlines = E.Lines;
	text_load();
	E.BSline = E.BEline = -1;
	if (!text_sync())
	    text_redisplay();
    }
}


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

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


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

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

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

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

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


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

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

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


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

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

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

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

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

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

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

u_char *
MAllocate(bytes)
{
    return(AllocMem(bytes, MEMF_CLEAR|MEMF_PUBLIC));
}


makeroom(n)
{
    register u_char **Newlist;

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


SHAR_EOF