wecker@cookie.dec.com.UUCP (02/21/87)
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# overview
# makefile
# uemacs.hlp
# ebind.h
# edef.h
# efunc.h
# epath.h
# estruct.h
# This archive created: Fri Feb 20 17:44:26 1987
echo shar: extracting overview
sed 's/^XX//' << \SHAR_EOF > overview
XX This set of 4 shar files contains my own version of micro EMACS that I have
XX been using for over a year. I am making this software available because it
XX has been so useful to me.... however:
XX
XX I WILL NOT SUPPORT IT!!! (caveat emptor)
XX
XX The file uemacs.hlp is the only documentation that exists.
XX
XX Editors are kind of a religous issue... so let's not get into word fights.
XX I like EMACS. I do not like mice/keypads/function keys while editing. If
XX you want a good portable EMACS, take a look at this kit.
XX
XX This is an UNSUPPORTED version (my own).. but is the ONLY editor I use on
XX the AMIGA, VMS and ULTRIX. You only need to change one define in estruct.h
XX (the machine you're on) and recompile (I use Manx on the Amiga).
XX
XX It includes:
XX
XX - Full regular expression pattern matching
XX - My own micro-lisp for batch mode editing
XX - sub-process windows (under ULTRIX)
XX - Keypad support on VMS and ULTRIX (which I never use so I
XX never got around to checking it out on the AMIGA)
XX - Any size window on VMS and ULTRIX (number of rows)
XX - Only 75k in size
XX - Built in Modes:
XX WRAP - auto wrap
XX EXACT - exact (case-sensitive) searching
XX LISP - language mode
XX MODULA - language mode
XX C - language mode
XX SLOW - slow speed (1200 baud) terminal optimizations
XX VIEW - read only mode
XX - LOTS AND LOTS of bug fixes from the standard PD version
XX - Too many other features to list.. take a look at UEMACS.HLP
XX
XX Again, I WILL NOT SUPPORT THIS EDITOR. It is for my own personal use,
XX but you are welcome to use it however you see fit.
XX
XX dave decwrl!cookie.dec.com!wecker
XX
XX
SHAR_EOF
if test 1618 -ne "`wc -c overview`"
then
echo shar: error transmitting overview '(should have been 1618 characters)'
fi
echo shar: extracting makefile
sed 's/^XX//' << \SHAR_EOF > makefile
XXCFLAGS = -O
XXLFLAGS = -O -ltermcap -lc
XX
XXOFILES = ansi.o basic.o bind.o buffer.o display.o file.o \
XX fileio.o line.o lisp.o lock.o main.o random.o region.o \
XX search.o spawn.o tcap.o termio.o window.o word.o
XX
XXHFILES = estruct.h edef.h efunc.h epath.h ebind.h
XX
XXuemacs : $(OFILES)
XX $(CC) -o uemacs $(OFILES) $(LFLAGS)
XX
XX#$(OFILES): $(HFILES)
XX
XXinstall :
XX install -c -m 775 uemacs /staff/bin/uemacs
XX
XX
SHAR_EOF
if test 398 -ne "`wc -c makefile`"
then
echo shar: error transmitting makefile '(should have been 398 characters)'
fi
echo shar: extracting uemacs.hlp
sed 's/^XX//' << \SHAR_EOF > uemacs.hlp
XX========================Micro EMACS Help File================================
XX
XXBindings: ^ = Control
XX M- = <ESC> prefix
XX K- = ansi keypad character
XX G- = ansi keypad character (with GOLD prefix)
XX
XXCommands:
XX meta prefix: "M-100 ^Xl" would go to line 100
XX numeric params come first: "^U 100 ^Xl" would go to line 100
XX extended commands: "^U 100 M-X goto-line" would go to line 100
XX init files: "(100 goto-line)" would go to line 100
XX (type Bindings as defined above (e.g. ^C for <control-C>) in files)
XX
XXModes: WRAP - perform word wrapping when the fill-column is reached
XX SLOW - do searches interactively (for slow speed terminals)
XX EXACT - do all searching with exact case matching
XX CMODE - do automatic indentation of C code
XX MMODE - do automatic indentation of MODULA code
XX LISP - do automatic indentation of LISP code
XX VIEW - set buffer to read-only
XX
XXSearching: In SLOW mode use ^F to go forward, ^R to reverse, ^G to abort
XX or any other character to terminate search and draw screen
XX All searching is done with (limited) regular expressions:
XX ^ = match beginning of line (if beginning of search)
XX $ = match end of line (if end of search)
XX [or] = match one of "or" (see below)
XX [^or]= match anything BUT "or" (see below)
XX . = match any one character
XX * = match zero or more of previous
XX + = match 1 or more of previous
XX \( \)= bracket sub expressions
XX \ = quote next character (except parens (above))
XX
XX "or" = string of characters or ranges:
XX [abcde] = [a-e] = [ab-de] = [a-cd-e]
XX
XXReplacing: \0 = entire match
XX \n = nth bracketed [\( \)] sub-expression (1 <= n <= 9)
XX
XX y = do the replacement (in query mode)
XX n = dont' do this replacement, but keep looking
XX . = stop replacing and go back to start
XX ^G = stop replacing and stary where you are
XX
XX NOTE: searches can NOT cross lines, but replacements CAN.
XX
XXmicro-LISP:
XX - only 1 buffer may be executed at a time (no recursive buffer executes).
XX - The entire contents of a buffer are viewed as a LISP progn.
XX - Values may be either INTEGERS or STRINGS (and are interchangable).
XX - All functions return a value. Non-LISP functions return success or
XX failure via a return value of 0 or 1.
XX - The startup file is .uemacsrc and is executed as a micro-LISP progn.
XX - The batch file option (-b filename) is also a LISP progn.
XX - Program statments (lists) may be arbitrarily nested.
XX - If the head of a list evaluates to an integer then this number is used
XX as a repeat count/numeric argument.
XX - Symbols are single lower case letters (a-z), and may contain any value.
XX - Progn labels may be either integers or strings.
XX - Comments run from a semi-colon (;) until the end of the line
XX - LISTS may only be used as program statements (not data) and are enclosed
XX in parenthesis (with whitespace between elements).
XX - SYMBOLS are the lower case letters a through z.
XX - SUBRS are all built in functions (there are NO user functions).
XX - INTEGERS are strings of the digits 0-9 with an optional leading "-".
XX - STRINGS are enclosed in double quotes (") and may contain:
XX normal characters
XX \r = return, \n = newline, \t = tab, \e = escape, \" = ", \\ = \
XX \#, \##, \### = ascii value where # = a digit between 0 and 7
XX - Note that strings ARE allowed to cross line boundaries
XX - All arithmetic/logic functions (except not) take 2 arguments and the
XX arguments are ALWAYS evaluated (even for "and" and "or").
XX
XXExample program:
XX ; First ask the user what to search for
XX
XX (setq a (ask "Search for what? "))
XX
XX ; Keep searching until the user says to stop, or there are no more
XX ; occurrances of the string in the buffer
XX
XX "Loop"
XX (if (not (search-forward a)) (go "Done"))
XX (if (eq (ask "Continue [y] ? ") "n") (go "Done") (go "Loop"))
XX
XX ; Now show the user the first five characters on the line
XX
XX "Done"
XX (beginning-of-line)
XX (set-mark)
XX (5 forward-character)
XX (copy-region)
XX (setq b (yank-string))
XX (ask "Line starts with: <" b "> ")
XX (return)
XX
XXKeypad: +--PF1--+--PF2--+--PF3--+--PF4--+
XX PF1 G- | GOLD | HELP | FIND | DEL L |
XX PF2 K-Q G-Q | | DESKEY| REVFND| YANK |
XX PF3 K-R G-R +---7---+---8---+---9---+-------+
XX PF4 K-S G-S | F-PARA| B-PARA|COPY- | DEL W |
XX 0 K-p G-p | COMMND| FILPAR| REGION| YANK |
XX 1 K-q G-q +---4---+---5---+---6---+---,---|
XX 2 K-r G-r | F-SCRL| B-SCRL| CUT | DEL C |
XX 3 K-s G-s | BOTTM | TOP | YANK | YANK |
XX 4 K-t G-t +---1---+---2---+---3---+-ENTER-+
XX 5 K-u G-u | F-WORD| EOL | F-CHAR| |
XX 6 K-v G-v | UPCASE| D-EOL | QUOTE | ENTER |
XX 7 K-w G-w +-------0-------+---.---+ |
XX 8 K-x G-x | BEGIN OF LINE | MARK | SUBS |
XX 9 K-y G-y | OPEN LINE | XCHG | |
XX - K-m G-m +---------------+-------+-------+
XX , K-l G-l
XX . K-n G-n
XX ENT K-M G-M
XX
XXCommand name Description (* = LISP function)
XX----------------------- -----------------------------------------------
XX+ - * / % & | * Arith: add,sub,mult,div,mod,and,or
XX= != > >= < <= * Logical comparisons (for numeric arguments)
XXadd-mode Add or delete a mode for the buffer
XXadjust-mode Add or delete a mode for the buffer
XXand * Logical and operator
XXask * Ask for input, paramaters concatenated for prompt
XXbackward-character Move the cursor
XXbegin-macro Start remembering keystrokes
XXbeginning-of-file Move cursor to top of buffer (sets mark)
XXbegining-of-line Cursor to beginning of line
XXbind-to-key Define a function to a key
XXbuffer-position Report on current buffer stats
XXcase-region-lower Translate between dot and mark to lower case
XXcase-region-upper Translate between dot and mrak to upper case
XXcase-word-capitalize Capitalize one word
XXcase-word-lower Downcase one word
XXcase-word-upper Upcase one word
XXchange-file-name Change the filename associated with a buffer
XXclear-and-redraw Refresh the screen
XXcopy-region Copy between dot and mark to the kill buffer
XXcurbuf * Return current buffer name as a string
XXcurchr,curcol,curlin * Return current char,column,line number as an int
XXdelete-blank-lines Delete surrounding blank lines
XXdelete-buffer Delete an entire buffer
XXdelete-mode Change a mode for a buffer
XXdelete-next-character Delete forward
XXdelete-next-word Delete forward one word
XXdelete-other-windows Go back to 1 window display
XXdelete-previous-character Remove character in front of cursor
XXdelete-previous-word Delete word before cursor
XXdelete-window Delete the current window
XXdescribe-bindings Give list of all key bindings
XXdescribe-key Describe a specific key
XXend-macro End defining a macro started with ^X(
XXend-of-file Move cursor to end of buffer (sets mark)
XXend-of-line Move cursor to end of line
XXeq * Compare two strings/integers for equality
XXexchange-point-and-mark Jump between dot and mark
XXexecute-buffer Execute a buffer as a list of commands
XXexecute-command-line Execute a single command line (not implemented)
XXexecute-file Execute a file as a list of commands
XXexecute-macro Execute a macro defined byt ^X( ^X)
XX
XXexecute-named-command Execute any of the commands in the 1st column
XXexit-emacs Get out of emacs
XXfill-paragraph Fill the surrounding paragraph
XXfind-file Read a file into the current buffer
XXforward-character Move cursor forward
XXgo * Goto a label in a LISP progn statment
XXgoto-line Jump to a specific line number
XXgrow-window Make window bigger
XXhandle-tab Insert a tab (different in diff modes)
XXhelp Type this file
XXif * LISP if (true if int != 0 or string != "")
XXinsert-file Insert a file at dot
XXkill-region Kill region between dot and mark
XXkill-to-end-of-line Kill text (put in kill buffer)
XXlist-buffers Show all buffers
XXmove-window-down Scroll the current window up
XXmove-window-up Scroll the current window down
XXname-buffer Change the name for a buffer
XXnewline Insert a <CR> (different in diff modes)
XXnewline-and-indent End line and indent next line
XXnext-line Move cursor down one line
XXnext-page Scroll screen up
XXnext-paragraph Move to next paragraph
XXnext-window Jump to the next window (move cursor)
XXnext-word Move to next word
XXnot * Logical not operator
XXopen-line Open up a blank line at cursor
XXor * Logical or operator
XXprevious-line Cursor up
XXprevious-page Scroll screen down
XXprevious-paragraph Move cursor back
XXprevious-window Go to the previous window on the screen
XXprevious-word Move cursor back
XXprinc * Insert all arguments into the current buffer
XXprogn * LISP progn
XXquery-replace-string Replace text interactively (sets mark)
XXquick-exit Save files and leave editor
XXquote-character Quote the next character
XXread-file Read a file in to the buffer (READONLY)
XXredraw-display Reposition display (center on current line)
XXreplace-string Replace text without asking (sets mark)
XXreturn * Leave a LISP progn (optional return value)
XXsave-file Save the current file (checkpoint)
XXscroll-next-up Scroll other window up
XXscroll-next-down Scroll other window down
XXsearch-forward Search forward for text (sets mark)
XXsearch-reverse Search backward for text (sets mark)
XXselect-buffer Pick a buffer to display
XXset-fill-column Change the fill column
XXset-mark Set the mark
XXsetq * Set a LISP variable (a-z) to concat. of parameters
XXshell Sprout a subprocess
XXshell-command Execute a one line command in a sub shell
XXshell-quote Send the next character to a sub-shell
XXshrink-window Make the window smaller
XXsplit-current-window Divide the current window in half
XXsuspend-emacs Pause emacs (on unix)
XXtranspose-characters Flip characters before/under cursor
XXunbind-key Delete a key binding
XXvisit-file Bring a file in (in a new buffer)
XXvisit-tag Bring a file in (via the current tagged word)
XXwrite-file Write file to a new name
XXyank Yank back from the kill buffer
XXyank-string * Yank the kill buffer into a LISP string
XX
XXadd-mode ^X^M adjust-mode ^X^M
XXbackward-character ^B,K-D begin-macro ^X(
XXbegining-of-file M-<,G-u begining-of-line ^A,K-p
XXbind-to-key buffer-position ^X=
XXcase-region-lower ^X^L case-region-upper ^X^U
XXcase-word-capitalize M-C case-word-lower M-L
XXcase-word-upper M-U,G-q change-file-name ^XN
XXclear-and-redraw ^L copy-region M-W,K-y,G-y
XXdelete-blank-lines ^X^O delete-buffer ^XK
XXdelete-mode ^X^M delete-next-character ^D,K-l
XXdelete-next-word M-D,K-m delete-other-windows ^X1
XXdelete-previous-character^H,^? delete-previous-word M-^H,M-^?
XXdelete-window ^XD describe-bindings M-?
XXdescribe-key ^X?,G-Q end-macro ^X)
XXend-of-file M->,G-t end-of-line ^E,K-r
XXexchange-point-and-mark ^X^X,G-n execute-buffer
XXexecute-command-line execute-file
XXexecute-macro ^Z,^XE execute-named-command M-X,G-w
XXexit-emacs ^X^C fill-paragraph M-G,G-x
XXfind-file ^X^R forward-character K-C,K-s
XXgoto-line ^XL grow-window ^X>,^X^,^XZ
XXhandle-tab ^I help K-Q
XXinsert-file ^X^I kill-region ^W,K-v,K-3
XXkill-to-end-of-line ^K,K-S,G-r list-buffers ^X^B
XXmove-window-down ^X^N move-window-up
XXname-buffer M-^N newline ^M,K-M
XXnewline-and-indent ^J next-line ^N,K-B
XXnext-page ^V,K-t,K-6 next-paragraph M-N,K-w
XXnext-window ^XO next-word M-F,K-q
XXopen-line ^O,K-2,G-p previous-line ^P,K-A
XXprevious-page M-V,K-u,K-5 previous-paragraph M-P,K-x
XXprevious-window ^XP previous-word M-B
XXquery-replace-string M-^R,M-Q,G-M quick-exit ^X^F,M-Z
XXquote-character ^],G-s read-file ^XR
XXredraw-display M-^L,M-! replace-string M-R
XXsave-file ^XS scroll-next-up M-^Z
XXscroll-next-down M-^V search-forward ^F,K-R,K-1
XXsearch-reverse ^R,G-R select-buffer ^XB
XXset-fill-column ^XF set-mark ^XM,^XX,M- ,M-.,K-n,K-4
XXshell-quote ^C shell-command ^X!
XXshrink-window ^X^Z,^X< split-current-window ^X2
XXsuspend-emacs ^X^P transpose-characters ^T
XXunbind-key M-^C visit-file ^X^V
XXvisit-tag ^X^T write-file ^X^W
XXyank ^Y,G-S,G-l,G-m,G-v
XX
XX
XX
XX
XXG-M query-replace-string G-Q describe-key
XXG-R search-reverse G-S yank
XXG-m yank G-p open-line
XXG-q case-word-upper G-r kill-to-end-of-line
XXG-s quote-character G-t end-of-file
XXG-u begining-of-file G-v yank
XXG-x fill-paragraph G-y copy-region
XX
XXK-1 search-forward K-2 open-line
XXK-3 kill-region K-4 set-mark
XXK-5 previous-page K-6 next-page
XXK-A previous-line K-B next-line
XXK-C forward-character K-D backward-character
XXK-M newline K-Q help
XXK-S kill-to-end-of-line K-l delete-next-character
XXK-m delete-next-word K-n set-mark
XXK-p begining-of-line K-q next-word
XXK-r end-of-line K-s forward-character
XXK-t next-page K-u previous-page
XXK-v kill-region K-w next-paragraph
XXK-x previous-paragraph K-y copy-region
XXM- set-mark M-! redraw-display
XXM-. set-mark M-< begining-of-file
XXM-> end-of-file M-? describe-bindings
XXM-B previous-word M-C case-word-capitalize
XXM-D delete-next-word M-F next-word
XXM-N next-paragraph M-P previous-paragraph
XXM-Q query-replace-string M-R replace-string
XXM-U case-word-upper M-V previous-page
XXM-W copy-region M-X execute-named-command
XXM-Z quick-exit M-^C unbind-key
XXM-^H delete-previous-word M-^L redraw-display
XXM-^N name-buffer M-^R query-replace-string
XXM-^V scroll-next-down M-^Z scroll-next-up
XXM-^? delete-previous-word ^A begining-of-line
XX^B backward-character ^C shell-quote
XX^D delete-next-character ^E end-of-line
XX^F search-forward ^H delete-previous-character
XX^I handle-tab ^J newline-and-indent
XX^K kill-to-end-of-line ^L clear-and-redraw
XX^M newline ^N next-line
XX^O open-line ^P previous-line
XX^R search-reverse ^T transpose-characters
XX^V next-page ^W kill-region
XX^X! shell-command ^X( begin-macro
XX^X) end-macro ^X1 delete-other-windows
XX^X2 split-current-window ^X< shrink-window
XX^X= buffer-position ^X> grow-window
XX^X? describe-key ^XB select-buffer
XX^XD delete-window ^XE execute-macro
XX^XF set-fill-column ^XK delete-buffer
XX^XL goto-line ^XM set-mark
XX^XN change-file-name ^XO next-window
XX^XP previous-window ^XR read-file
XX^XS save-file ^XX set-mark
XX^XZ grow-window ^X^ grow-window
XX^X^B list-buffers ^X^C exit-emacs
XX^X^F quick-exit ^X^I insert-file
XX^X^L case-region-lower ^X^M add-mode
XX^X^M adjust-mode ^X^M delete-mode
XX^X^N move-window-down ^X^O delete-blank-lines
XX^X^P suspend-emacs ^X^R find-file
XX^X^T visit-tag ^X^U case-region-upper
XX^X^V visit-file ^X^W write-file
XX^X^X exchange-point-and-mark ^X^Z shrink-window
XX^Y yank ^] quote-character
XX^? delete-previous-character
SHAR_EOF
if test 18356 -ne "`wc -c uemacs.hlp`"
then
echo shar: error transmitting uemacs.hlp '(should have been 18356 characters)'
fi
echo shar: extracting ebind.h
sed 's/^XX//' << \SHAR_EOF > ebind.h
XX/* EBIND: Initial default key to function bindings for
XX * MicroEMACS
XX */
XX
XX/*
XX * Command table.
XX * This table is *roughly* in ASCII order, left to right across the
XX * characters of the command. This expains the funny location of the
XX * control-X commands.
XX
XX */
XXKEYTAB keytab[NBINDS] = {
XX CTRL|']', quote,
XX CTRL|'A', gotobol,
XX CTRL|'B', backchar,
XX#if ULTRIX
XX CTRL|'C', shellquote,
XX#endif
XX CTRL|'D', forwdel,
XX CTRL|'E', gotoeol,
XX CTRL|'F', forwsearch,
XX CTRL|'G', ctrlg,
XX CTRL|'H', backdel,
XX CTRL|'I', tab,
XX CTRL|'J', indent,
XX CTRL|'K', killtext,
XX CTRL|'L', refresh,
XX CTRL|'M', newline,
XX CTRL|'N', forwline,
XX CTRL|'O', openline,
XX CTRL|'P', backline,
XX CTRL|'R', backsearch,
XX CTRL|'T', twiddle,
XX CTRL|'V', forwpage,
XX CTRL|'W', killregion,
XX CTRL|'Y', yank,
XX CTRL|'Z', ctlxe,
XX CTLX|CTRL|'B', listbuffers,
XX CTLX|CTRL|'C', quit,
XX CTLX|CTRL|'F', quickexit,
XX CTLX|CTRL|'I', insfile,
XX CTLX|CTRL|'L', lowerregion,
XX CTLX|CTRL|'M', adjustmode,
XX CTLX|CTRL|'N', mvdnwind,
XX CTLX|CTRL|'O', deblank,
XX#if ULTRIX
XX CTLX|CTRL|'P', bktoshell,
XX#endif
XX CTLX|CTRL|'R', filefind,
XX CTLX|CTRL|'T', visittag,
XX CTLX|CTRL|'U', upperregion,
XX CTLX|CTRL|'V', visitfile,
XX CTLX|CTRL|'W', filewrite,
XX CTLX|CTRL|'X', swapmark,
XX CTLX|CTRL|'Z', shrinkwind,
XX CTLX|'?', deskey,
XX CTLX|'!', spawn,
XX CTLX|'<', shrinkwind,
XX CTLX|'=', showcpos,
XX CTLX|'>', enlargewind,
XX CTLX|'(', ctlxlp,
XX CTLX|')', ctlxrp,
XX CTLX|'^', enlargewind,
XX CTLX|'1', onlywind,
XX CTLX|'2', splitwind,
XX CTLX|'B', usebuffer,
XX CTLX|'D', delwind,
XX CTLX|'E', ctlxe,
XX CTLX|'F', setfillcol,
XX CTLX|'K', killbuffer,
XX CTLX|'L', gotoline,
XX CTLX|'M', setmark,
XX CTLX|'N', filename,
XX CTLX|'O', nextwind,
XX CTLX|'P', prevwind,
XX CTLX|'R', fileread,
XX CTLX|'S', filesave,
XX CTLX|'X', setmark,
XX CTLX|'Z', enlargewind,
XX META|CTRL|'C', unbindkey,
XX META|CTRL|'H', delbword,
XX META|CTRL|'L', reposition,
XX META|CTRL|'N', namebuffer,
XX META|CTRL|'R', qreplace,
XX META|CTRL|'V', scrnextdw,
XX META|CTRL|'Z', scrnextup,
XX META|' ', setmark,
XX META|'?', desbind,
XX META|'!', reposition,
XX META|'.', setmark,
XX META|'>', gotoeob,
XX META|'<', gotobob,
XX META|'B', backword,
XX META|'C', capword,
XX META|'D', delfword,
XX META|'F', forwword,
XX META|'G', fillpara,
XX META|'L', lowerword,
XX META|'N', gotoeop,
XX META|'P', gotobop,
XX META|'Q', qreplace,
XX META|'R', sreplace,
XX META|'U', upperword,
XX META|'V', backpage,
XX META|'W', copyregion,
XX META|'X', namedcmd,
XX META|'Z', quickexit,
XX META|0x7F, delbword,
XX SPEC|'A', backline,
XX SPEC|'B', forwline,
XX SPEC|'C', forwchar,
XX SPEC|'D', backchar,
XX SPEC|'M', newline, /* enter*/
XX SPEC|'Q', help, /* PF2 */
XX SPEC|'R', forwsearch, /* PF3 */
XX SPEC|'S', killtext, /* PF4 */
XX SPEC|'l', forwdel, /* , */
XX SPEC|'m', delfword, /* - */
XX SPEC|'n', setmark, /* . */
XX SPEC|'p', gotobol, /* 0 */
XX SPEC|'q', forwword, /* 1 */
XX SPEC|'r', gotoeol, /* 2 */
XX SPEC|'s', forwchar, /* 3 */
XX SPEC|'t', forwpage, /* 4 */
XX SPEC|'u', backpage, /* 5 */
XX SPEC|'v', killregion, /* 6 */
XX SPEC|'w', gotoeop, /* 7 */
XX SPEC|'x', gotobop, /* 8 */
XX SPEC|'y', copyregion, /* 9 */
XX SPEC|'1', forwsearch,
XX SPEC|'2', openline,
XX SPEC|'3', killregion,
XX SPEC|'4', setmark,
XX SPEC|'5', backpage,
XX SPEC|'6', forwpage,
XX GOLD|'M', qreplace, /* enter*/
XX GOLD|'Q', deskey, /* PF2 */
XX GOLD|'R', backsearch, /* PF3 */
XX GOLD|'S', yank, /* PF4 */
XX GOLD|'l', yank, /* , */
XX GOLD|'m', yank, /* - */
XX GOLD|'n', swapmark, /* . */
XX GOLD|'p', openline, /* 0 */
XX GOLD|'q', upperword, /* 1 */
XX GOLD|'r', killtext, /* 2 */
XX GOLD|'s', quote, /* 3 */
XX GOLD|'t', gotoeob, /* 4 */
XX GOLD|'u', gotobob, /* 5 */
XX GOLD|'v', yank, /* 6 */
XX GOLD|'w', namedcmd, /* 7 */
XX GOLD|'x', fillpara, /* 8 */
XX GOLD|'y', copyregion, /* 9 */
XX 0x7F, backdel,
XX 0, NULL
XX };
SHAR_EOF
if test 4038 -ne "`wc -c ebind.h`"
then
echo shar: error transmitting ebind.h '(should have been 4038 characters)'
fi
echo shar: extracting edef.h
sed 's/^XX//' << \SHAR_EOF > edef.h
XX/* EDEF: Global variable definitions for MICROEmacs */
XX
XX#ifdef maindef
XX
XX/* for MAIN.C */
XX
XX/* initialized global definitions */
XX
XXint batchmode = FALSE; /* batch mode switch */
XXint fillcol = 72; /* Current fill column */
XXshort kbdm[NKBDM] = {CTLX|')'}; /* Macro */
XXchar pat[NPAT]; /* Search pattern */
XXchar rpat[NPAT]; /* replacement pattern */
XXchar sarg[NSTRING] = ""; /* string argument for line exec*/
XXint eolexist = TRUE; /* does clear to EOL exist */
XXchar *modename[] = /* name of modes */
XX { "WRAP", "CMODE", "SLOW", "EXACT", "VIEW", "MMODE", "LISP" };
XXchar modecode[] = "WCSEVML"; /* letters to represent modes */
XXint sgarbf = TRUE; /* TRUE if screen is garbage */
XXint mpresf = FALSE; /* TRUE if message in last line */
XXint clexec = FALSE; /* command line execution flag */
XXint slowterm= FALSE; /* are we running a slow speed term*/
XXBUFFER *procbuf= NULL; /* process buffer pointer */
XX
XX/* uninitialized global definitions */
XX
XXint currow; /* Cursor row */
XXint curcol; /* Cursor column */
XXint thisflag; /* Flags, this command */
XXint lastflag; /* Flags, last command */
XXint curgoal; /* Goal for C-P, C-N */
XXWINDOW *curwp; /* Current window */
XXBUFFER *curbp; /* Current buffer */
XXWINDOW *wheadp; /* Head of list of windows */
XXBUFFER *bheadp; /* Head of list of buffers */
XXBUFFER *blistp; /* Buffer for C-X C-B */
XXshort *kbdmip; /* Input pointer for above */
XXshort *kbdmop; /* Output pointer for above */
XX
XXBUFFER *bfind(); /* Lookup a buffer by name */
XXWINDOW *wpopup(); /* Pop up window creation */
XXLINE *lalloc(); /* Allocate a line */
XXint pid; /* process id of sub process */
XXint outchannel; /* output channel to sub process */
XXint inchannel; /* input channel from sub process */
XX#else
XX
XX/* for all the other .C files */
XX
XX/* initialized global external declarations */
XX
XXextern int batchmode; /* batch mode switch */
XXextern int fillcol; /* Fill column */
XXextern short kbdm[]; /* Holds kayboard macro data */
XXextern char pat[]; /* Search pattern */
XXextern char rpat[]; /* Replacement pattern */
XXextern char sarg[]; /* string argument for line exec*/
XXextern int eolexist; /* does clear to EOL exist? */
XXextern char *modename[]; /* text names of modes */
XXextern char modecode[]; /* letters to represent modes */
XXextern KEYTAB keytab[]; /* key bind to functions table */
XXextern NBIND names[]; /* name to function table */
XXextern int sgarbf; /* State of screen unknown */
XXextern int mpresf; /* Stuff in message line */
XXextern int clexec; /* command line execution flag */
XXextern int slowterm; /* are we running a slow speed term*/
XXextern BUFFER *procbuf; /* process buffer pointer */
XX
XX/* initialized global external declarations */
XX
XXextern int currow; /* Cursor row */
XXextern int curcol; /* Cursor column */
XXextern int thisflag; /* Flags, this command */
XXextern int lastflag; /* Flags, last command */
XXextern int curgoal; /* Goal for C-P, C-N */
XXextern WINDOW *curwp; /* Current window */
XXextern BUFFER *curbp; /* Current buffer */
XXextern WINDOW *wheadp; /* Head of list of windows */
XXextern BUFFER *bheadp; /* Head of list of buffers */
XXextern BUFFER *blistp; /* Buffer for C-X C-B */
XXextern short *kbdmip; /* Input pointer for above */
XXextern short *kbdmop; /* Output pointer for above */
XX
XXextern BUFFER *bfind(); /* Lookup a buffer by name */
XXextern WINDOW *wpopup(); /* Pop up window creation */
XXextern LINE *lalloc(); /* Allocate a line */
XXextern int pid; /* process id of sub process */
XXextern int outchannel; /* output channel to sub process */
XXextern int inchannel; /* input channel from sub process */
XX
XX#endif
XX
XX/* terminal table defined only in TERM.C */
XX
XX#ifndef termdef
XXextern TERM term; /* Terminal information. */
XX#endif
XX
XX
SHAR_EOF
if test 4341 -ne "`wc -c edef.h`"
then
echo shar: error transmitting edef.h '(should have been 4341 characters)'
fi
echo shar: extracting efunc.h
sed 's/^XX//' << \SHAR_EOF > efunc.h
XX/* EFUNC.H: MicroEMACS function declarations and names */
XX
XX/* External function declarations */
XX
XXextern int ctrlg(); /* Abort out of things */
XXextern int quit(); /* Quit */
XXextern int ctlxlp(); /* Begin macro */
XXextern int ctlxrp(); /* End macro */
XXextern int ctlxe(); /* Execute macro */
XXextern int fileread(); /* Get a file, read only */
XXextern int filefind(); /* Get a file, read write */
XXextern int filewrite(); /* Write a file */
XXextern int filesave(); /* Save current file */
XXextern int filename(); /* Adjust file name */
XXextern int getccol(); /* Get current column */
XXextern int gotobol(); /* Move to start of line */
XXextern int forwchar(); /* Move forward by characters */
XXextern int gotoeol(); /* Move to end of line */
XXextern int backchar(); /* Move backward by characters */
XXextern int forwline(); /* Move forward by lines */
XXextern int backline(); /* Move backward by lines */
XXextern int forwpage(); /* Move forward by pages */
XXextern int backpage(); /* Move backward by pages */
XXextern int gotobob(); /* Move to start of buffer */
XXextern int gotoeob(); /* Move to end of buffer */
XXextern int setfillcol(); /* Set fill column. */
XXextern int setmark(); /* Set mark */
XXextern int swapmark(); /* Swap "." and mark */
XXextern int forwsearch(); /* Search forward */
XXextern int backsearch(); /* Search backwards */
XXextern int sreplace(); /* search and replace */
XXextern int qreplace(); /* search and replace w/query */
XXextern int showcpos(); /* Show the cursor position */
XXextern int nextwind(); /* Move to the next window */
XXextern int prevwind(); /* Move to the previous window */
XXextern int onlywind(); /* Make current window only one */
XXextern int delwind(); /* Delete the current window */
XXextern int splitwind(); /* Split current window */
XXextern int mvdnwind(); /* Move window down */
XXextern int mvupwind(); /* Move window up */
XXextern int enlargewind(); /* Enlarge display window. */
XXextern int shrinkwind(); /* Shrink window. */
XXextern int listbuffers(); /* Display list of buffers */
XXextern int usebuffer(); /* Switch a window to a buffer */
XXextern int killbuffer(); /* Make a buffer go away. */
XXextern int reposition(); /* Reposition window */
XXextern int refresh(); /* Refresh the screen */
XXextern int twiddle(); /* Twiddle characters */
XXextern int tab(); /* Insert tab */
XXextern int newline(); /* Insert CR-LF */
XXextern int indent(); /* Insert CR-LF, then indent */
XXextern int openline(); /* Open up a blank line */
XXextern int deblank(); /* Delete blank lines */
XXextern int quote(); /* Insert literal */
XXextern int backword(); /* Backup by words */
XXextern int forwword(); /* Advance by words */
XXextern int forwdel(); /* Forward delete */
XXextern int backdel(); /* Backward delete */
XXextern int killtext(); /* Kill forward */
XXextern int yank(); /* Yank back from killbuffer. */
XXextern int upperword(); /* Upper case word. */
XXextern int lowerword(); /* Lower case word. */
XXextern int upperregion(); /* Upper case region. */
XXextern int lowerregion(); /* Lower case region. */
XXextern int capword(); /* Initial capitalize word. */
XXextern int delfword(); /* Delete forward word. */
XXextern int delbword(); /* Delete backward word. */
XXextern int killregion(); /* Kill region. */
XXextern int copyregion(); /* Copy region to kill buffer. */
XXextern int spawncli(); /* Run CLI in a subjob. */
XXextern int spawn(); /* Run a command in a subjob. */
XXextern int quickexit(); /* low keystroke style exit. */
XXextern int adjustmode(); /* set/unset an editor mode */
XXextern int gotoline(); /* go to a numbered line */
XXextern int namebuffer(); /* rename the current buffer */
XXextern int gotobop(); /* go to begining/paragraph */
XXextern int gotoeop(); /* go to end/paragraph */
XXextern int fillpara(); /* fill current paragraph */
XXextern int help(); /* get the help file here */
XXextern int deskey(); /* describe a key's binding */
XXextern int visitfile(); /* find a file in other window */
XXextern int visittag(); /* find a file (using tag) in other window */
XXextern int insfile(); /* insert a file */
XXextern int scrnextup(); /* scroll next window back */
XXextern int scrnextdw(); /* scroll next window down */
XXextern int bindtokey(); /* bind a function to a key */
XXextern int unbindkey(); /* unbind a key's function */
XXextern int namedcmd(); /* execute named command */
XXextern int desbind(); /* describe bindings */
XXextern int execcmd(); /* execute a command line */
XXextern int execbuf(); /* exec commands from a buffer */
XXextern int execfile(); /* exec commands from a file */
XXextern int l_eval(); /* evaluate a LISP s-expr */
XXextern int l_if(); /* LISP if */
XXextern int l_progn(); /* LISP progn */
XXextern int l_return(); /* LISP return */
XXextern int l_setq(); /* LISP setq */
XXextern int l_go(); /* LISP go */
XXextern int l_yank_str(); /* put the KILL buffer into a LISP string */
XXextern int l_ask(); /* ask the user for input */
XXextern int l_add(); /* arithmetic function */
XXextern int l_sub(); /* arithmetic function */
XXextern int l_mul(); /* arithmetic function */
XXextern int l_div(); /* arithmetic function */
XXextern int l_mod(); /* arithmetic function */
XXextern int l_bitand(); /* arithmetic function */
XXextern int l_bitor(); /* arithmetic function */
XXextern int l_eql(); /* arithmetic function */
XXextern int l_neq(); /* arithmetic function */
XXextern int l_gt(); /* arithmetic function */
XXextern int l_ge(); /* arithmetic function */
XXextern int l_lt(); /* arithmetic function */
XXextern int l_le(); /* arithmetic function */
XXextern int l_not(); /* arithmetic function */
XXextern int l_and(); /* arithmetic function */
XXextern int l_or(); /* arithmetic function */
XXextern int l_eq(); /* arithmetic function */
XXextern int l_curchr(); /* current character (returned as an integer) */
XXextern int l_curlin(); /* current line number in the buffer */
XXextern int l_curcol(); /* current column position */
XXextern int l_curbuf(); /* current buffer name */
XXextern int l_princ(); /* insert text into the buffer */
XX
XX#if ULTRIX
XXextern int shellquote(); /* send the next character to the sub proc */
XXextern int bktoshell(); /* suspend emacs to parent shell*/
XXextern int rtfrmshell(); /* return from a suspended state*/
XX#endif
XX
XX/* Name to function binding table
XX
XX This table gives the names of all the bindable functions
XX end their C function address. These are used for the bind-to-key
XX function.
XX*/
XX
XXNBIND names[] = {
XX "+", l_add,
XX "-", l_sub,
XX "*", l_mul,
XX "/", l_div,
XX "%", l_mod,
XX "&", l_bitand,
XX "|", l_bitor,
XX "=", l_eql,
XX "!=", l_neq,
XX ">", l_gt,
XX ">=", l_ge,
XX "<", l_lt,
XX "<=", l_le,
XX "add-mode", adjustmode,
XX "adjust-mode", adjustmode,
XX "and", l_and,
XX "ask", l_ask,
XX "backward-character", backchar,
XX "begin-macro", ctlxlp,
XX "beginning-of-file", gotobob,
XX "beginning-of-line", gotobol,
XX "bind-to-key", bindtokey,
XX "buffer-position", showcpos,
XX "case-region-lower", lowerregion,
XX "case-region-upper", upperregion,
XX "case-word-capitalize", capword,
XX "case-word-lower", lowerword,
XX "case-word-upper", upperword,
XX "change-file-name", filename,
XX "clear-and-redraw", refresh,
XX "copy-region", copyregion,
XX "curbuf", l_curbuf,
XX "curchr", l_curchr,
XX "curcol", l_curcol,
XX "curlin", l_curlin,
XX "delete-blank-lines", deblank,
XX "delete-buffer", killbuffer,
XX "delete-mode", adjustmode,
XX "delete-next-character",forwdel,
XX "delete-next-word", delfword,
XX "delete-other-windows", onlywind,
XX "delete-previous-character",backdel,
XX "delete-previous-word", delbword,
XX "delete-window", delwind,
XX "describe-bindings", desbind,
XX "describe-key", deskey,
XX "end-macro", ctlxrp,
XX "end-of-file", gotoeob,
XX "end-of-line", gotoeol,
XX "eq", l_eq,
XX "eval", l_eval,
XX "exchange-point-and-mark",swapmark,
XX "execute-buffer", execbuf,
XX "execute-command-line", execcmd,
XX "execute-file", execfile,
XX "execute-macro", ctlxe,
XX "execute-named-command",namedcmd,
XX "exit-emacs", quit,
XX "fill-paragraph", fillpara,
XX "find-file", filefind,
XX "forward-character", forwchar,
XX "go", l_go,
XX "goto-line", gotoline,
XX "grow-window", enlargewind,
XX "handle-tab", tab,
XX "help", help,
XX "if", l_if,
XX "insert-file", insfile,
XX "kill-region", killregion,
XX "kill-to-end-of-line", killtext,
XX "list-buffers", listbuffers,
XX "move-window-down", mvdnwind,
XX "move-window-up", mvupwind,
XX "name-buffer", namebuffer,
XX "newline", newline,
XX "newline-and-indent", indent,
XX "next-line", forwline,
XX "next-page", forwpage,
XX "next-paragraph", gotoeop,
XX "next-window", nextwind,
XX "next-word", forwword,
XX "not", l_not,
XX "open-line", openline,
XX "or", l_or,
XX "previous-line", backline,
XX "previous-page", backpage,
XX "previous-paragraph", gotobop,
XX "previous-window", prevwind,
XX "previous-word", backword,
XX "princ", l_princ,
XX "progn", l_progn,
XX "query-replace-string", qreplace,
XX "quick-exit", quickexit,
XX "quote-character", quote,
XX "read-file", fileread,
XX "redraw-display", reposition,
XX "replace-string", sreplace,
XX "return", l_return,
XX "save-file", filesave,
XX "scroll-next-up", scrnextup,
XX "scroll-next-down", scrnextdw,
XX "search-forward", forwsearch,
XX "search-reverse", backsearch,
XX "select-buffer", usebuffer,
XX "set-fill-column", setfillcol,
XX "set-mark", setmark,
XX "setq", l_setq,
XX "shell", spawncli,
XX#if ULTRIX
XX "shell-quote", shellquote,
XX#endif
XX "shell-command", spawn,
XX "shrink-window", shrinkwind,
XX "split-current-window", splitwind,
XX#if ULTRIX
XX "suspend-emacs", bktoshell,
XX#endif
XX "transpose-characters", twiddle,
XX "unbind-key", unbindkey,
XX "visit-file", visitfile,
XX "visit-tag", visittag,
XX "write-file", filewrite,
XX "yank", yank,
XX "yank-string", l_yank_str,
XX
XX "", NULL
XX };
SHAR_EOF
if test 9741 -ne "`wc -c efunc.h`"
then
echo shar: error transmitting efunc.h '(should have been 9741 characters)'
fi
echo shar: extracting epath.h
sed 's/^XX//' << \SHAR_EOF > epath.h
XX/* PATH: This file contains certain info needed to locate the
XX MicroEMACS files on a system dependant basis. */
XX
XX#if AMIGA
XX#ifdef INBIND
XXchar *pathname[5] = {
XX ".uemacsrc",
XX "uemacs.hlp",
XX "",
XX ":c/",
XX "c:"
XX };
XX#else
XXextern *pathname[5];
XX#endif
XX#endif
XX
XX#if ULTRIX
XX#ifdef INBIND
XXchar *pathname[7] = {
XX ".uemacsrc",
XX "uemacs.hlp",
XX "",
XX "~/",
XX "~/bin/",
XX "/staff/bin",
XX "/usr/local/bin"
XX };
XX#else
XXextern char *pathname[7];
XX#endif
XX#endif
XX
XX#if VMS
XX#ifdef INBIND
XXchar *pathname[6] = {
XX "uemacs.rc",
XX "uemacs.hlp",
XX "",
XX "sys$login:",
XX "sys$sysexe:",
XX "sys$library:"
XX };
XX#else
XXextern char *pathname[6];
XX#endif
XX#endif
XX
XX#define NPNAMES (sizeof(pathname)/sizeof(char *))
SHAR_EOF
if test 723 -ne "`wc -c epath.h`"
then
echo shar: error transmitting epath.h '(should have been 723 characters)'
fi
echo shar: extracting estruct.h
sed 's/^XX//' << \SHAR_EOF > estruct.h
XX/* ESTRUCT: Structure and preprocesser defined for MicroEMACS */
XX
XX/* Machine/OS definitions */
XX
XX#define AMIGA 0 /* AmigaDOS */
XX#define ULTRIX 1 /* ULTRIX (BSD 4.3) */
XX#define VMS 0 /* VAX/VMS */
XX
XX/* Terminal Output and compiler definitions */
XX
XX#if AMIGA
XX#define ANSI 1 /* ANSI escape sequence processing */
XX#define VMSVT 0 /* various VMS terminal entries */
XX#define TERMCAP 0 /* Use TERMCAP */
XX#define AZTEC 1 /* Aztec C compiler */
XX#define LATTICE 0 /* Lattice C compiler */
XX#endif
XX
XX#if ULTRIX
XX#define ANSI 0 /* ANSI escape sequence processing */
XX#define VMSVT 0 /* various VMS terminal entries */
XX#define TERMCAP 1 /* Use TERMCAP */
XX#define AZTEC 0 /* Aztec C compiler */
XX#define LATTICE 0 /* Lattice C compiler */
XX#endif
XX
XX#if VMS
XX#define ANSI 0 /* ANSI escape sequence processing */
XX#define VMSVT 1 /* various VMS terminal entries */
XX#define TERMCAP 0 /* Use TERMCAP */
XX#define AZTEC 0 /* Aztec C compiler */
XX#define LATTICE 0 /* Lattice C compiler */
XX#endif
XX
XX/* Configuration options */
XX
XX#define CVMVAS 1 /* arguments to page forward/back in pages */
XX#define NFWORD 0 /* forward word jumps to begining of word */
XX#define CLRMSG 0 /* space clears the message line with no insert */
XX#define TYPEAH 1 /* type ahead causes update to be skipped */
XX#define FILOCK 0 /* file locking under unix BSD 4.2 */
XX
XX/* internal constants */
XX
XX#define NBINDS 180 /* max # of bound keys */
XX#define NFILEN 80 /* # of bytes, file name */
XX#define NBUFN 16 /* # of bytes, buffer name */
XX#define NLINE 256 /* # of bytes, line */
XX#define NSTRING 256 /* # of bytes, string buffers */
XX#define NKBDM 256 /* # of strokes, keyboard macro */
XX#define NPAT 256 /* # of bytes, pattern */
XX#define HUGE 1000 /* Huge number */
XX#define NLOCKS 100 /* max # of file locks active */
XX
XX#define AGRAVE 0x60 /* M- prefix, Grave (LK201) */
XX#define METACH 0x1B /* M- prefix, Control-[, ESC */
XX#define CTMECH 0x1C /* C-M- prefix, Control-\ */
XX#define EXITCH 0x1D /* Exit level, Control-] */
XX#define CTRLCH 0x1E /* C- prefix, Control-^ */
XX#define HELPCH 0x1F /* Help key, Control-_ */
XX#define CSICH 0x9B /* CSI sequence on the AMIGA */
XX
XX#define CTRL 0x0100 /* Control flag, or'ed in */
XX#define META 0x0200 /* Meta flag, or'ed in */
XX#define CTLX 0x0400 /* ^X flag, or'ed in */
XX#define SPEC 0x0800 /* special key (function keys) */
XX#define GOLD 0x1000 /* gold prefix key (PF1) */
XX
XX#define FALSE 0 /* False, no, bad, etc. */
XX#define TRUE 1 /* True, yes, good, etc. */
XX#define ABORT 2 /* Death, ^G, abort, etc. */
XX
XX#define FIOSUC 0 /* File I/O, success. */
XX#define FIOFNF 1 /* File I/O, file not found. */
XX#define FIOEOF 2 /* File I/O, end of file. */
XX#define FIOERR 3 /* File I/O, error. */
XX#define FIOLNG 4 /*line longer than allowed len */
XX
XX#define CFCPCN 0x0001 /* Last command was C-P, C-N */
XX#define CFKILL 0x0002 /* Last command was a kill */
XX
XX#define BELL 0x07 /* a bell character */
XX#define TAB 0x09 /* a tab character */
XX
XX/*
XX * There is a window structure allocated for every active display window. The
XX * windows are kept in a big list, in top to bottom screen order, with the
XX * listhead at "wheadp". Each window contains its own values of dot and mark.
XX * The flag field contains some bits that are set by commands to guide
XX * redisplay; although this is a bit of a compromise in terms of decoupling,
XX * the full blown redisplay is just too expensive to run for every input
XX * character.
XX */
XXtypedef struct WINDOW {
XX struct WINDOW *w_wndp; /* Next window */
XX struct BUFFER *w_bufp; /* Buffer displayed in window */
XX struct LINE *w_linep; /* Top line in the window */
XX struct LINE *w_dotp; /* Line containing "." */
XX short w_doto; /* Byte offset for "." */
XX struct LINE *w_markp; /* Line containing "mark" */
XX short w_marko; /* Byte offset for "mark" */
XX char w_toprow; /* Origin 0 top row of window */
XX char w_ntrows; /* # of rows of text in window */
XX char w_force; /* If NZ, forcing row. */
XX char w_flag; /* Flags. */
XX } WINDOW;
XX
XX#define WFFORCE 0x01 /* Window needs forced reframe */
XX#define WFMOVE 0x02 /* Movement from line to line */
XX#define WFEDIT 0x04 /* Editing within a line */
XX#define WFHARD 0x08 /* Better to a full display */
XX#define WFMODE 0x10 /* Update mode line. */
XX
XX/*
XX * Text is kept in buffers. A buffer header, described below, exists for every
XX * buffer in the system. The buffers are kept in a big list, so that commands
XX * that search for a buffer by name can find the buffer header. There is a
XX * safe store for the dot and mark in the header, but this is only valid if
XX * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for
XX * the buffer is kept in a circularly linked list of lines, with a pointer to
XX * the header line in "b_linep".
XX * Buffers may be "Inactive" which means the files accosiated with them
XX * have not been read in yet. These get read in at "use buffer" time.
XX */
XXtypedef struct BUFFER {
XX struct BUFFER *b_bufp; /* Link to next BUFFER */
XX struct LINE *b_dotp; /* Link to "." LINE structure */
XX short b_doto; /* Offset of "." in above LINE */
XX struct LINE *b_markp; /* The same as the above two, */
XX short b_marko; /* but for the "mark" */
XX struct LINE *b_linep; /* Link to the header LINE */
XX char b_active; /* window activated flag */
XX char b_nwnd; /* Count of windows on buffer */
XX char b_flag; /* Flags */
XX char b_mode; /* editor mode of this buffer */
XX char b_fname[NFILEN];/* File name */
XX char b_bname[NBUFN]; /* Buffer name */
XX } BUFFER;
XX
XX#define BFTEMP 0x01 /* Internal temporary buffer */
XX#define BFCHG 0x02 /* Changed since last write */
XX
XX/* mode flags */
XX#define NUMMODES 7 /* # of defined modes */
XX
XX#define MDWRAP 0x0001 /* word wrap */
XX#define MDCMOD 0x0002 /* C indentation and fence match*/
XX#define MDSLOW 0x0004 /* slow speed searches */
XX#define MDEXACT 0x0008 /* Exact matching for searches */
XX#define MDVIEW 0x0010 /* read-only buffer */
XX#define MDMMOD 0x0020 /* Modula indentation mode */
XX#define MDLISP 0x0040 /* Lisp indentation mode */
XX
XX/*
XX * The starting position of a region, and the size of the region in
XX * characters, is kept in a region structure. Used by the region commands.
XX */
XXtypedef struct {
XX struct LINE *r_linep; /* Origin LINE address. */
XX short r_offset; /* Origin LINE offset. */
XX int r_size; /* Length in characters. */
XX } REGION;
XX
XX/*
XX * All text is kept in circularly linked lists of "LINE" structures. These
XX * begin at the header line (which is the blank line beyond the end of the
XX * buffer). This line is pointed to by the "BUFFER". Each line contains a the
XX * number of bytes in the line (the "used" size), the size of the text array,
XX * and the text. The end of line is not stored as a byte; it's implied. Future
XX * additions will include update hints, and a list of marks into the line.
XX */
XXtypedef struct LINE {
XX struct LINE *l_fp; /* Link to the next line */
XX struct LINE *l_bp; /* Link to the previous line */
XX short l_size; /* Allocated size */
XX short l_used; /* Used size */
XX char l_text[1]; /* A bunch of characters. */
XX } LINE;
XX
XX#define lforw(lp) ((lp)->l_fp)
XX#define lback(lp) ((lp)->l_bp)
XX#define lgetc(lp, n) ((lp)->l_text[(n)]&0xFF)
XX#define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
XX#define llength(lp) ((lp)->l_used)
XX
XX/*
XX * The editor communicates with the display using a high level interface. A
XX * "TERM" structure holds useful variables, and indirect pointers to routines
XX * that do useful operations. The low level get and put routines are here too.
XX * This lets a terminal, in addition to having non standard commands, have
XX * funny get and put character code too. The calls might get changed to
XX * "termp->t_field" style in the future, to make it possible to run more than
XX * one terminal type.
XX */
XXtypedef struct {
XX short t_nrow; /* Number of rows. */
XX short t_ncol; /* Number of columns. */
XX short t_margin; /* min margin for extended lines*/
XX short t_scrsiz; /* size of scroll region " */
XX int (*t_open)(); /* Open terminal at the start. */
XX int (*t_close)(); /* Close terminal at end. */
XX int (*t_getchar)(); /* Get character from keyboard. */
XX int (*t_putchar)(); /* Put character to display. */
XX int (*t_flush)(); /* Flush output buffers. */
XX int (*t_move)(); /* Move the cursor, origin 0. */
XX int (*t_eeol)(); /* Erase to end of line. */
XX int (*t_eeop)(); /* Erase to end of page. */
XX int (*t_beep)(); /* Beep. */
XX int (*t_insert)(); /* Insert n blank lines (scroll down) */
XX int (*t_delete)(); /* Delete n lines (scroll up) */
XX } TERM;
XX
XX/* structure for the table of initial key bindings */
XX
XXtypedef struct {
XX short k_code; /* Key code */
XX int (*k_fp)(); /* Routine to handle it */
XX } KEYTAB;
XX
XX/* structure for the name binding table */
XX
XXtypedef struct {
XX char *n_name; /* name of function key */
XX int (*n_func)(); /* function name is bound to */
XX } NBIND;
SHAR_EOF
if test 9841 -ne "`wc -c estruct.h`"
then
echo shar: error transmitting estruct.h '(should have been 9841 characters)'
fi
# End of shell archive
exit 0wecker@cookie.dec.com.UUCP (02/21/87)
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# ansi.c
# basic.c
# bind.c
# buffer.c
# display.c
# file.c
# This archive created: Fri Feb 20 17:44:29 1987
echo shar: extracting ansi.c
sed 's/^XX//' << \SHAR_EOF > ansi.c
XX/*
XX * The routines in this file provide support for ANSI style terminals
XX * over a serial line. The serial I/O services are provided by routines in
XX * "termio.c". It compiles into nothing if not an ANSI device.
XX */
XX
XX#define termdef 1 /* don't define "term" external */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if ANSI
XX
XX#define NROW 23 /* Screen size. */
XX#define NCOL 77 /* Edit if you want to. */
XX#define MARGIN 8 /* size of minimim margin and */
XX#define SCRSIZ 64 /* scroll size for extended lines */
XX#define BEL 0x07 /* BEL character. */
XX#define ESC 0x1B /* ESC character. */
XX
XXextern int ttopen(); /* Forward references. */
XXextern int ttgetc();
XXextern int ttputc();
XXextern int ttflush();
XXextern int ttclose();
XXextern int ansimove();
XXextern int ansieeol();
XXextern int ansieeop();
XXextern int ansibeep();
XXextern int ansiopen();
XXextern int ansiinsert();
XXextern int ansidelete();
XX
XX/*
XX * Standard terminal interface dispatch table. Most of the fields point into
XX * "termio" code.
XX */
XXTERM term = {
XX NROW-1,
XX NCOL,
XX MARGIN,
XX SCRSIZ,
XX ansiopen,
XX ttclose,
XX ttgetc,
XX ttputc,
XX ttflush,
XX ansimove,
XX ansieeol,
XX ansieeop,
XX ansibeep,
XX ansiinsert,
XX ansidelete
XX };
XX
XXansimove(row, col)
XX {
XX if (batchmode) return(TRUE);
XX ttputc(ESC);
XX ttputc('[');
XX ansiparm(row+1);
XX ttputc(';');
XX ansiparm(col+1);
XX ttputc('H');
XX }
XX
XXansieeol()
XX {
XX if (batchmode) return(TRUE);
XX ttputc(ESC);
XX ttputc('[');
XX ttputc('K');
XX }
XX
XXansieeop()
XX {
XX if (batchmode) return(TRUE);
XX ttputc(ESC);
XX ttputc('[');
XX ttputc('J');
XX }
XX
XXansibeep()
XX {
XX if (batchmode) return(TRUE);
XX ttputc(BEL);
XX ttflush();
XX }
XX
XXansiparm(n)
XXregister int n;
XX {
XX register int q;
XX
XX if (batchmode) return(TRUE);
XX q = n/10;
XX if (q != 0) ansiparm(q);
XX ttputc((n%10) + '0');
XX }
XX
XXansiinsert(row,n)
XX {
XX if (batchmode) return(TRUE);
XX ansimove(row,0);
XX ttputc(ESC);
XX ttputc('[');
XX ansiparm(n);
XX ttputc('L');
XX mlerase();
XX }
XX
XXansidelete(row,n)
XX {
XX if (batchmode) return(TRUE);
XX mlerase();
XX ansimove(row,0);
XX ttputc(ESC);
XX ttputc('[');
XX ansiparm(n);
XX ttputc('M');
XX }
XX
XX#endif
XX
XXansiopen()
XX {
XX#if ULTRIX
XX register char *cp;
XX char *getenv();
XX
XX if (batchmode) return(TRUE);
XX if ((cp = getenv("TERM")) == NULL) {
XX puts("Shell variable TERM not defined!");
XX exit(1);
XX }
XX if (strcmp(cp, "vt100") != 0) {
XX puts("Terminal type not 'vt100'!");
XX exit(1);
XX }
XX#endif
XX if (batchmode) return(TRUE);
XX ttopen();
XX }
SHAR_EOF
if test 2731 -ne "`wc -c ansi.c`"
then
echo shar: error transmitting ansi.c '(should have been 2731 characters)'
fi
echo shar: extracting basic.c
sed 's/^XX//' << \SHAR_EOF > basic.c
XX/*
XX * The routines in this file move the cursor around on the screen. They
XX * compute a new value for the cursor, then adjust ".". The display code
XX * always updates the cursor location, so only moves between lines, or
XX * functions that adjust the top line in the window and invalidate the
XX * framing, are hard.
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX/*
XX * Move the cursor to the
XX * beginning of the current line.
XX * Trivial.
XX */
XXgotobol(f, n)
XX {
XX curwp->w_doto = 0;
XX return (TRUE);
XX }
XX
XX/*
XX * Move the cursor backwards by "n" characters. If "n" is less than zero call
XX * "forwchar" to actually do the move. Otherwise compute the new cursor
XX * location. Error if you try and move out of the buffer. Set the flag if the
XX * line pointer for dot changes.
XX */
XXbackchar(f, n)
XXregister int n;
XX {
XX register LINE *lp;
XX
XX if (n < 0) return (forwchar(f, -n));
XX while (n--) {
XX if (curwp->w_doto == 0) {
XX if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) return (FALSE);
XX curwp->w_dotp = lp;
XX curwp->w_doto = llength(lp);
XX curwp->w_flag |= WFMOVE;
XX }
XX else
XX curwp->w_doto--;
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Move the cursor to the end of the current line. Trivial. No errors.
XX */
XXgotoeol(f, n)
XX {
XX curwp->w_doto = llength(curwp->w_dotp);
XX return (TRUE);
XX }
XX
XX/*
XX * Move the cursor forwwards by "n" characters. If "n" is less than zero call
XX * "backchar" to actually do the move. Otherwise compute the new cursor
XX * location, and move ".". Error if you try and move off the end of the
XX * buffer. Set the flag if the line pointer for dot changes.
XX */
XXforwchar(f, n)
XXregister int n;
XX {
XX if (n < 0) return (backchar(f, -n));
XX while (n--) {
XX if (curwp->w_doto == llength(curwp->w_dotp)) {
XX if (curwp->w_dotp == curbp->b_linep) return (FALSE);
XX curwp->w_dotp = lforw(curwp->w_dotp);
XX curwp->w_doto = 0;
XX curwp->w_flag |= WFMOVE;
XX }
XX else
XX curwp->w_doto++;
XX }
XX return (TRUE);
XX }
XX
XXgotoline(f, n) /* move to a particular line.
XX argument (n) must be a positive integer for
XX this to actually do anything */
XX
XX {
XX if (n < 1) /* if a bogus argument...then leave */
XX return(FALSE);
XX
XX /* first, we go to the start of the buffer */
XX curwp->w_dotp = lforw(curbp->b_linep);
XX curwp->w_doto = 0;
XX return(forwline(f, n-1));
XX }
XX
XX/*
XX * Goto the beginning of the buffer. Massive adjustment of dot. This is
XX * considered to be hard motion; it really isn't if the original value of dot
XX * is the same as the new value of dot. Normally bound to "M-<".
XX * arg 0 = do not set mark
XX */
XXgotobob(f, n) {
XX curwp->w_dotp = lforw(curbp->b_linep);
XX curwp->w_doto = 0;
XX curwp->w_flag |= WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * Move to the end of the buffer. Dot is always put at the end of the file
XX * (ZJ). The standard screen code does most of the hard parts of update.
XX * Bound to "M->". arg 0 = don't set mark.
XX */
XXgotoeob(f, n) {
XX curwp->w_dotp = lback(curbp->b_linep);
XX curwp->w_doto = curwp->w_dotp->l_used;
XX curwp->w_flag |= WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * Move forward by full lines. If the number of lines to move is less than
XX * zero, call the backward line function to actually do it. The last command
XX * controls how the goal column is set. Bound to "C-N". No errors are
XX * possible.
XX */
XXforwline(f, n)
XX {
XX register LINE *dlp;
XX
XX if (n < 0) return (backline(f, -n));
XX if ((lastflag&CFCPCN) == 0) /* Reset goal if last */
XX curgoal = curcol; /* not C-P or C-N */
XX thisflag |= CFCPCN;
XX dlp = curwp->w_dotp;
XX while (n-- && dlp!=curbp->b_linep) dlp = lforw(dlp);
XX curwp->w_dotp = dlp;
XX curwp->w_doto = getgoal(dlp);
XX curwp->w_flag |= WFMOVE;
XX return (TRUE);
XX }
XX
XX/*
XX * This function is like "forwline", but goes backwards. The scheme is exactly
XX * the same. Check for arguments that are less than zero and call your
XX * alternate. Figure out the new line and call "movedot" to perform the
XX * motion. No errors are possible. Bound to "C-P".
XX */
XXbackline(f, n)
XX {
XX register LINE *dlp;
XX
XX if (n < 0) return (forwline(f, -n));
XX if ((lastflag&CFCPCN) == 0) /* Reset goal if the */
XX curgoal = curcol; /* last isn't C-P, C-N */
XX thisflag |= CFCPCN;
XX dlp = curwp->w_dotp;
XX while (n-- && lback(dlp)!=curbp->b_linep) dlp = lback(dlp);
XX curwp->w_dotp = dlp;
XX curwp->w_doto = getgoal(dlp);
XX curwp->w_flag |= WFMOVE;
XX return (TRUE);
XX }
XX
XXgotobop(f, n) /* go back to the begining of the current paragraph
XXhere we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
XXcombination to delimit the begining of a paragraph */
XX
XXint f, n; /* default Flag & Numeric argument */
XX
XX {
XX register int suc; /* success of last backchar */
XX
XX if (n < 0) /* the other way...*/
XX return(gotoeop(f, -n));
XX
XX while (n-- > 0) { /* for each one asked for */
XX /* first scan back until we are in a word */
XX suc = backchar(FALSE, 1);
XX while (!inword() && suc) suc = backchar(FALSE, 1);
XX curwp->w_doto = 0; /* and go to the B-O-Line */
XX
XX /* and scan back until we hit a <NL><NL> or <NL><TAB>
XX or a <NL><SPACE> */
XX while (lback(curwp->w_dotp) != curbp->b_linep) if (llength(curwp->w_dotp) != 0 && lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
XX lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
XX curwp->w_dotp = lback(curwp->w_dotp);
XX else
XX break;
XX
XX /* and then forward until we are in a word */
XX suc = forwchar(FALSE, 1);
XX while (suc && !inword()) suc = forwchar(FALSE, 1);
XX }
XX curwp->w_flag |= WFMOVE; /* force screen update */
XX }
XX
XXgotoeop(f, n) /* go forword to the end of the current paragraph
XXhere we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
XXcombination to delimit the begining of a paragraph */
XX
XXint f, n; /* default Flag & Numeric argument */
XX
XX {
XX register int suc; /* success of last backchar */
XX
XX if (n < 0) /* the other way...*/
XX return(gotobop(f, -n));
XX
XX while (n-- > 0) { /* for each one asked for */
XX /* first scan forward until we are in a word */
XX suc = forwchar(FALSE, 1);
XX while (!inword() && suc) suc = forwchar(FALSE, 1);
XX curwp->w_doto = 0; /* and go to the B-O-Line */
XX if (suc) /* of next line if not at EOF */
XX curwp->w_dotp = lforw(curwp->w_dotp);
XX
XX /* and scan forword until we hit a <NL><NL> or <NL><TAB>
XX or a <NL><SPACE> */
XX while (curwp->w_dotp != curbp->b_linep) {
XX if (llength(curwp->w_dotp) != 0 && lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
XX lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
XX curwp->w_dotp = lforw(curwp->w_dotp);
XX else
XX break;
XX }
XX
XX /* and then backward until we are in a word */
XX suc = backchar(FALSE, 1);
XX while (suc && !inword()) {
XX suc = backchar(FALSE, 1);
XX }
XX curwp->w_doto = llength(curwp->w_dotp); /* and to the EOL */
XX }
XX curwp->w_flag |= WFMOVE; /* force screen update */
XX }
XX
XX/*
XX * This routine, given a pointer to a LINE, and the current cursor goal
XX * column, return the best choice for the offset. The offset is returned.
XX * Used by "C-N" and "C-P".
XX */
XXgetgoal(dlp)
XXregister LINE *dlp;
XX {
XX register int c;
XX register int col;
XX register int newcol;
XX register int dbo;
XX
XX col = 0;
XX dbo = 0;
XX while (dbo != llength(dlp)) {
XX c = lgetc(dlp, dbo);
XX newcol = col;
XX if (c == '\t') newcol |= 0x07;
XX else if (c<0x20 || c==0x7F)
XX ++newcol;
XX ++newcol;
XX if (newcol > curgoal) break;
XX col = newcol;
XX ++dbo;
XX }
XX return (dbo);
XX }
XX
XX/*
XX * Scroll forward by a specified number of lines, or by a full page if no
XX * argument. Bound to "C-V". The "2" in the arithmetic on the window size is
XX * the overlap; this value is the default overlap value in ITS EMACS. Because
XX * this zaps the top line in the display window, we have to do a hard update.
XX */
XXforwpage(f, n)
XXregister int n;
XX {
XX register LINE *lp;
XX
XX if (f == FALSE) {
XX n = curwp->w_ntrows - 2; /* Default scroll. */
XX if (n <= 0) /* Forget the overlap */
XX n = 1; /* if tiny window. */
XX }
XX else if (n < 0)
XX return (backpage(f, -n));
XX#if CVMVAS
XX else /* Convert from pages */
XX n *= curwp->w_ntrows; /* to lines. */
XX#endif
XX lp = curwp->w_linep;
XX while (n-- && lp!=curbp->b_linep) lp = lforw(lp);
XX curwp->w_linep = lp;
XX curwp->w_dotp = lp;
XX curwp->w_doto = 0;
XX curwp->w_flag |= WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * This command is like "forwpage", but it goes backwards. The "2", like
XX * above, is the overlap between the two windows. The value is from the ITS
XX * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
XX * reason.
XX */
XXbackpage(f, n)
XXregister int n;
XX {
XX register LINE *lp;
XX
XX if (f == FALSE) {
XX n = curwp->w_ntrows - 2; /* Default scroll. */
XX if (n <= 0) /* Don't blow up if the */
XX n = 1; /* window is tiny. */
XX }
XX else if (n < 0)
XX return (forwpage(f, -n));
XX#if CVMVAS
XX else /* Convert from pages */
XX n *= curwp->w_ntrows; /* to lines. */
XX#endif
XX lp = curwp->w_linep;
XX while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp);
XX curwp->w_linep = lp;
XX curwp->w_dotp = lp;
XX curwp->w_doto = 0;
XX curwp->w_flag |= WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * Set the mark in the current window to the value of "." in the window. No
XX * errors are possible. Bound to "M-.". arg 0 = do not report mark setting
XX */
XXsetmark(f, n)
XX {
XX curwp->w_markp = curwp->w_dotp;
XX curwp->w_marko = curwp->w_doto;
XX if (f == FALSE || n != 0) mlwrite("[Mark set]");
XX return (TRUE);
XX }
XX
XX/*
XX * Swap the values of "." and "mark" in the current window. This is pretty
XX * easy, bacause all of the hard work gets done by the standard routine
XX * that moves the mark about. The only possible error is "no mark". Bound to
XX * "C-X C-X".
XX */
XXswapmark(f, n)
XX {
XX register LINE *odotp;
XX register int odoto;
XX
XX if (curwp->w_markp == NULL) {
XX mlwrite("No mark in this window");
XX return (FALSE);
XX }
XX odotp = curwp->w_dotp;
XX odoto = curwp->w_doto;
XX curwp->w_dotp = curwp->w_markp;
XX curwp->w_doto = curwp->w_marko;
XX curwp->w_markp = odotp;
XX curwp->w_marko = odoto;
XX curwp->w_flag |= WFMOVE;
XX return (TRUE);
XX }
XX
XX
SHAR_EOF
if test 10190 -ne "`wc -c basic.c`"
then
echo shar: error transmitting basic.c '(should have been 10190 characters)'
fi
echo shar: extracting bind.c
sed 's/^XX//' << \SHAR_EOF > bind.c
XX/* This file is for functions having to do with key bindings,
XX * descriptions, help commands, and command line execution.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#define INBIND TRUE
XX#include "epath.h"
XX
XXextern short doflashing;
XX
XXdeskey(f, n) /* describe the command for a certain key */
XX {
XX register int c; /* command character to describe */
XX register char *ptr; /* string pointer to scan output strings */
XX register KEYTAB *ktp; /* pointer into the command table */
XX register int found; /* matched command flag */
XX register NBIND *nptr; /* pointer into the name binding table */
XX char outseq[80]; /* output buffer for command sequence */
XX
XX /* prompt the user to type us a key to describe */
XX mlwrite(": describe-key ");
XX
XX /* get the command sequence to describe */
XX c = getckey(); /* get a command sequence */
XX
XX /* change it to something we can print as well */
XX cmdstr(c, &outseq[0]);
XX
XX /* and dump it out */
XX ptr = &outseq[0];
XX while (*ptr) (*term.t_putchar)(*ptr++);
XX (*term.t_putchar)(' '); /* space it out */
XX
XX /* find the right ->function */
XX ktp = &keytab[0];
XX found = FALSE;
XX while (ktp->k_fp != NULL) {
XX if (ktp->k_code == c) {
XX found = TRUE;
XX break;
XX }
XX ++ktp;
XX }
XX
XX if (!found) strcpy(outseq,"Not Bound");
XX else {
XX /* match it against the name binding table */
XX nptr = &names[0];
XX strcpy(outseq,"[Bad binding]");
XX while (nptr->n_func != NULL) {
XX if (nptr->n_func == ktp->k_fp) {
XX strcpy(outseq, nptr->n_name);
XX break;
XX }
XX ++nptr;
XX }
XX }
XX
XX /* output the command sequence */
XX ptr = &outseq[0];
XX while (*ptr) (*term.t_putchar)(*ptr++);
XX }
XX
XXcmdstr(c, seq) /* change a key command to a string we can print out */
XX
XXint c; /* sequence to translate */
XXchar *seq; /* destination string for sequence */
XX
XX {
XX char *ptr; /* pointer into current position in sequence */
XX
XX ptr = seq;
XX
XX /* apply GOLD sequence if needed */
XX if (c & GOLD) {
XX *ptr++ = 'G';
XX *ptr++ = '-';
XX }
XX
XX /* apply SPEC sequence if needed */
XX if (c & SPEC) {
XX *ptr++ = 'K';
XX *ptr++ = '-';
XX }
XX
XX /* apply meta sequence if needed */
XX if (c & META) {
XX *ptr++ = 'M';
XX *ptr++ = '-';
XX }
XX
XX /* apply ^X sequence if needed */
XX if (c & CTLX) {
XX *ptr++ = '^';
XX *ptr++ = 'X';
XX }
XX
XX /* apply control sequence if needed */
XX if (c & CTRL) {
XX *ptr++ = '^';
XX }
XX
XX c = c & 255; /* strip the prefixes */
XX
XX /* and output the final sequence */
XX
XX *ptr++ = c;
XX *ptr = 0; /* terminate the string */
XX }
XX
XXhelp(f, n) /* give me some help!!!!
XX bring up a fake buffer and read the help file
XX into it with view mode */
XX {
XX register int status; /* status of I/O operations */
XX register WINDOW *wp; /* scnaning pointer to windows */
XX register int i; /* index into help file names */
XX char fname[NSTRING]; /* buffer to construct file name in */
XX
XX /* search through the list of help files */
XX for (i=2; i < NPNAMES; i++) {
XX strcpy(fname, pathname[i]);
XX strcat(fname, pathname[1]);
XX status = ffropen(fname);
XX if (status == FIOSUC) break;
XX }
XX
XX if (status == FIOFNF) {
XX mlwrite("[Help file is not online]");
XX return(FALSE);
XX }
XX ffclose(); /* close the file to prepare for to read it in */
XX
XX /* split the current window to make room for the help stuff */
XX if (splitwind(FALSE, 1) == FALSE) return(FALSE);
XX
XX /* and read the stuff in */
XX if (getfile(fname, FALSE) == FALSE) return(FALSE);
XX
XX /* make this window in VIEW mode, update all mode lines */
XX curwp->w_bufp->b_mode |= MDVIEW;
XX wp = wheadp;
XX while (wp != NULL) {
XX wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX return(TRUE);
XX }
XX
XXint (*fncmatch(fname))() /* match fname to a function in the names table
XXand return any match or NULL if none */
XX
XXchar *fname; /* name to attempt to match */
XX
XX {
XX register NBIND *ffp; /* pointer to entry in name binding table */
XX
XX /* scan through the table, returning any match */
XX ffp = &names[0];
XX while (ffp->n_func != NULL) {
XX if (strcmp(fname, ffp->n_name) == 0) return(ffp->n_func);
XX ++ffp;
XX }
XX return(NULL);
XX }
XX
XX/* bindtokey: add a new key to the key binding table
XX */
XX
XXbindtokey(f, n)
XX
XXint f, n; /* command arguments [IGNORED] */
XX
XX {
XX register int c; /* command key to bind */
XX register (*kfunc)(); /* ptr to the requexted function to bind to */
XX register char *ptr; /* ptr to dump out input key string */
XX register KEYTAB *ktp; /* pointer into the command table */
XX register int found; /* matched command flag */
XX char outseq[80]; /* output buffer for keystroke sequence */
XX int (*getcname())();
XX
XX /* prompt the user to type in a key to bind */
XX mlwrite(": bind-to-key ");
XX
XX /* get the function name to bind it to */
XX kfunc = getcname();
XX if (kfunc == NULL) {
XX mlwrite("[No such function]");
XX return(FALSE);
XX }
XX (*term.t_putchar)(' '); /* space it out */
XX
XX /* get the command sequence to bind */
XX c = getckey(); /* get a command sequence */
XX
XX /* change it to something we can print as well */
XX cmdstr(c, &outseq[0]);
XX
XX /* and dump it out */
XX ptr = &outseq[0];
XX while (*ptr) (*term.t_putchar)(*ptr++);
XX
XX /* search the table to see if it exists */
XX ktp = &keytab[0];
XX found = FALSE;
XX while (ktp->k_fp != NULL) {
XX if (ktp->k_code == c) {
XX found = TRUE;
XX break;
XX }
XX ++ktp;
XX }
XX
XX if (found) { /* it exists, just change it then */
XX ktp->k_fp = kfunc;
XX }
XX else { /* otherwise we need to add it to the end */
XX /* if we run out of binding room, bitch */
XX if (ktp >= &keytab[NBINDS]) {
XX mlwrite("Binding table FULL!");
XX return(FALSE);
XX }
XX
XX ktp->k_code = c; /* add keycode */
XX ktp->k_fp = kfunc; /* and the function pointer */
XX ++ktp; /* and make sure the next is null */
XX ktp->k_code = 0;
XX ktp->k_fp = NULL;
XX }
XX
XX return(TRUE);
XX }
XX
XX
XX/* unbindkey: delete a key from the key binding table
XX */
XX
XXunbindkey(f, n)
XX
XXint f, n; /* command arguments [IGNORED] */
XX
XX {
XX register int c; /* command key to unbind */
XX register char *ptr; /* ptr to dump out input key string */
XX register KEYTAB *ktp; /* pointer into the command table */
XX register KEYTAB *sktp; /* saved pointer into the command table */
XX register int found; /* matched command flag */
XX char outseq[80]; /* output buffer for keystroke sequence */
XX
XX /* prompt the user to type in a key to unbind */
XX mlwrite(": unbind-key ");
XX
XX /* get the command sequence to unbind */
XX c = getckey(); /* get a command sequence */
XX
XX /* change it to something we can print as well */
XX cmdstr(c, &outseq[0]);
XX
XX /* and dump it out */
XX ptr = &outseq[0];
XX while (*ptr) (*term.t_putchar)(*ptr++);
XX
XX /* search the table to see if the key exists */
XX ktp = &keytab[0];
XX found = FALSE;
XX while (ktp->k_fp != NULL) {
XX if (ktp->k_code == c) {
XX found = TRUE;
XX break;
XX }
XX ++ktp;
XX }
XX
XX /* if it isn't bound, bitch */
XX if (!found) {
XX mlwrite("[Key not bound]");
XX return(FALSE);
XX }
XX
XX /* save the pointer and scan to the end of the table */
XX sktp = ktp;
XX while (ktp->k_fp != NULL) ++ktp;
XX --ktp; /* backup to the last legit entry */
XX
XX /* copy the last entry to the current one */
XX sktp->k_code = ktp->k_code;
XX sktp->k_fp = ktp->k_fp;
XX
XX /* null out the last one */
XX ktp->k_code = 0;
XX ktp->k_fp = NULL;
XX return(TRUE);
XX }
XX
XX/* namedcmd: execute a named command even if it is not bound
XX */
XX
XXnamedcmd(f, n)
XX
XXint f, n; /* command arguments [passed through to command executed] */
XX
XX {
XX register int c; /* command key to bind */
XX register (*kfunc)(); /* ptr to the requexted function to bind to */
XX register int found; /* matched command flag */
XX int (*getcname())();
XX
XX /* prompt the user to type a named command */
XX mlwrite(": ");
XX
XX /* and now get the function name to execute */
XX kfunc = getcname();
XX if (kfunc == NULL) {
XX mlwrite("[No such function]");
XX return(FALSE);
XX }
XX
XX /* and then execute the command */
XX return((*kfunc)(f, n));
XX }
XX
XXdesbind(f, n) /* describe bindings
XXbring up a fake buffer and list the key bindings
XXinto it with view mode */
XX {
XX register WINDOW *wp; /* scnaning pointer to windows */
XX register KEYTAB *ktp; /* pointer into the command table */
XX register NBIND *nptr; /* pointer into the name binding table */
XX register BUFFER *bp; /* buffer to put binding list into */
XX register char *strp; /* pointer int string to send */
XX register int cpos; /* current position to use in outseq */
XX char outseq[80]; /* output buffer for keystroke sequence */
XX
XX /* split the current window to make room for the binding list */
XX if (splitwind(FALSE, 1) == FALSE) return(FALSE);
XX
XX /* and get a buffer for it */
XX bp = bfind("Binding list", TRUE, 0);
XX if (bp == NULL || bclear(bp) == FALSE) {
XX mlwrite("Can not display binding list");
XX return(FALSE);
XX }
XX
XX /* let us know this is in progress */
XX mlwrite("[Building buffer list]");
XX
XX /* disconect the current buffer */
XX if (--curbp->b_nwnd == 0) { /* Last use. */
XX curbp->b_dotp = curwp->w_dotp;
XX curbp->b_doto = curwp->w_doto;
XX curbp->b_markp = curwp->w_markp;
XX curbp->b_marko = curwp->w_marko;
XX }
XX
XX /* connect the current window to this buffer */
XX curbp = bp; /* make this buffer current in current window */
XX bp->b_mode = 0; /* no modes active in binding list */
XX bp->b_nwnd++; /* mark us as more in use */
XX wp = curwp;
XX wp->w_bufp = bp;
XX wp->w_linep = bp->b_linep;
XX wp->w_flag = WFHARD|WFFORCE|WFHARD;
XX wp->w_dotp = bp->b_dotp;
XX wp->w_doto = bp->b_doto;
XX wp->w_markp = NULL;
XX wp->w_marko = 0;
XX
XX /* build the contents of this window, inserting it line by line */
XX nptr = &names[0];
XX while (nptr->n_func != NULL) {
XX
XX /* add in the command name */
XX strcpy(outseq, nptr->n_name);
XX cpos = strlen(outseq);
XX
XX /* search down any keys bound to this */
XX ktp = &keytab[0];
XX while (ktp->k_fp != NULL) {
XX if (ktp->k_fp == nptr->n_func) {
XX /* padd out some spaces */
XX while (cpos < 25) outseq[cpos++] = ' ';
XX
XX /* add in the command sequence */
XX cmdstr(ktp->k_code, &outseq[cpos]);
XX while (outseq[cpos] != 0) ++cpos;
XX
XX /* and add it as a line into the buffer */
XX strp = &outseq[0];
XX while (*strp != 0) linsert(1, *strp++);
XX lnewline();
XX
XX cpos = 0; /* and clear the line */
XX }
XX ++ktp;
XX }
XX
XX /* if no key was bound, we need to dump it anyway */
XX if (cpos > 0) {
XX outseq[cpos] = 0;
XX strp = &outseq[0];
XX while (*strp != 0) linsert(1, *strp++);
XX lnewline();
XX }
XX
XX /* and on to the next name */
XX ++nptr;
XX }
XX
XX curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
XX curbp->b_flag &= ~BFCHG; /* don't flag this as a change */
XX wp->w_dotp = lforw(bp->b_linep);/* back to the begining */
XX wp->w_doto = 0;
XX wp = wheadp; /* and update ALL mode lines */
XX while (wp != NULL) {
XX wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX mlwrite(""); /* clear the mode line */
XX return(TRUE);
XX }
XX
XXgetckey() /* get a command key sequence from the keyboard */
XX
XX {
XX register int c; /* character fetched */
XX register char *tp; /* pointer into the token */
XX char tok[NSTRING]; /* command incoming */
XX
XX /* check to see if we are executing a command line */
XX if (clexec) {
XX nxtarg(tok); /* get the next token */
XX
XX /* parse it up */
XX tp = &tok[0];
XX c = 0;
XX
XX /* first the GOLD prefix */
XX if (*tp == 'G' && *(tp+1) == '-') {
XX c |= GOLD;
XX tp += 2;
XX }
XX
XX /* next the function prefix */
XX if (*tp == 'K' && *(tp+1) == '-') {
XX c |= SPEC;
XX tp += 2;
XX }
XX
XX /* next the META prefix */
XX if (*tp == 'M' && *(tp+1) == '-') {
XX c = META;
XX tp += 2;
XX }
XX
XX /* control-x as well... */
XX if (*tp == '^' && *(tp+1) == 'X') {
XX c |= CTLX;
XX tp += 2;
XX }
XX
XX /* a control char? */
XX if (*tp == '^' & *(tp+1) != 0) {
XX c |= CTRL;
XX ++tp;
XX }
XX
XX /* make sure we are not lower case */
XX if (c >= 'a' && c <= 'z') c -= 32;
XX
XX /* the final sequence... */
XX c |= *tp;
XX
XX return(c);
XX }
XX
XX /* or the normal way */
XX c = getkey(); /* get a command sequence */
XX if (c == (CTRL|'X')) /* get control-x sequence */
XX c = CTLX | getctl();
XX return(c);
XX }
XX
XX
SHAR_EOF
if test 12210 -ne "`wc -c bind.c`"
then
echo shar: error transmitting bind.c '(should have been 12210 characters)'
fi
echo shar: extracting buffer.c
sed 's/^XX//' << \SHAR_EOF > buffer.c
XX/*
XX * Buffer management.
XX * Some of the functions are internal,
XX * and some are actually attached to user
XX * keys. Like everyone else, they set hints
XX
XX * for the display system.
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX/*
XX * Attach a buffer to a window. The
XX * values of dot and mark come from the buffer
XX * if the use count is 0. Otherwise, they come
XX * from some other window.
XX */
XXusebuffer(f, n)
XX {
XX register BUFFER *bp;
XX register int s;
XX char bufn[NBUFN];
XX
XX if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE) return (s);
XX if ((bp=bfind(bufn, TRUE, 0)) == NULL) return (FALSE);
XX return(swbuffer(bp));
XX }
XX
XXswbuffer(bp) /* make buffer BP current */
XX
XXBUFFER *bp;
XX
XX {
XX register WINDOW *wp;
XX
XX if (--curbp->b_nwnd == 0) { /* Last use. */
XX curbp->b_dotp = curwp->w_dotp;
XX curbp->b_doto = curwp->w_doto;
XX curbp->b_markp = curwp->w_markp;
XX curbp->b_marko = curwp->w_marko;
XX }
XX curbp = bp; /* Switch. */
XX if (curbp->b_active != TRUE) { /* buffer not active yet*/
XX /* read it in and activate it */
XX readin(curbp->b_fname, TRUE);
XX curbp->b_dotp = lforw(curbp->b_linep);
XX curbp->b_doto = 0;
XX curbp->b_active = TRUE;
XX }
XX curwp->w_bufp = bp;
XX curwp->w_linep = bp->b_linep; /* For macros, ignored. */
XX curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */
XX if (bp->b_nwnd++ == 0) { /* First use. */
XX curwp->w_dotp = bp->b_dotp;
XX curwp->w_doto = bp->b_doto;
XX curwp->w_markp = bp->b_markp;
XX curwp->w_marko = bp->b_marko;
XX return (TRUE);
XX }
XX wp = wheadp; /* Look for old. */
XX while (wp != NULL) {
XX if (wp!=curwp && wp->w_bufp==bp) {
XX curwp->w_dotp = wp->w_dotp;
XX curwp->w_doto = wp->w_doto;
XX curwp->w_markp = wp->w_markp;
XX curwp->w_marko = wp->w_marko;
XX break;
XX }
XX wp = wp->w_wndp;
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Dispose of a buffer, by name.
XX * Ask for the name. Look it up (don't get too
XX * upset if it isn't there at all!). Get quite upset
XX * if the buffer is being displayed. Clear the buffer (ask
XX * if the buffer has been changed). Then free the header
XX * line and the buffer header. Bound to "C-X K".
XX */
XXkillbuffer(f, n)
XX
XX {
XX register BUFFER *bp;
XX register int s;
XX char bufn[NBUFN];
XX
XX if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE) return(s);
XX if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown. */
XX return (TRUE);
XX return(zotbuf(bp));
XX }
XX
XXzotbuf(bp) /* kill the buffer pointed to by bp */
XX
XXregister BUFFER *bp;
XX
XX {
XX register BUFFER *bp1;
XX register BUFFER *bp2;
XX register int s;
XX
XX if (bp->b_nwnd != 0) { /* Error if on screen. */
XX mlwrite("Buffer is being displayed");
XX return (FALSE);
XX }
XX
XX#if ULTRIX
XX if (bp == procbuf) {
XX kill(pid,9); /* kill the sub process */
XX inchannel = outchannel = pid = 0;
XX procbuf = NULL;
XX }
XX#endif
XX
XX if ((s=bclear(bp)) != TRUE) /* Blow text away. */
XX return (s);
XX free((char *) bp->b_linep); /* Release header line. */
XX bp1 = NULL; /* Find the header. */
XX bp2 = bheadp;
XX while (bp2 != bp) {
XX bp1 = bp2;
XX bp2 = bp2->b_bufp;
XX }
XX bp2 = bp2->b_bufp; /* Next one in chain. */
XX if (bp1 == NULL) /* Unlink it. */
XX bheadp = bp2;
XX else
XX bp1->b_bufp = bp2;
XX free((char *) bp); /* Release buffer block */
XX return (TRUE);
XX }
XX
XXnamebuffer(f,n) /* Rename the current buffer */
XX
XXint f, n; /* default Flag & Numeric arg */
XX
XX {
XX register BUFFER *bp; /* pointer to scan through all buffers */
XX char bufn[NBUFN]; /* buffer to hold buffer name */
XX
XX /* prompt for and get the new buffer name */
XX ask: if (mlreply("Change buffer name to: ", bufn, NBUFN) != TRUE)
XX return(FALSE);
XX
XX /* and check for duplicates */
XX bp = bheadp;
XX while (bp != NULL) {
XX if (bp != curbp) {
XX /* if the names the same */
XX if (strcmp(bufn, bp->b_bname) == 0) goto ask; /* try again */
XX }
XX bp = bp->b_bufp; /* onward */
XX }
XX
XX strcpy(curbp->b_bname, bufn); /* copy buffer name to structure */
XX curwp->w_flag |= WFMODE; /* make mode line replot */
XX mlerase();
XX }
XX
XX/*
XX * List all of the active
XX * buffers. First update the special
XX * buffer that holds the list. Next make
XX * sure at least 1 window is displaying the
XX * buffer list, splitting the screen if this
XX * is what it takes. Lastly, repaint all of
XX * the windows that are displaying the
XX * list. Bound to "C-X C-B".
XX
XX */
XXlistbuffers(f, n)
XX {
XX register WINDOW *wp;
XX register BUFFER *bp;
XX register int s;
XX
XX if ((s=makelist()) != TRUE) return (s);
XX if (blistp->b_nwnd == 0) { /* Not on screen yet. */
XX if ((wp=wpopup()) == NULL)
XX return (FALSE);
XX bp = wp->w_bufp;
XX if (--bp->b_nwnd == 0) {
XX bp->b_dotp = wp->w_dotp;
XX bp->b_doto = wp->w_doto;
XX bp->b_markp = wp->w_markp;
XX bp->b_marko = wp->w_marko;
XX }
XX wp->w_bufp = blistp;
XX ++blistp->b_nwnd;
XX }
XX wp = wheadp;
XX while (wp != NULL) {
XX if (wp->w_bufp == blistp) {
XX wp->w_linep = lforw(blistp->b_linep);
XX wp->w_dotp = lforw(blistp->b_linep);
XX wp->w_doto = 0;
XX wp->w_markp = NULL;
XX wp->w_marko = 0;
XX wp->w_flag |= WFMODE|WFHARD;
XX }
XX wp = wp->w_wndp;
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * This routine rebuilds the
XX * text in the special secret buffer
XX * that holds the buffer list. It is called
XX * by the list buffers command. Return TRUE
XX * if everything works. Return FALSE if there
XX * is an error (if there is no memory).
XX */
XXmakelist()
XX {
XX register char *cp1;
XX register char *cp2;
XX register int c;
XX register BUFFER *bp;
XX register LINE *lp;
XX register int nbytes;
XX register int s;
XX register int i;
XX register int type;
XX char b[6+1];
XX char line[128];
XX
XX blistp->b_flag &= ~BFCHG; /* Don't complain! */
XX if ((s=bclear(blistp)) != TRUE) /* Blow old text away */
XX return (s);
XX strcpy(blistp->b_fname, "");
XX if (addline("AC MODES Size Buffer File") == FALSE ||
XX addline("-- ------ ---- ------ ----") == FALSE)
XX return (FALSE);
XX bp = bheadp; /* For all buffers */
XX while (bp != NULL) {
XX if ((bp->b_flag&BFTEMP) != 0) { /* Skip magic ones. */
XX bp = bp->b_bufp;
XX continue;
XX }
XX cp1 = &line[0]; /* Start at left edge */
XX
XX /* output status of ACTIVE flag (has the file been read in? */
XX if (bp->b_active == TRUE) /* "@" if activated */
XX *cp1++ = '@';
XX else
XX *cp1++ = ' ';
XX
XX /* output status of changed flag */
XX if ((bp->b_flag&BFCHG) != 0) /* "*" if changed */
XX *cp1++ = '*';
XX else
XX *cp1++ = ' ';
XX *cp1++ = ' '; /* Gap. */
XX
XX /* output the mode codes */
XX for (i = 0; i < NUMMODES; i++) {
XX if (bp->b_mode & (1 << i)) *cp1++ = modecode[i];
XX else
XX *cp1++ = '.';
XX }
XX *cp1++ = ' '; /* Gap. */
XX nbytes = 0; /* Count bytes in buf. */
XX lp = lforw(bp->b_linep);
XX while (lp != bp->b_linep) {
XX nbytes += llength(lp)+1;
XX lp = lforw(lp);
XX }
XX itoa(b, 6, nbytes); /* 6 digit buffer size. */
XX cp2 = &b[0];
XX while ((c = *cp2++) != 0) *cp1++ = c;
XX *cp1++ = ' '; /* Gap. */
XX cp2 = &bp->b_bname[0]; /* Buffer name */
XX while ((c = *cp2++) != 0) *cp1++ = c;
XX cp2 = &bp->b_fname[0]; /* File name */
XX if (*cp2 != 0) {
XX while (cp1 < &line[2+1+5+1+6+1+NBUFN]) *cp1++ = ' ';
XX while ((c = *cp2++) != 0) {
XX if (cp1 < &line[128-1]) *cp1++ = c;
XX }
XX }
XX *cp1 = 0; /* Add to the buffer. */
XX if (addline(line) == FALSE) return (FALSE);
XX bp = bp->b_bufp;
XX }
XX return (TRUE); /* All done */
XX }
XX
XXitoa(buf, width, num)
XXregister char buf[];
XXregister int width;
XXregister int num;
XX {
XX buf[width] = 0; /* End of string. */
XX while (num >= 10) { /* Conditional digits. */
XX buf[--width] = (num%10) + '0';
XX num /= 10;
XX }
XX buf[--width] = num + '0'; /* Always 1 digit. */
XX while (width != 0) /* Pad with blanks. */
XX buf[--width] = ' ';
XX }
XX
XX/*
XX * The argument "text" points to
XX * a string. Append this line to the
XX * buffer list buffer. Handcraft the EOL
XX * on the end. Return TRUE if it worked and
XX * FALSE if you ran out of room.
XX */
XXaddline(text)
XXchar *text;
XX {
XX register LINE *lp;
XX register int i;
XX register int ntext;
XX
XX ntext = strlen(text);
XX if ((lp=lalloc(ntext)) == NULL) return (FALSE);
XX for (i=0; i<ntext; ++i) lputc(lp, i, text[i]);
XX blistp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
XX lp->l_bp = blistp->b_linep->l_bp;
XX blistp->b_linep->l_bp = lp;
XX lp->l_fp = blistp->b_linep;
XX if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */
XX blistp->b_dotp = lp; /* move it to new line */
XX return (TRUE);
XX }
XX
XX/*
XX * Look through the list of
XX * buffers. Return TRUE if there
XX * are any changed buffers. Buffers
XX * that hold magic internal stuff are
XX * not considered; who cares if the
XX * list of buffer names is hacked.
XX * Return FALSE if no buffers
XX * have been changed.
XX */
XXanycb()
XX {
XX register BUFFER *bp;
XX
XX bp = bheadp;
XX while (bp != NULL) {
XX if ( bp != procbuf &&
XX (bp->b_flag&BFTEMP) == 0 &&
XX (bp->b_flag&BFCHG) !=0 ) return (TRUE);
XX bp = bp->b_bufp;
XX }
XX return (FALSE);
XX }
XX
XX/*
XX * Find a buffer, by name. Return a pointer
XX * to the BUFFER structure associated with it. If
XX * the named buffer is found, but is a TEMP buffer (like
XX * the buffer list) complain. If the buffer is not found
XX * and the "cflag" is TRUE, create it. The "bflag" is
XX * the settings for the flags in the buffer.
XX */
XXBUFFER *
XXbfind(bname, cflag, bflag)
XXregister char *bname;
XX {
XX register BUFFER *bp;
XX register BUFFER *sb; /* buffer to insert after */
XX register LINE *lp;
XX char *malloc();
XX
XX bp = bheadp;
XX while (bp != NULL) {
XX if (strcmp(bname, bp->b_bname) == 0) {
XX if ((bp->b_flag&BFTEMP) != 0) {
XX mlwrite("Cannot select builtin buffer");
XX return (NULL);
XX }
XX return (bp);
XX }
XX bp = bp->b_bufp;
XX }
XX if (cflag != FALSE) {
XX if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) return (NULL);
XX if ((lp=lalloc(0)) == NULL) {
XX free((char *) bp);
XX return (NULL);
XX }
XX /* find the place in the list to insert this buffer */
XX if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
XX /* insert at the begining */
XX bp->b_bufp = bheadp;
XX bheadp = bp;
XX }
XX else {
XX sb = bheadp;
XX while (sb->b_bufp != NULL) {
XX if (strcmp(sb->b_bufp->b_bname, bname) > 0) break;
XX sb = sb->b_bufp;
XX }
XX
XX /* and insert it */
XX bp->b_bufp = sb->b_bufp;
XX
XX sb->b_bufp = bp;
XX }
XX
XX /* and set up the other buffer fields */
XX bp->b_active = TRUE;
XX bp->b_dotp = lp;
XX bp->b_doto = 0;
XX bp->b_markp = NULL;
XX bp->b_marko = 0;
XX bp->b_flag = bflag;
XX bp->b_mode = 0;
XX bp->b_nwnd = 0;
XX bp->b_linep = lp;
XX strcpy(bp->b_fname, "");
XX strcpy(bp->b_bname, bname);
XX lp->l_fp = lp;
XX lp->l_bp = lp;
XX }
XX return (bp);
XX }
XX
XX/*
XX * This routine blows away all of the text
XX * in a buffer. If the buffer is marked as changed
XX * then we ask if it is ok to blow it away; this is
XX * to save the user the grief of losing text. The
XX * window chain is nearly always wrong if this gets
XX * called; the caller must arrange for the updates
XX * that are required. Return TRUE if everything
XX * looks good.
XX */
XXbclear(bp)
XXregister BUFFER *bp;
XX {
XX register LINE *lp;
XX register int s;
XX
XX if ((bp->b_flag&BFTEMP) == 0 /* Not scratch buffer. */
XX && (bp->b_flag&BFCHG) != 0 /* Something changed */
XX && (s=mlyesno("Discard changes")) != TRUE)
XX return (s);
XX bp->b_flag &= ~BFCHG; /* Not changed */
XX while ((lp=lforw(bp->b_linep)) != bp->b_linep) lfree(lp);
XX bp->b_dotp = bp->b_linep; /* Fix "." */
XX bp->b_doto = 0;
XX bp->b_markp = NULL; /* Invalidate "mark" */
XX bp->b_marko = 0;
XX return (TRUE);
XX }
XX
XX
SHAR_EOF
if test 12143 -ne "`wc -c buffer.c`"
then
echo shar: error transmitting buffer.c '(should have been 12143 characters)'
fi
echo shar: extracting display.c
sed 's/^XX//' << \SHAR_EOF > display.c
XX/*
XX * The functions in this file handle redisplay. There are two halves, the
XX * ones that update the virtual display screen, and the ones that make the
XX * physical display screen the same as the virtual display screen. These
XX * functions use hints that are left in the windows by the commands.
XX *
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#define WFDEBUG 0 /* Window flag debug. */
XXtypedef struct VIDEO {
XX short v_flag; /* Flags */
XX char v_text[1]; /* Screen data. */
XX }
XXVIDEO;
XX
XX#define VFCHG 0x0001 /* Changed. */
XX#define VFEXT 0x0002 /* extended (beyond column 80) */
XX#define VFMOD 0x0004 /* change in mode line occurred*/
XX
XXint vtrow = 0; /* Row location of SW cursor */
XXint vtcol = 0; /* Column location of SW cursor */
XXint ttrow = HUGE; /* Row location of HW cursor */
XXint ttcol = HUGE; /* Column location of HW cursor */
XXint lbound = 0; /* leftmost column of current line
XXbeing displayed */
XX
XXVIDEO **vscreen; /* Virtual screen. */
XXVIDEO **pscreen; /* Physical screen. */
XX
XX/*
XX * Initialize the data structures used by the display code. The edge vectors
XX * used to access the screens are set up. The operating system's terminal I/O
XX * channel is set up. All the other things get initialized at compile time.
XX * The original window has "WFCHG" set, so that it will get completely
XX * redrawn on the first call to "update".
XX */
XX
XXvtinit()
XX {
XX register int i;
XX register VIDEO *vp;
XX char *malloc();
XX
XX (*term.t_open)();
XX vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
XX
XX if (vscreen == NULL) exit(1);
XX
XX pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
XX
XX if (pscreen == NULL) exit(1);
XX
XX for (i = 0; i < term.t_nrow; ++i) {
XX vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
XX
XX if (vp == NULL) exit(1);
XX
XX vp->v_flag = 0;
XX vscreen[i] = vp;
XX vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
XX
XX if (vp == NULL) exit(1);
XX
XX vp->v_flag = 0;
XX pscreen[i] = vp;
XX }
XX }
XX
XX/*
XX * Clean up the virtual terminal system, in anticipation for a return to the
XX * operating system. Move down to the last line and clear it out (the next
XX * system prompt will be written in the line). Shut down the channel to the
XX * terminal.
XX */
XXvttidy()
XX {
XX mlerase();
XX movecursor(term.t_nrow, 0);
XX (*term.t_close)();
XX }
XX
XX/*
XX * Set the virtual cursor to the specified row and column on the virtual
XX * screen. There is no checking for nonsense values; this might be a good
XX * idea during the early stages.
XX */
XXvtmove(row, col)
XX {
XX vtrow = row;
XX vtcol = col;
XX }
XX
XX/*
XX * Write a character to the virtual screen. The virtual row and column are
XX * updated. If the line is too long put a "$" in the last column. This routine
XX * only puts printing characters into the virtual terminal buffers. Only
XX * column overflow is checked.
XX */
XXvtputc(c)
XXint c;
XX {
XX register VIDEO *vp;
XX
XX vp = vscreen[vtrow];
XX
XX if (vtcol >= term.t_ncol) vp->v_text[term.t_ncol - 1] = '$';
XX else if (c == '\t')
XX {
XX do
XX {
XX vtputc(' ');
XX }
XX while ((vtcol&0x07) != 0 && vtcol < term.t_ncol);
XX }
XX else if (c < 0x20 || c == 0x7F)
XX {
XX vtputc('^');
XX vtputc(c ^ 0x40);
XX }
XX else
XX vp->v_text[vtcol++] = c;
XX }
XX
XX/* put a character to the virtual screen in an extended line. If we are
XXnot yet on left edge, don't print it yet. check for overflow on
XXthe right margin */
XX
XXvtpute(c)
XX
XXint c;
XX
XX {
XX register VIDEO *vp;
XX
XX vp = vscreen[vtrow];
XX
XX if (vtcol >= term.t_ncol) vp->v_text[term.t_ncol - 1] = '$';
XX else if (c == '\t')
XX {
XX do
XX {
XX vtpute(' ');
XX }
XX while (((vtcol + lbound)&0x07) != 0 && vtcol < term.t_ncol);
XX }
XX else if (c < 0x20 || c == 0x7F)
XX {
XX vtpute('^');
XX vtpute(c ^ 0x40);
XX }
XX else {
XX if (vtcol >= 0) vp->v_text[vtcol] = c;
XX ++vtcol;
XX }
XX }
XX
XX/*
XX * Erase from the end of the software cursor to the end of the line on which
XX * the software cursor is located.
XX */
XXvteeol()
XX {
XX register VIDEO *vp;
XX
XX vp = vscreen[vtrow];
XX while (vtcol < term.t_ncol) vp->v_text[vtcol++] = ' ';
XX }
XX
XX/*
XX * Make sure that the display is right. This is a three part process. First,
XX * scan through all of the windows looking for dirty ones. Check the framing,
XX * and refresh the screen. Second, make sure that "currow" and "curcol" are
XX * correct for the current window. Third, make the virtual and physical
XX * screens the same.
XX */
XXupdate()
XX {
XX register LINE *lp;
XX register WINDOW *wp;
XX register VIDEO *vp1;
XX register VIDEO *vp2;
XX register int i,j,k;
XX register int c;
XX int row_p,row_v,n,tryblock;
XX
XX#ifdef TYPEAH
XX if (typahead()) return;
XX#endif
XX tryblock = 0;
XX wp = wheadp;
XX
XX while (wp != NULL) {
XX /* Look at any window with update flags set on. */
XX
XX if (wp->w_flag != 0) {
XX /* If not force reframe, check the framing. */
XX
XX if ((wp->w_flag & WFFORCE) == 0) {
XX lp = wp->w_linep;
XX
XX for (i = 0; i < wp->w_ntrows; ++i) {
XX if (lp == wp->w_dotp) goto out;
XX
XX if (lp == wp->w_bufp->b_linep) break;
XX
XX lp = lforw(lp);
XX }
XX }
XX
XX /* Not acceptable, better compute a new value for the line at the
XX * top of the window. Then set the "WFHARD" flag to force full
XX * redraw.
XX */
XX i = wp->w_force;
XX
XX if (i > 0) {
XX --i;
XX if (i >= wp->w_ntrows) i = wp->w_ntrows-1;
XX }
XX else if (i < 0)
XX {
XX i += wp->w_ntrows;
XX
XX if (i < 0) i = 0;
XX }
XX else
XX i = wp->w_ntrows/2;
XX
XX lp = wp->w_dotp;
XX
XX while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
XX --i;
XX lp = lback(lp);
XX }
XX
XX wp->w_linep = lp;
XX wp->w_flag |= WFHARD; /* Force full. */
XX
XX out:
XX /* Try to use reduced update. Mode line update has its own special
XX * flag. The fast update is used if the only thing to do is within
XX * the line editing. */
XX lp = wp->w_linep;
XX i = wp->w_toprow;
XX
XX if ((wp->w_flag & ~WFMODE) == WFEDIT) {
XX while (lp != wp->w_dotp) {
XX ++i;
XX lp = lforw(lp);
XX }
XX
XX vscreen[i]->v_flag |= VFCHG;
XX vtmove(i, 0);
XX
XX for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j));
XX
XX vteeol();
XX }
XX else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0)
XX {
XX tryblock = 1;
XX while (i < wp->w_toprow+wp->w_ntrows) {
XX vscreen[i]->v_flag |= VFCHG;
XX vtmove(i, 0);
XX
XX /* if line has been changed */
XX if (lp != wp->w_bufp->b_linep) {
XX for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j));
XX lp = lforw(lp);
XX }
XX vteeol();
XX ++i;
XX }
XX }
XX#if ~WFDEBUG
XX if ((wp->w_flag&WFMODE) != 0) modeline(wp);
XX
XX wp->w_flag = 0;
XX wp->w_force = 0;
XX#endif
XX }
XX#if WFDEBUG
XX modeline(wp);
XX wp->w_flag = 0;
XX wp->w_force = 0;
XX#endif
XX
XX /* and onward to the next window */
XX wp = wp->w_wndp;
XX }
XX
XX /* Always recompute the row and column number of the hardware cursor. This
XX * is the only update for simple moves.
XX */
XX lp = curwp->w_linep;
XX currow = curwp->w_toprow;
XX
XX while (lp != curwp->w_dotp) {
XX ++currow;
XX lp = lforw(lp);
XX }
XX
XX curcol = 0;
XX i = 0;
XX
XX while (i < curwp->w_doto) {
XX c = lgetc(lp, i++);
XX
XX if (c == '\t') curcol |= 0x07;
XX else if (c < 0x20 || c == 0x7F)
XX ++curcol;
XX
XX ++curcol;
XX }
XX
XX if (curcol >= term.t_ncol - 1) { /* extended line. */
XX /* flag we are extended and changed */
XX vscreen[currow]->v_flag |= VFEXT | VFCHG;
XX updext(); /* and output extended line */
XX }
XX else
XX lbound = 0; /* not extended line */
XX
XX /* make sure no lines need to be de-extended because the cursor is
XX no longer on them */
XX
XX wp = wheadp;
XX
XX while (wp != NULL) {
XX lp = wp->w_linep;
XX i = wp->w_toprow;
XX
XX while (i < wp->w_toprow + wp->w_ntrows) {
XX if (vscreen[i]->v_flag & VFEXT) {
XX /* always flag extended lines as changed */
XX vscreen[i]->v_flag |= VFCHG;
XX if ((wp != curwp) || (lp != wp->w_dotp) || (curcol < term.t_ncol - 1)) {
XX vtmove(i, 0);
XX for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j));
XX vteeol();
XX
XX /* this line no longer is extended */
XX vscreen[i]->v_flag &= ~VFEXT;
XX }
XX }
XX lp = lforw(lp);
XX ++i;
XX }
XX /* if garbaged then fix up mode lines */
XX if (sgarbf != FALSE) vscreen[i]->v_flag |= VFMOD|VFCHG;
XX
XX /* and onward to the next window */
XX wp = wp->w_wndp;
XX }
XX
XX /* Special hacking if the screen is garbage. Clear the hardware screen,
XX * and update your copy to agree with it. Set all the virtual screen
XX * change bits, to force a full update.
XX */
XX if (sgarbf != FALSE) {
XX for (i = 0; i < term.t_nrow; ++i) {
XX vscreen[i]->v_flag |= VFCHG;
XX vp1 = pscreen[i];
XX for (j = 0; j < term.t_ncol; ++j) vp1->v_text[j] = ' ';
XX }
XX
XX (*term.t_putchar)('\033'); /* as good a place as any to force */
XX (*term.t_putchar)('='); /* application mode on the terminal */
XX
XX movecursor(0, 0); /* Erase the screen. */
XX (*term.t_eeop)();
XX sgarbf = FALSE;
XX mpresf = FALSE; /* the message area. */
XX tryblock = 0;
XX }
XX
XX /* If we're going to try a block transfer, make sure at least 1/4
XX * of the lines DON'T agree
XX */
XX if (tryblock) {
XX n = 0;
XX j = term.t_ncol >> 2;
XX k = term.t_ncol >> 1;
XX for (i = 0; i < term.t_nrow; i++) {
XX vp1 = vscreen[i];
XX vp2 = pscreen[i];
XX if (vp1->v_text[0] != vp2->v_text[0] ||
XX vp1->v_text[j] != vp2->v_text[j] ||
XX vp1->v_text[k] != vp2->v_text[k]) n++;
XX }
XX if (n <= (term.t_nrow >> 2)) tryblock = 0;
XX }
XX
XX /* First see if we can do a massive "block move" of data... */
XX if (tryblock) {
XX row_p = row_v = n = -1;
XX for (i = currow >= 4 ? currow - 4 : 0;
XX i <= currow+4 && i <= term.t_nrow-4; i++) {
XX for (j = 0; j < term.t_nrow; j++) {
XX for (k = 0; k < term.t_nrow-i && k < term.t_nrow-j; k++) {
XX vp1 = pscreen[i+k];
XX vp2 = vscreen[j+k];
XX if (strncmp(vp1->v_text,vp2->v_text,term.t_ncol)
XX != 0) break;
XX }
XX if (k > n) {
XX n = k;
XX row_p = i;
XX row_v = j;
XX }
XX }
XX }
XX
XX /* Make sure we got at least 1/4 lines to shift and
XX at most 1/4 of the screen to redo */
XX if (row_p != row_v && n >= (term.t_nrow >> 2) &&
XX (term.t_nrow-row_v)-n <= (term.t_nrow >> 2)) {
XX if (row_p < row_v) {
XX (*term.t_insert)(row_p,(row_v-row_p));
XX j = (term.t_nrow-1) - (row_v-row_p);
XX for (i=term.t_nrow-1; i >= row_v; i--) {
XX vscreen[i]->v_flag |= VFCHG;
XX vp1 = pscreen[j--];
XX vp2 = pscreen[i];
XX strncpy(vp2->v_text,vp1->v_text,term.t_ncol);
XX }
XX for (i=row_p; i < row_v; i++) {
XX vscreen[i]->v_flag |= VFCHG;
XX vp1 = pscreen[i];
XX for(j=0; j < term.t_ncol; j++) vp1->v_text[j] = ' ';
XX }
XX }
XX else {
XX (*term.t_delete)(row_v,(row_p-row_v));
XX j = row_v;
XX for (i=row_p; i < term.t_nrow; i++) {
XX vscreen[j]->v_flag |= VFCHG;
XX vp1 = pscreen[j++];
XX vp2 = pscreen[i];
XX strncpy(vp1->v_text,vp2->v_text,term.t_ncol);
XX }
XX for (i=j; i < term.t_nrow; i++) {
XX vscreen[i]->v_flag |= VFCHG;
XX vp1 = pscreen[i];
XX for(j=0; j < term.t_ncol; j++) vp1->v_text[j] = ' ';
XX }
XX }
XX wp = wheadp;
XX while (wp != NULL) {
XX i = wp->w_toprow+wp->w_ntrows;
XX if (i >= row_p || i >= row_v)
XX vscreen[i]->v_flag |= VFMOD|VFCHG;
XX wp = wp->w_wndp;
XX }
XX }
XX else tryblock = 0;
XX }
XX
XX /* Make sure that the physical and virtual displays agree. Unlike before,
XX * the "updateline" code is only called with a line that has been updated
XX * for sure.
XX */
XX for (i = 0; i < term.t_nrow; ++i) {
XX vp1 = vscreen[i];
XX
XX if ((vp1->v_flag&VFCHG) != 0) {
XX#ifdef TYPEAH
XX if (!tryblock && typahead()) return;
XX#endif
XX vp1->v_flag &= ~VFCHG;
XX vp2 = pscreen[i];
XX
XX if ((vp1->v_flag&VFMOD) != 0) {
XX updateline(i, &vp1->v_text[0], &vp2->v_text[0],1);
XX vp1->v_flag &= ~VFMOD;
XX }
XX else updateline(i, &vp1->v_text[0], &vp2->v_text[0],0);
XX
XX }
XX }
XX
XX /* Finally, update the hardware cursor and flush out buffers. */
XX movecursor(currow, curcol - lbound);
XX (*term.t_flush)();
XX }
XX
XX/* updext: update the extended line which the cursor is currently
XXon at a column greater than the terminal width. The line
XXwill be scrolled right or left to let the user see where
XXthe cursor is
XX */
XX
XXupdext()
XX
XX {
XX register int rcursor; /* real cursor location */
XX register LINE *lp; /* pointer to current line */
XX register int j; /* index into line */
XX
XX /* calculate what column the real cursor will end up in */
XX rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
XX lbound = curcol - rcursor + 1;
XX
XX /* scan through the line outputing characters to the virtual screen */
XX /* once we reach the left edge */
XX vtmove(currow, -lbound); /* start scanning offscreen */
XX lp = curwp->w_dotp; /* line to output */
XX for (j=0; j<llength(lp); ++j) /* until the end-of-line */
XX vtpute(lgetc(lp, j));
XX
XX /* truncate the virtual line */
XX vteeol();
XX
XX /* and put a '$' in column 1 */
XX vscreen[currow]->v_text[0] = '$';
XX }
XX
XX/*
XX * Update a single line. This does not know how to use insert or delete
XX * character sequences; we are using VT52 functionality. Update the physical
XX * row and column variables. It does try an exploit erase to end of line. The
XX * RAINBOW version of this routine uses fast video.
XX */
XXupdateline(row, vline, pline, ismode)
XXchar vline[];
XXchar pline[];
XX {
XX register char *cp1;
XX register char *cp2;
XX register char *cp3;
XX register char *cp4;
XX register char *cp5;
XX register int nbflag;
XX
XX cp1 = &vline[0]; /* Compute left match. */
XX cp2 = &pline[0];
XX
XX while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0]) {
XX ++cp1;
XX ++cp2;
XX }
XX
XX /* This can still happen, even though we only call this routine on changed
XX * lines. A hard update is always done when a line splits, a massive
XX * change is done, or a buffer is displayed twice. This optimizes out most
XX * of the excess updating. A lot of computes are used, but these tend to
XX * be hard operations that do a lot of update, so I don't really care.
XX */
XX if (cp1 == &vline[term.t_ncol]) /* All equal. */
XX return;
XX
XX nbflag = FALSE;
XX cp3 = &vline[term.t_ncol]; /* Compute right match. */
XX cp4 = &pline[term.t_ncol];
XX
XX while (cp3[-1] == cp4[-1]) {
XX --cp3;
XX --cp4;
XX if (cp3[0] != ' ') /* Note if any nonblank */
XX nbflag = TRUE; /* in right match. */
XX }
XX
XX cp5 = cp3;
XX
XX if (nbflag == FALSE && eolexist == TRUE) /* Erase to EOL ? */
XX {
XX while (cp5!=cp1 && cp5[-1]==' ') --cp5;
XX
XX if (cp3-cp5 <= 3) /* Use only if erase is */
XX cp5 = cp3; /* fewer characters. */
XX }
XX
XX movecursor(row, cp1-&vline[0]); /* Go to start of line. */
XX
XX if (ismode) {
XX (*term.t_putchar)('\033');
XX (*term.t_putchar)('[');
XX (*term.t_putchar)('7');
XX (*term.t_putchar)('m');
XX }
XX
XX while (cp1 != cp5) /* Ordinary. */
XX {
XX (*term.t_putchar)(*cp1);
XX ++ttcol;
XX *cp2++ = *cp1++;
XX }
XX
XX if (cp5 != cp3) /* Erase. */
XX {
XX (*term.t_eeol)();
XX while (cp1 != cp3) *cp2++ = *cp1++;
XX }
XX
XX if (ismode) {
XX (*term.t_putchar)('\033');
XX (*term.t_putchar)('[');
XX (*term.t_putchar)('0');
XX (*term.t_putchar)('m');
XX }
XX
XX }
XX
XX/*
XX * Redisplay the mode line for the window pointed to by the "wp". This is the
XX * only routine that has any idea of how the modeline is formatted. You can
XX * change the modeline format by hacking at this routine. Called by "update"
XX * any time there is a dirty window. Also fixes up tabbing.
XX */
XXmodeline(wp)
XXWINDOW *wp;
XX {
XX register char *cp;
XX register int c;
XX register int n; /* cursor position count */
XX register BUFFER *bp;
XX register i; /* loop index */
XX register lchar; /* character to draw line in buffer with */
XX register firstm; /* is this the first mode? */
XX char tline[NLINE]; /* buffer for part of mode line */
XX
XX
XX n = wp->w_toprow+wp->w_ntrows; /* Location. */
XX
XX vscreen[n]->v_flag |= VFCHG|VFMOD; /* Redraw next time. */
XX
XX vtmove(n, 0); /* Seek to right line. */
XX bp = wp->w_bufp;
XX if (wp == curwp) { /* mark the current buffer */
XX lchar = '=';
XX if ((bp->b_mode & (MDCMOD|MDMMOD)) != 0) tab(FALSE,4);
XX else if ((bp->b_mode & MDLISP) != 0) tab(FALSE,2);
XX else tab(FALSE,0);
XX }
XX else
XX lchar = '-';
XX
XX vtputc(lchar);
XX
XX if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */
XX vtputc('*');
XX else vtputc(' ');
XX
XX n = 2;
XX
XX strcpy(tline, " uEMACS ("); /* Buffer name. */
XX
XX /* display the modes */
XX
XX firstm = TRUE;
XX for (i = 0; i < NUMMODES; i++) /* add in the mode flags */
XX if (wp->w_bufp->b_mode & (1 << i)) {
XX if (firstm != TRUE) strcat(tline, " ");
XX firstm = FALSE;
XX strcat(tline, modename[i]);
XX }
XX strcat(tline,") ");
XX
XX cp = &tline[0];
XX while ((c = *cp++) != 0) {
XX vtputc(c);
XX ++n;
XX }
XX
XX vtputc('-');
XX vtputc('-');
XX vtputc(' ');
XX n += 3;
XX cp = &bp->b_bname[0];
XX
XX while ((c = *cp++) != 0) {
XX vtputc(c);
XX ++n;
XX }
XX
XX vtputc(' ');
XX vtputc('-');
XX vtputc('-');
XX n += 3;
XX
XX if (bp->b_fname[0] != 0) /* File name. */
XX {
XX vtputc(' ');
XX ++n;
XX cp = "File: ";
XX
XX while ((c = *cp++) != 0) {
XX vtputc(c);
XX ++n;
XX }
XX
XX cp = &bp->b_fname[0];
XX
XX while ((c = *cp++) != 0) {
XX vtputc(c);
XX ++n;
XX }
XX
XX vtputc(' ');
XX ++n;
XX }
XX
XX#if WFDEBUG
XX vtputc(lchar);
XX vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : lchar);
XX vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : lchar);
XX vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : lchar);
XX vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : lchar);
XX vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : lchar);
XX n += 6;
XX#endif
XX
XX while (n < term.t_ncol) /* Pad to full width. */
XX {
XX vtputc('-');
XX ++n;
XX }
XX }
XX
XXupmode() /* update all the mode lines */
XX
XX {
XX register WINDOW *wp;
XX
XX wp = wheadp;
XX while (wp != NULL) {
XX wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX }
XX
XX/*
XX * Send a command to the terminal to move the hardware cursor to row "row"
XX * and column "col". The row and column arguments are origin 0. Optimize out
XX * random calls. Update "ttrow" and "ttcol".
XX */
XXmovecursor(row, col)
XX {
XX if (row!=ttrow || col!=ttcol) {
XX ttrow = row;
XX ttcol = col;
XX (*term.t_move)(row, col);
XX }
XX }
XX
XX/*
XX * Erase the message line. This is a special routine because the message line
XX * is not considered to be part of the virtual screen. It always works
XX * immediately; the terminal buffer is flushed via a call to the flusher.
XX */
XXmlerase()
XX {
XX int i;
XX
XX movecursor(term.t_nrow, 0);
XX if (eolexist == TRUE) (*term.t_eeol)();
XX else {
XX for (i == 0; i < term.t_ncol - 1; i++) (*term.t_putchar)(' ');
XX movecursor(term.t_nrow, 1); /* force the move! */
XX movecursor(term.t_nrow, 0);
XX }
XX (*term.t_flush)();
XX mpresf = FALSE;
XX }
XX
XX/*
XX * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
XX * ABORT. The ABORT status is returned if the user bumps out of the question
XX * with a ^G. Used any time a confirmation is required.
XX */
XX
XXmlyesno(prompt)
XX
XXchar *prompt;
XX
XX {
XX register int s;
XX int c; /* input character */
XX char buf[NPAT]; /* prompt to user */
XX
XX for (;;) {
XX /* build and prompt the user */
XX strcpy(buf, prompt);
XX strcat(buf, " [y/n]? ");
XX mlwrite(buf);
XX
XX /* get the responce */
XX c = getkey();
XX if (c & CTRL) c -= (CTRL|'@');
XX c &= 0x7F;
XX
XX if (c == BELL) /* Bail out! */
XX return(ABORT);
XX
XX
XX if (c=='y' || c=='Y') return(TRUE);
XX
XX if (c=='n' || c=='N') return(FALSE);
XX }
XX }
XX
XX/*
XX * Write a prompt into the message line, then read back a response. Keep
XX * track of the physical position of the cursor. If we are in a keyboard
XX * macro throw the prompt away, and return the remembered response. This
XX * lets macros run at full speed. The reply is always terminated by a carriage
XX * return. Handle erase, kill, and abort keys.
XX */
XX
XXmlreply(prompt, buf, nbuf)
XXchar *prompt;
XXchar *buf;
XX {
XX return(mlreplyt(prompt,buf,nbuf,'\n'));
XX }
XX
XX/* A more generalized prompt/reply function allowing the caller
XXto specify the proper terminator. If the terminator is not
XXa return ('\n') it will echo as "<NL>"
XX */
XXmlreplyt(prompt, buf, nbuf, eolchar)
XX
XXchar *prompt;
XXchar *buf;
XXchar eolchar;
XX
XX {
XX register int cpos;
XX register int i;
XX register int c;
XX int anytyped;
XX
XX cpos = 0;
XX
XX if (kbdmop != NULL) {
XX while ((c = *kbdmop++) != '\0') buf[cpos++] = c;
XX buf[cpos] = 0;
XX if (buf[0] == 0) return(FALSE);
XX return(TRUE);
XX }
XX
XX /* check to see if we are executing a command line */
XX if (clexec) {
XX nxtarg(buf);
XX return(TRUE);
XX }
XX
XX mlwrite(prompt);
XX
XX anytyped = FALSE;
XX for (;;) {
XX /* get a character from the user. if it is a <ret>, change it
XX to a <NL> */
XX c = getkey();
XX if (c & CTRL) c -= (CTRL|'@');
XX c &= 0x7F;
XX
XX if (c == '\r') c = '\n';
XX
XX if (c == eolchar) {
XX buf[cpos++] = 0;
XX
XX if (kbdmip != NULL) {
XX if (kbdmip+cpos > &kbdm[NKBDM-3]) {
XX ctrlg(FALSE, 0);
XX (*term.t_flush)();
XX return(ABORT);
XX }
XX for (i=0; i<cpos; ++i) *kbdmip++ = buf[i];
XX }
XX (*term.t_putchar)('\r');
XX ttcol = 0;
XX (*term.t_flush)();
XX return(anytyped);
XX }
XX else if (c == BELL) { /* Bell, abort */
XX (*term.t_putchar)('^');
XX (*term.t_putchar)('G');
XX ttcol += 2;
XX ctrlg(FALSE, 0);
XX (*term.t_flush)();
XX return(ABORT);
XX }
XX else if (c == 0x7F || c == 0x08) { /* rubout/erase */
XX if (cpos != 0) {
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)('\b');
XX --ttcol;
XX if (buf[--cpos] < 0x20) {
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)('\b');
XX --ttcol;
XX }
XX if (buf[cpos] == '\n') {
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)('\b');
XX --ttcol;
XX --ttcol;
XX }
XX (*term.t_flush)();
XX }
XX }
XX else if (c == 0x15) { /* C-U, kill */
XX while (cpos != 0) {
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)('\b');
XX --ttcol;
XX
XX if (buf[--cpos] < 0x20) {
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)('\b');
XX --ttcol;
XX }
XX }
XX (*term.t_flush)();
XX }
XX else {
XX if (cpos < nbuf-1) {
XX buf[cpos++] = c;
XX
XX if ((c < ' ') && (c != '\n')) {
XX (*term.t_putchar)('^');
XX ++ttcol;
XX c ^= 0x40;
XX }
XX
XX if (c != '\n') (*term.t_putchar)(c);
XX else { /* put out <NL> for <ret> */
XX (*term.t_putchar)('<');
XX (*term.t_putchar)('N');
XX (*term.t_putchar)('L');
XX (*term.t_putchar)('>');
XX ttcol += 3;
XX }
XX ++ttcol;
XX anytyped = TRUE;
XX (*term.t_flush)();
XX }
XX }
XX }
XX }
XX
XX/*
XX * Write a message into the message line. Keep track of the physical cursor
XX * position. A small class of printf like format items is handled. Assumes the
XX * stack grows down; this assumption is made by the "++" in the argument scan
XX * loop. Set the "message line" flag TRUE.
XX */
XX
XXmlwrite(fmt, arg)
XXchar *fmt;
XX {
XX register int c;
XX register char *ap;
XX
XX if (eolexist == FALSE) {
XX mlerase();
XX (*term.t_flush)();
XX }
XX
XX movecursor(term.t_nrow, 0);
XX ap = (char *) &arg;
XX while ((c = *fmt++) != 0) {
XX if (c != '%') {
XX (*term.t_putchar)(c);
XX ++ttcol;
XX }
XX else
XX {
XX c = *fmt++;
XX switch (c) {
XX case 'd':
XX mlputi(*(int *)ap, 10);
XX ap += sizeof(int);
XX break;
XX
XX case 'o':
XX mlputi(*(int *)ap, 8);
XX ap += sizeof(int);
XX break;
XX
XX case 'x':
XX mlputi(*(int *)ap, 16);
XX ap += sizeof(int);
XX break;
XX
XX case 'D':
XX mlputli(*(long *)ap, 10);
XX ap += sizeof(long);
XX break;
XX
XX case 's':
XX mlputs(*(char **)ap);
XX ap += sizeof(char *);
XX break;
XX
XX default:
XX (*term.t_putchar)(c);
XX ++ttcol;
XX }
XX }
XX }
XX if (eolexist == TRUE) (*term.t_eeol)();
XX (*term.t_flush)();
XX mpresf = TRUE;
XX }
XX
XX/*
XX * Write out a string. Update the physical cursor position. This assumes that
XX * the characters in the string all have width "1"; if this is not the case
XX * things will get screwed up a little.
XX */
XXmlputs(s)
XXchar *s;
XX {
XX register int c;
XX
XX while ((c = *s++) != 0) {
XX (*term.t_putchar)(c);
XX ++ttcol;
XX }
XX }
XX
XX/*
XX * Write out an integer, in the specified radix. Update the physical cursor
XX * position. This will not handle any negative numbers; maybe it should.
XX */
XXmlputi(i, r)
XX {
XX register int q;
XX static char hexdigits[] = "0123456789ABCDEF";
XX
XX if (i < 0) {
XX i = -i;
XX (*term.t_putchar)('-');
XX }
XX
XX q = i/r;
XX
XX if (q != 0) mlputi(q, r);
XX
XX (*term.t_putchar)(hexdigits[i%r]);
XX ++ttcol;
XX }
XX
XX/*
XX * do the same except as a long integer.
XX */
XXmlputli(l, r)
XXlong l;
XX {
XX register long q;
XX
XX if (l < 0) {
XX l = -l;
XX (*term.t_putchar)('-');
XX }
XX
XX q = l/r;
XX
XX if (q != 0) mlputli(q, r);
XX
XX (*term.t_putchar)((int)(l%r)+'0');
XX ++ttcol;
XX }
XX
XX/* get a command name from the command line. Command completion means
XXthat pressing a <SPACE> will attempt to complete an unfinished command
XXname if it is unique.
XX */
XX
XXint (*getcname())()
XX
XX {
XX register int cpos; /* current column on screen output */
XX register int i;
XX register int c;
XX register char *sp; /* pointer to string for output */
XX register NBIND *ffp; /* first ptr to entry in name binding table */
XX register NBIND *cffp; /* current ptr to entry in name binding table */
XX register NBIND *lffp; /* last ptr to entry in name binding table */
XX char buf[NSTRING]; /* buffer to hold tentative command name */
XX int (*fncmatch())();
XX
XX /* starting at the begining of the string buffer */
XX cpos = 0;
XX
XX /* if we are executing a keyboard macro, fill our buffer from there,
XX and attempt a straight match */
XX if (kbdmop != NULL && *kbdmop != ' ' && *kbdmop != '\t') {
XX while ((c = *kbdmop++) != '\0') buf[cpos++] = c;
XX
XX buf[cpos] = 0;
XX
XX /* return the result of a match */
XX return(fncmatch(&buf[0]));
XX }
XX
XX /* if we are executing a command line get the next arg and match it */
XX if (clexec) {
XX nxtarg(buf);
XX return(fncmatch(&buf[0]));
XX }
XX
XX /* build a name string from the keyboard */
XX while (TRUE) {
XX c = getkey();
XX if (c & CTRL) c -= (CTRL|'@');
XX c &= 0x7F;
XX
XX /* if we are at the end, just match it */
XX if (c == 0x0d) {
XX buf[cpos] = 0;
XX
XX /* save keyboard macro string if needed */
XX if (kbdtext(&buf[0]) == ABORT) return(NULL);
XX
XX /* and match it off */
XX return(fncmatch(&buf[0]));
XX
XX }
XX else if (c == 0x07) { /* Bell, abort */
XX (*term.t_putchar)('^');
XX (*term.t_putchar)('G');
XX ttcol += 2;
XX ctrlg(FALSE, 0);
XX (*term.t_flush)();
XX return(NULL);
XX
XX }
XX else if (c == 0x7F || c == 0x08) { /* rubout/erase */
XX if (cpos != 0) {
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)('\b');
XX --ttcol;
XX --cpos;
XX (*term.t_flush)();
XX }
XX
XX }
XX else if (c == 0x15) { /* C-U, kill */
XX while (cpos != 0) {
XX (*term.t_putchar)('\b');
XX (*term.t_putchar)(' ');
XX (*term.t_putchar)('\b');
XX --cpos;
XX --ttcol;
XX }
XX
XX (*term.t_flush)();
XX
XX }
XX else if (c == ' ') {
XX /* attempt a completion */
XX buf[cpos] = 0; /* terminate it for us */
XX ffp = &names[0]; /* scan for matches */
XX while (ffp->n_func != NULL) {
XX if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
XX /* a possible match! More than one? */
XX if ((ffp + 1)->n_func == NULL ||
XX (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
XX /* no...we match, print it */
XX sp = ffp->n_name + cpos;
XX while (*sp) (*term.t_putchar)(*sp++);
XX return(ffp->n_func);
XX }
XX else {
XX /* try for a partial match against the list */
XX
XX /* first scan down until we no longer match the
XX current input */
XX lffp = (ffp + 1);
XX while ((lffp+1)->n_func != NULL) {
XX if (strncmp(buf, (lffp+1)->n_name, strlen(buf))
XX != 0) break;
XX ++lffp;
XX }
XX
XX /* and now, attempt to partial complete the string,
XX char at a time */
XX while (TRUE) {
XX /* add the next char in */
XX buf[cpos] = ffp->n_name[cpos];
XX
XX /* scan through the candidates */
XX cffp = ffp + 1;
XX while (cffp <= lffp) {
XX if (cffp->n_name[cpos] != buf[cpos]) goto onward;
XX ++cffp;
XX }
XX
XX /* add the character */
XX (*term.t_putchar)(buf[cpos++]);
XX }
XX }
XX }
XX ++ffp;
XX }
XX
XX /* no match.....beep and onward */
XX (*term.t_beep)();
XX onward:;
XX }
XX else {
XX if (cpos < NSTRING-1 && c > ' ') {
XX buf[cpos++] = c;
XX (*term.t_putchar)(c);
XX }
XX
XX ++ttcol;
XX (*term.t_flush)();
XX }
XX }
XX }
XX
XXkbdtext(buf) /* add this text string to the current keyboard macro
XXdefinition */
XX
XXchar *buf; /* text to add to keyboard macro */
XX
XX {
XX /* if we are defining a keyboard macro, save it */
XX if (kbdmip != NULL) {
XX if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) {
XX ctrlg(FALSE, 0);
XX (*term.t_flush)();
XX return(ABORT);
XX }
XX
XX /* copy string in and null terminate it */
XX while (*buf) *kbdmip++ = *buf++;
XX *kbdmip++ = 0;
XX }
XX return(TRUE);
XX }
SHAR_EOF
if test 28840 -ne "`wc -c display.c`"
then
echo shar: error transmitting display.c '(should have been 28840 characters)'
fi
echo shar: extracting file.c
sed 's/^XX//' << \SHAR_EOF > file.c
XX/*
XX * The routines in this file
XX * handle the reading and writing of
XX * disk files. All of details about the
XX * reading and writing of the disk are
XX * in "fileio.c".
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if ULTRIX
XX#include <strings.h>
XX#endif
XX
XX#if AMIGA
XXextern char *strcat(),*strncat(),*strcpy(),*strncpy(),
XX *index(),*rindex();
XX#endif
XX
XX#if VMS
XX#define index(str,chr) strchr(str,chr)
XX#define rindex(str,chr) strrchr(str,chr)
XX#endif
XX
XX/*
XX * Read a file into the current
XX * buffer. This is really easy; all you do it
XX * find the name of the file, and call the standard
XX * "read a file into the current buffer" code.
XX * Bound to "C-X C-R".
XX */
XXfileread(f, n)
XX {
XX register int s;
XX char fname[NFILEN];
XX
XX if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE) return(s);
XX return(readin(fname, TRUE));
XX }
XX
XX/*
XX * Insert a file into the current
XX * buffer. This is really easy; all you do it
XX * find the name of the file, and call the standard
XX * "insert a file into the current buffer" code.
XX * Bound to "C-X C-I".
XX */
XXinsfile(f, n)
XX {
XX register int s;
XX char fname[NFILEN];
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE) return(s);
XX return(ifile(fname));
XX }
XX
XX/*
XX * Select a file for editing.
XX * Look around to see if you can find the
XX * fine in another buffer; if you can find it
XX * just switch to the buffer. If you cannot find
XX * the file, create a new buffer, read in the
XX * text, and switch to the new buffer.
XX * Bound to C-X C-F.
XX */
XXfilefind(f, n)
XX {
XX char fname[NFILEN]; /* file user wishes to find */
XX register int s; /* status return */
XX
XX if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE) return(s);
XX return(getfile(fname, TRUE));
XX }
XX
XXvisitfile(f, n) /* visit a file */
XX {
XX char fname[NFILEN]; /* file user wishes to find */
XX register int s; /* status return */
XX register WINDOW *wp; /* scan for windows that need updating */
XX
XX if ((s=mlreply("Visit file: ", fname, NFILEN)) != TRUE) return (s);
XX if ((wp = wpopup()) != NULL) {
XX curwp = wp;
XX curbp = wp->w_bufp;
XX }
XX
XX s = getfile(fname, FALSE);
XX if (s) { /* see if we succeed */
XX /* scan through and update mode lines of all windows */
XX wp = wheadp;
XX while (wp != NULL) {
XX wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX }
XX return(s);
XX }
XX
XXvisittag(f, n) /* visit a file (via a sorted tag file) */
XX {
XX FILE *fp;
XX char fname[NFILEN]; /* file that the user wishes to open */
XX char tname[40]; /* tag name to search for */
XX char sstr[128]; /* search string */
XX char istr[128],*ptr; /* input string */
XX register WINDOW *wp; /* scan for windows that need updating */
XX register LINE *dotp;
XX register int doto,i;
XX
XX /* save the current position */
XX dotp = curwp->w_dotp;
XX doto = curwp->w_doto;
XX
XX /* now get the name of the tag */
XX while (inword() == FALSE)
XX if (forwchar(FALSE,1) == FALSE) return(FALSE);
XX i = 0;
XX while (inword() == TRUE || lgetc(curwp->w_dotp,curwp->w_doto) == '-') {
XX tname[i++] = lgetc(curwp->w_dotp,curwp->w_doto);
XX if (forwchar(FALSE,1) == FALSE) return(FALSE);
XX }
XX tname[i] = '\000';
XX /* restore the buffer position */
XX curwp->w_dotp = dotp;
XX curwp->w_doto = doto;
XX if (i == 0) return(FALSE);
XX
XX /* now open the tags file */
XX if ((fp = fopen("tags","r")) == NULL) {
XX mlwrite("No tags file found");
XX return(FALSE);
XX }
XX
XX /* now search for the tag in the file */
XX fname[0] = '\000';
XX ptr = &istr[0];
XX while (fgets(ptr,127,fp) != NULL) {
XX if (*ptr == tname[0] && strncmp(ptr,tname,i) == 0) {
XX ptr += i;
XX sscanf(ptr," %s %127c",fname,sstr);
XX break;
XX }
XX }
XX fclose(fp);
XX if (fname[0] == '\000') {
XX mlwrite("Tag not found in tag file");
XX return(FALSE);
XX }
XX
XX /* put the window up */
XX if ((wp = wpopup()) != NULL) {
XX curwp = wp;
XX curbp = wp->w_bufp;
XX }
XX
XX /* read the file in */
XX if (! getfile(fname, FALSE)) return(FALSE);
XX
XX /* scan through and update mode lines of all windows */
XX wp = wheadp;
XX while (wp != NULL) {
XX wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX
XX /* get rid of delimeters */
XX ptr = sstr + strlen(sstr);
XX while (ptr != sstr && *ptr != '/') ptr--;
XX if (*ptr == '/') *ptr = '\000';
XX while ((ptr = index(sstr,'*')) != NULL) *ptr = '.';
XX while ((ptr = index(sstr,'+')) != NULL) *ptr = '.';
XX while ((ptr = index(sstr,'[')) != NULL) *ptr = '.';
XX while ((ptr = index(sstr,']')) != NULL) *ptr = '.';
XX if ((ptr=index(sstr,'/')) != NULL) ptr++;
XX else ptr = sstr;
XX
XX /* do the scan (leave pointer at beginning of string) */
XX strcpy(pat,ptr);
XX gotobob(FALSE,1);
XX compile_bcode();
XX return(dosearch(TRUE,1,FALSE));
XX }
XX
XXgetfile(fname, lockfl)
XX
XXchar fname[]; /* file name to find */
XXint lockfl; /* check the file for locks? */
XX
XX {
XX register BUFFER *bp;
XX register WINDOW *wp;
XX register LINE *lp;
XX register int i;
XX register int s;
XX char bname[NBUFN]; /* buffer name to put file */
XX
XX for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
XX if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) {
XX swbuffer(bp);
XX lp = curwp->w_dotp;
XX i = curwp->w_ntrows/2;
XX while (i-- && lback(lp)!=curbp->b_linep) lp = lback(lp);
XX curwp->w_linep = lp;
XX curwp->w_flag |= WFMODE|WFHARD;
XX mlwrite("[Old buffer]");
XX return (TRUE);
XX }
XX }
XX makename(bname, fname); /* New buffer name. */
XX while ((bp=bfind(bname, FALSE, 0)) != NULL) {
XX s = mlreply("Buffer name: ", bname, NBUFN);
XX if (s == ABORT) /* ^G to just quit */
XX return (s);
XX if (s == FALSE) { /* CR to clobber it */
XX makename(bname, fname);
XX break;
XX }
XX }
XX if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
XX mlwrite("Cannot create buffer");
XX return (FALSE);
XX }
XX if (--curbp->b_nwnd == 0) { /* Undisplay. */
XX curbp->b_dotp = curwp->w_dotp;
XX curbp->b_doto = curwp->w_doto;
XX curbp->b_markp = curwp->w_markp;
XX curbp->b_marko = curwp->w_marko;
XX }
XX curbp = bp; /* Switch to it. */
XX curwp->w_bufp = bp;
XX curbp->b_nwnd++;
XX return(readin(fname, lockfl)); /* Read it in. */
XX }
XX
XX/*
XX * Read file "fname" into the current
XX * buffer, blowing away any text found there. Called
XX * by both the read and find commands. Return the final
XX * status of the read. Also called by the mainline,
XX * to read in a file specified on the command line as
XX * an argument. If the filename ends in a ".c", CMODE is
XX * set for the current buffer.
XX */
XXreadin(fname, lockfl)
XX
XXchar fname[]; /* name of file to read */
XXint lockfl; /* check for file locks? */
XX
XX {
XX register LINE *lp1;
XX register LINE *lp2;
XX register int i;
XX register WINDOW *wp;
XX register BUFFER *bp;
XX register int s;
XX register int nbytes;
XX register int nline;
XX register char *sptr; /* pointer into filename string */
XX int lflag; /* any lines longer than allowed? */
XX char line[NLINE];
XX
XX#if FILOCK
XX if (lockfl && lockchk(fname) == ABORT) return(ABORT);
XX#endif
XX bp = curbp; /* Cheap. */
XX if ((s=bclear(bp)) != TRUE) /* Might be old. */
XX return (s);
XX bp->b_flag &= ~(BFTEMP|BFCHG);
XX bp->b_mode |= MDEXACT; /*default to exact */
XX if (slowterm) bp->b_mode |= MDSLOW;
XX
XX sptr = fname + strlen(fname) - 4;
XX if (strlen(fname) > 1 &&
XX *(sptr+2) == '.' &&
XX *(sptr+3) == 'c' || *(sptr+3) == 'h') {
XX tab(FALSE,4);
XX bp->b_mode |= MDCMOD;
XX }
XX else if (strlen(fname) > 3 &&
XX (*sptr=='.' && *(sptr+1)=='m' && *(sptr+2)=='o' && *(sptr+3)=='d')
XX || (*sptr=='.' && *(sptr+1)=='d' && *(sptr+2)=='e' && *(sptr+3)=='f')
XX || (*sptr=='.' && *(sptr+1)=='m' && *(sptr+2)=='m' && *(sptr+3)=='4')
XX || (*(sptr+1)=='.' && *(sptr+2)=='m' && *(sptr+3)=='4')) {
XX tab(FALSE,4);
XX bp->b_mode |= MDMMOD;
XX }
XX else if (strlen(fname) > 3 &&
XX (*sptr=='.' && *(sptr+1)=='l' && *(sptr+2)=='s' && *(sptr+3)=='p')
XX || (*(sptr+2)=='.' && *(sptr+3)=='l')
XX || (*(sptr+1)=='.' && *(sptr+2)=='e' && *(sptr+3)=='l')
XX || (*(sptr+1)=='.' && *(sptr+2)=='e' && *(sptr+3)=='m')) {
XX tab(FALSE,2);
XX bp->b_mode |= MDLISP;
XX }
XX else {
XX tab(FALSE,0);
XX bp->b_mode |= MDWRAP;
XX }
XX
XX strcpy(bp->b_fname, fname);
XX if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
XX goto out;
XX if (s == FIOFNF) { /* File not found. */
XX mlwrite("[New file]");
XX goto out;
XX }
XX mlwrite("[Reading file]");
XX nline = 0;
XX lflag = FALSE;
XX while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) {
XX if (s == FIOLNG) lflag = TRUE;
XX nbytes = strlen(line);
XX if ((lp1=lalloc(nbytes)) == NULL) {
XX s = FIOERR; /* Keep message on the */
XX break; /* display. */
XX }
XX lp2 = lback(curbp->b_linep);
XX lp2->l_fp = lp1;
XX lp1->l_fp = curbp->b_linep;
XX lp1->l_bp = lp2;
XX curbp->b_linep->l_bp = lp1;
XX for (i=0; i<nbytes; ++i) lputc(lp1, i, line[i]);
XX ++nline;
XX }
XX ffclose(); /* Ignore errors. */
XX if (s == FIOEOF) { /* Don't zap message! */
XX if (nline == 1)
XX mlwrite("[Read 1 line]");
XX else
XX mlwrite("[Read %d lines]", nline);
XX }
XX if (lflag) mlwrite("[Read %d line(s), Long lines wrapped]",nline);
XX out:
XX for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
XX if (wp->w_bufp == curbp) {
XX wp->w_linep = lforw(curbp->b_linep);
XX wp->w_dotp = lforw(curbp->b_linep);
XX wp->w_doto = 0;
XX wp->w_markp = NULL;
XX wp->w_marko = 0;
XX wp->w_flag |= WFMODE|WFHARD;
XX }
XX }
XX if (s == FIOERR || s == FIOFNF) /* False if error. */
XX return(FALSE);
XX return (TRUE);
XX }
XX
XX/*
XX * Take a file name, and from it
XX * fabricate a buffer name. This routine knows
XX * about the syntax of file names on the target system.
XX * I suppose that this information could be put in
XX * a better place than a line of code.
XX */
XXmakename(bname, fname)
XXchar bname[];
XXchar fname[];
XX {
XX register char *cp1;
XX register char *cp2;
XX
XX cp1 = &fname[0];
XX while (*cp1 != 0) ++cp1;
XX
XX#if AMIGA
XX while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/') --cp1;
XX#endif
XX#if VMS
XX while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']') --cp1;
XX#endif
XX#if ULTRIX
XX while (cp1!=&fname[0] && cp1[-1]!='/') --cp1;
XX#endif
XX cp2 = &bname[0];
XX while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';') *cp2++ = *cp1++;
XX *cp2 = 0;
XX }
XX
XX/*
XX * Ask for a file name, and write the
XX * contents of the current buffer to that file.
XX * Update the remembered file name and clear the
XX * buffer changed flag. This handling of file names
XX * is different from the earlier versions, and
XX * is more compatable with Gosling EMACS than
XX * with ITS EMACS. Bound to "C-X C-W".
XX */
XXfilewrite(f, n)
XX {
XX register WINDOW *wp;
XX register int s;
XX char fname[NFILEN];
XX
XX if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE) return (s);
XX if ((s=writeout(fname)) == TRUE) {
XX strcpy(curbp->b_fname, fname);
XX curbp->b_flag &= ~BFCHG;
XX wp = wheadp; /* Update mode lines. */
XX while (wp != NULL) {
XX if (wp->w_bufp == curbp) wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX }
XX return (s);
XX }
XX
XX/*
XX * Save the contents of the current
XX * buffer in its associatd file. No nothing
XX * if nothing has changed (this may be a bug, not a
XX * feature). Error if there is no remembered file
XX * name for the buffer. Bound to "C-X C-S". May
XX * get called by "C-Z".
XX */
XXfilesave(f, n)
XX {
XX register WINDOW *wp;
XX register int s;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */
XX return (TRUE);
XX if (curbp->b_fname[0] == 0) { /* Must have a name. */
XX mlwrite("No file name");
XX return (FALSE);
XX }
XX if ((s=writeout(curbp->b_fname)) == TRUE) {
XX curbp->b_flag &= ~BFCHG;
XX wp = wheadp; /* Update mode lines. */
XX while (wp != NULL) {
XX if (wp->w_bufp == curbp) wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX }
XX return (s);
XX }
XX
XX/*
XX * This function performs the details of file
XX * writing. Uses the file management routines in the
XX * "fileio.c" package. The number of lines written is
XX * displayed. Sadly, it looks inside a LINE; provide
XX * a macro for this. Most of the grief is error
XX * checking of some sort.
XX */
XXwriteout(fn)
XXchar *fn;
XX {
XX register int s;
XX register LINE *lp;
XX register int nline;
XX
XX if ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */
XX return (FALSE);
XX mlwrite("[Writing..]"); /* tell us were writing */
XX lp = lforw(curbp->b_linep); /* First line. */
XX nline = 0; /* Number of lines. */
XX while (lp != curbp->b_linep) {
XX if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC) break;
XX ++nline;
XX lp = lforw(lp);
XX }
XX if (s == FIOSUC) { /* No write error. */
XX s = ffclose();
XX if (s == FIOSUC) { /* No close error. */
XX if (nline == 1)
XX mlwrite("[Wrote 1 line]");
XX else
XX mlwrite("[Wrote %d lines]", nline);
XX }
XX }
XX else /* Ignore close error */
XX ffclose(); /* if a write error. */
XX if (s != FIOSUC) /* Some sort of error. */
XX return (FALSE);
XX return (TRUE);
XX }
XX
XX/*
XX * The command allows the user
XX * to modify the file name associated with
XX * the current buffer. It is like the "f" command
XX * in UNIX "ed". The operation is simple; just zap
XX * the name in the BUFFER structure, and mark the windows
XX * as needing an update. You can type a blank line at the
XX * prompt if you wish.
XX */
XXfilename(f, n)
XX {
XX register WINDOW *wp;
XX register int s;
XX char fname[NFILEN];
XX
XX if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT) return (s);
XX if (s == FALSE) strcpy(curbp->b_fname, "");
XX else
XX strcpy(curbp->b_fname, fname);
XX wp = wheadp; /* Update mode lines. */
XX while (wp != NULL) {
XX if (wp->w_bufp == curbp) wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX curbp->b_mode &= ~MDVIEW; /* no longer read only mode */
XX return (TRUE);
XX }
XX
XX/*
XX * Insert file "fname" into the current
XX * buffer, Called by insert file command. Return the final
XX * status of the read.
XX */
XXifile(fname)
XXchar fname[];
XX {
XX register LINE *lp0;
XX register LINE *lp1;
XX register LINE *lp2;
XX register int i;
XX register WINDOW *wp;
XX register BUFFER *bp;
XX register int s;
XX register int nbytes;
XX register int nline;
XX int lflag; /* any lines longer than allowed? */
XX char line[NLINE];
XX
XX bp = curbp; /* Cheap. */
XX bp->b_flag |= BFCHG; /* we have changed */
XX bp->b_flag &= ~BFTEMP; /* and are not temporary*/
XX if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
XX goto out;
XX if (s == FIOFNF) { /* File not found. */
XX mlwrite("[No such file]");
XX return(FALSE);
XX }
XX mlwrite("[Inserting file]");
XX
XX /* back up a line and save the mark here */
XX curwp->w_dotp = lback(curwp->w_dotp);
XX curwp->w_doto = 0;
XX curwp->w_markp = curwp->w_dotp;
XX curwp->w_marko = 0;
XX
XX nline = 0;
XX lflag = FALSE;
XX while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) {
XX if (s == FIOLNG) lflag = TRUE;
XX nbytes = strlen(line);
XX if ((lp1=lalloc(nbytes)) == NULL) {
XX s = FIOERR; /* Keep message on the */
XX break; /* display. */
XX }
XX lp0 = curwp->w_dotp; /* line previous to insert */
XX lp2 = lp0->l_fp; /* line after insert */
XX
XX /* re-link new line between lp0 and lp2 */
XX lp2->l_bp = lp1;
XX lp0->l_fp = lp1;
XX lp1->l_bp = lp0;
XX lp1->l_fp = lp2;
XX
XX /* and advance and write out the current line */
XX curwp->w_dotp = lp1;
XX for (i=0; i<nbytes; ++i) lputc(lp1, i, line[i]);
XX ++nline;
XX }
XX ffclose(); /* Ignore errors. */
XX curwp->w_markp = lforw(curwp->w_markp);
XX if (s == FIOEOF) { /* Don't zap message! */
XX if (nline == 1)
XX mlwrite("[Inserted 1 line]");
XX else
XX mlwrite("[Inserted %d lines]", nline);
XX }
XX if (lflag) mlwrite("[Inserted %d line(s), Long lines wrapped]",nline);
XX out:
XX /* advance to the next line and mark the window for changes */
XX curwp->w_dotp = lforw(curwp->w_dotp);
XX curwp->w_flag |= WFHARD;
XX
XX /* copy window parameters back to the buffer structure */
XX curbp->b_dotp = curwp->w_dotp;
XX curbp->b_doto = curwp->w_doto;
XX curbp->b_markp = curwp->w_markp;
XX curbp->b_marko = curwp->w_marko;
XX
XX if (s == FIOERR) /* False if error. */
XX return (FALSE);
XX return (TRUE);
XX }
XX
SHAR_EOF
if test 16669 -ne "`wc -c file.c`"
then
echo shar: error transmitting file.c '(should have been 16669 characters)'
fi
# End of shell archive
exit 0wecker@cookie.dec.com.UUCP (02/21/87)
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# region.c
# search.c
# spawn.c
# tcap.c
# termio.c
# vmsvt.c
# window.c
# word.c
# This archive created: Fri Feb 20 17:44:37 1987
echo shar: extracting region.c
sed 's/^XX//' << \SHAR_EOF > region.c
XX/*
XX * The routines in this file
XX * deal with the region, that magic space
XX * between "." and mark. Some functions are
XX * commands. Some functions are just for
XX * internal use.
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX/*
XX * Kill the region. Ask "getregion"
XX * to figure out the bounds of the region.
XX * Move "." to the start, and kill the characters.
XX * Bound to "C-W".
XX */
XXkillregion(f, n)
XX {
XX register int s;
XX REGION region;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if ((s=getregion(®ion)) != TRUE) return (s);
XX if ((lastflag&CFKILL) == 0) /* This is a kill type */
XX kdelete(); /* command, so do magic */
XX thisflag |= CFKILL; /* kill buffer stuff. */
XX curwp->w_dotp = region.r_linep;
XX curwp->w_doto = region.r_offset;
XX return (ldelete(region.r_size, TRUE));
XX }
XX
XX/*
XX * Copy all of the characters in the
XX * region to the kill buffer. Don't move dot
XX * at all. This is a bit like a kill region followed
XX * by a yank. Bound to "M-W".
XX */
XXcopyregion(f, n)
XX {
XX register LINE *linep;
XX register int loffs;
XX register int s;
XX REGION region;
XX
XX if ((s=getregion(®ion)) != TRUE) return (s);
XX if ((lastflag&CFKILL) == 0) /* Kill type command. */
XX kdelete();
XX thisflag |= CFKILL;
XX linep = region.r_linep; /* Current line. */
XX loffs = region.r_offset; /* Current offset. */
XX while (region.r_size--) {
XX if (loffs == llength(linep)) { /* End of line. */
XX if ((s=kinsert('\n')) != TRUE)
XX return (s);
XX linep = lforw(linep);
XX loffs = 0;
XX }
XX else { /* Middle of line. */
XX if ((s=kinsert(lgetc(linep, loffs))) != TRUE) return (s);
XX ++loffs;
XX }
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Lower case region. Zap all of the upper
XX * case characters in the region to lower case. Use
XX * the region code to set the limits. Scan the buffer,
XX * doing the changes. Call "lchange" to ensure that
XX * redisplay is done in all buffers. Bound to
XX * "C-X C-L".
XX */
XXlowerregion(f, n)
XX {
XX register LINE *linep;
XX register int loffs;
XX register int c;
XX register int s;
XX REGION region;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if ((s=getregion(®ion)) != TRUE) return (s);
XX lchange(WFHARD);
XX linep = region.r_linep;
XX loffs = region.r_offset;
XX while (region.r_size--) {
XX if (loffs == llength(linep)) {
XX linep = lforw(linep);
XX loffs = 0;
XX }
XX else {
XX c = lgetc(linep, loffs);
XX if (c>='A' && c<='Z') lputc(linep, loffs, c+'a'-'A');
XX ++loffs;
XX }
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Upper case region. Zap all of the lower
XX * case characters in the region to upper case. Use
XX * the region code to set the limits. Scan the buffer,
XX * doing the changes. Call "lchange" to ensure that
XX * redisplay is done in all buffers. Bound to
XX * "C-X C-L".
XX */
XXupperregion(f, n)
XX {
XX register LINE *linep;
XX register int loffs;
XX register int c;
XX register int s;
XX REGION region;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if ((s=getregion(®ion)) != TRUE) return (s);
XX lchange(WFHARD);
XX linep = region.r_linep;
XX loffs = region.r_offset;
XX while (region.r_size--) {
XX if (loffs == llength(linep)) {
XX linep = lforw(linep);
XX loffs = 0;
XX }
XX else {
XX c = lgetc(linep, loffs);
XX if (c>='a' && c<='z') lputc(linep, loffs, c-'a'+'A');
XX ++loffs;
XX }
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * This routine figures out the
XX * bounds of the region in the current window, and
XX * fills in the fields of the "REGION" structure pointed
XX * to by "rp". Because the dot and mark are usually very
XX * close together, we scan outward from dot looking for
XX * mark. This should save time. Return a standard code.
XX * Callers of this routine should be prepared to get
XX * an "ABORT" status; we might make this have the
XX * conform thing later.
XX */
XXgetregion(rp)
XXregister REGION *rp;
XX {
XX register LINE *flp;
XX register LINE *blp;
XX register int fsize;
XX register int bsize;
XX
XX if (curwp->w_markp == NULL) {
XX mlwrite("No mark set in this window");
XX return (FALSE);
XX }
XX if (curwp->w_dotp == curwp->w_markp) {
XX rp->r_linep = curwp->w_dotp;
XX if (curwp->w_doto < curwp->w_marko) {
XX rp->r_offset = curwp->w_doto;
XX rp->r_size = curwp->w_marko-curwp->w_doto;
XX }
XX else {
XX rp->r_offset = curwp->w_marko;
XX rp->r_size = curwp->w_doto-curwp->w_marko;
XX }
XX return (TRUE);
XX }
XX blp = curwp->w_dotp;
XX bsize = curwp->w_doto;
XX flp = curwp->w_dotp;
XX fsize = llength(flp)-curwp->w_doto+1;
XX while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
XX if (flp != curbp->b_linep) {
XX flp = lforw(flp);
XX if (flp == curwp->w_markp) {
XX rp->r_linep = curwp->w_dotp;
XX rp->r_offset = curwp->w_doto;
XX rp->r_size = fsize + curwp->w_marko;
XX return (TRUE);
XX }
XX fsize += llength(flp)+1;
XX }
XX if (lback(blp) != curbp->b_linep) {
XX blp = lback(blp);
XX bsize += llength(blp)+1;
XX if (blp == curwp->w_markp) {
XX rp->r_linep = blp;
XX rp->r_offset = curwp->w_marko;
XX rp->r_size = bsize - curwp->w_marko;
XX return (TRUE);
XX }
XX }
XX }
XX mlwrite("Bug: lost mark");
XX return (FALSE);
XX }
XX
SHAR_EOF
if test 5463 -ne "`wc -c region.c`"
then
echo shar: error transmitting region.c '(should have been 5463 characters)'
fi
echo shar: extracting search.c
sed 's/^XX//' << \SHAR_EOF > search.c
XX/*
XX * The functions in this file implement commands that search in the forward
XX * and backward directions with regular expressions.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if ULTRIX
XX#include <sys/types.h>
XX#include <sys/timeb.h>
XX#define FLASHTIME 200
XX#endif
XX
XX#if VMS
XX#include <types.h>
XX#include <timeb.h>
XX#define FLASHTIME 400
XX#endif
XX
XX/* string search input parameters */
XX
XX#define PTBEG 1 /* leave the point at the begining on search */
XX#define PTEND 2 /* leave the point at the end on search */
XX
XX/* byte codes for matching */
XX#define M_NULL 0 /* no op code */
XX#define M_BEGIN 1 /* begin a sub expression */
XX#define M_END 2 /* end a sub expression */
XX#define M_BOL 3 /* match BOL */
XX#define M_EOL 4 /* match EOL */
XX#define M_CHR 5 /* match a range of characters */
XX#define M_ANY 6 /* match any chars inside of brackets */
XX#define M_NONE 7 /* don't match any chars inside of brackets */
XX#define M_DOT 8 /* match one of any character */
XX
XX#define R_NONE 0 /* never try to match */
XX#define R_ONCE 1 /* match once */
XX#define R_ZERO 2 /* match zero or more times */
XX#define R_MANY 3 /* match at least once (and maybe more) */
XX
XXstruct { /* byte code control for pattern */
XX unsigned char
XX code, /* M_ code */
XX pos1, /* pointer into pat */
XX pos2, /* pointer into par */
XX rpt; /* R_ repeat type */
XX }
XXbcode[100];
XX
XX
XXchar substr[10][128]; /* successful substring matches */
XXchar outstr[128]; /* scratch output buffer */
XXint inexact; /* are we doing inexact matches? */
XX
XXcompile_bcode() {
XX short pptr, /* pattern pointer */
XX bptr, /* byte code pointer */
XX mptr, /* match pointer */
XX i,j,k; /* scratch loop counters */
XX
XX bptr = 0; mptr = 0;
XX bcode[bptr].code = M_BEGIN;
XX bcode[bptr].pos1 = mptr++;
XX bcode[bptr++].rpt = R_ONCE;
XX
XX for (pptr = 0; pat[pptr] != 0; pptr++) {
XX bcode[bptr].code = M_NULL;
XX bcode[bptr].pos1 = 0;
XX bcode[bptr].pos2 = 0;
XX bcode[bptr].rpt = R_ONCE;
XX switch (pat[pptr]) {
XX case '^':
XX if (pptr != 0) goto dochr;
XX bcode[bptr++].code = M_BOL;
XX break;
XX
XX case '$':
XX if (pat[pptr+1] != 0) goto dochr;
XX bcode[bptr++].code = M_EOL;
XX break;
XX
XX case '\\':
XX if (pat[++pptr] != '(' && pat[pptr] != ')') goto dochr;
XX if (pat[pptr] == '(') {
XX bcode[bptr].code = M_BEGIN;
XX bcode[bptr++].pos1 = mptr++;
XX }
XX else {
XX j = 1;
XX for (i = bptr-1 ; i >= 0 ; i--) {
XX if (bcode[i].code == M_END) j++;
XX else if (bcode[i].code == M_BEGIN && --j == 0) break;
XX }
XX if (j != 0) {
XX mlwrite("Bad matching of \( and \) in pattern");
XX return(FALSE);
XX }
XX if (pat[pptr+1] == '*') {bcode[i].rpt = R_ZERO; pptr++;}
XX else if (pat[pptr+1] == '+') {bcode[i].rpt = R_MANY; pptr++;}
XX bcode[bptr].code = M_END;
XX bcode[bptr].pos1 = bcode[i].pos1;
XX bcode[bptr].pos2 = i;
XX bcode[bptr].rpt = bcode[i].rpt;
XX bcode[i].pos2 = bptr++;
XX }
XX break;
XX
XX case '[':
XX if (pat[pptr+1] == '^') {bcode[bptr].code = M_NONE; pptr++;}
XX else bcode[bptr].code = M_ANY;
XX if (pat[++pptr] == ']') {
XX mlwrite("Cannot specify null []");
XX return(FALSE);
XX }
XX bcode[bptr].pos1 = pptr;
XX while (pat[++pptr] != ']' && pat[pptr] != 0) {
XX if (pat[pptr] == '\\') ++pptr;
XX }
XX if (pat[pptr] == 0) {
XX mlwrite("No closing ] found");
XX return(FALSE);
XX }
XX bcode[bptr].pos2 = pptr - 1;
XX if (pat[pptr+1] == '*') {bcode[bptr].rpt = R_ZERO; pptr++;}
XX else if (pat[pptr+1] == '+') {bcode[bptr].rpt = R_MANY; pptr++;}
XX bptr++;
XX break;
XX
XX case '.':
XX bcode[bptr].code = M_DOT;
XX if (pat[pptr+1] == '*') {bcode[bptr].rpt = R_ZERO; pptr++;}
XX else if (pat[pptr+1] == '+') {bcode[bptr].rpt = R_MANY; pptr++;}
XX bptr++;
XX break;
XX
XX default:
XX dochr:
XX bcode[bptr].code = M_CHR;
XX bcode[bptr].pos1 = pptr;
XX while ( pat[pptr+1] != 0 &&
XX pat[pptr+1] != '\\' &&
XX pat[pptr+1] != '*' &&
XX pat[pptr+1] != '+' &&
XX pat[pptr+1] != '[' &&
XX pat[pptr+1] != '.' &&
XX pat[pptr+1] != '$' ) pptr++;
XX if (pat[pptr+1] == '*' || pat[pptr+1] == '+') {
XX
XX if (bcode[bptr].pos1 == pptr) {
XX bcode[bptr].pos2 = pptr;
XX
XX if (pat[++pptr] == '*') bcode[bptr].rpt = R_ZERO;
XX else bcode[bptr].rpt = R_MANY;
XX }
XX else bcode[bptr].pos2 = --pptr;
XX }
XX else bcode[bptr].pos2 = pptr;
XX bptr++;
XX break;
XX }
XX }
XX bcode[bptr].code = M_END;
XX bcode[bptr].pos1 = bcode[0].pos1;
XX bcode[bptr].pos2 = 0;
XX bcode[bptr].rpt = bcode[0].rpt;
XX bcode[0].pos2 = bptr++;
XX
XX return(TRUE);
XX }
XX
XXmatch(lp,so,eo)
XXLINE *lp;
XXint so,*eo;
XX {
XX short i;
XX
XX switch(bcode[1].code) {
XX case M_BOL:
XX if (so != 0) return(FALSE);
XX break;
XX
XX case M_CHR:
XX if (!eq(lgetc(lp,so),pat[bcode[1].pos1])) return(FALSE);
XX break;
XX }
XX
XX for (i = 0; i < 10; i++) substr[i][0] = '\000';
XX return(do_begin(0,lp,so,eo));
XX }
XX
XXdo_begin(bptr,lp,so,eo)
XXLINE *lp;
XXint bptr,so,*eo;
XX {
XX short i,j,mptr,rpt,start,retval,prevo,curro,keepgoing,nxtcod;
XX int nexto,scro;
XX
XX start = bptr; prevo = so; curro = so;
XX rpt = bcode[start].rpt;
XX if (rpt == R_ZERO) retval = TRUE; else retval = FALSE;
XX
XX while (TRUE) {
XX switch (bcode[++bptr].code) {
XX case M_BEGIN:
XX if (!do_begin(bptr,lp,curro,&nexto)) {*eo = prevo; return(retval);}
XX bptr = bcode[bptr].pos2;
XX prevo = curro;
XX curro = nexto;
XX break;
XX
XX case M_END:
XX mptr = bcode[start].pos1;
XX j = strlen(substr[mptr]);
XX for (i = so; i < curro; i++) {
XX substr[mptr][j++] = lgetc(lp,i);
XX }
XX substr[mptr][j] = 0;
XX if (rpt == R_ONCE) {*eo = curro; return(TRUE); }
XX retval = TRUE;
XX bptr = start;
XX prevo = curro;
XX break;
XX
XX case M_BOL:
XX if (curro != 0) { *eo = prevo; return(retval); }
XX break;
XX
XX case M_EOL:
XX if (curro < llength(lp)) { *eo = prevo; return(retval); }
XX break;
XX
XX case M_DOT:
XX if (curro >= llength(lp)) {
XX if (bcode[bptr].rpt == R_ZERO) {curro = llength(lp); break;}
XX *eo = prevo;
XX return(retval);
XX }
XX if (bcode[bptr].rpt == R_ONCE) nexto = curro + 1;
XX else {
XX if (bcode[bptr].rpt == R_MANY) nexto = curro+1;
XX else nexto = curro;
XX keepgoing = TRUE;
XX i = 1;
XX while (bptr+i < bcode[0].pos2 &&
XX bcode[bptr+i].code == M_END) i++;
XX while (nexto < llength(lp) && keepgoing) {
XX switch (bcode[bptr+i].code) {
XX case M_BEGIN:
XX if (do_begin(bptr+i,lp,nexto,&scro)) keepgoing = FALSE;
XX break;
XX
XX case M_EOL:
XX case M_END:
XX nexto = llength(lp);
XX keepgoing = FALSE;
XX break;
XX
XX case M_DOT:
XX keepgoing = FALSE;
XX break;
XX
XX case M_CHR:
XX if (do_chr(bptr+i,lp,nexto,&scro)) keepgoing = FALSE;
XX break;
XX
XX case M_ANY:
XX if (do_any(bptr+i,lp,nexto,&scro,TRUE)) keepgoing = FALSE;
XX break;
XX
XX case M_NONE:
XX if (do_any(bptr+i,lp,nexto,&scro,FALSE)) keepgoing = FALSE;
XX break;
XX
XX default:
XX break;
XX }
XX if (keepgoing) nexto++;
XX }
XX }
XX prevo = curro;
XX curro = nexto;
XX break;
XX
XX case M_CHR:
XX if (!do_chr(bptr,lp,curro,&nexto)) {*eo = prevo; return(retval); }
XX prevo = curro;
XX curro = nexto;
XX break;
XX
XX case M_ANY:
XX if (!do_any(bptr,lp,curro,&nexto,TRUE)) {
XX *eo = prevo;
XX return(retval);
XX }
XX prevo = curro;
XX curro = nexto;
XX break;
XX
XX case M_NONE:
XX if (!do_any(bptr,lp,curro,&nexto,FALSE)) {
XX *eo = prevo;
XX return(retval);
XX }
XX prevo = curro;
XX curro = nexto;
XX break;
XX }
XX }
XX }
XX
XXdo_chr(bptr,lp,so,eo)
XXLINE *lp;
XXint bptr,so,*eo;
XX {
XX short rpt,curro,prevo,retval,i;
XX
XX rpt = bcode[bptr].rpt; prevo = so; curro = so;
XX if (rpt == R_ZERO) retval = TRUE; else retval = FALSE;
XX
XX while (TRUE) {
XX for (i = bcode[bptr].pos1 ; i <= bcode[bptr].pos2 ; i++) {
XX if (curro >= llength(lp) || !eq(lgetc(lp,curro++),pat[i])) {*eo = prevo; return(retval);}
XX }
XX if (rpt == R_ONCE) {*eo = curro; return(TRUE); }
XX retval = TRUE;
XX prevo = curro;
XX }
XX }
XX
XXdo_any(bptr,lp,so,eo,DOANY)
XXLINE *lp;
XXint bptr,so,*eo,DOANY;
XX {
XX char c1,c2,c3;
XX short rpt,curro,prevo,retval,i;
XX
XX rpt = bcode[bptr].rpt; prevo = so; curro = so;
XX if (rpt == R_ZERO) retval = TRUE; else retval = FALSE;
XX
XX while (TRUE) {
XX if (curro >= llength(lp)) {*eo = llength(lp); return(retval); }
XX c3 = lgetc(lp,curro++);
XX if (inexact && c3 >= 'a' && c3 <= 'z') c3 -= 0x20;
XX
XX for (i = bcode[bptr].pos1; i <= bcode[bptr].pos2; i++) {
XX if (pat[i] == '\\') c1 = pat[++i]; else c1 = pat[i];
XX c2 = c1;
XX if (pat[i+1] == '-' && pat[i+2] != 0) {
XX i += 2;
XX if (pat[i] == '\\') c2 = pat[++i]; else c2 = pat[i];
XX }
XX if (inexact) {
XX if (c1 >= 'a' && c1 <= 'z') c1 -= 0x20;
XX if (c2 >= 'a' && c2 <= 'z') c2 -= 0x20;
XX }
XX if (c3 >= c1 && c3 <= c2) {
XX if (rpt == R_ONCE) {*eo = curro; return(DOANY); }
XX if (DOANY) {prevo = curro; retval = TRUE; break; }
XX *eo = prevo; return(retval);
XX }
XX }
XX if (DOANY) {
XX if (i > bcode[bptr].pos2) {
XX *eo = prevo;
XX return(retval);
XX }
XX }
XX else {
XX if (rpt == R_ONCE) {*eo = curro; return(TRUE); }
XX prevo = curro;
XX retval = TRUE;
XX }
XX }
XX }
XX
XXforwsearch(f, n)
XX {
XX register int status;
XX
XX /* resolve the repeat count */
XX if (n == 0) n = 1;
XX if (n < 1) return(backsearch(f, -n));
XX
XX /* ask the user for the text of a pattern */
XX if ((status = readpattern(pat,"Search",'\006')) != TRUE) return(status);
XX
XX /* search for the pattern */
XX while (n-- > 0) {
XX if ((status = dosearch(TRUE,PTEND,TRUE)) == FALSE) break;
XX }
XX if (status == FALSE) mlwrite("Not found"); else mlerase();
XX return(status);
XX }
XX
XXbacksearch(f, n)
XX {
XX register int status;
XX
XX /* resolve the repeat count */
XX if (n == 0) n = 1;
XX if (n < 1) return(forwsearch(f, -n));
XX
XX /* ask the user for the text of a pattern */
XX if ((status = readpattern(pat,"Reverse Search",'\022')) != TRUE) return(status);
XX
XX /* search for the pattern */
XX while (n-- > 0) {
XX if ((status = dosearch(FALSE,PTBEG,TRUE)) == FALSE) break;
XX }
XX if (status == FALSE) mlwrite("Not found"); else mlerase();
XX return(status);
XX }
XX
XXdosearch(forward,where,interactive)
XX {
XX register LINE *clp;
XX register int cbo,i,j;
XX LINE *slp;
XX int tbo,sbo,doslow;
XX
XX if ((curwp->w_bufp->b_mode & MDEXACT) == 0) inexact = TRUE;
XX else inexact = FALSE;
XX
XX /* make local copies of the starting location */
XX clp = curwp->w_dotp;
XX cbo = curwp->w_doto;
XX if (curwp->w_bufp->b_mode & MDSLOW) doslow = TRUE; else doslow = FALSE;
XX slp = clp;
XX sbo = cbo;
XX
XX for (;;) {
XX if (!forward) cbo--;
XX /* if we are at the begining of the line, wrap back around */
XX if (cbo < 0) {
XX clp = lback(clp);
XX if (clp == curbp->b_linep) {
XX mlwrite("Not found");
XX return (FALSE);
XX }
XX cbo = llength(clp);
XX }
XX if (cbo > llength(clp)) {
XX clp = lforw(clp);
XX
XX if (clp == curbp->b_linep) {
XX mlwrite("Not found");
XX return (FALSE);
XX }
XX cbo = 0;
XX }
XX if (match(clp,cbo,&tbo)) {
XX /* A Match! reset the current cursor */
XX if (interactive && doslow) {
XX j = 0;
XX for (i = 0; i <= llength(clp); i++) {
XX if (i == cbo || i == tbo) {
XX outstr[j++] = '\033';
XX outstr[j++] = '[';
XX if (i == cbo && i != tbo) outstr[j++] = '7';
XX outstr[j++] = 'm';
XX }
XX if (i < llength(clp)) outstr[j++] = lgetc(clp,i);
XX }
XX outstr[j] = 0;
XX mlerase(); mlputs(outstr); update(); mpresf = TRUE;
XX switch (getkey()) {
XX case CTRL|'F':
XX forward = TRUE;
XX where = PTEND;
XX break;
XX
XX case CTRL|'R':
XX forward = FALSE;
XX where = PTBEG;
XX break;
XX
XX case CTRL|'G':
XX return(FALSE);
XX
XX default:
XX mlerase();
XX goto movecursor;
XX }
XX }
XX else {
XX
XX movecursor:
XX curwp->w_dotp = clp;
XX if (where == PTBEG) curwp->w_doto = cbo;
XX else curwp->w_doto = tbo;
XX curwp->w_flag |= WFMOVE;
XX break;
XX }
XX }
XX if (forward) cbo++;
XX }
XX return(TRUE);
XX }
XX
XX/*
XX * Compare two characters. The "bc" comes from the buffer. It has it's case
XX * folded out. The "pc" is from the pattern.
XX */
XXeq(bc, pc)
XXint bc;
XXint pc;
XX {
XX if (inexact) {
XX if (bc>='a' && bc<='z') bc -= 0x20;
XX if (pc>='a' && pc<='z') pc -= 0x20;
XX }
XX if (bc == pc) return (TRUE);
XX return (FALSE);
XX }
XX
XX/*
XX * Read a pattern. Stash it in the external variable "pat". The "pat" is not
XX * updated if the user types in an empty line. If the user typed an empty line,
XX * and there is no old pattern, it is an error. Display the old pattern, in the
XX * style of Jeff Lomicka. There is some do-it-yourself control expansion.
XX * change to using supplied char to delemit the end-of-pattern.
XX */
XXreadpattern(result,prompt,c)
XXchar *result,*prompt,c;
XX {
XX register int s;
XX char tpat[NPAT+20],c1[2];
XX
XX strcpy(tpat, prompt); /* copy prompt to output string */
XX strcat(tpat, " {"); /* build new prompt string */
XX expandp(&result[0], &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
XX strcat(tpat, "} [");
XX c1[0] = c; c1[1] = 0;
XX expandp(&c1[0], &tpat[strlen(tpat)], NPAT/2);
XX strcat(tpat,"]: ");
XX
XX s = mlreplyt(tpat, tpat, NPAT, c); /* Read pattern */
XX
XX if (s == TRUE) { /* Specified */
XX strcpy(result, tpat);
XX if (result == pat) compile_bcode(); /* compile it */
XX }
XX else if (s == FALSE && result[0] != 0) /* CR, but old one */
XX s = TRUE;
XX
XX return (s);
XX }
XX
XXsreplace(f, n) /* Search and replace (ESC-R) */
XXint f; /* default flag */
XXint n; /* # of repetitions wanted */
XX {
XX return(replaces(FALSE, f, n));
XX }
XX
XXqreplace(f, n) /* search and replace with query (ESC-CTRL-R) */
XXint f; /* default flag */
XXint n; /* # of repetitions wanted */
XX
XX {
XX return(replaces(TRUE, f, n));
XX }
XX
XX/* replaces: search for a string and replace it with another
XX string. query might be enabled (according to kind). */
XX
XXreplaces(kind, f, n)
XXint kind; /* Query enabled flag */
XXint f; /* default flag */
XXint n; /* # of repetitions wanted */
XX {
XX int s; /* success flag on pattern inputs */
XX int numsub; /* number of substitutions */
XX int nummatch; /* number of found matches */
XX int i,j; /* loop index */
XX char tmpc; /* temporary character */
XX int c; /* input char for query */
XX char tpat[NPAT]; /* temporary to hold search pattern */
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX
XX /* check for negative repititions */
XX if (f && n < 0) return(FALSE);
XX
XX /* ask the user for the text of a pattern */
XX if ((s = readpattern(pat, (kind == FALSE ? "Replace" : "Query replace"),'\006')) != TRUE)
XX return(s);
XX
XX /* ask for the replacement string */
XX if ((s = readpattern(rpat,"with",'\006')) == ABORT) return(s);
XX
XX /* build query replace question string */
XX strcpy(tpat, "Replace? ");
XX
XX /* save original . position */
XX setmark(TRUE,0);
XX
XX /* scan through the file */
XX numsub = 0;
XX nummatch = 0;
XX
XX if ((curwp->w_bufp->b_mode & MDEXACT) == 0) inexact = TRUE;
XX else inexact = FALSE;
XX
XX while (f == FALSE || n > nummatch) {
XX
XX /* search for the pattern */
XX if (dosearch(TRUE,PTBEG,FALSE) != TRUE) break; /* all done */
XX ++nummatch; /* increment # of matches */
XX
XX /* check for query */
XX if (kind) {
XX /* get the query */
XX mlerase(); mlputs(&tpat[0]);
XX qprompt:
XX update(); /* show the proposed place to change */
XX c = getkey(); /* and input */
XX mlerase(""); /* and clear it */
XX
XX /* and respond appropriately */
XX switch (c) {
XX case 'Y':
XX case 'y': /* yes, substitute */
XX case ' ':
XX break;
XX
XX case 'N':
XX case 'n': /* no, onword */
XX forwchar(FALSE, 1);
XX continue;
XX
XX case '!': /* yes/stop asking */
XX kind = FALSE;
XX break;
XX
XX case '.': /* abort! and return */
XX /* restore old position */
XX swapmark(FALSE,1);
XX
XX case CTRL|'G': /* abort! and stay */
XX mlwrite("Aborted!");
XX return(FALSE);
XX
XX default: /* bitch and beep */
XX (*term.t_beep)();
XX
XX case '?': /* help me */
XX case SPEC|'Q':
XX mlwrite("(Y)es, (N)o, (!)Do the rest, (^G)Abort, (.)Abort back, (?)Help: ");
XX goto qprompt;
XX }
XX }
XX
XX /* delete the sucker */
XX if (ldelete(strlen(substr[0]), FALSE) != TRUE) {
XX /* error while deleting */
XX mlwrite("ERROR while deleteing");
XX return(FALSE);
XX }
XX
XX /* and insert its replacement */
XX for (i=0; i<strlen(rpat); i++) {
XX tmpc = rpat[i];
XX if (tmpc == '\\' && rpat[i+1] >= '0' && rpat[i+1] <= '9') {
XX tmpc = rpat[++i] - 0x30;
XX for (j = 0; j<strlen(substr[tmpc]); j++) {
XX if (linsert(1,substr[tmpc][j]) != TRUE) {
XX mlwrite("Out of memory while inserting");
XX return(FALSE);
XX }
XX }
XX }
XX else {
XX s = (tmpc == '\n' ? lnewline() : linsert(1, tmpc));
XX if (s != TRUE) {
XX mlwrite("Out of memory while inserting");
XX return(FALSE);
XX }
XX }
XX }
XX
XX numsub++; /* increment # of substitutions */
XX }
XX
XX /* and report the results */
XX mlwrite("%d susbstitutions",numsub);
XX return(TRUE);
XX }
XX
XX/* expandp: expand control key sequences for output */
XX
XXexpandp(srcstr, deststr, maxlength)
XXchar *srcstr; /* string to expand */
XXchar *deststr; /* destination of expanded string */
XXint maxlength; /* maximum chars in destination */
XX {
XX char c; /* current char to translate */
XX
XX /* scan through the string */
XX while ((c = *srcstr++) != 0) {
XX if (c == '\n') { /* its an EOL */
XX *deststr++ = '<';
XX *deststr++ = 'N';
XX *deststr++ = 'L';
XX *deststr++ = '>';
XX maxlength -= 4;
XX }
XX
XX else if (c < 0x20 || c == 0x7f) { /* control character */
XX *deststr++ = '^';
XX *deststr++ = c ^ 0x40;
XX maxlength -= 2;
XX }
XX
XX else { /* any other character */
XX *deststr++ = c;
XX maxlength--;
XX }
XX if (maxlength < 4) {
XX *deststr++ = '$';
XX *deststr = '\0';
XX return(FALSE);
XX }
XX }
XX *deststr = '\0';
XX return(TRUE);
XX }
XX
XXflash(cchr)
XXchar cchr;
XX {
XX register LINE *clp;
XX register int cbo;
XX LINE *oldp;
XX int oldo,count,i,j,inwindow;
XX char c,ochr;
XX
XX#if AMIGA == 0
XX struct timeb tp;
XX time_t t1;
XX unsigned short t2;
XX#endif
XX
XX update();
XX switch (cchr) {
XX case ')': ochr = '('; break;
XX case '}': ochr = '{'; break;
XX case ']': ochr = '['; break;
XX case '>': ochr = '<'; break;
XX default: return(FALSE);
XX }
XX
XX clp = curwp->w_dotp; oldp = clp;
XX cbo = curwp->w_doto; oldo = cbo;
XX count = 0; inwindow = TRUE;
XX
XX while(TRUE) {
XX while (--cbo < 0) {
XX if (ochr == '<' || ochr == '[') return(TRUE);
XX if (clp == curwp->w_linep) inwindow = FALSE;
XX clp = lback(clp);
XX if (clp == curbp->b_linep) {
XX mlwrite("No matching paren found");
XX return(FALSE);
XX }
XX cbo = llength(clp);
XX }
XX c = lgetc(clp,cbo);
XX if (c == ochr && --count < 0) {
XX mlwrite("No matching paren found");
XX return(FALSE);
XX }
XX else if (c == cchr) ++count;
XX if (count == 0) {
XX if (inwindow) {
XX curwp->w_dotp = clp;
XX curwp->w_doto = cbo;
XX update();
XX#if AMIGA
XX Delay(10L);
XX#else
XX ftime(&tp.time);
XX t1 = tp.time;
XX t2 = tp.millitm + FLASHTIME;
XX if (t2 > 1000) {
XX t1++;
XX t2 -= 1000;
XX }
XX while (1) {
XX ftime(&tp.time);
XX if (tp.time > t1 ||
XX (tp.time == t1 && tp.millitm >= t2)) break;
XX }
XX#endif
XX curwp->w_dotp = oldp;
XX curwp->w_doto = oldo;
XX update();
XX return(TRUE);
XX }
XX for (i = 0; i < llength(clp); i++) outstr[i] = lgetc(clp,i);
XX outstr[i] = 0;
XX mlerase(); mlputs(outstr); update(); mpresf = TRUE;
XX return(TRUE);
XX }
XX }
XX }
XX
SHAR_EOF
if test 19273 -ne "`wc -c search.c`"
then
echo shar: error transmitting search.c '(should have been 19273 characters)'
fi
echo shar: extracting spawn.c
sed 's/^XX//' << \SHAR_EOF > spawn.c
XX/*
XX * The routines in this file are called to create a subjob running a command
XX * interpreter. This code is a big fat nothing on CP/M-86. You lose.
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if AMIGA
XX#define NEW 1006
XX#endif
XX
XX#if VMS
XX#define EFN 0 /* Event flag. */
XX
XX#include <ssdef.h> /* Random headers. */
XX#include <stsdef.h>
XX#include <descrip.h>
XX#include <iodef.h>
XX
XXextern int oldmode[2]; /* In "termio.c" */
XXextern int newmode[2]; /* In "termio.c" */
XXextern short iochan; /* In "termio.c" */
XX#endif
XX
XX#if ULTRIX
XX#include <signal.h>
XX#include <fcntl.h>
XX#include <sys/types.h>
XX#include <sys/stat.h>
XX#include <sys/file.h>
XX
XX#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
XX#define IOC_VOID 0x20000000 /* no parameters */
XX#define IOC_OUT 0x40000000 /* copy out parameters */
XX#define IOC_IN 0x80000000 /* copy in parameters */
XX#define _IO(x,y) (IOC_VOID|('x'<<8)|y)
XX#define _IOR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
XX#define _IOW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
XX#define FIONREAD _IOR(f, 127, int) /* get # bytes to read */
XX#define TIOCSPGRP _IOW(t, 118, int) /* set pgrp of tty */
XX#define TIOCNOTTY _IO(t, 113) /* void tty association */
XX
XXextern int vttidy();
XX
XX/* Open an available pty, putting descriptor in *ptyv,
XX and return the file name of the pty. Return 0 if none available. */
XX
XXchar ptyname[24];
XX
XXchar *pty(ptyv)
XXint *ptyv;
XX {
XX struct stat stb;
XX register c, i;
XX
XX for (c = 'p'; c <= 'z'; c++) {
XX for (i = 0; i < 16; i++) {
XX sprintf (ptyname, "/dev/pty%c%x", c, i);
XX if (stat (ptyname, &stb) < 0) continue;
XX
XX *ptyv = open (ptyname, O_RDWR | O_NDELAY, 0);
XX if (*ptyv >= 0) {
XX /* check to make certain that both sides are available
XX this avoids a nasty yet stupid bug in rlogins */
XX int x;
XX sprintf (ptyname, "/dev/tty%c%x", c, i);
XX x = open (ptyname, O_RDWR | O_NDELAY, 0);
XX if (x < 0) {close (*ptyv); continue; }
XX close(x);
XX return ptyname;
XX }
XX }
XX }
XX return(NULL);
XX }
XX
XX/*
XX * Create a sub process in a window (only under ULTRIX)
XX */
XX
XXcreate_process()
XX {
XX int sv[2],forkin,forkout;
XX WINDOW *wp;
XX char *ptyname;
XX
XX /* get us a window/buffer to work in */
XX if ((wp = wpopup()) != NULL) {
XX curwp = wp;
XX curbp = wp->w_bufp;
XX }
XX if (procbuf != NULL) {
XX mlwrite("*SHELL* already exists!!");
XX return(FALSE);
XX }
XX if ((procbuf=bfind("*SHELL*",TRUE,0)) == NULL) return(FALSE);
XX if (swbuffer(procbuf) == FALSE) return(FALSE);
XX
XX /* now create the process */
XX ptyname = pty(&inchannel);
XX outchannel = inchannel;
XX if (ptyname) {
XX forkout = forkin = open(ptyname, O_RDWR, 0);
XX if (forkin < 0) return(FALSE);
XX }
XX else {
XX pipe (sv);
XX inchannel = sv[0];
XX forkout = sv[1];
XX pipe (sv);
XX outchannel = sv[1];
XX forkin = sv[0];
XX }
XX pid = vfork();
XX if (pid == 0) {
XX if (ptyname) {
XX int j = open("/dev/tty",O_RDWR,0);
XX ioctl(j,TIOCNOTTY,0);
XX close(j);
XX }
XX pid = getpid();
XX close(0);
XX close(1);
XX close(2);
XX dup2(forkin,0);
XX dup2(forkout,1);
XX dup2(forkout,2);
XX setpgrp(pid,pid);
XX ioctl(0, TIOCSPGRP, &pid);
XX execl("/bin/csh","uemacs-sub-shell","-is",NULL);
XX }
XX close(forkin);
XX if (forkin != forkout) close(forkout);
XX return(TRUE);
XX }
XX
XX/* wait for subprocess data (or a key to be pressed) */
XX
XXreadsubproc() {
XX extern dotoplevel();
XX char *bptr,buf[4096];
XX int i,j,n,c,flags;
XX BUFFER *bp;
XX
XX flags = fcntl(0,F_GETFL,0);
XX fcntl(0,F_SETFL,flags|FASYNC);
XX while (TRUE) {
XX /* see if the process has any data */
XX bptr = &buf[0];
XX signal(SIGIO,dotoplevel);
XX i = read(inchannel,bptr,sizeof(buf));
XX signal(SIGIO,SIG_DFL);
XX if (i < 1 || procbuf == NULL) {
XX procbuf = NULL;
XX fcntl(0,F_SETFL,flags);
XX return;
XX }
XX bp = curbp;
XX if (bp != procbuf) swbuffer(procbuf);
XX if (curwp->w_dotp != curbp->b_linep) gotoeob(TRUE,0);
XX while (i-- > 0) {
XX c = *bptr++ & 0x7F;
XX if (c != 0x0A) linsert(1,c); else lnewline();
XX }
XX setmark(TRUE,0);
XX if (bp != procbuf) swbuffer(bp);
XX update();
XX }
XX }
XX
XX/* insert a line (or region) to a sub shell */
XXpinsert() {
XX register LINE *linep;
XX register int loffs;
XX register int clen,s;
XX REGION region;
XX
XX /* get the region to send */
XX if (curwp->w_markp == NULL) {
XX region.r_linep = linep = curwp->w_dotp;
XX region.r_offset = loffs = 0;
XX region.r_size = llength(linep);
XX while (loffs < llength(linep) && loffs < 20) {
XX if (lgetc(linep,loffs) == '%' || lgetc(linep,loffs) == '#') {
XX region.r_offset += ++loffs;
XX region.r_size -= loffs;
XX break;
XX }
XX ++loffs;
XX }
XX }
XX else getregion(®ion);
XX
XX linep = region.r_linep;
XX loffs = region.r_offset;
XX while (region.r_size--) {
XX if (loffs == llength(linep)) {
XX if (write(outchannel,"\n",1) == -1) {
XX mlwrite("Write to subprocess failed!!");
XX procbuf = NULL;
XX return(FALSE);
XX }
XX linep = lforw(linep);
XX loffs = 0;
XX }
XX else {
XX if (write(outchannel,&linep->l_text[loffs],1) == -1) {
XX mlwrite("Write to subprocess failed!!");
XX procbuf = NULL;
XX return(FALSE);
XX }
XX loffs++;
XX }
XX }
XX lnewline();
XX if (write(outchannel,"\n",1) == -1) {
XX mlwrite("Write to subprocess failed!!");
XX procbuf = NULL;
XX return(FALSE);
XX }
XX gotoeob(TRUE,0);
XX setmark(TRUE,0);
XX return(TRUE);
XX }
XX
XX/* send a quoted character to the sub shell */
XXshellquote(f, n)
XX {
XX int c;
XX
XX if (procbuf == NULL) {
XX mlwrite("No process to talk to!!");
XX return(FALSE);
XX }
XX
XX /* get the character to quote */
XX c = getkey();
XX if (c & CTRL) c -= (CTRL|'@');
XX c &= 0x7F;
XX
XX if (write(outchannel,&c,1) == -1) {
XX mlwrite("Write to subprocess failed!!");
XX procbuf = NULL;
XX return(FALSE);
XX }
XX return(TRUE);
XX }
XX
XX#endif
XX
XX/*
XX * Create a subjob with a copy of the command intrepreter in it. When the
XX * command interpreter exits, mark the screen as garbage so that you do a full
XX * repaint. Bound to "C-C". The message at the start in VMS puts out a newline.
XX * Under some (unknown) condition, you don't get one free when DCL starts up.
XX */
XXspawncli(f, n)
XX {
XX#if AMIGA
XX long newcli;
XX
XX newcli = (long)Open("CON:1/1/639/199/MicroEmacs Subprocess",(long)NEW);
XX mlwrite("[Starting new CLI]");
XX sgarbf = TRUE;
XX Execute("", (long)newcli, 0L);
XX Close((long)newcli);
XX return(TRUE);
XX#endif
XX
XX#if ULTRIX
XX register char *cp;
XX char *getenv();
XX#endif
XX#if VMS
XX register int s;
XX movecursor(term.t_nrow, 0); /* In last line. */
XX mlputs("[Starting DCL]\r\n");
XX (*term.t_flush)(); /* Ignore "ttcol". */
XX s = sys(NULL); /* NULL => DCL. */
XX mlputs("\r\n\n[End]"); /* Pause. */
XX (*term.t_flush)();
XX do {
XX s = getkey();
XX if (s & CTRL) s -= (CTRL|'@');
XX s &= 0x7F;
XX } while (s != ' ' && s != 'y' && s != '\r' && s != '\n');/* Pause. */
XX sgarbf = TRUE;
XX return(TRUE);
XX#endif
XX#if ULTRIX
XX return(create_process());
XX#endif
XX }
XX
XX#if ULTRIX
XX
XXbktoshell() /* suspend MicroEMACS and wait to wake up */
XX {
XX int pid;
XX
XX vttidy();
XX pid = getpid();
XX kill(pid,SIGTSTP);
XX }
XX
XXrtfrmshell()
XX {
XX ttopen();
XX curwp->w_flag = WFHARD;
XX refresh();
XX }
XX#endif
XX
XX/*
XX * Run a one-liner in a subjob. When the command returns, wait for a single
XX * character to be typed, then mark the screen as garbage so a full repaint is
XX * done. Bound to "C-X !".
XX */
XXspawn(f, n)
XX {
XX register int s;
XX char line[NLINE];
XX#if AMIGA
XX long newcli;
XX
XX if ((s=mlreply("CLI command: ", line, NLINE)) != TRUE) return (s);
XX newcli = (long)Open("CON:1/1/639/199/MicroEmacs Subprocess",(long)NEW);
XX Execute(line,0L,(long)newcli);
XX Close((long)newcli);
XX#endif
XX#if VMS
XX if ((s=mlreply("DCL command: ", line, NLINE)) != TRUE) return (s);
XX (*term.t_putchar)('\n'); /* Already have '\r' */
XX
XX (*term.t_flush)();
XX s = sys(line); /* Run the command. */
XX mlputs("\r\n\n[End]"); /* Pause. */
XX#endif
XX#if ULTRIX
XX if ((s=mlreply("! ", line, NLINE)) != TRUE) return (s);
XX (*term.t_putchar)('\n'); /* Already have '\r' */
XX (*term.t_flush)();
XX ttclose(); /* stty to old modes */
XX system(line);
XX sleep(2);
XX ttopen();
XX mlputs("[End]"); /* Pause. */
XX#endif
XX (*term.t_flush)();
XX do {
XX s = getkey();
XX if (s & CTRL) s -= (CTRL|'@');
XX s &= 0x7F;
XX } while (s != ' ' && s != 'y' && s != '\r' && s != '\n');/* Pause. */
XX sgarbf = TRUE;
XX return(TRUE);
XX }
XX
XX#if VMS
XX/*
XX * Run a command. The "cmd" is a pointer to a command string, or NULL if you
XX * want to run a copy of DCL in the subjob (this is how the standard routine
XX * LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in
XX * and the way out, because DCL does not want the channel to be in raw mode.
XX */
XXsys(cmd)
XXregister char *cmd;
XX {
XX struct dsc$descriptor cdsc;
XX struct dsc$descriptor *cdscp;
XX long status;
XX long substatus;
XX long iosb[2];
XX
XX status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX oldmode, sizeof(oldmode), 0, 0, 0, 0);
XX if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) return (FALSE);
XX cdscp = NULL; /* Assume DCL. */
XX if (cmd != NULL) { /* Build descriptor. */
XX cdsc.dsc$a_pointer = cmd;
XX cdsc.dsc$w_length = strlen(cmd);
XX cdsc.dsc$b_dtype = DSC$K_DTYPE_T;
XX cdsc.dsc$b_class = DSC$K_CLASS_S;
XX cdscp = &cdsc;
XX }
XX status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
XX if (status != SS$_NORMAL) substatus = status;
XX status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX newmode, sizeof(newmode), 0, 0, 0, 0);
XX if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) return (FALSE);
XX if ((substatus&STS$M_SUCCESS) == 0) /* Command failed. */
XX return (FALSE);
XX return (TRUE);
XX }
XX#endif
SHAR_EOF
if test 9843 -ne "`wc -c spawn.c`"
then
echo shar: error transmitting spawn.c '(should have been 9843 characters)'
fi
echo shar: extracting tcap.c
sed 's/^XX//' << \SHAR_EOF > tcap.c
XX/* tcap: Unix V5, V7 and BS4.2 Termcap video driver
XX * for MicroEMACS */
XX
XX#define termdef 1 /* don't define "term" external */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if TERMCAP
XX
XX#define NROW 24
XX#define NCOL 80
XX#define MARGIN 8
XX#define SCRSIZ 64
XX#define BEL 0x07
XX#define ESC 0x1B
XX
XXextern int ttopen();
XXextern int ttgetc();
XXextern int ttputc();
XXextern int ttflush();
XXextern int ttclose();
XXextern int tcapmove();
XXextern int tcapeeol();
XXextern int tcapeeop();
XXextern int tcapbeep();
XXextern int tcapopen();
XXextern int tcapinsert();
XXextern int tcapdelete();
XXextern int tput();
XXextern char *tgoto();
XX
XX#define TCAPSLEN 315
XXchar tcapbuf[TCAPSLEN];
XXchar *UP, PC, *CM, *CE, *CL;
XX
XXTERM term = {
XX NROW-1,
XX NCOL,
XX MARGIN,
XX SCRSIZ,
XX tcapopen,
XX ttclose,
XX ttgetc,
XX ttputc,
XX ttflush,
XX tcapmove,
XX tcapeeol,
XX tcapeeop,
XX tcapbeep,
XX tcapinsert,
XX tcapdelete
XX };
XX
XXtcapopen()
XX
XX {
XX char *getenv();
XX char *t, *p, *tgetstr();
XX char tcbuf[1024];
XX char *tv_stype;
XX char err_str[72];
XX
XX int row,col;
XX
XX if (batchmode) return(TRUE);
XX
XX if ((tv_stype = getenv("TERM")) == NULL) {
XX puts("Environment variable TERM not defined!");
XX exit(1);
XX }
XX
XX if((tgetent(tcbuf, tv_stype)) != 1)
XX {
XX sprintf(err_str, "Unknown terminal type %s!", tv_stype);
XX puts(err_str);
XX exit(1);
XX }
XX
XX row = tgetnum("li") - 1;
XX if (row < 0) row = NROW - 1;
XX col = tgetnum("co");
XX if (col < 0) col = NCOL;
XX term.t_nrow = row;
XX term.t_ncol = col;
XX
XX p = tcapbuf;
XX t = tgetstr("pc", &p);
XX if(t)
XX PC = *t;
XX CL = tgetstr("cl", &p);
XX CM = tgetstr("cm", &p);
XX CE = tgetstr("ce", &p);
XX UP = tgetstr("up", &p);
XX
XX if(CL == NULL || CM == NULL || UP == NULL)
XX {
XX puts("Incomplete termcap entry\n");
XX exit(1);
XX }
XX
XX if (CE == NULL) /* will we be able to use clear to EOL? */
XX eolexist = FALSE;
XX
XX if (p >= &tcapbuf[TCAPSLEN]) {
XX puts("Terminal description too big!\n");
XX exit(1);
XX }
XX ttopen();
XX }
XX
XXtcapmove(row, col)
XXregister int row, col;
XX {
XX if (batchmode) return(TRUE);
XX putpad(tgoto(CM, col, row));
XX }
XX
XXtcapeeol()
XX {
XX if (batchmode) return(TRUE);
XX putpad(CE);
XX }
XX
XXtcapeeop()
XX {
XX if (batchmode) return(TRUE);
XX putpad(CL);
XX }
XX
XXtcapbeep()
XX {
XX if (batchmode) return(TRUE);
XX ttputc(BEL);
XX }
XX
XXtcapinsert(row,n)
XX {
XX char str[40];
XX
XX if (batchmode) return(TRUE);
XX sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,row+1);
XX putpad(str);
XX sprintf(str,"\033M");
XX while (n--) putpad(str);
XX putpad("\033[r");
XX mlerase();
XX }
XX
XXtcapdelete(row,n)
XX {
XX char str[40];
XX
XX if (batchmode) return(TRUE);
XX mlerase();
XX sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,term.t_nrow);
XX putpad(str);
XX sprintf(str,"\033D");
XX while (n--) putpad(str);
XX putpad("\033[r");
XX }
XX
XXputpad(str)
XXchar *str;
XX {
XX if (batchmode) return(TRUE);
XX tputs(str, 1, ttputc);
XX }
XX
XXputnpad(str, n)
XXchar *str;
XX {
XX if (batchmode) return(TRUE);
XX tputs(str, n, ttputc);
XX }
XX
XX#else
XX
XXhello()
XX {
XX }
XX
XX#endif TERMCAP
XX
SHAR_EOF
if test 3153 -ne "`wc -c tcap.c`"
then
echo shar: error transmitting tcap.c '(should have been 3153 characters)'
fi
echo shar: extracting termio.c
sed 's/^XX//' << \SHAR_EOF > termio.c
XX/*
XX * The functions in this file negotiate with the operating system for
XX * characters, and write characters in a barely buffered fashion on the display.
XX * All operating systems.
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if AMIGA
XXextern char *Open();
XXextern long Read(),Write();
XXextern void Close();
XX
XX#define NEW 1006L
XX#define AMG_MAXBUF 1024
XXstatic char *terminal = NULL;
XXstatic char scrn_tmp[AMG_MAXBUF+1];
XXstatic long scrn_tmp_p = 0;
XX#endif
XX
XX#if VMS
XX#include <stsdef.h>
XX#include <ssdef.h>
XX#include <descrip.h>
XX#include <iodef.h>
XX#include <ttdef.h>
XX
XX#define NIBUF 128 /* Input buffer size */
XX#define NOBUF 1024 /* MM says bug buffers win! */
XX#define EFN 0 /* Event flag */
XX
XXchar obuf[NOBUF]; /* Output buffer */
XXint nobuf; /* # of bytes in above */
XXchar ibuf[NIBUF]; /* Input buffer */
XXint nibuf; /* # of bytes in above */
XXint ibufi; /* Read index */
XXint oldmode[2]; /* Old TTY mode bits */
XXint newmode[2]; /* New TTY mode bits */
XXshort iochan; /* TTY I/O channel */
XX#endif
XX
XX#if ULTRIX
XX#undef CTRL
XX#include <sgtty.h> /* for stty/gtty functions */
XX#include <signal.h>
XXstruct sgttyb ostate; /* saved tty state */
XXstruct sgttyb nstate; /* values for editor mode */
XXstruct tchars otchars; /* Saved terminal special character set */
XXstruct tchars ntchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
XX/* A lot of nothing */
XX#if ULTRIX
XX#include <sys/ioctl.h> /* to get at the typeahead */
XXextern int rtfrmshell(); /* return from suspended shell */
XX#endif
XX#endif
XX/*
XX* This function is called once to set up the terminal device streams.
XX* On VMS, it translates TT until it finds the terminal, then assigns
XX* a channel to it and sets it raw. On CPM it is a no-op.
XX*/
XXttopen()
XX {
XX#if AMIGA
XX if (batchmode) return(TRUE);
XX terminal = Open("RAW:1/1/639/199/MicroEmacs",(long)NEW);
XX#endif
XX#if VMS
XX struct dsc$descriptor idsc;
XX struct dsc$descriptor odsc;
XX char oname[40];
XX int iosb[2];
XX int status;
XX
XX if (batchmode) return(TRUE);
XX odsc.dsc$a_pointer = "TT";
XX odsc.dsc$w_length = strlen(odsc.dsc$a_pointer);
XX odsc.dsc$b_dtype = DSC$K_DTYPE_T;
XX odsc.dsc$b_class = DSC$K_CLASS_S;
XX idsc.dsc$b_dtype = DSC$K_DTYPE_T;
XX idsc.dsc$b_class = DSC$K_CLASS_S;
XX do {
XX idsc.dsc$a_pointer = odsc.dsc$a_pointer;
XX idsc.dsc$w_length = odsc.dsc$w_length;
XX odsc.dsc$a_pointer = &oname[0];
XX odsc.dsc$w_length = sizeof(oname);
XX status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
XX if (status!=SS$_NORMAL && status!=SS$_NOTRAN) exit(status);
XX if (oname[0] == 0x1B) {
XX odsc.dsc$a_pointer += 4;
XX odsc.dsc$w_length -= 4;
XX }
XX }
XX while (status == SS$_NORMAL);
XX status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
XX if (status != SS$_NORMAL) exit(status);
XX status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
XX oldmode, sizeof(oldmode), 0, 0, 0, 0);
XX if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) exit(status);
XX term.t_nrow = ((oldmode[1] >> 24) & 0xFF) - 1;
XX newmode[0] = oldmode[0];
XX newmode[1] = oldmode[1] | TT$M_PASSALL | TT$M_NOECHO;
XX status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX newmode, sizeof(newmode), 0, 0, 0, 0);
XX if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) exit(status);
XX#endif
XX#if ULTRIX
XX if (batchmode) return(TRUE);
XX gtty(0, &ostate); /* save old state */
XX gtty(0, &nstate); /* get base of new state */
XX nstate.sg_flags |= RAW;
XX nstate.sg_flags &= ~(ECHO|CRMOD); /* no echo for now... */
XX stty(0, &nstate); /* set mode */
XX ioctl(0, TIOCGETC, &otchars); /* Save old characters */
XX ioctl(0, TIOCSETC, &ntchars); /* Place new character into K */
XX signal(SIGTSTP,SIG_DFL); /* set signals so that we can */
XX signal(SIGCONT,rtfrmshell); /* suspend & restart emacs */
XX#endif
XX }
XX/*
XX* This function gets called just before we go back home to the command
XX* interpreter. On VMS it puts the terminal back in a reasonable state.
XX* Another no-operation on CPM.
XX*/
XXttclose()
XX {
XX#if AMIGA
XX if (batchmode) return(TRUE);
XX amg_flush();
XX Close(terminal);
XX#endif
XX#if VMS
XX int status;
XX int iosb[1];
XX
XX if (batchmode) return(TRUE);
XX ttflush();
XX status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX oldmode, sizeof(oldmode), 0, 0, 0, 0);
XX if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) exit(status);
XX status = SYS$DASSGN(iochan);
XX if (status != SS$_NORMAL) exit(status);
XX#endif
XX#if ULTRIX
XX if (batchmode) return(TRUE);
XX stty(0, &ostate);
XX ioctl(0, TIOCSETC, &otchars); /* Place old character into K */
XX#endif
XX }
XX
XX/*
XX* Write a character to the display. On VMS, terminal output is buffered, and
XX* we just put the characters in the big array, after checking for overflow.
XX* On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
XX* MS-DOS (use the very very raw console output routine).
XX*/
XXttputc(c)
XX#if AMIGA
XXchar c;
XX#endif
XX {
XX if (batchmode) return(TRUE);
XX#if AMIGA
XX scrn_tmp[scrn_tmp_p++] = c;
XX if(scrn_tmp_p>=AMG_MAXBUF)
XX amg_flush();
XX#endif
XX#if VMS
XX if (nobuf >= NOBUF) ttflush();
XX obuf[nobuf++] = c;
XX#endif
XX
XX#if ULTRIX
XX fputc(c, stdout);
XX#endif
XX }
XX
XX#if AMIGA
XXamg_flush()
XX {
XX if (batchmode) return(TRUE);
XX if(scrn_tmp_p)
XX Write(terminal,scrn_tmp,(long)scrn_tmp_p);
XX scrn_tmp_p = 0;
XX }
XX#endif
XX/*
XX* Flush terminal buffer. Does real work where the terminal output is buffered
XX* up. A no-operation on systems where byte at a time terminal I/O is done.
XX*/
XXttflush()
XX {
XX#if AMIGA
XX if (batchmode) return(TRUE);
XX amg_flush();
XX#endif
XX#if VMS
XX int status;
XX int iosb[2];
XX if (batchmode) return(TRUE);
XX status = SS$_NORMAL;
XX if (nobuf != 0) {
XX status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
XX iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
XX if (status == SS$_NORMAL) status = iosb[0] & 0xFFFF;
XX nobuf = 0;
XX }
XX return (status);
XX#endif
XX#if ULTRIX
XX if (batchmode) return(TRUE);
XX fflush(stdout);
XX#endif
XX }
XX
XX/*
XX * Read a character from the terminal, performing no editing and doing no echo
XX * at all. More complex in VMS that almost anyplace else, which figures. Very
XX * simple on CPM, because the system can do exactly what you want.
XX */
XXttgetc()
XX {
XX#if AMIGA
XX unsigned char ch[2];
XX
XX if (batchmode) return(TRUE);
XX amg_flush();
XX Read(terminal, ch, 1L);
XX return (ch[0] & 0xFF);
XX#endif
XX#if VMS
XX int status;
XX int iosb[2];
XX int term[2];
XX
XX if (batchmode) return(TRUE);
XX while (ibufi >= nibuf) {
XX ibufi = 0;
XX term[0] = 0;
XX term[1] = 0;
XX status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
XX iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
XX if (status != SS$_NORMAL) exit(status);
XX status = iosb[0] & 0xFFFF;
XX if (status!=SS$_NORMAL && status!=SS$_TIMEOUT) exit(status);
XX nibuf = (iosb[0]>>16) + (iosb[1]>>16);
XX if (nibuf == 0) {
XX status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
XX iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
XX if (status != SS$_NORMAL || (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
XX exit(status);
XX nibuf = (iosb[0]>>16) + (iosb[1]>>16);
XX }
XX }
XX return (ibuf[ibufi++] & 0xFF); /* Allow multinational */
XX#endif
XX
XX#if ULTRIX
XX if (batchmode) return(TRUE);
XX return(127 & fgetc(stdin));
XX#endif
XX }
XX
XX#if TYPEAH
XX/* typahead: Check to see if any characters are already in the
XX keyboard buffer
XX */
XXtypahead()
XX
XX {
XX#if ULTRIX
XX int x; /* holds # of pending chars */
XX
XX if (batchmode) return(FALSE);
XX return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x);
XX#else
XX return(FALSE);
XX#endif
XX }
XX#endif
SHAR_EOF
if test 7495 -ne "`wc -c termio.c`"
then
echo shar: error transmitting termio.c '(should have been 7495 characters)'
fi
echo shar: extracting vmsvt.c
sed 's/^XX//' << \SHAR_EOF > vmsvt.c
XX/*
XX * VMS terminal handling routines
XX *
XX * Known types are:
XX * VT52, VT100, and UNKNOWN (which is defined to be an ADM3a)
XX * written by Curtis Smith
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if VMSVT
XX
XX#define termdef 1 /* don't define "term" external */
XX
XX#include <ssdef.h> /* Status code definitions */
XX#include <descrip.h> /* Descriptor structures */
XX#include <iodef.h> /* IO commands */
XX#include <ttdef.h> /* tty commands */
XX
XXextern int ttopen(); /* Forward references. */
XXextern int ttgetc();
XXextern int ttputc();
XXextern int ttflush();
XXextern int ttclose();
XXextern int vmsopen();
XXextern int vmseeol();
XXextern int vmseeop();
XXextern int vmsbeep();
XXextern int vmsmove();
XXextern int vmsinsert();
XXextern int vmsdelete();
XXextern int eolexist;
XX
XX#define NROWS 24 /* # of screen rolls */
XX#define NCOLS 80 /* # of screen columns */
XX#define MARGIN 8 /* size of minimim margin and */
XX#define SCRSIZ 64 /* scroll size for extended lines */
XX
XX/*
XX * Dispatch table. All the
XX * hard fields just point into the
XX * terminal I/O code.
XX */
XXTERM term = {
XX NROWS - 1,
XX NCOLS,
XX MARGIN,
XX SCRSIZ,
XX &vmsopen,
XX &ttclose,
XX &ttgetc,
XX &ttputc,
XX &ttflush,
XX &vmsmove,
XX &vmseeol,
XX &vmseeop,
XX &vmsbeep,
XX &vmsinsert,
XX &vmsdelete
XX };
XX
XXchar * termeop; /* Erase to end of page string */
XXint eoppad; /* Number of pad characters after eop */
XXchar * termeol; /* Erase to end of line string */
XXint eolpad; /* Number of pad characters after eol */
XXchar termtype; /* Terminal type identifier */
XX
XX
XX/*******
XX * ttputs - Send a string to ttputc
XX*******/
XX
XXttputs(string)
XXchar * string;
XX {
XX if (batchmode) return(TRUE);
XX while (*string != '\0') ttputc(*string++);
XX }
XX
XX
XX/*******
XX * vmspad - Pad the output after an escape sequence
XX*******/
XX
XXvmspad(count)
XXint count;
XX {
XX if (slowterm) return;
XX if (batchmode) return(TRUE);
XX
XX while (count-- > 0) ttputc('\0');
XX }
XX
XX
XX/*******
XX * vmsmove - Move the cursor
XX*******/
XX
XXvmsmove(row, col)
XX {
XX if (batchmode) return(TRUE);
XX switch (termtype) {
XX case TT$_UNKNOWN:
XX ttputc('\033');
XX ttputc('=');
XX ttputc(row+' ');
XX ttputc(col+' ');
XX break;
XX
XX case TT$_VT52:
XX ttputc('\033');
XX ttputc('Y');
XX ttputc(row+' ');
XX ttputc(col+' ');
XX break;
XX
XX case TT$_VT100:
XX {
XX char buffer[24];
XX
XX sprintf(buffer, "\033[%d;%dH", row+1, col+1);
XX ttputs(buffer);
XX vmspad(5);
XX }
XX }
XX }
XX
XX
XX/*******
XX * vmseeol - Erase to end of line
XX*******/
XX
XXvmseeol()
XX {
XX if (batchmode) return(TRUE);
XX ttputs(termeol);
XX vmspad(eolpad);
XX }
XX
XX
XX/*******
XX * vmseeop - Erase to end of page (clear screen)
XX*******/
XX
XXvmseeop()
XX {
XX if (batchmode) return(TRUE);
XX ttputs(termeop);
XX vmspad(eoppad);
XX }
XX
XX
XX/*******
XX * vmsbeep - Ring the bell
XX*******/
XX
XXvmsbeep()
XX {
XX if (batchmode) return(TRUE);
XX ttputc('\007');
XX }
XX
XX
XX/*******
XX * vmsinsert - insert n blank lines (assumes a vt100)
XX*******/
XX
XXvmsinsert(row, n)
XX {
XX char str[40];
XX
XX if (batchmode) return(TRUE);
XX sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,row+1);
XX ttputs(str);
XX sprintf(str,"\033M");
XX while (n--) ttputs(str);
XX ttputs("\033[r");
XX vmspad(10);
XX mlerase();
XX }
XX
XX/*******
XX * vmsdelete - delete n lines (assumes a vt100)
XX*******/
XX
XXvmsdelete(row, n)
XX {
XX char str[40];
XX
XX if (batchmode) return(TRUE);
XX mlerase();
XX sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,term.t_nrow);
XX ttputs(str);
XX sprintf(str,"\033D");
XX while (n--) ttputs(str);
XX ttputs("\033[r");
XX vmspad(10);
XX }
XX
XX/*******
XX * vmsopen - Get terminal type and open terminal
XX*******/
XX
XXvmsopen()
XX {
XX if (batchmode) return(TRUE);
XX termtype = vmsgtty();
XX switch (termtype) {
XX case TT$_UNKNOWN: /* Assume ADM3a */
XX eolexist = FALSE;
XX termeop = "\032";
XX eoppad = 0;
XX break;
XX
XX case TT$_VT52:
XX termeol = "\033K";
XX eolpad = 0;
XX termeop = "\033H\033J";
XX eoppad = 0;
XX break;
XX
XX case TT$_VT100:
XX termeol = "\033[K";
XX eolpad = 1;
XX termeop = "\033[;H\033[2J";
XX eoppad = 5;
XX break;
XX
XX default:
XX puts("Terminal type not supported");
XX exit (SS$_NORMAL);
XX }
XX ttopen();
XX }
XX
XX
XXstruct iosb { /* I/O status block */
XX short i_cond; /* Condition value */
XX short i_xfer; /* Transfer count */
XX long i_info; /* Device information */
XX };
XX
XXstruct termchar { /* Terminal characteristics */
XX char t_class; /* Terminal class */
XX char t_type; /* Terminal type */
XX short t_width; /* Terminal width in characters */
XX long t_mandl; /* Terminal's mode and length */
XX
XX long t_extend; /* Extended terminal characteristics */
XX };
XX
XX/*******
XX * vmsgtty - Get terminal type from system control block
XX*******/
XX
XXvmsgtty()
XX {
XX /*DBW*/ return (TT$_VT100);
XX }
XX
XX#else
XX
XXhellovms()
XX
XX {
XX }
XX
XX#endif VMSVT
XX
SHAR_EOF
if test 4763 -ne "`wc -c vmsvt.c`"
then
echo shar: error transmitting vmsvt.c '(should have been 4763 characters)'
fi
echo shar: extracting window.c
sed 's/^XX//' << \SHAR_EOF > window.c
XX/*
XX * Window management. Some of the functions are internal, and some are
XX * attached to keys that the user actually types.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX/*
XX * Reposition dot in the current window to line "n". If the argument is
XX * positive, it is that line. If it is negative it is that line from the
XX * bottom. If it is 0 the window is centered (this is what the standard
XX * redisplay code does). With no argument it defaults to 1. Bound to M-!.
XX * Because of the default, it works like in Gosling.
XX */
XXreposition(f, n)
XX {
XX if (f == FALSE) /* default to top of screen */
XX n = 1;
XX curwp->w_force = n;
XX curwp->w_flag |= WFFORCE;
XX return (TRUE);
XX }
XX
XX/*
XX * Refresh the screen. With no argument, it just does the refresh. With an
XX * argument it recenters "." in the current window. Bound to "C-L".
XX */
XXrefresh(f, n)
XX {
XX WINDOW *wp;
XX
XX if (f == FALSE) sgarbf = TRUE;
XX else
XX {
XX curwp->w_force = 0; /* Center dot. */
XX curwp->w_flag |= WFFORCE;
XX }
XX wp = wheadp; /* update all mode lines */
XX while (wp != NULL) {
XX wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX return (TRUE);
XX }
XX
XX
XX/*
XX * The command make the next window (next => down the screen) the current
XX * window. There are no real errors, although the command does nothing if
XX * there is only 1 window on the screen. Bound to "C-X C-N".
XX
XX */
XXnextwind(f, n)
XX {
XX register WINDOW *wp;
XX
XX if ((wp = curwp->w_wndp) == NULL) wp = wheadp;
XX
XX curwp = wp;
XX curbp = wp->w_bufp;
XX upmode();
XX return (TRUE);
XX }
XX
XX/*
XX * This command makes the previous window (previous => up the screen) the
XX * current window. There arn't any errors, although the command does not do a
XX * lot if there is 1 window.
XX */
XXprevwind(f, n)
XX {
XX register WINDOW *wp1;
XX register WINDOW *wp2;
XX
XX wp1 = wheadp;
XX wp2 = curwp;
XX
XX if (wp1 == wp2) wp2 = NULL;
XX
XX while (wp1->w_wndp != wp2) wp1 = wp1->w_wndp;
XX
XX curwp = wp1;
XX curbp = wp1->w_bufp;
XX upmode();
XX return (TRUE);
XX }
XX
XX/*
XX * This command moves the current window down by "arg" lines. Recompute the
XX * top line in the window. The move up and move down code is almost completely
XX * the same; most of the work has to do with reframing the window, and picking
XX * a new dot. We share the code by having "move down" just be an interface to
XX * "move up". Magic. Bound to "C-X C-N".
XX */
XXmvdnwind(f, n)
XXint n;
XX {
XX
XX return (mvupwind(f, -n));
XX }
XX
XX/*
XX * Move the current window up by "arg" lines. Recompute the new top line of
XX * the window. Look to see if "." is still on the screen. If it is, you win.
XX * If it isn't, then move "." to center it in the new framing of the window
XX * (this command does not really move "."; it moves the frame). Bound to
XX * "C-X C-P".
XX */
XXmvupwind(f, n)
XXint n;
XX {
XX register LINE *lp;
XX register int i;
XX
XX lp = curwp->w_linep;
XX
XX if (n < 0) {
XX while (n++ && lp!=curbp->b_linep) lp = lforw(lp);
XX }
XX else
XX {
XX while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp);
XX }
XX
XX curwp->w_linep = lp;
XX curwp->w_flag |= WFHARD; /* Mode line is OK. */
XX
XX for (i = 0; i < curwp->w_ntrows; ++i) {
XX if (lp == curwp->w_dotp) return (TRUE);
XX if (lp == curbp->b_linep) break;
XX lp = lforw(lp);
XX }
XX
XX lp = curwp->w_linep;
XX i = curwp->w_ntrows/2;
XX
XX while (i-- && lp != curbp->b_linep) lp = lforw(lp);
XX
XX curwp->w_dotp = lp;
XX curwp->w_doto = 0;
XX return (TRUE);
XX }
XX
XX/*
XX * This command makes the current window the only window on the screen. Bound
XX * to "C-X 1". Try to set the framing so that "." does not have to move on the
XX * display. Some care has to be taken to keep the values of dot and mark in
XX * the buffer structures right if the destruction of a window makes a buffer
XX * become undisplayed.
XX */
XXonlywind(f, n)
XX {
XX register WINDOW *wp;
XX register LINE *lp;
XX register int i;
XX
XX while (wheadp != curwp) {
XX wp = wheadp;
XX wheadp = wp->w_wndp;
XX if (--wp->w_bufp->b_nwnd == 0) {
XX wp->w_bufp->b_dotp = wp->w_dotp;
XX wp->w_bufp->b_doto = wp->w_doto;
XX wp->w_bufp->b_markp = wp->w_markp;
XX wp->w_bufp->b_marko = wp->w_marko;
XX }
XX free((char *) wp);
XX }
XX while (curwp->w_wndp != NULL) {
XX wp = curwp->w_wndp;
XX curwp->w_wndp = wp->w_wndp;
XX if (--wp->w_bufp->b_nwnd == 0) {
XX wp->w_bufp->b_dotp = wp->w_dotp;
XX wp->w_bufp->b_doto = wp->w_doto;
XX wp->w_bufp->b_markp = wp->w_markp;
XX wp->w_bufp->b_marko = wp->w_marko;
XX }
XX free((char *) wp);
XX }
XX lp = curwp->w_linep;
XX i = curwp->w_toprow;
XX while (i!=0 && lback(lp)!=curbp->b_linep) {
XX --i;
XX lp = lback(lp);
XX }
XX curwp->w_toprow = 0;
XX curwp->w_ntrows = term.t_nrow-1;
XX curwp->w_linep = lp;
XX curwp->w_flag |= WFMODE|WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * This command deletes the current window (provided it isn't the only one)
XX */
XXdelwind(f, n)
XX {
XX register WINDOW *wp,*prevwp;
XX register LINE *lp;
XX register int ntr,i;
XX
XX wp = wheadp;
XX if (wp->w_wndp == NULL) {
XX mlwrite("Cannot delete the only window");
XX return(FALSE);
XX }
XX prevwp = NULL;
XX while (wp != curwp) { prevwp = wp ; wp = wp->w_wndp; }
XX if (prevwp == NULL) wheadp = wp->w_wndp;
XX else prevwp->w_wndp = wp->w_wndp;
XX
XX if (--wp->w_bufp->b_nwnd == 0) {
XX wp->w_bufp->b_dotp = wp->w_dotp;
XX wp->w_bufp->b_doto = wp->w_doto;
XX wp->w_bufp->b_markp = wp->w_markp;
XX wp->w_bufp->b_marko = wp->w_marko;
XX }
XX ntr = wp->w_ntrows + 1;
XX free((char *) wp);
XX
XX curwp = wheadp;
XX curbp = wheadp->w_bufp;
XX lp = curwp->w_linep;
XX i = curwp->w_toprow;
XX while (i!=0 && lback(lp)!=curbp->b_linep) {
XX --i;
XX lp = lback(lp);
XX }
XX curwp->w_toprow = 0;
XX curwp->w_ntrows += ntr;
XX curwp->w_linep = lp;
XX curwp->w_flag |= WFMODE|WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * Split the current window. A window smaller than 3 lines cannot be split.
XX * The only other error that is possible is a "malloc" failure allocating the
XX * structure for the new window. Bound to "C-X 2".
XX */
XXsplitwind(f, n)
XX {
XX register WINDOW *wp;
XX register LINE *lp;
XX register int ntru;
XX register int ntrl;
XX register int ntrd;
XX register WINDOW *wp1;
XX register WINDOW *wp2;
XX char *malloc();
XX
XX if (curwp->w_ntrows < 3) {
XX mlwrite("Cannot split a %d line window", curwp->w_ntrows);
XX return (FALSE);
XX }
XX if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
XX mlwrite("Cannot allocate WINDOW block");
XX return (FALSE);
XX }
XX ++curbp->b_nwnd; /* Displayed twice. */
XX wp->w_bufp = curbp;
XX wp->w_dotp = curwp->w_dotp;
XX wp->w_doto = curwp->w_doto;
XX wp->w_markp = curwp->w_markp;
XX wp->w_marko = curwp->w_marko;
XX wp->w_flag = 0;
XX wp->w_force = 0;
XX ntru = (curwp->w_ntrows-1) / 2; /* Upper size */
XX ntrl = (curwp->w_ntrows-1) - ntru; /* Lower size */
XX lp = curwp->w_linep;
XX ntrd = 0;
XX while (lp != curwp->w_dotp) {
XX ++ntrd;
XX lp = lforw(lp);
XX }
XX lp = curwp->w_linep;
XX if (ntrd <= ntru) { /* Old is upper window. */
XX if (ntrd == ntru) /* Hit mode line. */
XX lp = lforw(lp);
XX curwp->w_ntrows = ntru;
XX wp->w_wndp = curwp->w_wndp;
XX curwp->w_wndp = wp;
XX wp->w_toprow = curwp->w_toprow+ntru+1;
XX wp->w_ntrows = ntrl;
XX }
XX else { /* Old is lower window */
XX wp1 = NULL;
XX wp2 = wheadp;
XX while (wp2 != curwp) {
XX wp1 = wp2;
XX wp2 = wp2->w_wndp;
XX }
XX if (wp1 == NULL) wheadp = wp;
XX else
XX wp1->w_wndp = wp;
XX wp->w_wndp = curwp;
XX wp->w_toprow = curwp->w_toprow;
XX wp->w_ntrows = ntru;
XX ++ntru; /* Mode line. */
XX curwp->w_toprow += ntru;
XX curwp->w_ntrows = ntrl;
XX while (ntru--) lp = lforw(lp);
XX }
XX curwp->w_linep = lp; /* Adjust the top lines */
XX wp->w_linep = lp; /* if necessary. */
XX curwp->w_flag |= WFMODE|WFHARD;
XX wp->w_flag |= WFMODE|WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * Enlarge the current window. Find the window that loses space. Make sure it
XX * is big enough. If so, hack the window descriptions, and ask redisplay to do
XX * all the hard work. You don't just set "force reframe" because dot would
XX * move. Bound to "C-X Z".
XX */
XXenlargewind(f, n)
XX {
XX register WINDOW *adjwp;
XX register LINE *lp;
XX register int i;
XX
XX if (n < 0) return (shrinkwind(f, -n));
XX if (wheadp->w_wndp == NULL) {
XX mlwrite("Only one window");
XX return (FALSE);
XX }
XX if ((adjwp=curwp->w_wndp) == NULL) {
XX adjwp = wheadp;
XX while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp;
XX }
XX if (adjwp->w_ntrows <= n) {
XX mlwrite("Impossible change");
XX return (FALSE);
XX }
XX if (curwp->w_wndp == adjwp) { /* Shrink below. */
XX lp = adjwp->w_linep;
XX for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i) lp = lforw(lp);
XX adjwp->w_linep = lp;
XX adjwp->w_toprow += n;
XX }
XX else { /* Shrink above. */
XX lp = curwp->w_linep;
XX for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i) lp = lback(lp);
XX curwp->w_linep = lp;
XX curwp->w_toprow -= n;
XX }
XX curwp->w_ntrows += n;
XX adjwp->w_ntrows -= n;
XX curwp->w_flag |= WFMODE|WFHARD;
XX adjwp->w_flag |= WFMODE|WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * Shrink the current window. Find the window that gains space. Hack at the
XX * window descriptions. Ask the redisplay to do all the hard work. Bound to
XX * "C-X C-Z".
XX */
XXshrinkwind(f, n)
XX {
XX register WINDOW *adjwp;
XX register LINE *lp;
XX register int i;
XX
XX if (n < 0) return (enlargewind(f, -n));
XX if (wheadp->w_wndp == NULL) {
XX mlwrite("Only one window");
XX return (FALSE);
XX }
XX if ((adjwp=curwp->w_wndp) == NULL) {
XX adjwp = wheadp;
XX while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp;
XX }
XX if (curwp->w_ntrows <= n) {
XX mlwrite("Impossible change");
XX return (FALSE);
XX }
XX if (curwp->w_wndp == adjwp) { /* Grow below. */
XX lp = adjwp->w_linep;
XX for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i) lp = lback(lp);
XX adjwp->w_linep = lp;
XX adjwp->w_toprow -= n;
XX }
XX else { /* Grow above. */
XX lp = curwp->w_linep;
XX for (i=0; i<n && lp!=curbp->b_linep; ++i) lp = lforw(lp);
XX curwp->w_linep = lp;
XX curwp->w_toprow += n;
XX }
XX curwp->w_ntrows -= n;
XX adjwp->w_ntrows += n;
XX curwp->w_flag |= WFMODE|WFHARD;
XX adjwp->w_flag |= WFMODE|WFHARD;
XX return (TRUE);
XX }
XX
XX/*
XX * Pick a window for a pop-up. Split the screen if there is only one window.
XX * Pick the uppermost window that isn't the current window. An LRU algorithm
XX * might be better. Return a pointer, or NULL on error.
XX */
XXWINDOW *
XXwpopup()
XX {
XX register WINDOW *wp;
XX
XX if (wheadp->w_wndp == NULL /* Only 1 window */
XX && splitwind(FALSE, 0) == FALSE) /* and it won't split */
XX return (NULL);
XX wp = wheadp; /* Find window to use */
XX while (wp!=NULL && wp==curwp) wp = wp->w_wndp;
XX return (wp);
XX }
XX
XXscrnextup(f, n) /* scroll the next window up (back) a page */
XX
XX {
XX nextwind(FALSE, 1);
XX backpage(f, n);
XX prevwind(FALSE, 1);
XX }
XX
XXscrnextdw(f, n) /* scroll the next window down (forward) a page */
XX
XX {
XX nextwind(FALSE, 1);
XX forwpage(f, n);
XX prevwind(FALSE, 1);
XX }
XX
SHAR_EOF
if test 11068 -ne "`wc -c window.c`"
then
echo shar: error transmitting window.c '(should have been 11068 characters)'
fi
echo shar: extracting word.c
sed 's/^XX//' << \SHAR_EOF > word.c
XX/*
XX * The routines in this file implement commands that work word at a time.
XX * There are all sorts of word mode commands. If I do any sentence and/or
XX * paragraph mode commands, they are likely to be put in this file.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX/* Word wrap on n-spaces. Back-over whatever precedes the point on the current
XX * line and stop on the first word-break or the beginning of the line. If we
XX * reach the beginning of the line, jump back to the end of the word and start
XX * a new line. Otherwise, break the line at the word-break, eat it, and jump
XX * back to the end of the word.
XX * Returns TRUE on success, FALSE on errors.
XX */
XXwrapword(n)
XXint n;
XX {
XX register int chr;
XX
XX /* back up until we are in a word,
XX make sure there is a break in the line */
XX do {
XX if (! backchar(0, 1)) return(FALSE);
XX }
XX while (! inword());
XX
XX /* backup past the space */
XX if (! backword(0, 1)) return(FALSE);
XX
XX /* backup until we have a space or tab */
XX chr = lgetc(curwp->w_dotp, curwp->w_doto);
XX while (chr != ' ' && chr != '\t') {
XX if (! backchar(0, 1)) return(FALSE);
XX chr = lgetc(curwp->w_dotp, curwp->w_doto);
XX }
XX
XX /* delete the forward space */
XX if (! forwdel(0, 1)) return(FALSE);
XX
XX /* put in an end of line */
XX if (! newline(0, 1)) return(FALSE);
XX
XX /* advance past the next word and space and return */
XX while (inword() != FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX
XX /* and to the end of that line */
XX curwp->w_doto = llength(curwp->w_dotp);
XX return(TRUE);
XX }
XX
XX/*
XX * Move the cursor backward by "n" words. All of the details of motion are
XX * performed by the "backchar" and "forwchar" routines. Error if you try to
XX * move beyond the buffers.
XX */
XXbackword(f, n)
XX {
XX if (n < 0) return (forwword(f, -n));
XX if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX while (n--) {
XX while (inword() == FALSE) {
XX if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX while (inword() != FALSE) {
XX if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX }
XX return (forwchar(FALSE, 1));
XX }
XX
XX/*
XX * Move the cursor forward by the specified number of words. All of the motion
XX * is done by "forwchar". Error if you try and move beyond the buffer's end.
XX */
XXforwword(f, n)
XX {
XX if (n < 0) return (backword(f, -n));
XX while (n--) {
XX#if NFWORD
XX while (inword() != FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX#endif
XX while (inword() == FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX#if NFWORD == 0
XX while (inword() != FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX#endif
XX }
XX return(TRUE);
XX }
XX
XX/*
XX * Move the cursor forward by the specified number of words. As you move,
XX * convert any characters to upper case. Error if you try and move beyond the
XX * end of the buffer. Bound to "M-U".
XX */
XXupperword(f, n)
XX {
XX register int c;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX while (n--) {
XX while (inword() == FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX while (inword() != FALSE) {
XX c = lgetc(curwp->w_dotp, curwp->w_doto);
XX if (c>='a' && c<='z') {
XX c -= 'a'-'A';
XX lputc(curwp->w_dotp, curwp->w_doto, c);
XX lchange(WFHARD);
XX }
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX }
XX
XX return (TRUE);
XX }
XX
XX/*
XX * Move the cursor forward by the specified number of words. As you move
XX * convert characters to lower case. Error if you try and move over the end of
XX * the buffer. Bound to "M-L".
XX */
XXlowerword(f, n)
XX {
XX register int c;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX while (n--) {
XX while (inword() == FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX while (inword() != FALSE) {
XX c = lgetc(curwp->w_dotp, curwp->w_doto);
XX if (c>='A' && c<='Z') {
XX c += 'a'-'A';
XX lputc(curwp->w_dotp, curwp->w_doto, c);
XX lchange(WFHARD);
XX }
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Move the cursor forward by the specified number of words. As you move
XX * convert the first character of the word to upper case, and subsequent
XX * characters to lower case. Error if you try and move past the end of the
XX * buffer. Bound to "M-C".
XX */
XXcapword(f, n)
XX {
XX register int c;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX while (n--) {
XX while (inword() == FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX if (inword() != FALSE) {
XX c = lgetc(curwp->w_dotp, curwp->w_doto);
XX if (c>='a' && c<='z') {
XX c -= 'a'-'A';
XX lputc(curwp->w_dotp, curwp->w_doto, c);
XX lchange(WFHARD);
XX }
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX while (inword() != FALSE) {
XX c = lgetc(curwp->w_dotp, curwp->w_doto);
XX if (c>='A' && c<='Z') {
XX c += 'a'-'A';
XX lputc(curwp->w_dotp, curwp->w_doto, c);
XX lchange(WFHARD);
XX }
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX }
XX }
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Kill forward by "n" words. Remember the location of dot. Move forward by
XX * the right number of words. Put dot back where it was and issue the kill
XX * command for the right number of characters. Bound to "M-D".
XX */
XXdelfword(f, n)
XX {
XX register int size;
XX register LINE *dotp;
XX register int doto;
XX
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX dotp = curwp->w_dotp;
XX doto = curwp->w_doto;
XX size = 0;
XX while (n--) {
XX#if NFWORD
XX while (inword() != FALSE) {
XX if (forwchar(FALSE,1) == FALSE) return(FALSE);
XX ++size;
XX }
XX#endif
XX while (inword() == FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX ++size;
XX }
XX#if NFWORD == 0
XX while (inword() != FALSE) {
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX ++size;
XX }
XX#endif
XX }
XX curwp->w_dotp = dotp;
XX curwp->w_doto = doto;
XX return (ldelete(size, TRUE));
XX }
XX
XX/*
XX * Kill backwards by "n" words. Move backwards by the desired number of words,
XX * counting the characters. When dot is finally moved to its resting place,
XX * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
XX */
XXdelbword(f, n)
XX {
XX register int size;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX size = 0;
XX while (n--) {
XX while (inword() == FALSE) {
XX if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX ++size;
XX }
XX while (inword() != FALSE) {
XX if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX ++size;
XX }
XX }
XX if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX return (ldelete(size, TRUE));
XX }
XX
XX/*
XX * Return TRUE if the character at dot is a character that is considered to be
XX * part of a word. The word character list is hard coded. Should be setable.
XX */
XXinword()
XX {
XX register int c;
XX
XX if (curwp->w_doto == llength(curwp->w_dotp)) return (FALSE);
XX c = lgetc(curwp->w_dotp, curwp->w_doto);
XX if (c>='a' && c<='z') return (TRUE);
XX if (c>='A' && c<='Z') return (TRUE);
XX if (c>='0' && c<='9') return (TRUE);
XX if (c=='$' || c=='_') /* For identifiers */
XX return (TRUE);
XX return (FALSE);
XX }
XX
XXfillpara(f, n) /* Fill the current paragraph according to the current
XXfill column */
XX
XXint f, n; /* deFault flag and Numeric argument */
XX
XX {
XX register int c; /* current char durring scan */
XX register int wordlen; /* length of current word */
XX register int clength; /* position on line during fill */
XX register int i; /* index during word copy */
XX register int newlength; /* tentative new line length */
XX register int eopflag; /* Are we at the End-Of-Paragraph? */
XX register int firstflag; /* first word? (needs no space) */
XX register LINE *eopline; /* pointer to line just past EOP */
XX char wbuf[NSTRING]; /* buffer for current word */
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (fillcol == 0) { /* no fill column set */
XX mlwrite("No fill column set");
XX return(FALSE);
XX }
XX
XX /* record the pointer to the line just past the EOP */
XX gotoeop(FALSE, 1);
XX eopline = lforw(curwp->w_dotp);
XX
XX /* and back top the begining of the paragraph */
XX gotobop(FALSE, 1);
XX
XX /* initialize various info */
XX clength = curwp->w_doto;
XX if (clength && curwp->w_dotp->l_text[0] == TAB) clength = 8;
XX wordlen = 0;
XX
XX /* scan through lines, filling words */
XX firstflag = TRUE;
XX eopflag = FALSE;
XX while (!eopflag) {
XX /* get the next character in the paragraph */
XX if (curwp->w_doto == llength(curwp->w_dotp)) {
XX c = ' ';
XX if (lforw(curwp->w_dotp) == eopline) eopflag = TRUE;
XX }
XX else
XX c = lgetc(curwp->w_dotp, curwp->w_doto);
XX
XX /* and then delete it */
XX ldelete(1, FALSE);
XX
XX /* if not a separator, just add it in */
XX if (c != ' ' && c != ' ') {
XX if (wordlen < NSTRING - 1) wbuf[wordlen++] = c;
XX }
XX else if (wordlen) {
XX /* at a word break with a word waiting */
XX /* calculate tantitive new length with word added */
XX newlength = clength + 1 + wordlen;
XX if (newlength <= fillcol) {
XX /* add word to current line */
XX if (!firstflag) {
XX linsert(1, ' '); /* the space */
XX ++clength;
XX }
XX firstflag = FALSE;
XX
XX }
XX else {
XX /* start a new line */
XX lnewline();
XX clength = 0;
XX }
XX
XX /* and add the word in in either case */
XX for (i=0; i<wordlen; i++) {
XX linsert(1, wbuf[i]);
XX ++clength;
XX }
XX wordlen = 0;
XX }
XX }
XX /* and add a last newline for the end of our new paragraph */
XX lnewline();
XX }
SHAR_EOF
if test 10090 -ne "`wc -c word.c`"
then
echo shar: error transmitting word.c '(should have been 10090 characters)'
fi
# End of shell archive
exit 0wecker@cookie.dec.com.UUCP (02/21/87)
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# fileio.c
# line.c
# lisp.c
# lock.c
# main.c
# random.c
# This archive created: Fri Feb 20 17:44:33 1987
echo shar: extracting fileio.c
sed 's/^XX//' << \SHAR_EOF > fileio.c
XX/*
XX * The routines in this file read and write ASCII files from the disk. All of
XX * the knowledge about files are here. A better message writing scheme should
XX * be used.
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XXFILE *ffp; /* File pointer, all functions. */
XX
XX/*
XX * Open a file for reading.
XX */
XXffropen(fn)
XXchar *fn;
XX {
XX if ((ffp=fopen(fn, "r")) == NULL) return (FIOFNF);
XX return (FIOSUC);
XX }
XX
XX/*
XX * Open a file for writing. Return TRUE if all is well, and FALSE on error
XX * (cannot create).
XX */
XXffwopen(fn)
XXchar *fn;
XX {
XX#if VMS
XX register int fd;
XX
XX if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0 || (ffp=fdopen(fd, "w")) == NULL) {
XX#else
XX if ((ffp=fopen(fn, "w")) == NULL) {
XX#endif
XX mlwrite("Cannot open file for writing");
XX return (FIOERR);
XX }
XX return (FIOSUC);
XX }
XX
XX /*
XX * Close a file. Should look at the status in all systems.
XX */
XX ffclose()
XX {
XX#if ULTRIX
XX if (fclose(ffp) != FALSE) {
XX mlwrite("Error closing file");
XX return(FIOERR);
XX }
XX return(FIOSUC);
XX#else
XX fclose(ffp);
XX return (FIOSUC);
XX#endif
XX }
XX
XX /*
XX * Write a line to the already opened file. The "buf" points to the buffer,
XX * and the "nbuf" is its length, less the free newline. Return the status.
XX * Check only at the newline.
XX */
XX ffputline(buf, nbuf)
XX char buf[];
XX {
XX register int i;
XX
XX for (i = 0; i < nbuf; ++i) fputc(buf[i]&0xFF, ffp);
XX
XX fputc('\n', ffp);
XX
XX if (ferror(ffp)) {
XX mlwrite("Write I/O error");
XX return (FIOERR);
XX }
XX
XX return (FIOSUC);
XX }
XX
XX /*
XX * Read a line from a file, and store the bytes in the supplied buffer. The
XX * "nbuf" is the length of the buffer. Complain about long lines and lines
XX * at the end of the file that don't have a newline present. Check for I/O
XX * errors too. Return status.
XX */
XX ffgetline(buf, nbuf)
XX register char buf[];
XX {
XX register int c;
XX register int i;
XX
XX i = 0;
XX
XX while ((c = fgetc(ffp)) != EOF && c != '\n') {
XX if (i >= nbuf-2) {
XX buf[nbuf - 2] = c; /* store last char read */
XX buf[nbuf - 1] = 0; /* and terminate it */
XX mlwrite("File has long line");
XX return (FIOLNG);
XX }
XX buf[i++] = c;
XX }
XX
XX if (c == EOF) {
XX if (ferror(ffp)) {
XX mlwrite("File read error");
XX return (FIOERR);
XX }
XX
XX if (i != 0) {
XX mlwrite("File has funny line at EOF");
XX return (FIOERR);
XX }
XX return (FIOEOF);
XX }
XX
XX buf[i] = 0;
XX return (FIOSUC);
XX }
XX
SHAR_EOF
if test 2446 -ne "`wc -c fileio.c`"
then
echo shar: error transmitting fileio.c '(should have been 2446 characters)'
fi
echo shar: extracting line.c
sed 's/^XX//' << \SHAR_EOF > line.c
XX/*
XX * The functions in this file are a general set of line management utilities.
XX * They are the only routines that touch the text. They also touch the buffer
XX * and window structures, to make sure that the necessary updating gets done.
XX * There are routines in this file that handle the kill buffer too. It isn't
XX * here for any good reason.
XX *
XX * Note that this code only updates the dot and mark values in the window list.
XX * Since all the code acts on the current window, the buffer that we are
XX * editing must be being displayed, which means that "b_nwnd" is non zero,
XX * which means that the dot and mark values in the buffer headers are nonsense.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#define NBLOCK 16 /* Line block chunk size */
XX#define KBLOCK 1024 /* Kill buffer block size */
XX
XXchar *kbufp = NULL; /* Kill buffer data */
XXunsigned kused = 0; /* # of bytes used in KB */
XXunsigned ksize = 0; /* # of bytes allocated in KB */
XX
XX/*
XX * This routine allocates a block of memory large enough to hold a LINE
XX * containing "used" characters. The block is always rounded up a bit. Return
XX * a pointer to the new block, or NULL if there isn't any memory left. Print a
XX * message in the message line if no space.
XX */
XXLINE *
XXlalloc(used)
XXregister int used;
XX {
XX register LINE *lp;
XX register int size;
XX char *malloc();
XX
XX size = (used+NBLOCK-1) & ~(NBLOCK-1);
XX if (size == 0) /* Assume that an empty */
XX size = NBLOCK; /* line is for type-in. */
XX if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
XX mlwrite("Cannot allocate %d bytes", size);
XX return (NULL);
XX }
XX lp->l_size = size;
XX lp->l_used = used;
XX return (lp);
XX }
XX
XX/*
XX * Delete line "lp". Fix all of the links that might point at it (they are
XX * moved to offset 0 of the next line. Unlink the line from whatever buffer it
XX * might be in. Release the memory. The buffers are updated too; the magic
XX * conditions described in the above comments don't hold here.
XX */
XXlfree(lp)
XXregister LINE *lp;
XX {
XX register BUFFER *bp;
XX register WINDOW *wp;
XX
XX wp = wheadp;
XX while (wp != NULL) {
XX if (wp->w_linep == lp) wp->w_linep = lp->l_fp;
XX if (wp->w_dotp == lp) {
XX wp->w_dotp = lp->l_fp;
XX wp->w_doto = 0;
XX }
XX if (wp->w_markp == lp) {
XX wp->w_markp = lp->l_fp;
XX wp->w_marko = 0;
XX }
XX wp = wp->w_wndp;
XX }
XX bp = bheadp;
XX while (bp != NULL) {
XX if (bp->b_nwnd == 0) {
XX if (bp->b_dotp == lp) {
XX bp->b_dotp = lp->l_fp;
XX bp->b_doto = 0;
XX }
XX if (bp->b_markp == lp) {
XX bp->b_markp = lp->l_fp;
XX bp->b_marko = 0;
XX }
XX }
XX bp = bp->b_bufp;
XX }
XX lp->l_bp->l_fp = lp->l_fp;
XX lp->l_fp->l_bp = lp->l_bp;
XX free((char *) lp);
XX }
XX
XX/*
XX * This routine gets called when a character is changed in place in the current
XX * buffer. It updates all of the required flags in the buffer and window
XX * system. The flag used is passed as an argument; if the buffer is being
XX * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
XX * mode line needs to be updated (the "*" has to be set).
XX */
XXlchange(flag)
XXregister int flag;
XX {
XX register WINDOW *wp;
XX
XX if (curbp->b_nwnd != 1) /* Ensure hard. */
XX flag = WFHARD;
XX if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
XX flag |= WFMODE; /* update mode lines. */
XX curbp->b_flag |= BFCHG;
XX }
XX wp = wheadp;
XX while (wp != NULL) {
XX if (wp->w_bufp == curbp) wp->w_flag |= flag;
XX wp = wp->w_wndp;
XX }
XX }
XX
XX/*
XX * Insert "n" copies of the character "c" at the current location of dot. In
XX * the easy case all that happens is the text is stored in the line. In the
XX * hard case, the line has to be reallocated. When the window list is updated,
XX * take special care; I screwed it up once. You always update dot in the
XX * current window. You update mark, and a dot in another window, if it is
XX * greater than the place where you did the insert. Return TRUE if all is
XX * well, and FALSE on errors.
XX */
XXlinsert(n, c)
XX {
XX register char *cp1;
XX register char *cp2;
XX register LINE *lp1;
XX register LINE *lp2;
XX register LINE *lp3;
XX register int doto;
XX register int i;
XX register WINDOW *wp;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX lchange(WFEDIT);
XX lp1 = curwp->w_dotp; /* Current line */
XX if (lp1 == curbp->b_linep) { /* At the end: special */
XX if (curwp->w_doto != 0) {
XX mlwrite("bug: linsert");
XX return (FALSE);
XX }
XX if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
XX return (FALSE);
XX lp3 = lp1->l_bp; /* Previous line */
XX lp3->l_fp = lp2; /* Link in */
XX lp2->l_fp = lp1;
XX lp1->l_bp = lp2;
XX lp2->l_bp = lp3;
XX for (i=0; i<n; ++i) lp2->l_text[i] = c;
XX curwp->w_dotp = lp2;
XX curwp->w_doto = n;
XX return (TRUE);
XX }
XX doto = curwp->w_doto; /* Save for later. */
XX if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
XX if ((lp2=lalloc(lp1->l_used+n)) == NULL)
XX return (FALSE);
XX cp1 = &lp1->l_text[0];
XX cp2 = &lp2->l_text[0];
XX while (cp1 != &lp1->l_text[doto]) *cp2++ = *cp1++;
XX cp2 += n;
XX while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++;
XX lp1->l_bp->l_fp = lp2;
XX lp2->l_fp = lp1->l_fp;
XX lp1->l_fp->l_bp = lp2;
XX lp2->l_bp = lp1->l_bp;
XX free((char *) lp1);
XX }
XX else { /* Easy: in place */
XX lp2 = lp1; /* Pretend new line */
XX lp2->l_used += n;
XX cp2 = &lp1->l_text[lp1->l_used];
XX cp1 = cp2-n;
XX while (cp1 != &lp1->l_text[doto]) *--cp2 = *--cp1;
XX }
XX for (i=0; i<n; ++i) /* Add the characters */
XX lp2->l_text[doto+i] = c;
XX wp = wheadp; /* Update windows */
XX while (wp != NULL) {
XX if (wp->w_linep == lp1) wp->w_linep = lp2;
XX if (wp->w_dotp == lp1) {
XX wp->w_dotp = lp2;
XX if (wp==curwp || wp->w_doto>doto) wp->w_doto += n;
XX }
XX if (wp->w_markp == lp1) {
XX wp->w_markp = lp2;
XX if (wp->w_marko > doto) wp->w_marko += n;
XX }
XX wp = wp->w_wndp;
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Insert a newline into the buffer at the current location of dot in the
XX * current window. The funny ass-backwards way it does things is not a botch;
XX * it just makes the last line in the file not a special case. Return TRUE if
XX * everything works out and FALSE on error (memory allocation failure). The
XX * update of dot and mark is a bit easier then in the above case, because the
XX * split forces more updating.
XX */
XXlnewline()
XX {
XX register char *cp1;
XX register char *cp2;
XX register LINE *lp1;
XX register LINE *lp2;
XX register int doto;
XX register WINDOW *wp;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX lchange(WFHARD);
XX lp1 = curwp->w_dotp; /* Get the address and */
XX doto = curwp->w_doto; /* offset of "." */
XX if ((lp2=lalloc(doto)) == NULL) /* New first half line */
XX return (FALSE);
XX cp1 = &lp1->l_text[0]; /* Shuffle text around */
XX cp2 = &lp2->l_text[0];
XX while (cp1 != &lp1->l_text[doto]) *cp2++ = *cp1++;
XX cp2 = &lp1->l_text[0];
XX while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++;
XX lp1->l_used -= doto;
XX lp2->l_bp = lp1->l_bp;
XX lp1->l_bp = lp2;
XX lp2->l_bp->l_fp = lp2;
XX lp2->l_fp = lp1;
XX wp = wheadp; /* Windows */
XX while (wp != NULL) {
XX if (wp->w_linep == lp1) wp->w_linep = lp2;
XX if (wp->w_dotp == lp1) {
XX if (wp->w_doto < doto) wp->w_dotp = lp2;
XX else
XX wp->w_doto -= doto;
XX }
XX if (wp->w_markp == lp1) {
XX if (wp->w_marko < doto) wp->w_markp = lp2;
XX else
XX wp->w_marko -= doto;
XX }
XX wp = wp->w_wndp;
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * This function deletes "n" bytes, starting at dot. It understands how do deal
XX * with end of lines, etc. It returns TRUE if all of the characters were
XX * deleted, and FALSE if they were not (because dot ran into the end of the
XX * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
XX */
XXldelete(n, kflag)
XX {
XX register char *cp1;
XX register char *cp2;
XX register LINE *dotp;
XX register int doto;
XX register int chunk;
XX register WINDOW *wp;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX while (n != 0) {
XX dotp = curwp->w_dotp;
XX doto = curwp->w_doto;
XX if (dotp == curbp->b_linep) /* Hit end of buffer. */
XX return (FALSE);
XX chunk = dotp->l_used-doto; /* Size of chunk. */
XX if (chunk > n) chunk = n;
XX if (chunk == 0) { /* End of line, merge. */
XX lchange(WFHARD);
XX if (ldelnewline() == FALSE || (kflag!=FALSE && kinsert('\n')==FALSE))
XX return (FALSE);
XX --n;
XX continue;
XX }
XX lchange(WFEDIT);
XX cp1 = &dotp->l_text[doto]; /* Scrunch text. */
XX cp2 = cp1 + chunk;
XX if (kflag != FALSE) { /* Kill? */
XX while (cp1 != cp2) {
XX if (kinsert(*cp1) == FALSE) return (FALSE);
XX ++cp1;
XX }
XX cp1 = &dotp->l_text[doto];
XX }
XX while (cp2 != &dotp->l_text[dotp->l_used]) *cp1++ = *cp2++;
XX dotp->l_used -= chunk;
XX wp = wheadp; /* Fix windows */
XX while (wp != NULL) {
XX if (wp->w_dotp==dotp && wp->w_doto>=doto) {
XX wp->w_doto -= chunk;
XX if (wp->w_doto < doto) wp->w_doto = doto;
XX }
XX if (wp->w_markp==dotp && wp->w_marko>=doto) {
XX wp->w_marko -= chunk;
XX if (wp->w_marko < doto) wp->w_marko = doto;
XX }
XX wp = wp->w_wndp;
XX }
XX n -= chunk;
XX }
XX return (TRUE);
XX }
XX
XX/*
XX * Delete a newline. Join the current line with the next line. If the next line
XX * is the magic header line always return TRUE; merging the last line with the
XX * header line can be thought of as always being a successful operation, even
XX * if nothing is done, and this makes the kill buffer work "right". Easy cases
XX * can be done by shuffling data around. Hard cases require that lines be moved
XX * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
XX * "ldelete" only.
XX */
XXldelnewline()
XX {
XX register char *cp1;
XX register char *cp2;
XX register LINE *lp1;
XX register LINE *lp2;
XX register LINE *lp3;
XX register WINDOW *wp;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX lp1 = curwp->w_dotp;
XX lp2 = lp1->l_fp;
XX if (lp2 == curbp->b_linep) { /* At the buffer end. */
XX if (lp1->l_used == 0) /* Blank line. */
XX lfree(lp1);
XX return (TRUE);
XX }
XX if (lp2->l_used <= lp1->l_size-lp1->l_used) {
XX cp1 = &lp1->l_text[lp1->l_used];
XX cp2 = &lp2->l_text[0];
XX while (cp2 != &lp2->l_text[lp2->l_used]) *cp1++ = *cp2++;
XX wp = wheadp;
XX while (wp != NULL) {
XX if (wp->w_linep == lp2) wp->w_linep = lp1;
XX if (wp->w_dotp == lp2) {
XX wp->w_dotp = lp1;
XX wp->w_doto += lp1->l_used;
XX }
XX if (wp->w_markp == lp2) {
XX wp->w_markp = lp1;
XX wp->w_marko += lp1->l_used;
XX }
XX wp = wp->w_wndp;
XX }
XX lp1->l_used += lp2->l_used;
XX lp1->l_fp = lp2->l_fp;
XX lp2->l_fp->l_bp = lp1;
XX free((char *) lp2);
XX return (TRUE);
XX }
XX if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL) return (FALSE);
XX cp1 = &lp1->l_text[0];
XX cp2 = &lp3->l_text[0];
XX while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++;
XX cp1 = &lp2->l_text[0];
XX while (cp1 != &lp2->l_text[lp2->l_used]) *cp2++ = *cp1++;
XX lp1->l_bp->l_fp = lp3;
XX lp3->l_fp = lp2->l_fp;
XX lp2->l_fp->l_bp = lp3;
XX lp3->l_bp = lp1->l_bp;
XX wp = wheadp;
XX while (wp != NULL) {
XX if (wp->w_linep==lp1 || wp->w_linep==lp2) wp->w_linep = lp3;
XX if (wp->w_dotp == lp1) wp->w_dotp = lp3;
XX else if (wp->w_dotp == lp2) {
XX wp->w_dotp = lp3;
XX wp->w_doto += lp1->l_used;
XX }
XX if (wp->w_markp == lp1) wp->w_markp = lp3;
XX else if (wp->w_markp == lp2) {
XX wp->w_markp = lp3;
XX wp->w_marko += lp1->l_used;
XX }
XX wp = wp->w_wndp;
XX }
XX free((char *) lp1);
XX free((char *) lp2);
XX return (TRUE);
XX }
XX
XX/*
XX * Delete all of the text saved in the kill buffer. Called by commands when a
XX * new kill context is being created. The kill buffer array is released, just
XX * in case the buffer has grown to immense size. No errors.
XX */
XXkdelete()
XX {
XX if (kbufp != NULL) {
XX free((char *) kbufp);
XX kbufp = NULL;
XX kused = 0;
XX ksize = 0;
XX }
XX }
XX
XX/*
XX * Insert a character to the kill buffer, enlarging the buffer if there isn't
XX * any room. Always grow the buffer in chunks, on the assumption that if you
XX * put something in the kill buffer you are going to put more stuff there too
XX * later. Return TRUE if all is well, and FALSE on errors.
XX */
XX
XXkinsert(c)
XX {
XX register char *nbufp;
XX char *realloc();
XX char *malloc();
XX
XX if (kused == ksize) {
XX if (ksize == 0) /* first time through? */
XX nbufp = malloc(KBLOCK); /* alloc the first block */
XX else /* or re allocate a bigger block */
XX nbufp = realloc(kbufp, ksize+KBLOCK);
XX
XX if (nbufp == NULL) /* abort if it fails */
XX return(FALSE);
XX kbufp = nbufp; /* point our global at it */
XX ksize += KBLOCK; /* and adjust the size */
XX }
XX kbufp[kused++] = c;
XX return (TRUE);
XX }
XX
XX/*
XX * This function gets characters from the kill buffer. If the character index
XX * "n" is off the end, it returns "-1". This lets the caller just scan along
XX * until it gets a "-1" back.
XX */
XXkremove(n)
XX {
XX if (n >= kused) return (-1);
XX else
XX return (kbufp[n] & 0xFF);
XX }
XX
XX
XX#if LATTICE | AZTEC
XX/* we need to have the following functions to manage memory that
XXdon't exist under Lattice */
XX
XX
XXchar *realloc(ptr, size) /* re-allocate a memory chunk to a
XXdifferent size, copying what can
XXby copied */
XX
XXchar *ptr; /* pointer to the original block */
XXunsigned size; /* # of bytes needed in new block */
XX
XX {
XX char *newptr; /* pointer to new block */
XX unsigned csize; /* size of area to copy from old buffer to new */
XX char *malloc();
XX
XX newptr = malloc(size); /* get the new block */
XX if (newptr == NULL) /* if malloc fails....*/
XX return(NULL);
XX
XX csize = ksize; /******THIS IS A CHEAT SINCE WE CAN NOT GET
XX AT THE SIZE OF THE MALLOCED BLOCK!!
XX DO NOT USE THIS FUNCTION GENERICALLY!!!*/
XX if (csize > size) /* we need to copy some stuff from */
XX csize = size; /* the old buffer to the new */
XX
XX movmem(ptr, newptr, csize); /* copy the availible bytes */
XX free(ptr); /* dump the old buffer */
XX return(newptr); /* and return the new */
XX }
XX#endif
XX
XX
SHAR_EOF
if test 14691 -ne "`wc -c line.c`"
then
echo shar: error transmitting line.c '(should have been 14691 characters)'
fi
echo shar: extracting lisp.c
sed 's/^XX//' << \SHAR_EOF > lisp.c
XX/**************************************************************************
XX *
XX * Micro LISP functions for micro EMACS
XX *
XX * V1.0 DBW 870204 Dave Wecker
XX *
XX *************************************************************************/
XX
XX
XX#include <stdio.h>
XX#include <setjmp.h>
XX
XX#include "estruct.h"
XX#include "edef.h"
XX#include "epath.h"
XX
XXextern short doflashing;
XXextern char *malloc();
XX
XXjmp_buf env[10]; /* environments for setjmp/longjmp */
XXstatic envnum = -1;
XX#define PROGN_RETURN 1
XX#define PROGN_GO 2
XX
XX/* node definitions */
XX#define NIL 0
XX#define CONS 1
XX#define INTEGER 2
XX#define STRING 3
XX#define SUBR 4
XX#define SYMBOL 5
XX
XX#if AMIGA
XX#define MAXNODE 500
XX#else
XX#define MAXNODE 5000
XX#endif
XX
XXtypedef struct node {
XX char type;
XX struct node *car;
XX struct node *cdr;
XX } NODE;
XX
XXtypedef int INTRTN();
XX
XXextern NODE *fncmatch(); /* match a function name with an address */
XX
XX#if AMIGA
XXstatic NODE TNODE = { INTEGER, 1L, 0L };
XXstatic NODE FNODE = { INTEGER, 0L, 0L };
XX#else
XXstatic NODE TNODE = { INTEGER, (NODE *)1L, (NODE *)0L };
XXstatic NODE FNODE = { INTEGER, (NODE *)0L, (NODE *)0L };
XX#endif
XX
XXstatic NODE *syms[26]; /* symbols A-Z */
XXstatic NODE *retval; /* global return value for procedures */
XXstatic NODE *gblpar[20]; /* global parameters for emacs routines */
XXstatic NODE **nodes = NULL; /* nodes available to the system */
XXstatic int maxnode = -1; /* current maximum node index */
XXstatic int gblidx = 0; /* current parameter index */
XXstatic int gblnum = 0; /* maximum parameter count */
XXstatic int pushback = -1;
XXstatic LINE *c_endp; /* compile end line pointer */
XXstatic LINE *c_dotp; /* current compile line */
XXstatic short c_doto; /* current compile offset */
XXstatic INTRTN *lstfnc = NULL; /* last function executed */
XX
XX/************************** support routines ***************************/
XX
XXDEBUG_dump(n)
XXNODE *n;
XX {
XX long l;
XX char c;
XX
XX if (n == NULL) {
XX printf("NIL");
XX fflush(stderr);
XX return;
XX }
XX switch (n->type) {
XX case INTEGER:
XX printf("%ld ",(long)n->car);
XX break;
XX
XX case STRING:
XX printf("\042%s\042 ",(char *)n->car);
XX break;
XX
XX case SYMBOL:
XX l = (long)n->car + 97L;
XX c = l;
XX printf("%c ",c);
XX break;
XX
XX case SUBR:
XX printf("#%lx ",(long)n->car);
XX break;
XX
XX case CONS:
XX printf("(");
XX DEBUG_dump(n->car);
XX printf(". ");
XX DEBUG_dump(n->cdr);
XX printf(")");
XX break;
XX }
XX fflush(stderr);
XX }
XX
XXNODE *
XXnewtnode(typ,len)
XXint typ,len;
XX {
XX if (nodes == NULL) nodes = (NODE **)malloc(MAXNODE * sizeof(NODE *));
XX if (++maxnode >= MAXNODE) {
XX mlwrite("!!!!! RAN OUT OF LISP NODES !!!!!");
XX maxnode = MAXNODE-1;
XX }
XX nodes[maxnode] = (NODE *)malloc(sizeof(NODE));
XX nodes[maxnode]->type = typ;
XX if (typ == STRING) nodes[maxnode]->car = (NODE *)malloc(len+1);
XX else nodes[maxnode]->car = NULL;
XX nodes[maxnode]->cdr = NULL;
XX return(nodes[maxnode]);
XX }
XX
XXrettnode()
XX {
XX int i;
XX
XX for (i = 0; i <= maxnode; i++) {
XX if (nodes[i] != NULL) {
XX if (nodes[i]->type == STRING && nodes[i]->car != NULL)
XX free((char *)nodes[i]->car);
XX free((char *)nodes[i]);
XX nodes[i] = NULL;
XX }
XX }
XX if (nodes != NULL) free((char *)nodes);
XX nodes = NULL;
XX maxnode = -1;
XX for (i = 0; i < 26; i++) syms[i] = NULL;
XX }
XX
XXNODE *
XXnewnode(typ,len)
XXint typ,len;
XX {
XX NODE *n;
XX
XX n = (NODE *)malloc(sizeof(NODE));
XX n->type = typ;
XX if (typ == STRING) n->car = (NODE *)malloc(len+1);
XX else n->car = NULL;
XX n->cdr = NULL;
XX return(n);
XX }
XX
XXretnode(n)
XXNODE *n;
XX {
XX NODE *nnew;
XX
XX while (n != NULL) {
XX switch (n->type) {
XX case CONS:
XX retnode(n->car);
XX nnew = n->cdr;
XX free((char *)n);
XX n = nnew;
XX break;
XX
XX case STRING:
XX if (n->car != NULL) free((char *)n->car);
XX
XX default:
XX free((char *)n);
XX return;
XX }
XX }
XX }
XX
XX/************************ compilation of LISP code **********************/
XXchar
XXlisp_readchr(instr)
XXint instr;
XX {
XX char c;
XX
XX if (pushback != -1) {
XX c = (char)pushback;
XX if (pushback != 0) pushback = -1;
XX return(c);
XX }
XX
XX /* compress out comments */
XX c = ';';
XX while (c == ';') {
XX /* do we need to terminate this line */
XX if (c_doto == llength(c_dotp)) {
XX c_doto++;
XX if (instr) c = '\n';
XX else c = ' ';
XX return(c);
XX }
XX /* are we past the end of line */
XX while (c_doto >= llength(c_dotp)) {
XX c_dotp = c_dotp->l_fp;
XX c_doto = 0;
XX if (c_dotp == c_endp) {
XX pushback = 0;
XX return('\000');
XX }
XX }
XX c = lgetc(c_dotp,c_doto++);
XX if (instr) return(c);
XX
XX /* all white becomes a space */
XX if (c == '\n' || c == '\r' || c == '\t' || c == '\014') c = ' ';
XX
XX /* skip comments */
XX if (c == ';') c_doto = llength(c_dotp) + 1;
XX else return(c);
XX }
XX }
XX
XXNODE *
XXlisp_sexpr()
XX {
XX char c,d,str[256];
XX long sign,intval;
XX int i;
XX NODE *val,*cur,*nxt;
XX
XX c = ' ';
XX while (c == ' ') c = lisp_readchr(0);
XX
XX if (c == '\000' || c == ')') return(NULL);
XX
XX /* see if we have a list to put together */
XX if (c == '(') {
XX val = cur = NULL;
XX while ((nxt = lisp_sexpr()) != NULL) {
XX if (cur == NULL) {
XX cur = newnode(CONS,0);
XX val = cur;
XX }
XX else {
XX cur->cdr = newnode(CONS,0);
XX cur = cur->cdr;
XX }
XX cur->car = nxt;
XX }
XX return(val);
XX }
XX
XX /* see if we have an integer to gather */
XX if ((c >= '0' && c <= '9') || c == '-') {
XX sign = 1L;
XX intval = 0L;
XX if (c == '-') {
XX c = lisp_readchr(0);
XX if (c == '\000') return(NULL);
XX
XX /* no, it's really the subtraction operator */
XX if (c == ' ') {
XX str[0] = '-';
XX str[1] = '\000';
XX val = newnode(SUBR,0);
XX val->car = fncmatch(str);
XX if (val->car == NULL) {
XX mlwrite("Unknown function: %s",str);
XX longjmp(env[0],1);
XX }
XX return(val);
XX }
XX sign = -1L;
XX }
XX while (c >= '0' && c <= '9') {
XX intval = (10L * intval) + (long)(c - '0');
XX c = lisp_readchr(0);
XX if (c == '\000') return(NULL);
XX }
XX if (c != ' ') pushback = c;
XX intval *= sign;
XX val = newnode(INTEGER,0);
XX val->car = (NODE *)intval;
XX return(val);
XX }
XX
XX /* maybe it's a string */
XX if (c == '"') {
XX i = 0;
XX for (c = lisp_readchr(1); c != '"'; c = lisp_readchr(1)) {
XX if (c == '\000') return(NULL);
XX if (c != '\\') str[i++] = c;
XX else {
XX c = lisp_readchr(1);
XX if (c == '\000') return(NULL);
XX switch(c) {
XX case 'n': c = '\n'; break;
XX case 'r': c = '\r'; break;
XX case 't': c = '\t'; break;
XX case 'e': c = '\033'; break;
XX default:
XX if (c >= '0' && c <= '7') {
XX c = (c - '0') * 64;
XX d = lisp_readchr(1);
XX if (d == '\000') return(NULL);
XX if (d < '0' || d > '7') {
XX c /= 64;
XX pushback = d;
XX break;
XX }
XX c += (d - '0') * 8;
XX d = lisp_readchr(1);
XX if (d == '\000') return(NULL);
XX if (d < '0' || d > '7') {
XX c /= 8;
XX pushback = d;
XX break;
XX }
XX c += d - '0';
XX }
XX }
XX str[i++] = c;
XX }
XX if (i > 255) i = 255;
XX }
XX str[i] = '\000';
XX val = newnode(STRING,strlen(str));
XX strcpy((char *)val->car,(char *)str);
XX return(val);
XX }
XX
XX /* possibly a symbol */
XX str[0] = c;
XX c = lisp_readchr(0);
XX if (c == '\000') return(NULL);
XX if (str[0] >= 'a' && str[0] <= 'z' && (c == ' ' || c == ')')) {
XX val = newnode(SYMBOL,0);
XX val->car = (NODE *)(str[0] - 'a');
XX if (c != ' ') pushback = c;
XX return(val);
XX }
XX
XX /* must be a subr */
XX i = 1;
XX while (c != ' ' && c != ')') {
XX str[i++] = c;
XX c = lisp_readchr(0);
XX if (c == '\000') return(NULL);
XX if (i > 255) i = 255;
XX }
XX if (c != ' ') pushback = c;
XX str[i] = '\000';
XX val = newnode(SUBR,0);
XX val->car = fncmatch(str);
XX if (val->car == NULL) {
XX mlwrite("Unknown function: %s",str);
XX longjmp(env[0],1);
XX }
XX return(val);
XX }
XX
XXNODE *
XXcompilebuf(bp)
XXBUFFER *bp;
XX {
XX int i;
XX WINDOW *wp;
XX NODE *head,*val,*cur,*prv;
XX
XX mlwrite("Compiling buffer");
XX
XX /* Now walk through the buffer (compiling s-expers) */
XX c_endp = bp->b_linep;
XX c_dotp = bp->b_linep->l_fp;
XX c_doto = 0;
XX pushback = -1;
XX head = NULL;
XX while ((val=lisp_sexpr()) != NULL) {
XX cur = newnode(CONS,0);
XX cur->car = val;
XX cur->cdr = NULL;
XX if (head == NULL) head = cur;
XX else prv->cdr = cur;
XX prv = cur;
XX }
XX if (head == NULL) {
XX mlwrite("Compile of buffer failed!");
XX return(NULL);
XX }
XX else mlerase();
XX return(head);
XX }
XX
XX/************************ execution of compiled code *********************/
XX
XX/* dobuf: execute the contents of the buffer pointed to by the passed bp. */
XX
XXdobuf(f,n,bp)
XXint f,n;
XXBUFFER *bp;
XX {
XX NODE *head;
XX int oldcle,status;
XX
XX /* first make sure that the buffer is compiled */
XX if (setjmp(env[0])) return(FALSE);
XX head = compilebuf(bp);
XX
XX /* now execute the compiled code (as a progn) */
XX if (f == FALSE) n = 1;
XX while (n-- > 0) {
XX envnum = -1;
XX status = l_progn(head);
XX rettnode();
XX if (status != TRUE) break;
XX }
XX retnode(head);
XX return(status);
XX }
XX
XXl_progn(head)
XXNODE *head;
XX {
XX NODE *curr,*scr;
XX int jmp,oldcle,curenv;
XX
XX curr = head;
XX oldcle = clexec;
XX curenv = ++envnum;
XX if (envnum > 9) {
XX mlwrite("Too many PROGN nestings");
XX return(FALSE);
XX }
XX
XX /* set up for non-local goto's */
XX if ((jmp = setjmp(env[curenv])) != 0) {
XX clexec = oldcle;
XX if (jmp == PROGN_RETURN) {
XX envnum--;
XX return(TRUE);
XX }
XX curr = head;
XX while (curr != NULL) {
XX if (curr->type != CONS) {
XX envnum--;
XX return(FALSE);
XX }
XX if (curr->car->type == INTEGER && retval->type == INTEGER &&
XX (long)(curr->car->car) == (long)(retval->car)) break;
XX if (curr->car->type == STRING && retval->type == STRING &&
XX strcmp((char *)(curr->car->car),(char *)(retval->car))
XX == 0) break;
XX curr = curr->cdr;
XX }
XX
XX /* try finding the label at a higher level */
XX if (curr == NULL) longjmp(env[--envnum],PROGN_GO);
XX }
XX
XX /* actual progn loop */
XX while (curr != NULL) {
XX if (l_eval(curr->car) == FALSE) {
XX envnum--;
XX return(FALSE);
XX }
XX curr = curr->cdr;
XX }
XX envnum--;
XX return(TRUE);
XX }
XX
XXl_setq(expr)
XXNODE *expr;
XX {
XX long i;
XX char str[256],istr[20];
XX NODE *sym;
XX
XX if (expr == NULL || expr->type != CONS) return(FALSE);
XX sym = expr->car;
XX expr = expr->cdr;
XX if (sym == NULL || sym->type != SYMBOL) return(FALSE);
XX i = (long)sym->car;
XX str[0] = '\000';
XX
XX /* now concatenate parameters */
XX while (expr != NULL && expr->type == CONS) {
XX if (l_eval(expr->car) == FALSE) return(FALSE);
XX if (retval->type == STRING) strcat(str,(char *)retval->car);
XX else if (retval->type == INTEGER) {
XX sprintf(istr,"%ld",(long)retval->car);
XX strcat(str,istr);
XX }
XX expr = expr->cdr;
XX }
XX retval = newtnode(STRING,strlen(str));
XX strcpy((char *)retval->car,str);
XX
XX syms[i] = retval;
XX return(TRUE);
XX }
XX
XXl_if(expr)
XXNODE *expr;
XX {
XX NODE *thn,*els;
XX int tst,status;
XX
XX if (expr == NULL || expr->type != CONS) return(FALSE);
XX tst = 0;
XX if (l_eval(expr->car) != FALSE)
XX if ((retval->type == INTEGER && (long)retval->car != 0L) ||
XX (retval->type == STRING && *((char *)retval->car) != '\000'))
XX tst = 1;
XX
XX thn = expr->cdr;
XX if (thn != NULL) els = thn->cdr;
XX else els = NULL;
XX
XX if (tst) status = l_eval(thn->car);
XX else if (els != NULL) status = l_eval(els->car);
XX else {
XX retval = &TNODE;
XX status = TRUE;
XX }
XX return(status);
XX }
XX
XXl_eval(expr)
XXNODE *expr;
XX {
XX long i;
XX int p,q,status,oldcle,f,n;
XX NODE *func,*par[20];
XX INTRTN *fnc;
XX
XX if (expr == NULL) return(FALSE);
XX switch (expr->type) {
XX case INTEGER:
XX case STRING:
XX case SUBR:
XX retval = expr;
XX return(TRUE);
XX
XX case SYMBOL:
XX i = (long)expr->car;
XX retval = syms[i];
XX return(TRUE);
XX
XX case CONS:
XX if (l_eval(expr->car) == FALSE) return(FALSE);
XX func = retval;
XX if (func != NULL && func->type == INTEGER) {
XX f = TRUE;
XX i = (long)func->car;
XX n = i;
XX expr = expr->cdr;
XX if (l_eval(expr->car) == FALSE) return(FALSE);
XX func = retval;
XX }
XX else {
XX f = FALSE;
XX n = 1;
XX }
XX if (func == NULL || func->type != SUBR) return(FALSE);
XX fnc = (INTRTN *)(func->car);
XX expr = expr->cdr;
XX
XX /* take care of fsubr's in-line */
XX if (*fnc == l_progn || *fnc == l_setq || *fnc == l_if) {
XX status = TRUE;
XX while (n-- > 0) {
XX gblidx = 0;
XX status = (*fnc)(expr);
XX if (status != TRUE) return(status);
XX }
XX return(status);
XX }
XX
XX p = 0;
XX while (expr != NULL) {
XX if (l_eval(expr->car) == FALSE) return(FALSE);
XX par[p++] = retval;
XX expr = expr->cdr;
XX }
XX for (q = 0; q < p; q++) gblpar[q] = par[q];
XX gblidx = 0;
XX gblnum = p;
XX lstfnc = fnc;
XX oldcle = clexec;
XX clexec = TRUE;
XX retval = NULL;
XX status = (*fnc)(f,n);
XX clexec = oldcle;
XX if (retval == NULL) {
XX if (status) retval = &TNODE;
XX else retval = &FNODE;
XX status = TRUE;
XX }
XX return(status);
XX }
XX }
XX
XXnxtarg(tok)
XXchar *tok;
XX {
XX NODE *cur;
XX NBIND *ffp;
XX
XX if (gblidx >= gblnum) {
XX ffp = &names[0];
XX while (ffp->n_func != NULL && ffp->n_func != lstfnc) ++ffp;
XX if (ffp->n_func != NULL) mlwrite("Missing param for: %s",ffp->n_name);
XX else mlwrite("Missing paramater for function");
XX longjmp(env[0],1);
XX }
XX else cur = gblpar[gblidx++];
XX if (cur == NULL) {
XX *tok = '\000';
XX return(TRUE);
XX }
XX if (cur->type == STRING) {
XX strcpy(tok,(char *)cur->car);
XX return(TRUE);
XX }
XX if (cur->type == INTEGER) {
XX sprintf(tok,"%ld",(long)cur->car);
XX return(TRUE);
XX }
XX *tok = '\000';
XX return(TRUE);
XX }
XX
XXl_go(f,n)
XXint f,n;
XX {
XX if (gblpar[0] == NULL) return(FALSE);
XX retval = gblpar[0];
XX longjmp(env[envnum],PROGN_GO);
XX }
XX
XXl_return(f,n)
XXint f,n;
XX {
XX retval = gblpar[0];
XX longjmp(env[envnum],PROGN_RETURN);
XX }
XX
XXl_yank_str(f,n)
XXint f,n;
XX {
XX char str[256];
XX int i,c;
XX
XX for (i=0; i < 255 && (c=kremove(i)) >= 0; i++) str[i] = (char)c;
XX str[i] = '\000';
XX retval = newtnode(STRING,i);
XX strcpy((char *)retval->car,str);
XX return(TRUE);
XX }
XX
XXl_ask(f,n)
XXint f,n;
XX {
XX char c,str[256],inp[256];
XX int oldcle;
XX
XX gblidx = 0;
XX if (gblidx >= gblnum) strcpy(str,"Ask> ");
XX else nxtarg(str);
XX if (gblidx >= gblnum) inp[0] = '\000';
XX else nxtarg(inp);
XX while (inp[0] != '\000') {
XX strcat(str,inp);
XX if (gblidx >= gblnum) inp[0] = '\000';
XX else nxtarg(inp);
XX }
XX oldcle = clexec;
XX clexec = FALSE;
XX update();
XX if (batchmode) {
XX printf(str);
XX if (gets(inp) == NULL) inp[0] = '\000';
XX }
XX else mlreply(str,inp,255);
XX clexec = oldcle;
XX retval = newtnode(STRING,strlen(inp));
XX strcpy((char *)retval->car,inp);
XX return(TRUE);
XX }
XX
XXlong
XXmake_num(n)
XXNODE *n;
XX {
XX long i;
XX
XX if (n == NULL) return(0L);
XX if (n->type == INTEGER) return((long)n->car);
XX if (n->type == STRING) {
XX if (sscanf((char *)n->car," %ld",&i) != 1) return(0L);
XX return(i);
XX }
XX return(0L);
XX }
XX
XXmath_compute(op)
XXchar op;
XX {
XX long p1,p2;
XX
XX p1 = make_num(gblpar[0]);
XX p2 = make_num(gblpar[1]);
XX switch(op) {
XX case '=': retval = (p1==p2) ? &TNODE : &FNODE; return(TRUE);
XX case '#': retval = (p1!=p2) ? &TNODE : &FNODE; return(TRUE);
XX case '>': retval = (p1>p2) ? &TNODE : &FNODE; return(TRUE);
XX case ']': retval = (p1>=p2) ? &TNODE : &FNODE; return(TRUE);
XX case '<': retval = (p1<p2) ? &TNODE : &FNODE; return(TRUE);
XX case '[': retval = (p1<=p2) ? &TNODE : &FNODE; return(TRUE);
XX case 'n': retval = (p1==0) ? &TNODE : &FNODE; return(TRUE);
XX case 'a': retval = (p1&&p2) ? &TNODE : &FNODE; return(TRUE);
XX case 'o': retval = (p1||p2) ? &TNODE : &FNODE; return(TRUE);
XX }
XX retval = newtnode(INTEGER,0);
XX switch (op) {
XX case '+': retval->car = (NODE *)(p1 + p2); return(TRUE);
XX case '-': retval->car = (NODE *)(p1 - p2); return(TRUE);
XX case '*': retval->car = (NODE *)(p1 * p2); return(TRUE);
XX case '/': retval->car = (NODE *)(p1 / ((p2!=0)?p2:1L)); return(TRUE);
XX case '%': retval->car = (NODE *)(p1 % p2); return(TRUE);
XX case '&': retval->car = (NODE *)(p1 & p2); return(TRUE);
XX case '|': retval->car = (NODE *)(p1 | p2); return(TRUE);
XX }
XX return(FALSE);
XX }
XX
XXl_add(f,n) { return(math_compute('+')); }
XXl_sub(f,n) { return(math_compute('-')); }
XXl_mul(f,n) { return(math_compute('*')); }
XXl_div(f,n) { return(math_compute('/')); }
XXl_mod(f,n) { return(math_compute('%')); }
XXl_bitand(f,n) { return(math_compute('&')); }
XXl_bitor(f,n) { return(math_compute('|')); }
XXl_eql(f,n) { return(math_compute('=')); }
XXl_neq(f,n) { return(math_compute('#')); }
XXl_gt(f,n) { return(math_compute('>')); }
XXl_ge(f,n) { return(math_compute(']')); }
XXl_lt(f,n) { return(math_compute('<')); }
XXl_le(f,n) { return(math_compute('[')); }
XXl_not(f,n) { return(math_compute('n')); }
XXl_and(f,n) { return(math_compute('a')); }
XXl_or(f,n) { return(math_compute('o')); }
XX
XXl_eq(f,n)
XXint f,n;
XX {
XX retval = &FNODE;
XX if (gblpar[0] == NULL && gblpar[1] == NULL) retval = &TNODE;
XX else if (gblpar[0] != NULL && gblpar[1] != NULL &&
XX gblpar[0]->type == gblpar[1]->type) {
XX if (gblpar[0]->type == INTEGER &&
XX (long)gblpar[0]->car == (long)gblpar[1]->car) retval = &TNODE;
XX else if (gblpar[0]->type == STRING &&
XX strcmp((char *)gblpar[0]->car,(char *)gblpar[1]->car) == 0)
XX retval = &TNODE;
XX }
XX return(TRUE);
XX }
XX
XXl_curchr(f,n)
XXint f,n;
XX {
XX long i;
XX
XX if (curwp->w_doto >= llength(curwp->w_dotp)) i = (long)'\n';
XX else i = (long)lgetc(curwp->w_dotp,curwp->w_doto);
XX retval = newtnode(INTEGER,0);
XX retval->car = (NODE *)i;
XX return(TRUE);
XX }
XX
XXl_curlin(f,n)
XXint f,n;
XX {
XX long i;
XX LINE *clp;
XX
XX clp = lforw(curbp->b_linep);
XX i = 0L;
XX while (clp != curwp->w_dotp) {
XX clp = lforw(clp);
XX i++;
XX }
XX retval = newtnode(INTEGER,0);
XX retval->car = (NODE *)i;
XX return(TRUE);
XX }
XX
XXl_curcol(f,n)
XXint f,n;
XX {
XX long i;
XX
XX i = (long)getccol(FALSE);
XX retval = newtnode(INTEGER,0);
XX retval->car = (NODE *)i;
XX return(TRUE);
XX }
XX
XXl_curbuf(f,n)
XXint f,n;
XX {
XX
XX retval = newtnode(STRING,strlen(curbp->b_bname));
XX strcpy((char *)retval->car,curbp->b_bname);
XX return(TRUE);
XX }
XX
XXl_princ(f,n)
XXint f,n;
XX {
XX char str[256];
XX int i;
XX
XX if (f == FALSE) n = 1;
XX while (n-- > 0) {
XX gblidx = 0;
XX if (gblidx >= gblnum) str[0] = '\000';
XX else nxtarg(str);
XX while (str[0] != '\000') {
XX for (i=0; str[i] != '\000'; i++) {
XX if (str[i] == '\n') lnewline(FALSE,1);
XX else linsert(1,str[i]);
XX }
XX if (gblidx >= gblnum) str[0] = '\000';
XX else nxtarg(str);
XX }
XX }
XX return(TRUE);
XX }
XX
XX
XX/* execute a command line to be typed in */
XXexeccmd(f,n)
XXint f,n;
XX {
XX mlwrite("Not implemented yet");
XX }
XX
XX/* execute the contents of a named buffer */
XXexecbuf(f,n)
XXint f,n;
XX {
XX register BUFFER *bp; /* ptr to buffer to execute */
XX register int status; /* status return */
XX char bufn[NBUFN]; /* name of buffer to execute */
XX
XX /* find out what buffer the user wants to execute */
XX if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE) return(status);
XX
XX /* find the pointer to that buffer */
XX if ((bp=bfind(bufn, TRUE, 0)) == NULL) return(FALSE);
XX
XX /* and now execute it as asked */
XX if ((status = dobuf(f,n,bp)) != TRUE) return(status);
XX return(TRUE);
XX }
XX
XXexecfile(f, n) /* execute a series of commands in a file */
XXint f, n; /* default flag and numeric arg to pass on to file */
XX {
XX register int status; /* return status of name query */
XX char *fname[NSTRING]; /* name of file to execute */
XX
XX if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE) return(status);
XX
XX /* otherwise, execute it */
XX if ((status=dofile(f,n,fname)) != TRUE) return(status);
XX
XX return(TRUE);
XX }
XX
XX/* dofile: yank a file into a buffer and execute it
XX if there are no errors, delete the buffer on exit */
XX
XXdofile(f,n,fname)
XXint f,n;
XXchar *fname; /* file name to execute */
XX {
XX register BUFFER *bp; /* buffer to place file to exeute */
XX register BUFFER *cb; /* temp to hold current buf while we read */
XX register int status; /* results of various calls */
XX char bname[NBUFN]; /* name of buffer */
XX
XX makename(bname, fname); /* derive the name of the buffer */
XX if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
XX return(FALSE);
XX
XX bp->b_mode = MDVIEW; /* mark the buffer as read only */
XX cb = curbp; /* save the old buffer */
XX curbp = bp; /* make this one current */
XX /* and try to read in the file to execute */
XX if ((status = readin(fname, FALSE)) != TRUE) {
XX curbp = cb; /* restore the current buffer */
XX return(status);
XX }
XX
XX /* go execute it! */
XX curbp = cb; /* restore the current buffer */
XX if ((status = dobuf(f,n,bp)) != TRUE) return(status);
XX
XX /* if not displayed, remove the now unneeded buffer and exit */
XX if (bp->b_nwnd == 0) zotbuf(bp);
XX return(TRUE);
XX }
XX
XX/* execute the startup file */
XX
XXstartup()
XX {
XX register int status; /* status of I/O operations */
XX register int i; /* index into help file names */
XX char fname[NSTRING]; /* buffer to construct file name in */
XX
XX char *homedir; /* pointer to your home directory */
XX char *getenv();
XX
XX#if ULTRIX | AMIGA
XX /* are we on a slow terminal */
XX if (getenv("SLOWTERM") != NULL) slowterm = TRUE;
XX
XX /* get the HOME from the environment */
XX if ((homedir = getenv("HOME")) != NULL) {
XX /* build the file name */
XX strcpy(fname, homedir);
XX strcat(fname, "/");
XX strcat(fname, pathname[0]);
XX
XX /* and test it */
XX status = ffropen(fname);
XX if (status == FIOSUC) {
XX ffclose();
XX return(dofile(FALSE,1,fname));
XX }
XX }
XX#endif
XX#if VMS
XX /* are we on a slow terminal */
XX if (getenv("EMACSVAR_SLOWTERM") != NULL) slowterm = TRUE;
XX
XX /* get the HOME from the environment */
XX if ((homedir = getenv("SYS$LOGIN")) != NULL) {
XX /* build the file name */
XX strcpy(fname, homedir);
XX strcat(fname, pathname[0]);
XX
XX /* and test it */
XX status = ffropen(fname);
XX if (status == FIOSUC) {
XX ffclose();
XX return(dofile(FALSE,1,fname));
XX }
XX }
XX#endif
XX
XX /* search through the list of startup files */
XX for (i=2; i < NPNAMES; i++) {
XX strcpy(fname, pathname[i]);
XX strcat(fname, pathname[0]);
XX status = ffropen(fname);
XX if (status == FIOSUC) break;
XX }
XX
XX /* if it isn't around, don't sweat it */
XX if (status == FIOFNF) return(TRUE);
XX
XX ffclose(); /* close the file to prepare for to read it in */
XX
XX return(dofile(FALSE,1,fname));
XX }
XX
SHAR_EOF
if test 22291 -ne "`wc -c lisp.c`"
then
echo shar: error transmitting lisp.c '(should have been 22291 characters)'
fi
echo shar: extracting lock.c
sed 's/^XX//' << \SHAR_EOF > lock.c
XX/* LOCK: File locking command routines for MicroEMACS
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if FILOCK
XX#if ULTRIX
XX
XXchar *lname[NLOCKS]; /* names of all locked files */
XXint numlocks; /* # of current locks active */
XX
XX/* lockchk: check a file for locking and add it to the list */
XX
XXlockchk(fname)
XX
XXchar *fname; /* file to check for a lock */
XX
XX {
XX register int i; /* loop indexes */
XX register int status; /* return status */
XX char *undolock();
XX
XX /* check to see if that file is already locked here */
XX if (numlocks > 0) for (i=0; i < numlocks; ++i)
XX if (strcmp(fname, lname[i]) == 0) return(TRUE);
XX
XX /* if we have a full locking table, bitch and leave */
XX if (numlocks == NLOCKS) {
XX mlwrite("LOCK ERROR: Lock table full");
XX return(ABORT);
XX }
XX
XX /* next, try to lock it */
XX status = lock(fname);
XX if (status == ABORT) /* file is locked, no override */
XX return(ABORT);
XX if (status == FALSE) /* locked, overriden, dont add to table */
XX return(TRUE);
XX
XX /* we have now locked it, add it to our table */
XX lname[++numlocks - 1] = (char *)malloc(strlen(fname) + 1);
XX if (lname[numlocks - 1] == NULL) { /* malloc failure */
XX undolock(fname); /* free the lock */
XX mlwrite("Cannot lock, out of memory");
XX --numlocks;
XX return(ABORT);
XX }
XX
XX /* everthing is cool, add it to the table */
XX strcpy(lname[numlocks-1], fname);
XX return(TRUE);
XX }
XX
XX/* lockrel: release all the file locks so others may edit */
XX
XXlockrel()
XX
XX {
XX register int i; /* loop index */
XX
XX if (numlocks > 0) for (i=0; i < numlocks; ++i) {
XX unlock(lname[i]);
XX free(lname[i]);
XX }
XX numlocks = 0;
XX }
XX
XX/* lock: Check and lock a file from access by others
XXreturns TRUE = files was not locked and now is
XXFALSE = file was locked and overridden
XXABORT = file was locked, abort command
XX */
XX
XXlock(fname)
XX
XXchar *fname; /* file name to lock */
XX
XX {
XX register char *locker; /* lock error message */
XX register int status; /* return status */
XX char msg[NSTRING]; /* message string */
XX char *dolock();
XX
XX /* attempt to lock the file */
XX locker = dolock(fname);
XX if (locker == NULL) /* we win */
XX return(TRUE);
XX
XX /* file failed...abort */
XX if (strncmp(locker, "LOCK", 4) == 0) {
XX mlwrite(locker);
XX return(ABORT);
XX }
XX
XX /* someone else has it....override? */
XX strcpy(msg, "File in use by ");
XX strcat(msg, locker);
XX strcat(msg, ", overide?");
XX status = mlyesno(msg); /* ask them */
XX if (status == TRUE) return(FALSE);
XX else
XX return(ABORT);
XX }
XX
XX/* unlock: Unlock a file
XXthis only warns the user if it fails
XX */
XX
XXunlock(fname)
XX
XXchar *fname; /* file to unlock */
XX
XX {
XX register char *locker; /* undolock return string */
XX char *undolock();
XX
XX /* unclock and return */
XX locker = undolock(fname);
XX if (locker == NULL) return(TRUE);
XX
XX /* report the error and come back */
XX mlwrite(locker);
XX return(FALSE);
XX }
XX#endif
XX#else
XXlckhello() /* dummy function */
XX {
XX }
XX#endif
XX
SHAR_EOF
if test 3010 -ne "`wc -c lock.c`"
then
echo shar: error transmitting lock.c '(should have been 3010 characters)'
fi
echo shar: extracting main.c
sed 's/^XX//' << \SHAR_EOF > main.c
XX/*
XX* This program is in public domain; written by Dave G. Conroy.
XX* This file contains the main driving routine, and some keyboard processing
XX* code, for the MicroEMACS screen editor.
XX*
XX* REVISION HISTORY:
XX*
XX* 1.0 Steve Wilhite, 30-Nov-85
XX* 2.0 George Jones, 12-Dec-85
XX* 3.0 Daniel Lawrence, 29-Dec-85
XX* xxx Dave Wecker 29-June-86
XX*/
XX
XX#include <stdio.h>
XX
XX/* make global definitions not external */
XX
XX#define maindef
XX
XX#include "estruct.h"
XX#include "efunc.h"
XX#include "edef.h"
XX#include "ebind.h"
XX
XX#if VMS
XX#include <ssdef.h>
XX#define GOOD (SS$_NORMAL)
XX#endif
XX
XX#ifndef GOOD
XX#define GOOD 0
XX#endif
XX
XX#if ULTRIX
XX#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
XX#define IOC_OUT 0x40000000 /* copy out parameters */
XX#define _IOR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
XX#define FIONREAD _IOR(f, 127, int) /* get # bytes to read */
XX#endif
XX
XX#if AMIGA
XXextern short int Enable_Abort;
XX#endif
XX
XXshort doflashing = TRUE;
XX
XXmain(argc, argv)
XXchar *argv[];
XX {
XX register int c;
XX register int f;
XX int n;
XX register int mflag;
XX register BUFFER *bp;
XX register int ffile; /* first file flag */
XX register int carg; /* current arg to scan */
XX int basec; /* c stripped of meta character */
XX int viewflag; /* are we starting in view mode? */
XX char bname[NBUFN]; /* buffer name of file to read */
XX char *bfile; /* batch file name */
XX int s;
XX WINDOW *wp;
XX
XX /* initialize the editor and process the startup file */
XX
XX#if AMIGA
XX Enable_Abort = 0;
XX#endif
XX
XX /* pre scan the command line for the batchmode switch */
XX for (carg = 1; carg < argc; ++carg)
XX if (argv[carg][0] == '-' && (argv[carg][1]|' ') == 'b') {
XX batchmode = TRUE;
XX break;
XX }
XX
XX strcpy(bname, "main"); /* default buffer name */
XX vtinit(); /* Displays. */
XX edinit(bname); /* Buffers, windows. */
XX startup(); /* execute .emacsrc if there */
XX viewflag = FALSE;
XX ffile = TRUE; /* no file to edit yet */
XX update(); /* let the user know we are here */
XX
XX /* scan through the command line and get the files to edit */
XX for (carg = 1; carg < argc; ++carg) {
XX /* if its a switch, process it */
XX if (argv[carg][0] == '-') {
XX switch (argv[carg][1]|' ') {
XX case 'v': /* -v for View File */
XX viewflag = TRUE;
XX break;
XX
XX case 'e': /* -e for Edit file */
XX viewflag = FALSE;
XX break;
XX
XX case 'b': /* -b for batch mode */
XX if (++carg >= argc) exit(1);
XX bfile = argv[carg];
XX break;
XX
XX default: /* unknown switch */
XX /* ignore this for now */
XX break;
XX }
XX }
XX else { /* process a file name */
XX /* set up a buffer for this file */
XX makename(bname, argv[carg]);
XX
XX /* if this is the first file, read it in */
XX if (ffile) {
XX bp = curbp;
XX makename(bname, argv[carg]);
XX strcpy(bp->b_bname, bname);
XX strcpy(bp->b_fname, argv[carg]);
XX readin(argv[carg], (viewflag==FALSE));
XX bp->b_dotp = bp->b_linep;
XX bp->b_doto = 0;
XX ffile = FALSE;
XX }
XX else {
XX /* visit the file */
XX if ((wp = wpopup()) != NULL) {
XX curwp = wp;
XX curbp = wp->w_bufp;
XX }
XX if (getfile(argv[carg],FALSE)) {
XX wp = wheadp;
XX while (wp != NULL) {
XX wp->w_flag |= WFMODE;
XX wp = wp->w_wndp;
XX }
XX }
XX bp = curbp;
XX }
XX
XX /* set the view mode appropriatly */
XX if (viewflag) bp->b_mode |= MDVIEW;
XX }
XX }
XX
XX /* setup to process commands */
XX lastflag = 0; /* Fake last flags. */
XX
XX /* if in batch mode... do the batch file and get out */
XX if (batchmode) {
XX dofile(FALSE,1,bfile);
XX quit(TRUE,1);
XX }
XX
XX update();
XX
XX while (TRUE) { /* do top level forever */
XX
XX#if ULTRIX
XX /* sit in a subprocess wait loop */
XX if (procbuf != NULL) readsubproc();
XX#endif
XX /* do the real top level processing */
XX dotoplevel();
XX }
XX }
XX
XXdotoplevel() {
XX register int c,basec,f,mflag;
XX int n;
XX
XXloop:
XX update();
XX
XX#if ULTRIX
XX ioctl(0,FIONREAD,&n);
XX if (n < 1 && procbuf != NULL) return;
XX#endif
XX
XX c = getkey();
XX if (mpresf != FALSE) {
XX mlerase();
XX update();
XX#if CLRMSG
XX if (c == ' ') /* ITS EMACS does this */
XX goto loop;
XX#endif
XX }
XX f = FALSE;
XX n = 1;
XX
XX /* do META-# processing if needed */
XX
XX basec = c & ~META; /* strip meta char off if there */
XX if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
XX f = TRUE; /* there is a # arg */
XX n = 0; /* start with a zero default */
XX mflag = 1; /* current minus flag */
XX c = basec; /* strip the META */
XX while ((c >= '0' && c <= '9') || (c == '-')) {
XX if (c == '-') {
XX /* already hit a minus or digit? */
XX if ((mflag == -1) || (n != 0)) break;
XX mflag = -1;
XX }
XX else {
XX n = n * 10 + (c - '0');
XX }
XX if ((n == 0) && (mflag == -1)) /* lonely - */
XX mlwrite("Arg:");
XX else
XX mlwrite("Arg: %d",n * mflag);
XX
XX c = getkey(); /* get the next key */
XX }
XX n = n * mflag; /* figure in the sign */
XX }
XX
XX /* do ^U repeat argument processing */
XX
XX if (c == (CTRL|'U')) { /* ^U, start argument */
XX f = TRUE;
XX n = 4; /* with argument of 4 */
XX mflag = 0; /* that can be discarded. */
XX mlwrite("Arg: 4");
XX while ((c=getkey()) >='0' && c<='9' || c==(CTRL|'U') || c=='-'){
XX if (c == (CTRL|'U')) n = n*4;
XX /*
XX * If dash, and start of argument string, set arg.
XX * to -1. Otherwise, insert it.
XX */
XX else if (c == '-') {
XX if (mflag) break;
XX n = 0;
XX mflag = -1;
XX }
XX /*
XX * If first digit entered, replace previous argument
XX * with digit and set sign. Otherwise, append to arg.
XX */
XX else {
XX if (!mflag) {
XX n = 0;
XX mflag = 1;
XX }
XX n = 10*n + c - '0';
XX }
XX mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
XX }
XX /*
XX * Make arguments preceded by a minus sign negative and change
XX * the special argument "^U -" to an effective "^U -1".
XX */
XX if (mflag == -1) {
XX if (n == 0) n++;
XX n = -n;
XX }
XX }
XX if (c == (CTRL|'X')) { /* ^X is a prefix */
XX c = getkey();
XX if ((c & 0x77) >='a' && (c & 0x77) <= 'z') c -= 0x20;
XX c |= CTLX;
XX }
XX
XX if (kbdmip != NULL) { /* Save macro strokes. */
XX if (c!=(CTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
XX ctrlg(FALSE, 0);
XX goto loop;
XX }
XX if (f != FALSE) {
XX *kbdmip++ = (CTRL|'U');
XX *kbdmip++ = n;
XX }
XX *kbdmip++ = c;
XX }
XX execute(c, f, n); /* Do it. */
XX goto loop;
XX }
XX
XX/*
XX* Initialize all of the buffers and windows. The buffer name is passed down
XX* as an argument, because the main routine may have been told to read in a
XX* file by default, and we want the buffer name to be right.
XX*/
XXedinit(bname)
XXchar bname[];
XX {
XX register BUFFER *bp;
XX register WINDOW *wp;
XX char *malloc();
XX
XX bp = bfind(bname, TRUE, 0); /* First buffer */
XX blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer */
XX wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window */
XX if (bp==NULL || wp==NULL || blistp==NULL) exit(1);
XX curbp = bp; /* Make this current */
XX wheadp = wp;
XX curwp = wp;
XX wp->w_wndp = NULL; /* Initialize window */
XX wp->w_bufp = bp;
XX bp->b_nwnd = 1; /* Displayed. */
XX wp->w_linep = bp->b_linep;
XX wp->w_dotp = bp->b_linep;
XX wp->w_doto = 0;
XX wp->w_markp = NULL;
XX wp->w_marko = 0;
XX wp->w_toprow = 0;
XX wp->w_ntrows = term.t_nrow-1; /* "-1" for mode line. */
XX wp->w_force = 0;
XX wp->w_flag = WFMODE|WFHARD; /* Full. */
XX }
XX
XX/*
XX* This is the general command execution routine. It handles the fake binding
XX* of all the keys to "self-insert". It also clears out the "thisflag" word,
XX* and arranges to move it to the "lastflag", so that the next command can
XX* look at it. Return the status of command.
XX*/
XXexecute(c, f, n)
XX {
XX register KEYTAB *ktp;
XX register int status;
XX
XX ktp = &keytab[0]; /* Look in key table. */
XX while (ktp->k_fp != NULL) {
XX if (ktp->k_code == c) {
XX thisflag = 0;
XX status = (*ktp->k_fp)(f, n);
XX lastflag = thisflag;
XX return (status);
XX }
XX ++ktp;
XX }
XX
XX /*
XX * If a space was typed, fill column is defined, the argument is non-
XX * negative, wrap mode is enabled, and we are now past fill column,
XX * and we are not read-only, perform word wrap.
XX */
XX if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 && n >= 0 && getccol(FALSE) > fillcol &&
XX (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
XX wrapword();
XX
XX if ((c>=0x20 && c<=0x7E) /* Self inserting. */
XX || (c>=0xA0 && c<=0xFE)) {
XX if (n <= 0) { /* Fenceposts. */
XX lastflag = 0;
XX return (n<0 ? FALSE : TRUE);
XX }
XX thisflag = 0; /* For the future. */
XX status = linsert(n, c);
XX c &= 0x7f;
XX if (status && doflashing &&
XX (c == ')' || c == ']' || c == '}' || c == '>')) flash(c);
XX lastflag = thisflag;
XX return (status);
XX }
XXmlwrite("\007[Key not bound]"); /* complain */
XXlastflag = 0; /* Fake last flags. */
XXreturn (FALSE);
XX}
XX
XX/*
XX* Read in a key.
XX* Do the standard keyboard preprocessing. Convert the keys to the internal
XX* character set.
XX*/
XXgetkey()
XX {
XX register int c;
XX
XX c = (*term.t_getchar)();
XX if (c == METACH || c == 0x9B) { /* Apply M- prefix */
XX if (c == METACH) c = getctl();
XX else c = '['; /* kludge for the AMIGA CSI*/
XX
XX if (c == '[' || c == 'O') {
XX c = (*term.t_getchar)() & 0x7F;
XX if (c == 'P') {
XX c = (*term.t_getchar)();
XX if (c != METACH && c != 0x9B) return (META | (c&0x7f));
XX if (c == METACH) c = getctl(); /* kludge for AMIGA CSI */
XX else c = '[';
XX
XX if (c == '[' || c == 'O') {
XX c = (*term.t_getchar)() & 0x7F;
XX if (c != ']') return (GOLD | c);
XX c = getctl();
XX if (c == '<') return (0x7f);
XX return (GOLD | CTRL | c);
XX }
XX return (GOLD | META | c);
XX }
XX if (c != ']') return (SPEC | c);
XX c = getctl();
XX if (c == '<') return (0x7F);
XX return (CTRL | c);
XX }
XX return (META | c);
XX }
XX if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
XX c = CTRL | (c+'@');
XX return (c);
XX }
XX
XX/*
XX* Get a key.
XX* Apply control modifications to the read key.
XX*/
XXgetctl()
XX {
XX register int c;
XX
XX c = (*term.t_getchar)();
XX if (c>='a' && c<='z') /* Force to upper */
XX c -= 0x20;
XX if (c>=0x00 && c<=0x1F) /* C0 control -> C- */
XX c = CTRL | (c+'@');
XX return (c);
XX }
XX
XX/*
XX* Fancy quit command, as implemented by Norm. If the any buffer has
XX* changed do a write on that buffer and exit emacs, otherwise simply exit.
XX*/
XXquickexit(f, n)
XX {
XX register BUFFER *bp; /* scanning pointer to buffers */
XX
XX bp = bheadp;
XX while (bp != NULL) {
XX if ((bp->b_flag&BFCHG) != 0 /* Changed. */
XX && (bp->b_flag&BFTEMP) == 0) { /* Real. */
XX curbp = bp; /* make that buffer cur */
XX mlwrite("[Saving %s]",bp->b_fname);
XX filesave(f, n);
XX }
XX bp = bp->b_bufp; /* on to the next buffer */
XX }
XX quit(f, n); /* conditionally quit */
XX }
XX
XX/*
XX* Quit command. If an argument, always quit. Otherwise confirm if a buffer
XX* has been changed and not written out. Normally bound to "C-X C-C".
XX*/
XXquit(f, n)
XX {
XX register int s;
XX
XX if (f != FALSE /* Argument forces it. */
XX || anycb() == FALSE /* All buffers clean. */
XX /* User says it's OK. */
XX || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
XX#if FILOCK
XX lockrel();
XX#endif
XX vttidy();
XX exit(GOOD);
XX }
XX mlwrite("");
XX return (s);
XX }
XX
XX/*
XX* Begin a keyboard macro.
XX* Error if not at the top level in keyboard processing. Set up variables and
XX* return.
XX*/
XXctlxlp(f, n)
XX {
XX if (kbdmip!=NULL || kbdmop!=NULL) {
XX mlwrite("Not now");
XX return (FALSE);
XX }
XX mlwrite("[Start macro]");
XX kbdmip = &kbdm[0];
XX return (TRUE);
XX }
XX
XX/*
XX* End keyboard macro. Check for the same limit conditions as the above
XX* routine. Set up the variables and return to the caller.
XX*/
XXctlxrp(f, n)
XX {
XX if (kbdmip == NULL) {
XX mlwrite("Not now");
XX return (FALSE);
XX }
XX mlwrite("[End macro]");
XX kbdmip = NULL;
XX return (TRUE);
XX }
XX
XX/*
XX* Execute a macro.
XX* The command argument is the number of times to loop. Quit as soon as a
XX* command gets an error. Return TRUE if all ok, else FALSE.
XX*/
XXctlxe(f, n)
XX {
XX register int c;
XX register int af;
XX register int an;
XX register int s;
XX
XX if (kbdmip!=NULL || kbdmop!=NULL) {
XX mlwrite("Not now");
XX return (FALSE);
XX }
XX if (n <= 0) return (TRUE);
XX do {
XX kbdmop = &kbdm[0];
XX doflashing = FALSE;
XX do {
XX af = FALSE;
XX an = 1;
XX if ((c = *kbdmop++) == (CTRL|'U')) {
XX af = TRUE;
XX an = *kbdmop++;
XX c = *kbdmop++;
XX }
XX s = TRUE;
XX }
XX while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
XX doflashing = TRUE;
XX kbdmop = NULL;
XX }
XX while (s==TRUE && --n);
XX return (s);
XX }
XX
XX/*
XX* Abort.
XX* Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
XX* Sometimes called as a routine, to do general aborting of stuff.
XX*/
XXctrlg(f, n)
XX {
XX (*term.t_beep)();
XX if (kbdmip != NULL) {
XX kbdm[0] = (CTLX|')');
XX kbdmip = NULL;
XX }
XX mlwrite("[Aborted]");
XX return (ABORT);
XX }
XX
XX/* tell the user that this command is illegal while we are in
XX VIEW (read-only) mode */
XX
XXrdonly()
XX
XX {
XX (*term.t_beep)();
XX mlwrite("[Key illegal in VIEW mode]");
XX return(FALSE);
XX }
SHAR_EOF
if test 13526 -ne "`wc -c main.c`"
then
echo shar: error transmitting main.c '(should have been 13526 characters)'
fi
echo shar: extracting random.c
sed 's/^XX//' << \SHAR_EOF > random.c
XX/*
XX * This file contains the command processing functions for a number of random
XX * commands. There is no functional grouping here, for sure.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XXint tabsize; /* Tab size (0: use real tabs) */
XX
XX/*
XX * Set fill column to n.
XX
XX */
XXsetfillcol(f, n)
XX {
XX fillcol = n;
XX mlwrite("[Fill column is %d]",n);
XX return(TRUE);
XX }
XX
XX/*
XX * Display the current position of the cursor, in origin 1 X-Y coordinates,
XX * the character that is under the cursor (in octal), and the fraction of the
XX * text that is before the cursor. The displayed column is not the current
XX * column, but the column that would be used on an infinite width display.
XX * Normally this is bound to "C-X =".
XX */
XXshowcpos(f, n)
XX {
XX register LINE *clp;
XX register long nch;
XX register int cbo;
XX register long nbc;
XX register int cac;
XX register int ratio;
XX register int col;
XX register int i;
XX register int c;
XX
XX clp = lforw(curbp->b_linep); /* Grovel the data. */
XX cbo = 0;
XX nch = 0;
XX for (;;) {
XX if (clp==curwp->w_dotp && cbo==curwp->w_doto) {
XX nbc = nch;
XX if (cbo == llength(clp)) cac = '\n';
XX else
XX cac = lgetc(clp, cbo);
XX }
XX if (cbo == llength(clp)) {
XX if (clp == curbp->b_linep) break;
XX clp = lforw(clp);
XX cbo = 0;
XX }
XX else
XX ++cbo;
XX ++nch;
XX }
XX col = getccol(FALSE); /* Get real column. */
XX ratio = 0; /* Ratio before dot. */
XX if (nch != 0) ratio = (100L*nbc) / nch;
XX mlwrite("X=%d Y=%d CH=0x%x .=%D (%d%% of %D)",
XX col+1, currow+1, cac, nbc, ratio, nch);
XX return (TRUE);
XX }
XX
XX/*
XX * Return current column. Stop at first non-blank given TRUE argument.
XX */
XXgetccol(bflg)
XXint bflg;
XX {
XX register int c, i, col;
XX col = 0;
XX for (i=0; i<curwp->w_doto; ++i) {
XX c = lgetc(curwp->w_dotp, i);
XX if (c!=' ' && c!='\t' && bflg) break;
XX if (c == '\t') col |= 0x07;
XX else if (c<0x20 || c==0x7F) ++col;
XX ++col;
XX }
XX return(col);
XX }
XX
XX/*
XX * Twiddle the two characters on either side of dot. If dot is at the end of
XX * the line twiddle the two characters before it. Return with an error if dot
XX * is at the beginning of line; it seems to be a bit pointless to make this
XX * work. This fixes up a very common typo with a single stroke. Normally bound
XX * to "C-T". This always works within a line, so "WFEDIT" is good enough.
XX */
XXtwiddle(f, n)
XX {
XX register LINE *dotp;
XX register int doto;
XX register int cl;
XX register int cr;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX dotp = curwp->w_dotp;
XX doto = curwp->w_doto;
XX if (doto==llength(dotp) && --doto<0) return (FALSE);
XX cr = lgetc(dotp, doto);
XX if (--doto < 0) return (FALSE);
XX cl = lgetc(dotp, doto);
XX lputc(dotp, doto+0, cr);
XX lputc(dotp, doto+1, cl);
XX lchange(WFEDIT);
XX return (TRUE);
XX }
XX
XX/*
XX * Quote the next character, and insert it into the buffer. All the characters
XX * are taken literally, with the exception of the newline, which always has
XX * its line splitting meaning. The character is always read, even if it is
XX * inserted 0 times, for regularity. Bound to "C-Q"
XX */
XXquote(f, n)
XX {
XX register int s;
XX register int c;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX c = getkey();
XX if (c & CTRL) c -= (CTRL|'@');
XX c &= 0x7F;
XX
XX if (n < 0) return (FALSE);
XX if (n == 0) return (TRUE);
XX if (c == '\n') {
XX do {
XX s = lnewline();
XX }
XX while (s==TRUE && --n);
XX return (s);
XX }
XX return (linsert(n, c));
XX }
XX
XX/*
XX * Set tab size if given non-default argument (n <> 1). Otherwise, insert a
XX * tab into file. If given argument, n, of zero, change to true tabs.
XX * If n > 1, simulate tab stop every n-characters using spaces. This has to be
XX * done in this slightly funny way because the tab (in ASCII) has been turned
XX * into "C-I" (in 10 bit code) already. Bound to "C-I".
XX */
XXtab(f, n)
XX {
XX register int curcol,newcol,nxttab;
XX
XX if (n < 0) return (FALSE);
XX if (n == 0 || n > 1) {
XX tabsize = n;
XX return(TRUE);
XX }
XX if (! tabsize) return(linsert(1, '\t'));
XX
XX /* try to compress out spaces whenever possible */
XX curcol = getccol(FALSE);
XX newcol = curcol + (tabsize - (curcol % tabsize));
XX while (curwp->w_doto > 0 && curwp->w_dotp->l_text[curwp->w_doto-1] == ' ')
XX backdel(FALSE,1);
XX
XX curcol = getccol(FALSE);
XX nxttab = 8 - (curcol % 8);
XX while (nxttab+curcol <= newcol) {
XX if (linsert(1,'\t') == FALSE) return(FALSE);
XX curcol += nxttab;
XX nxttab = 8;
XX }
XX if (newcol > curcol) return(linsert(newcol-curcol,' '));
XX return(TRUE);
XX }
XX
XX/*
XX * Open up some blank space. The basic plan is to insert a bunch of newlines,
XX * and then back up over them. Everything is done by the subcommand
XX * procerssors. They even handle the looping. Normally this is bound to "C-O".
XX */
XXopenline(f, n)
XX {
XX register int i;
XX register int s;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX if (n == 0) return (TRUE);
XX i = n; /* Insert newlines. */
XX do {
XX s = lnewline();
XX }
XX while (s==TRUE && --i);
XX if (s == TRUE) /* Then back up overtop */
XX s = backchar(f, n); /* of them all. */
XX return (s);
XX }
XX
XX/*
XX * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
XX * indentation as specified.
XX */
XXnewline(f, n)
XX {
XX register LINE *lp;
XX register int s;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX
XX /* if we are in C mode and this is a default <NL> */
XX if (n == 1 && (curbp->b_mode & MDCMOD) && curwp->w_dotp != curbp->b_linep)
XX return(cinsert());
XX
XX /* if we are in MODULA mode and this is a default <NL> */
XX if (n == 1 && (curbp->b_mode & MDMMOD) && curwp->w_dotp != curbp->b_linep)
XX return(minsert());
XX
XX /* if we are in LISP mode and this is a default <NL> */
XX if (n == 1 && (curbp->b_mode & MDLISP) && curwp->w_dotp != curbp->b_linep)
XX return(lispinsert());
XX
XX#if ULTRIX
XX /* if we are in a sub shell then send the line */
XX if (curbp == procbuf) return(pinsert());
XX#endif
XX
XX /* insert some lines */
XX while (n--) {
XX if ((s=lnewline()) != TRUE) return (s);
XX }
XX return (TRUE);
XX }
XX
XXcinsert() /* insert a newline and indentation for C */
XX {
XX register char *cptr; /* string pointer into text to copy */
XX register int tptr; /* index to scan into line */
XX register int i,j;
XX int gotleft,gotright;
XX
XX /* grab a pointer to text to copy indentation from */
XX cptr = &curwp->w_dotp->l_text[0];
XX tptr = curwp->w_doto - 1;
XX gotleft = gotright = 0;
XX for (i = 0; i<=tptr; i++) {
XX if (*cptr == '{') ++gotleft;
XX if (*cptr++ == '}') ++gotright;
XX }
XX if (gotright > gotleft) return(fixblockend(gotleft,gotright));
XX
XX
XX /* save the indent of the previous line */
XX i = getccol(TRUE); j = getccol(FALSE);
XX
XX if (gotleft > gotright && i == j-1) {
XX backdel(FALSE,1); /* get rid of curly on blank line */
XX tab(FALSE,1); /* indent it correctly */
XX linsert(1,'{'); /* put it back in */
XX }
XX else if (i == j) {
XX backdel(FALSE,tptr+1); /* get rid of spaces on blank lines */
XX }
XX
XX /* put in the newline */
XX if (lnewline() == FALSE) return(FALSE);
XX
XX /* and the saved indentation */
XX while (getccol(TRUE) < i) tab(FALSE, 1);
XX
XX /* add tabs for brace nesting on the previous line */
XX while (gotleft-- > gotright) tab(FALSE,1);
XX
XX return(TRUE);
XX }
XX
XXfixblockend(gotleft,gotright) /* fix up a close brace in CMODE/MMODE/LISP */
XX {
XX register int i;
XX register int target; /* column brace should go after */
XX
XX
XX /* calc where we will go back to */
XX target = getccol(TRUE);
XX while (gotright-- > gotleft) {
XX i = target % (tabsize == 0 ? 8 : tabsize);
XX if (i == 0) i = (tabsize == 0 ? 8 : tabsize);
XX target -= i;
XX }
XX
XX /* end the line and indent */
XX if (lnewline() == FALSE) return(FALSE);
XX if (target <= 0) return(TRUE);
XX
XX while (getccol(TRUE) < target) tab(FALSE, 1);
XX
XX return(TRUE);
XX
XX }
XX
XXminsert() /* insert a newline and indentation for MODULA */
XX {
XX register char *cptr; /* string pointer into text to copy */
XX register int tptr; /* index to scan into line */
XX register int i,j,doto;
XX int gotleft,gotright;
XX char scrbuf[20]; /* scratch buffer for comparisons */
XX
XX /* grab a pointer to text to copy indentation from */
XX cptr = &curwp->w_dotp->l_text[0];
XX tptr = curwp->w_doto - 1;
XX gotleft = gotright = 0;
XX
XX /* compress out leading white space */
XX for (doto = 0; doto<=tptr && (*cptr == ' ' || *cptr == '\t'); doto++)
XX cptr++;
XX
XX /* upcase the test string */
XX strncpy(scrbuf,cptr,6);
XX for (i = 0; i<6 ; i++)
XX if (scrbuf[i]>=0x61 && scrbuf[i]<=0x7A) scrbuf[i] -= 0x20;
XX
XX if (strncmp(scrbuf,"IF",2) == 0 ||
XX strncmp(scrbuf,"FOR",3) == 0 ||
XX strncmp(scrbuf,"CASE",4) == 0 ||
XX strncmp(scrbuf,"LOOP",4) == 0 ||
XX strncmp(scrbuf,"WITH",4) == 0 ||
XX strncmp(scrbuf,"WHILE",5) == 0 ||
XX strncmp(scrbuf,"BEGIN",5) == 0 ||
XX strncmp(scrbuf,"REPEAT",6) == 0 ||
XX strncmp(scrbuf,"RECORD",6) == 0) ++gotleft;
XX else if (strncmp(scrbuf,"ELSE",4) == 0 ||
XX strncmp(scrbuf,"ELSIF",5) == 0) {
XX ++gotleft;
XX ++gotright;
XX }
XX else if (strncmp(scrbuf,"END",3) == 0 ||
XX strncmp(scrbuf,"UNTIL",5) == 0) ++gotright;
XX
XX /* just ended a block */
XX if (gotright > gotleft) return(fixblockend(gotleft,gotright));
XX
XX
XX /* save the indent of the previous line */
XX i = getccol(TRUE); j = getccol(FALSE);
XX
XX /* get rid of spaces on blank lines */
XX if (i == j) backdel(FALSE,tptr+1);
XX
XX /* adjust current line */
XX else if (gotleft > 0 && gotleft == gotright) {
XX curwp->w_doto = doto;
XX while(getccol(TRUE) > i-4 && curwp->w_doto > 0) backdel(FALSE,1);
XX while(getccol(TRUE) < i-4) tab(FALSE,1);
XX curwp->w_doto = llength(curwp->w_dotp);
XX }
XX
XX /* put in the newline */
XX if (lnewline() == FALSE) return(FALSE);
XX
XX /* and the saved indentation */
XX while (getccol(TRUE) < i) tab(FALSE, 1);
XX
XX /* add tabs for block nesting on the previous line */
XX while (gotleft-- > gotright) tab(FALSE,1);
XX
XX return(TRUE);
XX }
XX
XXlispinsert() /* insert a newline and indentation for LISP */
XX {
XX register char *cptr; /* string pointer into text to copy */
XX register int tptr; /* index to scan into line */
XX register int i,j;
XX int gotleft,gotright;
XX
XX /* grab a pointer to text to copy indentation from */
XX cptr = &curwp->w_dotp->l_text[0];
XX tptr = curwp->w_doto - 1;
XX gotleft = gotright = 0;
XX for (i = 0; i<=tptr; i++) {
XX if (*cptr == '(') ++gotleft;
XX if (*cptr++ == ')') ++gotright;
XX }
XX if (gotright > gotleft) return(fixblockend(gotleft,gotright));
XX
XX /* save the indent of the previous line */
XX i = getccol(TRUE); j = getccol(FALSE);
XX
XX if (i == j) {
XX backdel(FALSE,tptr+1); /* get rid of spaces on blank lines */
XX }
XX
XX /* put in the newline */
XX if (lnewline() == FALSE) return(FALSE);
XX
XX /* and the saved indentation */
XX while (getccol(TRUE) < i) tab(FALSE, 1);
XX
XX /* add tabs for paren nesting on the previous line */
XX while (gotleft-- > gotright) tab(FALSE,1);
XX
XX return(TRUE);
XX }
XX
XX/*
XX* Delete blank lines around dot. What this command does depends if dot is
XX* sitting on a blank line. If dot is sitting on a blank line, this command
XX* deletes all the blank lines above and below the current line. If it is
XX* sitting on a non blank line then it deletes all of the blank lines after
XX* the line. Normally this command is bound to "C-X C-O". Any argument is
XX* ignored.
XX*/
XXdeblank(f, n)
XX {
XX register LINE *lp1;
XX register LINE *lp2;
XX register int nld;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX lp1 = curwp->w_dotp;
XX while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep) lp1 = lp2;
XX lp2 = lp1;
XX nld = 0;
XX while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0) ++nld;
XX if (nld == 0) return (TRUE);
XX curwp->w_dotp = lforw(lp1);
XX curwp->w_doto = 0;
XX return (ldelete(nld));
XX }
XX
XX/*
XX* Insert a newline, then enough tabs and spaces to duplicate the indentation
XX* of the previous line. Assumes tabs are every eight characters. Quite simple.
XX* Figure out the indentation of the current line. Insert a newline by calling
XX* the standard routine. Insert the indentation by inserting the right number
XX* of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
XX* subcomands failed. Normally bound to "C-J".
XX*/
XXindent(f, n)
XX {
XX register int nicol;
XX register int c;
XX register int i;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX while (n--) {
XX nicol = 0;
XX for (i=0; i<llength(curwp->w_dotp); ++i) {
XX c = lgetc(curwp->w_dotp, i);
XX if (c!=' ' && c!='\t') break;
XX if (c == '\t') nicol |= 0x07;
XX ++nicol;
XX }
XX if (lnewline() == FALSE || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE)
XX || ((i=nicol%8)!=0 && linsert(i, ' ')==FALSE))
XX return (FALSE);
XX }
XX return (TRUE);
XX }
XX
XX/*
XX* Delete forward. This is real easy, because the basic delete routine does
XX* all of the work. Watches for negative arguments, and does the right thing.
XX* If any argument is present, it kills rather than deletes, to prevent loss
XX* of text if typed with a big argument. Normally bound to "C-D".
XX*/
XXforwdel(f, n)
XX {
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (backdel(f, -n));
XX if (f != FALSE) { /* Really a kill. */
XX if ((lastflag&CFKILL) == 0)
XX kdelete();
XX thisflag |= CFKILL;
XX }
XX return (ldelete(n, f));
XX }
XX
XX/*
XX* Delete backwards. This is quite easy too, because it's all done with other
XX* functions. Just move the cursor back, and delete forwards. Like delete
XX* forward, this actually does a kill if presented with an argument. Bound to
XX* both "RUBOUT" and "C-H".
XX*/
XXbackdel(f, n)
XX {
XX register int s;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (forwdel(f, -n));
XX if (f != FALSE) { /* Really a kill. */
XX if ((lastflag&CFKILL) == 0)
XX kdelete();
XX thisflag |= CFKILL;
XX }
XX if ((s=backchar(f, n)) == TRUE) s = ldelete(n, f);
XX return (s);
XX }
XX
XX/*
XX* Kill text. If called without an argument, it kills from dot to the end of
XX* the line, unless it is at the end of the line, when it kills the newline.
XX* If called with an argument of 0, it kills from the start of the line to dot.
XX* If called with a positive argument, it kills from dot forward over that
XX* number of newlines. If called with a negative argument it kills backwards
XX* that number of newlines. Normally bound to "C-K".
XX*/
XXkilltext(f, n)
XX {
XX register int chunk;
XX register LINE *nextp;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX
XX return(rdonly()); /* we are in read only mode */
XX if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */
XX kdelete(); /* last wasn't a kill. */
XX thisflag |= CFKILL;
XX if (f == FALSE) {
XX chunk = llength(curwp->w_dotp)-curwp->w_doto;
XX if (chunk == 0) chunk = 1;
XX }
XX else if (n == 0) {
XX chunk = curwp->w_doto;
XX curwp->w_doto = 0;
XX }
XX else if (n > 0) {
XX chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
XX nextp = lforw(curwp->w_dotp);
XX while (--n) {
XX if (nextp == curbp->b_linep) return (FALSE);
XX chunk += llength(nextp)+1;
XX nextp = lforw(nextp);
XX }
XX }
XX else {
XX mlwrite("neg kill");
XX return (FALSE);
XX }
XX return (ldelete(chunk, TRUE));
XX }
XX
XX/*
XX* Yank text back from the kill buffer. This is really easy. All of the work
XX* is done by the standard insert routines. All you do is run the loop, and
XX* check for errors. Bound to "C-Y".
XX*/
XXyank(f, n)
XX {
XX register int c;
XX register int i;
XX extern int kused;
XX
XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */
XX return(rdonly()); /* we are in read only mode */
XX if (n < 0) return (FALSE);
XX while (n--) {
XX i = 0;
XX while ((c=kremove(i)) >= 0) {
XX if (c == '\n') {
XX if (lnewline(FALSE, 1) == FALSE) return (FALSE);
XX }
XX else {
XX if (linsert(1, c) == FALSE) return (FALSE);
XX }
XX ++i;
XX }
XX }
XX return (TRUE);
XX }
XX
XX
XXadjustmode(f,n) /* change the editor mode status */
XX {
XX register char *scan; /* scanning pointer to convert prompt */
XX register int i; /* loop index */
XX char cbuf[NPAT]; /* buffer to recieve mode name into */
XX char prompt[80]; /* string to prompt user with */
XX
XX strcpy(prompt,"Change mode (");
XX strcat(prompt,modename[0]);
XX for (i=1; i < NUMMODES; i++) {
XX strcat(prompt,",");
XX strcat(prompt,modename[i]);
XX }
XX strcat(prompt,"): ");
XX
XX /* prompt the user and get an answer */
XX
XX mlreply(prompt, cbuf, NPAT - 1);
XX
XX /* make it uppercase */
XX
XX scan = cbuf;
XX while (*scan != 0) {
XX if (*scan >= 'a' && *scan <= 'z') *scan = *scan - 32;
XX scan++;
XX }
XX
XX /* test it against the modes we know (first letter only) */
XX
XX for (i=0; i < NUMMODES; i++) {
XX if (cbuf[0] == modename[i][0]) {
XX /* finding a match, we process it */
XX if ((curwp->w_bufp->b_mode & (1 << i)) == 0) {
XX curwp->w_bufp->b_mode |= (1 << i);
XX if ((1 << i) == MDCMOD) {
XX tab(FALSE,4);
XX curwp->w_bufp->b_mode &= ~(MDMMOD|MDLISP);
XX }
XX if ((1 << i) == MDMMOD) {
XX tab(FALSE,4);
XX curwp->w_bufp->b_mode &= ~(MDCMOD|MDLISP);
XX }
XX if ((1 << i) == MDLISP) {
XX tab(FALSE,2);
XX curwp->w_bufp->b_mode &= ~(MDCMOD|MDMMOD);
XX }
XX }
XX else {
XX curwp->w_bufp->b_mode &= ~(1 << i);
XX if (((1 << i) == MDCMOD) ||
XX ((1 << i) == MDMMOD) ||
XX ((1 << i) == MDLISP)) tab(FALSE,0);
XX }
XX /* display new mode line */
XX upmode();
XX mlerase(); /* erase the junk */
XX return(TRUE);
XX }
XX }
XX
XX mlwrite("No such mode!");
XX return(FALSE);
XX }
XX
SHAR_EOF
if test 18178 -ne "`wc -c random.c`"
then
echo shar: error transmitting random.c '(should have been 18178 characters)'
fi
# End of shell archive
exit 0