rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) (12/15/88)
Many people asked me for the stevie sources. Here they are (in 5 messages, the first contains the doc). I send the full sources and not the diffs to 3.10 (some people suggest this) because the diffs are more than 100k and not everybody will have 3.10. Special answers for - Helge Oldach: There is no 8Bit-character support. A modified regexp package is included. - Dan Lancian: I have not seen the version posted to the atari group. - martin leisner: I don't know any well-known anonymous ftpable place ask Tony Andrews (uunet!isis!onecom!wldrdg!tony) - Jonathan C. Broome: Supporting large files (as the real vi) is very good. Please post diffs when you has added it to the new version ! stevie.doc contains 262 control chars - they were probably removed ------------------------------------------ cut --------------------------- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: ctags.doc porting.doc source.doc stevie.doc stevie.mm # Wrapped by rtregn@faui32 on Wed Dec 14 16:56:15 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'ctags.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ctags.doc'\" else echo shar: Extracting \"'ctags.doc'\" \(994 characters\) sed "s/^X//" >'ctags.doc' <<'END_OF_FILE' X Xctags - first cut at a UNIX ctags re-implementation X X XThis is a public domain rewrite of the standard UNIX ctags command. XIt is a simplified version written primarily for use with the 'stevie' Xeditor. The command line syntax is: X X ctags [file ...] X XCtags scans the all files given on the command line. If no files are Xgiven, the standard input is scanned for a list of file names. X XFunction declarations and macros are supported. However, only simple Xforms of each are recognized. Functions must be of the following form: X Xtype Xfname(...) X Xwhere "fname" is the name of the function and must come at the beginning Xof a line. This is the form I always use, so the limitation doesn't Xbother me. X XMacros (with or without parameters) of the following form are also detected: X X"#" [white space] "define" [white space] NAME X XThe white space between the "#" and "define" is optional. X X XOther Limitations and Changes X XNo sorting or detection of duplicate functions is done. X X XTony Andrews XAugust 1987 END_OF_FILE if test 994 -ne `wc -c <'ctags.doc'`; then echo shar: \"'ctags.doc'\" unpacked with wrong size! fi # end of 'ctags.doc' fi if test -f 'porting.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'porting.doc'\" else echo shar: Extracting \"'porting.doc'\" \(2372 characters\) sed "s/^X//" >'porting.doc' <<'END_OF_FILE' X X Release Notes for STEVIE - Version 3.15 X X Atari ST Editor for VI Enthusiasts X X Porting X X X Tony Andrews X X 3/27/88 X X X Porting the editor is a relatively simple task. Most of the Xcode is pretty machine-independent. For each environment, there is Xa file of routines that perform various low-level operations that Xtend to vary a lot from one machine to another. Another file contains Xthe escape sequences to be used for each machine. X X The machine-dependent files currently used are: X Xtos.c: Atari ST - ifdef for either Megamax or Alcyon X Xunix.c: UNIX System V X Xos2.c: Microsoft OS/2 X X X Each of these files are around 150 lines long and deal with Xlow-level issues like character I/O to the terminal, terminal Xinitialization, cursor addressing, and so on. There are different Xtradeoffs to be made depending on the environment. For example, the XUNIX version buffers terminal output because of the relatively high Xoverhead of system calls. A quick look at the files will make it clear Xwhat needs to be done in a new environment. X X Terminal escape sequences are in the file "term.h". These are Xdefined statically, for the time being. There is some discussion in Xterm.h regarding which sequences are optional and which are not. The Xeditor is somewhat flexible in dealing with a lack of terminal Xcapabilities. X X Because not all C compilers support command line macro definitions, Xthe #define's for system-specific macros are placed in the file 'env.h'. XIf you port to a new system, add another line there to define the macro you Xchoose for your port. X X The basic process for doing a new port is: X X 1. Come up with a macro name to use when ifdef'ing your system- X specific changes. Add a line to 'env.h' to define the macro X name you've chosen. X X 2. Look at unix.c, tos.c, and os2.c and copy the one that comes X closest to working on your system. Then modify your new file X as needed. X X 3. Look at term.h and edit the file appropriately adding a new X set of escape sequence definitions for your system. X X 4. If you haven't already, get a copy of Henry Spencer's regular X expression library and compile it. This has been very simple X every time I've done it. X X 5. Compiling and debug the editor. X X X In most cases it should really be that simple. I've done two Xports (UNIX and OS/2) and both were completed in just a couple of hours. END_OF_FILE if test 2372 -ne `wc -c <'porting.doc'`; then echo shar: \"'porting.doc'\" unpacked with wrong size! fi # end of 'porting.doc' fi if test -f 'source.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'source.doc'\" else echo shar: Extracting \"'source.doc'\" \(4609 characters\) sed "s/^X//" >'source.doc' <<'END_OF_FILE' X X Release Notes for STEVIE - Version 3.15 X X Source Notes X X Tony Andrews X X 3/27/88 X X XOverview X-------- X X This file provides a brief description of the source code for XStevie. The data structures are described later as well. For information Xspecific to porting the editor, see the file 'porting.doc'. This document Xis more relevant to people who want to hack on the editor apart from doing Xa simple port. X X Most of this document was written some time ago so a lot of the Xdiscussion centers on problems related to the Atari ST environment and Xcompilers. Most of this can be ignored for other systems. X XThings You Need X--------------- X X Stevie has been compiled with both the Alcyon (4.14A) and the XMegamax C compilers. For the posted binary, Megamax was used because Xit's less buggy and provides a reasonable malloc(). Ports to other Xcompilers should be pretty simple. The current ifdef's for ALCYON and XMEGAMAX should point to the potential trouble areas. (See 'porting.doc' Xfor more information.) X X The search code depends on Henry Spencer's regular expression Xcode. I used a version I got from the net recently (as part of a 'grep' Xposting) and had absolutely no trouble compiling it on the ST. Thanks, XHenry! X X The file 'getenv.c' contains a getenv routine that may or may Xnot be needed with your compiler. My version works with Alcyon and XMegamax, under either the Beckemeyer or Gulam shells. X X Lastly, you need a decent malloc. Lots of stuff in stevie is Xallocated dynamically. The malloc with Alcyon is problematic because Xit allocates from the heap between the end of data and the top of stack. XIf you make the stack big enough to edit large files, you wind up Xwasting space when working with small files. Mallocs that get their memory Xfrom GEMDOG (in fairly large chunks) are much better. X X XCruft X----- X X Some artifacts from Tim Thompson's original version remain. In Xsome cases, code has been re-written, with the original left in place Xbut ifdef'd out. This will all be cleaned up eventually, but for now Xit's sometimes useful to see how things used to work. X X XData Structures X--------------- X X A brief discussion of the evolution of the data structures will Xdo much to clarify the code, and explain some of the strangeness you may Xsee. X X In the original version, the file was maintained in memory as a Xsimple contiguous buffer. References to positions in the file were simply Xcharacter pointers. Due to the obvious performance problems inherent in Xthis approach, I made the following changes. X X The file is now represented by a doubly linked list of 'line' Xstructures defined as follows: X Xstruct line { X struct line *prev, *next; /* previous and next lines */ X char *s; /* text for this line */ X int size; /* actual size of space at 's' */ X unsigned long num; /* line "number" */ X}; X XThe members of the line structure are described more completely here: X Xprev - pointer to the structure for the prior line, or NULL for the X first line of the file X Xnext - like 'prev' but points to the next line X Xs - points to the contents of the line (null terminated) X Xsize - contains the size of the chunk of space pointed to by s. This X is used so we know when we can add text to a line without getting X more space. When we DO need more space, we always get a little X extra so we don't make so many calls to malloc. X Xnum - This is a pseudo line number that makes it easy to compare X positions within the file. Otherwise, we'd have to traverse X all the links to tell which line came first. X X X Since character pointers served to mark file positions in the Xoriginal, a similar data object was needed for the new data structures. XThis purpose is served by the 'lptr' structure which is defined as: X Xstruct lptr { X struct line *linep; /* line we're referencing */ X int index; /* position within that line */ X}; X X XThe member 'linep' points to the 'line' structure for the line containing Xthe location of interest. The integer 'index' is the offset into the line Xdata (member 's') of the character to be referenced. X XThe following typedef's are more commonly used: X Xtypedef struct line LINE; Xtypedef struct lptr LPTR; X XMany operations that were trivial with character pointers had to be Ximplemented by functions to manipulate LPTR's. Most of these are in the Xfile 'ptrfunc.c'. There you'll find functions to increment, decrement, Xand compare LPTR's. X XThis was the biggest change to the editor. Fortunately, I made this Xchange very early on, while I was still doing the work on a UNIX system. XUsing 'sdb' made it much easier to debug this code than if I had done it Xon the ST. X END_OF_FILE if test 4609 -ne `wc -c <'source.doc'`; then echo shar: \"'source.doc'\" unpacked with wrong size! fi # end of 'source.doc' fi if test -f 'stevie.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie.doc'\" else echo shar: Extracting \"'stevie.doc'\" \(28858 characters\) sed "s/^X//" >'stevie.doc' <<'END_OF_FILE' X X X X STEVIE - An Aspiring VI Clone X X User Reference - 3.44 X X Tony Andrews X X X X 1. _O_v_e_r_v_i_e_w X X STEVIE is an editor designed to mimic the interface of the X UNIX editor 'vi'. The name (ST Editor for VI Enthusiasts) X comes from the fact that the editor was first written for X the Atari ST. The current version has been ported to UNIX, X Minix, MS-DOS, and OS/2, but I've left the name intact for X now. X X This program is the result of many late nights of hacking X over the last year or so. The first version was written by X Tim Thompson and posted to USENET. From there, I reworked X the data structures completely, added LOTS of features, and X generally improved the overall performance in the process. X X I've labelled STEVIE an 'aspiring' vi clone as a warning to X those who may expect too much. On the whole, the editor is X pretty complete. Almost all of the visual mode commands are X supported. I've tried very hard to capture the 'feel' of vi X by getting the little things right. Making lines wrap X correctly, supporting true operators, and even getting the X cursor to land on the right place for tabs are all a real X pain, but really help make the editor 'feel' right. X X STEVIE may be freely distributed. The source isn't copy- X righted or restricted in any way. If you pass the program X along, please include all the documentation and, if practi- X cal, the source as well. I'm not fanatical about this, but I X tried to make STEVIE fairly portable and that doesn't do any X good if the source isn't available. X X The remainder of this document describes the operation of X the editor. This is intended as a reference for users X already familiar with the real vi editor. X X X 2. _S_t_a_r_t_i_n_g__t_h_e__E_d_i_t_o_r X X The following command line forms are supported: X X stevie [file ...] Edit the specified file(s) X X stevie -t tag Start at the location of the given tag X X stevie + file Edit file starting at end X X X X X X - 1 - X X X X X X X X STEVIE User Reference X X X X stevie +n file Edit file starting a line number 'n' X X stevie +/pat file Edit file starting at pattern 'pat' X X If multiple files are given on the command line (using the X first form), the ":n" command goes to the next file, ":N" X goes backward in the list, and ":rew" can be used to rewind X back to the start of the file list. X X X 3. _S_e_t__C_o_m_m_a_n_d__O_p_t_i_o_n_s X X The ":set" command works as usual to set parameters. Each X parameter has a long and an abbreviated name, either of X which may be used. Boolean parameters are set as in: X X set showmatch X X or cleared by: X X set noshowmatch X X Numeric parameters are set as in: X X set scroll=5 X X Several parameters may be set with a single command: X X set novb sm report=1 X X To see the status of all parameters use ":set all". Typing X ":set" with no arguments will show only those parameters X that have been changed. The supported parameters, their X names, abbreviations, defaults, and descriptions are shown X below: X X X X X X X X X X X X X X X X X X X X - 2 - X X X X X X X X STEVIE User Reference X X X X autoindent Short: ai, Default: noai, Type: Boolean X When in insert mode, start new lines at the same X column as the prior line. Unlike vi, you can X backspace over the indentation. X X backup Short: bk, Default: nobk, Type: Boolean X Leave a backup on file writes. X X errorbells Short: eb, Default: noeb, Type: Boolean X Ring bell when error messages are shown. X X ignorecase Short: ic, Default: noic, Type: Boolean X Ignore case in string searches. X X lines Short: lines, Default: lines=25, Type: Numeric X Number of physical lines on the screen. The X default value actually depends on the host X machine, but is generally 25. X X list Short: list, Default: nolist, Type: Boolean X Show tabs and newlines graphically. X X number Short: nu, Default: nonu, Type: Boolean X Display lines on the screen with their line X numbers. X X report Short: report, Default: report=5, Type: Numeric X Minimum number of lines to report operations on. X X return Short: cr, Default: cr, Type: Boolean X End lines with cr-lf when writing files. X X scroll Short: scroll, Default: scroll=12, Type: Numeric X Number of lines to scroll for ^D & ^U. X X showmatch Short: sm, Default: nosm, Type: Boolean X When a ), }, or ] is typed, show the matching (, X {, or [ if it's on the current screen by moving X the cursor there briefly. X X showmode Short: mo, Default: nomo, Type: Boolean X Show on status line when in insert mode. X X tabstop Short: ts, Default: ts=8, Type: Numeric X Number of spaces in a tab. X X wrapscan Short: ws, Default: ws, Type: Boolean X String searches wrap around the ends of the X file. X X X X X X - 3 - X X X X X X X X STEVIE User Reference X X X X vbell Short: vb, Default: vb, Type: Boolean X Use a visual bell, if possible. (novb for audi- X ble bell) X X The EXINIT environment variable can be used to modify the X default values on startup as in: X X setenv EXINIT="set sm ts=4" X X The 'backup' parameter, if set, causes the editor to retain X a backup of any files that are written. During file writes, X a backup is always kept for safety until the write is com- X pleted. At that point, the 'backup' parameter determines X whether the backup file is deleted. X X In environments (e.g. OS/2 or TOS) where lines are normally X terminated by CR-LF, the 'return' parameter allows files to X be written with only a LF terminator (if the parameter is X cleared). This parameter is ignored on UNIX systems. X X The 'lines' parameter tells the editor how many lines there X are on the screen. This is useful on systems like the ST X (or OS/2 machines with an EGA adapter) where various screen X resolutions may be used. By using the 'lines' parameter, X different screen sizes can be easily handled. X X X 4. _C_o_l_o_n__C_o_m_m_a_n_d_s X X Several of the normal 'vi' colon commands are supported by X STEVIE. Some commands may be preceded by a line range X specification. For commands that accept a range of lines, X the following address forms are supported: X X addr X addr + number X addr - number X X where 'addr' may be one of the following: X X a line number X a mark (as in 'a or 'b) X '.' (the current line) X '$' (the last line) X X An address range of "%" is accepted as an abbreviation of X "1,$". X X X X X X X X - 4 - X X X X X X X X STEVIE User Reference X X X X 4.1 _T_h_e__G_l_o_b_a_l__C_o_m_m_a_n_d X X A limited form of the global command is supported, accepting X the following command form: X X g/pattern/X X X where X may be either 'd' or 'p' to delete or print lines X that match the given pattern. If a line range is given, X only those lines are checked for a match with the pattern. X If no range is given, all lines are checked. X X If the trailing command character is omitted, 'p' is X assumed. In this case, the trailing slash is also optional. X The current version of the editor does not support the undo X operation following the deletion of lines with the global X command. X X 4.2 _T_h_e__S_u_b_s_t_i_t_u_t_e__C_o_m_m_a_n_d X X The substitute command provides a powerful mechanism for X making more complex substitutions than can be done directly X from visual mode. The general form of the command is: X X s/pattern/replacement/g X X Each line in the given range (or the current line, if no X range was given) is scanned for the given regular expres- X sion. When found, the string that matched the pattern is X replaced with the given replacement string. If the replace- X ment string is null, each matching pattern string is X deleted. X X The trailing 'g' is optional and, if present, indicates that X multiple occurrences of 'pattern' on a line should all be X replaced. X X Some special sequences are recognized in the replacement X string. The ampersand character is replaced by the entire X pattern that was matched. For example, the following com- X mand could be used to put all occurrences of 'foo' or 'bar' X within double quotes: X X 1,$s/foo|bar/"&"/g X X The special sequence "\n" where 'n' is a digit from 1 to 9, X is replaced by the string the matched the corresponding X parenthesized expression in the pattern. The following com- X mand could be used to swap the first two parameters in calls X to the C function "foo": X X X X X - 5 - X X X X X X X X STEVIE User Reference X X X X 1,$s/foo\(([^,]*),([^,]*),/foo(\2,\1,/g X X Like the global command, substitutions can't be undone with X this version of the editor. X X 4.3 _F_i_l_e__M_a_n_i_p_u_l_a_t_i_o_n__C_o_m_m_a_n_d_s X X The following table shows the supported file manipulation X commands as well as some other 'ex' commands that aren't X described elsewhere: X X :w write the current file X :wq write and quit X :x write (if necessary) and quit X ZZ same as ":x" X X :e file edit the named file X :e! re-edit the current file, discarding changes X :e # edit the alternate file X X :w file write the buffer to the named file X :x,yw file write lines x through y to the named file X :r file read the named file into the buffer X X :n edit the next file X :N edit the previous file X :rew rewind the file list X X :f show the current file name X :f name change the current file name X :x= show the line number of address 'x' X X :ta tag go to the named tag X ^] like ":ta" using the current word as the tag X X :help display a command summary X :ve show the version number X X :sh run an interactive shell X :!cmd run a command X X The ":help" command can also be invoked with the <HELP> key X on the Atari ST. This actually displays a pretty complete X summary of the real vi with unsupported features indicated X appropriately. X X The commands above work pretty much like they do in 'vi'. X Most of the commands support a '!' suffix (if appropriate) X to discard any pending changes. X X X X X X - 6 - X X X X X X X X STEVIE User Reference X X X X 5. _S_t_r_i_n_g__S_e_a_r_c_h_e_s X X String searches are supported, as in vi, accepting the usual X regular expression syntax. This was done using a modified X form of Henry Spencer's regular expression library. I added X code outside the library to support the '\<' and '\>' exten- X sions. This actually turned out to be pretty easy, although X there may be some glitches in the way I did it. The parame- X ter "ignorecase" can be set to ignore case in all string X searches. X X X 6. _O_p_e_r_a_t_o_r_s X X The vi operators (d, c, y, !, <, and >) work as true opera- X tors. The only exception is that the change operator works X only for character-oriented changes (like cw or c%) and not X for line-oriented changes (like cL or c3j). X X X 7. _T_a_g_s X X Tags are implemented and a fairly simple version of 'ctags' X is supplied with the editor. The current version of ctags X will find functions and macros following a specific (but X common) form. See 'ctags.doc' for a complete discussion. X X X 8. _S_y_s_t_e_m_-_S_p_e_c_i_f_i_c__C_o_m_m_e_n_t_s X X The following sections provide additional relevant informa- X tion for the systems to which STEVIE has been ported. X X 8.1 _A_t_a_r_i__S_T X X 8.1.1 _T_O_S The editor has been tested in all three resolu- X tions, although low and high res. are less tested than X medium. The 50-line high res. mode can be used by setting X the 'lines' parameter to 50. Alternatively, the environment X variable 'LINES' can be set. The editor doesn't actively set X the number of lines on the screen. It just operates using X the number of lines it was told. X X The arrow keys, as well as the <INSERT>, <HELP>, and <UNDO> X keys are all mapped appropriately. X X 8.1.2 _M_i_n_i_x The editor is pretty much the same under X Minix, but many of the keyboard mappings aren't supported. X X X X X X X - 7 - X X X X X X X X STEVIE User Reference X X X X 8.2 _U_N_I_X X X The editor has been ported to UNIX System V release 3 as X well as 4.2 BSD. This was done mainly to get some profiling X data so I haven't put much effort into doing the UNIX ver- X sion right. It's hard-coded for ansi-style escape sequences X and doesn't use the termcap/terminfo routines at all. X X 8.3 _O_S_/_2 X X This port was done because the editor that comes with the X OS/2 developer's kit really stinks. Make sure 'ansi' mode is X on (using the 'ansi' command). The OS/2 console driver X doesn't support insert/delete line, so STEVIE bypasses the X driver and makes the appropriate system calls directly. X This is all done in the system-specific part of the editor X so the kludge is at least localized. X X The arrow keys, page up/down and home/end all do what you'd X expect. The function keys are hard-coded to some useful mac- X ros until I can get true support for macros into the editor. X The current mappings are: X X F1 :p <RETURN> X F2 :n <RETURN> X F3 :e # <RETURN> X F4 :rew <RETURN> X F5 [[ X F6 ]] X F7 << X F8 >> X F9 :x <RETURN> X F10 :help <RETURN> X X S-F1 :p! <RETURN> X S-F2 :n! <RETURN> X X 8.4 _M_S_D_O_S X X STEVIE has been ported to MSDOS 3.3 using the Microsoft C X compiler, version 5.1. The keyboard mappings are the same X as for OS/2. The only problem with the PC version is that X the inefficiency of the screen update code becomes painfully X apparent on slower machines. X X X X X X X X X X X - 8 - X X X X X X X X STEVIE User Reference X X X X 9. _M_i_s_s_i_n_g__F_e_a_t_u_r_e_s X X 1. Counts aren't yet supported everywhere that they X should be. X X 2. Macros with support for function keys. X X 3. More "set" options. X X 4. Many others... X X X 10. _K_n_o_w_n__B_u_g_s__a_n_d__P_r_o_b_l_e_m_s X X 1. The change operator is only half-way implemented. It X works for character motions but not line motions. This X isn't so bad since most change operations are charac- X ter oriented anyway. X X 2. The yank buffer uses statically allocated memory, so X large yanks will fail. If a delete spans an area X larger than the yank buffer, the program asks for con- X firmation before proceeding. That way, if you were X moving text, you don't get screwed by the limited yank X buffer. You just have to move smaller chunks at a X time. All the internal buffers (yank, redo, etc.) X need to be reworked to allocate memory dynamically. X The 'undo' buffer is now dynamically allocated, so any X change can be undone. X X 3. If you stay in insert mode for a long time, the insert X buffer can overflow. The editor will print a message X and dump you back into command mode. X X 4. The current version of the substitute command (i.e. X ":s/foo/bar") can't be undone. X X 5. Several other less bothersome glitches... X X X X X X X X X X X X X X X X X - 9 - X X X X X X X X STEVIE User Reference X X X X 11. _C_o_n_c_l_u_s_i_o_n X X The editor has reached a pretty stable state, and performs X well on the systems I use it on, so I'm pretty much in X maintenance mode now. There's still plenty to be done; the X screen update code is still pretty inefficient and the X yank/put code is still primitive. But after more than a X year of hacking, I'm ready to work on new projects. I'm X still interested in bug reports, and I do still add a new X feature from time to time, but the rate of change is way X down now. X X I'd like to thank Tim Thompson for writing the original ver- X sion of the editor. His program was well structured and X quite readable. Thanks for giving me a good base to work X with. X X If you're reading this file, but didn't get the source code X for STEVIE, it can be had by sending a disk with return pos- X tage to the address given below. I can write disks for the X Atari ST (SS or DS) or MSDOS (360K or 1.2M). Please be sure X to include the return postage. I don't intend to make money X from this program, but I don't want to lose any either. X X I'm not planning to try to coordinate the various ports of X STEVIE that may occur. I just don't have the time. But if X you do port it, I'd be interested in hearing about it. X X Tony Andrews UUCP: onecom!wldrdg!tony X 5902E Gunbarrel Ave. X Boulder, CO 80301 X X X X X X X X X X X X X X X X X X X X X X X X - 10 - X X X X X X X X STEVIE User Reference X X X X _C_h_a_r_a_c_t_e_r__F_u_n_c_t_i_o_n__S_u_m_m_a_r_y X X The following list describes the meaning of each character X that's used by the editor. In some cases characters have X meaning in both command and insert mode; these are all X described. X X X ^@ The null character. Not used in any mode. This char- X acter may not be present in the file, as is the case X with vi. X X ^B Backward one screen. X X ^D Scroll the window down one half screen. X X ^E Scroll the screen up one line. X X ^F Forward one screen. X X ^G Same as ":f" command. Displays file information. X X ^H (Backspace) Moves cursor left one space in command X mode. In insert mode, erases the last character X typed. X X ^J Move the cursor down one line. X X ^L Clear and redraw the screen. X X ^M (Carriage return) Move to the first non-white char- X acter in the next line. In insert mode, a carriage X return opens a new line for input. X X ^N Move the cursor down a line. X X ^P Move the cursor up a line. X X ^U Scroll the window up one half screen. X X ^Y Scroll the screen down one line. X X ^[ Escape cancels a pending command in command mode, X and is used to terminate insert mode. X X ^] Moves to the tag whose name is given by the word in X which the cursor resides. X X ^` Same as ":e #" if supported (system-dependent). X X X X X X - 11 - X X X X X X X X STEVIE User Reference X X X X SPACE Move the cursor right on column. X X ! The filter operator always operates on a range of X lines, passing the lines as input to a program, and X replacing them with the output of the program. The X shorthand command "!!" can be used to filter a X number of lines (specified by a preceding count). X The command "!" is replaced by the last command X used, so "!!!<RETURN>" runs the given number of X lines through the last specified command. X X $ Move to the end of the current line. X X % If the cursor rests on a paren '()', brace '{}', or X bracket '[]', move to the matching one. X X ' Used to move the cursor to a previously marked posi- X tion, as in 'a or 'b. The cursor moves to the start X of the marked line. The special mark '' refers to X the "previous context". X X + Same as carriage return, in command mode. X X , Reverse of the last t, T, f, or F command. X X - Move to the first non-white character in the previ- X ous line. X X . Repeat the last edit command. X X / Start of a forward string search command. String X searches may be optionally terminated with a closing X slash. To search for a slash use '\/' in the search X string. X X 0 Move to the start of the current line. Also used X within counts. X X 1-9 Used to add 'count' prefixes to commands. X X : Prefix character for "ex" commands. X X ; Repeat last t, T, f, or F command. X X < The 'left shift' operator. X X > The 'right shift' operator. X X ? Same as '/', but search backward. X X X X X X - 12 - X X X X X X X X STEVIE User Reference X X X X A Append at the end of the current line. X X B Backward one blank-delimited word. X X C Change the rest of the current line. X X D Delete the rest of the current line. X X E End of the end of a blank-delimited word. X X F Find a character backward on the current line. X X G Go to the given line number (end of file, by X default). X X H Move to the first non-white char. on the top screen X line. X X I Insert before the first non-white char. on the X current line. X X J Join two lines. X X L Move to the first non-white char. on the bottom X screen line. X X M Move to the first non-white char. on the middle X screen line. X X N Reverse the last string search. X X O Open a new line above the current line, and start X inserting. X X P Put the yank/delete buffer before the current cursor X position. X X R Replace characters until an "escape" character is X received. Similar to insert mode, but replaces X instead of inserting. Typing a newline in replace X mode is the same as in insert mode, but replacing X continues on the new line. X X T Reverse search 'upto' the given character. X X U Restore the current line to its state before you X started changing it. X X W Move forward one blank-delimited word. X X X X X X - 13 - X X X X X X X X STEVIE User Reference X X X X X Delete one character before the cursor. X X Y Yank the current line. Same as 'yy'. X X ZZ Exit from the editor, saving changes if necessary. X X [[ Move backward one C function. X X ]] Move forward one C function. X X ^ Move to the first non-white on the current line. X X ` Move to the given mark, as with '. The distinction X between the two commands is important when used with X operators. I support the difference correctly. If X you don't know what I'm talking about, don't worry, X it won't matter to you. X X a Append text after the cursor. X X b Back one word. X X c The change operator. X X d The delete operator. X X e Move to the end of a word. X X f Find a character on the current line. X X h Move left one column. X X i Insert text before the cursor. X X j Move down one line. X X k Move up one line. X X l Move right one column. X X m Set a mark at the current position (e.g. ma or mb). X X n Repeat the last string search. X X o Open a new line and start inserting text. X X p Put the yank/delete buffer after the cursor. X X r Replace a character. X X X X X X - 14 - X X X X X X X X STEVIE User Reference X X X X s Replace characters. X X t Move forward 'upto' the given character on the X current line. X X u Undo the last edit. X X w Move forward one word. X X x Delete the character under the cursor. X X y The yank operator. X X z Redraw the screen with the current line at the top X (zRETURN), the middle (z.), or the bottom (z-). X X | Move to the column given by the preceding count. X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X - 15 - X X X X X X X X X X X X STEVIE - User Guide X X CONTENTS X X X 1. Overview........................................... 1 X X 2. Starting the Editor................................ 1 X X 3. Set Command Options................................ 2 X X 4. Colon Commands..................................... 4 X 4.1 The Global Command............................ 5 X 4.2 The Substitute Command........................ 5 X 4.3 File Manipulation Commands.................... 6 X X 5. String Searches.................................... 7 X X 6. Operators.......................................... 7 X X 7. Tags............................................... 7 X X 8. System-Specific Comments........................... 7 X 8.1 Atari ST...................................... 7 X 8.2 UNIX.......................................... 8 X 8.3 OS/2.......................................... 8 X 8.4 MSDOS......................................... 8 X X 9. Missing Features................................... 9 X X 10. Known Bugs and Problems............................ 9 X X 11. Conclusion......................................... 10 X X Character Function Summary.............................. 11 X X X X X X X X X X X X X X X X X X X X - i - X X X X END_OF_FILE echo shar: 262 control characters may be missing from \"'stevie.doc'\" if test 28858 -ne `wc -c <'stevie.doc'`; then echo shar: \"'stevie.doc'\" unpacked with wrong size! fi # end of 'stevie.doc' fi if test -f 'stevie.mm' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie.mm'\" else echo shar: Extracting \"'stevie.mm'\" \(20348 characters\) sed "s/^X//" >'stevie.mm' <<'END_OF_FILE' X.\" $Header: stevie.mm,v 3.44 88/11/04 15:03:24 tony Exp $ X.\" X.\" Documentation for STEVIE. Process with nroff using the mm macros. X.\" X.nr Hu 1 X.SA 1 X.TL XSTEVIE - An Aspiring VI Clone X.sp XUser Reference - 3.44 X.AU "Tony Andrews" X.AF "" X.MT 4 X.PH "'STEVIE''User Reference'" X.PF "''- \\\\nP -''" X.H 1 "Overview" XSTEVIE is an editor designed to mimic the interface of the UNIX Xeditor 'vi'. The name (ST Editor for VI Enthusiasts) comes from the fact that Xthe editor was first written for the Atari ST. The current version has Xbeen ported to UNIX, Minix, MS-DOS, and OS/2, but I've left Xthe name intact for now. X.P XThis program is the result of many late nights of hacking over the last Xyear or so. The first version was written by Tim Thompson and posted Xto USENET. From there, I reworked the data structures completely, added XLOTS of features, and generally improved the overall performance in the Xprocess. X.P XI've labelled STEVIE an 'aspiring' vi clone as a warning to those who Xmay expect too much. On the whole, the editor is pretty complete. Almost Xall of the visual mode commands are supported. I've tried very hard to Xcapture the 'feel' of vi by getting the little things right. Making lines Xwrap correctly, supporting true operators, and even getting the cursor to Xland on the right place for tabs are all a real pain, but really help make Xthe editor 'feel' right. X.P XSTEVIE may be freely distributed. The source isn't copyrighted or Xrestricted in any way. If you pass the program along, please include all Xthe documentation and, if practical, the source as well. I'm not fanatical Xabout this, but I tried to make STEVIE fairly portable and that doesn't Xdo any good if the source isn't available. X.P XThe remainder of this document describes the operation of the editor. XThis is intended as a reference for users already familiar with the real Xvi editor. X.H 1 "Starting the Editor" XThe following command line forms are supported: X.VL 20 X.LI "stevie [file ...]" XEdit the specified file(s) X.LI "stevie -t tag" XStart at the location of the given tag X.LI "stevie + file" XEdit file starting at end X.LI "stevie +n file" XEdit file starting a line number 'n' X.LI "stevie +/pat file" XEdit file starting at pattern 'pat' X.LE X.P XIf multiple files are given on the command line (using the first form), Xthe ":n" command goes to the next file, ":N" goes backward in the list, Xand ":rew" can be used to rewind back to the start of the file list. X.H 1 "Set Command Options" XThe ":set" command works as usual to set parameters. Each parameter has Xa long and an abbreviated name, either of which may be used. Boolean Xparameters are set as in: X.sp X.ti +5 Xset showmatch X.sp Xor cleared by: X.sp X.ti +5 Xset noshowmatch X.sp XNumeric parameters are set as in: X.sp X.ti +5 Xset scroll=5 X.sp XSeveral parameters may be set with a single command: X.sp X.ti +5 Xset novb sm report=1 X.P XTo see the status of all parameters use ":set all". Typing ":set" with Xno arguments will show only those parameters that have been changed. XThe supported parameters, their names, abbreviations, defaults, Xand descriptions are shown below: X.SK X.VL 12 X.LI autoindent XShort: ai, Default: noai, Type: Boolean X.br XWhen in insert mode, start new lines at the same column as the prior Xline. Unlike vi, you can backspace over the indentation. X.LI backup XShort: bk, Default: nobk, Type: Boolean X.br XLeave a backup on file writes. X.LI errorbells XShort: eb, Default: noeb, Type: Boolean X.br XRing bell when error messages are shown. X.LI ignorecase XShort: ic, Default: noic, Type: Boolean X.br XIgnore case in string searches. X.LI lines XShort: lines, Default: lines=25, Type: Numeric X.br XNumber of physical lines on the screen. The default value actually Xdepends on the host machine, but is generally 25. X.LI list XShort: list, Default: nolist, Type: Boolean X.br XShow tabs and newlines graphically. X.LI number XShort: nu, Default: nonu, Type: Boolean X.br XDisplay lines on the screen with their line numbers. X.LI report XShort: report, Default: report=5, Type: Numeric X.br XMinimum number of lines to report operations on. X.LI return XShort: cr, Default: cr, Type: Boolean X.br XEnd lines with cr-lf when writing files. X.LI scroll XShort: scroll, Default: scroll=12, Type: Numeric X.br XNumber of lines to scroll for ^D & ^U. X.LI showmatch XShort: sm, Default: nosm, Type: Boolean X.br XWhen a ), }, or ] is typed, show the matching (, {, or [ if Xit's on the current screen by moving the cursor there briefly. X.LI showmode XShort: mo, Default: nomo, Type: Boolean X.br XShow on status line when in insert mode. X.LI tabstop XShort: ts, Default: ts=8, Type: Numeric X.br XNumber of spaces in a tab. X.LI wrapscan XShort: ws, Default: ws, Type: Boolean X.br XString searches wrap around the ends of the file. X.LI vbell XShort: vb, Default: vb, Type: Boolean X.br XUse a visual bell, if possible. (novb for audible bell) X.LE X.P XThe EXINIT environment variable can be used to modify the default values Xon startup as in: X.sp X.ti +5 Xsetenv EXINIT="set sm ts=4" X.P XThe 'backup' parameter, if set, causes the editor to retain a backup of any Xfiles that are written. During file writes, a backup is always kept for Xsafety until the write is completed. At that point, the 'backup' parameter Xdetermines whether the backup file is deleted. X.P XIn environments (e.g. OS/2 or TOS) where lines are normally terminated by XCR-LF, the 'return' parameter allows files to be written with only a LF Xterminator (if the parameter is cleared). XThis parameter is ignored on UNIX systems. X.P XThe 'lines' parameter tells the editor how many lines there are on the screen. XThis is useful on systems like the ST (or OS/2 machines with an EGA adapter) Xwhere various screen resolutions may be Xused. By using the 'lines' parameter, different screen sizes can be easily Xhandled. X.H 1 "Colon Commands" XSeveral of the normal 'vi' colon commands are supported by STEVIE. XSome commands may be preceded by a Xline range specification. XFor commands that accept a range of lines, Xthe following address forms are supported: X.DS 1 Xaddr Xaddr + number Xaddr - number X.DE Xwhere 'addr' may be one of the following: X.DS 1 Xa line number Xa mark (as in 'a or 'b) X\'.' (the current line) X\'$' (the last line) X.DE X.P XAn address range of "%" is accepted as an abbreviation of "1,$". X.H 2 "The Global Command" XA limited form of the global command is supported, accepting the Xfollowing command form: X.DS 1 Xg/pattern/X X.DE Xwhere X may be either 'd' or 'p' to delete or print lines that match Xthe given pattern. XIf a line range is given, only those lines are checked for a match Xwith the pattern. XIf no range is given, all lines are checked. X.P XIf the trailing command character is omitted, 'p' is assumed. XIn this case, the trailing slash is also optional. XThe current version of the editor does not support the undo operation Xfollowing the deletion of lines with the global command. X.H 2 "The Substitute Command" XThe substitute command provides a powerful mechanism for making more Xcomplex substitutions than can be done directly from visual mode. XThe general form of the command is: X.DS 1 Xs/pattern/replacement/g X.DE XEach line in the given range (or the current line, if no range was Xgiven) is scanned for the given regular expression. XWhen found, the string that matched the pattern is replaced with Xthe given replacement string. XIf the replacement string is null, each matching pattern string is Xdeleted. X.P XThe trailing 'g' is optional and, if present, indicates that multiple Xoccurrences of 'pattern' on a line should all be replaced. X.P XSome special sequences are recognized in the replacement string. The Xampersand character is replaced by the entire pattern that was matched. XFor example, the following command could be used to put all occurrences Xof 'foo' or 'bar' within double quotes: X.DS 1 X1,$s/foo|bar/"&"/g X.DE X.P XThe special sequence "\\n" where 'n' is a digit from 1 to 9, is replaced Xby the string the matched the corresponding parenthesized expression in Xthe pattern. The following command could be used to swap the first two Xparameters in calls to the C function "foo": X.DS 1 X1,$s/foo\\\\(([^,]*),([^,]*),/foo(\\\\2,\\\\1,/g X.DE X.P XLike the global command, substitutions can't be undone with this Xversion of the editor. X.H 2 "File Manipulation Commands" XThe following table shows the supported file manipulation commands as Xwell as some other 'ex' commands that aren't described elsewhere: X.DS X:w write the current file X:wq write and quit X:x write (if necessary) and quit XZZ same as ":x" X X:e file edit the named file X:e! re-edit the current file, discarding changes X:e # edit the alternate file X X:w file write the buffer to the named file X:x,yw file write lines x through y to the named file X:r file read the named file into the buffer X X:n edit the next file X:N edit the previous file X:rew rewind the file list X X:f show the current file name X:f name change the current file name X:x= show the line number of address 'x' X X:ta tag go to the named tag X^] like ":ta" using the current word as the tag X X:help display a command summary X:ve show the version number X X:sh run an interactive shell X:!cmd run a command X.DE X.P XThe ":help" command can also be invoked with the <HELP> key on the Atari XST. This actually displays a pretty complete summary of the real vi with Xunsupported features indicated appropriately. X.P XThe commands above work pretty much like they do in 'vi'. Most of the Xcommands support a '!' suffix (if appropriate) to discard any pending Xchanges. X.H 1 "String Searches" XString searches are supported, as in vi, accepting the usual regular Xexpression syntax. This was done using a modified form of XHenry Spencer's regular expression Xlibrary. I added code outside the library to support Xthe '\\<' and '\\>' extensions. This actually turned out to be pretty easy, Xalthough there may be some glitches in the way I did it. XThe parameter "ignorecase" can be set to ignore case in all string searches. X.H 1 "Operators" XThe vi operators (d, c, y, !, <, and >) work as true operators. The only Xexception is that the change operator works only for character-oriented Xchanges (like cw or c%) and not for line-oriented changes (like cL or c3j). X.H 1 "Tags" XTags are implemented and a fairly simple version of 'ctags' is supplied Xwith the editor. The current version of ctags will find functions and Xmacros following a specific (but common) form. See 'ctags.doc' for a Xcomplete discussion. X.H 1 "System-Specific Comments" XThe following sections provide additional relevant information for the Xsystems to which STEVIE has been ported. X.H 2 "Atari ST" X.H 3 "TOS" XThe editor has been tested in all three resolutions, although low and Xhigh res. are less tested than medium. The 50-line high res. mode can Xbe used by setting the 'lines' parameter to 50. Alternatively, the Xenvironment variable 'LINES' can be set. The editor doesn't actively Xset the number of lines on the screen. It just operates using the number Xof lines it was told. X.P XThe arrow keys, as well as the <INSERT>, <HELP>, and <UNDO> keys are Xall mapped appropriately. X.H 3 "Minix" XThe editor is pretty much the same under Minix, but many of the Xkeyboard mappings aren't supported. X.H 2 "UNIX" XThe editor has been ported to UNIX System V release 3 as well as 4.2 BSD. XThis was done Xmainly to get some profiling data so I haven't put much effort into Xdoing the UNIX version right. It's hard-coded for ansi-style escape Xsequences and doesn't use the termcap/terminfo routines at all. X.H 2 "OS/2" XThis port was done because the editor that comes with the OS/2 developer's Xkit really stinks. Make sure 'ansi' mode is on (using the 'ansi' command). XThe OS/2 console driver doesn't support insert/delete line, so STEVIE Xbypasses the driver and makes the appropriate system calls directly. XThis is all done in the system-specific part of the editor so the kludge Xis at least localized. X.P XThe arrow keys, page up/down and home/end all do what Xyou'd expect. The function keys are hard-coded to some useful macros until XI can get true support for macros into the editor. The current mappings Xare: X.DS 1 XF1 :p <RETURN> XF2 :n <RETURN> XF3 :e # <RETURN> XF4 :rew <RETURN> XF5 [[ XF6 ]] XF7 << XF8 >> XF9 :x <RETURN> XF10 :help <RETURN> X XS-F1 :p! <RETURN> XS-F2 :n! <RETURN> X.DE X.H 2 "MSDOS" XSTEVIE has been ported to MSDOS 3.3 using the Microsoft XC compiler, version 5.1. XThe keyboard mappings are the same as for OS/2. XThe only problem with the PC version is that the inefficiency of Xthe screen update code becomes painfully apparent on slower machines. X.H 1 "Missing Features" X.AL X.LI XCounts aren't yet supported everywhere that they should be. X.LI XMacros with support for function keys. X.LI XMore "set" options. X.LI XMany others... X.LE X.H 1 "Known Bugs and Problems" X.AL X.LI XThe change operator is only half-way implemented. It works for character Xmotions but not line motions. This isn't so bad since most change Xoperations are character oriented anyway. X.LI XThe yank buffer uses statically allocated memory, so large yanks Xwill fail. If a delete spans an area larger than the yank buffer, Xthe program asks Xfor confirmation before proceeding. That way, if you were moving text, Xyou don't get screwed by the limited yank buffer. You just have to move Xsmaller chunks at a time. All the internal buffers (yank, redo, etc.) Xneed to be reworked to allocate memory dynamically. The 'undo' buffer Xis now dynamically allocated, so any change can be undone. X.LI XIf you stay in insert mode for a long time, the insert buffer can overflow. XThe editor will print a message and dump you back into command mode. X.LI XThe current version of the substitute command (i.e. ":s/foo/bar") can't Xbe undone. X.LI XSeveral other less bothersome glitches... X.LE X.SK X.H 1 "Conclusion" XThe editor has reached a pretty stable state, and performs well on Xthe systems I use it on, so I'm pretty much in maintenance mode now. XThere's still plenty to be done; the screen update code is still pretty Xinefficient and the yank/put code is still primitive. XBut after more than a year of hacking, I'm ready to work on new projects. XI'm still interested in bug reports, and I do still add a new feature Xfrom time to time, but the rate of change is way down now. X.P XI'd like to thank Tim Thompson for writing the original version of the Xeditor. His program was well structured and quite readable. Thanks for Xgiving me a good base to work with. X.P XIf you're reading this file, but didn't get the source code for STEVIE, Xit can be had by sending a disk with return postage to the address given Xbelow. I can write disks for the Atari ST (SS or DS) or MSDOS (360K or X1.2M). Please be sure to include the return postage. I don't intend to Xmake money from this program, but I don't want to lose any either. X.P XI'm not planning to try to coordinate the various ports of STEVIE that Xmay occur. I just don't have the time. But if you do port it, I'd be Xinterested in hearing about it. X.DS 1 XTony Andrews UUCP: onecom!wldrdg!tony X5902E Gunbarrel Ave. XBoulder, CO 80301 X.DE X.SK X.HU "Character Function Summary" XThe following list describes the meaning of each character that's used Xby the editor. In some cases characters have meaning in both command and Xinsert mode; these are all described. X.SP 2 X.VL 8 X.LI ^@ XThe null character. Not used in any mode. This character may not Xbe present in the file, as is the case with vi. X.LI ^B XBackward one screen. X.LI ^D XScroll the window down one half screen. X.LI ^E XScroll the screen up one line. X.LI ^F XForward one screen. X.LI ^G XSame as ":f" command. Displays file information. X.LI ^H X(Backspace) Moves cursor left one space in command mode. XIn insert mode, erases the last character typed. X.LI ^J XMove the cursor down one line. X.LI ^L XClear and redraw the screen. X.LI ^M X(Carriage return) Move to the first non-white character Xin the next line. In insert mode, a carriage return opens a new Xline for input. X.LI ^N XMove the cursor down a line. X.LI ^P XMove the cursor up a line. X.LI ^U XScroll the window up one half screen. X.LI ^Y XScroll the screen down one line. X.LI ^[ XEscape cancels a pending command in command mode, and is used to Xterminate insert mode. X.LI ^] XMoves to the tag whose name is given by the word in which the cursor Xresides. X.LI ^` XSame as ":e #" if supported (system-dependent). X.LI SPACE XMove the cursor right on column. X.LI ! XThe filter operator always operates on a range of lines, passing the Xlines as input to a program, and replacing them with the output of the Xprogram. The shorthand command "!!" can be used to filter a number of Xlines (specified by a preceding count). The command "!" is replaced Xby the last command used, so "!!!<RETURN>" runs the given number of Xlines through the last specified command. X.LI $ XMove to the end of the current line. X.LI % XIf the cursor rests on a paren '()', brace '{}', or bracket '[]', Xmove to the matching one. X.LI \' XUsed to move the cursor to a previously marked position, as Xin 'a or 'b. The cursor moves to the start of the marked line. The Xspecial mark '' refers to the "previous context". X.LI + XSame as carriage return, in command mode. X.LI , XReverse of the last t, T, f, or F command. X.LI - XMove to the first non-white character in the previous line. X.LI . XRepeat the last edit command. X.LI / XStart of a forward string search command. String searches may be Xoptionally terminated with a closing slash. To search for a slash Xuse '\\/' in the search string. X.LI 0 XMove to the start of the current line. Also used within counts. X.LI 1-9 XUsed to add 'count' prefixes to commands. X.LI : XPrefix character for "ex" commands. X.LI ; XRepeat last t, T, f, or F command. X.LI < XThe 'left shift' operator. X.LI > XThe 'right shift' operator. X.LI ? XSame as '/', but search backward. X.LI A XAppend at the end of the current line. X.LI B XBackward one blank-delimited word. X.LI C XChange the rest of the current line. X.LI D XDelete the rest of the current line. X.LI E XEnd of the end of a blank-delimited word. X.LI F XFind a character backward on the current line. X.LI G XGo to the given line number (end of file, by default). X.LI H XMove to the first non-white char. on the top screen line. X.LI I XInsert before the first non-white char. on the current line. X.LI J XJoin two lines. X.LI L XMove to the first non-white char. on the bottom screen line. X.LI M XMove to the first non-white char. on the middle screen line. X.LI N XReverse the last string search. X.LI O XOpen a new line above the current line, and start inserting. X.LI P XPut the yank/delete buffer before the current cursor position. X.LI R XReplace characters until an "escape" character is received. XSimilar to insert mode, but replaces instead of inserting. XTyping a newline in replace mode is the same as in insert mode, Xbut replacing continues on the new line. X.LI T XReverse search 'upto' the given character. X.LI U XRestore the current line to its state before you started changing it. X.LI W XMove forward one blank-delimited word. X.LI X XDelete one character before the cursor. X.LI Y XYank the current line. Same as 'yy'. X.LI ZZ XExit from the editor, saving changes if necessary. X.LI [[ XMove backward one C function. X.LI ]] XMove forward one C function. X.LI ^ XMove to the first non-white on the current line. X.LI ` XMove to the given mark, as with '. The distinction between the two Xcommands is important when used with operators. I support the Xdifference correctly. If you don't know what I'm talking about, Xdon't worry, it won't matter to you. X.LI a XAppend text after the cursor. X.LI b XBack one word. X.LI c XThe change operator. X.LI d XThe delete operator. X.LI e XMove to the end of a word. X.LI f XFind a character on the current line. X.LI h XMove left one column. X.LI i XInsert text before the cursor. X.LI j XMove down one line. X.LI k XMove up one line. X.LI l XMove right one column. X.LI m XSet a mark at the current position (e.g. ma or mb). X.LI n XRepeat the last string search. X.LI o XOpen a new line and start inserting text. X.LI p XPut the yank/delete buffer after the cursor. X.LI r XReplace a character. X.LI s XReplace characters. X.LI t XMove forward 'upto' the given character on the current line. X.LI u XUndo the last edit. X.LI w XMove forward one word. X.LI x XDelete the character under the cursor. X.LI y XThe yank operator. X.LI z XRedraw the screen with the current line at the top (zRETURN), Xthe middle (z.), or the bottom (z-). X.LI | XMove to the column given by the preceding count. X.LE X.de TX X.ce XSTEVIE - User Guide X.sp X.. X.TC END_OF_FILE if test 20348 -ne `wc -c <'stevie.mm'`; then echo shar: \"'stevie.mm'\" unpacked with wrong size! fi # end of 'stevie.mm' fi echo shar: End of shell archive. exit 0 Robert Regn\ rtregn@faui32.uucp\ rtregn@immd3.informatik.uni-erlangen.de
rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) (12/15/88)
Files not used for Minix are renamed from *.c to *_c Robert Regn\ rtregn@faui32.uucp\ rtregn@immd3.informatik.uni-erlangen.de #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: alloc.c ascii.h cmdline.c ctags.c dos_c edit.c env.h # fileio.c help.c hexchars.c keymap.h linefunc.c # Wrapped by rtregn@faui32 on Wed Dec 14 17:04:57 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'alloc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'alloc.c'\" else echo shar: Extracting \"'alloc.c'\" \(4435 characters\) sed "s/^X//" >'alloc.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: alloc.c,v 1.2 88/08/26 08:44:18 tony Exp $"; X X/* X * Various allocation routines and routines returning information about X * allocated objects. X * X * $Log: alloc.c,v $ X * Revision 1.2 88/08/26 08:44:18 tony X * Misc. changes to make lint happy. X * X * Revision 1.1 88/03/20 21:06:06 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xchar * Xalloc(size) Xunsigned size; X{ X char *p; /* pointer to new storage space */ X X p = malloc(size); X if ( p == (char *)NULL ) { /* if there is no more room... */ X emsg("alloc() is unable to find memory!"); X } X return(p); X} X Xchar * Xstrsave(string) Xchar *string; X{ X return(strcpy(alloc((unsigned)(strlen(string)+1)),string)); X} X Xvoid Xscreenalloc() X{ X /* X * If we're changing the size of the screen, free the old arrays X */ X if (Realscreen != NULL) X free(Realscreen); X if (Nextscreen != NULL) X free(Nextscreen); X X Realscreen = malloc((unsigned)(Rows*Columns)); X Nextscreen = malloc((unsigned)(Rows*Columns)); X} X X/* X * Allocate and initialize a new line structure with room for X * 'nchars' characters. X */ XLINE * Xnewline(nchars) Xint nchars; X{ X register LINE *l; X X if ((l = (LINE *) alloc(sizeof(LINE))) == NULL) X return (LINE *) NULL; X X l->s = alloc((unsigned) nchars); /* the line is empty */ X l->s[0] = NUL; X l->size = nchars; X X l->prev = (LINE *) NULL; /* should be initialized by caller */ X l->next = (LINE *) NULL; X X return l; X} X X/* X * filealloc() - construct an initial empty file buffer X */ Xvoid Xfilealloc() X{ X if ((Filemem->linep = newline(1)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X if ((Filetop->linep = newline(1)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X if ((Fileend->linep = newline(1)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X Filemem->index = 0; X Filetop->index = 0; X Fileend->index = 0; X X Filetop->linep->next = Filemem->linep; /* connect Filetop to Filemem */ X Filemem->linep->prev = Filetop->linep; X X Filemem->linep->next = Fileend->linep; /* connect Filemem to Fileend */ X Fileend->linep->prev = Filemem->linep; X X *Curschar = *Filemem; X *Topchar = *Filemem; X X Filemem->linep->num = 0; X Fileend->linep->num = 0xffff; X X clrall(); /* clear all marks */ X u_clear(); /* clear the undo buffer */ X} X X/* X * freeall() - free the current buffer X * X * Free all lines in the current buffer. X */ Xvoid Xfreeall() X{ X LINE *lp, *xlp; X X for (lp = Filetop->linep; lp != NULL ;lp = xlp) { X if (lp->s != NULL) X free(lp->s); X xlp = lp->next; X free(lp); X } X X Curschar->linep = NULL; /* clear pointers */ X Filetop->linep = NULL; X Filemem->linep = NULL; X Fileend->linep = NULL; X X u_clear(); X} X X/* X * bufempty() - return TRUE if the buffer is empty X */ Xbool_t Xbufempty() X{ X return (buf1line() && Filemem->linep->s[0] == NUL); X} X X/* X * buf1line() - return TRUE if there is only one line X */ Xbool_t Xbuf1line() X{ X return (Filemem->linep->next == Fileend->linep); X} X X/* X * lineempty() - return TRUE if the current line is empty X */ Xbool_t Xlineempty() X{ X return (Curschar->linep->s[0] == NUL); X} X X/* X * endofline() - return TRUE if the given position is at end of line X * X * This routine will probably never be called with a position resting X * on the NUL byte, but handle it correctly in case it happens. X */ Xbool_t Xendofline(p) Xregister LPTR *p; X{ X return (p->linep->s[p->index] == NUL || p->linep->s[p->index+1] == NUL); X} X/* X * canincrease(n) - returns TRUE if the current line can be increased 'n' bytes X * X * This routine returns immediately if the requested space is available. X * If not, it attempts to allocate the space and adjust the data structures X * accordingly. If everything fails it returns FALSE. X */ Xbool_t Xcanincrease(n) Xregister int n; X{ X register int nsize; X register char *s; /* pointer to new space */ X X nsize = strlen(Curschar->linep->s) + 1 + n; /* size required */ X X if (nsize <= Curschar->linep->size) X return TRUE; X X /* X * Need to allocate more space for the string. Allow some extra X * space on the assumption that we may need it soon. This avoids X * excessive numbers of calls to malloc while entering new text. X */ X if ((s = alloc((unsigned) (nsize + SLOP))) == NULL) { X emsg("Can't add anything, file is too big!"); X State = NORMAL; X return FALSE; X } X X Curschar->linep->size = nsize + SLOP; X strcpy(s, Curschar->linep->s); X free(Curschar->linep->s); X Curschar->linep->s = s; X X return TRUE; X} END_OF_FILE if test 4435 -ne `wc -c <'alloc.c'`; then echo shar: \"'alloc.c'\" unpacked with wrong size! fi # end of 'alloc.c' fi if test -f 'ascii.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ascii.h'\" else echo shar: Extracting \"'ascii.h'\" \(350 characters\) sed "s/^X//" >'ascii.h' <<'END_OF_FILE' X/* X * Definitions of various common control characters X * X * $Header: ascii.h,v 1.1 88/03/20 21:03:24 tony Exp $ X * X * $Log: ascii.h,v $ X * Revision 1.1 88/03/20 21:03:24 tony X * Initial revision X * X * X */ X X#define NUL '\0' X#define BS '\010' X#define TAB '\011' X#define NL '\012' X#define CR '\015' X#define ESC '\033' X X#define CTRL(x) ((x) & 0x1f) END_OF_FILE if test 350 -ne `wc -c <'ascii.h'`; then echo shar: \"'ascii.h'\" unpacked with wrong size! fi # end of 'ascii.h' fi if test -f 'cmdline.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cmdline.c'\" else echo shar: Extracting \"'cmdline.c'\" \(14535 characters\) sed "s/^X//" >'cmdline.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: cmdline.c,v 1.9 88/11/10 08:58:04 tony Exp $"; X X/* X * Routines to parse and execute "command line" commands, such as searches X * or colon commands. X * X * further modifications by: Robert Regn rtregn@faui32.uucp X * X * $Log: cmdline.c,v $ X * Revision 1.9 88/11/10 08:58:04 tony X * Added support for modelines when a new file edit is started. X * X * Revision 1.8 88/11/01 21:31:56 tony X * Added a call to flushbuf() in msg() to make sure messages get out X * when they should. X * X * Revision 1.7 88/10/27 08:21:38 tony X * Removed support for Megamax. Added support for ":sh" and ":!", and X * removed doshell() since it needs to be system-dependent. Changed X * ":p" to ":N" to avoid name conflict with the "print" command. The X * address spec "%" is translated to "1,$". The "=" command now works X * to print the line number of the given address. X * X * Revision 1.6 88/08/26 08:44:48 tony X * Misc. changes to make lint happy. X * X * Revision 1.5 88/06/26 14:48:20 tony X * Added a call to doglob() to handle the new ":g" command. X * X * Revision 1.4 88/06/25 21:43:19 tony X * Fixed a problem in the processing of colon commands that caused X * substitutions of patterns containing white space to fail. X * X * Revision 1.3 88/04/24 21:35:09 tony X * Added a new colon command "s" (substitute), which is performed by the X * routine dosub() in search.c. X * X * Revision 1.2 88/03/23 21:25:10 tony X * Fixed a bug involving backspacing out of a colon or search command. X * The fix is a hack until that part of the code can be cleaned up more. X * X * Revision 1.1 88/03/20 21:06:19 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xstatic char *altfile = NULL; /* alternate file */ Xstatic int altline; /* line # in alternate file */ X Xstatic char *nowrtmsg = "No write since last change (use ! to override)"; Xstatic char *nooutfile = "No output file"; Xstatic char *morefiles = "more files to edit"; X Xextern char **files; /* used for "n" and "rew" */ Xextern int numfiles, curfile; X X/* X * The next two variables contain the bounds of any range given in a X * command. If no range was given, both contain null line pointers. X * If only a single line was given, u_pos will contain a null line X * pointer. X */ Xstatic LPTR l_pos, u_pos; X Xstatic bool_t interactive; /* TRUE if we're reading a real command line */ X X#define CMDSZ 100 /* size of the command buffer */ X Xstatic bool_t doecmd(); Xstatic void badcmd(), get_range(); Xstatic LPTR *get_line(); X X/* X * readcmdline() - accept a command line starting with ':', '/', or '?' X * X * readcmdline() accepts and processes colon commands and searches. If X * 'cmdline' is null, the command line is read here. Otherwise, cmdline X * points to a complete command line that should be used. This is used X * in main() to handle initialization commands in the environment variable X * "EXINIT". X */ Xvoid Xreadcmdline(firstc, cmdline) Xint firstc; /* either ':', '/', or '?' */ Xchar *cmdline; /* optional command string */ X{ X int c; X char buff[CMDSZ]; X char cmdbuf[CMDSZ]; X char argbuf[CMDSZ]; X char *p, *q, *cmd, *arg; X X /* X * Clear the range variables. X */ X l_pos.linep = (struct line *) NULL; X u_pos.linep = (struct line *) NULL; X X interactive = (cmdline == NULL); X X if (interactive) X gotocmd(TRUE, firstc); X p = buff; X if ( firstc != ':' ) X *p++ = firstc; X X if (interactive) { X /* collect the command string, handling '\b' and @ */ X for ( ; ; ) { X c = vgetc(); X if ( c=='\n'||c=='\r'||c==EOF ) X break; X if ( c=='\b' ) { X if ( p > buff + (firstc != ':') ) { X p--; X /* this is gross, but it relies X * only on 'gotocmd' X */ X gotocmd(TRUE, firstc==':'?':':0); X for ( q=buff; q<p; q++ ) X outchar(*q); X } else { X msg(""); X return; /* back to cmd mode */ X } X continue; X } X if ( c=='@' ) { X p = buff; X gotocmd(TRUE, firstc); X continue; X } X outchar(c); X *p++ = c; X } X *p = '\0'; X } else { X if (strlen(cmdline) > CMDSZ-2) /* should really do something */ X return; /* better here... */ X strcpy(p, cmdline); X } X X /* skip any initial white space */ X for ( cmd = buff; *cmd != NUL && isspace(*cmd); cmd++ ) X ; X X /* search commands */ X c = *cmd; X if ( c == '/' || c == '?' ) { X cmd++; X if ( *cmd == c || *cmd == NUL ) { X /* X * The command was just '/' or '?' or possibly X * '//' or '??'. Search in the requested direction X * for the last search string used. The NULL X * parameter to dosearch() tells it to do this. X */ X dosearch((c == '/') ? FORWARD : BACKWARD, NULL); X return; X } X /* If there is a matching '/' or '?' at the end, toss it */ X p = strchr(cmd, NUL); X if ( *(p-1) == c && *(p-2) != '\\' ) X *(p-1) = NUL; X dosearch((c == '/') ? FORWARD : BACKWARD, cmd); X return; X } X X if (*cmd == '%') { /* change '%' to "1,$" */ X strcpy(cmdbuf, "1,$"); /* kind of gross... */ X strcat(cmdbuf, cmd+1); X strcpy(cmd, cmdbuf); X } X X while ( (p=strchr(cmd, '%')) != NULL && *(p-1) != '\\') { X /* change '%' to Filename */ X if (Filename == NULL) { X emsg("No filename"); X return; X } X *p= NUL; X strcpy (cmdbuf, cmd); X strcat (cmdbuf, Filename); X strcat (cmdbuf, p+1); X strcpy(cmd, cmdbuf); X msg(cmd); /*repeat */ X } X X while ( (p=strchr(cmd, '#')) != NULL && *(p-1) != '\\') { X /* change '#' to Altname */ X if (altfile == NULL) { X emsg("No alternate file"); X return; X } X *p= NUL; X strcpy (cmdbuf, cmd); X strcat (cmdbuf, altfile); X strcat (cmdbuf, p+1); X strcpy(cmd, cmdbuf); X msg(cmd); /*repeat */ X } X X /* X * Parse a range, if present (and update the cmd pointer). X */ X get_range(&cmd); X X if (l_pos.linep != NULL) { X if (LINEOF(&l_pos) > LINEOF(&u_pos)) { X emsg("Invalid range"); X return; X } X } X X strcpy(cmdbuf, cmd); /* save the unmodified command */ X X /* isolate the command and find any argument */ X for ( p=cmd; *p != NUL && ! isspace(*p); p++ ) X ; X if ( *p == NUL ) X arg = NULL; X else { X *p = NUL; X for (p++; *p != NUL && isspace(*p) ;p++) X ; X if (*p == NUL) X arg = NULL; X else { X strcpy(argbuf, p); X arg = argbuf; X } X } X if ( strcmp(cmd,"q!")==0 ) X getout(); X if ( strcmp(cmd,"q")==0 ) { X if ( Changed ) X emsg(nowrtmsg); X else X if ( (curfile + 1) < numfiles ) X emsg (morefiles); X else getout(); X return; X } X if ( strcmp(cmd,"w")==0 ) { X if ( arg == NULL ) { X if (Filename != NULL) { X writeit(Filename, &l_pos, &u_pos); X } else X emsg(nooutfile); X } X else X writeit(arg, &l_pos, &u_pos); X return; X } X if ( strcmp(cmd,"wq")==0 ) { X if (Filename != NULL) { X if (writeit(Filename, (LPTR *)NULL, (LPTR *)NULL)) X getout(); X } else X emsg(nooutfile); X return; X } X if ( strcmp(cmd, "x") == 0 ) { X doxit(); X return; X } X X if ( strcmp(cmd,"f")==0 && arg==NULL ) { X fileinfo(); X return; X } X if ( *cmd == 'n' ) { X if ( (curfile + 1) < numfiles ) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[++curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if ( *cmd == 'N' ) { X if ( curfile > 0 ) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[--curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if ( strncmp(cmd, "rew", 3) == 0) { X if (numfiles <= 1) /* nothing to rewind */ X return; X curfile = 0; X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[3] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[0]); X stuffin("\n"); X return; X } X if ( strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0 ) { X doecmd(arg, cmd[1] == '!'); X return; X } X if ( strcmp(cmd,"f") == 0 ) { X Filename = strsave(arg); X filemess(""); X return; X } X if ( strcmp(cmd,"r") == 0 ) { X if ( arg == NULL ) { X badcmd(); X return; X } X if (readfile(arg, Curschar, 1)) { X emsg("Can't open file"); X return; X } X updatescreen(); X CHANGED; X return; X } X if ( strcmp(cmd,"=")==0 ) { X smsg("%d", cntllines(Filemem, &l_pos)); X return; X } X if ( strncmp(cmd,"ta", 2) == 0 ) { X dotag(arg, cmd[2] == '!'); X return; X } X if ( strncmp(cmd,"set", 2)==0 ) { X doset(arg, interactive); X return; X } X if ( strcmp(cmd,"help")==0 ) { X if (help()) { X screenclear(); X updatescreen(); X } X return; X } X if ( strncmp(cmd, "ve", 2) == 0) { X extern char *Version; X X msg(Version); X return; X } X if ( strcmp(cmd, "sh") == 0) { X doshell(NULL); X return; X } X if ( *cmd == '!' ) { X doshell(cmdbuf+1); X return; X } X if ( strncmp(cmd, "s/", 2)==0 ) { X dosub(&l_pos, &u_pos, cmdbuf+1); X return; X } X if (strncmp(cmd, "g/", 2) == 0) { X doglob(&l_pos, &u_pos, cmdbuf+1); X return; X } X /* X * If we got a line, but no command, then go to the line. X */ X if (*cmd == NUL && l_pos.linep != NULL) { X *Curschar = l_pos; X cursupdate(); X return; X } X X badcmd(); X} X X Xdoxit() X{ X if (Changed) { X if (Filename != NULL) { X if (!writeit(Filename, (LPTR *)NULL, (LPTR *)NULL)) X return; X } else { X emsg(nooutfile); X return; X } X } X if ( (curfile + 1) < numfiles ) X emsg (morefiles); X else getout(); X} X X/* X * get_range - parse a range specifier X * X * Ranges are of the form: X * X * addr[,addr] X * X * where 'addr' is: X * X * $ [+- NUM] X * 'x [+- NUM] (where x denotes a currently defined mark) X * . [+- NUM] X * NUM X * X * The pointer *cp is updated to point to the first character following X * the range spec. If an initial address is found, but no second, the X * upper bound is equal to the lower. X */ Xstatic void Xget_range(cp) Xchar **cp; X{ X LPTR *l; X char *p; X X if ((l = get_line(cp)) == NULL) X return; X X l_pos = *l; X X for (p = *cp; *p != NUL && isspace(*p) ;p++) X ; X X *cp = p; X X if (*p != ',') { /* is there another line spec ? */ X u_pos = l_pos; X return; X } X X *cp = ++p; X X if ((l = get_line(cp)) == NULL) { X u_pos = l_pos; X return; X } X X u_pos = *l; X} X Xstatic LPTR * Xget_line(cp) Xchar **cp; X{ X static LPTR pos; X LPTR *lp; X char *p, c; X int lnum; X X pos.index = 0; /* shouldn't matter... check back later */ X X p = *cp; X /* X * Determine the basic form, if present. X */ X switch (c = *p++) { X X case '$': X pos.linep = Fileend->linep->prev; X break; X X case '.': X pos.linep = Curschar->linep; X break; X X case '\'': X if ((lp = getmark(*p++)) == NULL) { X emsg("Unknown mark"); X return (LPTR *) NULL; X } X pos = *lp; X break; X X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X for (lnum = c - '0'; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X pos = *gotoline(lnum); X break; X X default: X return (LPTR *) NULL; X } X X while (*p != NUL && isspace(*p)) X p++; X X if (*p == '-' || *p == '+') { X bool_t neg = (*p++ == '-'); X X for (lnum = 0; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X if (neg) X lnum = -lnum; X X pos = *gotoline( cntllines(Filemem, &pos) + lnum ); X } X X *cp = p; X return &pos; X} X Xstatic void Xbadcmd() X{ X if (interactive) X emsg("Unrecognized command"); X} X X#define LSIZE 512 /* max. size of a line in the tags file */ X X/* X * dotag(tag, force) - goto tag X */ Xvoid Xdotag(tag, force) Xchar *tag; Xbool_t force; X{ X FILE *tp, *fopen(); X char lbuf[LSIZE]; X char *fname, *str; X X if ((tp = fopen("tags", "r")) == NULL) { X emsg("Can't open tags file"); X return; X } X X while (fgets(lbuf, LSIZE, tp) != NULL) { X X if ((fname = strchr(lbuf, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *fname++ = '\0'; X if ((str = strchr(fname, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *str++ = '\0'; X X if (strcmp(lbuf, tag) == 0) { X if (doecmd(fname, force)) { X stuffin(str); /* str has \n at end */ X stuffin("\007"); /* CTRL('G') */ X fclose(tp); X return; X } X } X } X emsg("tag not found"); X fclose(tp); X} X Xstatic bool_t Xdoecmd(arg, force) Xchar *arg; Xbool_t force; X{ X int line = 1; /* line # to go to in new file */ X X if (!force && Changed) { X emsg(nowrtmsg); X if (altfile) X free(altfile); X altfile = strsave(arg); X return FALSE; X } X if ( arg != NULL ) { X /* X * First detect a ":e" on the current file. This is mainly X * for ":ta" commands where the destination is within the X * current file. X */ X if (Filename != NULL && strcmp(arg, Filename) == 0) { X if (!Changed || (Changed && !force)) X return TRUE; X } X#ifdef OLDSUB X if (strcmp(arg, "#") == 0) { /* alternate */ X char *s = Filename; X X if (altfile == NULL) { X emsg("No alternate file"); X return FALSE; X } X Filename = altfile; X altfile = s; X line = altline; X altline = cntllines(Filemem, Curschar); X } else X if (strchr(arg, '%')) { X char *s, *buf=alloc(strlen(arg)+strlen(Filename)); X if (Filename == NULL) { X emsg("No filename"); X return FALSE; X } X s = strchr(arg, '%'); X *s = 0; X strcpy (buf, arg); X strcat (buf, Filename); X strcat (buf, s+1); X if (altfile) /* I'm not shure if it is ok */ X free(altfile); X altfile = Filename; X altline = cntllines(Filemem, Curschar); X Filename = buf; X } else { X#endif X if (altfile) /* I'm not shure if it is ok */ X { X if (strcmp (arg, altfile) == 0) X line = altline; X free(altfile); X } X altfile = Filename; X altline = cntllines(Filemem, Curschar); X Filename = strsave(arg); X#ifdef OLDSUB X } X#endif X } X if (Filename == NULL) { X emsg("No filename"); X return FALSE; X } X X /* clear mem and read file */ X freeall(); X filealloc(); X UNCHANGED; X X if (readfile(Filename, Filemem, 0)) X filemess("[New File]"); X *Topchar = *Curschar; X if (line != 1) { X stuffnum(line); X stuffin("G"); X } X do_mlines(); X setpcmark(); X updatescreen(); X return TRUE; X} X Xvoid Xgotocmd(clr, firstc) Xbool_t clr; Xchar firstc; X{ X windgoto(Rows-1,0); X if ( clr ) X outstr(T_EL); /* clear the bottom line */ X if ( firstc ) X outchar(firstc); X} X X/* X * msg(s) - displays the string 's' on the status line X */ Xvoid Xmsg(s) Xchar *s; X{ X gotocmd(TRUE, 0); X outstr(s); X flushbuf(); X} X X/*VARARGS1*/ Xvoid Xsmsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9) Xchar *s; Xint a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X char sbuf[80]; X X sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9); X msg(sbuf); X} X X/* X * emsg() - display an error message X * X * Rings the bell, if appropriate, and calls message() to do the real work X */ Xvoid Xemsg(s) Xchar *s; X{ X if (P(P_EB)) X beep(); X msg(s); X} X Xvoid Xwait_return() X{ X char c; X X outstr("Press RETURN to continue"); X do { X c = vgetc(); X } while (c != '\r' && c != '\n' && c != ' ' && c != ':'); X X if ( c == ':') { /* this can vi too */ X outstr("\n"); X readcmdline(c, NULL); X } X else X screenclear(); X updatescreen(); X} END_OF_FILE if test 14535 -ne `wc -c <'cmdline.c'`; then echo shar: \"'cmdline.c'\" unpacked with wrong size! fi # end of 'cmdline.c' fi if test -f 'ctags.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ctags.c'\" else echo shar: Extracting \"'ctags.c'\" \(3077 characters\) sed "s/^X//" >'ctags.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: ctags.c,v 1.1 88/03/20 21:06:51 tony Exp $"; X X/* X * ctags - first cut at a UNIX ctags re-implementation X * X * $Log: ctags.c,v $ X * Revision 1.1 88/03/20 21:06:51 tony X * Initial revision X * X * X */ X X/* X * Caveats: X * X * Only simple function declarations are recognized, as in: X * X * type X * fname(...) X * X * where "fname" is the name of the function and must come at the beginning X * of a line. This is the form I always use, so the limitation doesn't X * bother me. X * X * Macros (with or without parameters) of the following form are also detected: X * X * "#" [white space] "define" [white space] NAME X * X * No sorting or detection of duplicate functions is done. X * X * If there are no arguments, a list of filenames to be searched is read X * from the standard input. Otherwise, all arguments are assumed to be X * file names. X * X * Tony Andrews X * August 1987 X */ X X#include <stdio.h> X#include <ctype.h> X#include <string.h> X X#if 0 X#define index strchr X#endif X Xint ac; Xchar **av; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X char *fname, *nextfile(); X FILE *tp, *fopen(); X X ac = argc; X av = argv; X X if ((tp = fopen("tags", "w")) == NULL) { X fprintf(stderr, "Can't create tags file\n"); X exit(1); X } X X while ((fname = nextfile()) != NULL) X dofile(fname, tp); X X fclose(tp); X exit(0); X} X Xchar * Xnextfile() /* returns ptr to next file to be searched, null at end */ X{ X static char buf[128]; X static int ap = 1; X char *gets(); X X if (ac <= 1) { /* read from stdin */ X if (feof(stdin)) X return (char *) NULL; X return (gets(buf)); X } else { X if (ap < ac) X return av[ap++]; X else X return (char *) NULL; X } X} X X#define LSIZE 512 /* max. size of a line */ X X#define BEGID(c) (isalpha(c) || (c) == '_') X#define MIDID(c) (isalpha(c) || isdigit(c) || (c) == '_') X Xdofile(fn, tp) Xchar *fn; XFILE *tp; X{ X FILE *fp, *fopen(); X char *cp, *index(); X char lbuf[LSIZE]; X char func[LSIZE]; X int i, j; X X if ((fp = fopen(fn, "r")) == NULL) { X fprintf(stderr, "Can't open file '%s' - skipping\n", fn); X return; X } X X while (fgets(lbuf, LSIZE, fp) != NULL) { X X if (BEGID(lbuf[0])) { /* could be a function */ X for (i=0; MIDID(lbuf[i]) ;i++) /* grab the name */ X func[i] = lbuf[i]; X X func[i] = '\0'; /* null terminate the name */ X X /* X * We've skipped to the end of what may be a function X * name. Check to see if the next char is a paren, X * and make sure the closing paren is here too. X */ X if (lbuf[i]=='(' && (((cp = index(lbuf, ')'))!=NULL))) { X *++cp = '\0'; X fprintf(tp, "%s\t%s\t/^%s\\(/\n", func,fn,func); X } X X } else if (lbuf[0] == '#') { /* could be a define */ X for (i=1; isspace(lbuf[i]) ;i++) X ; X if (strncmp(&lbuf[i], "define", 6) != 0) X continue; X X i += 6; /* skip "define" */ X X for (; isspace(lbuf[i]) ;i++) X ; X X if (!BEGID(lbuf[i])) X continue; X X for (j=0; MIDID(lbuf[i]) ;i++, j++) X func[j] = lbuf[i]; X X func[j] = '\0'; /* null terminate the name */ X lbuf[i] = '\0'; /* null terminate the line */ X fprintf(tp, "%s\t%s\t/^%s/\n", func, fn, lbuf); X } X } X fclose(fp); X} END_OF_FILE if test 3077 -ne `wc -c <'ctags.c'`; then echo shar: \"'ctags.c'\" unpacked with wrong size! fi # end of 'ctags.c' fi if test -f 'dos_c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dos_c'\" else echo shar: Extracting \"'dos_c'\" \(5670 characters\) sed "s/^X//" >'dos_c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: dos.c,v 1.4 88/10/28 14:40:15 tony Exp $"; X X/* X * DOS System-dependent routines. X * X * System-specific code for MS-DOS. This has been tested with X * MSDOS 3.3 on an AT. Also, the console driver "nansi.sys" is X * required. X * X * $Log: dos.c,v $ X * Revision 1.4 88/10/28 14:40:15 tony X * Added doshell() to support ":sh" and ":!". X * X * Revision 1.3 88/10/06 10:13:30 tony X * Added fixname() routine which trims the base and extension parts of X * a file name to 8 and 3 characters, and returns a pointer to the X * resulting string. This makes it easier to deal with UNIX-style names X * on stupid systems. X * X * Revision 1.2 88/08/26 13:39:42 tony X * Added routines to get and set the switch character, and modified the X * init and terminate code to set the switch character to '/' during X * execution. This seems to be needed to make the system() routine happy. X * X * Revision 1.1 88/05/03 14:22:16 tony X * Initial revision X * X * X */ X X#include "stevie.h" X#include <stdio.h> X#include <dos.h> X Xstatic char getswitch(); Xstatic void setswitch(); X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X int c; X X for (;;beep()) { /* loop until we get a valid character */ X X flushbuf(); /* flush any pending output */ X X switch (c = getch()) { X case 0x1e: X return K_CGRAVE; X case 0: /* special key */ X if (State != NORMAL) { X c = getch(); /* throw away next char */ X continue; /* and loop for another char */ X } X switch (c = getch()) { X case 0x50: X return K_DARROW; X case 0x48: X return K_UARROW; X case 0x4b: X return K_LARROW; X case 0x4d: X return K_RARROW; X case 0x52: X return K_INSERT; X case 0x47: X stuffin("1G"); X return -1; X case 0x4f: X stuffin("G"); X return -1; X case 0x51: X stuffin(mkstr(CTRL('F'))); X return -1; X case 0x49: X stuffin(mkstr(CTRL('B'))); X return -1; X /* X * Hard-code some useful function key macros. X */ X case 0x3b: /* F1 */ X stuffin(":p\n"); X return -1; X case 0x54: /* SF1 */ X stuffin(":p!\n"); X return -1; X case 0x3c: /* F2 */ X stuffin(":n\n"); X return -1; X case 0x55: /* SF2 */ X stuffin(":n!\n"); X return -1; X case 0x3d: /* F3 */ X stuffin(":e #\n"); X return -1; X case 0x3e: /* F4 */ X stuffin(":rew\n"); X return -1; X case 0x57: /* SF4 */ X stuffin(":rew!\n"); X return -1; X case 0x3f: /* F5 */ X stuffin("[["); X return -1; X case 0x40: /* F6 */ X stuffin("]]"); X return -1; X case 0x41: /* F7 */ X stuffin("<<"); X return -1; X case 0x42: /* F8 */ X stuffin(">>"); X return -1; X case 0x43: /* F9 */ X stuffin(":x\n"); X return -1; X case 0x44: /* F10 */ X stuffin(":help\n"); X return -1; X default: X break; X } X break; X X default: X return c; X } X } X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xvoid Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xregister char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X X/* X * outstr(s) - write a string to the console X */ Xvoid Xoutstr(s) Xregister char *s; X{ X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X outone('\007'); X} X Xsleep(n) Xint n; X{ X /* X * Should do something reasonable here. X */ X} X Xvoid Xdelay() X{ X long l; X X flushbuf(); X /* X * Should do something better here... X */ X for (l=0; l < 5000 ;l++) X ; X} X Xstatic char schar; /* save original switch character */ X Xvoid Xwindinit() X{ X Columns = 80; X P(P_LI) = Rows = 25; X schar = getswitch(); X setswitch('/'); X} X Xvoid Xwindexit(r) Xint r; X{ X flushbuf(); X setswitch(schar); X exit(r); X} X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X r += 1; X c += 1; X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X FILE *fopen(); X char modestr[16]; X X sprintf(modestr, "%sb", mode); X return fopen(fname, modestr); X} X Xstatic char Xgetswitch() X{ X union REGS inregs, outregs; X X inregs.h.ah = 0x37; X inregs.h.al = 0; X X intdos(&inregs, &outregs); X X return outregs.h.dl; X} X Xstatic void Xsetswitch(c) Xchar c; X{ X union REGS inregs, outregs; X X inregs.h.ah = 0x37; X inregs.h.al = 1; X inregs.h.dl = c; X X intdos(&inregs, &outregs); X} X X#define PSIZE 128 X X/* X * fixname(s) - fix up a dos name X * X * Takes a name like: X * X * \x\y\z\base.ext X * X * and trims 'base' to 8 characters, and 'ext' to 3. X */ Xchar * Xfixname(s) Xchar *s; X{ X char *strchr(), *strrchr(); X static char f[PSIZE]; X char base[32]; X char ext[32]; X char *p; X int i; X X strcpy(f, s); X X for (i=0; i < PSIZE ;i++) X if (f[i] == '/') X f[i] = '\\'; X X /* X * Split the name into directory, base, extension. X */ X if ((p = strrchr(f, '\\')) != NULL) { X strcpy(base, p+1); X p[1] = '\0'; X } else { X strcpy(base, f); X f[0] = '\0'; X } X X if ((p = strchr(base, '.')) != NULL) { X strcpy(ext, p+1); X *p = '\0'; X } else X ext[0] = '\0'; X X /* X * Trim the base name if necessary. X */ X if (strlen(base) > 8) X base[8] = '\0'; X X if (strlen(ext) > 3) X ext[3] = '\0'; X X /* X * Paste it all back together X */ X strcat(f, base); X strcat(f, "."); X strcat(f, ext); X X return f; X} X Xvoid Xdoshell(cmd) Xchar *cmd; X{ X if (cmd == NULL) X cmd = "command.com"; X X system(cmd); X wait_return(); X} END_OF_FILE if test 5670 -ne `wc -c <'dos_c'`; then echo shar: \"'dos_c'\" unpacked with wrong size! fi # end of 'dos_c' fi if test -f 'edit.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'edit.c'\" else echo shar: Extracting \"'edit.c'\" \(7989 characters\) sed "s/^X//" >'edit.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: edit.c,v 1.7 88/11/10 13:29:15 tony Exp $"; X X/* X * The main edit loop as well as some other simple cursor movement routines. X * X * $Log: edit.c,v $ X * Revision 1.7 88/11/10 13:29:15 tony X * Added a call to do_mlines() to check for mode lines at initialization. X * X * Revision 1.6 88/10/06 10:11:50 tony X * Fixed a bug in scrolldown() involving the special case of the cursor X * being on the last line, and the line being scrolled onto the screen X * being long. The special case code needs to deal with physical lines, X * not logical. X * X * Revision 1.5 88/08/30 20:35:53 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 1.4 88/08/26 08:44:55 tony X * Misc. changes to make lint happy. X * X * Revision 1.3 88/05/01 20:08:47 tony X * Fixed some problems with the new auto-indent feature. X * X * Revision 1.2 88/04/30 19:59:43 tony X * Added support for auto-indent option. X * X * Revision 1.1 88/03/20 21:07:10 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * This flag is used to make auto-indent work right on lines where only X * a <RETURN> or <ESC> is typed. It is set when an auto-indent is done, X * and reset when any other editting is done on the line. If an <ESC> X * or <RETURN> is received, and did_ai is TRUE, the line is truncated. X */ Xbool_t did_ai = FALSE; X Xvoid Xedit() X{ X int c; X char *p, *q; X X Prenum = 0; X X /* position the display and the cursor at the top of the file. */ X *Topchar = *Filemem; X *Curschar = *Filemem; X Cursrow = Curscol = 0; X X do_mlines(); /* check for mode lines before starting */ X X for ( ;; ) { X X /* Figure out where the cursor is based on Curschar. */ X cursupdate(); X X windgoto(Cursrow,Curscol); X X c = vgetc(); X X if (State == NORMAL) { X X /* We're in the normal (non-insert) mode. */ X X /* Pick up any leading digits and compute 'Prenum' */ X if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){ X Prenum = Prenum*10 + (c-'0'); X continue; X } X /* execute the command */ X normal(c); X Prenum = 0; X X } else { X X /* X * Insert or Replace mode. X */ X switch (c) { X X case ESC: /* an escape ends input mode */ X X /* X * If we just did an auto-indent, truncate the X * line, and put the cursor back. X */ X if (did_ai) { X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X did_ai = FALSE; X } X X set_want_col = TRUE; X X /* Don't end up on a '\n' if you can help it. */ X if (gchar(Curschar) == NUL && Curschar->index != 0) X dec(Curschar); X X /* X * The cursor should end up on the last inserted X * character. This is an attempt to match the real X * 'vi', but it may not be quite right yet. X */ X if (Curschar->index != 0 && !endofline(Curschar)) X dec(Curschar); X X State = NORMAL; X msg(""); X X /* construct the Redo buffer */ X p=Redobuff; X q=Insbuff; X while ( q < Insptr ) X *p++ = *q++; X *p++ = ESC; X *p = NUL; X updatescreen(); X break; X X case CTRL('D'): X /* X * Control-D is treated as a backspace in insert X * mode to make auto-indent easier. This isn't X * completely compatible with vi, but it's a lot X * easier than doing it exactly right, and the X * difference isn't very noticeable. X */ X case BS: X /* can't backup past starting point */ X if (Curschar->linep == Insstart->linep && X Curschar->index <= Insstart->index) { X beep(); X break; X } X X /* can't backup to a previous line */ X if (Curschar->linep != Insstart->linep && X Curschar->index <= 0) { X beep(); X break; X } X X did_ai = FALSE; X dec(Curschar); X if (State == INSERT) X delchar(TRUE); X /* X * It's a little strange to put backspaces into X * the redo buffer, but it makes auto-indent a X * lot easier to deal with. X */ X *Insptr++ = BS; X Ninsert++; X cursupdate(); X updateline(); X break; X X case CR: X case NL: X *Insptr++ = NL; X Ninsert++; X opencmd(FORWARD, TRUE); /* open a new line */ X break; X X default: X did_ai = FALSE; X insertchar(c); X break; X } X } X } X} X X/* X * Special characters in this context are those that need processing other X * than the simple insertion that can be performed here. This includes ESC X * which terminates the insert, and CR/NL which need special processing to X * open up a new line. This routine tries to optimize insertions performed X * by the "redo" command, so it needs to know when it should stop and defer X * processing to the "normal" mechanism. X */ X#define ISSPECIAL(c) ((c) == NL || (c) == CR || (c) == ESC) X Xvoid Xinsertchar(c) Xint c; X{ X#if 0 X char *p; X X if ( ! anyinput() ) { X#endif X inschar(c); X *Insptr++ = c; X Ninsert++; X /* X * The following kludge avoids overflowing the statically X * allocated insert buffer. Just dump the user back into X * command mode, and print a message. X */ X if (Insptr+10 >= &Insbuff[1024]) { X stuffin(mkstr(ESC)); X emsg("No buffer space - returning to command mode"); X sleep(2); X } X#if 0 X } X else { X /* If there's any pending input, grab it all at once. */ X p = Insptr; X *Insptr++ = c; X Ninsert++; X for (c = vpeekc(); !ISSPECIAL(c) ;c = vpeekc()) { X c = vgetc(); X *Insptr++ = c; X Ninsert++; X } X *Insptr = '\0'; X insstr(p); X } X#endif X updateline(); X} X Xvoid Xgetout() X{ X windgoto(Rows-1,0); X putchar('\r'); X putchar('\n'); X windexit(0); X} X Xvoid Xscrolldown(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X X /* Scroll up 'nlines' lines. */ X while (nlines--) { X if ((p = prevline(Topchar)) == NULL) X break; X done += plines(p); X *Topchar = *p; X /* X * If the cursor is on the bottom line, we need to X * make sure it gets moved up the appropriate number X * of lines so it stays on the screen. X */ X if (Curschar->linep == Botchar->linep->prev) { X int i = 0; X while (i < done) { X i += plines(Curschar); X *Curschar = *prevline(Curschar); X } X } X } X s_ins(0, done); X} X Xvoid Xscrollup(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X register int pl; /* # of plines for the current line */ X X /* Scroll down 'nlines' lines. */ X while (nlines--) { X pl = plines(Topchar); X if ((p = nextline(Topchar)) == NULL) X break; X done += pl; X if (Curschar->linep == Topchar->linep) X *Curschar = *p; X *Topchar = *p; X X } X s_del(0, done); X} X X/* X * oneright X * oneleft X * onedown X * oneup X * X * Move one char {right,left,down,up}. Return TRUE when X * sucessful, FALSE when we hit a boundary (of a line, or the file). X */ X Xbool_t Xoneright() X{ X set_want_col = TRUE; X X switch (inc(Curschar)) { X X case 0: X return TRUE; X X case 1: X dec(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ X} X Xbool_t Xoneleft() X{ X set_want_col = TRUE; X X switch (dec(Curschar)) { X X case 0: X return TRUE; X X case 1: X inc(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ X} X Xvoid Xbeginline(flag) Xbool_t flag; X{ X while ( oneleft() ) X ; X if (flag) { X while (isspace(gchar(Curschar)) && oneright()) X ; X } X set_want_col = TRUE; X} X Xbool_t Xoneup(n) X{ X LPTR p, *np; X int k; X X p = *Curschar; X for ( k=0; k<n; k++ ) { X /* Look for the previous line */ X if ( (np=prevline(&p)) == NULL ) { X /* If we've at least backed up a little .. */ X if ( k > 0 ) X break; /* to update the cursor, etc. */ X else X return FALSE; X } X p = *np; X } X *Curschar = p; X /* This makes sure Topchar gets updated so the complete line */ X /* is one the screen. */ X cursupdate(); X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} X Xbool_t Xonedown(n) X{ X LPTR p, *np; X int k; X X p = *Curschar; X for ( k=0; k<n; k++ ) { X /* Look for the next line */ X if ( (np=nextline(&p)) == NULL ) { X if ( k > 0 ) X break; X else X return FALSE; X } X p = *np; X } X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} END_OF_FILE if test 7989 -ne `wc -c <'edit.c'`; then echo shar: \"'edit.c'\" unpacked with wrong size! fi # end of 'edit.c' fi if test -f 'env.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'env.h'\" else echo shar: Extracting \"'env.h'\" \(1686 characters\) sed "s/^X//" >'env.h' <<'END_OF_FILE' X/* X * The defines in this file establish the environment we're compiling X * in. Set these appropriately before compiling the editor. X */ X X/* X * One (and only 1) of the following defines should be uncommented. X * Most of the code is pretty machine-independent. Machine dependent X * code goes in a file like tos.c or unix.c. The only other place X * where machine dependent code goes is term.h for escape sequences. X */ X X/* #define ATARI /* For the Atari ST */ X/* #define UNIX /* System V or BSD */ X/* #define OS2 /* Microsoft OS/2 1.1 */ X/* #define DOS /* MSDOS 3.3 (on AT) */ X X/* X * If UNIX is defined above, then BSD may be defined. X */ X#ifdef UNIX X/* #define BSD /* Berkeley UNIX */ X#endif X X/* X * If ATARI is defined, MINIX may be defined. Otherwise, the editor X * is set up to compile using the Sozobon C compiler under TOS. X */ X#ifdef ATARI X#define MINIX /* Minix for the Atari ST */ X#endif X X/* X * If HELP is defined, the :help command shows a vi command summary. X * Help costs on the PC minix about 900 Bytes text and 5000 Bytes data !! X */ X/* #define HELP /* enable help command */ X X/* X * Use of termcap is optional in some environments. If available, it X * is enabled by the following define. Check the appropriate system- X * dependent source file to see if termcap is supported. X */ X/* #define TERMCAP /* enable termcap support */ X X/* X * The yank buffer is still static, but its size can be specified X * here to override the default of 4K. X */ X/* #define YBSIZE 8192 /* yank buffer size */ X X/* X * STRCSPN should be defined if the target system doesn't have the X * routine strcspn() available. See regexp.c for details. X */ X X X#ifdef MINIX X#define STRCSPN X#endif X END_OF_FILE if test 1686 -ne `wc -c <'env.h'`; then echo shar: \"'env.h'\" unpacked with wrong size! fi # end of 'env.h' fi if test -f 'fileio.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'fileio.c'\" else echo shar: Extracting \"'fileio.c'\" \(7044 characters\) sed "s/^X//" >'fileio.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: fileio.c,v 1.7 88/10/27 08:15:27 tony Exp $"; X X/* X * Basic file I/O routines. X * X * further modifications by: Robert Regn rtregn@faui32.uucp X * X * $Log: fileio.c,v $ X * Revision 1.7 88/10/27 08:15:27 tony X * Removed support for Megamax, and added a call to flushbuf() for X * versions that buffer output. X * X * Revision 1.6 88/10/06 10:10:45 tony X * File names passed to fopen() are now processed by fixname() to do X * system-dependent hacks on the name (mainly for DOS & OS/2). X * X * Revision 1.5 88/08/26 08:45:00 tony X * Misc. changes to make lint happy. X * X * Revision 1.4 88/06/10 13:43:19 tony X * Fixed a bug involving writing out files with long pathnames. A small X * fixed size buffer was being used. The space for the backup file name X * is now allocated dynamically. X * X * Revision 1.3 88/05/02 21:37:12 tony X * Reworked the readfile() routine to better deal with null characters, X * non-ascii characters, long lines, and incomplete last lines. The status X * messages now match the real vi correctly for all cases. X * X * Revision 1.2 88/03/21 16:46:01 tony X * Changed the line counter in renum() from 'int' to 'long' to correspond X * to the actual type of the pseudo line number in the LINE structure. X * X * Revision 1.1 88/03/20 21:07:19 tony X * Initial revision X * X * X */ X X#include "stevie.h" X#include <sys/stat.h> X Xvoid Xfilemess(s) Xchar *s; X{ X smsg("\"%s\" %s", (Filename == NULL) ? "" : Filename, s); X flushbuf(); X} X Xvoid Xrenum() X{ X LPTR *p; X unsigned long l = 0; X X for (p = Filemem; p != NULL ;p = nextline(p), l += LINEINC) X p->linep->num = l; X X Fileend->linep->num = 0xffffffff; X} X X#define MAXLINE 256 /* maximum size of a line */ X Xstatic char rdonly=0; X Xbool_t Xreadfile(fname,fromp,nochangename) Xchar *fname; XLPTR *fromp; Xbool_t nochangename; /* if TRUE, don't change the Filename */ X{ X FILE *f, *fopen(); X LINE *curr; X char buff[MAXLINE], buf2[80]; X int i, c; X long nchars = 0; X int linecnt = 0; X bool_t wasempty = bufempty(); X int nonascii = 0; /* count garbage characters */ X int nulls = 0; /* count nulls */ X bool_t incomplete = FALSE; /* was the last line incomplete? */ X bool_t toolong = FALSE; /* a line was too long */ X X curr = fromp->linep; X X if ( ! nochangename ) X Filename = strsave(fname); X X if ( (f=fopen(fixname(fname),"r")) == NULL ) X return TRUE; X X rdonly = (access(fname, 2) != 0); X filemess( rdonly ? "[Read only]" : ""); X X i = 0; X do { X c = getc(f); X X if (c == EOF) { X if (i == 0) /* normal loop termination */ X break; X X /* X * If we get EOF in the middle of a line, note the X * fact and complete the line ourselves. X */ X incomplete = TRUE; X c = NL; X } X X if (c >= 0x80) { X c -= 0x80; X nonascii++; X } X X /* X * If we reached the end of the line, OR we ran out of X * space for it, then process the complete line. X */ X if (c == NL || i == (MAXLINE-1)) { X int len; X LINE *lp; X X if (c != NL) X toolong = TRUE; X X buff[i] = '\0'; X len = strlen(buff) + 1; X if ((lp = newline(len)) == NULL) X {msg("Buffer overflow - File is uncomplete !!\n\r"); X break; X } X X strcpy(lp->s, buff); X X curr->next->prev = lp; /* new line to next one */ X lp->next = curr->next; X X curr->next = lp; /* new line to prior one */ X lp->prev = curr; X X curr = lp; /* new line becomes current */ X i = 0; X linecnt++; X X } else if (c == NUL) X nulls++; /* count and ignore nulls */ X else { X buff[i++] = c; /* normal character */ X } X X nchars++; X X } while (!incomplete && !toolong); X X fclose(f); X X /* X * If the buffer was empty when we started, we have to go back X * and remove the "dummy" line at Filemem and patch up the ptrs. X */ X if (wasempty && nchars > 0 /* !!! */) { X LINE *dummy = Filemem->linep; /* dummy line ptr */ X X free(dummy->s); /* free string space */ X Filemem->linep = Filemem->linep->next; X free(dummy); /* free LINE struct */ X Filemem->linep->prev = Filetop->linep; X Filetop->linep->next = Filemem->linep; X X Curschar->linep = Filemem->linep; X Topchar->linep = Filemem->linep; X } X X renum(); X X if (toolong) { X smsg("\"%s\" Line too long", fname); X return FALSE; X } X X sprintf(buff, "\"%s\" %s %s%d line%s, %ld character%s", X fname, X rdonly ? "[Read only]" : "", X incomplete ? "[Incomplete last line] " : "", X linecnt, (linecnt > 1) ? "s" : "", X nchars, (nchars > 1) ? "s" : ""); X X buf2[0] = NUL; X X if (nonascii || nulls) { X if (nonascii) { X if (nulls) X sprintf(buf2, " (%d null, %d non-ASCII)", X nulls, nonascii); X else X sprintf(buf2, " (%d non-ASCII)", nonascii); X } else X sprintf(buf2, " (%d null)", nulls); X } X strcat(buff, buf2); X msg(buff); X X return FALSE; X} X X X/* X * writeit - write to file 'fname' lines 'start' through 'end' X * X * If either 'start' or 'end' contain null line pointers, the default X * is to use the start or end of the file respectively. X */ Xbool_t Xwriteit(fname, start, end) Xchar *fname; XLPTR *start, *end; X{ X FILE *f, *fopen(); X FILE *fopenb(); /* open in binary mode, where needed */ X char *backup, *s; X long nchars; X int lines; X LPTR *p; X struct stat sbuf; X char newfile=0; X X if (stat(fname, &sbuf)!= 0) /* save mode of file for creating */ X newfile = 1; X X /* X X smsg("\"%s\"", fname); X X /* X * Form the backup file name - change foo.* to foo.bak X */ X backup = alloc((unsigned) (strlen(fname) + 5)); X strcpy(backup, fname); X for (s = backup; *s && *s != '.' ;s++) X ; X *s = NUL; X strcat(backup, ".bak"); X X /* X * Delete any existing backup and move the current version X * to the backup. For safety, we don't remove the backup X * until the write has finished successfully. And if the X * 'backup' option is set, leave it around. X */ X /* skipping rename avoids overwriting R/O files by creating a new */ X /* also save link structure R. Regn*/ X X if (!rdonly && sbuf.st_nlink == 1) X rename(fname, backup); X X X f = P(P_CR) ? fopen(fixname(fname), "w") : fopenb(fixname(fname), "w"); X X if ( f == NULL ) { X if (rdonly) X emsg("File is Read only"); X else emsg("Permission denied"); X free(backup); X return FALSE; X } X X if (!rdonly && !newfile) /* restore mode (and owner) properly */ X {chmod (fname, sbuf.st_mode&04777); X chown (fname, sbuf.st_uid, sbuf.st_gid); X } X X /* X * If we were given a bound, start there. Otherwise just X * start at the beginning of the file. X */ X if (start == NULL || start->linep == NULL) X p = Filemem; X else X p = start; X X lines = nchars = 0; X do { X fprintf(f, "%s\n", p->linep->s); X nchars += strlen(p->linep->s) + 1; X lines++; X X /* X * If we were given an upper bound, and we just did that X * line, then bag it now. X */ X if (end != NULL && end->linep != NULL) { X if (end->linep == p->linep) X break; X } X X } while ((p = nextline(p)) != NULL); X X fclose(f); X smsg("\"%s\" %s %d line%s, %ld character%s", fname, X newfile ? "[New File]" : "", X lines, (lines > 1) ? "s" : "", X nchars, (nchars > 1) ? "s" : ""); X X UNCHANGED; X X /* X * Remove the backup unless they want it left around X */ X if (!P(P_BK)) X remove(backup); X X free(backup); X X return TRUE; X} END_OF_FILE if test 7044 -ne `wc -c <'fileio.c'`; then echo shar: \"'fileio.c'\" unpacked with wrong size! fi # end of 'fileio.c' fi if test -f 'help.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'help.c'\" else echo shar: Extracting \"'help.c'\" \(9234 characters\) sed "s/^X//" >'help.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: help.c,v 1.7 88/10/28 13:59:18 tony Exp $"; X X/* X * Routine to display a command summary. X * X * $Log: help.c,v $ X * Revision 1.7 88/10/28 13:59:18 tony X * Minor changes to the screen. X * X * Revision 1.6 88/10/27 07:55:13 tony X * Rearranged the screens to fit more of the colon commands. X * X * Revision 1.5 88/08/30 20:36:46 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 1.4 88/08/26 13:41:56 tony X * Added a mention of the '!' operator as that is now supported. X * X * Revision 1.3 88/08/26 08:45:05 tony X * Misc. changes to make lint happy. X * X * Revision 1.2 88/07/09 20:37:46 tony X * Changed the help screen containing 'U' to remove the "not yet" notation. X * X * Revision 1.1 88/03/20 21:07:26 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xextern char *Version; X Xstatic int helprow; X X#ifdef HELP X Xstatic void longline(); X Xbool_t Xhelp() X{ X X/*********************************************************************** X * First Screen: Positioning within file, Adjusting the Screen X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Positioning within file\n\ X =======================\n\ X ^F Forward screenfull Developed by:\n\ X ^B Backward screenfull Tony Andrews\n"); Xlongline("\ X ^D scroll down half screen\n\ X ^U scroll up half screen Based on a program by:\n"); Xlongline("\ X G Goto line (end default) Tim Thompson\n\ X ]] next function\n\ X [[ previous function\n\ X /re next occurence of regular expression 're'\n"); Xlongline("\ X ?re prior occurence of regular expression 're'\n\ X n repeat last / or ?\n\ X N reverse last / or ?\n\ X % find matching (, ), {, }, [, or ]\n"); Xlongline("\ X\n\ X Adjusting the screen\n\ X ====================\n\ X ^L Redraw the screen\n\ X ^E scroll window down 1 line\n\ X ^Y scroll window up 1 line\n"); Xlongline("\ X z<RETURN> redraw, current line at top\n\ X z- ... at bottom\n\ X z. ... at center\n"); X X windgoto(0, 52); X longline(Version); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Second Screen: Character positioning X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Character Positioning\n\ X =====================\n\ X ^ first non-white\n\ X 0 beginning of line\n\ X $ end of line\n\ X h backward\n"); Xlongline("\ X l forward\n\ X ^H same as h\n\ X space same as l\n\ X fx find 'x' forward\n"); Xlongline("\ X Fx find 'x' backward\n\ X tx upto 'x' forward\n\ X Tx upto 'x' backward\n\ X ; Repeat last f, F, t, or T\n"); Xlongline("\ X , inverse of ;\n\ X | to specified column\n\ X % find matching (, ), {, }, [, or ]\n"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Third Screen: Line Positioning, Marking and Returning X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Line Positioning\n\ X ================\n\ X H home window line\n\ X L last window line\n\ X M middle window line\n"); Xlongline("\ X + next line, at first non-white\n\ X - previous line, at first non-white\n\ X CR return, same as +\n\ X j next line, same column\n\ X k previous line, same column\n"); X Xlongline("\ X\n\ X Marking and Returning\n\ X =====================\n\ X `` previous context\n\ X '' ... at first non-white in line\n"); Xlongline("\ X mx mark position with letter 'x'\n\ X `x to mark 'x'\n\ X 'x ... at first non-white in line\n"); X Xlongline("\n\ X Undo & Redo\n\ X =============\n\ X u undo last change\n\ X U restore current line\n\ X . repeat last change\n"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X/*********************************************************************** X * Fourth Screen: Insert & Replace, X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Insert and Replace\n\ X ==================\n\ X a append after cursor\n\ X i insert before cursor\n\ X A append at end of line\n\ X I insert before first non-blank\n"); Xlongline("\ X o open line below\n\ X O open line above\n\ X rx replace single char with 'x'\n\ X R replace characters\n"); X Xlongline("\ X\n\ X Words, sentences, paragraphs\n\ X ============================\n\ X w word forward\n\ X b back word\n\ X e end of word\n\ X ) to next sentence (not yet)\n\ X } to next paragraph (not yet)\n"); Xlongline("\ X ( back sentence (not yet)\n\ X { back paragraph (not yet)\n\ X W blank delimited word\n\ X B back W\n\ X E to end of W\n"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Fifth Screen: Misc. operations, X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Miscellaneous Commands\n\ X ======================\n"); Xlongline("\ X :w write back changes\n\ X :wq write and quit\n\ X :x write if modified, and quit\n\ X :q quit\n\ X :q! quit, discard changes\n\ X :e name edit file 'name'\n"); Xlongline("\ X :e! reedit, discard changes\n\ X :e # edit alternate file\n\ X :w name write file 'name'\n"); Xlongline("\ X :n edit next file in arglist\n\ X :N edit prior file in arglist\n\ X :n args specify new arglist (not yet)\n\ X :rew rewind arglist\n\ X :f show current file and lines\n"); Xlongline("\ X :f file change current file name\n\ X :g/pat/p|d global command (print or delete only)\n\ X :s/p1/p2/ text substitution (trailing 'g' optional)\n\ X"); Xlongline("\ X :ta tag to tag file entry 'tag'\n\ X ^] :ta, current word is tag\n\ X :sh run an interactive shell\n\ X :!cmd execute a shell command\n\ X"); X X windgoto(helprow = Rows-2, 47); X longline("<Press space bar to continue>\n"); X windgoto(helprow = Rows-1, 47); X longline("<Any other key will quit>"); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Sixth Screen: Operators, Misc. operations, Yank & Put X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Operators (double to affect lines)\n\ X ==================================\n\ X d delete\n\ X c change\n"); Xlongline("\ X < left shift\n\ X > right shift\n\ X y yank to buffer\n\ X ! filter lines\n"); X Xlongline("\n\ X Miscellaneous operations\n\ X ========================\n\ X C change rest of line\n\ X D delete rest of line\n\ X s substitute chars\n"); Xlongline("\ X S substitute lines (not yet)\n\ X J join lines\n\ X x delete characters\n\ X X ... before cursor\n"); X Xlongline("\n\ X Yank and Put\n\ X ============\n\ X p put back text\n\ X P put before\n\ X Y yank lines"); X X windgoto(helprow = Rows-1, 47); X longline("<Press any key>"); X X vgetc(); X X return TRUE; X} X Xstatic void Xlongline(p) Xchar *p; X{ X char *s; X X for ( s = p; *s ;s++ ) { X if ( *s == '\n' ) X windgoto(++helprow, 0); X else X outchar(*s); X } X} X#else X Xbool_t Xhelp() X{ X msg("Sorry, help not configured"); X return FALSE; X} X#endif END_OF_FILE if test 9234 -ne `wc -c <'help.c'`; then echo shar: \"'help.c'\" unpacked with wrong size! fi # end of 'help.c' fi if test -f 'hexchars.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hexchars.c'\" else echo shar: Extracting \"'hexchars.c'\" \(3413 characters\) sed "s/^X//" >'hexchars.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: hexchars.c,v 1.3 88/08/26 08:45:10 tony Exp $"; X X/* X * Contains information concerning the representation of characters for X * visual output by the editor. X * X * $Log: hexchars.c,v $ X * Revision 1.3 88/08/26 08:45:10 tony X * Misc. changes to make lint happy. X * X * Revision 1.2 88/05/03 14:38:43 tony X * Fixed the representation for the ascii character DELETE to be the X * same as vi. X * X * Revision 1.1 88/03/20 21:07:42 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * This file shows how to display characters on the screen. This is X * approach is something of an overkill. It's a remnant from the X * original code that isn't worth messing with for now. TABS are X * special-cased depending on the value of the "list" parameter. X */ X Xstruct charinfo chars[] = { X /* 000 */ 1, NULL, X /* 001 */ 2, "^A", X /* 002 */ 2, "^B", X /* 003 */ 2, "^C", X /* 004 */ 2, "^D", X /* 005 */ 2, "^E", X /* 006 */ 2, "^F", X /* 007 */ 2, "^G", X /* 010 */ 2, "^H", X /* 011 */ 2, "^I", X /* 012 */ 7, "[ERROR]", /* shouldn't occur */ X /* 013 */ 2, "^K", X /* 014 */ 2, "^L", X /* 015 */ 2, "^M", X /* 016 */ 2, "^N", X /* 017 */ 2, "^O", X /* 020 */ 2, "^P", X /* 021 */ 2, "^Q", X /* 022 */ 2, "^R", X /* 023 */ 2, "^S", X /* 024 */ 2, "^T", X /* 025 */ 2, "^U", X /* 026 */ 2, "^V", X /* 027 */ 2, "^W", X /* 030 */ 2, "^X", X /* 031 */ 2, "^Y", X /* 032 */ 2, "^Z", X /* 033 */ 2, "^[", X /* 034 */ 2, "^\\", X /* 035 */ 2, "^]", X /* 036 */ 2, "^^", X /* 037 */ 2, "^_", X /* 040 */ 1, NULL, X /* 041 */ 1, NULL, X /* 042 */ 1, NULL, X /* 043 */ 1, NULL, X /* 044 */ 1, NULL, X /* 045 */ 1, NULL, X /* 046 */ 1, NULL, X /* 047 */ 1, NULL, X /* 050 */ 1, NULL, X /* 051 */ 1, NULL, X /* 052 */ 1, NULL, X /* 053 */ 1, NULL, X /* 054 */ 1, NULL, X /* 055 */ 1, NULL, X /* 056 */ 1, NULL, X /* 057 */ 1, NULL, X /* 060 */ 1, NULL, X /* 061 */ 1, NULL, X /* 062 */ 1, NULL, X /* 063 */ 1, NULL, X /* 064 */ 1, NULL, X /* 065 */ 1, NULL, X /* 066 */ 1, NULL, X /* 067 */ 1, NULL, X /* 070 */ 1, NULL, X /* 071 */ 1, NULL, X /* 072 */ 1, NULL, X /* 073 */ 1, NULL, X /* 074 */ 1, NULL, X /* 075 */ 1, NULL, X /* 076 */ 1, NULL, X /* 077 */ 1, NULL, X /* 100 */ 1, NULL, X /* 101 */ 1, NULL, X /* 102 */ 1, NULL, X /* 103 */ 1, NULL, X /* 104 */ 1, NULL, X /* 105 */ 1, NULL, X /* 106 */ 1, NULL, X /* 107 */ 1, NULL, X /* 110 */ 1, NULL, X /* 111 */ 1, NULL, X /* 112 */ 1, NULL, X /* 113 */ 1, NULL, X /* 114 */ 1, NULL, X /* 115 */ 1, NULL, X /* 116 */ 1, NULL, X /* 117 */ 1, NULL, X /* 120 */ 1, NULL, X /* 121 */ 1, NULL, X /* 122 */ 1, NULL, X /* 123 */ 1, NULL, X /* 124 */ 1, NULL, X /* 125 */ 1, NULL, X /* 126 */ 1, NULL, X /* 127 */ 1, NULL, X /* 130 */ 1, NULL, X /* 131 */ 1, NULL, X /* 132 */ 1, NULL, X /* 133 */ 1, NULL, X /* 134 */ 1, NULL, X /* 135 */ 1, NULL, X /* 136 */ 1, NULL, X /* 137 */ 1, NULL, X /* 140 */ 1, NULL, X /* 141 */ 1, NULL, X /* 142 */ 1, NULL, X /* 143 */ 1, NULL, X /* 144 */ 1, NULL, X /* 145 */ 1, NULL, X /* 146 */ 1, NULL, X /* 147 */ 1, NULL, X /* 150 */ 1, NULL, X /* 151 */ 1, NULL, X /* 152 */ 1, NULL, X /* 153 */ 1, NULL, X /* 154 */ 1, NULL, X /* 155 */ 1, NULL, X /* 156 */ 1, NULL, X /* 157 */ 1, NULL, X /* 160 */ 1, NULL, X /* 161 */ 1, NULL, X /* 162 */ 1, NULL, X /* 163 */ 1, NULL, X /* 164 */ 1, NULL, X /* 165 */ 1, NULL, X /* 166 */ 1, NULL, X /* 167 */ 1, NULL, X /* 170 */ 1, NULL, X /* 171 */ 1, NULL, X /* 172 */ 1, NULL, X /* 173 */ 1, NULL, X /* 174 */ 1, NULL, X /* 175 */ 1, NULL, X /* 176 */ 1, NULL, X /* 177 */ 2, "^?", X}; END_OF_FILE if test 3413 -ne `wc -c <'hexchars.c'`; then echo shar: \"'hexchars.c'\" unpacked with wrong size! fi # end of 'hexchars.c' fi if test -f 'keymap.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'keymap.h'\" else echo shar: Extracting \"'keymap.h'\" \(1076 characters\) sed "s/^X//" >'keymap.h' <<'END_OF_FILE' X/* X * $Header: keymap.h,v 1.1 88/03/20 21:03:51 tony Exp $ X * X * Keycode definitions for special keys X * X * On systems that have any of these keys, the routine 'inchar' in the X * machine-dependent code should return one of the codes here. X * X * $Log: keymap.h,v $ X * Revision 1.1 88/03/20 21:03:51 tony X * Initial revision X * X * X */ X X#define K_HELP 0x80 X#define K_UNDO 0x81 X#define K_INSERT 0x82 X#define K_HOME 0x83 X#define K_UARROW 0x84 X#define K_DARROW 0x85 X#define K_LARROW 0x86 X#define K_RARROW 0x87 X#ifdef ATARI X#define K_CGRAVE 0x88 /* control grave accent */ X#else X#define K_CGRAVE 036 /* control grave accent */ X#endif X X#define K_F1 0x91 /* function keys */ X#define K_F2 0x92 X#define K_F3 0x93 X#define K_F4 0x94 X#define K_F5 0x95 X#define K_F6 0x96 X#define K_F7 0x97 X#define K_F8 0x98 X#define K_F9 0x99 X#define K_F10 0x9a X X#define K_SF1 0xa1 /* shifted function keys */ X#define K_SF2 0xa2 X#define K_SF3 0xa3 X#define K_SF4 0xa4 X#define K_SF5 0xa5 X#define K_SF6 0xa6 X#define K_SF7 0xa7 X#define K_SF8 0xa8 X#define K_SF9 0xa9 X#define K_SF10 0xaa END_OF_FILE if test 1076 -ne `wc -c <'keymap.h'`; then echo shar: \"'keymap.h'\" unpacked with wrong size! fi # end of 'keymap.h' fi if test -f 'linefunc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'linefunc.c'\" else echo shar: Extracting \"'linefunc.c'\" \(1656 characters\) sed "s/^X//" >'linefunc.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: linefunc.c,v 1.1 88/03/20 21:08:07 tony Exp $"; X X/* X * Basic line-oriented motions. X * X * $Log: linefunc.c,v $ X * Revision 1.1 88/03/20 21:08:07 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * nextline(curr) X * X * Return a pointer to the beginning of the next line after the one X * referenced by 'curr'. Return NULL if there is no next line (at EOF). X */ X XLPTR * Xnextline(curr) XLPTR *curr; X{ X static LPTR next; X X if (curr->linep->next != Fileend->linep) { X next.index = 0; X next.linep = curr->linep->next; X return &next; X } X return (LPTR *) NULL; X} X X/* X * prevline(curr) X * X * Return a pointer to the beginning of the line before the one X * referenced by 'curr'. Return NULL if there is no prior line. X */ X XLPTR * Xprevline(curr) XLPTR *curr; X{ X static LPTR prev; X X if (curr->linep->prev != Filetop->linep) { X prev.index = 0; X prev.linep = curr->linep->prev; X return &prev; X } X return (LPTR *) NULL; X} X X/* X * coladvance(p,col) X * X * Try to advance to the specified column, starting at p. X */ X XLPTR * Xcoladvance(p, col) XLPTR *p; Xint col; X{ X static LPTR lp; X int c, in; X X lp.linep = p->linep; X lp.index = p->index; X X /* If we're on a blank ('\n' only) line, we can't do anything */ X if (lp.linep->s[lp.index] == '\0') X return &lp; X /* try to advance to the specified column */ X for ( c=0; col-- > 0; c++ ) { X /* Count a tab for what it's worth (if list mode not on) */ X if ( gchar(&lp) == TAB && !P(P_LS) ) { X in = ((P(P_TS)-1) - c%P(P_TS)); X col -= in; X c += in; X } X /* Don't go past the end of */ X /* the file or the line. */ X if (inc(&lp)) { X dec(&lp); X break; X } X } X return &lp; X} END_OF_FILE if test 1656 -ne `wc -c <'linefunc.c'`; then echo shar: \"'linefunc.c'\" unpacked with wrong size! fi # end of 'linefunc.c' fi echo shar: End of shell archive. exit 0
rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) (12/15/88)
Found 1 control char in "'makefile'" makefile.min was the original makefile for ST Minix #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: main.c makefile makefile.dos makefile.min makefile.os2 # makefile.tos makefile.usg mark.c minix.c misccmds.c normal.c os2_c # Wrapped by rtregn@faui32 on Wed Dec 14 17:08:00 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'main.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'main.c'\" else echo shar: Extracting \"'main.c'\" \(7937 characters\) sed "s/^X//" >'main.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: main.c,v 1.5 88/11/10 13:28:38 tony Exp $"; X X/* X * The main routine and routines to deal with the input buffer. X * X * $Log: main.c,v $ X * Revision 1.5 88/11/10 13:28:38 tony X * Moved the call to do_mlines() to edit() so that it gets called after X * the various position pointers have been initialized. X * X * Revision 1.4 88/11/10 08:58:40 tony X * Added code to scan for modelines in the file currently being edited. X * X * Revision 1.3 88/11/01 21:32:29 tony X * Changed the RBSIZE macro (and comment) since it is no longer tied to X * the yank buffer size. X * X * Revision 1.2 88/08/26 08:45:14 tony X * Misc. changes to make lint happy. X * X * Revision 1.1 88/03/20 21:08:18 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xint Rows; /* Number of Rows and Columns */ Xint Columns; /* in the current window. */ X Xchar *Realscreen = NULL; /* What's currently on the screen, a single */ X /* array of size Rows*Columns. */ Xchar *Nextscreen = NULL; /* What's to be put on the screen. */ X Xchar *Filename = NULL; /* Current file name */ X XLPTR *Filemem; /* Pointer to the first line of the file */ X XLPTR *Filetop; /* Line 'above' the start of the file */ X XLPTR *Fileend; /* Pointer to the end of the file in Filemem. */ X /* (It points to the byte AFTER the last byte.) */ X XLPTR *Topchar; /* Pointer to the byte in Filemem which is */ X /* in the upper left corner of the screen. */ X XLPTR *Botchar; /* Pointer to the byte in Filemem which is */ X /* just off the bottom of the screen. */ X XLPTR *Curschar; /* Pointer to byte in Filemem at which the */ X /* cursor is currently placed. */ X Xint Cursrow, Curscol; /* Current position of cursor */ X Xint Cursvcol; /* Current virtual column, the column number of */ X /* the file's actual line, as opposed to the */ X /* column number we're at on the screen. This */ X /* makes a difference on lines that span more */ X /* than one screen line. */ X Xint Curswant = 0; /* The column we'd like to be at. This is used */ X /* try to stay in the same column through up/down */ X /* cursor motions. */ X Xbool_t set_want_col; /* If set, then update Curswant the next time */ X /* through cursupdate() to the current virtual */ X /* column. */ X Xint State = NORMAL; /* This is the current state of the command */ X /* interpreter. */ X Xint Prenum = 0; /* The (optional) number before a command. */ X XLPTR *Insstart; /* This is where the latest insert/append */ X /* mode started. */ X Xbool_t Changed = 0; /* Set to 1 if something in the file has been */ X /* changed and not written out. */ X Xchar Redobuff[1024]; /* Each command should stuff characters into this */ X /* buffer that will re-execute itself. */ X Xchar Insbuff[1024]; /* Each insertion gets stuffed into this buffer. */ X Xint Ninsert = 0; /* Number of characters in the current insertion. */ Xchar *Insptr = NULL; X Xchar **files; /* list of input files */ Xint numfiles; /* number of input files */ Xint curfile; /* number of the current file */ X Xstatic void Xusage() X{ X fprintf(stderr, "usage: stevie [file ...]\n"); X fprintf(stderr, " stevie -t tag\n"); X fprintf(stderr, " stevie +[num] file\n"); X fprintf(stderr, " stevie +/pat file\n"); X exit(1); X} X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X char *initstr, *getenv(); /* init string from the environment */ X char *tag = NULL; /* tag from command line */ X char *pat = NULL; /* pattern from command line */ X int line = -1; /* line number from command line */ X X /* X * Process the command line arguments. X */ X if (argc > 1) { X switch (argv[1][0]) { X X case '-': /* -t tag */ X if (argv[1][1] != 't') X usage(); X X if (argv[2] == NULL) X usage(); X X Filename = NULL; X tag = argv[2]; X numfiles = 1; X break; X X case '+': /* +n or +/pat */ X if (argv[1][1] == '/') { X if (argv[2] == NULL) X usage(); X Filename = strsave(argv[2]); X pat = &(argv[1][1]); X numfiles = 1; X X } else if (isdigit(argv[1][1]) || argv[1][1] == NUL) { X if (argv[2] == NULL) X usage(); X Filename = strsave(argv[2]); X numfiles = 1; X X line = (isdigit(argv[1][1])) ? X atoi(&(argv[1][1])) : 0; X } else X usage(); X X break; X X default: /* must be a file name */ X Filename = strsave(argv[1]); X files = &(argv[1]); X numfiles = argc - 1; X break; X } X } else { X Filename = NULL; X numfiles = 1; X } X curfile = 0; X X if (numfiles > 1) X fprintf(stderr, "%d files to edit\n", numfiles); X X windinit(); X X /* X * Allocate LPTR structures for all the various position pointers X */ X if ((Filemem = (LPTR *) malloc(sizeof(LPTR))) == NULL || X (Filetop = (LPTR *) malloc(sizeof(LPTR))) == NULL || X (Fileend = (LPTR *) malloc(sizeof(LPTR))) == NULL || X (Topchar = (LPTR *) malloc(sizeof(LPTR))) == NULL || X (Botchar = (LPTR *) malloc(sizeof(LPTR))) == NULL || X (Curschar = (LPTR *) malloc(sizeof(LPTR))) == NULL || X (Insstart = (LPTR *) malloc(sizeof(LPTR))) == NULL ) { X fprintf(stderr, "Can't allocate data structures\n"); X windexit(0); X } X X screenalloc(); X filealloc(); /* Initialize Filemem, Filetop, and Fileend */ X X screenclear(); X X if ((initstr = getenv("EXINIT")) != NULL) { X char *lp, buf[128]; X X if ((lp = getenv("LINES")) != NULL) { X sprintf(buf, "%s lines=%s", initstr, lp); X readcmdline(':', buf); X } else X readcmdline(':', initstr); X } X X if (Filename != NULL) { X if (readfile(Filename, Filemem, FALSE)) X filemess("[New File]"); X } else X msg("Empty Buffer"); X X setpcmark(); X X updatescreen(); X X if (tag) { X stuffin(":ta "); X stuffin(tag); X stuffin("\n"); X X } else if (pat) { X stuffin(pat); X stuffin("\n"); X X } else if (line >= 0) { X if (line > 0) X stuffnum(line); X stuffin("G"); X } X X edit(); X X windexit(0); X X return 1; /* shouldn't be reached */ X} X X#define RBSIZE 1024 Xstatic char getcbuff[RBSIZE]; Xstatic char *getcnext = NULL; X Xvoid Xstuffin(s) Xchar *s; X{ X if ( getcnext == NULL ) { X strcpy(getcbuff,s); X getcnext = getcbuff; X } else X strcat(getcbuff,s); X} X Xvoid Xstuffnum(n) Xint n; X{ X char buf[32]; X X sprintf(buf, "%d", n); X stuffin(buf); X} X X/*VARARGS1*/ Xvoid Xaddtobuff(s,c1,c2,c3,c4,c5,c6) Xchar *s; Xchar c1, c2, c3, c4, c5, c6; X{ X char *p = s; X if ( (*p++ = c1) == NUL ) X return; X if ( (*p++ = c2) == NUL ) X return; X if ( (*p++ = c3) == NUL ) X return; X if ( (*p++ = c4) == NUL ) X return; X if ( (*p++ = c5) == NUL ) X return; X if ( (*p++ = c6) == NUL ) X return; X} X Xint Xvgetc() X{ X int c; X X /* X * inchar() may map special keys by using stuffin(). If it does X * so, it returns -1 so we know to loop here to get a real char. X */ X do { X if ( getcnext != NULL ) { X int nextc = *getcnext++; X if ( *getcnext == NUL ) { X *getcbuff = NUL; X getcnext = NULL; X } X return(nextc); X } X c = inchar(); X } while (c == -1); X X return c; X} X X#if 0 Xint Xvpeekc() X{ X if ( getcnext != NULL ) X return(*getcnext); X return(-1); X} X#endif X X/* X * anyinput X * X * Return non-zero if input is pending. X */ X Xbool_t Xanyinput() X{ X return (getcnext != NULL); X} X X/* X * do_mlines() - process mode lines for the current file X * X * Returns immediately if the "ml" parameter isn't set. X */ X#define NMLINES 5 /* no. of lines at start/end to check for modelines */ X Xvoid Xdo_mlines() X{ X void chk_mline(); X int i; X LPTR *p; X X if (!P(P_ML)) X return; X X p = Filemem; X for (i=0; i < NMLINES ;i++) { X chk_mline(p->linep->s); X if ((p = nextline(p)) == NULL) X break; X } X X if ((p = prevline(Fileend)) == NULL) X return; X X for (i=0; i < NMLINES ;i++) { X chk_mline(p->linep->s); X if ((p = prevline(p)) == NULL) X break; X } X} X X/* X * chk_mline() - check a single line for a mode string X */ Xstatic void Xchk_mline(s) Xregister char *s; X{ X register char *cs; /* local copy of any modeline found */ X register char *e; X X for (; *s != NUL ;s++) { X if (strncmp(s, "vi:", 3) == 0 || strncmp(s, "ex:", 3) == 0) { X cs = strsave(s+3); X if ((e = strchr(cs, ':')) != NULL) { X *e = NUL; X readcmdline(':', cs); X } X free(cs); X } X } X} END_OF_FILE if test 7937 -ne `wc -c <'main.c'`; then echo shar: \"'main.c'\" unpacked with wrong size! fi # end of 'main.c' fi if test -f 'makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile'\" else echo shar: Extracting \"'makefile'\" \(491 characters\) sed "s/^X//" >'makefile' <<'END_OF_FILE' X# X# Makefile for PC Minix X# X XLDFLAGS= -i -T/usr/tmp XCFLAGS= -DMINIX -O X X XMACH= minix.s X XOBJ= main.s edit.s linefunc.s normal.s cmdline.s hexchars.s \ X misccmds.s help.s ptrfunc.s search.s alloc.s mark.s \ X regexp.s regsub.s \ X screen.s fileio.s param.s undo.s version.s X X X Xall : stevie X Xstevie : $(OBJ) $(MACH) X $(CC) $(LDFLAGS) $(OBJ) $(MACH) -o stevie X @echo stevie fertig X Xctags: ctags.c X $(CC) -o ctags ctags.c X chmem =4096 ctags Xclean : X rm $(OBJ) $(MACH) END_OF_FILE echo shar: 1 control character may be missing from \"'makefile'\" if test 491 -ne `wc -c <'makefile'`; then echo shar: \"'makefile'\" unpacked with wrong size! fi # end of 'makefile' fi if test -f 'makefile.dos' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile.dos'\" else echo shar: Extracting \"'makefile.dos'\" \(1487 characters\) sed "s/^X//" >'makefile.dos' <<'END_OF_FILE' X# X# Makefile for DOS X# X# This makefile is set up for Microsoft C 5.1 X# X X# X# Compact model lets us edit large files, but keep small model code X# XMODEL= /AC XCFLAGS = $(MODEL) X XMACH= dos.obj X XOBJ= main.obj edit.obj linefunc.obj normal.obj cmdline.obj hexchars.obj \ X misccmds.obj help.obj ptrfunc.obj search.obj alloc.obj mark.obj \ X regexp.obj regsub.obj \ X screen.obj fileio.obj param.obj undo.obj version.obj $(MACH) X Xall: stevie.exe X Xmain.obj: main.c X cl -c $(CFLAGS) main.c X Xalloc.obj : alloc.c X cl -c $(CFLAGS) alloc.c X Xedit.obj : edit.c X cl -c $(CFLAGS) edit.c X Xlinefunc.obj : linefunc.c X cl -c $(CFLAGS) linefunc.c X Xnormal.obj : normal.c X cl -c $(CFLAGS) normal.c X Xcmdline.obj : cmdline.c X cl -c $(CFLAGS) cmdline.c X Xhexchars.obj : hexchars.c X cl -c $(CFLAGS) hexchars.c X Xmisccmds.obj : misccmds.c X cl -c $(CFLAGS) misccmds.c X Xhelp.obj : help.c X cl -c $(CFLAGS) help.c X Xptrfunc.obj : ptrfunc.c X cl -c $(CFLAGS) ptrfunc.c X Xsearch.obj : search.c X cl -c $(CFLAGS) search.c X Xmark.obj : mark.c X cl -c $(CFLAGS) mark.c X Xscreen.obj : screen.c X cl -c $(CFLAGS) screen.c X Xfileio.obj : fileio.c X cl -c $(CFLAGS) fileio.c X Xparam.obj : param.c X cl -c $(CFLAGS) param.c X Xdos.obj : dos.c X cl -c $(CFLAGS) dos.c X Xregexp.obj : regexp.c X cl -c $(CFLAGS) regexp.c X Xregsub.obj : regsub.c X cl -c $(CFLAGS) regsub.c X Xundo.obj : undo.c X cl -c $(CFLAGS) undo.c X Xversion.obj : version.c X cl -c $(CFLAGS) version.c X Xstevie.exe : $(OBJ) X cl $(MODEL) *.obj c:\lib\setargv.obj -o stevie.exe /F 6000 -link /NOE END_OF_FILE if test 1487 -ne `wc -c <'makefile.dos'`; then echo shar: \"'makefile.dos'\" unpacked with wrong size! fi # end of 'makefile.dos' fi if test -f 'makefile.min' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile.min'\" else echo shar: Extracting \"'makefile.min'\" \(393 characters\) sed "s/^X//" >'makefile.min' <<'END_OF_FILE' X# X# Makefile for Atari ST Minix X# X XLDFLAGS= -T. XCFLAGS= -O -T. X XMACH= minix.o X XOBJ= main.o edit.o linefunc.o normal.o cmdline.o hexchars.o \ X misccmds.o help.o ptrfunc.o search.o alloc.o mark.o \ X regexp.o regsub.o \ X screen.o fileio.o param.o undo.o version.o X Xall : stevie X Xstevie : $(OBJ) $(MACH) X $(CC) $(LDFLAGS) $(OBJ) $(MACH) -o stevie X chmem =150000 stevie X Xclean : X rm $(OBJ) $(MACH) END_OF_FILE if test 393 -ne `wc -c <'makefile.min'`; then echo shar: \"'makefile.min'\" unpacked with wrong size! fi # end of 'makefile.min' fi if test -f 'makefile.os2' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile.os2'\" else echo shar: Extracting \"'makefile.os2'\" \(1451 characters\) sed "s/^X//" >'makefile.os2' <<'END_OF_FILE' X# X# Makefile for OS/2 X# X# The make command with OS/2 is really stupid. X# X X# X# Compact model lets us edit large files, but keep small model code X# XMODEL= /AC XCFLAGS = $(MODEL) X XMACH= os2.obj X XOBJ= main.obj edit.obj linefunc.obj normal.obj cmdline.obj hexchars.obj \ X misccmds.obj help.obj ptrfunc.obj search.obj alloc.obj mark.obj \ X screen.obj fileio.obj param.obj undo.obj version.obj $(MACH) X Xmain.obj: main.c X cl -c $(CFLAGS) main.c X Xalloc.obj : alloc.c X cl -c $(CFLAGS) alloc.c X Xedit.obj : edit.c X cl -c $(CFLAGS) edit.c X Xlinefunc.obj : linefunc.c X cl -c $(CFLAGS) linefunc.c X Xnormal.obj : normal.c X cl -c $(CFLAGS) normal.c X Xcmdline.obj : cmdline.c X cl -c $(CFLAGS) cmdline.c X Xhexchars.obj : hexchars.c X cl -c $(CFLAGS) hexchars.c X Xmisccmds.obj : misccmds.c X cl -c $(CFLAGS) misccmds.c X Xhelp.obj : help.c X cl -c $(CFLAGS) help.c X Xptrfunc.obj : ptrfunc.c X cl -c $(CFLAGS) ptrfunc.c X Xsearch.obj : search.c X cl -c $(CFLAGS) search.c X Xmark.obj : mark.c X cl -c $(CFLAGS) mark.c X Xscreen.obj : screen.c X cl -c $(CFLAGS) screen.c X Xfileio.obj : fileio.c X cl -c $(CFLAGS) fileio.c X Xparam.obj : param.c X cl -c $(CFLAGS) param.c X Xregexp.obj : regexp.c X cl -c $(CFLAGS) regexp.c X Xregsub.obj : regsub.c X cl -c $(CFLAGS) regsub.c X Xos2.obj : os2.c X cl -c $(CFLAGS) os2.c X Xundo.obj : undo.c X cl -c $(CFLAGS) undo.c X Xversion.obj : version.c X cl -c $(CFLAGS) version.c X Xstevie.exe : $(OBJ) X cl $(MODEL) *.obj \pmsdk\lib\setargv.obj -o stevie.exe /F 6000 -link /NOE END_OF_FILE if test 1451 -ne `wc -c <'makefile.os2'`; then echo shar: \"'makefile.os2'\" unpacked with wrong size! fi # end of 'makefile.os2' fi if test -f 'makefile.tos' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile.tos'\" else echo shar: Extracting \"'makefile.tos'\" \(418 characters\) sed "s/^X//" >'makefile.tos' <<'END_OF_FILE' X# X# Makefile for the Atari ST - Sozobon C Compiler X# X XCFLAGS = -O X X.c.o: X $(CC) -c $(CFLAGS) $< X ar rv vi.lib $*.o X XMACH = tos.o X XOBJ = main.o edit.o linefunc.o normal.o cmdline.o hexchars.o \ X misccmds.o help.o ptrfunc.o search.o alloc.o mark.o \ X regexp.o regsub.o \ X screen.o fileio.o param.o undo.o version.o $(MACH) X Xall : stevie.ttp X Xstevie.ttp : $(OBJ) X $(CC) vi.lib -o stevie.ttp X Xclean : X $(RM) $(OBJ) vi.lib END_OF_FILE if test 418 -ne `wc -c <'makefile.tos'`; then echo shar: \"'makefile.tos'\" unpacked with wrong size! fi # end of 'makefile.tos' fi if test -f 'makefile.usg' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile.usg'\" else echo shar: Extracting \"'makefile.usg'\" \(499 characters\) sed "s/^X//" >'makefile.usg' <<'END_OF_FILE' X# X# Makefile for UNIX (System V) X# X XLDFLAGS= XCFLAGS= -g X XMACH= unix.o X XOBJ= main.o edit.o linefunc.o normal.o cmdline.o hexchars.o \ X misccmds.o help.o ptrfunc.o search.o alloc.o mark.o \ X regexp.o regsub.o \ X screen.o fileio.o param.o undo.o version.o term.o X Xall : stevie stevie.doc X Xstevie : $(OBJ) $(MACH) X $(CC) $(LDFLAGS) $(OBJ) $(MACH) -o stevie -lcurses X Xlint : X lint $(OBJ:.o=.c) $(MACH:.o=.c) X Xstevie.doc : stevie.mm X nroff -rB1 -Tlp -mm stevie.mm > stevie.doc X Xclean : X rm $(OBJ) $(MACH) END_OF_FILE if test 499 -ne `wc -c <'makefile.usg'`; then echo shar: \"'makefile.usg'\" unpacked with wrong size! fi # end of 'makefile.usg' fi if test -f 'mark.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mark.c'\" else echo shar: Extracting \"'mark.c'\" \(2315 characters\) sed "s/^X//" >'mark.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: mark.c,v 1.2 88/10/27 07:54:45 tony Exp $"; X X/* X * Routines to save and retrieve marks. X * X * $Log: mark.c,v $ X * Revision 1.2 88/10/27 07:54:45 tony X * Removed support for Megamax. X * X * Revision 1.1 88/03/20 21:08:32 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X#define NMARKS 10 /* max. # of marks that can be saved */ X Xstruct mark { X char name; X LPTR pos; X}; X Xstatic struct mark mlist[NMARKS]; Xstatic struct mark pcmark; /* previous context mark */ Xstatic bool_t pcvalid = FALSE; /* true if pcmark is valid */ X X/* X * setmark(c) - set mark 'c' at current cursor position X * X * Returns TRUE on success, FALSE if no room for mark or bad name given. X */ Xbool_t Xsetmark(c) Xchar c; X{ X int i; X X if (!isalpha(c)) X return FALSE; X X /* X * If there is already a mark of this name, then just use the X * existing mark entry. X */ X for (i=0; i < NMARKS ;i++) { X if (mlist[i].name == c) { X mlist[i].pos = *Curschar; X return TRUE; X } X } X X /* X * There wasn't a mark of the given name, so find a free slot X */ X for (i=0; i < NMARKS ;i++) { X if (mlist[i].name == NUL) { /* got a free one */ X mlist[i].name = c; X mlist[i].pos = *Curschar; X return TRUE; X } X } X return FALSE; X} X X/* X * setpcmark() - set the previous context mark to the current position X */ Xvoid Xsetpcmark() X{ X pcmark.pos = *Curschar; X pcvalid = TRUE; X} X X/* X * getmark(c) - find mark for char 'c' X * X * Return pointer to LPTR or NULL if no such mark. X */ XLPTR * Xgetmark(c) Xchar c; X{ X register int i; X X if (c == '\'' || c == '`') /* previous context mark */ X return pcvalid ? &(pcmark.pos) : (LPTR *) NULL; X X for (i=0; i < NMARKS ;i++) { X if (mlist[i].name == c) X return &(mlist[i].pos); X } X return (LPTR *) NULL; X} X X/* X * clrall() - clear all marks X * X * Used mainly when trashing the entire buffer during ":e" type commands X */ Xvoid Xclrall() X{ X register int i; X X for (i=0; i < NMARKS ;i++) X mlist[i].name = NUL; X pcvalid = FALSE; X} X X/* X * clrmark(line) - clear any marks for 'line' X * X * Used any time a line is deleted so we don't have marks pointing to X * non-existent lines. X */ Xvoid Xclrmark(line) XLINE *line; X{ X register int i; X X for (i=0; i < NMARKS ;i++) { X if (mlist[i].pos.linep == line) X mlist[i].name = NUL; X } X if (pcvalid && (pcmark.pos.linep == line)) X pcvalid = FALSE; X} END_OF_FILE if test 2315 -ne `wc -c <'mark.c'`; then echo shar: \"'mark.c'\" unpacked with wrong size! fi # end of 'mark.c' fi if test -f 'minix.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'minix.c'\" else echo shar: Extracting \"'minix.c'\" \(3974 characters\) sed "s/^X//" >'minix.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: minix.c,v 1.3 88/10/29 14:07:36 tony Exp $"; X X/* X * System-dependent routines for Minix-ST X * X * modifications by: Robert Regn rtregn@faui32.uucp X * X * $Log: minix.c,v $ X * Revision 1.3 88/10/29 14:07:36 tony X * Added optional support for termcap. X * X * Revision 1.2 88/10/27 08:20:12 tony X * Added doshell() (same as the unix version), and a no-op version of fixname(). X * X * Revision 1.1 88/10/25 20:14:00 tony X * Initial revision X * X * X */ X X#include "stevie.h" X#include <sgtty.h> X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X char c[4]; X short n; X X flushbuf(); /* flush any pending output */ X X while ( (n=read(0, c, 3)) < 1) X ; X if (n > 1) { X if (n == 3 && c[0] == 033 && c[1] == '[') /* cursor button */ X switch (c[2]) { X case 'A': return K_UARROW; X case 'B': return K_DARROW; X case 'C': return K_RARROW; X case 'D': return K_LARROW; X default: /* .. stuffin */ ; X } X c[n] = NUL; X stuffin ( c+1); X } X X return *c; X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xvoid Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xregister char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X Xvoid Xoutstr(s) Xregister char *s; X{ X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X outone('\007'); X} X X/* X * remove(file) - remove a file X */ Xvoid Xremove(file) Xchar *file; X{ X unlink(file); X} X X/* X * rename(of, nf) - rename existing file 'of' to 'nf' X */ Xvoid Xrename(of, nf) Xchar *of, *nf; X{ X unlink(nf); X link(of, nf); X unlink(of); X} X Xvoid Xdelay() X{ X /* not implemented */ X} X Xstatic struct sgttyb ostate; X X/* X * Go into cbreak mode X */ Xvoid Xset_tty() X{ X struct sgttyb nstate; X X ioctl(0, TIOCGETP, &ostate); X nstate = ostate; X nstate.sg_flags &= ~(XTABS|ECHO); X nstate.sg_flags |= CBREAK; X ioctl(0, TIOCSETP, &nstate); X} X X/* X * Restore original terminal modes X */ Xvoid Xreset_tty() X{ X ioctl(0, TIOCSETP, &ostate); X} X Xvoid Xwindinit() X{ X#ifdef TERMCAP X if (t_init() != 1) { X fprintf(stderr, "unknown terminal type\n"); X exit(1); X } X#else X X char *term, *getenv(); X if ((term = getenv("TERM")) == NULL || strcmp(term, "minix") != 0) { X fprintf(stderr, "Invalid terminal type '%s'\n", term); X exit(1); X } X Columns = 80; X P(P_LI) = Rows = 25; X#endif X X set_tty(); X} X Xvoid Xwindexit(r) Xint r; X{ X flushbuf(); X reset_tty(); X exit(r); X} X X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X#ifdef TERMCAP X char *tgoto(); X#else X r += 1; X c += 1; X#endif X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X#ifdef TERMCAP X outstr(tgoto(T_CM, c, r)); X#else X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X#endif X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X return fopen(fname, mode); X} X Xchar * Xstrchr(s, c) Xchar *s; Xchar c; X{ X char *index(); X X return index(s, c); X} X Xchar * Xfixname(s) Xchar *s; X{ X return s; X} X X/* X * doshell() - run a command or an interactive shell X */ Xvoid Xdoshell(cmd) Xchar *cmd; X{ X char *cp, *getenv(); X char cline[128]; X X outstr("\r\n"); X flushbuf(); X reset_tty(); X X if (cmd == NULL /* don't say sh sh */ X || *cmd == NUL ) { /* handle :!<return> */ X if ((cmd = getenv("SHELL")) == NULL) X cmd = "/bin/sh"; X switch (fork() ) { X case 0: X execl(cmd, "sh", "-i", 0); X emsg("exec failed - "); X exit(1); X X case -1: emsg("fork failed - "); X break; X X default: wait(0); X } X X } X X else if (system(cmd) == -1) X outstr("execution of command failed - "); X set_tty(); X X wait_return(); X} END_OF_FILE if test 3974 -ne `wc -c <'minix.c'`; then echo shar: \"'minix.c'\" unpacked with wrong size! fi # end of 'minix.c' fi if test -f 'misccmds.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'misccmds.c'\" else echo shar: Extracting \"'misccmds.c'\" \(11025 characters\) sed "s/^X//" >'misccmds.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: misccmds.c,v 1.9 88/09/06 06:50:42 tony Exp $"; X X/* X * Various routines to perform specific editing operations or return X * useful information about the file. X * X * $Log: misccmds.c,v $ X * Revision 1.9 88/09/06 06:50:42 tony X * Fixed a bug with shifts that was introduced when replace mode was added. X * X * Revision 1.8 88/08/30 20:36:51 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 1.7 88/08/26 08:45:18 tony X * Misc. changes to make lint happy. X * X * Revision 1.6 88/06/26 14:50:19 tony X * Added a new parameter to delline() to control whether screen updates X * may be performed while deleting the line(s). X * X * Revision 1.5 88/05/02 07:34:46 tony X * Fixed a bug in the last change to plines(). The column counter wasn't X * being initialized to zero, so plines() returned garbage. X * X * Revision 1.4 88/05/01 20:09:13 tony X * Modified plines() to support the new "number" parameter. X * X * Revision 1.3 88/04/30 20:00:04 tony X * Added code to openfwd() and openbwd() to support auto-indent. X * X * Revision 1.2 88/04/23 20:39:21 tony X * Reworked openfwd() to avoid a problem when opening a line at the end of X * the file when on the last line of the screen. Opening a line now inserts X * or scrolls appropriately and deals with opens correctly when the cursor X * is on a long line. X * X * Revision 1.1 88/03/20 21:08:41 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xstatic void openfwd(), openbwd(); X Xextern bool_t did_ai; X X/* X * opencmd X * X * Add a blank line above or below the current line. X */ X Xvoid Xopencmd(dir, can_ai) Xint dir; Xint can_ai; /* if true, consider auto-indent */ X{ X if (dir == FORWARD) X openfwd(can_ai); X else X openbwd(can_ai); X} X Xstatic void Xopenfwd(can_ai) Xint can_ai; X{ X LINE *l; X LPTR *next; X char *s; /* string to be moved to new line, if any */ X int newindex = 0; /* index of the cursor on the new line */ X X /* X * If we're in insert mode, we need to move the remainder of the X * current line onto the new line. Otherwise the new line is left X * blank. X */ X if (State == INSERT || State == REPLACE) X s = &Curschar->linep->s[Curschar->index]; X else X s = ""; X X if ((next = nextline(Curschar)) == NULL) /* open on last line */ X next = Fileend; X X /* X * By asking for as much space as the prior line had we make sure X * that we'll have enough space for any auto-indenting. X */ X if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) X return; X X if (*s != NUL) X strcpy(l->s, s); /* copy string to new line */ X X else if (can_ai && P(P_AI) && !anyinput()) { X char *p; X X /* X * Copy prior line, and truncate after white space X */ X strcpy(l->s, Curschar->linep->s); X X for (p = l->s; *p == ' ' || *p == TAB ;p++) X ; X *p = NUL; X newindex = p - l->s; X X /* X * If we just did an auto-indent, then we didn't type X * anything on the prior line, and it should be truncated. X */ X if (did_ai) X Curschar->linep->s[0] = NUL; X X did_ai = TRUE; X } X X /* truncate current line at cursor */ X if (State == INSERT || State == REPLACE) X *s = NUL; X X X Curschar->linep->next = l; /* link neighbors to new line */ X next->linep->prev = l; X X l->prev = Curschar->linep; /* link new line to neighbors */ X l->next = next->linep; X X if (next == Fileend) /* new line at end */ X l->num = Curschar->linep->num + LINEINC; X X else if ((l->prev->num) + 1 == l->next->num) /* no gap, renumber */ X renum(); X X else { /* stick it in the middle */ X unsigned long lnum; X lnum = ((long)l->prev->num + (long)l->next->num) / 2; X l->num = lnum; X } X X /* X * Get the cursor to the start of the line, so that 'Cursrow' X * gets set to the right physical line number for the stuff X * that follows... X */ X Curschar->index = 0; X cursupdate(); X X /* X * If we're doing an open on the last logical line, then X * go ahead and scroll the screen up. Otherwise, just insert X * a blank line at the right place. We use calls to plines() X * in case the cursor is resting on a long line. X */ X if (Cursrow + plines(Curschar) == (Rows - 1)) X scrollup(1); X else X s_ins(Cursrow+plines(Curschar), 1); X X *Curschar = *nextline(Curschar); /* cursor moves down */ X Curschar->index = newindex; X X updatescreen(); /* because Botchar is now invalid... */ X X cursupdate(); /* update Cursrow before insert */ X} X Xstatic void Xopenbwd(can_ai) Xint can_ai; X{ X LINE *l; X LINE *prev; X int newindex = 0; X X prev = Curschar->linep->prev; X X if ((l = newline(strlen(Curschar->linep->s) + SLOP)) == NULL) X return; X X Curschar->linep->prev = l; /* link neighbors to new line */ X prev->next = l; X X l->next = Curschar->linep; /* link new line to neighbors */ X l->prev = prev; X X if (can_ai && P(P_AI) && !anyinput()) { X char *p; X X /* X * Copy current line, and truncate after white space X */ X strcpy(l->s, Curschar->linep->s); X X for (p = l->s; *p == ' ' || *p == TAB ;p++) X ; X *p = NUL; X newindex = p - l->s; X X did_ai = TRUE; X } X X Curschar->linep = Curschar->linep->prev; X Curschar->index = newindex; X X if (prev == Filetop->linep) /* new start of file */ X Filemem->linep = l; X X renum(); /* keep it simple - we don't do this often */ X X cursupdate(); /* update Cursrow before insert */ X if (Cursrow != 0) X s_ins(Cursrow, 1); /* insert a physical line */ X X updatescreen(); X} X Xint Xcntllines(pbegin,pend) XLPTR *pbegin, *pend; X{ X LINE *lp; X int lnum = 1; X X for (lp = pbegin->linep; lp != pend->linep ;lp = lp->next) X lnum++; X X return(lnum); X} X X/* X * plines(p) - return the number of physical screen lines taken by line 'p' X */ Xint Xplines(p) XLPTR *p; X{ X register int col = 0; X register char *s; X X s = p->linep->s; X X if (*s == NUL) /* empty line */ X return 1; X X for (; *s != NUL ;s++) { X if ( *s == TAB && !P(P_LS)) X col += P(P_TS) - (col % P(P_TS)); X else X col += chars[(unsigned)(*s & 0xff)].ch_size; X } X X /* X * If list mode is on, then the '$' at the end of X * the line takes up one extra column. X */ X if (P(P_LS)) X col += 1; X /* X * If 'number' mode is on, add another 8. X */ X if (P(P_NU)) X col += 8; X X return ((col + (Columns-1)) / Columns); X} X Xvoid Xfileinfo() X{ X long l1, l2; X char buf[80]; X X if (bufempty()) { X l1 = 0; X l2 = 1; /* sonst div by zero */ X } X else { X l1 = cntllines(Filemem, Curschar); X l2 = cntllines(Filemem, Fileend) - 1; X } X X l1 = cntllines(Filemem, Curschar); X l2 = cntllines(Filemem, Fileend) - 1; X sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --", X (Filename != NULL) ? Filename : "No File", X Changed ? " [Modified]" : "", X l1, l2, (l1 * 100)/l2); X msg(buf); X} X X/* X * gotoline(n) - return a pointer to line 'n' X * X * Returns a pointer to the last line of the file if n is zero, or X * beyond the end of the file. X */ XLPTR * Xgotoline(n) Xint n; X{ X static LPTR l; X X l.index = 0; X X if ( n == 0 ) X l = *prevline(Fileend); X else { X LPTR *p; X X for (l = *Filemem; --n > 0 ;l = *p) X if ((p = nextline(&l)) == NULL) X break; X } X return &l; X} X Xvoid Xinschar(c) Xint c; X{ X register char *p, *pend; X X /* make room for the new char. */ X if ( ! canincrease(1) ) X return; X X if (State != REPLACE) { X p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1]; X pend = &Curschar->linep->s[Curschar->index]; X X for (; p > pend ;p--) X *p = *(p-1); X X *p = c; X X } else { /* replace mode */ X /* X * Once we reach the end of the line, we are effectively X * inserting new text, so make sure the string terminator X * stays out there. X */ X if (gchar(Curschar) == NUL) X Curschar->linep->s[Curschar->index+1] = NUL; X pchar(Curschar, c); X } X X /* X * If we're in insert mode and showmatch mode is set, then X * check for right parens and braces. If there isn't a match, X * then beep. If there is a match AND it's on the screen, then X * flash to it briefly. If it isn't on the screen, don't do anything. X */ X if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) { X LPTR *lpos, csave; X X if ((lpos = showmatch()) == NULL) /* no match, so beep */ X beep(); X else if (LINEOF(lpos) >= LINEOF(Topchar)) { X updatescreen(); /* show the new char first */ X csave = *Curschar; X *Curschar = *lpos; /* move to matching char */ X cursupdate(); X windgoto(Cursrow, Curscol); X delay(); /* brief pause */ X *Curschar = csave; /* restore cursor position */ X cursupdate(); X } X } X X inc(Curschar); X CHANGED; X} X X#if 0 Xvoid Xinsstr(s) Xregister char *s; X{ X register char *p, *endp; X register int k, n = strlen(s); X X /* Move everything in the file over to make */ X /* room for the new string. */ X if (!canincrease(n)) X return; X X endp = &Curschar->linep->s[Curschar->index]; X p = Curschar->linep->s + strlen(Curschar->linep->s) + 1 + n; X X for (; p>endp ;p--) X *p = *(p-n); X X p = &Curschar->linep->s[Curschar->index]; X for ( k=0; k<n; k++ ) { X *p++ = *s++; X inc(Curschar); X } X CHANGED; X} X#endif X Xbool_t Xdelchar(fixpos) Xbool_t fixpos; /* if TRUE, fix the cursor position when done */ X{ X register int i; X X /* Check for degenerate case; there's nothing in the file. */ X if (bufempty()) X return FALSE; X X if (lineempty()) /* can't do anything */ X return FALSE; X X /* Delete the char. at Curschar by shifting everything */ X /* in the line down. */ X for ( i=Curschar->index+1; i < Curschar->linep->size ;i++) X Curschar->linep->s[i-1] = Curschar->linep->s[i]; X X /* If we just took off the last character of a non-blank line, */ X /* we don't want to end up positioned at the newline. */ X if (fixpos) { X if (gchar(Curschar)==NUL && Curschar->index>0 && State!=INSERT) X Curschar->index--; X } X CHANGED; X X return TRUE; X} X X Xvoid Xdelline(nlines, can_update) Xint nlines; Xbool_t can_update; X{ X register LINE *p, *q; X int doscreen; /* if true, update the screen */ X X doscreen = can_update; X /* X * There's no point in keeping the screen updated if we're X * deleting more than a screen's worth of lines. X */ X if (nlines > (Rows - 1) && can_update) { X doscreen = FALSE; X s_del(Cursrow, Rows-1); /* flaky way to clear rest of screen */ X } X X while ( nlines-- > 0 ) { X X if (bufempty()) /* nothing to delete */ X break; X X if (buf1line()) { /* just clear the line */ X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X break; X } X X p = Curschar->linep->prev; X q = Curschar->linep->next; X X if (p == Filetop->linep) { /* first line of file so... */ X Filemem->linep = q; /* adjust start of file */ X Topchar->linep = q; /* and screen */ X } X p->next = q; X q->prev = p; X X clrmark(Curschar->linep); /* clear marks for the line */ X X /* X * Delete the correct number of physical lines on the screen X */ X if (doscreen) X s_del(Cursrow, plines(Curschar)); X X /* X * If deleting the top line on the screen, adjust Topchar X */ X if (Topchar->linep == Curschar->linep) X Topchar->linep = q; X X free(Curschar->linep->s); X free(Curschar->linep); X X Curschar->linep = q; X Curschar->index = 0; /* is this right? */ X CHANGED; X X /* If we delete the last line in the file, back up */ X if ( Curschar->linep == Fileend->linep) { X Curschar->linep = Curschar->linep->prev; X /* and don't try to delete any more lines */ X break; X } X } X} END_OF_FILE if test 11025 -ne `wc -c <'misccmds.c'`; then echo shar: \"'misccmds.c'\" unpacked with wrong size! fi # end of 'misccmds.c' fi if test -f 'normal.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'normal.c'\" else echo shar: Extracting \"'normal.c'\" \(28721 characters\) sed "s/^X//" >'normal.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: normal.c,v 1.12 88/11/01 21:32:55 tony Exp $"; X X/* X * Contains the main routine for processing characters in X * command mode as well as routines for handling the operators. X * X * $Log: normal.c,v $ X * Revision 1.12 88/11/01 21:32:55 tony X * Improved the 'put' code. It now modifies the buffer directly instead X * of stuffing things into the input buffer. This is MUCH faster. The X * yank buffer is still statically allocated, but this can be easily X * changed now. X * X * Revision 1.11 88/10/27 08:13:39 tony X * Made the replace command more robust. X * X * Revision 1.10 88/09/16 08:37:05 tony X * No longer beeps when repeated searches fail. X * X * Revision 1.9 88/08/30 20:36:57 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 1.8 88/08/26 13:46:05 tony X * Added support for the '!' (filter) operator. X * X * Revision 1.7 88/08/26 08:45:24 tony X * Misc. changes to make lint happy. X * X * Revision 1.6 88/07/09 20:38:20 tony X * Added support code for the 'U' command. X * X * Revision 1.5 88/06/28 07:51:09 tony X * Fixed a bug involving redo's of the '~' command. The redo would just X * repeat the replacement last performed instead of switching the case of X * the current character. X * X * Revision 1.4 88/06/26 14:49:45 tony X * Modified calls to delline() for the addition of a new parameter. X * X * Revision 1.3 88/05/04 08:28:09 tony X * Fixed a minor bug with the 'G' command. It now goes to the first X * non-white character on the destination line. X * X * Revision 1.2 88/04/29 14:47:21 tony X * Fixed up several motion commands to clear any pending operator if the X * motion command failed. This fixes several bugs where commands like X * "dtx" would fail, but still perform the indicated operation. X * X * Revision 1.1 88/03/20 21:09:09 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xstatic void doshift(), dodelete(), doput(), dochange(), dofilter(); Xstatic void tabinout(), startinsert(); Xstatic bool_t dojoin(), doyank(); X X/* X * Macro evaluates true if char 'c' is a valid identifier character X */ X#define IDCHAR(c) (isalpha(c) || isdigit(c) || (c) == '_') X X/* X * Operators X */ X#define NOP 0 /* no pending operation */ X#define DELETE 1 X#define YANK 2 X#define CHANGE 3 X#define LSHIFT 4 X#define RSHIFT 5 X#define FILTER 6 X X#define CLEAROP (operator = NOP) /* clear any pending operator */ X Xstatic int operator = NOP; /* current pending operator */ X X/* X * When a cursor motion command is made, it is marked as being a character X * or line oriented motion. Then, if an operator is in effect, the operation X * becomes character or line oriented accordingly. X * X * Character motions are marked as being inclusive or not. Most char. X * motions are inclusive, but some (e.g. 'w') are not. X * X * Generally speaking, every command in normal() should either clear any X * pending operator (with CLEAROP), or set the motion type variable. X */ X X/* X * Motion types X */ X#define MBAD (-1) /* 'bad' motion type marks unusable yank buf */ X#define MCHAR 0 X#define MLINE 1 X Xstatic int mtype; /* type of the current cursor motion */ Xstatic bool_t mincl; /* true if char motion is inclusive */ X Xstatic LPTR startop; /* cursor pos. at start of operator */ X X/* X * Operators can have counts either before the operator, or between the X * operator and the following cursor motion as in: X * X * d3w or 3dw X * X * If a count is given before the operator, it is saved in opnum. If X * normal() is called with a pending operator, the count in opnum (if X * present) overrides any count that came later. X */ Xstatic int opnum = 0; X X X#define DEFAULT1(x) (((x) == 0) ? 1 : (x)) X X/* X * normal X * X * Execute a command in normal mode. X */ X Xvoid Xnormal(c) Xint c; X{ X int n; X bool_t flag = FALSE; X int type = 0; /* used in some operations to modify type */ X int dir = FORWARD; /* search direction */ X int nchar = NUL; X bool_t finish_op; X X /* X * If there is an operator pending, then the command we take X * this time will terminate it. Finish_op tells us to finish X * the operation before returning this time (unless the operation X * was cancelled. X */ X finish_op = (operator != NOP); X X /* X * If we're in the middle of an operator AND we had a count before X * the operator, then that count overrides the current value of X * Prenum. What this means effectively, is that commands like X * "3dw" get turned into "d3w" which makes things fall into place X * pretty neatly. X */ X if (finish_op) { X if (opnum != 0) X Prenum = opnum; X } else X opnum = 0; X X u_lcheck(); /* clear the "line undo" buffer if we've moved */ X X switch(c & 0xff){ X X case K_HELP: X CLEAROP; X if (help()) { X screenclear(); X updatescreen(); X } X break; X X case CTRL('L'): X CLEAROP; X screenclear(); X updatescreen(); X break; X X case CTRL('D'): X CLEAROP; X if (Prenum) X P(P_SS) = (Prenum > Rows-1) ? Rows-1 : Prenum; X scrollup(P(P_SS)); X onedown(P(P_SS)); X updatescreen(); X break; X X case CTRL('U'): X CLEAROP; X if (Prenum) X P(P_SS) = (Prenum > Rows-1) ? Rows-1 : Prenum; X scrolldown(P(P_SS)); X oneup(P(P_SS)); X updatescreen(); X break; X X /* X * ^F and ^B are neat hacks, but don't take counts. This is very X * code-efficient, and does the right thing. I'll fix it later X * to take a count. The old code took a count, but didn't do the X * right thing in other respects (e.g. leaving some context). X */ X case CTRL('F'): X#if 1 X screenclear(); X stuffin("Lz\nM"); X#else X /* X * Old code X */ X CLEAROP; X n = DEFAULT1(Prenum); X if ( ! onedown(Rows * n) ) X beep(); X cursupdate(); X#endif X break; X X case CTRL('B'): X#if 1 X screenclear(); X stuffin("Hz-M"); X#else X /* X * Old code X */ X CLEAROP; X n = DEFAULT1(Prenum); X if ( ! oneup(Rows * n) ) X beep(); X cursupdate(); X#endif X break; X X case CTRL('E'): X CLEAROP; X scrollup(DEFAULT1(Prenum)); X updatescreen(); X break; X X case CTRL('Y'): X CLEAROP; X scrolldown(DEFAULT1(Prenum)); X updatescreen(); X break; X X case 'z': X CLEAROP; X switch (vgetc()) { X case NL: /* put Curschar at top of screen */ X case CR: X *Topchar = *Curschar; X Topchar->index = 0; X updatescreen(); X break; X X case '.': /* put Curschar in middle of screen */ X n = Rows/2; X goto dozcmd; X X case '-': /* put Curschar at bottom of screen */ X n = Rows-1; X /* fall through */ X X dozcmd: X { X register LPTR *lp = Curschar; X register int l = 0; X X while ((l < n) && (lp != NULL)) { X l += plines(lp); X *Topchar = *lp; X lp = prevline(lp); X } X } X Topchar->index = 0; X updatescreen(); X break; X X default: X beep(); X } X break; X X case CTRL('G'): X CLEAROP; X fileinfo(); X break; X X case 'G': X mtype = MLINE; X *Curschar = *gotoline(Prenum); X beginline(TRUE); X break; X X case 'H': X mtype = MLINE; X *Curschar = *Topchar; X for (n = Prenum; n && onedown(1) ;n--) X ; X beginline(TRUE); X break; X X case 'M': X mtype = MLINE; X *Curschar = *Topchar; X for (n = 0; n < Rows/2 && onedown(1) ;n++) X ; X beginline(TRUE); X break; X X case 'L': X mtype = MLINE; X *Curschar = *prevline(Botchar); X for (n = Prenum; n && oneup(1) ;n--) X ; X beginline(TRUE); X break; X X case 'l': X case K_RARROW: X case ' ': X mtype = MCHAR; X mincl = FALSE; X n = DEFAULT1(Prenum); X while (n--) { X if ( ! oneright() ) X beep(); X } X set_want_col = TRUE; X break; X X case 'h': X case K_LARROW: X case CTRL('H'): X mtype = MCHAR; X mincl = FALSE; X n = DEFAULT1(Prenum); X while (n--) { X if ( ! oneleft() ) X beep(); X } X set_want_col = TRUE; X break; X X case '-': X flag = TRUE; X /* fall through */ X X case 'k': X case K_UARROW: X case CTRL('P'): X mtype = MLINE; X if ( ! oneup(DEFAULT1(Prenum)) ) X beep(); X if (flag) X beginline(TRUE); X break; X X case '+': X case CR: X case NL: X flag = TRUE; X /* fall through */ X X case 'j': X case K_DARROW: X case CTRL('N'): X mtype = MLINE; X if ( ! onedown(DEFAULT1(Prenum)) ) X beep(); X if (flag) X beginline(TRUE); X break; X X /* X * This is a strange motion command that helps make operators X * more logical. It is actually implemented, but not documented X * in the real 'vi'. This motion command actually refers to "the X * current line". Commands like "dd" and "yy" are really an alternate X * form of "d_" and "y_". It does accept a count, so "d3_" works to X * delete 3 lines. X */ X case '_': X lineop: X mtype = MLINE; X onedown(DEFAULT1(Prenum)-1); X break; X X case '|': X mtype = MCHAR; X mincl = TRUE; X beginline(FALSE); X if (Prenum > 0) X *Curschar = *coladvance(Curschar, Prenum-1); X Curswant = Prenum - 1; X break; X X case CTRL(']'): /* :ta to current identifier */ X CLEAROP; X { X char ch; X LPTR save; X X save = *Curschar; X /* X * First back up to start of identifier. This X * doesn't match the real vi but I like it a X * little better and it shouldn't bother anyone. X */ X ch = gchar(Curschar); X while (IDCHAR(ch)) { X if (!oneleft()) X break; X ch = gchar(Curschar); X } X if (!IDCHAR(c)) X oneright(); X X stuffin(":ta "); X /* X * Now grab the chars in the identifier X */ X ch = gchar(Curschar); X while (IDCHAR(ch)) { X stuffin(mkstr(ch)); X if (!oneright()) X break; X ch = gchar(Curschar); X } X stuffin("\n"); X X *Curschar = save; /* restore, in case of error */ X } X break; X X case '%': X mtype = MCHAR; X mincl = TRUE; X { X LPTR *pos; X X if ((pos = showmatch()) == NULL) { X beep(); X CLEAROP; X } else { X setpcmark(); X *Curschar = *pos; X set_want_col = TRUE; X } X } X break; X X /* X * Word Motions X */ X X case 'B': X type = 1; X /* fall through */ X X case 'b': X mtype = MCHAR; X mincl = FALSE; X set_want_col = TRUE; X for (n = DEFAULT1(Prenum); n > 0 ;n--) { X LPTR *pos; X X if ((pos = bck_word(Curschar, type)) == NULL) { X beep(); X CLEAROP; X break; X } else X *Curschar = *pos; X } X break; X X case 'W': X type = 1; X /* fall through */ X X case 'w': X /* X * This is a little strange. To match what the real vi X * does, we effectively map 'cw' to 'ce', and 'cW' to 'cE'. X * This seems impolite at first, but it's really more X * what we mean when we say 'cw'. X */ X if (operator == CHANGE) X goto doecmd; X X mtype = MCHAR; X mincl = FALSE; X set_want_col = TRUE; X for (n = DEFAULT1(Prenum); n > 0 ;n--) { X LPTR *pos; X X if ((pos = fwd_word(Curschar, type)) == NULL) { X beep(); X CLEAROP; X break; X } else X *Curschar = *pos; X } X break; X X case 'E': X type = 1; X /* fall through */ X X case 'e': X doecmd: X mtype = MCHAR; X mincl = TRUE; X set_want_col = TRUE; X for (n = DEFAULT1(Prenum); n > 0 ;n--) { X LPTR *pos; X X if ((pos = end_word(Curschar, type)) == NULL) { X beep(); X CLEAROP; X break; X } else X *Curschar = *pos; X } X break; X X case '$': X mtype = MCHAR; X mincl = TRUE; X while ( oneright() ) X ; X Curswant = 999; /* so we stay at the end */ X break; X X case '^': X flag = TRUE; X /* fall through */ X X case '0': X mtype = MCHAR; X mincl = TRUE; X beginline(flag); X break; X X case 'x': X CLEAROP; X if (lineempty()) /* can't do it on a blank line */ X beep(); X if (Prenum) X stuffnum(Prenum); X stuffin("d."); X break; X X case 'X': X CLEAROP; X if (!oneleft()) X beep(); X else { X addtobuff(Redobuff, 'X', NUL); X u_saveline(); X delchar(TRUE); X updateline(); X } X break; X X case 'A': X set_want_col = TRUE; X while (oneright()) X ; X /* fall through */ X X case 'a': X CLEAROP; X /* Works just like an 'i'nsert on the next character. */ X if (!lineempty()) X inc(Curschar); X u_saveline(); X startinsert(mkstr(c), FALSE); X break; X X case 'I': X beginline(TRUE); X /* fall through */ X X case 'i': X case K_INSERT: X CLEAROP; X u_saveline(); X startinsert(mkstr(c), FALSE); X break; X X case 'o': X CLEAROP; X u_save(Curschar->linep, Curschar->linep->next); X opencmd(FORWARD, TRUE); X startinsert("o", TRUE); X break; X X case 'O': X CLEAROP; X u_save(Curschar->linep->prev, Curschar->linep); X opencmd(BACKWARD, TRUE); X startinsert("O", TRUE); X break; X X case 'R': X CLEAROP; X u_saveline(); X startinsert("R", FALSE); X break; X X case 'd': X if (operator == DELETE) /* handle 'dd' */ X goto lineop; X if (Prenum != 0) X opnum = Prenum; X startop = *Curschar; X operator = DELETE; X break; X X case '!': X if (operator == FILTER) /* handle '!!' */ X goto lineop; X if (Prenum != 0) X opnum = Prenum; X startop = *Curschar; X operator = FILTER; X break; X X /* X * Some convenient abbreviations... X */ X X case 'D': X stuffin("d$"); X break; X X case 'Y': X if (Prenum) X stuffnum(Prenum); X stuffin("yy"); X break; X X case 'C': X stuffin("c$"); X break; X X case 'c': X if (operator == CHANGE) { /* handle 'cc' */ X CLEAROP; X stuffin("0c$"); X break; X } X if (Prenum != 0) X opnum = Prenum; X startop = *Curschar; X operator = CHANGE; X break; X X case 'y': X if (operator == YANK) /* handle 'yy' */ X goto lineop; X if (Prenum != 0) X opnum = Prenum; X startop = *Curschar; X operator = YANK; X break; X X case 'p': X doput(FORWARD); X break; X X case 'P': X doput(BACKWARD); X break; X X case '>': X if (operator == RSHIFT) /* handle >> */ X goto lineop; X if (Prenum != 0) X opnum = Prenum; X startop = *Curschar; X operator = RSHIFT; X break; X X case '<': X if (operator == LSHIFT) /* handle << */ X goto lineop; X if (Prenum != 0) X opnum = Prenum; X startop = *Curschar; /* save current position */ X operator = LSHIFT; X break; X X case 's': /* substitute characters */ X if (Prenum) X stuffnum(Prenum); X stuffin("c."); X break; X X case '?': X case '/': X case ':': X CLEAROP; X readcmdline(c, NULL); X break; X X case 'n': X mtype = MCHAR; X mincl = FALSE; X set_want_col = TRUE; X if (!repsearch(0)) X CLEAROP; X break; X X case 'N': X mtype = MCHAR; X mincl = FALSE; X set_want_col = TRUE; X if (!repsearch(1)) X CLEAROP; X break; X X /* X * Character searches X */ X case 'T': X dir = BACKWARD; X /* fall through */ X X case 't': X type = 1; X goto docsearch; X X case 'F': X dir = BACKWARD; X /* fall through */ X X case 'f': X docsearch: X mtype = MCHAR; X mincl = TRUE; X set_want_col = TRUE; X if ((nchar = vgetc()) == ESC) /* search char */ X break; X if (!searchc(nchar, dir, type)) { X CLEAROP; X beep(); X } X break; X X case ',': X flag = 1; X /* fall through */ X X case ';': X mtype = MCHAR; X mincl = TRUE; X set_want_col = TRUE; X if (!crepsearch(flag)) { X CLEAROP; X beep(); X } X break; X X /* X * Function searches X */ X X case '[': X dir = BACKWARD; X /* fall through */ X X case ']': X mtype = MLINE; X set_want_col = TRUE; X if (vgetc() != c) { X beep(); X CLEAROP; X break; X } X X if (!findfunc(dir)) { X beep(); X CLEAROP; X } X break; X X /* X * Marks X */ X X case 'm': X CLEAROP; X if (!setmark(vgetc())) X beep(); X break; X X case '\'': X flag = TRUE; X /* fall through */ X X case '`': X { X LPTR mtmp, *mark = getmark(vgetc()); X X if (mark == NULL) { X beep(); X CLEAROP; X } else { X mtmp = *mark; X setpcmark(); X *Curschar = mtmp; X if (flag) X beginline(TRUE); X } X mtype = flag ? MLINE : MCHAR; X mincl = TRUE; /* ignored if not MCHAR */ X set_want_col = TRUE; X } X break; X X case 'r': X CLEAROP; X if (lineempty()) { /* Nothing to replace */ X beep(); X break; X } X if ((nchar = vgetc()) == ESC) X break; X X if ((nchar & 0x80) || nchar == CR || nchar == NL) { X beep(); X break; X } X u_saveline(); X X /* Change current character. */ X pchar(Curschar, nchar); X X /* Save stuff necessary to redo it */ X addtobuff(Redobuff, 'r', nchar, NULL); X X CHANGED; X updateline(); X break; X X case '~': /* swap case */ X CLEAROP; X if (lineempty()) { X beep(); X break; X } X c = gchar(Curschar); X X if (isalpha(c)) { X if (islower(c)) X c = toupper(c); X else X c = tolower(c); X } X u_saveline(); X X pchar(Curschar, c); /* Change current character. */ X oneright(); X X addtobuff(Redobuff, '~', NULL); X X CHANGED; X updateline(); X X break; X X case 'J': X CLEAROP; X X u_save(Curschar->linep->prev, Curschar->linep->next->next); X X if (!dojoin()) X beep(); X X addtobuff(Redobuff,'J',NULL); X updatescreen(); X break; X X case K_CGRAVE: /* shorthand command */ X CLEAROP; X stuffin(":e #\n"); X break; X X case 'Z': /* write, if changed, and exit */ X if (vgetc() != 'Z') { X beep(); X break; X } X X doxit(); X break; X X case '.': X /* X * If a delete is in effect, we let '.' help out the same X * way that '_' helps for some line operations. It's like X * an 'l', but subtracts one from the count and is inclusive. X */ X if (operator == DELETE || operator == CHANGE) { X if (Prenum != 0) { X n = DEFAULT1(Prenum) - 1; X while (n--) X if (! oneright()) X break; X } X mtype = MCHAR; X mincl = TRUE; X } else { /* a normal 'redo' */ X CLEAROP; X stuffin(Redobuff); X } X break; X X case 'u': X case K_UNDO: X CLEAROP; X u_undo(); X break; X X case 'U': X CLEAROP; X u_lundo(); X break; X X default: X CLEAROP; X beep(); X break; X } X X /* X * If an operation is pending, handle it... X */ X if (finish_op) { /* we just finished an operator */ X if (operator == NOP) /* ... but it was cancelled */ X return; X X switch (operator) { X X case LSHIFT: X case RSHIFT: X doshift(operator, c, nchar, Prenum); X break; X X case DELETE: X dodelete(c, nchar, Prenum); X break; X X case YANK: X doyank(); /* no redo on yank... */ X break; X X case CHANGE: X dochange(c, nchar, Prenum); X break; X X case FILTER: X dofilter(c, nchar, Prenum); X break; X X default: X beep(); X } X operator = NOP; X } X} X X/* X * doshift - handle a shift operation X */ Xstatic void Xdoshift(op, c1, c2, num) Xint op; Xchar c1, c2; Xint num; X{ X LPTR top, bot; X int nlines; X char opchar; X X top = startop; X bot = *Curschar; X X if (lt(&bot, &top)) X pswap(&top, &bot); X X u_save(top.linep->prev, bot.linep->next); X X nlines = cntllines(&top, &bot); X *Curschar = top; X tabinout((op == LSHIFT), nlines); X X /* construct Redo buff */ X opchar = (op == LSHIFT) ? '<' : '>'; X if (num != 0) X sprintf(Redobuff, "%c%d%c%c", opchar, num, c1, c2); X else X sprintf(Redobuff, "%c%c%c", opchar, c1, c2); X X /* X * The cursor position afterward is the prior of the two positions. X */ X *Curschar = top; X X /* X * If we were on the last char of a line that got shifted left, X * then move left one so we aren't beyond the end of the line X */ X if (gchar(Curschar) == NUL && Curschar->index > 0) X Curschar->index--; X X updatescreen(); X X if (nlines > P(P_RP)) X smsg("%d lines %ced", nlines, opchar); X} X X/* X * dodelete - handle a delete operation X */ Xstatic void Xdodelete(c1, c2, num) Xchar c1, c2; Xint num; X{ X LPTR top, bot; X int nlines; X int n; X X /* X * Do a yank of whatever we're about to delete. If there's too much X * stuff to fit in the yank buffer, then get a confirmation before X * doing the delete. This is crude, but simple. And it avoids doing X * a delete of something we can't put back if we want. X */ X if (!doyank()) { X msg("yank buffer exceeded: press <y> to confirm"); X if (vgetc() != 'y') { X msg("delete aborted"); X *Curschar = startop; X return; X } X } X X top = startop; X bot = *Curschar; X X if (lt(&bot, &top)) X pswap(&top, &bot); X X u_save(top.linep->prev, bot.linep->next); X X nlines = cntllines(&top, &bot); X *Curschar = top; X cursupdate(); X X if (mtype == MLINE) { X delline(nlines, TRUE); X } else { X if (!mincl && bot.index != 0) X dec(&bot); X X if (top.linep == bot.linep) { /* del. within line */ X n = bot.index - top.index + 1; X while (n--) X if (!delchar(TRUE)) X break; X } else { /* del. between lines */ X n = Curschar->index; X while (Curschar->index >= n) X if (!delchar(TRUE)) X break; X X top = *Curschar; X *Curschar = *nextline(Curschar); X delline(nlines-2, TRUE); X Curschar->index = 0; X n = bot.index + 1; X while (n--) X if (!delchar(TRUE)) X break; X *Curschar = top; X dojoin(); X } X } X X /* construct Redo buff */ X if (num != 0) X sprintf(Redobuff, "d%d%c%c", num, c1, c2); X else X sprintf(Redobuff, "d%c%c", c1, c2); X X if (mtype == MCHAR && nlines == 1) X updateline(); X else X updatescreen(); X X if (nlines > P(P_RP)) X smsg("%d fewer lines", nlines); X} X X/* X * dofilter - handle a filter operation X */ X X#define ITMP "/tmp/viXXXXXX" X#define OTMP "/tmp/voXXXXXX" X Xstatic char itmp[15]; Xstatic char otmp[15]; X X X/* X * dofilter - filter lines through a command given by the user X * X * We use temp files and the system() routine here. This would normally X * be done using pipes on a UNIX machine, but this is more portable to X * the machines we usually run on. The system() routine needs to be able X * to deal with redirection somehow, and should handle things like looking X * at the PATH env. variable, and adding reasonable extensions to the X * command name given by the user. All reasonable versions of system() X * do this. X */ Xstatic void Xdofilter(c1, c2, num) Xchar c1, c2; Xint num; X{ X char *mktemp(); X static char *lastcmd = NULL; /* the last thing we did */ X char buff[80]; /* buffer for prompting */ X char *p, *q; X char c; X char cmdln[128]; /* filtering command line */ X LPTR top, bot; X int nlines; X int n; X X top = startop; X bot = *Curschar; X X /* X * Finish prompting for the filtering command... X */ X gotocmd(TRUE, '!'); X p = buff; X X /* collect the command string, handling '\b' and @ */ X for (;;) { X c = vgetc(); X if (c==NL || c==CR || c==EOF) X break; X if (c == BS) { X if (p > buff) { X p--; X /* this is gross, but it relies X * only on 'gotocmd' X */ X gotocmd(TRUE, '!'); X for (q=buff; q < p ; q++) X outchar(*q); X } else { X msg(""); X return; /* operator aborted */ X } X continue; X } X if (c == '@') { X p = buff; X gotocmd(TRUE, '!'); X continue; X } X outchar(c); X *p++ = c; X } X *p = '\0'; X X if (buff[0] == '!') { /* use the 'last' command */ X if (lastcmd == NULL) { X emsg("No previous command"); X return; X } X strcpy(buff, lastcmd); X } X X /* X * Remember the current command X */ X if (lastcmd != NULL) X free(lastcmd); X lastcmd = strsave(buff); X X if (lt(&bot, &top)) X pswap(&top, &bot); X X u_save(top.linep->prev, bot.linep->next); X X nlines = cntllines(&top, &bot); X *Curschar = top; X cursupdate(); X X /* X * 1. Form temp file names X * 2. Write the lines to a temp file X * 3. Run the filter command on the temp file X * 4. Read the output of the command into the buffer X * 5. Delete the original lines to be filtered X * 6. Remove the temp files X */ X X strcpy(itmp, ITMP); X strcpy(otmp, OTMP); X X if (mktemp(itmp) == NULL || mktemp(otmp) == NULL) { X emsg("Can't get temp file names"); X return; X } X X if (!writeit(itmp, &top, &bot)) { X emsg("Can't create input temp file"); X return; X } X X sprintf(cmdln, "%s <%s >%s", buff, itmp, otmp); X X if (system(cmdln) != 0) { X emsg("Filter command failed"); X remove(ITMP); X return; X } X X if (readfile(otmp, &bot, TRUE)) { X emsg("Can't read filter output"); X return; X } X X delline(nlines, TRUE); X X remove(itmp); X remove(otmp); X X /* construct Redo buff */ X if (num != 0) X sprintf(Redobuff, "d%d%c%c", num, c1, c2); X else X sprintf(Redobuff, "d%c%c", c1, c2); X X updatescreen(); X X if (nlines > P(P_RP)) X smsg("%d lines filtered", nlines); X} X X/* X * dochange - handle a change operation X */ Xstatic void Xdochange(c1, c2, num) Xchar c1, c2; Xint num; X{ X char sbuf[16]; X bool_t doappend; /* true if we should do append, not insert */ X X doappend = endofline( (lt(Curschar, &startop)) ? &startop: Curschar); X X if (mtype == MLINE) { X msg("multi-line changes not yet supported"); X return; X } X X dodelete(c1, c2, num); X X if (num) X sprintf(sbuf, "c%d%c%c", num, c1, c2); X else X sprintf(sbuf, "c%c%c", c1, c2); X X if (doappend && !lineempty()) X inc(Curschar); X X startinsert(sbuf, FALSE); X} X X#ifndef YBSIZE X#define YBSIZE 4096 X#endif X Xstatic char ybuf[YBSIZE]; Xstatic int ybtype = MBAD; X Xstatic bool_t Xdoyank() X{ X LPTR top, bot; X char *yptr = ybuf; X char *ybend = &ybuf[YBSIZE-1]; X int nlines; X X top = startop; X bot = *Curschar; X X if (lt(&bot, &top)) X pswap(&top, &bot); X X nlines = cntllines(&top, &bot); X X ybtype = mtype; /* set the yank buffer type */ X X if (mtype == MLINE) { X top.index = 0; X bot.index = strlen(bot.linep->s); X /* X * The following statement checks for the special case of X * yanking a blank line at the beginning of the file. If X * not handled right, we yank an extra char (a newline). X */ X if (dec(&bot) == -1) { X ybuf[0] = NUL; X if (operator == YANK) X *Curschar = startop; X return TRUE; X } X } else { X if (!mincl) { X if (bot.index) X bot.index--; X } X } X X for (; ltoreq(&top, &bot) ;inc(&top)) { X *yptr = (gchar(&top) != NUL) ? gchar(&top) : NL; X if (++yptr >= ybend) { X msg("yank too big for buffer"); X ybtype = MBAD; X return FALSE; X } X } X X *yptr = NUL; X X if (operator == YANK) { /* restore Curschar if really doing yank */ X *Curschar = startop; X X if (nlines > P(P_RP)) X smsg("%d lines yanked", nlines); X } X X return TRUE; X} X X/* X * inslines(lp, dir, buf) X * X * Inserts lines in the file from the given buffer. Lines are inserted X * before or after "lp" according to the given direction flag. Newlines X * in the buffer result in multiple lines being inserted. The cursor X * is left on the first of the inserted lines. X */ Xstatic void Xinslines(lp, dir, buf) XLINE *lp; Xint dir; Xchar *buf; X{ X register char *cp = buf; X register int len; X char *ep; X LINE *l, *nc = NULL; X LPTR sc; X X if (dir == BACKWARD) X lp = lp->prev; X X do { X if ((ep = strchr(cp, NL)) == NULL) X len = strlen(cp); X else X len = ep - cp; X X l = newline(len+1); X strncpy(l->s, cp, len); X l->s[len] = NUL; X X l->next = lp->next; X l->prev = lp; X lp->next->prev = l; X lp->next = l; X X if (nc == NULL) X nc = l; X X lp = lp->next; X X cp = ep + 1; X } while (ep != NULL); X X if (dir == BACKWARD) /* fix the top line in case we were there */ X Filemem->linep = Filetop->linep->next; X X renum(); X X updatescreen(); X Curschar->linep = nc; X Curschar->index = 0; X} X X/* X * doput(dir) X * X * Put the yank buffer at the current location, using the direction given X * by 'dir'. X */ Xstatic void Xdoput(dir) Xint dir; X{ X if (ybtype == MBAD) { X beep(); X return; X } X X u_saveline(); X X if (ybtype == MLINE) X inslines(Curschar->linep, dir, ybuf); X else { X /* X * If we did a character-oriented yank, and the buffer X * contains multiple lines, the situation is more complex. X * For the moment, we punt, and pretend the user did a X * line-oriented yank. This doesn't actually happen that X * often. X */ X if (strchr(ybuf, NL) != NULL) X inslines(Curschar->linep, dir, ybuf); X else { X char *s; X int len; X X len = strlen(Curschar->linep->s) + strlen(ybuf) + 1; X s = alloc(len); X strcpy(s, Curschar->linep->s); X if (dir == FORWARD) X Curschar->index++; X strcpy(s + Curschar->index, ybuf); X strcat(s, &Curschar->linep->s[Curschar->index]); X free(Curschar->linep->s); X Curschar->linep->s = s; X Curschar->linep->size = len; X updateline(); X } X } X X CHANGED; X} X X/* X * tabinout(inout,num) X * X * If inout==0, add a tab to the begining of the next num lines. X * If inout==1, delete a tab from the beginning of the next num lines. X */ Xstatic void Xtabinout(inout, num) Xint inout; Xint num; X{ X int ntodo = num; X LPTR *p; X X beginline(FALSE); X while ( ntodo-- > 0 ) { X beginline(FALSE); X if ( inout == 0 ) X inschar(TAB); X else { X if ( gchar(Curschar) == TAB ) X delchar(TRUE); X } X if ( ntodo > 0 ) { X if ( (p=nextline(Curschar)) != NULL ) X *Curschar = *p; X else X break; X } X } X} X Xstatic void Xstartinsert(initstr, startln) Xchar *initstr; Xint startln; /* if set, insert point really at start of line */ X{ X char *p, c; X X *Insstart = *Curschar; X if (startln) X Insstart->index = 0; X Ninsert = 0; X Insptr = Insbuff; X for (p=initstr; (c=(*p++))!='\0'; ) X *Insptr++ = c; X X if (*initstr == 'R') X State = REPLACE; X else X State = INSERT; X X if (P(P_MO)) X msg((State == INSERT) ? "Insert Mode" : "Replace Mode"); X} X Xstatic bool_t Xdojoin() X{ X int scol; /* save cursor column */ X int size; /* size of the joined line */ X X if (nextline(Curschar) == NULL) /* on last line */ X return FALSE; X X if (!canincrease(size = strlen(Curschar->linep->next->s))) X return FALSE; X X while (oneright()) /* to end of line */ X ; X X strcat(Curschar->linep->s, Curschar->linep->next->s); X X /* X * Delete the following line. To do this we move the cursor X * there briefly, and then move it back. Don't back up if the X * delete made us the last line. X */ X Curschar->linep = Curschar->linep->next; X scol = Curschar->index; X X if (nextline(Curschar) != NULL) { X delline(1, TRUE); X Curschar->linep = Curschar->linep->prev; X } else X delline(1, TRUE); X X Curschar->index = scol; X X oneright(); /* go to first char. of joined line */ X X if (size != 0) { X /* X * Delete leading white space on the joined line X * and insert a single space. X */ X while (gchar(Curschar) == ' ' || gchar(Curschar) == TAB) X delchar(TRUE); X inschar(' '); X } X X return TRUE; X} X Xchar * Xmkstr(c) Xchar c; X{ X static char s[2]; X X s[0] = c; X s[1] = NUL; X X return s; X} END_OF_FILE if test 28721 -ne `wc -c <'normal.c'`; then echo shar: \"'normal.c'\" unpacked with wrong size! fi # end of 'normal.c' fi if test -f 'os2_c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'os2_c'\" else echo shar: Extracting \"'os2_c'\" \(5296 characters\) sed "s/^X//" >'os2_c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: os2.c,v 1.4 88/10/28 14:40:33 tony Exp $"; X X/* X * OS/2 System-dependent routines. X * X * $Log: os2.c,v $ X * Revision 1.4 88/10/28 14:40:33 tony X * Added doshell() to support ":sh" and ":!". X * X * Revision 1.3 88/10/06 10:14:22 tony X * Added fixname() routine which trims the base and extension parts of X * a file name to 8 and 3 characters, and returns a pointer to the X * resulting string. This makes it easier to deal with UNIX-style names X * on stupid systems. X * X * Revision 1.2 88/04/25 16:50:19 tony X * Minor changes for OS/2 version 1.1; also fixed up the RCS header. X * X * Revision 1.1 88/03/21 12:04:23 tony X * Initial revision X * X * X */ X X#define INCL_BASE X#include <os2.h> X#include "stevie.h" X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X int c; X X for (;;beep()) { /* loop until we get a valid character */ X X flushbuf(); /* flush any pending output */ X X switch (c = getch()) { X case 0x1e: X return K_CGRAVE; X case 0: /* special key */ X if (State != NORMAL) { X c = getch(); /* throw away next char */ X continue; /* and loop for another char */ X } X switch (c = getch()) { X case 0x50: X return K_DARROW; X case 0x48: X return K_UARROW; X case 0x4b: X return K_LARROW; X case 0x4d: X return K_RARROW; X case 0x52: X return K_INSERT; X case 0x47: X stuffin("1G"); X return -1; X case 0x4f: X stuffin("G"); X return -1; X case 0x51: X stuffin(mkstr(CTRL('F'))); X return -1; X case 0x49: X stuffin(mkstr(CTRL('B'))); X return -1; X /* X * Hard-code some useful function key macros. X */ X case 0x3b: /* F1 */ X stuffin(":p\n"); X return -1; X case 0x54: /* SF1 */ X stuffin(":p!\n"); X return -1; X case 0x3c: /* F2 */ X stuffin(":n\n"); X return -1; X case 0x55: /* SF2 */ X stuffin(":n!\n"); X return -1; X case 0x3d: /* F3 */ X stuffin(":e #\n"); X return -1; X case 0x3e: /* F4 */ X stuffin(":rew\n"); X return -1; X case 0x57: /* SF4 */ X stuffin(":rew!\n"); X return -1; X case 0x3f: /* F5 */ X stuffin("[["); X return -1; X case 0x40: /* F6 */ X stuffin("]]"); X return -1; X case 0x41: /* F7 */ X stuffin("<<"); X return -1; X case 0x42: /* F8 */ X stuffin(">>"); X return -1; X case 0x43: /* F9 */ X stuffin(":x\n"); X return -1; X case 0x44: /* F10 */ X stuffin(":help\n"); X return -1; X default: X break; X } X break; X X default: X return c; X } X } X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xvoid Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xregister char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X Xstatic char cell[2] = { 0, 7 }; X X/* X * outstr(s) - write a string to the console X * X * We implement insert/delete line escape sequences here. This is kind X * of a kludge, but at least it's localized to a single point. X */ Xvoid Xoutstr(s) Xregister char *s; X{ X if (strcmp(s, T_DL) == 0) { /* delete line */ X int r, c; X X flushbuf(); X VioGetCurPos(&r, &c, 0); X VioScrollUp(r, 0, 100, 100, 1, cell, 0); X return; X } X if (strcmp(s, T_IL) == 0) { /* insert line */ X int r, c; X X flushbuf(); X VioGetCurPos(&r, &c, 0); X VioScrollDn(r, 0, 100, 100, 1, cell, 0); X return; X } X X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X outone('\007'); X} X Xsleep(n) Xint n; X{ X DosSleep(1000L * n); X} X Xvoid Xdelay() X{ X flushbuf(); X DosSleep(300L); X} X Xvoid Xwindinit() X{ X Columns = 80; X P(P_LI) = Rows = 25; X} X Xvoid Xwindexit(r) Xint r; X{ X flushbuf(); X exit(r); X} X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X r += 1; X c += 1; X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X FILE *fopen(); X char modestr[16]; X X sprintf(modestr, "%sb", mode); X return fopen(fname, modestr); X} X X#define PSIZE 128 X X/* X * fixname(s) - fix up a dos name X * X * Takes a name like: X * X * \x\y\z\base.ext X * X * and trims 'base' to 8 characters, and 'ext' to 3. X */ Xchar * Xfixname(s) Xchar *s; X{ X char *strchr(), *strrchr(); X static char f[PSIZE]; X char base[32]; X char ext[32]; X char *p; X int i; X X strcpy(f, s); X X for (i=0; i < PSIZE ;i++) X if (f[i] == '/') X f[i] = '\\'; X X /* X * Split the name into directory, base, extension. X */ X if ((p = strrchr(f, '\\')) != NULL) { X strcpy(base, p+1); X p[1] = '\0'; X } else { X strcpy(base, f); X f[0] = '\0'; X } X X if ((p = strchr(base, '.')) != NULL) { X strcpy(ext, p+1); X *p = '\0'; X } else X ext[0] = '\0'; X X /* X * Trim the base name if necessary. X */ X if (strlen(base) > 8) X base[8] = '\0'; X X if (strlen(ext) > 3) X ext[3] = '\0'; X X /* X * Paste it all back together X */ X strcat(f, base); X strcat(f, "."); X strcat(f, ext); X X return f; X} X Xvoid Xdoshell(cmd) Xchar *cmd; X{ X if (cmd == NULL) X cmd = "cmd.exe"; X X system(cmd); X wait_return(); X} END_OF_FILE if test 5296 -ne `wc -c <'os2_c'`; then echo shar: \"'os2_c'\" unpacked with wrong size! fi # end of 'os2_c' fi echo shar: End of shell archive. exit 0
rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) (12/15/88)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: param.c param.h ptrfunc.c readme regexp.c regexp.h # regmagic.h regsub.c screen.c # Wrapped by rtregn@faui32 on Wed Dec 14 17:11:22 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'param.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'param.c'\" else echo shar: Extracting \"'param.c'\" \(4470 characters\) sed "s/^X//" >'param.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: param.c,v 1.6 88/11/10 08:57:18 tony Exp $"; X X/* X * Code to handle user-settable parameters. This is all pretty much table- X * driven. To add a new parameter, put it in the params array, and add a X * macro for it in param.h. If it's a numeric parameter, add any necessary X * bounds checks to doset(). String parameters aren't currently supported. X * X * $Log: param.c,v $ X * Revision 1.6 88/11/10 08:57:18 tony X * Added a new parameter, modelines ("ml"), to support the modeline X * feature. X * X * Revision 1.5 88/08/26 08:45:34 tony X * Misc. changes to make lint happy. X * X * Revision 1.4 88/05/01 20:08:12 tony X * Added the new boolean parameter "number" to turn on line numbering. X * X * Revision 1.3 88/04/30 20:00:29 tony X * Added the parameter "autoindent". X * X * Revision 1.2 88/04/28 08:06:11 tony X * Added a new parameter "ignorecase" which can be set to ignore case X * distinctions in string searches. X * X * Revision 1.1 88/03/20 21:09:40 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xstruct param params[] = { X X { "tabstop", "ts", 8, P_NUM }, X { "scroll", "scroll", 12, P_NUM }, X { "report", "report", 5, P_NUM }, X { "lines", "lines", 25, P_NUM }, X X { "vbell", "vb", TRUE, P_BOOL }, X { "showmatch", "sm", FALSE, P_BOOL }, X { "wrapscan", "ws", TRUE, P_BOOL }, X { "errorbells", "eb", FALSE, P_BOOL }, X { "showmode", "mo", FALSE, P_BOOL }, X { "backup", "bk", FALSE, P_BOOL }, X { "return", "cr", TRUE, P_BOOL }, X { "list", "list", FALSE, P_BOOL }, X { "ignorecase", "ic", FALSE, P_BOOL }, X { "autoindent", "ai", FALSE, P_BOOL }, X { "number", "nu", FALSE, P_BOOL }, X { "modelines", "ml", FALSE, P_BOOL }, X { "", "", 0, 0, } /* end marker */ X X}; X Xstatic void showparms(); X Xvoid Xdoset(arg, inter) Xchar *arg; /* parameter string */ Xbool_t inter; /* TRUE if called interactively */ X{ X int i; X char *s; X bool_t did_lines = FALSE; X X bool_t state = TRUE; /* new state of boolean parms. */ X X if (arg == NULL) { X showparms(FALSE); X return; X } X if (strncmp(arg, "all", 3) == 0) { X showparms(TRUE); X return; X } X if (strncmp(arg, "no", 2) == 0) { X state = FALSE; X arg += 2; X } X X for (i=0; params[i].fullname[0] != NUL ;i++) { X s = params[i].fullname; X if (strncmp(arg, s, strlen(s)) == 0) /* matched full name */ X break; X s = params[i].shortname; X if (strncmp(arg, s, strlen(s)) == 0) /* matched short name */ X break; X } X X if (params[i].fullname[0] != NUL) { /* found a match */ X if (params[i].flags & P_NUM) { X did_lines = (i == P_LI); X if (inter && (arg[strlen(s)] != '=' || state == FALSE)) X emsg("Invalid set of numeric parameter"); X else { X params[i].value = atoi(arg+strlen(s)+1); X params[i].flags |= P_CHANGED; X } X } else /* boolean */ { X if (inter && (arg[strlen(s)] == '=')) X emsg("Invalid set of boolean parameter"); X else { X params[i].value = state; X params[i].flags |= P_CHANGED; X } X } X } else { X if (inter) X emsg("Unrecognized 'set' option"); X } X X /* X * Update the screen in case we changed something like "tabstop" X * or "list" that will change its appearance. X */ X if (inter) X updatescreen(); X X if (did_lines) { X Rows = P(P_LI); X screenalloc(); /* allocate new screen buffers */ X screenclear(); X updatescreen(); X } X /* X * Check the bounds for numeric parameters here X */ X if (P(P_TS) <= 0 || P(P_TS) > 32) { X if (inter) X emsg("Invalid tab size specified"); X P(P_TS) = 8; X return; X } X X if (P(P_SS) <= 0 || P(P_SS) > Rows) { X if (inter) X emsg("Invalid scroll size specified"); X P(P_SS) = 12; X return; X } X X /* X * Check for another argument, and call doset() recursively, if X * found. If any argument results in an error, no further X * parameters are processed. X */ X while (*arg != ' ' && *arg != '\t') { /* skip to next white space */ X if (*arg == NUL) X return; /* end of parameter list */ X arg++; X } X while (*arg == ' ' || *arg == '\t') /* skip to next non-white */ X arg++; X X if (*arg) X doset(arg, inter); /* recurse on next parameter */ X} X Xstatic void Xshowparms(all) Xbool_t all; /* show ALL parameters */ X{ X struct param *p; X char buf[64]; X X gotocmd(TRUE, 0); X outstr("Parameters:\r\n"); X X for (p = ¶ms[0]; p->fullname[0] != NUL ;p++) { X if (!all && ((p->flags & P_CHANGED) == 0)) X continue; X if (p->flags & P_BOOL) X sprintf(buf, "\t%s%s\r\n", X (p->value ? "" : "no"), p->fullname); X else X sprintf(buf, "\t%s=%d\r\n", p->fullname, p->value); X X outstr(buf); X } X wait_return(); X} END_OF_FILE if test 4470 -ne `wc -c <'param.c'`; then echo shar: \"'param.c'\" unpacked with wrong size! fi # end of 'param.c' fi if test -f 'param.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'param.h'\" else echo shar: Extracting \"'param.h'\" \(1897 characters\) sed "s/^X//" >'param.h' <<'END_OF_FILE' X/* X * $Header: param.h,v 1.5 88/11/10 08:57:56 tony Exp $ X * X * Settable parameters X * X * $Log: param.h,v $ X * Revision 1.5 88/11/10 08:57:56 tony X * Added a new parameter, modelines ("ml"), to support the modeline X * feature. X * X * Revision 1.4 88/05/01 20:08:29 tony X * Added the new boolean parameter "number" to turn on line numbering. X * X * Revision 1.3 88/04/30 20:00:42 tony X * Added the parameter "autoindent". X * X * Revision 1.2 88/04/28 08:06:48 tony X * Added a new parameter "ignorecase" which can be set to ignore case X * distinctions in string searches. X * X * Revision 1.1 88/03/20 21:04:50 tony X * Initial revision X * X * X */ X Xstruct param { X char *fullname; /* full parameter name */ X char *shortname; /* permissible abbreviation */ X int value; /* parameter value */ X int flags; X}; X Xextern struct param params[]; X X/* X * Flags X */ X#define P_BOOL 0x01 /* the parameter is boolean */ X#define P_NUM 0x02 /* the parameter is numeric */ X#define P_CHANGED 0x04 /* the parameter has been changed */ X X/* X * The following are the indices in the params array for each parameter X */ X X/* X * Numeric parameters X */ X#define P_TS 0 /* tab size */ X#define P_SS 1 /* scroll size */ X#define P_RP 2 /* report */ X#define P_LI 3 /* lines */ X X/* X * Boolean parameters X */ X#define P_VB 4 /* visual bell */ X#define P_SM 5 /* showmatch */ X#define P_WS 6 /* wrap scan */ X#define P_EB 7 /* error bells */ X#define P_MO 8 /* show mode */ X#define P_BK 9 /* make backups when writing out files */ X#define P_CR 10 /* use cr-lf to terminate lines on writes */ X#define P_LS 11 /* show tabs and newlines graphically */ X#define P_IC 12 /* ignore case in searches */ X#define P_AI 13 /* auto-indent */ X#define P_NU 14 /* number lines on the screen */ X#define P_ML 15 /* enables mode-lines processing */ X X/* X * Macro to get the value of a parameter X */ X#define P(n) (params[n].value) END_OF_FILE if test 1897 -ne `wc -c <'param.h'`; then echo shar: \"'param.h'\" unpacked with wrong size! fi # end of 'param.h' fi if test -f 'ptrfunc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ptrfunc.c'\" else echo shar: Extracting \"'ptrfunc.c'\" \(3242 characters\) sed "s/^X//" >'ptrfunc.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: ptrfunc.c,v 1.4 88/10/27 08:14:11 tony Exp $"; X X/* X * The routines in this file attempt to imitate many of the operations X * that used to be performed on simple character pointers and are now X * performed on LPTR's. This makes it easier to modify other sections X * of the code. Think of an LPTR as representing a position in the file. X * Positions can be incremented, decremented, compared, etc. through X * the functions implemented here. X * X * $Log: ptrfunc.c,v $ X * Revision 1.4 88/10/27 08:14:11 tony X * Made some of the pointer operations less sensitive to the possibility X * of null pointers. X * X * Revision 1.3 88/08/26 08:45:40 tony X * Misc. changes to make lint happy. X * X * Revision 1.2 88/04/23 20:36:45 tony X * Fixed a bug in dec() that caused problems when decrementing at the start X * of the file. dec() now sticks at the start of the file. This caused X * problems when reverse searching from the first character of the file. X * X * Revision 1.1 88/03/20 21:09:55 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * inc(p) X * X * Increment the line pointer 'p' crossing line boundaries as necessary. X * Return 1 when crossing a line, -1 when at end of file, 0 otherwise. X */ Xint Xinc(lp) Xregister LPTR *lp; X{ X register char *p; X X if (lp && lp->linep) X p = &(lp->linep->s[lp->index]); X else X return -1; X X if (*p != NUL) { /* still within line */ X lp->index++; X return ((p[1] != NUL) ? 0 : 1); X } X X if (lp->linep->next != Fileend->linep) { /* there is a next line */ X lp->index = 0; X lp->linep = lp->linep->next; X return 1; X } X X return -1; X} X X/* X * dec(p) X * X * Decrement the line pointer 'p' crossing line boundaries as necessary. X * Return 1 when crossing a line, -1 when at start of file, 0 otherwise. X */ Xint Xdec(lp) Xregister LPTR *lp; X{ X if (lp->index > 0) { /* still within line */ X lp->index--; X return 0; X } X X if (lp->linep->prev != Filetop->linep) { /* there is a prior line */ X lp->linep = lp->linep->prev; X lp->index = strlen(lp->linep->s); X return 1; X } X X lp->index = 0; /* stick at first char */ X return -1; /* at start of file */ X} X X/* X * gchar(lp) - get the character at position "lp" X */ Xint Xgchar(lp) Xregister LPTR *lp; X{ X if (lp && lp->linep) X return (lp->linep->s[lp->index]); X else X return 0; X} X X/* X * pchar(lp, c) - put character 'c' at position 'lp' X */ Xvoid Xpchar(lp, c) Xregister LPTR *lp; Xchar c; X{ X lp->linep->s[lp->index] = c; X} X X/* X * pswap(a, b) - swap two position pointers X */ Xvoid Xpswap(a, b) Xregister LPTR *a, *b; X{ X LPTR tmp; X X tmp = *a; X *a = *b; X *b = tmp; X} X X/* X * Position comparisons X */ X Xbool_t Xlt(a, b) Xregister LPTR *a, *b; X{ X register int an, bn; X X an = LINEOF(a); X bn = LINEOF(b); X X if (an != bn) X return (an < bn); X else X return (a->index < b->index); X} X X#if 0 Xbool_t Xgt(a, b) XLPTR *a, *b; X{ X register int an, bn; X X an = LINEOF(a); X bn = LINEOF(b); X X if (an != bn) X return (an > bn); X else X return (a->index > b->index); X} X#endif X Xbool_t Xequal(a, b) Xregister LPTR *a, *b; X{ X return (a->linep == b->linep && a->index == b->index); X} X Xbool_t Xltoreq(a, b) Xregister LPTR *a, *b; X{ X return (lt(a, b) || equal(a, b)); X} X X#if 0 Xbool_t Xgtoreq(a, b) XLPTR *a, *b; X{ X return (gt(a, b) || equal(a, b)); X} X#endif END_OF_FILE if test 3242 -ne `wc -c <'ptrfunc.c'`; then echo shar: \"'ptrfunc.c'\" unpacked with wrong size! fi # end of 'ptrfunc.c' fi if test -f 'readme' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'readme'\" else echo shar: Extracting \"'readme'\" \(1667 characters\) sed "s/^X//" >'readme' <<'END_OF_FILE' XSTEVIE Source Release - 3.26 X XThis is a source release of the STEVIE editor, a public domain clone Xof the UNIX editor 'vi'. The program was originally developed for the XAtari ST, but has been ported to UNIX and OS/2 as well. X XParts of the editor are still badly in need of improvement, but it's Xreached a pretty usable state overall. I'm not going to have much time Xto work on it over the next couple of months, so I'll just release it Xas is. The 'undo' facility is in pretty good shape, but yanks and puts Xstill need some work. The current code there is rather limited and slow. X XThe files included in this release are: X Xreadme X This file. X Xstevie.doc X Reference manual for STEVIE. Assumes familiarity with vi. X Xsource.doc X Quick overview of the major data structures used. X Xporting.doc X Tips for porting STEVIE to other systems. X Xmakefile.os2 Xmakefile.usg Xmakefile.tos X Makefiles for OS/2, UNIX System V, and the Atari ST respectively. X Xos2.c Xunix.c Xtos.c Xenv.h Xterm.h X System-dependent code for the same. X Xalloc.c ascii.h cmdline.c edit.c fileio.c help.c hexchars.c Xkeymap.h linefunc.c main.c mark.c misccmds.c normal.c param.c Xparam.h ptrfunc.c screen.c search.c stevie.h undo.c version.c X X C source and header files for STEVIE. X Xctags.doc X Documentation for the accompanying program 'ctags'. X Xctags.c X Source code for the program 'ctags'. X X XTo compile STEVIE for one of the provided systems: X X 1. Compile the regular expression library and install as X appropriate for your system. X X 2. Edit the file 'env.h' to set the system defines as needed. X X 3. Check the makefile for your system, and modify as needed. X X 4. Compile. X XGood Luck... X XTony Andrews X3/27/88 X END_OF_FILE if test 1667 -ne `wc -c <'readme'`; then echo shar: \"'readme'\" unpacked with wrong size! fi # end of 'readme' fi if test -f 'regexp.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'regexp.c'\" else echo shar: Extracting \"'regexp.c'\" \(29650 characters\) sed "s/^X//" >'regexp.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: regexp.c,v 1.3 88/10/27 08:12:32 tony Exp $"; X X/* X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * This is NOT the original regular expression code as written by X * Henry Spencer. This code has been modified specifically for use X * with the STEVIE editor, and should not be used apart from compiling X * STEVIE. If you want a good regular expression library, get the X * original code. The copyright notice that follows is from the X * original. X * X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * X * regcomp and regexec -- regsub and regerror are elsewhere X * X * Copyright (c) 1986 by University of Toronto. X * Written by Henry Spencer. Not derived from licensed software. X * X * Permission is granted to anyone to use this software for any X * purpose on any computer system, and to redistribute it freely, X * subject to the following restrictions: X * X * 1. The author is not responsible for the consequences of use of X * this software, no matter how awful, even if they arise X * from defects in it. X * X * 2. The origin of this software must not be misrepresented, either X * by explicit claim or by omission. X * X * 3. Altered versions must be plainly marked as such, and must not X * be misrepresented as being the original software. X * X * Beware that some of this code is subtly aware of the way operator X * precedence is structured in regular expressions. Serious changes in X * regular-expression syntax might require a total rethink. X * X * $Log: regexp.c,v $ X * Revision 1.3 88/10/27 08:12:32 tony X * Removed support for Megamax. X * X * Revision 1.2 88/04/28 08:09:45 tony X * First modification of the regexp library. Added an external variable X * 'reg_ic' which can be set to indicate that case should be ignored. X * Added a new parameter to regexec() to indicate that the given string X * comes from the beginning of a line and is thus eligible to match X * 'beginning-of-line'. X * X */ X X#include "env.h" X X#include <stdio.h> X#include "regexp.h" X#include "regmagic.h" X X/* X * The "internal use only" fields in regexp.h are present to pass info from X * compile to execute that permits the execute phase to run lots faster on X * simple cases. They are: X * X * regstart char that must begin a match; '\0' if none obvious X * reganch is the match anchored (at beginning-of-line only)? X * regmust string (pointer into program) that match must include, or NULL X * regmlen length of regmust string X * X * Regstart and reganch permit very fast decisions on suitable starting points X * for a match, cutting down the work a lot. Regmust permits fast rejection X * of lines that cannot possibly match. The regmust tests are costly enough X * that regcomp() supplies a regmust only if the r.e. contains something X * potentially expensive (at present, the only such thing detected is * or + X * at the start of the r.e., which can involve a lot of backup). Regmlen is X * supplied because the test in regexec() needs it and regcomp() is computing X * it anyway. X */ X X/* X * Structure for regexp "program". This is essentially a linear encoding X * of a nondeterministic finite-state machine (aka syntax charts or X * "railroad normal form" in parsing technology). Each node is an opcode X * plus a "next" pointer, possibly plus an operand. "Next" pointers of X * all nodes except BRANCH implement concatenation; a "next" pointer with X * a BRANCH on both ends of it is connecting two alternatives. (Here we X * have one of the subtle syntax dependencies: an individual BRANCH (as X * opposed to a collection of them) is never concatenated with anything X * because of operator precedence.) The operand of some types of node is X * a literal string; for others, it is a node leading into a sub-FSM. In X * particular, the operand of a BRANCH node is the first node of the branch. X * (NB this is *not* a tree structure: the tail of the branch connects X * to the thing following the set of BRANCHes.) The opcodes are: X */ X X/* definition number opnd? meaning */ X#define END 0 /* no End of program. */ X#define BOL 1 /* no Match "" at beginning of line. */ X#define EOL 2 /* no Match "" at end of line. */ X#define ANY 3 /* no Match any one character. */ X#define ANYOF 4 /* str Match any character in this string. */ X#define ANYBUT 5 /* str Match any character not in this string. */ X#define BRANCH 6 /* node Match this alternative, or the next... */ X#define BACK 7 /* no Match "", "next" ptr points backward. */ X#define EXACTLY 8 /* str Match this string. */ X#define NOTHING 9 /* no Match empty string. */ X#define STAR 10 /* node Match this (simple) thing 0 or more times. */ X#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ X#define OPEN 20 /* no Mark this point in input as start of #n. */ X /* OPEN+1 is number 1, etc. */ X#define CLOSE 30 /* no Analogous to OPEN. */ X X/* X * Opcode notes: X * X * BRANCH The set of branches constituting a single choice are hooked X * together with their "next" pointers, since precedence prevents X * anything being concatenated to any individual branch. The X * "next" pointer of the last BRANCH in a choice points to the X * thing following the whole choice. This is also where the X * final "next" pointer of each individual branch points; each X * branch starts with the operand node of a BRANCH node. X * X * BACK Normal "next" pointers all implicitly point forward; BACK X * exists to make loop structures possible. X * X * STAR,PLUS '?', and complex '*' and '+', are implemented as circular X * BRANCH structures using BACK. Simple cases (one character X * per match) are implemented with STAR and PLUS for speed X * and to minimize recursive plunges. X * X * OPEN,CLOSE ...are numbered at compile time. X */ X X/* X * A node is one char of opcode followed by two chars of "next" pointer. X * "Next" pointers are stored as two 8-bit pieces, high order first. The X * value is a positive offset from the opcode of the node containing it. X * An operand, if any, simply follows the node. (Note that much of the X * code generation knows about this implicit relationship.) X * X * Using two bytes for the "next" pointer is vast overkill for most things, X * but allows patterns to get big without disasters. X */ X#define OP(p) (*(p)) X#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) X#define OPERAND(p) ((p) + 3) X X/* X * See regmagic.h for one further detail of program structure. X */ X X X/* X * Utility definitions. X */ X#ifndef CHARBITS X#define UCHARAT(p) ((int)*(unsigned char *)(p)) X#else X#define UCHARAT(p) ((int)*(p)&CHARBITS) X#endif X X#define FAIL(m) { regerror(m); return(NULL); } X#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') X#define META "^$.[()|?+*\\" X X/* X * Flags to be passed up and down. X */ X#define HASWIDTH 01 /* Known never to match null string. */ X#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ X#define SPSTART 04 /* Starts with * or +. */ X#define WORST 0 /* Worst case. */ X X#ifndef ORIGINAL X/* X * The following supports the ability to ignore case in searches. X */ X X#include <ctype.h> X Xint reg_ic = 0; /* set by callers to ignore case */ X X/* X * mkup - convert to upper case IF we're doing caseless compares X */ X#define mkup(c) ((islower(c) && reg_ic) ? toupper(c) : (c)) X X#endif X X/* X * Global work variables for regcomp(). X */ Xstatic char *regparse; /* Input-scan pointer. */ Xstatic int regnpar; /* () count. */ Xstatic char regdummy; Xstatic char *regcode; /* Code-emit pointer; ®dummy = don't. */ Xstatic long regsize; /* Code size. */ X X/* X * Forward declarations for regcomp()'s friends. X */ X#ifndef STATIC X#define STATIC static X#endif XSTATIC char *reg(); XSTATIC char *regbranch(); XSTATIC char *regpiece(); XSTATIC char *regatom(); XSTATIC char *regnode(); XSTATIC char *regnext(); XSTATIC void regc(); XSTATIC void reginsert(); XSTATIC void regtail(); XSTATIC void regoptail(); X#ifdef STRCSPN XSTATIC int strcspn(); X#endif X X/* X - regcomp - compile a regular expression into internal code X * X * We can't allocate space until we know how big the compiled form will be, X * but we can't compile it (and thus know how big it is) until we've got a X * place to put the code. So we cheat: we compile it twice, once with code X * generation turned off and size counting turned on, and once "for real". X * This also means that we don't allocate space until we are sure that the X * thing really will compile successfully, and we never have to move the X * code and thus invalidate pointers into it. (Note that it has to be in X * one piece because free() must be able to free it all.) X * X * Beware that the optimization-preparation code in here knows about some X * of the structure of the compiled regexp. X */ Xregexp * Xregcomp(exp) Xchar *exp; X{ X register regexp *r; X register char *scan; X register char *longest; X register int len; X int flags; X extern char *malloc(); X X if (exp == NULL) X FAIL("NULL argument"); X X /* First pass: determine size, legality. */ X regparse = exp; X regnpar = 1; X regsize = 0L; X regcode = ®dummy; X regc(MAGIC); X if (reg(0, &flags) == NULL) X return(NULL); X X /* Small enough for pointer-storage convention? */ X if (regsize >= 32767L) /* Probably could be 65535L. */ X FAIL("regexp too big"); X X /* Allocate space. */ X r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); X if (r == NULL) X FAIL("out of space"); X X /* Second pass: emit code. */ X regparse = exp; X regnpar = 1; X regcode = r->program; X regc(MAGIC); X if (reg(0, &flags) == NULL) X return(NULL); X X /* Dig out information for optimizations. */ X r->regstart = '\0'; /* Worst-case defaults. */ X r->reganch = 0; X r->regmust = NULL; X r->regmlen = 0; X scan = r->program+1; /* First BRANCH. */ X if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ X scan = OPERAND(scan); X X /* Starting-point info. */ X if (OP(scan) == EXACTLY) X r->regstart = *OPERAND(scan); X else if (OP(scan) == BOL) X r->reganch++; X X /* X * If there's something expensive in the r.e., find the X * longest literal string that must appear and make it the X * regmust. Resolve ties in favor of later strings, since X * the regstart check works with the beginning of the r.e. X * and avoiding duplication strengthens checking. Not a X * strong reason, but sufficient in the absence of others. X */ X if (flags&SPSTART) { X longest = NULL; X len = 0; X for (; scan != NULL; scan = regnext(scan)) X if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { X longest = OPERAND(scan); X len = strlen(OPERAND(scan)); X } X r->regmust = longest; X r->regmlen = len; X } X } X X return(r); X} X X/* X - reg - regular expression, i.e. main body or parenthesized thing X * X * Caller must absorb opening parenthesis. X * X * Combining parenthesis handling with the base level of regular expression X * is a trifle forced, but the need to tie the tails of the branches to what X * follows makes it hard to avoid. X */ Xstatic char * Xreg(paren, flagp) Xint paren; /* Parenthesized? */ Xint *flagp; X{ X register char *ret; X register char *br; X register char *ender; X register int parno; X int flags; X X *flagp = HASWIDTH; /* Tentatively. */ X X /* Make an OPEN node, if parenthesized. */ X if (paren) { X if (regnpar >= NSUBEXP) X FAIL("too many ()"); X parno = regnpar; X regnpar++; X ret = regnode(OPEN+parno); X } else X ret = NULL; X X /* Pick up the branches, linking them together. */ X br = regbranch(&flags); X if (br == NULL) X return(NULL); X if (ret != NULL) X regtail(ret, br); /* OPEN -> first. */ X else X ret = br; X if (!(flags&HASWIDTH)) X *flagp &= ~HASWIDTH; X *flagp |= flags&SPSTART; X while (*regparse == '|') { X regparse++; X br = regbranch(&flags); X if (br == NULL) X return(NULL); X regtail(ret, br); /* BRANCH -> BRANCH. */ X if (!(flags&HASWIDTH)) X *flagp &= ~HASWIDTH; X *flagp |= flags&SPSTART; X } X X /* Make a closing node, and hook it on the end. */ X ender = regnode((paren) ? CLOSE+parno : END); X regtail(ret, ender); X X /* Hook the tails of the branches to the closing node. */ X for (br = ret; br != NULL; br = regnext(br)) X regoptail(br, ender); X X /* Check for proper termination. */ X if (paren && *regparse++ != ')') { X FAIL("unmatched ()"); X } else if (!paren && *regparse != '\0') { X if (*regparse == ')') { X FAIL("unmatched ()"); X } else X FAIL("junk on end"); /* "Can't happen". */ X /* NOTREACHED */ X } X X return(ret); X} X X/* X - regbranch - one alternative of an | operator X * X * Implements the concatenation operator. X */ Xstatic char * Xregbranch(flagp) Xint *flagp; X{ X register char *ret; X register char *chain; X register char *latest; X int flags; X X *flagp = WORST; /* Tentatively. */ X X ret = regnode(BRANCH); X chain = NULL; X while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { X latest = regpiece(&flags); X if (latest == NULL) X return(NULL); X *flagp |= flags&HASWIDTH; X if (chain == NULL) /* First piece. */ X *flagp |= flags&SPSTART; X else X regtail(chain, latest); X chain = latest; X } X if (chain == NULL) /* Loop ran zero times. */ X (void) regnode(NOTHING); X X return(ret); X} X X/* X - regpiece - something followed by possible [*+?] X * X * Note that the branching code sequences used for ? and the general cases X * of * and + are somewhat optimized: they use the same NOTHING node as X * both the endmarker for their branch list and the body of the last branch. X * It might seem that this node could be dispensed with entirely, but the X * endmarker role is not redundant. X */ Xstatic char * Xregpiece(flagp) Xint *flagp; X{ X register char *ret; X register char op; X register char *next; X int flags; X X ret = regatom(&flags); X if (ret == NULL) X return(NULL); X X op = *regparse; X if (!ISMULT(op)) { X *flagp = flags; X return(ret); X } X X if (!(flags&HASWIDTH) && op != '?') X FAIL("*+ operand could be empty"); X *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); X X if (op == '*' && (flags&SIMPLE)) X reginsert(STAR, ret); X else if (op == '*') { X /* Emit x* as (x&|), where & means "self". */ X reginsert(BRANCH, ret); /* Either x */ X regoptail(ret, regnode(BACK)); /* and loop */ X regoptail(ret, ret); /* back */ X regtail(ret, regnode(BRANCH)); /* or */ X regtail(ret, regnode(NOTHING)); /* null. */ X } else if (op == '+' && (flags&SIMPLE)) X reginsert(PLUS, ret); X else if (op == '+') { X /* Emit x+ as x(&|), where & means "self". */ X next = regnode(BRANCH); /* Either */ X regtail(ret, next); X regtail(regnode(BACK), ret); /* loop back */ X regtail(next, regnode(BRANCH)); /* or */ X regtail(ret, regnode(NOTHING)); /* null. */ X } else if (op == '?') { X /* Emit x? as (x|) */ X reginsert(BRANCH, ret); /* Either x */ X regtail(ret, regnode(BRANCH)); /* or */ X next = regnode(NOTHING); /* null. */ X regtail(ret, next); X regoptail(ret, next); X } X regparse++; X if (ISMULT(*regparse)) X FAIL("nested *?+"); X X return(ret); X} X X/* X - regatom - the lowest level X * X * Optimization: gobbles an entire sequence of ordinary characters so that X * it can turn them into a single node, which is smaller to store and X * faster to run. Backslashed characters are exceptions, each becoming a X * separate node; the code is simpler that way and it's not worth fixing. X */ Xstatic char * Xregatom(flagp) Xint *flagp; X{ X register char *ret; X int flags; X X *flagp = WORST; /* Tentatively. */ X X switch (*regparse++) { X case '^': X ret = regnode(BOL); X break; X case '$': X ret = regnode(EOL); X break; X case '.': X ret = regnode(ANY); X *flagp |= HASWIDTH|SIMPLE; X break; X case '[': { X register int class; X register int classend; X X if (*regparse == '^') { /* Complement of range. */ X ret = regnode(ANYBUT); X regparse++; X } else X ret = regnode(ANYOF); X if (*regparse == ']' || *regparse == '-') X regc(*regparse++); X while (*regparse != '\0' && *regparse != ']') { X if (*regparse == '-') { X regparse++; X if (*regparse == ']' || *regparse == '\0') X regc('-'); X else { X class = UCHARAT(regparse-2)+1; X classend = UCHARAT(regparse); X if (class > classend+1) X FAIL("invalid [] range"); X for (; class <= classend; class++) X regc(class); X regparse++; X } X } else X regc(*regparse++); X } X regc('\0'); X if (*regparse != ']') X FAIL("unmatched []"); X regparse++; X *flagp |= HASWIDTH|SIMPLE; X } X break; X case '(': X ret = reg(1, &flags); X if (ret == NULL) X return(NULL); X *flagp |= flags&(HASWIDTH|SPSTART); X break; X case '\0': X case '|': X case ')': X FAIL("internal urp"); /* Supposed to be caught earlier. */ X break; X case '?': X case '+': X case '*': X FAIL("?+* follows nothing"); X break; X case '\\': X if (*regparse == '\0') X FAIL("trailing \\"); X ret = regnode(EXACTLY); X regc(*regparse++); X regc('\0'); X *flagp |= HASWIDTH|SIMPLE; X break; X default: { X register int len; X register char ender; X X regparse--; X len = strcspn(regparse, META); X if (len <= 0) X FAIL("internal disaster"); X ender = *(regparse+len); X if (len > 1 && ISMULT(ender)) X len--; /* Back off clear of ?+* operand. */ X *flagp |= HASWIDTH; X if (len == 1) X *flagp |= SIMPLE; X ret = regnode(EXACTLY); X while (len > 0) { X regc(*regparse++); X len--; X } X regc('\0'); X } X break; X } X X return(ret); X} X X/* X - regnode - emit a node X */ Xstatic char * /* Location. */ Xregnode(op) Xchar op; X{ X register char *ret; X register char *ptr; X X ret = regcode; X if (ret == ®dummy) { X regsize += 3; X return(ret); X } X X ptr = ret; X *ptr++ = op; X *ptr++ = '\0'; /* Null "next" pointer. */ X *ptr++ = '\0'; X regcode = ptr; X X return(ret); X} X X/* X - regc - emit (if appropriate) a byte of code X */ Xstatic void Xregc(b) Xchar b; X{ X if (regcode != ®dummy) X *regcode++ = b; X else X regsize++; X} X X/* X - reginsert - insert an operator in front of already-emitted operand X * X * Means relocating the operand. X */ Xstatic void Xreginsert(op, opnd) Xchar op; Xchar *opnd; X{ X register char *src; X register char *dst; X register char *place; X X if (regcode == ®dummy) { X regsize += 3; X return; X } X X src = regcode; X regcode += 3; X dst = regcode; X while (src > opnd) X *--dst = *--src; X X place = opnd; /* Op node, where operand used to be. */ X *place++ = op; X *place++ = '\0'; X *place++ = '\0'; X} X X/* X - regtail - set the next-pointer at the end of a node chain X */ Xstatic void Xregtail(p, val) Xchar *p; Xchar *val; X{ X register char *scan; X register char *temp; X register int offset; X X if (p == ®dummy) X return; X X /* Find last node. */ X scan = p; X for (;;) { X temp = regnext(scan); X if (temp == NULL) X break; X scan = temp; X } X X if (OP(scan) == BACK) X offset = scan - val; X else X offset = val - scan; X *(scan+1) = (offset>>8)&0377; X *(scan+2) = offset&0377; X} X X/* X - regoptail - regtail on operand of first argument; nop if operandless X */ Xstatic void Xregoptail(p, val) Xchar *p; Xchar *val; X{ X /* "Operandless" and "op != BRANCH" are synonymous in practice. */ X if (p == NULL || p == ®dummy || OP(p) != BRANCH) X return; X regtail(OPERAND(p), val); X} X X/* X * regexec and friends X */ X X/* X * Global work variables for regexec(). X */ Xstatic char *reginput; /* String-input pointer. */ Xstatic char *regbol; /* Beginning of input, for ^ check. */ Xstatic char **regstartp; /* Pointer to startp array. */ Xstatic char **regendp; /* Ditto for endp. */ X X/* X * Forwards. X */ XSTATIC int regtry(); XSTATIC int regmatch(); XSTATIC int regrepeat(); X X#ifdef DEBUG Xint regnarrate = 0; Xvoid regdump(); XSTATIC char *regprop(); X#endif X X/* X - regexec - match a regexp against a string X */ Xint Xregexec(prog, string, at_bol) Xregister regexp *prog; Xregister char *string; Xint at_bol; X{ X register char *s; X extern char *cstrchr(); X X /* Be paranoid... */ X if (prog == NULL || string == NULL) { X regerror("NULL parameter"); X return(0); X } X X /* Check validity of program. */ X if (UCHARAT(prog->program) != MAGIC) { X regerror("corrupted program"); X return(0); X } X X /* If there is a "must appear" string, look for it. */ X if (prog->regmust != NULL) { X s = string; X while ((s = cstrchr(s, prog->regmust[0])) != NULL) { X if (cstrncmp(s, prog->regmust, prog->regmlen) == 0) X break; /* Found it. */ X s++; X } X if (s == NULL) /* Not present. */ X return(0); X } X X /* Mark beginning of line for ^ . */ X if (at_bol) X regbol = string; /* is possible to match bol */ X else X regbol = NULL; /* we aren't there, so don't match it */ X X /* Simplest case: anchored match need be tried only once. */ X if (prog->reganch) X return(regtry(prog, string)); X X /* Messy cases: unanchored match. */ X s = string; X if (prog->regstart != '\0') X /* We know what char it must start with. */ X while ((s = cstrchr(s, prog->regstart)) != NULL) { X if (regtry(prog, s)) X return(1); X s++; X } X else X /* We don't -- general case. */ X do { X if (regtry(prog, s)) X return(1); X } while (*s++ != '\0'); X X /* Failure. */ X return(0); X} X X/* X - regtry - try match at specific point X */ Xstatic int /* 0 failure, 1 success */ Xregtry(prog, string) Xregexp *prog; Xchar *string; X{ X register int i; X register char **sp; X register char **ep; X X reginput = string; X regstartp = prog->startp; X regendp = prog->endp; X X sp = prog->startp; X ep = prog->endp; X for (i = NSUBEXP; i > 0; i--) { X *sp++ = NULL; X *ep++ = NULL; X } X if (regmatch(prog->program + 1)) { X prog->startp[0] = string; X prog->endp[0] = reginput; X return(1); X } else X return(0); X} X X/* X - regmatch - main matching routine X * X * Conceptually the strategy is simple: check to see whether the current X * node matches, call self recursively to see whether the rest matches, X * and then act accordingly. In practice we make some effort to avoid X * recursion, in particular by going through "ordinary" nodes (that don't X * need to know whether the rest of the match failed) by a loop instead of X * by recursion. X */ Xstatic int /* 0 failure, 1 success */ Xregmatch(prog) Xchar *prog; X{ X register char *scan; /* Current node. */ X char *next; /* Next node. */ X extern char *strchr(); X X scan = prog; X#ifdef DEBUG X if (scan != NULL && regnarrate) X fprintf(stderr, "%s(\n", regprop(scan)); X#endif X while (scan != NULL) { X#ifdef DEBUG X if (regnarrate) X fprintf(stderr, "%s...\n", regprop(scan)); X#endif X next = regnext(scan); X X switch (OP(scan)) { X case BOL: X if (reginput != regbol) X return(0); X break; X case EOL: X if (*reginput != '\0') X return(0); X break; X case ANY: X if (*reginput == '\0') X return(0); X reginput++; X break; X case EXACTLY: { X register int len; X register char *opnd; X X opnd = OPERAND(scan); X /* Inline the first character, for speed. */ X if (mkup(*opnd) != mkup(*reginput)) X return(0); X len = strlen(opnd); X if (len > 1 && cstrncmp(opnd,reginput,len) != 0) X return(0); X reginput += len; X } X break; X case ANYOF: X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) X return(0); X reginput++; X break; X case ANYBUT: X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) X return(0); X reginput++; X break; X case NOTHING: X break; X case BACK: X break; X case OPEN+1: X case OPEN+2: X case OPEN+3: X case OPEN+4: X case OPEN+5: X case OPEN+6: X case OPEN+7: X case OPEN+8: X case OPEN+9: { X register int no; X register char *save; X X no = OP(scan) - OPEN; X save = reginput; X X if (regmatch(next)) { X /* X * Don't set startp if some later X * invocation of the same parentheses X * already has. X */ X if (regstartp[no] == NULL) X regstartp[no] = save; X return(1); X } else X return(0); X } X break; X case CLOSE+1: X case CLOSE+2: X case CLOSE+3: X case CLOSE+4: X case CLOSE+5: X case CLOSE+6: X case CLOSE+7: X case CLOSE+8: X case CLOSE+9: { X register int no; X register char *save; X X no = OP(scan) - CLOSE; X save = reginput; X X if (regmatch(next)) { X /* X * Don't set endp if some later X * invocation of the same parentheses X * already has. X */ X if (regendp[no] == NULL) X regendp[no] = save; X return(1); X } else X return(0); X } X break; X case BRANCH: { X register char *save; X X if (OP(next) != BRANCH) /* No choice. */ X next = OPERAND(scan); /* Avoid recursion. */ X else { X do { X save = reginput; X if (regmatch(OPERAND(scan))) X return(1); X reginput = save; X scan = regnext(scan); X } while (scan != NULL && OP(scan) == BRANCH); X return(0); X /* NOTREACHED */ X } X } X break; X case STAR: X case PLUS: { X register char nextch; X register int no; X register char *save; X register int min; X X /* X * Lookahead to avoid useless match attempts X * when we know what character comes next. X */ X nextch = '\0'; X if (OP(next) == EXACTLY) X nextch = *OPERAND(next); X min = (OP(scan) == STAR) ? 0 : 1; X save = reginput; X no = regrepeat(OPERAND(scan)); X while (no >= min) { X /* If it could work, try it. */ X if (nextch == '\0' || *reginput == nextch) X if (regmatch(next)) X return(1); X /* Couldn't or didn't -- back up. */ X no--; X reginput = save + no; X } X return(0); X } X break; X case END: X return(1); /* Success! */ X break; X default: X regerror("memory corruption"); X return(0); X break; X } X X scan = next; X } X X /* X * We get here only if there's trouble -- normally "case END" is X * the terminating point. X */ X regerror("corrupted pointers"); X return(0); X} X X/* X - regrepeat - repeatedly match something simple, report how many X */ Xstatic int Xregrepeat(p) Xchar *p; X{ X register int count = 0; X register char *scan; X register char *opnd; X X scan = reginput; X opnd = OPERAND(p); X switch (OP(p)) { X case ANY: X count = strlen(scan); X scan += count; X break; X case EXACTLY: X while (mkup(*opnd) == mkup(*scan)) { X count++; X scan++; X } X break; X case ANYOF: X while (*scan != '\0' && strchr(opnd, *scan) != NULL) { X count++; X scan++; X } X break; X case ANYBUT: X while (*scan != '\0' && strchr(opnd, *scan) == NULL) { X count++; X scan++; X } X break; X default: /* Oh dear. Called inappropriately. */ X regerror("internal foulup"); X count = 0; /* Best compromise. */ X break; X } X reginput = scan; X X return(count); X} X X/* X - regnext - dig the "next" pointer out of a node X */ Xstatic char * Xregnext(p) Xregister char *p; X{ X register int offset; X X if (p == ®dummy) X return(NULL); X X offset = NEXT(p); X if (offset == 0) X return(NULL); X X if (OP(p) == BACK) X return(p-offset); X else X return(p+offset); X} X X#ifdef DEBUG X XSTATIC char *regprop(); X X/* X - regdump - dump a regexp onto stdout in vaguely comprehensible form X */ Xvoid Xregdump(r) Xregexp *r; X{ X register char *s; X register char op = EXACTLY; /* Arbitrary non-END op. */ X register char *next; X extern char *strchr(); X X X s = r->program + 1; X while (op != END) { /* While that wasn't END last time... */ X op = OP(s); X printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ X next = regnext(s); X if (next == NULL) /* Next ptr. */ X printf("(0)"); X else X printf("(%d)", (s-r->program)+(next-s)); X s += 3; X if (op == ANYOF || op == ANYBUT || op == EXACTLY) { X /* Literal string, where present. */ X while (*s != '\0') { X putchar(*s); X s++; X } X s++; X } X putchar('\n'); X } X X /* Header fields of interest. */ X if (r->regstart != '\0') X printf("start `%c' ", r->regstart); X if (r->reganch) X printf("anchored "); X if (r->regmust != NULL) X printf("must have \"%s\"", r->regmust); X printf("\n"); X} X X/* X - regprop - printable representation of opcode X */ Xstatic char * Xregprop(op) Xchar *op; X{ X register char *p; X static char buf[50]; X X (void) strcpy(buf, ":"); X X switch (OP(op)) { X case BOL: X p = "BOL"; X break; X case EOL: X p = "EOL"; X break; X case ANY: X p = "ANY"; X break; X case ANYOF: X p = "ANYOF"; X break; X case ANYBUT: X p = "ANYBUT"; X break; X case BRANCH: X p = "BRANCH"; X break; X case EXACTLY: X p = "EXACTLY"; X break; X case NOTHING: X p = "NOTHING"; X break; X case BACK: X p = "BACK"; X break; X case END: X p = "END"; X break; X case OPEN+1: X case OPEN+2: X case OPEN+3: X case OPEN+4: X case OPEN+5: X case OPEN+6: X case OPEN+7: X case OPEN+8: X case OPEN+9: X sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN); X p = NULL; X break; X case CLOSE+1: X case CLOSE+2: X case CLOSE+3: X case CLOSE+4: X case CLOSE+5: X case CLOSE+6: X case CLOSE+7: X case CLOSE+8: X case CLOSE+9: X sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE); X p = NULL; X break; X case STAR: X p = "STAR"; X break; X case PLUS: X p = "PLUS"; X break; X default: X regerror("corrupted opcode"); X break; X } X if (p != NULL) X (void) strcat(buf, p); X return(buf); X} X#endif X X/* X * The following is provided for those people who do not have strcspn() in X * their C libraries. They should get off their butts and do something X * about it; at least one public-domain implementation of those (highly X * useful) string routines has been published on Usenet. X */ X#ifdef STRCSPN X/* X * strcspn - find length of initial segment of s1 consisting entirely X * of characters not from s2 X */ X Xstatic int Xstrcspn(s1, s2) Xchar *s1; Xchar *s2; X{ X register char *scan1; X register char *scan2; X register int count; X X count = 0; X for (scan1 = s1; *scan1 != '\0'; scan1++) { X for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ X if (*scan1 == *scan2++) X return(count); X count++; X } X return(count); X} X#endif X Xint Xcstrncmp(s1, s2, n) Xchar *s1, *s2; Xint n; X{ X char *p, *S1, *S2, *strsave(); X int rval; X X if (!reg_ic) X return (strncmp(s1, s2, n)); X X S1 = strsave(s1); X S2 = strsave(s2); X X for (p = S1; *p ;p++) X if (islower(*p)) X *p = toupper(*p); X X for (p = S2; *p ;p++) X if (islower(*p)) X *p = toupper(*p); X X rval = strncmp(S1, S2, n); X X free(S1); X free(S2); X X return rval; X} X Xchar * Xcstrchr(s, c) Xchar *s; Xchar c; X{ X char *p; X X for (p = s; *p ;p++) { X if (mkup(*p) == mkup(c)) X return p; X } X return NULL; X} END_OF_FILE if test 29650 -ne `wc -c <'regexp.c'`; then echo shar: \"'regexp.c'\" unpacked with wrong size! fi # end of 'regexp.c' fi if test -f 'regexp.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'regexp.h'\" else echo shar: Extracting \"'regexp.h'\" \(1167 characters\) sed "s/^X//" >'regexp.h' <<'END_OF_FILE' X/* X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * This is NOT the original regular expression code as written by X * Henry Spencer. This code has been modified specifically for use X * with the STEVIE editor, and should not be used apart from compiling X * STEVIE. If you want a good regular expression library, get the X * original code. The copyright notice that follows is from the X * original. X * X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * Definitions etc. for regexp(3) routines. X * X * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], X * not the System V one. X */ X#define NSUBEXP 10 Xtypedef struct regexp { X char *startp[NSUBEXP]; X char *endp[NSUBEXP]; X char regstart; /* Internal use only. */ X char reganch; /* Internal use only. */ X char *regmust; /* Internal use only. */ X int regmlen; /* Internal use only. */ X char program[1]; /* Unwarranted chumminess with compiler. */ X} regexp; X Xextern regexp *regcomp(); Xextern int regexec(); Xextern void regsub(); Xextern void regerror(); X X#ifndef ORIGINAL Xextern int reg_ic; /* set non-zero to ignore case in searches */ X#endif END_OF_FILE if test 1167 -ne `wc -c <'regexp.h'`; then echo shar: \"'regexp.h'\" unpacked with wrong size! fi # end of 'regexp.h' fi if test -f 'regmagic.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'regmagic.h'\" else echo shar: Extracting \"'regmagic.h'\" \(655 characters\) sed "s/^X//" >'regmagic.h' <<'END_OF_FILE' X/* X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * This is NOT the original regular expression code as written by X * Henry Spencer. This code has been modified specifically for use X * with the STEVIE editor, and should not be used apart from compiling X * STEVIE. If you want a good regular expression library, get the X * original code. The copyright notice that follows is from the X * original. X * X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * The first byte of the regexp internal "program" is actually this magic X * number; the start node begins in the second byte. X */ X#define MAGIC 0234 END_OF_FILE if test 655 -ne `wc -c <'regmagic.h'`; then echo shar: \"'regmagic.h'\" unpacked with wrong size! fi # end of 'regmagic.h' fi if test -f 'regsub.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'regsub.c'\" else echo shar: Extracting \"'regsub.c'\" \(2999 characters\) sed "s/^X//" >'regsub.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: regsub.c,v 1.3 88/10/27 08:13:03 tony Exp $"; X X/* X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * This is NOT the original regular expression code as written by X * Henry Spencer. This code has been modified specifically for use X * with the STEVIE editor, and should not be used apart from compiling X * STEVIE. If you want a good regular expression library, get the X * original code. The copyright notice that follows is from the X * original. X * X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE X * X * regsub X * X * Copyright (c) 1986 by University of Toronto. X * Written by Henry Spencer. Not derived from licensed software. X * X * Permission is granted to anyone to use this software for any X * purpose on any computer system, and to redistribute it freely, X * subject to the following restrictions: X * X * 1. The author is not responsible for the consequences of use of X * this software, no matter how awful, even if they arise X * from defects in it. X * X * 2. The origin of this software must not be misrepresented, either X * by explicit claim or by omission. X * X * 3. Altered versions must be plainly marked as such, and must not X * be misrepresented as being the original software. X * X * $Log: regsub.c,v $ X * Revision 1.3 88/10/27 08:13:03 tony X * Removed support for Megamax. X * X * Revision 1.2 88/04/28 08:11:25 tony X * First modification of the regexp library. Added an external variable X * 'reg_ic' which can be set to indicate that case should be ignored. X * Added a new parameter to regexec() to indicate that the given string X * comes from the beginning of a line and is thus eligible to match X * 'beginning-of-line'. X * X */ X X#include <stdio.h> X#include "regexp.h" X#include "regmagic.h" X X#ifndef CHARBITS X#define UCHARAT(p) ((int)*(unsigned char *)(p)) X#else X#define UCHARAT(p) ((int)*(p)&CHARBITS) X#endif X X/* X - regsub - perform substitutions after a regexp match X */ Xvoid Xregsub(prog, source, dest) Xregexp *prog; Xchar *source; Xchar *dest; X{ X register char *src; X register char *dst; X register char c; X register int no; X register int len; X extern char *strncpy(); X X if (prog == NULL || source == NULL || dest == NULL) { X regerror("NULL parm to regsub"); X return; X } X if (UCHARAT(prog->program) != MAGIC) { X regerror("damaged regexp fed to regsub"); X return; X } X X src = source; X dst = dest; X while ((c = *src++) != '\0') { X if (c == '&') X no = 0; X else if (c == '\\' && '0' <= *src && *src <= '9') X no = *src++ - '0'; X else X no = -1; X if (no < 0) { /* Ordinary character. */ X if (c == '\\' && (*src == '\\' || *src == '&')) X c = *src++; X *dst++ = c; X } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { X len = prog->endp[no] - prog->startp[no]; X (void) strncpy(dst, prog->startp[no], len); X dst += len; X if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ X regerror("damaged match string"); X return; X } X } X } X *dst++ = '\0'; X} END_OF_FILE if test 2999 -ne `wc -c <'regsub.c'`; then echo shar: \"'regsub.c'\" unpacked with wrong size! fi # end of 'regsub.c' fi if test -f 'screen.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'screen.c'\" else echo shar: Extracting \"'screen.c'\" \(16090 characters\) sed "s/^X//" >'screen.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: screen.c,v 1.4 88/08/26 08:45:43 tony Exp $"; X X/* X * Routines to manipulate the screen representations. X * X * $Log: screen.c,v $ X * Revision 1.4 88/08/26 08:45:43 tony X * Misc. changes to make lint happy. X * X * Revision 1.3 88/06/26 14:50:59 tony X * Added a new routine prt_line() to just dump a line of text, handling X * control characters, etc. appropriately. X * X * Revision 1.2 88/05/01 20:09:39 tony X * Added support for the new "number" parameter. X * X * Revision 1.1 88/03/20 21:10:21 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * The following variable is set (in filetonext) to the number of physical X * lines taken by the line the cursor is on. We use this to avoid extra X * calls to plines(). The optimized routines lfiletonext() and lnexttoscreen() X * make sure that the size of the cursor line hasn't changed. If so, lines X * below the cursor will move up or down and we need to call the routines X * filetonext() and nexttoscreen() to examine the entire screen. X */ Xstatic int Cline_size; /* size (in rows) of the cursor line */ Xstatic int Cline_row; /* starting row of the cursor line */ X Xstatic char *mkline(); /* calculate line string for "number" mode */ X X/* X * filetonext() X * X * Based on the current value of Topchar, transfer a screenfull of X * stuff from Filemem to Nextscreen, and update Botchar. X */ X Xstatic void Xfiletonext() X{ X register int row, col; X register char *screenp = Nextscreen; X LPTR memp; X LPTR save; /* save pos. in case line won't fit */ X register char *endscreen; X register char *nextrow; X char extra[16]; X int nextra = 0; X register int c; X int n; X bool_t done; /* if TRUE, we hit the end of the file */ X bool_t didline; /* if TRUE, we finished the last line */ X int srow; /* starting row of the current line */ X int lno; /* number of the line we're doing */ X int coff; /* column offset */ X X coff = P(P_NU) ? 8 : 0; X X save = memp = *Topchar; X X if (P(P_NU)) X lno = cntllines(Filemem, Topchar); X X /* The number of rows shown is Rows-1. */ X /* The last line is the status/command line. */ X endscreen = &screenp[(Rows-1)*Columns]; X X done = didline = FALSE; X srow = row = col = 0; X /* X * We go one past the end of the screen so we can find out if the X * last line fit on the screen or not. X */ X while ( screenp <= endscreen && !done) { X X X if (P(P_NU) && col == 0 && memp.index == 0) { X strcpy(extra, mkline(lno++)); X nextra = 8; X } X X /* Get the next character to put on the screen. */ X X /* The 'extra' array contains the extra stuff that is */ X /* inserted to represent special characters (tabs, and */ X /* other non-printable stuff. The order in the 'extra' */ X /* array is reversed. */ X X if ( nextra > 0 ) X c = extra[--nextra]; X else { X c = (unsigned)(0xff & gchar(&memp)); X if (inc(&memp) == -1) X done = 1; X /* when getting a character from the file, we */ X /* may have to turn it into something else on */ X /* the way to putting it into 'Nextscreen'. */ X if ( c == TAB && !P(P_LS) ) { X strcpy(extra," "); X /* tab amount depends on current column */ X nextra = ((P(P_TS)-1) - (col - coff)%P(P_TS)); X c = ' '; X } X else if ( c == NUL && P(P_LS) ) { X extra[0] = NUL; X nextra = 1; X c = '$'; X } else if ( (n = chars[c].ch_size) > 1 ) { X char *p; X nextra = 0; X p = chars[c].ch_str; X /* copy 'ch-str'ing into 'extra' in reverse */ X while ( n > 1 ) X extra[nextra++] = p[--n]; X c = p[0]; X } X } X X if (screenp == endscreen) { X /* X * We're one past the end of the screen. If the X * current character is null, then we really did X * finish, so set didline = TRUE. In either case, X * break out because we're done. X */ X dec(&memp); X if (memp.index != 0 && c == NUL) { X didline = TRUE; X inc(&memp); X } X break; X } X X if ( c == NUL ) { X srow = ++row; X /* X * Save this position in case the next line won't X * fit on the screen completely. X */ X save = memp; X /* get pointer to start of next row */ X nextrow = &Nextscreen[row*Columns]; X /* blank out the rest of this row */ X while ( screenp != nextrow ) X *screenp++ = ' '; X col = 0; X continue; X } X if ( col >= Columns ) { X row++; X col = 0; X } X /* store the character in Nextscreen */ X *screenp++ = c; X col++; X } X /* X * If we didn't hit the end of the file, and we didn't finish X * the last line we were working on, then the line didn't fit. X */ X if (!done && !didline) { X /* X * Clear the rest of the screen and mark the unused lines. X */ X screenp = &Nextscreen[srow * Columns]; X while (screenp < endscreen) X *screenp++ = ' '; X for (; srow < (Rows-1) ;srow++) X Nextscreen[srow * Columns] = '@'; X *Botchar = save; X return; X } X /* make sure the rest of the screen is blank */ X while ( screenp < endscreen ) X *screenp++ = ' '; X /* put '~'s on rows that aren't part of the file. */ X if ( col != 0 ) X row++; X while ( row < Rows ) { X Nextscreen[row*Columns] = '~'; X row++; X } X if (done) /* we hit the end of the file */ X *Botchar = *Fileend; X else X *Botchar = memp; /* FIX - prev? */ X} X X/* X * nexttoscreen X * X * Transfer the contents of Nextscreen to the screen, using Realscreen X * to avoid unnecessary output. X */ Xstatic void Xnexttoscreen() X{ X register char *np = Nextscreen; X register char *rp = Realscreen; X register char *endscreen; X register int row = 0, col = 0; X int gorow = -1, gocol = -1; X X endscreen = &np[(Rows-1)*Columns]; X X outstr(T_CI); /* disable cursor */ X X for ( ; np < endscreen ; np++,rp++ ) { X /* If desired screen (contents of Nextscreen) does not */ X /* match what's really there, put it there. */ X if ( *np != *rp ) { X /* if we are positioned at the right place, */ X /* we don't have to use windgoto(). */ X if (gocol != col || gorow != row) { X /* X * If we're just off by one, don't send X * an entire esc. seq. (this happens a lot!) X */ X if (gorow == row && gocol+1 == col) { X outchar(*(np-1)); X gocol++; X } else X windgoto(gorow=row,gocol=col); X } X outchar(*rp = *np); X gocol++; X } X if ( ++col >= Columns ) { X col = 0; X row++; X } X } X outstr(T_CV); /* enable cursor again */ X} X X/* X * lfiletonext() - like filetonext() but only for cursor line X * X * Returns true if the size of the cursor line (in rows) hasn't changed. X * This determines whether or not we need to call filetonext() to examine X * the entire screen for changes. X */ Xstatic bool_t Xlfiletonext() X{ X register int row, col; X register char *screenp; X LPTR memp; X register char *nextrow; X char extra[16]; X int nextra = 0; X register int c; X int n; X bool_t eof; X int lno; /* number of the line we're doing */ X int coff; /* column offset */ X X coff = P(P_NU) ? 8 : 0; X X /* X * This should be done more efficiently. X */ X if (P(P_NU)) X lno = cntllines(Filemem, Curschar); X X screenp = Nextscreen + (Cline_row * Columns); X X memp = *Curschar; X memp.index = 0; X X eof = FALSE; X col = 0; X row = Cline_row; X X while (!eof) { X X if (P(P_NU) && col == 0 && memp.index == 0) { X strcpy(extra, mkline(lno)); X nextra = 8; X } X X /* Get the next character to put on the screen. */ X X /* The 'extra' array contains the extra stuff that is */ X /* inserted to represent special characters (tabs, and */ X /* other non-printable stuff. The order in the 'extra' */ X /* array is reversed. */ X X if ( nextra > 0 ) X c = extra[--nextra]; X else { X c = (unsigned)(0xff & gchar(&memp)); X if (inc(&memp) == -1) X eof = TRUE; X /* when getting a character from the file, we */ X /* may have to turn it into something else on */ X /* the way to putting it into 'Nextscreen'. */ X if ( c == TAB && !P(P_LS) ) { X strcpy(extra," "); X /* tab amount depends on current column */ X nextra = ((P(P_TS)-1) - (col - coff)%P(P_TS)); X c = ' '; X } else if ( c == NUL && P(P_LS) ) { X extra[0] = NUL; X nextra = 1; X c = '$'; X } else if ( c != NUL && (n=chars[c].ch_size) > 1 ) { X char *p; X nextra = 0; X p = chars[c].ch_str; X /* copy 'ch-str'ing into 'extra' in reverse */ X while ( n > 1 ) X extra[nextra++] = p[--n]; X c = p[0]; X } X } X X if ( c == NUL ) { X row++; X /* get pointer to start of next row */ X nextrow = &Nextscreen[row*Columns]; X /* blank out the rest of this row */ X while ( screenp != nextrow ) X *screenp++ = ' '; X col = 0; X break; X } X X if ( col >= Columns ) { X row++; X col = 0; X } X /* store the character in Nextscreen */ X *screenp++ = c; X col++; X } X return ((row - Cline_row) == Cline_size); X} X X/* X * lnexttoscreen X * X * Like nexttoscreen() but only for the cursor line. X */ Xstatic void Xlnexttoscreen() X{ X register char *np = Nextscreen + (Cline_row * Columns); X register char *rp = Realscreen + (Cline_row * Columns); X register char *endline; X register int row, col; X int gorow = -1, gocol = -1; X X endline = np + (Cline_size * Columns); X X row = Cline_row; X col = 0; X X outstr(T_CI); /* disable cursor */ X X for ( ; np < endline ; np++,rp++ ) { X /* If desired screen (contents of Nextscreen) does not */ X /* match what's really there, put it there. */ X if ( *np != *rp ) { X /* if we are positioned at the right place, */ X /* we don't have to use windgoto(). */ X if (gocol != col || gorow != row) { X /* X * If we're just off by one, don't send X * an entire esc. seq. (this happens a lot!) X */ X if (gorow == row && gocol+1 == col) { X outchar(*(np-1)); X gocol++; X } else X windgoto(gorow=row,gocol=col); X } X outchar(*rp = *np); X gocol++; X } X if ( ++col >= Columns ) { X col = 0; X row++; X } X } X outstr(T_CV); /* enable cursor again */ X} X Xstatic char * Xmkline(n) Xint n; X{ X static char lbuf[9]; X int i = 2; X X strcpy(lbuf, " "); X X lbuf[i++] = (n % 10) + '0'; X n /= 10; X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X return lbuf; X} X X/* X * updateline() - update the line the cursor is on X * X * Updateline() is called after changes that only affect the line that X * the cursor is on. This improves performance tremendously for normal X * insert mode operation. The only thing we have to watch for is when X * the cursor line grows or shrinks around a row boundary. This means X * we have to repaint other parts of the screen appropriately. If X * lfiletonext() returns FALSE, the size of the cursor line (in rows) X * has changed and we have to call updatescreen() to do a complete job. X */ Xvoid Xupdateline() X{ X if (!lfiletonext()) X updatescreen(); /* bag it, do the whole screen */ X else X lnexttoscreen(); X} X Xvoid Xupdatescreen() X{ X filetonext(); X nexttoscreen(); X} X X/* X * prt_line() - print the given line X */ Xvoid Xprt_line(s) Xchar *s; X{ X register int si = 0; X register int c; X register int col = 0; X X char extra[16]; X int nextra = 0; X int n; X X for (;;) { X X if ( nextra > 0 ) X c = extra[--nextra]; X else { X c = s[si++]; X if ( c == TAB && !P(P_LS) ) { X strcpy(extra, " "); X /* tab amount depends on current column */ X nextra = (P(P_TS) - 1) - col%P(P_TS); X c = ' '; X } else if ( c == NUL && P(P_LS) ) { X extra[0] = NUL; X nextra = 1; X c = '$'; X } else if ( c != NUL && (n=chars[c].ch_size) > 1 ) { X char *p; X X nextra = 0; X p = chars[c].ch_str; X /* copy 'ch-str'ing into 'extra' in reverse */ X while ( n > 1 ) X extra[nextra++] = p[--n]; X c = p[0]; X } X } X X if ( c == NUL ) X break; X X outchar(c); X col++; X } X} X Xvoid Xscreenclear() X{ X register char *rp, *np; X register char *end; X X outstr(T_ED); /* clear the display */ X X rp = Realscreen; X end = Realscreen + Rows * Columns; X np = Nextscreen; X X /* blank out the stored screens */ X while (rp != end) X *rp++ = *np++ = ' '; X} X Xvoid Xcursupdate() X{ X LPTR *p; X int icnt, c, nlines; X int i; X int didinc; X X if (bufempty()) { /* special case - file is empty */ X *Topchar = *Filemem; X *Curschar = *Filemem; X } else if ( LINEOF(Curschar) < LINEOF(Topchar) ) { X nlines = cntllines(Curschar,Topchar); X /* if the cursor is above the top of */ X /* the screen, put it at the top of the screen.. */ X *Topchar = *Curschar; X Topchar->index = 0; X /* ... and, if we weren't very close to begin with, */ X /* we scroll so that the line is close to the middle. */ X if ( nlines > Rows/3 ) { X for (i=0, p = Topchar; i < Rows/3 ;i++, *Topchar = *p) X if ((p = prevline(p)) == NULL) X break; X } else X s_ins(0, nlines-1); X updatescreen(); X } X else if (LINEOF(Curschar) >= LINEOF(Botchar)) { X nlines = cntllines(Botchar,Curschar); X /* If the cursor is off the bottom of the screen, */ X /* put it at the top of the screen.. */ X /* ... and back up */ X if ( nlines > Rows/3 ) { X p = Curschar; X for (i=0; i < (2*Rows)/3 ;i++) X if ((p = prevline(p)) == NULL) X break; X *Topchar = *p; X } else { X scrollup(nlines); X } X updatescreen(); X } X X Cursrow = Curscol = Cursvcol = 0; X for ( p=Topchar; p->linep != Curschar->linep ;p = nextline(p) ) X Cursrow += plines(p); X X Cline_row = Cursrow; X Cline_size = plines(p); X X if (P(P_NU)) X Curscol = 8; X X for (i=0; i <= Curschar->index ;i++) { X c = Curschar->linep->s[i]; X /* A tab gets expanded, depending on the current column */ X if ( c == TAB && !P(P_LS) ) X icnt = P(P_TS) - (Cursvcol % P(P_TS)); X else X icnt = chars[(unsigned)(c & 0xff)].ch_size; X Curscol += icnt; X Cursvcol += icnt; X if ( Curscol >= Columns ) { X Curscol -= Columns; X Cursrow++; X didinc = TRUE; X } X else X didinc = FALSE; X } X if (didinc) X Cursrow--; X X if (c == TAB && State == NORMAL && !P(P_LS)) { X Curscol--; X Cursvcol--; X } else { X Curscol -= icnt; X Cursvcol -= icnt; X } X if (Curscol < 0) X Curscol += Columns; X X if (set_want_col) { X Curswant = Cursvcol; X set_want_col = FALSE; X } X} X X/* X * The rest of the routines in this file perform screen manipulations. X * The given operation is performed physically on the screen. The X * corresponding change is also made to the internal screen image. X * In this way, the editor anticipates the effect of editing changes X * on the appearance of the screen. That way, when we call screenupdate X * a complete redraw isn't usually necessary. Another advantage is that X * we can keep adding code to anticipate screen changes, and in the X * meantime, everything still works. X */ X X/* X * s_ins(row, nlines) - insert 'nlines' lines at 'row' X */ Xvoid Xs_ins(row, nlines) Xint row; Xint nlines; X{ X register char *s, *d; /* src & dest for block copy */ X register char *e; /* end point for copy */ X register int i; X X if (T_IL[0] == NUL) /* can't do it */ X return; X X /* X * It "looks" better if we do all the inserts at once X */ X outstr(T_SC); /* save position */ X X for (i=0; i < nlines ;i++) { X windgoto(row, 0); X outstr(T_IL); X } X X windgoto(Rows-1, 0); /* delete any garbage that may have */ X outstr(T_EL); /* been shifted to the bottom line */ X outstr(T_RC); /* restore the cursor position */ X X /* X * Now do a block move to update the internal screen image X */ X d = Realscreen + (Columns * (Rows - 1)) - 1; X s = d - (Columns * nlines); X e = Realscreen + (Columns * row); X X while (s >= e) X *d-- = *s--; X X /* X * Clear the inserted lines X */ X s = Realscreen + (row * Columns); X e = s + (nlines * Columns); X while (s < e) X *s++ = ' '; X} X X/* X * s_del(row, nlines) - delete 'nlines' lines at 'row' X */ Xvoid Xs_del(row, nlines) Xint row; Xint nlines; X{ X register char *s, *d, *e; X register int i; X X if (T_DL[0] == NUL) /* can't do it */ X return; X X /* delete the lines */ X outstr(T_SC); /* save position */ X for (i=0; i < nlines ;i++) { X windgoto(row, 0); X outstr(T_DL); /* delete a line */ X if (i == 0) { X windgoto(Rows-2, 0); /* delete any garbage that */ X outstr(T_EL); /* was on the status line */ X } X } X outstr(T_RC); /* restore position */ X X /* X * do a block move to update the internal image X */ X d = Realscreen + (row * Columns); X s = d + (nlines * Columns); X e = Realscreen + ((Rows - 1) * Columns); X X while (s < e) X *d++ = *s++; X X while (d < e) /* clear the lines at the bottom */ X *d++ = ' '; X} END_OF_FILE if test 16090 -ne `wc -c <'screen.c'`; then echo shar: \"'screen.c'\" unpacked with wrong size! fi # end of 'screen.c' fi echo shar: End of shell archive. exit 0
rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) (12/15/88)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: search.c stevie.h tags term.c term.h undo.c unix.c # version.c tos_c # Wrapped by rtregn@faui32 on Wed Dec 14 17:19:38 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'search.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'search.c'\" else echo shar: Extracting \"'search.c'\" \(19131 characters\) sed "s/^X//" >'search.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: search.c,v 1.10 88/10/27 08:11:21 tony Exp $"; X X/* X * This file contains various searching-related routines. These fall into X * three groups: string searches (for /, ?, n, and N), character searches X * within a single line (for f, F, t, T, etc), and "other" kinds of searches X * like the '%' command, and 'word' searches. X * X * $Log: search.c,v $ X * Revision 1.10 88/10/27 08:11:21 tony X * Removed support for Megamax, and added code to print the search X * string on repeated searches. X * X * Revision 1.9 88/08/31 20:49:04 tony X * Made another fix in search.c related to repeated searches. X * X * Revision 1.8 88/08/25 15:12:06 tony X * Fixed a bug where the cursor didn't land on the right place after X * "beginning-of-word" searches if the word was preceded by the start X * of the line and a single character. X * X * Revision 1.7 88/08/23 12:52:08 tony X * Fixed a bug in ssearch() where repeated searches ('n' or 'N') resulted X * in dynamic memory being referenced after it was freed. X * X * Revision 1.6 88/06/26 14:48:51 tony X * Added a new routine, doglob(), to implement the ":g" command. X * X * Revision 1.5 88/05/02 21:34:34 tony X * Fixed a bug in my last modification that caused reverse repeated X * searches to save the wrong direction away for future use. X * X * Revision 1.4 88/04/29 14:46:06 tony X * Changed repsearch() and dosearch() to return a boolean indicating X * whether the search was successful. X * X * Revision 1.3 88/04/28 08:18:14 tony X * Added support for the "ignorecase" parameter. Also changed the search X * routines to use the modified regexec() interface. Changed dosub() to X * allow multiple substitutions per line. X * X * Revision 1.2 88/04/24 21:36:19 tony X * Added support for global substitution with the routine dosub(). The hard X * work is really done by regsub() in the regexp library. Only a single X * substitution per line is supported, for the moment. X * X * Revision 1.1 88/03/20 21:10:30 tony X * Initial revision X * X * X */ X X#include "stevie.h" X#include "regexp.h" /* Henry Spencer's (modified) reg. exp. routines */ X X/* X * String searches X * X * The actual searches are done using Henry Spencer's regular expression X * library. X */ X X#define BEGWORD "([^a-zA-Z0-9_]|^)" /* replaces "\<" in search strings */ X#define ENDWORD "([^a-zA-Z0-9_]|$)" /* likewise replaces "\>" */ X X#define BEGCHAR(c) (islower(c) || isupper(c) || isdigit(c) || ((c) == '_')) X Xbool_t begword; /* does the search include a 'begin word' match */ X X/* X * mapstring(s) - map special backslash sequences X */ Xstatic char * Xmapstring(s) Xregister char *s; X{ X static char ns[80]; X char *p; X X begword = FALSE; X X for (p = ns; *s ;s++) { X if (*s != '\\') { /* not an escape */ X *p++ = *s; X continue; X } X switch (*++s) { X case '/': X *p++ = '/'; X break; X X case '<': X strcpy(p, BEGWORD); X p += strlen(BEGWORD); X begword = TRUE; X break; X X case '>': X strcpy(p, ENDWORD); X p += strlen(ENDWORD); X break; X X default: X *p++ = '\\'; X *p++ = *s; X break; X } X } X *p++ = NUL; X X return ns; X} X Xstatic char *laststr = NULL; Xstatic int lastsdir; X Xstatic LPTR * Xssearch(dir,str) Xint dir; /* FORWARD or BACKWARD */ Xchar *str; X{ X LPTR *bcksearch(), *fwdsearch(); X LPTR *pos; X char *old_ls = laststr; X X reg_ic = P(P_IC); /* tell the regexp routines how to search */ X X laststr = strsave(str); X lastsdir = dir; X X if ( old_ls != NULL ) X free(old_ls); X X if ( dir == BACKWARD ) { X smsg("?%s", laststr); X pos = bcksearch(mapstring(laststr)); X } else { X smsg("/%s", laststr); X pos = fwdsearch(mapstring(laststr)); X } X X /* X * This is kind of a kludge, but its needed to make X * 'beginning of word' searches land on the right place. X */ X if (pos != NULL && begword) { X if (pos->index != 0 || !BEGCHAR(pos->linep->s[0])) X pos->index += 1; X } X return pos; X} X Xbool_t Xdosearch(dir,str) Xint dir; Xchar *str; X{ X LPTR *p; X X if (str == NULL) X str = laststr; X X if ((p = ssearch(dir,str)) == NULL) { X msg("Pattern not found"); X return FALSE; X } else { X LPTR savep; X X cursupdate(); X /* if we're backing up, we make sure the line we're on */ X /* is on the screen. */ X setpcmark(); X *Curschar = savep = *p; X cursupdate(); X X return TRUE; X } X} X X#define OTHERDIR(x) (((x) == FORWARD) ? BACKWARD : FORWARD) X Xbool_t Xrepsearch(flag) Xint flag; X{ X int dir = lastsdir; X bool_t found; X X if ( laststr == NULL ) { X beep(); X return FALSE; X } X X found = dosearch(flag ? OTHERDIR(lastsdir) : lastsdir, laststr); X X /* X * We have to save and restore 'lastsdir' because it gets munged X * by ssearch() and winds up saving the wrong direction from here X * if 'flag' is true. X */ X lastsdir = dir; X X return found; X} X X/* X * regerror - called by regexp routines when errors are detected. X */ Xvoid Xregerror(s) Xchar *s; X{ X emsg(s); X} X Xstatic LPTR * Xfwdsearch(str) Xregister char *str; X{ X static LPTR infile; X register LPTR *p; X regexp *prog; X X register char *s; X register int i; X X if ((prog = regcomp(str)) == NULL) { X emsg("Invalid search string"); X return NULL; X } X X p = Curschar; X i = Curschar->index + 1; X do { X s = p->linep->s + i; X X if (regexec(prog, s, i == 0)) { /* got a match */ X infile.linep = p->linep; X infile.index = (int) (prog->startp[0] - p->linep->s); X free(prog); X return (&infile); X } X i = 0; X } while ((p = nextline(p)) != NULL); X X /* X * If wrapscan isn't set, then don't scan from the beginning X * of the file. Just return failure here. X */ X if (!P(P_WS)) { X free(prog); X return NULL; X } X X /* search from the beginning of the file to Curschar */ X for (p = Filemem; p != NULL ;p = nextline(p)) { X s = p->linep->s; X X if (regexec(prog, s, TRUE)) { /* got a match */ X infile.linep = p->linep; X infile.index = (int) (prog->startp[0] - s); X free(prog); X return (&infile); X } X X if (p->linep == Curschar->linep) X break; X } X X free(prog); X return(NULL); X} X Xstatic LPTR * Xbcksearch(str) Xchar *str; X{ X static LPTR infile; X register LPTR *p; X regexp *prog; X register char *s; X register int i; X register char *match; X X /* make sure str isn't empty */ X if (str == NULL || *str == NUL) X return NULL; X X if ((prog = regcomp(str)) == NULL) { X emsg("Invalid search string"); X return NULL; X } X X p = Curschar; X dec(p); X X if (begword) /* so we don't get stuck on one match */ X dec(p); X X i = p->index; X X do { X s = p->linep->s; X X if (regexec(prog, s, TRUE)) { /* match somewhere on line */ X X /* X * Now, if there are multiple matches on this line, X * we have to get the last one. Or the last one X * before the cursor, if we're on that line. X */ X match = prog->startp[0]; X X while (regexec(prog, prog->endp[0], FALSE)) { X if ((i >= 0) && ((prog->startp[0] - s) > i)) X break; X match = prog->startp[0]; X } X X if ((i >= 0) && ((match - s) > i)) { X i = -1; X continue; X } X X infile.linep = p->linep; X infile.index = (int) (match - s); X free(prog); X return (&infile); X } X i = -1; X X } while ((p = prevline(p)) != NULL); X X /* X * If wrapscan isn't set, bag the search now X */ X if (!P(P_WS)) { X free(prog); X return NULL; X } X X /* search backward from the end of the file */ X p = prevline(Fileend); X do { X s = p->linep->s; X X if (regexec(prog, s, TRUE)) { /* match somewhere on line */ X X /* X * Now, if there are multiple matches on this line, X * we have to get the last one. X */ X match = prog->startp[0]; X X while (regexec(prog, prog->endp[0], FALSE)) X match = prog->startp[0]; X X infile.linep = p->linep; X infile.index = (int) (match - s); X free(prog); X return (&infile); X } X X if (p->linep == Curschar->linep) X break; X X } while ((p = prevline(p)) != NULL); X X free(prog); X return NULL; X} X X/* X * dosub(lp, up, cmd) X * X * Perform a substitution from line 'lp' to line 'up' using the X * command pointed to by 'cmd' which should be of the form: X * X * /pattern/substitution/g X * X * The trailing 'g' is optional and, if present, indicates that multiple X * substitutions should be performed on each line, if applicable. X * The usual escapes are supported as described in the regexp docs. X */ Xvoid Xdosub(lp, up, cmd) XLPTR *lp, *up; Xchar *cmd; X{ X LINE *cp; X char *pat, *sub; X regexp *prog; X int nsubs; X bool_t do_all; /* do multiple substitutions per line */ X X /* X * If no range was given, do the current line. If only one line X * was given, just do that one. X */ X if (lp->linep == NULL) X *up = *lp = *Curschar; X else { X if (up->linep == NULL) X *up = *lp; X } X X pat = ++cmd; /* skip the initial '/' */ X X while (*cmd) { X if (cmd[0] == '/' && cmd[-1] != '\\') { X *cmd++ = NUL; X break; X } X cmd++; X } X X if (*pat == NUL) { X emsg("NULL pattern specified"); X return; X } X X sub = cmd; X X do_all = FALSE; X X while (*cmd) { X if (cmd[0] == '/' && cmd[-1] != '\\') { X do_all = (cmd[1] == 'g'); X *cmd++ = NUL; X break; X } X cmd++; X } X X reg_ic = P(P_IC); /* set "ignore case" flag appropriately */ X X if ((prog = regcomp(pat)) == NULL) { X emsg("Invalid search string"); X return; X } X X nsubs = 0; X X for (cp = lp->linep; cp != NULL ;cp = cp->next) { X if (regexec(prog, cp->s, TRUE)) { /* a match on this line */ X char *ns, *sns, *p; X X /* X * Get some space for a temporary buffer X * to do the substitution into. X */ X sns = ns = alloc(2048); X *sns = NUL; X X p = cp->s; X X do { X for (ns = sns; *ns ;ns++) X ; X /* X * copy up to the part that matched X */ X while (p < prog->startp[0]) X *ns++ = *p++; X X regsub(prog, sub, ns); X X /* X * continue searching after the match X */ X p = prog->endp[0]; X X } while (regexec(prog, p, FALSE) && do_all); X X for (ns = sns; *ns ;ns++) X ; X X /* X * copy the rest of the line, that didn't match X */ X while (*p) X *ns++ = *p++; X X *ns = NUL; X X free(cp->s); /* free the original line */ X cp->s = strsave(sns); /* and save the modified str */ X cp->size = strlen(cp->s) + 1; X free(sns); /* free the temp buffer */ X nsubs++; X CHANGED; X } X if (cp == up->linep) X break; X } X X if (nsubs) { X updatescreen(); X if (nsubs >= P(P_RP)) X smsg("%d substitution%c", nsubs, (nsubs>1) ? 's' : ' '); X } else X msg("No match"); X X free(prog); X} X X/* X * doglob(cmd) X * X * Execute a global command of the form: X * X * g/pattern/X X * X * where 'x' is a command character, currently one of the following: X * X * d Delete all matching lines X * p Print all matching lines X * X * The command character (as well as the trailing slash) is optional, and X * is assumed to be 'p' if missing. X */ Xvoid Xdoglob(lp, up, cmd) XLPTR *lp, *up; Xchar *cmd; X{ X LINE *cp; X char *pat; X regexp *prog; X int ndone; X char cmdchar = NUL; /* what to do with matching lines */ X X /* X * If no range was given, do every line. If only one line X * was given, just do that one. X */ X if (lp->linep == NULL) { X *lp = *Filemem; X *up = *Fileend; X } else { X if (up->linep == NULL) X *up = *lp; X } X X pat = ++cmd; /* skip the initial '/' */ X X while (*cmd) { X if (cmd[0] == '/' && cmd[-1] != '\\') { X cmdchar = cmd[1]; X *cmd++ = NUL; X break; X } X cmd++; X } X if (cmdchar == NUL) X cmdchar = 'p'; X X reg_ic = P(P_IC); /* set "ignore case" flag appropriately */ X X if (cmdchar != 'd' && cmdchar != 'p') { X emsg("Invalid command character"); X return; X } X X if ((prog = regcomp(pat)) == NULL) { X emsg("Invalid search string"); X return; X } X X msg(""); X ndone = 0; X X for (cp = lp->linep; cp != NULL ;cp = cp->next) { X if (regexec(prog, cp->s, TRUE)) { /* a match on this line */ X switch (cmdchar) { X X case 'd': /* delete the line */ X if (Curschar->linep != cp) { X LPTR savep; X X savep = *Curschar; X Curschar->linep = cp; X Curschar->index = 0; X delline(1, FALSE); X *Curschar = savep; X } else X delline(1, FALSE); X break; X X case 'p': /* print the line */ X prt_line(cp->s); X outstr("\r\n"); X break; X } X ndone++; X } X if (cp == up->linep) X break; X } X X if (ndone) { X switch (cmdchar) { X X case 'd': X updatescreen(); X if (ndone >= P(P_RP)) X smsg("%d fewer line%c", ndone, X (ndone > 1) ? 's' : ' '); X break; X X case 'p': X wait_return(); X break; X } X } else X msg("No match"); X X free(prog); X} X X/* X * Character Searches X */ X Xstatic char lastc = NUL; /* last character searched for */ Xstatic int lastcdir; /* last direction of character search */ Xstatic int lastctype; /* last type of search ("find" or "to") */ X X/* X * searchc(c, dir, type) X * X * Search for character 'c', in direction 'dir'. If type is 0, move to X * the position of the character, otherwise move to just before the char. X */ Xbool_t Xsearchc(c, dir, type) Xchar c; Xint dir; Xint type; X{ X LPTR save; X X save = *Curschar; /* save position in case we fail */ X lastc = c; X lastcdir = dir; X lastctype = type; X X /* X * On 'to' searches, skip one to start with so we can repeat X * searches in the same direction and have it work right. X */ X if (type) X (dir == FORWARD) ? oneright() : oneleft(); X X while ( (dir == FORWARD) ? oneright() : oneleft() ) { X if (gchar(Curschar) == c) { X if (type) X (dir == FORWARD) ? oneleft() : oneright(); X return TRUE; X } X } X *Curschar = save; X return FALSE; X} X Xbool_t Xcrepsearch(flag) Xint flag; X{ X int dir = lastcdir; X int rval; X X if (lastc == NUL) X return FALSE; X X rval = searchc(lastc, flag ? OTHERDIR(lastcdir) : lastcdir, lastctype); X X lastcdir = dir; /* restore dir., since it may have changed */ X X return rval; X} X X/* X * "Other" Searches X */ X X/* X * showmatch - move the cursor to the matching paren or brace X */ XLPTR * Xshowmatch() X{ X static LPTR pos; X int (*move)(), inc(), dec(); X char initc = gchar(Curschar); /* initial char */ X char findc; /* terminating char */ X char c; X int count = 0; X X pos = *Curschar; /* set starting point */ X X switch (initc) { X X case '(': X findc = ')'; X move = inc; X break; X case ')': X findc = '('; X move = dec; X break; X case '{': X findc = '}'; X move = inc; X break; X case '}': X findc = '{'; X move = dec; X break; X case '[': X findc = ']'; X move = inc; X break; X case ']': X findc = '['; X move = dec; X break; X default: X return (LPTR *) NULL; X } X X while ((*move)(&pos) != -1) { /* until end of file */ X c = gchar(&pos); X if (c == initc) X count++; X else if (c == findc) { X if (count == 0) X return &pos; X count--; X } X } X return (LPTR *) NULL; /* never found it */ X} X X/* X * findfunc(dir) - Find the next function in direction 'dir' X * X * Return TRUE if a function was found. X */ Xbool_t Xfindfunc(dir) Xint dir; X{ X LPTR *curr; X X curr = Curschar; X X do { X curr = (dir == FORWARD) ? nextline(curr) : prevline(curr); X X if (curr != NULL && curr->linep->s[0] == '{') { X setpcmark(); X *Curschar = *curr; X return TRUE; X } X } while (curr != NULL); X X return FALSE; X} X X/* X * The following routines do the word searches performed by the X * 'w', 'W', 'b', 'B', 'e', and 'E' commands. X */ X X/* X * To perform these searches, characters are placed into one of three X * classes, and transitions between classes determine word boundaries. X * X * The classes are: X * X * 0 - white space X * 1 - letters, digits, and underscore X * 2 - everything else X */ X Xstatic int stype; /* type of the word motion being performed */ X X#define C0(c) (((c) == ' ') || ((c) == '\t') || ((c) == NUL)) X#define C1(c) (isalpha(c) || isdigit(c) || ((c) == '_')) X X/* X * cls(c) - returns the class of character 'c' X * X * The 'type' of the current search modifies the classes of characters X * if a 'W', 'B', or 'E' motion is being done. In this case, chars. from X * class 2 are reported as class 1 since only white space boundaries are X * of interest. X */ Xstatic int Xcls(c) Xchar c; X{ X if (C0(c)) X return 0; X X if (C1(c)) X return 1; X X /* X * If stype is non-zero, report these as class 1. X */ X return (stype == 0) ? 2 : 1; X} X X X/* X * fwd_word(pos, type) - move forward one word X * X * Returns the resulting position, or NULL if EOF was reached. X */ XLPTR * Xfwd_word(p, type) XLPTR *p; Xint type; X{ X static LPTR pos; X int sclass = cls(gchar(p)); /* starting class */ X X pos = *p; X X stype = type; X X /* X * We always move at least one character. X */ X if (inc(&pos) == -1) X return NULL; X X if (sclass != 0) { X while (cls(gchar(&pos)) == sclass) { X if (inc(&pos) == -1) X return NULL; X } X /* X * If we went from 1 -> 2 or 2 -> 1, return here. X */ X if (cls(gchar(&pos)) != 0) X return &pos; X } X X /* We're in white space; go to next non-white */ X X while (cls(gchar(&pos)) == 0) { X /* X * We'll stop if we land on a blank line X */ X if (pos.index == 0 && pos.linep->s[0] == NUL) X break; X X if (inc(&pos) == -1) X return NULL; X } X X return &pos; X} X X/* X * bck_word(pos, type) - move backward one word X * X * Returns the resulting position, or NULL if EOF was reached. X */ XLPTR * Xbck_word(p, type) XLPTR *p; Xint type; X{ X static LPTR pos; X int sclass = cls(gchar(p)); /* starting class */ X X pos = *p; X X stype = type; X X if (dec(&pos) == -1) X return NULL; X X /* X * If we're in the middle of a word, we just have to X * back up to the start of it. X */ X if (cls(gchar(&pos)) == sclass && sclass != 0) { X /* X * Move backward to start of the current word X */ X while (cls(gchar(&pos)) == sclass) { X if (dec(&pos) == -1) X return NULL; X } X inc(&pos); /* overshot - forward one */ X return &pos; X } X X /* X * We were at the start of a word. Go back to the start X * of the prior word. X */ X X while (cls(gchar(&pos)) == 0) { /* skip any white space */ X /* X * We'll stop if we land on a blank line X */ X if (pos.index == 0 && pos.linep->s[0] == NUL) X return &pos; X X if (dec(&pos) == -1) X return NULL; X } X X sclass = cls(gchar(&pos)); X X /* X * Move backward to start of this word. X */ X while (cls(gchar(&pos)) == sclass) { X if (dec(&pos) == -1) X return NULL; X } X inc(&pos); /* overshot - forward one */ X X return &pos; X} X X/* X * end_word(pos, type) - move to the end of the word X * X * There is an apparent bug in the 'e' motion of the real vi. At least X * on the System V Release 3 version for the 80386. Unlike 'b' and 'w', X * the 'e' motion crosses blank lines. When the real vi crosses a blank X * line in an 'e' motion, the cursor is placed on the FIRST character X * of the next non-blank line. The 'E' command, however, works correctly. X * Since this appears to be a bug, I have not duplicated it here. X * X * Returns the resulting position, or NULL if EOF was reached. X */ XLPTR * Xend_word(p, type) XLPTR *p; Xint type; X{ X static LPTR pos; X int sclass = cls(gchar(p)); /* starting class */ X X pos = *p; X X stype = type; X X if (inc(&pos) == -1) X return NULL; X X /* X * If we're in the middle of a word, we just have to X * move to the end of it. X */ X if (cls(gchar(&pos)) == sclass && sclass != 0) { X /* X * Move forward to end of the current word X */ X while (cls(gchar(&pos)) == sclass) { X if (inc(&pos) == -1) X return NULL; X } X dec(&pos); /* overshot - forward one */ X return &pos; X } X X /* X * We were at the end of a word. Go to the end X * of the next word. X */ X X while (cls(gchar(&pos)) == 0) { /* skip any white space */ X if (inc(&pos) == -1) X return NULL; X } X X sclass = cls(gchar(&pos)); X X /* X * Move forward to end of this word. X */ X while (cls(gchar(&pos)) == sclass) { X if (inc(&pos) == -1) X return NULL; X } X dec(&pos); /* overshot - forward one */ X X return &pos; X} END_OF_FILE if test 19131 -ne `wc -c <'search.c'`; then echo shar: \"'search.c'\" unpacked with wrong size! fi # end of 'search.c' fi if test -f 'stevie.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stevie.h'\" else echo shar: Extracting \"'stevie.h'\" \(5840 characters\) sed "s/^X//" >'stevie.h' <<'END_OF_FILE' X/* X * $Header: stevie.h,v 1.15 88/11/10 08:59:10 tony Exp $ X * X * Main header file included by all source files. X * X * $Log: stevie.h,v $ X * Revision 1.15 88/11/10 08:59:10 tony X * Added a declaration for the routine do_mlines() in main.c that checks X * for mode lines in a file. X * X * Revision 1.14 88/10/28 13:59:36 tony X * Added missing endif. X * X * Revision 1.13 88/10/27 08:23:47 tony X * Also added declarations for the new system- X * dependent routines flushbuf() and doshell(). X * X * Revision 1.12 88/10/06 10:13:08 tony X * Added a declaration for fixname(). X * X * Revision 1.11 88/08/30 20:37:10 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 1.10 88/08/26 08:45:51 tony X * Misc. changes to make lint happy. X * X * Revision 1.9 88/07/09 20:38:47 tony X * Added declarations for new routines in undo.c supporting the 'U' command. X * X * Revision 1.8 88/06/26 14:52:33 tony X * Added missing declaration for prt_line() in screen.c X * X * Revision 1.7 88/06/26 14:49:21 tony X * Added a declaration for the new routine, doglog(), in search.c. X * X * Revision 1.6 88/06/20 14:52:13 tony X * Merged in changes for BSD Unix sent in by Michael Lichter. X * X * Revision 1.5 88/05/03 14:39:15 tony X * Minor change for DOS support. X * X * Revision 1.4 88/04/29 14:46:39 tony X * Changed the declarations of repsearch() and dosearch() from void to bool_t. X * X * Revision 1.3 88/04/24 21:35:56 tony X * Added a declaration for the new routine dosub() in search.c. X * X * Revision 1.2 88/03/21 16:46:57 tony X * Moved the environmental defines out to a file named "env.h" which is X * not maintained with RCS. X * X * Revision 1.1 88/03/20 21:05:17 tony X * Initial revision X * X * X */ X X#include "env.h" /* defines to establish the compile-time environment */ X X#include <stdio.h> X#include <ctype.h> X X#ifdef BSD X X#include <strings.h> X#define strchr index X X#else X X#ifdef MINIX X Xextern char *strchr(); Xextern char *strrchr(); Xextern char *strcpy(); Xextern char *strcat(); Xextern int strlen(); X X#else X#include <string.h> X#endif X X#endif X X#include "ascii.h" X#include "keymap.h" X#include "param.h" X#include "term.h" X Xextern char *strchr(); X X#define NORMAL 0 X#define CMDLINE 1 X#define INSERT 2 X#define REPLACE 3 X#define FORWARD 4 X#define BACKWARD 5 X X/* X * Boolean type definition and constants X */ Xtypedef short bool_t; X X#ifndef TRUE X#define FALSE (0) X#define TRUE (1) X#endif X X/* X * SLOP is the amount of extra space we get for text on a line during X * editing operations that need more space. This keeps us from calling X * malloc every time we get a character during insert mode. No extra X * space is allocated when the file is initially read. X */ X#define SLOP 10 X X/* X * LINEINC is the gap we leave between the artificial line numbers. This X * helps to avoid renumbering all the lines every time a new line is X * inserted. X */ X#define LINEINC 10 X X#define CHANGED Changed=TRUE X#define UNCHANGED Changed=FALSE X Xstruct line { X struct line *prev, *next; /* previous and next lines */ X char *s; /* text for this line */ X int size; /* actual size of space at 's' */ X unsigned long num; /* line "number" */ X}; X X#define LINEOF(x) ((x)->linep->num) X Xstruct lptr { X struct line *linep; /* line we're referencing */ X int index; /* position within that line */ X}; X Xtypedef struct line LINE; Xtypedef struct lptr LPTR; X Xstruct charinfo { X char ch_size; X char *ch_str; X}; X Xextern struct charinfo chars[]; X Xextern int State; Xextern int Rows; Xextern int Columns; Xextern char *Realscreen; Xextern char *Nextscreen; Xextern char *Filename; Xextern LPTR *Filemem; Xextern LPTR *Filetop; Xextern LPTR *Fileend; Xextern LPTR *Topchar; Xextern LPTR *Botchar; Xextern LPTR *Curschar; Xextern LPTR *Insstart; Xextern int Cursrow, Curscol, Cursvcol, Curswant; Xextern bool_t set_want_col; Xextern int Prenum; Xextern bool_t Changed; Xextern char Redobuff[], Insbuff[]; Xextern char *Insptr; Xextern int Ninsert; X Xextern char *malloc(), *strcpy(); X X/* X * alloc.c X */ Xchar *alloc(), *strsave(); Xvoid screenalloc(), filealloc(), freeall(); XLINE *newline(); Xbool_t bufempty(), buf1line(), lineempty(), endofline(), canincrease(); X X/* X * cmdline.c X */ Xvoid readcmdline(), dotag(), msg(), emsg(), smsg(), gotocmd(), wait_return(); X X/* X * edit.c X */ Xvoid edit(), insertchar(), getout(), scrollup(), scrolldown(), beginline(); Xbool_t oneright(), oneleft(), oneup(), onedown(); X X/* X * fileio.c X */ Xvoid filemess(), renum(); Xbool_t readfile(), writeit(); X X/* X * help.c X */ Xbool_t help(); X X/* X * linefunc.c X */ XLPTR *nextline(), *prevline(), *coladvance(); X X/* X * main.c X */ Xvoid stuffin(), stuffnum(), addtobuff(); Xvoid do_mlines(); Xint vgetc(); Xbool_t anyinput(); X X/* X * mark.c X */ Xvoid setpcmark(), clrall(), clrmark(); Xbool_t setmark(); XLPTR *getmark(); X X/* X * misccmds.c X */ Xvoid opencmd(), fileinfo(), inschar(), delline(); Xbool_t delchar(); Xint cntllines(), plines(); XLPTR *gotoline(); X X/* X * normal.c X */ Xvoid normal(); Xchar *mkstr(); X X/* X * param.c X */ Xvoid doset(); X X/* X * ptrfunc.c X */ Xint inc(), dec(); Xint gchar(); Xvoid pchar(), pswap(); Xbool_t lt(), equal(), ltoreq(); X#if 0 X/* not currently used */ Xbool_t gtoreq(), gt(); X#endif X X/* X * screen.c X */ Xvoid updatescreen(), updateline(); Xvoid screenclear(), cursupdate(); Xvoid s_ins(), s_del(); Xvoid prt_line(); X X/* X * search.c X */ Xvoid dosub(), doglob(); Xbool_t searchc(), crepsearch(), findfunc(), dosearch(), repsearch(); XLPTR *showmatch(); XLPTR *fwd_word(), *bck_word(), *end_word(); X X/* X * undo.c X */ Xvoid u_save(), u_saveline(), u_clear(); Xvoid u_lcheck(), u_lundo(); Xvoid u_undo(); X X/* X * Machine-dependent routines. X */ Xint inchar(); Xvoid flushbuf(); Xvoid outchar(), outstr(), beep(); Xchar *fixname(); X#ifndef OS2 X#ifndef DOS Xvoid remove(), rename(); X#endif X#endif Xvoid windinit(), windexit(), windgoto(); Xvoid delay(); Xvoid doshell(); END_OF_FILE if test 5840 -ne `wc -c <'stevie.h'`; then echo shar: \"'stevie.h'\" unpacked with wrong size! fi # end of 'stevie.h' fi if test -f 'tags' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tags'\" else echo shar: Extracting \"'tags'\" \(7248 characters\) sed "s/^X//" >'tags' <<'END_OF_FILE' XBEGCHAR search.c /^#define BEGCHAR(c) (islower(c) || isupper(c) || is/ XBEGID ctags.c /^#define BEGID(c) (isalpha(c) || (c) == '_')$/ XC0 search.c /^#define C0(c) (((c) == ' ') || ((c) == '\\t') || ((/ XC1 search.c /^#define C1(c) (isalpha(c) || isdigit(c) || ((c) ==/ XDEFAULT1 normal.c /^#define DEFAULT1(x) (((x) == 0) ? 1 : (x))$/ XFAIL regexp.c /^#define FAIL(m) { regerror(m); return(NULL); }$/ XIDCHAR normal.c /^#define IDCHAR(c) (isalpha(c) || isdigit(c) || (c)/ XISMULT regexp.c /^#define ISMULT(c) ((c) == '*' || (c) == '+' || (c)/ XISSPECIAL edit.c /^#define ISSPECIAL(c) ((c) == NL || (c) == CR || (c/ XMIDID ctags.c /^#define MIDID(c) (isalpha(c) || isdigit(c) || (c) / XMctags ctags.c /^main(argc, argv)$/ XMmain main.c /^main(argc,argv)$/ XNEXT regexp.c /^#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&/ XOP regexp.c /^#define OP(p) (*(p))$/ XOPERAND regexp.c /^#define OPERAND(p) ((p) + 3)$/ XOTHERDIR search.c /^#define OTHERDIR(x) (((x) == FORWARD) ? BACKWARD :/ XUCHARAT regexp.c /^#define UCHARAT(p) ((int)*(unsigned char *)(p))$/ Xaddtobuff main.c /^addtobuff(s,c1,c2,c3,c4,c5,c6)$/ Xalloc alloc.c /^alloc(size)$/ Xanyinput main.c /^anyinput()$/ Xbadcmd cmdline.c /^badcmd()$/ Xbck_word search.c /^bck_word(p, type)$/ Xbcksearch search.c /^bcksearch(str)$/ Xbeep dos.c /^beep()$/ Xbeginline edit.c /^beginline(flag)$/ Xbuf1line alloc.c /^buf1line()$/ Xbufempty alloc.c /^bufempty()$/ Xcanincrease alloc.c /^canincrease(n)$/ Xchk_mline main.c /^chk_mline(s)$/ Xclrall mark.c /^clrall()$/ Xclrmark mark.c /^clrmark(line)$/ Xcls search.c /^cls(c)$/ Xcntllines misccmds.c /^cntllines(pbegin,pend)$/ Xcoladvance linefunc.c /^coladvance(p, col)$/ Xcopyline undo.c /^copyline(l)$/ Xcrepsearch search.c /^crepsearch(flag)$/ Xcstrchr regexp.c /^cstrchr(s, c)$/ Xcstrncmp regexp.c /^cstrncmp(s1, s2, n)$/ Xcursupdate screen.c /^cursupdate()$/ Xdec ptrfunc.c /^dec(lp)$/ Xdelay dos.c /^delay()$/ Xdelchar misccmds.c /^delchar(fixpos)$/ Xdelline misccmds.c /^delline(nlines, can_update)$/ Xdo_mlines main.c /^do_mlines()$/ Xdochange normal.c /^dochange(c1, c2, num)$/ Xdodelete normal.c /^dodelete(c1, c2, num)$/ Xdoecmd cmdline.c /^doecmd(arg, force)$/ Xdofile ctags.c /^dofile(fn, tp)$/ Xdofilter normal.c /^dofilter(c1, c2, num)$/ Xdoglob search.c /^doglob(lp, up, cmd)$/ Xdojoin normal.c /^dojoin()$/ Xdoput normal.c /^doput(dir)$/ Xdosearch search.c /^dosearch(dir,str)$/ Xdoset param.c /^doset(arg, inter)$/ Xdoshell dos.c /^doshell(cmd)$/ Xdoshift normal.c /^doshift(op, c1, c2, num)$/ Xdosub search.c /^dosub(lp, up, cmd)$/ Xdotag cmdline.c /^dotag(tag, force)$/ Xdoyank normal.c /^doyank()$/ Xedit edit.c /^edit()$/ Xemsg cmdline.c /^emsg(s)$/ Xend_word search.c /^end_word(p, type)$/ Xendofline alloc.c /^endofline(p)$/ Xequal ptrfunc.c /^equal(a, b)$/ Xfilealloc alloc.c /^filealloc()$/ Xfileinfo misccmds.c /^fileinfo()$/ Xfilemess fileio.c /^filemess(s)$/ Xfiletonext screen.c /^filetonext()$/ Xfindfunc search.c /^findfunc(dir)$/ Xfixname dos.c /^fixname(s)$/ Xflushbuf dos.c /^flushbuf()$/ Xfopenb dos.c /^fopenb(fname, mode)$/ Xfreeall alloc.c /^freeall()$/ Xfwd_word search.c /^fwd_word(p, type)$/ Xfwdsearch search.c /^fwdsearch(str)$/ Xgchar ptrfunc.c /^gchar(lp)$/ Xget_line cmdline.c /^get_line(cp)$/ Xget_range cmdline.c /^get_range(cp)$/ Xgetmark mark.c /^getmark(c)$/ Xgetout edit.c /^getout()$/ Xgetswitch dos.c /^getswitch()$/ Xgotocmd cmdline.c /^gotocmd(clr, firstc)$/ Xgotoline misccmds.c /^gotoline(n)$/ Xgt ptrfunc.c /^gt(a, b)$/ Xgtoreq ptrfunc.c /^gtoreq(a, b)$/ Xhelp help.c /^help()$/ Xinc ptrfunc.c /^inc(lp)$/ Xinchar dos.c /^inchar()$/ Xinschar misccmds.c /^inschar(c)$/ Xinsertchar edit.c /^insertchar(c)$/ Xinslines normal.c /^inslines(lp, dir, buf)$/ Xinsstr misccmds.c /^insstr(s)$/ Xlfiletonext screen.c /^lfiletonext()$/ Xlineempty alloc.c /^lineempty()$/ Xlnexttoscreen screen.c /^lnexttoscreen()$/ Xlongline help.c /^longline(p)$/ Xlt ptrfunc.c /^lt(a, b)$/ Xltoreq ptrfunc.c /^ltoreq(a, b)$/ Xmapstring search.c /^mapstring(s)$/ Xmkline screen.c /^mkline(n)$/ Xmkstr normal.c /^mkstr(c)$/ Xmkup regexp.c /^#define mkup(c) ((islower(c) && reg_ic) ? toupper/ Xmsg cmdline.c /^msg(s)$/ Xnewline alloc.c /^newline(nchars)$/ Xnextfile ctags.c /^nextfile() \/* returns ptr to next file to be searc/ Xnextline linefunc.c /^nextline(curr)$/ Xnexttoscreen screen.c /^nexttoscreen()$/ Xnormal normal.c /^normal(c)$/ Xonedown edit.c /^onedown(n)$/ Xoneleft edit.c /^oneleft()$/ Xoneright edit.c /^oneright()$/ Xoneup edit.c /^oneup(n)$/ Xopenbwd misccmds.c /^openbwd(can_ai)$/ Xopencmd misccmds.c /^opencmd(dir, can_ai)$/ Xopenfwd misccmds.c /^openfwd(can_ai)$/ Xoutchar dos.c /^outchar(c)$/ Xoutone dos.c /^#define outone(c) outbuf[bpos++] = c; if (bpos >= / Xoutstr dos.c /^outstr(s)$/ Xpchar ptrfunc.c /^pchar(lp, c)$/ Xplines misccmds.c /^plines(p)$/ Xprevline linefunc.c /^prevline(curr)$/ Xprt_line screen.c /^prt_line(s)$/ Xpswap ptrfunc.c /^pswap(a, b)$/ Xreadcmdline cmdline.c /^readcmdline(firstc, cmdline)$/ Xreadfile fileio.c /^readfile(fname,fromp,nochangename)$/ Xreg regexp.c /^reg(paren, flagp)$/ Xregatom regexp.c /^regatom(flagp)$/ Xregbranch regexp.c /^regbranch(flagp)$/ Xregc regexp.c /^regc(b)$/ Xregcomp regexp.c /^regcomp(exp)$/ Xregdump regexp.c /^regdump(r)$/ Xregerror search.c /^regerror(s)$/ Xregexec regexp.c /^regexec(prog, string, at_bol)$/ Xreginsert regexp.c /^reginsert(op, opnd)$/ Xregmatch regexp.c /^regmatch(prog)$/ Xregnext regexp.c /^regnext(p)$/ Xregnode regexp.c /^regnode(op)$/ Xregoptail regexp.c /^regoptail(p, val)$/ Xregpiece regexp.c /^regpiece(flagp)$/ Xregprop regexp.c /^regprop(op)$/ Xregrepeat regexp.c /^regrepeat(p)$/ Xregsub regsub.c /^regsub(prog, source, dest)$/ Xregtail regexp.c /^regtail(p, val)$/ Xregtry regexp.c /^regtry(prog, string)$/ Xremove minix.c /^remove(file)$/ Xrename minix.c /^rename(of, nf)$/ Xrenum fileio.c /^renum()$/ Xrepsearch search.c /^repsearch(flag)$/ Xreset_tty minix.c /^reset_tty()$/ Xs_del screen.c /^s_del(row, nlines)$/ Xs_ins screen.c /^s_ins(row, nlines)$/ Xscreenalloc alloc.c /^screenalloc()$/ Xscreenclear screen.c /^screenclear()$/ Xscrolldown edit.c /^scrolldown(nlines)$/ Xscrollup edit.c /^scrollup(nlines)$/ Xsearchc search.c /^searchc(c, dir, type)$/ Xset_tty minix.c /^set_tty()$/ Xsetmark mark.c /^setmark(c)$/ Xsetpcmark mark.c /^setpcmark()$/ Xsetswitch dos.c /^setswitch(c)$/ Xshowmatch search.c /^showmatch()$/ Xshowparms param.c /^showparms(all)$/ Xsleep dos.c /^sleep(n)$/ Xsmsg cmdline.c /^smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9)$/ Xssearch search.c /^ssearch(dir,str)$/ Xstartinsert normal.c /^startinsert(initstr, startln)$/ Xstrchr minix.c /^strchr(s, c)$/ Xstrcspn regexp.c /^strcspn(s1, s2)$/ Xstrsave alloc.c /^strsave(string)$/ Xstuffin main.c /^stuffin(s)$/ Xstuffnum main.c /^stuffnum(n)$/ Xt_init term.c /^t_init()$/ Xtabinout normal.c /^tabinout(inout, num)$/ Xu_clear undo.c /^u_clear()$/ Xu_lcheck undo.c /^u_lcheck()$/ Xu_lfree undo.c /^u_lfree()$/ Xu_lsave undo.c /^u_lsave(l, u)$/ Xu_lundo undo.c /^u_lundo()$/ Xu_save undo.c /^u_save(l, u)$/ Xu_saveline undo.c /^u_saveline()$/ Xu_undo undo.c /^u_undo()$/ Xupdateline screen.c /^updateline()$/ Xupdatescreen screen.c /^updatescreen()$/ Xusage main.c /^usage()$/ Xvgetc main.c /^vgetc()$/ Xvpeekc main.c /^vpeekc()$/ Xwait_return cmdline.c /^wait_return()$/ Xwindexit dos.c /^windexit(r)$/ Xwindgoto dos.c /^windgoto(r, c)$/ Xwindinit dos.c /^windinit()$/ Xwriteit fileio.c /^writeit(fname, start, end)$/ END_OF_FILE if test 7248 -ne `wc -c <'tags'`; then echo shar: \"'tags'\" unpacked with wrong size! fi # end of 'tags' fi if test -f 'term.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'term.c'\" else echo shar: Extracting \"'term.c'\" \(1878 characters\) sed "s/^X//" >'term.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: term.c,v 1.2 88/10/31 13:10:32 tony Exp $"; X X/* X * Termcap initialization (optional). X * X * $Log: term.c,v $ X * Revision 1.2 88/10/31 13:10:32 tony X * Removed text after "#endif" that some compilers complain about. X * X * Revision 1.1 88/10/29 14:05:27 tony X * Initial revision X * X */ X X#include <stdio.h> X#include "stevie.h" X X#ifdef TERMCAP X Xstatic char buf[1024]; /* termcap entry read here */ Xstatic char cap[256]; /* capability strings go in here */ X Xchar *T_EL; /* erase the entire current line */ Xchar *T_IL; /* insert one line */ Xchar *T_DL; /* delete one line */ Xchar *T_SC; /* save the cursor position */ Xchar *T_ED; /* erase display (may optionally home cursor) */ Xchar *T_RC; /* restore the cursor position */ Xchar *T_CI; /* invisible cursor (very optional) */ Xchar *T_CV; /* visible cursor (very optional) */ X Xchar *T_CM; /* cursor motion string */ X Xextern int tgetent(), tgetnum(); Xextern char *tgetstr(); Xextern char *getenv(); X Xint Xt_init() X{ X char *term; X int n; X char *cp = cap; X X if ((term = getenv("TERM")) == NULL) X return 0; X X if (tgetent(buf, term) != 1) X return 0; X X if ((n = tgetnum("li")) == -1) X return 0; X else X P(P_LI) = Rows = n; X X if ((n = tgetnum("co")) == -1) X return 0; X else X Columns = n; X X /* X * Get mandatory capability strings. X */ X if ((T_CM = tgetstr("cm", &cp)) == NULL) X return 0; X X if ((T_EL = tgetstr("ce", &cp)) == NULL) X return 0; X X if ((T_IL = tgetstr("al", &cp)) == NULL) X return 0; X X if ((T_DL = tgetstr("dl", &cp)) == NULL) X return 0; X X if ((T_ED = tgetstr("cl", &cp)) == NULL) X return 0; X X if ((T_SC = tgetstr("sc", &cp)) == NULL) X return 0; X X if ((T_RC = tgetstr("rc", &cp)) == NULL) X return 0; X X /* X * Optional capabilities. X */ X if ((T_CI = tgetstr("vi", &cp)) == NULL) X T_CI = ""; X X if ((T_CV = tgetstr("ve", &cp)) == NULL) X T_CV = ""; X X return 1; X} X X#endif END_OF_FILE if test 1878 -ne `wc -c <'term.c'`; then echo shar: \"'term.c'\" unpacked with wrong size! fi # end of 'term.c' fi if test -f 'term.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'term.h'\" else echo shar: Extracting \"'term.h'\" \(5757 characters\) sed "s/^X//" >'term.h' <<'END_OF_FILE' X/* X * $Header: term.h,v 1.5 88/10/31 13:10:56 tony Exp $ X * X * System-dependent escape sequence definitions. X * X * $Log: term.h,v $ X * Revision 1.5 88/10/31 13:10:56 tony X * Removed text after "#endif" that some compilers complain about. X * X * Revision 1.4 88/10/29 14:06:41 tony X * Added support for termcap, if TERMCAP is defined. If not defined, the X * escape sequences are still hard-coded here. X * X * Revision 1.3 88/10/27 07:54:01 tony X * Added escape sequences for Minix-ST. X * X * Revision 1.2 88/05/03 14:39:27 tony X * Added escape sequences for DOS. X * X * Revision 1.1 88/03/21 12:04:50 tony X * Initial revision X * X * X */ X X#ifdef TERMCAP X Xextern char *T_EL; /* erase the entire current line */ Xextern char *T_IL; /* insert one line */ Xextern char *T_DL; /* delete one line */ Xextern char *T_SC; /* save the cursor position */ Xextern char *T_ED; /* erase display (may optionally home cursor) */ Xextern char *T_RC; /* restore the cursor position */ Xextern char *T_CI; /* invisible cursor (very optional) */ Xextern char *T_CV; /* visible cursor (very optional) */ X Xextern char *T_CM; /* cursor motion string */ X X#else X X/* X * This file contains the machine dependent escape sequences that X * the editor needs to perform various operations. Some of the sequences X * here are optional. Anything not available should be indicated by X * a null string. In the case of insert/delete line sequences, the X * editor checks the capability and works around the deficiency, if X * necessary. X * X * Currently, insert/delete line sequences are used for screen scrolling. X * There are lots of terminals that have 'index' and 'reverse index' X * capabilities, but no line insert/delete. For this reason, the editor X * routines s_ins() and s_del() should be modified to use 'index' X * sequences when the line to be inserted or deleted line zero. X */ X X/* X * The macro names here correspond (more or less) to the actual ANSI names X */ X X#ifdef MINIX X X#define T_EL "\033[K" /* erase the entire current line */ X#define T_IL "\033[L" /* insert one line */ X#define T_DL "\033[M" /* delete one line */ X#define T_SC "\0337" /* save the cursor position */ X#define T_ED "\033[H\033[J" /* erase display (may optionally home cursor) */ X#define T_RC "\0338" /* restore the cursor position */ X#define T_CI "" /* invisible cursor (very optional) */ X#define T_CV "" /* visible cursor (very optional) */ X X#endif X X#ifdef ATARI X#ifdef MINIX X X#define T_EL "\033[2K" /* erase the entire current line */ X#define T_IL "\033[L" /* insert one line */ X#define T_DL "\033[M" /* delete one line */ X#define T_SC "\0337" /* save the cursor position */ X#define T_ED "\033[2J" /* erase display (may optionally home cursor) */ X#define T_RC "\0338" /* restore the cursor position */ X#define T_CI "" /* invisible cursor (very optional) */ X#define T_CV "" /* visible cursor (very optional) */ X X#else X X X#define T_EL "\033l" /* erase the entire current line */ X#define T_IL "\033L" /* insert one line */ X#define T_DL "\033M" /* delete one line */ X#define T_SC "\033j" /* save the cursor position */ X#define T_ED "\033E" /* erase display (may optionally home cursor) */ X#define T_RC "\033k" /* restore the cursor position */ X#define T_CI "\033f" /* invisible cursor (very optional) */ X#define T_CV "\033e" /* visible cursor (very optional) */ X X#endif X#endif X X#ifdef UNIX X/* X * The UNIX sequences are hard-wired for ansi-like terminals. I should X * really use termcap/terminfo, but the UNIX port was done for profiling, X * not for actual use, so it wasn't worth the effort. X */ X#define T_EL "\033[2K" /* erase the entire current line */ X#define T_IL "\033[L" /* insert one line */ X#define T_DL "\033[M" /* delete one line */ X#define T_ED "\033[2J" /* erase display (may optionally home cursor) */ X#define T_SC "\0337" /* save the cursor position */ X#define T_RC "\0338" /* restore the cursor position */ X#define T_CI "" /* invisible cursor (very optional) */ X#define T_CV "" /* visible cursor (very optional) */ X#endif X X#ifdef OS2 X/* X * The OS/2 ansi console driver is pretty deficient. No insert or delete line X * sequences. The erase line sequence only erases from the cursor to the end X * of the line. For our purposes that works out okay, since the only time X * T_EL is used is when the cursor is in column 0. X * X * The insert/delete line sequences marked here are actually implemented in X * the file os2.c using direct OS/2 system calls. This makes the capability X * available for the rest of the editor via appropriate escape sequences X * passed to outstr(). X */ X#define T_EL "\033[K" /* erase the entire current line */ X#define T_IL "\033[L" /* insert one line - fake (see os2.c) */ X#define T_DL "\033[M" /* delete one line - fake (see os2.c) */ X#define T_ED "\033[2J" /* erase display (may optionally home cursor) */ X#define T_SC "\033[s" /* save the cursor position */ X#define T_RC "\033[u" /* restore the cursor position */ X#define T_CI "" /* invisible cursor (very optional) */ X#define T_CV "" /* visible cursor (very optional) */ X#endif X X#ifdef DOS X/* X * DOS sequences X * X * Some of the following sequences require the use of the "nansi.sys" X * console driver. The standard "ansi.sys" driver doesn't support X * sequences for insert/delete line. X */ X#define T_EL "\033[K" /* erase the entire current line */ X#define T_IL "\033[L" /* insert line (requires nansi.sys driver) */ X#define T_DL "\033[M" /* delete line (requires nansi.sys driver) */ X#define T_ED "\033[2J" /* erase display (may optionally home cursor) */ X#define T_SC "\033[s" /* save the cursor position */ X#define T_RC "\033[u" /* restore the cursor position */ X#define T_CI "" /* invisible cursor (very optional) */ X#define T_CV "" /* visible cursor (very optional) */ X#endif X X#endif END_OF_FILE if test 5757 -ne `wc -c <'term.h'`; then echo shar: \"'term.h'\" unpacked with wrong size! fi # end of 'term.h' fi if test -f 'undo.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'undo.c'\" else echo shar: Extracting \"'undo.c'\" \(7253 characters\) sed "s/^X//" >'undo.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: undo.c,v 1.4 88/08/26 08:45:56 tony Exp $"; X X/* X * Undo facility X * X * The routines in this file comprise a general undo facility for use X * throughout the rest of the editor. The routine u_save() is called X * before each edit operation to save the current contents of the lines X * to be editted. Later, u_undo() can be called to return those lines X * to their original state. The routine u_clear() should be called X * whenever a new file is going to be editted to clear the undo buffer. X * X * $Log: undo.c,v $ X * Revision 1.4 88/08/26 08:45:56 tony X * Misc. changes to make lint happy. X * X * Revision 1.3 88/08/17 07:38:14 tony X * Made u_save() more robust by checking for null parameters. It's up to X * the caller to notice the problem before it causes trouble elsewhere. X * X * Revision 1.2 88/07/09 20:39:11 tony X * Added routines to implement the 'U' command. X * X * Revision 1.1 88/03/20 21:10:53 tony X * Initial revision X * X */ X X#include "stevie.h" X X/* X * The next two variables mark the boundaries of the changed section X * of the file. Lines BETWEEN the lower and upper bounds are changed X * and originally contained the lines pointed to by u_lines. To undo X * the last change, insert the lines in u_lines between the lower and X * upper bounds. X */ Xstatic LINE *u_lbound = NULL; /* line just prior to first changed line */ Xstatic LINE *u_ubound = NULL; /* line just after the last changed line */ X Xstatic LINE *u_lline = NULL; /* bounds of the saved lines */ Xstatic LINE *u_uline = NULL; X Xstatic int u_col; Xstatic bool_t u_valid = FALSE; /* is the undo buffer valid */ X X/* X * Local forward declarations X */ Xstatic LINE *copyline(); Xstatic void u_lsave(); Xstatic void u_lfree(); X X/* X * u_save(l, u) - save the current contents of part of the file X * X * The lines between 'l' and 'u' are about to be changed. This routine X * saves their current contents into the undo buffer. The range l to u X * is not inclusive because when we do an open, for example, there aren't X * any lines in between. If no lines are to be saved, then l->next == u. X */ Xvoid Xu_save(l, u) XLINE *l, *u; X{ X LINE *nl; /* copy of the current line */ X X /* X * If l or u is null, there's an error. We don't return an X * indication to the caller. They should find the problem X * while trying to perform whatever edit is being requested X * (e.g. a join on the last line). X */ X if (l == NULL || u == NULL) X return; X X u_clear(); /* clear the buffer, first */ X X u_lsave(l, u); /* save to the "line undo" buffer, if needed */ X X u_lbound = l; X u_ubound = u; X X if (l->next != u) { /* there are lines in the middle */ X l = l->next; X u = u->prev; X X u_lline = nl = copyline(l); /* copy the first line */ X while (l != u) { X nl->next = copyline(l->next); X nl->next->prev = nl; X l = l->next; X nl = nl->next; X } X u_uline = nl; X } else X u_lline = u_uline = NULL; X X u_valid = TRUE; X u_col = Cursvcol; X} X X/* X * u_saveline() - save the current line in the undo buffer X */ Xvoid Xu_saveline() X{ X u_save(Curschar->linep->prev, Curschar->linep->next); X} X X/* X * u_undo() - effect an 'undo' operation X * X * The last edit is undone by restoring the modified section of the file X * to its original state. The lines we're going to trash are copied to X * the undo buffer so that even an 'undo' can be undone. Rings the bell X * if the undo buffer is empty. X */ Xvoid Xu_undo() X{ X LINE *tl, *tu; X X if (!u_valid) { X beep(); X return; X } X X /* X * Get the first line of the thing we're undoing on the screen. X */ X Curschar->linep = u_lbound->next; X Curschar->index = 0; /* for now */ X if (Curschar->linep == Fileend->linep) X Curschar->linep = Curschar->linep->prev; X cursupdate(); X X /* X * Save pointers to what's in the file now. X */ X if (u_lbound->next != u_ubound) { /* there are lines to get */ X tl = u_lbound->next; X tu = u_ubound->prev; X tl->prev = NULL; X tu->next = NULL; X } else X tl = tu = NULL; /* no lines between bounds */ X X /* X * Link the undo buffer into the right place in the file. X */ X if (u_lline != NULL) { /* there are lines in the undo buf */ X X /* X * If the top line of the screen is being undone, we need to X * fix up Topchar to point to the new line that will be there. X */ X if (u_lbound->next == Topchar->linep) X Topchar->linep = u_lline; X X u_lbound->next = u_lline; X u_lline->prev = u_lbound; X u_ubound->prev = u_uline; X u_uline->next = u_ubound; X } else { /* no lines... link the bounds */ X if (u_lbound->next == Topchar->linep) X Topchar->linep = u_ubound; X if (u_lbound == Filetop->linep) X Topchar->linep = u_ubound; X X u_lbound->next = u_ubound; X u_ubound->prev = u_lbound; X } X X /* X * If we swapped the top line, patch up Filemem appropriately. X */ X if (u_lbound == Filetop->linep) X Filemem->linep = Filetop->linep->next; X X /* X * Now save the old stuff in the undo buffer. X */ X u_lline = tl; X u_uline = tu; X X renum(); /* have to renumber everything */ X X /* X * Put the cursor on the first line of the 'undo' region. X */ X Curschar->linep = u_lbound->next; X Curschar->index = 0; X if (Curschar->linep == Fileend->linep) X Curschar->linep = Curschar->linep->prev; X *Curschar = *coladvance(Curschar, u_col); X cursupdate(); X updatescreen(); /* now show the change */ X X u_lfree(); /* clear the "line undo" buffer */ X} X X/* X * u_clear() - clear the undo buffer X * X * This routine is called to clear the undo buffer at times when the X * pointers are about to become invalid, such as when a new file is X * about to be editted. X */ Xvoid Xu_clear() X{ X LINE *l, *nextl; X X if (!u_valid) /* nothing to do */ X return; X X for (l = u_lline; l != NULL ;l = nextl) { X nextl = l->next; X free(l->s); X free(l); X } X X u_lbound = u_ubound = u_lline = u_uline = NULL; X u_valid = FALSE; X} X X/* X * The following functions and data implement the "line undo" feature X * performed by the 'U' command. X */ X Xstatic LINE *u_line; /* pointer to the line we last saved */ Xstatic LINE *u_lcopy = NULL; /* local copy of the original line */ X X/* X * u_lfree() - free the line save buffer X */ Xstatic void Xu_lfree() X{ X if (u_lcopy != NULL) { X free(u_lcopy->s); X free(u_lcopy); X u_lcopy = NULL; X } X u_line = NULL; X} X X/* X * u_lsave() - save the current line if necessary X */ Xstatic void Xu_lsave(l, u) XLINE *l, *u; X{ X X if (l->next != u->prev) { /* not changing exactly one line */ X u_lfree(); X return; X } X X if (l->next == u_line) /* more edits on the same line */ X return; X X u_lfree(); X u_line = l->next; X u_lcopy = copyline(l->next); X} X X/* X * u_lundo() - undo the current line (the 'U' command) X */ Xvoid Xu_lundo() X{ X if (u_lcopy != NULL) { X free(Curschar->linep->s); X Curschar->linep->s = u_lcopy->s; X Curschar->linep->size = u_lcopy->size; X free(u_lcopy); X } else X beep(); X Curschar->index = 0; X X cursupdate(); X updatescreen(); /* now show the change */ X X u_lcopy = NULL; /* can't undo this kind of undo */ X u_line = NULL; X} X X/* X * u_lcheck() - clear the "line undo" buffer if we've moved to a new line X */ Xvoid Xu_lcheck() X{ X if (Curschar->linep != u_line) X u_lfree(); X} X X/* X * copyline(l) - copy the given line, and return a pointer to the copy X */ Xstatic LINE * Xcopyline(l) XLINE *l; X{ X LINE *nl; /* the new line */ X X nl = newline(strlen(l->s) + 1); X strcpy(nl->s, l->s); X X return nl; X} END_OF_FILE if test 7253 -ne `wc -c <'undo.c'`; then echo shar: \"'undo.c'\" unpacked with wrong size! fi # end of 'undo.c' fi if test -f 'unix.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'unix.c'\" else echo shar: Extracting \"'unix.c'\" \(3697 characters\) sed "s/^X//" >'unix.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: unix.c,v 1.5 88/10/31 13:11:03 tony Exp $"; X X/* X * System-dependent routines for UNIX System V or Berkeley. X * X * $Log: unix.c,v $ X * Revision 1.5 88/10/31 13:11:03 tony X * Added code (optional) to support the use of termcap. X * X * Revision 1.4 88/10/27 08:16:52 tony X * Added doshell() to support ":sh" and ":!". X * X * Revision 1.3 88/10/06 10:14:36 tony X * Added fixname() routine, which does nothing under UNIX. X * X * Revision 1.2 88/06/20 14:51:36 tony X * Merged in changes for BSD Unix sent in by Michael Lichter. X * X * Revision 1.1 88/03/20 21:11:02 tony X * Initial revision X * X * X */ X X#include "stevie.h" X#ifdef BSD X#include <sgtty.h> X#else X#include <termio.h> X#endif X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X char c; X X flushbuf(); /* flush any pending output */ X X do { X while (read(0, &c, 1) != 1) X ; X } while (c == NUL); X X return c; X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xvoid Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xregister char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X Xvoid Xoutstr(s) Xregister char *s; X{ X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X outone('\007'); X} X X/* X * remove(file) - remove a file X */ Xvoid Xremove(file) Xchar *file; X{ X unlink(file); X} X X/* X * rename(of, nf) - rename existing file 'of' to 'nf' X */ Xvoid Xrename(of, nf) Xchar *of, *nf; X{ X unlink(nf); X link(of, nf); X unlink(of); X} X Xvoid Xdelay() X{ X /* not implemented */ X} X X#ifdef BSD Xstatic struct sgttyb ostate; X#else Xstatic struct termio ostate; X#endif X X/* X * Go into cbreak mode X */ Xvoid Xset_tty() X{ X#ifdef BSD X struct sgttyb nstate; X X ioctl(0, TIOCGETP, &ostate); X nstate = ostate; X nstate.sg_flags &= ~(XTABS|CRMOD|ECHO); X nstate.sg_flags |= CBREAK; X ioctl(0, TIOCSETN, &nstate); X#else X struct termio nstate; X X ioctl(0, TCGETA, &ostate); X nstate = ostate; X nstate.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); X nstate.c_cc[VMIN] = 1; X nstate.c_cc[VTIME] = 0; X ioctl(0, TCSETAW, &nstate); X#endif X} X X/* X * Restore original terminal modes X */ Xvoid Xreset_tty() X{ X#ifdef BSD X ioctl(0, TIOCSETP, &ostate); X#else X ioctl(0, TCSETAW, &ostate); X#endif X} X Xvoid Xwindinit() X{ X#ifdef TERMCAP X if (t_init() != 1) { X fprintf(stderr, "unknown terminal type\n"); X exit(1); X } X#else X Columns = 80; X P(P_LI) = Rows = 24; X#endif X X set_tty(); X} X Xvoid Xwindexit(r) Xint r; X{ X reset_tty(); X exit(r); X} X X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X#ifdef TERMCAP X char *tgoto(); X#else X r += 1; X c += 1; X#endif X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X#ifdef TERMCAP X outstr(tgoto(T_CM, c, r)); X#else X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X#endif X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X return fopen(fname, mode); X} X Xchar * Xfixname(s) Xchar *s; X{ X return s; X} X X/* X * doshell() - run a command or an interactive shell X */ Xvoid Xdoshell(cmd) Xchar *cmd; X{ X char *cp, *getenv(); X char cline[128]; X X outstr("\r\n"); X flushbuf(); X X if (cmd == NULL) { X if ((cmd = getenv("SHELL")) == NULL) X cmd = "/bin/sh"; X sprintf(cline, "%s -i", cmd); X cmd = cline; X } X X reset_tty(); X system(cmd); X set_tty(); X X wait_return(); X} END_OF_FILE if test 3697 -ne `wc -c <'unix.c'`; then echo shar: \"'unix.c'\" unpacked with wrong size! fi # end of 'unix.c' fi if test -f 'version.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'version.c'\" else echo shar: Extracting \"'version.c'\" \(7218 characters\) sed "s/^X//" >'version.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: version.c,v 3.45 88/11/10 09:00:06 tony Exp $"; X X/* X * Contains the declaration of the global version number variable. X * X * changes by Robert Regn: X * Tue Nov 29 12:12:10 MET 1988 X * Better handling of Read/only files X * preserving link structure and modes X * recognizes % in cmdline - better algorithm for # also X * edit an empty file is now possible X * restore tty if the file to edit is too big X * if writeit in :w fails, :q is not further possible X * X * $Log: version.c,v $ X * Revision 3.45 88/11/10 09:00:06 tony X * Added support for mode lines. Strings like "vi:stuff:" or "ex:stuff:" X * occurring in the first or last 5 lines of a file cause the editor to X * pretend that "stuff" was types as a colon command. This examination X * is done only if the parameter "modelines" (or "ml") is set. This is X * not enabled, by default, because of the security implications involved. X * X * Revision 3.44 88/11/01 21:34:11 tony X * Fixed a couple of minor points for Minix, and improved the speed of X * the 'put' command dramatically. X * X * Revision 3.43 88/10/31 13:11:33 tony X * Added optional support for termcap. Initialization is done in term.c X * and also affects the system-dependent files. To enable termcap in those X * environments that support it, define the symbol "TERMCAP" in env.h X * X * Revision 3.42 88/10/27 18:30:19 tony X * Removed support for Megamax. Added '%' as an alias for '1,$'. Made the X * 'r' command more robust. Now prints the string on repeated searches. X * The ':=" command now works. Some pointer operations are now safer. X * The ":!" and ":sh" now work correctly. Re-organized the help screens X * a little. X * X * Revision 3.41 88/10/06 10:15:00 tony X * Fixed a bug involving ^Y that occurs when the cursor is on the last X * line, and the line above the screen is long. Also hacked up fileio.c X * to pass pathnames off to fixname() for system-dependent processing. X * Used under DOS & OS/2 to trim parts of the name appropriately. X * X * Revision 3.40 88/09/16 08:37:36 tony X * No longer beeps when repeated searches fail. X * X * Revision 3.39 88/09/06 06:51:07 tony X * Fixed a bug with shifts that was introduced when replace mode was added. X * X * Revision 3.38 88/08/31 20:48:28 tony X * Made another fix in search.c related to repeated searches. X * X * Revision 3.37 88/08/30 20:37:16 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 3.36 88/08/26 13:46:34 tony X * Added support for the '!' (filter) operator. X * X * Revision 3.35 88/08/26 08:46:01 tony X * Misc. changes to make lint happy. X * X * Revision 3.34 88/08/25 15:13:36 tony X * Fixed a bug where the cursor didn't land on the right place after X * "beginning-of-word" searches if the word was preceded by the start X * of the line and a single character. X * X * Revision 3.33 88/08/23 12:53:08 tony X * Fixed a bug in ssearch() where repeated searches ('n' or 'N') resulted X * in dynamic memory being referenced after it was freed. X * X * Revision 3.32 88/08/17 07:37:07 tony X * Fixed a general problem in u_save() by checking both parameters for X * null values. The specific symptom was that a join on the last line of X * the file would crash the editor. X * X * Revision 3.31 88/07/09 20:39:38 tony X * Implemented the "line undo" command (i.e. 'U'). X * X * Revision 3.30 88/06/28 07:54:22 tony X * Fixed a bug involving redo's of the '~' command. The redo would just X * repeat the replacement last performed instead of switching the case of X * the current character. X * X * Revision 3.29 88/06/26 14:53:19 tony X * Added support for a simple form of the "global" command. It supports X * commands of the form "g/pat/d" or "g/pat/p", to delete or print lines X * that match the given pattern. A range spec may be used to limit the X * lines to be searched. X * X * Revision 3.28 88/06/25 21:44:22 tony X * Fixed a problem in the processing of colon commands that caused X * substitutions of patterns containing white space to fail. X * X * Revision 3.27 88/06/20 14:52:21 tony X * Merged in changes for BSD Unix sent in by Michael Lichter. X * X * Revision 3.26 88/06/10 13:44:06 tony X * Fixed a bug involving writing out files with long pathnames. A small X * fixed size buffer was being used. The space for the backup file name X * is now allocated dynamically. X * X * Revision 3.25 88/05/04 08:29:02 tony X * Fixed a minor incompatibility with vi involving the 'G' command. Also X * changed the RCS version number of version.c to match the actual version X * of the editor. X * X * Revision 1.12 88/05/03 14:39:52 tony X * Changed the screen representation of the ascii character DELETE to be X * compatible with vi. Also merged in support for DOS. X * X * Revision 1.11 88/05/02 21:38:21 tony X * The code that reads files now handles boundary/error conditions much X * better, and generates status/error messages that are compatible with X * the real vi. Also fixed a bug in repeated reverse searches that got X * inserted in the recent changes to search.c. X * X * Revision 1.10 88/05/02 07:35:41 tony X * Fixed a bug in the routine plines() that was introduced during changes X * made for the last version. X * X * Revision 1.9 88/05/01 20:10:19 tony X * Fixed some problems with auto-indent, and added support for the "number" X * parameter. X * X * Revision 1.8 88/04/30 20:00:49 tony X * Added support for the auto-indent feature. X * X * Revision 1.7 88/04/29 14:50:11 tony X * Fixed a class of bugs involving commands like "ct)" where the cursor X * motion part of the operator can fail. If the motion failed, the operator X * was continued, with the cursor position unchanged. Cases like this were X * modified to abort the operation if the motion fails. X * X * Revision 1.6 88/04/28 08:19:35 tony X * Modified Henry Spencer's regular expression library to support new X * features that couldn't be done easily with the existing interface. X * This code is now a direct part of the editor source code. The editor X * now supports the "ignorecase" parameter, and multiple substitutions X * per line, as in "1,$s/foo/bar/g". X * X * Revision 1.5 88/04/24 21:38:00 tony X * Added preliminary support for the substitute command. Full range specs. X * are supported, but only a single substitution is allowed on each line. X * X * Revision 1.4 88/04/23 20:41:01 tony X * Worked around a problem with adding lines to the end of the buffer when X * the cursor is at the bottom of the screen (in misccmds.c). Also fixed a X * bug that caused reverse searches from the start of the file to bomb. X * X * Revision 1.3 88/03/24 08:57:00 tony X * Fixed a bug in cmdline() that had to do with backspacing out of colon X * commands or searches. Searches were okay, but colon commands backed out X * one backspace too early. X * X * Revision 1.2 88/03/21 16:47:55 tony X * Fixed a bug in renum() causing problems with large files (>6400 lines). X * Also moved system-specific defines out of stevie.h and into a new file X * named env.h. This keeps volatile information outside the scope of RCS. X * X * Revision 1.1 88/03/20 21:00:39 tony X * Initial revision X * X */ X Xchar *Version = "STEVIE - Version 3.45"; END_OF_FILE if test 7218 -ne `wc -c <'version.c'`; then echo shar: \"'version.c'\" unpacked with wrong size! fi # end of 'version.c' fi if test -f 'tos_c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tos_c'\" else echo shar: Extracting \"'tos_c'\" \(7273 characters\) sed "s/^X//" >'tos_c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: tos.c,v 1.3 88/10/27 08:18:07 tony Exp $"; X X/* X * System-dependent routines for the Atari ST. X * X * $Log: tos.c,v $ X * Revision 1.3 88/10/27 08:18:07 tony X * Added a null flushbuf() for compatibility with versions that buffer X * output. Added fixname() to do appropriate name truncation. Added X * a quick doshell() that supports commands, but not interactive shells. X * Removed support for Megamax. X * X * Revision 1.2 88/09/23 19:35:44 tony X * Added mktemp() for use with the '!' operator. Also added support for X * the Sozobon C compiler. X * X * Revision 1.1 88/03/20 21:10:42 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X#include <osbind.h> X X/* X * The following buffer is used to work around a bug in TOS. It appears that X * unread console input can cause a crash, but only if console output is X * going on. The solution is to always grab any unread input before putting X * out a character. The following buffer holds any characters read in this X * fashion. The problem can be easily produced because STEVIE can't yet keep X * up with the normal auto-repeat rate in insert mode. X */ X#define IBUFSZ 128 X Xstatic long inbuf[IBUFSZ]; /* buffer for unread input */ Xstatic long *inptr = inbuf; /* where to put next character */ X X/* X * inchar() - get a character from the keyboard X * X * Certain special keys are mapped to values above 0x80. These X * mappings are defined in keymap.h. If the key has a non-zero X * ascii value, it is simply returned. Otherwise it may be a X * special key we want to map. X * X * The ST has a bug involving keyboard input that seems to occur X * when typing quickly, especially typing capital letters. Sometimes X * a value of 0x02540000 is read. This doesn't correspond to anything X * on the keyboard, according to my documentation. My solution is to X * loop when any unknown key is seen. Normally, the bell is rung to X * indicate the error. If the "bug" value is seen, we ignore it completely. X */ Xint Xinchar() X{ X for (;;) { X long c, *p; X X /* X * Get the next input character, either from the input X * buffer or directly from TOS. X */ X if (inptr != inbuf) { /* input in the buffer, use it */ X c = inbuf[0]; X /* X * Shift everything else in the buffer down. This X * would be cleaner if we used a circular buffer, X * but it really isn't worth it. X */ X inptr--; X for (p = inbuf; p < inptr ;p++) X *p = *(p+1); X } else X c = Crawcin(); X X if ((c & 0xff) != 0) X return ((int) c); X X switch ((int) (c >> 16) & 0xff) { X X case 0x62: return K_HELP; X case 0x61: return K_UNDO; X case 0x52: return K_INSERT; X case 0x47: return K_HOME; X case 0x48: return K_UARROW; X case 0x50: return K_DARROW; X case 0x4b: return K_LARROW; X case 0x4d: return K_RARROW; X case 0x29: return K_CGRAVE; /* control grave accent */ X X /* X * Occurs due to a bug in TOS. X */ X case 0x54: X break; X /* X * Add the function keys here later if we put in support X * for macros. X */ X X default: X beep(); X break; X X } X } X} X X/* X * get_inchars - snarf away any pending console input X * X * If the buffer overflows, we discard what's left and ring the bell. X */ Xstatic void Xget_inchars() X{ X while (Cconis()) { X if (inptr >= &inbuf[IBUFSZ]) { /* no room in buffer? */ X Crawcin(); /* discard the input */ X beep(); /* and sound the alarm */ X } else X *inptr++ = Crawcin(); X } X} X Xvoid Xoutchar(c) Xchar c; X{ X get_inchars(); X Cconout(c); X} X Xvoid Xoutstr(s) Xregister char *s; X{ X get_inchars(); X Cconws(s); X} X X/* X * flushbuf() - a no-op for TOS X */ Xvoid Xflushbuf() X{ X} X X#define BGND 0 X#define TEXT 3 X X/* X * vbeep() - visual bell X */ Xstatic void Xvbeep() X{ X int text, bgnd; /* text and background colors */ X long l; X X text = Setcolor(TEXT, -1); X bgnd = Setcolor(BGND, -1); X X Setcolor(TEXT, bgnd); /* swap colors */ X Setcolor(BGND, text); X X for (l=0; l < 5000 ;l++) /* short pause */ X ; X X Setcolor(TEXT, text); /* restore colors */ X Setcolor(BGND, bgnd); X} X Xvoid Xbeep() X{ X if (P(P_VB)) X vbeep(); X else X outchar('\007'); X} X X/* X * remove(file) - remove a file X */ Xvoid Xremove(file) Xchar *file; X{ X Fdelete(file); X} X X/* X * rename(of, nf) - rename existing file 'of' to 'nf' X */ Xvoid Xrename(of, nf) Xchar *of, *nf; X{ X Fdelete(nf); /* if 'nf' exists, remove it */ X Frename(0, of, nf); X} X Xvoid Xwindinit() X{ X if (Getrez() == 0) X Columns = 40; /* low resolution */ X else X Columns = 80; /* medium or high */ X X P(P_LI) = Rows = 25; X X Cursconf(1,NULL); X} X Xvoid Xwindexit(r) Xint r; X{ X exit(r); X} X Xvoid Xwindgoto(r, c) Xint r, c; X{ X outstr("\033Y"); X outchar(r + 040); X outchar(c + 040); X} X X/* X * System calls or library routines missing in TOS. X */ X Xvoid Xsleep(n) Xint n; X{ X int k; X X k = Tgettime(); X while ( Tgettime() <= k+n ) X ; X} X Xvoid Xdelay() X{ X long n; X X for (n = 0; n < 8000 ;n++) X ; X} X Xint Xsystem(cmd) Xchar *cmd; X{ X char arg[1]; X X arg[0] = (char) 0; /* no arguments passed to the shell */ X X if (Pexec(0, cmd, arg, 0L) < 0) X return -1; X else X return 0; X} X X#ifdef SOZOBON X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X char modestr[10]; X X sprintf(modestr, "%sb", mode); X X return fopen(fname, modestr); X} X X#endif X X#ifndef SOZOBON X/* X * getenv() - get a string from the environment X * X * Both Alcyon and Megamax are missing getenv(). This routine works for X * both compilers and with the Beckemeyer and Gulam shells. With gulam, X * the env_style variable should be set to either "mw" or "gu". X */ Xchar * Xgetenv(name) Xchar *name; X{ X extern long _base; X char *envp, *p; X X envp = *((char **) (_base + 0x2c)); X X for (; *envp ;envp += strlen(envp)+1) { X if (strncmp(envp, name, strlen(name)) == 0) { X p = envp + strlen(name); X if (*p++ == '=') X return p; X } X } X return (char *) 0; X} X#endif X X/* X * mktemp() - quick hack since there isn't one here X */ Xchar * Xmktemp(name) Xchar *name; X{ X int num; /* pasted into the string to make it unique */ X char cbuf[7]; X char *s; /* where the X's start in name */ X int fd; X X if ((s = strchr(name, 'X')) == NULL) /* needs to be an X */ X return (char *) NULL; X X if (strlen(s) != 6) /* should be 6 X's */ X return (char *) NULL; X X for (num = 0; num < 1000 ;num++) { X sprintf(cbuf, "%06d", num); X strcpy(s, cbuf); X if ((fd = open(name, 0)) < 0) X return name; X close(fd); X } X return (char *) NULL; X} X Xvoid Xdoshell(cmd) Xchar *cmd; X{ X if (cmd == NULL) { X emsg("Sorry, no interactive shell"); X return; X } X system(cmd); X wait_return(); X} X X#define PSIZE 128 X X/* X * fixname(s) - fix up a dos name X * X * Takes a name like: X * X * \x\y\z\base.ext X * X * and trims 'base' to 8 characters, and 'ext' to 3. X */ Xchar * Xfixname(s) Xchar *s; X{ X char *strchr(), *strrchr(); X static char f[PSIZE]; X char base[32]; X char ext[32]; X char *p; X int i; X X strcpy(f, s); X X for (i=0; i < PSIZE ;i++) X if (f[i] == '/') X f[i] = '\\'; X X /* X * Split the name into directory, base, extension. X */ X if ((p = strrchr(f, '\\')) != NULL) { X strcpy(base, p+1); X p[1] = '\0'; X } else { X strcpy(base, f); X f[0] = '\0'; X } X X if ((p = strchr(base, '.')) != NULL) { X strcpy(ext, p+1); X *p = '\0'; X } else X ext[0] = '\0'; X X /* X * Trim the base name if necessary. X */ X if (strlen(base) > 8) X base[8] = '\0'; X X if (strlen(ext) > 3) X ext[3] = '\0'; X X /* X * Paste it all back together X */ X strcat(f, base); X strcat(f, "."); X strcat(f, ext); X X return f; X} END_OF_FILE if test 7273 -ne `wc -c <'tos_c'`; then echo shar: \"'tos_c'\" unpacked with wrong size! fi # end of 'tos_c' fi echo shar: End of shell archive. exit 0