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 0
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: # 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 0
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: # 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 0
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: # 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