mh@roger.imsd.contel.com (Mike H.) (01/11/91)
The following postings in comp.windows.news are modifications I made to version 1.4 of elvis to run under the NeWS toolkit (tNt). If you are not familiar with elvis it is a vi clone written by Steve Kirkendall it's much better than stevie and the various wimply emacs vi emulators so I suggest giving it a shot if you are a vi fan. Although I intend to make some more additions to the elvis I am at the point now where I'm going to stop for a bit until I get the new version of tNt. As a result I figured I'd post what I've got at the moment since this newsgroup has been extremely dead lately. What exists now works well but does'nt have much in the way of neat 'window' things in it yet. I does however have some fixes for the more annoying things present in the stock 1.4 version fixed. See the change notes file in the following postings for more info on that subject. I did not include the doc directory normally found in the elvis release. you can get that from the stock version of elvis 1.4 which can be had in the gnu ftp directory on prep.ai.mit.edu. Elvis 1.4 was also posted to alt.sources awhile back by the author so if you know where an alt.sources archive is you can get the docs there also. p.s. - If anybody adds any neat things let me know. I'd love to have them. Also, Josh Siegel at sun was kind enough to make mods to this version of elvis to work under the new version of tNt. If there is a demand for those mods i'll post those too. mike hoegeman, mh@roger.imsd.contel.com
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # elvis.ps # elvis_cps.cps # This archive created: Thu Jan 10 17:21:05 1991 export PATH; PATH=/bin:$PATH if test -f 'elvis.ps' then echo shar: will not over-write existing file "'elvis.ps'" else cat << \SHAR_EOF > 'elvis.ps' % % NeWS postscript machinery for the elvis editor % Author: Mike Hoegeman, mh@wlbr.imsd.contel.com % systemdict dup /ElvisCanvas known %% pop false { pop } { ClassCanvas dictbegin /StandOut? false def /OldCursor? false def /CursorEnabled? true def /CursorX 0 def /CursorY 0 def /BoldTextColor ColorDict /Black get def /TextDescent 0 def dictend classbegin % Class Variables: % Defaults: % TO BE DONE: chances are there is a way to install a key mapping directly % into the interest /ElvisKeyDict dictbegin 0 1 256 { dup def } for 127 8 def % remap delete to backspace dictend def /LeftMargin 0 def /OrigMatrix null def % Bug extrordinaire , only non scalable fonts work!! % I really have to fix this /TextFamily /7x14 def /TextSize 13 def /TextSpacing 0 def /SavedTextColor null def % Methods: /oldcursor { /OldCursor? exch def } def /settextstuff { /TextDescent TextFont fontdescent def } def /newinit { /newinit super send /SavedTextColor TextColor def /FillColor FillColor promote /TextColor TextColor promote } def /validate { /resetscale self send /validate super send } def % (lifted from psterm, this stuff should be redone) % We have some nasty code here that tries to save the % canvas' original matrix. The default canvas matrix will % be altered by resetscale and we need to restore it before % we can recalculate the new scale factors. % /reshape { % x y w h => - OrigMatrix null ne { gsave Canvas setcanvas OrigMatrix setmatrix clippath Canvas reshapecanvas grestore } if % adjust height to be even number of rows of text... TextFont fontheight TextSpacing add div truncate TextFont fontheight TextSpacing add mul % do likewise for the columns exch WidthScale div truncate WidthScale mul exch /reshape super send % tell the C side a reshape has occured % damage repainting will ensue on it's own gsave MyScale ElvisResizeTag tagprint size typedprint typedprint grestore /OrigMatrix matrix currentmatrix promote /invalidate self send } def /WidthScale { TextFont setfont (W) stringwidth pop } def /MyScale { WidthScale TextFont fontheight TextSpacing add neg scale } def /resetscale { gsave Canvas setcanvas OrigMatrix null ne { OrigMatrix setmatrix } if % flip clippath pathbbox 0 exch TextFont fontheight sub TextSpacing sub translate pop pop pop MyScale settextstuff LeftMargin 0 translate newpath clippath Canvas reshapecanvas grestore } def % display (string) % /ST { % (string) => - HideCursor Canvas setcanvas % blank out old string CursorX CursorY moveto dup length -1 rect FillColor setcolor fill % paint string CursorX CursorY TextDescent sub moveto TextColor setcolor TextFont setfont show currentpoint TextDescent add cm } def /HideCursor { % unpaint any previous cursor OldCursor? { gsave 5 setrasteropcode CursorX CursorY 2 copy moveto CursorPath fill moveto grestore } if false oldcursor } def %% cursorshape change commands /cpathset { HideCursor /CursorPath exch load promote CursorX CursorY cm } def % /CursorPath { 1 -1 rect } def % normal cursor shape /cQ { /cQpath cpathset } def /cQpath { 1 -1 rect } def % when in command mode shape /cV { cQ } def % ex command line cursor shape /cX { /cXpath cpathset } def /cXpath { 1 -.2 rect } def % input mode cursor shape /cI { /cIpath cpathset } def /cIpath { -.2 .2 rmoveto -.5 0 rlineto .5 -.5 rlineto .5 .5 rlineto closepath } def % replace mode cursor shape /cR { cI } def /cm { % x y => - CursorEnabled? { currentrasteropcode 3 1 roll 5 setrasteropcode % unpaint any previous cursor OldCursor? { CursorX CursorY moveto CursorPath fill } if % move caret 2 copy /CursorY exch def /CursorX exch def moveto % turn caret on currentpoint moveto CursorPath fill true oldcursor setrasteropcode } { % move caret 2 copy /CursorY exch def /CursorX exch def moveto } ifelse } def % % termcap primitives % % begin standout mode % /so { TextColor FillColor /TextColor exch promote /FillColor exch promote } def % end standout mode % /se { so } def % start/end underline mode % /us { so } def /ue { se } def % start/end bold text mode % /VB { so } def /Vb { se } def /bc { CursorX 1 sub 0 max CursorY cm } def /Cr { 0 CursorY cm } def /Nl { CursorY Height 1 sub ge { % we have gone below the scroll area % scroll everything up a line.. 0 0 moveto Width Height 1 sub rect 0 -1 copyarea % .. and clear out the garbage at the bottom. % we don't have to worry about the cursor cause it's % in the garbage area (unless it's a mighty bizarre cursor!) false oldcursor 0 Height moveto Width LeftMargin sub -2 rect FillColor setcolor fill CursorX CursorY cm } { CursorX CursorY 1 add cm } ifelse } def /RSR { % scroll window up dup % => lines lines 0 CursorY moveto Width Height neg rect % => lines lines 0 exch neg copyarea % => lines % blank out invalid stuff at bottom % => lines 0 CursorY moveto Width LeftMargin sub exch neg rect % => - FillColor setcolor fill } def /CrNl { /CursorX 0 def Nl } def % upline (cursor up) % /up { CursorX CursorY 1 sub cm } def % visual bell (must not move the cursor) % /vb { gsave 5 setrasteropcode fill pause pause fill grestore } def % scroll down % /sr { 1 SR } def % block version of sr % /SR { % number_of_lines_to_scroll_down => - false oldcursor dup gsave % do the scroll, more than needed Height wise but so what 0 CursorY 1 sub moveto Width Height rect 0 exch copyarea % blank out the area we vacated with the scroll 0 CursorY 1 sub moveto Width LeftMargin sub exch rect FillColor setcolor fill grestore } def % clear to end of line % /ce { false oldcursor CursorX CursorY 2 copy moveto Width CursorX LeftMargin add sub -1 rect FillColor setcolor fill cm } def % make cursor appear normal (undo vs/vi) % /ve { true EC } def % make cursor invisible % /vi { false EC } def % (Dis)/(En)able cursor % /EC { dup CursorEnabled? eq { pop } { dup { % enable , turn cursor on % we can just do this with an in place move cursor /CursorEnabled? exch def CursorX CursorY cm } { % disable , turn cursor off HideCursor /CursorEnabled? exch def } ifelse } ifelse } def /KeyBoard { /ElvisKeyTag where { pop /Name get ElvisKeyDict exch get %% dup (% key\n) exch mark exch ] dbgprintf dup type /nametype eq { self send } { ElvisKeyTag tagprint typedprint } ifelse } { } ifelse } def /MakeInterests { /MakeInterests super send /KeyBoard self soften buildsend Canvas /defaultkeys ClassKeysInterest send } def /PaintCanvas { % - => - ElvisDamageTag tagprint flush } def /minsize { % - => w h /minsize super send 128 max exch 128 max exch } def /preferredsize { % - => width height gsave /canvas self send setcanvas WidthScale 80 mul TextFont fontheight TextSpacing add 44 mul grestore } def classend /ElvisCanvas exch put } ifelse systemdict dup /ElvisFrame known %% pop false { pop } { /defaultclass ClassBaseFrame send [] classbegin /FooterFraction .99 def % fraction of how much footer is used for % the left footer /destroyfromuser { ElvisDestroyTag tagprint flush % /destroyfromuser super send } def classend /ElvisFrame exch put } ifelse % create a window /win [ElvisCanvas] [/Footer true] framebuffer /new ElvisFrame send def /C /client win send soften def C setcanvas (Elvis) /setlabel win send [/place /activate] { win send } forall /S { send } def 0 0 /cm C S (Elvis) /setlabel win send currentprocess cvx /ProcessName (Elvis) put /map win send pause %newprocessgroup currentfile closefile SHAR_EOF fi # end of overwriting check if test -f 'elvis_cps.cps' then echo shar: will not over-write existing file "'elvis_cps.cps'" else cat << \SHAR_EOF > 'elvis_cps.cps' % % elvis_cps.cps % #define GET_DIMEN_TAG 10 % include the tags such that both cps code inthis file and c code % eleswhere can use them cdef ps_RunFile(string file_name) file_name run cdef ps_RegisterTag(string tag_name, tag_value) tag_name cvn tag_value def cdef ps_ST(cstring str) str /ST C S cdef ps_scroll_down(int lines) lines /SR C S cdef ps_pswrite(cpostscript source_code) source_code cdef ps_Cr() /Cr C S cdef ps_Nl() /Nl C S cdef ps_CrNl() /CrNl C S cdef ps_beep() beep pause cdef ps_enable_cursor() /ve C S cdef ps_disable_cursor() /vi C S cdef ps_rendermsg(string msg) msg null /setfooter win send cdef ps_appendmsg(string old, string new) old new append null /setfooter win send cdef ps_set_title(string title) title /setlabel win send %% so you can recognize the postscript half of elvis via 'psps' currentprocess cvx /ProcessName (Elvis-) title append put title /setlabel /Icon /sendsubframe win send cdef ps_get_lines_and_cols(int lines, int cols) => GET_DIMEN_TAG(lines, cols) { GET_DIMEN_TAG tagprint Height typedprint Width typedprint flush } C send SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # CHANGE_NOTES # Makefile # Makefile.mix # config.h # curses.h # elvis_cps.h # osk.h # regexp.h # vi.h # wconfig.h # This archive created: Thu Jan 10 17:21:06 1991 export PATH; PATH=/bin:$PATH if test -f 'CHANGE_NOTES' then echo shar: will not over-write existing file "'CHANGE_NOTES'" else cat << \SHAR_EOF > 'CHANGE_NOTES' Mike Hoegeman's change log, this is not gospel of every single change i made Dec 7 00:00 - date of my copy of elvis version 1.4 ***BUG*** -rw------- 1 mh 16474 Dec 20 20:39 input.c -rw------- 1 mh 13527 Dec 20 20:47 vcmd.c added indentref arg to input(). this is so autoindent works right with the 'O' command. I don't know about anybody else but for me this *has* to work like the standard vi since i use it constantly. ***BUG*** ***BUG*** -rw------- 1 mh 20109 Dec 20 23:14 redraw.c A bug (i put a hack in to work around it. see the /* HACK */ comment) To exercise the bug do the following. - move cursor to a line not at the top or bottom of the screen - make a change (like add a couples of X's at the beginning) - hit '-' to move the cursor up one line - hit 'dd' (it's more obvious if the line you dd is blank) notice that the line the cursor is on is displaying the old deleted line it looks like smartlno is not getting readjusted properly ***BUG*** -rw-r--r-- 1 mh 7618 Dec 20 10:01 elvis.ps Various futzing to get ps file closer to using scalable fonts misc minor tweaks -rw-r--r-- 1 mh 1652 Dec 19 13:38 elvismug.im1 elvismug.im1 is a sun raster format file that has a rather grainy picture of elvis. will use this for icon image when i get around to it. it would be nice to get a better picture. this one came from the pbm package bitmaps. It might look pretty good in color/grayscale. -rw-r--r-- 1 mh 1015 Dec 19 13:03 elvis_cps.cps elvis_cps.cps file mod to get filename on icon. ***BUG*** -rw-r--r-- 1 mh 25955 Dec 20 17:25 Makefile -rw-r--r-- 1 mh 2525 Dec 20 17:23 tnamerec.c -rw------- 1 mh 5248 Dec 20 17:10 virec.c -rw------- 1 mh 8195 Jan 1 15:50 config.h -rw------- 1 mh 12876 Dec 20 13:00 tmp.c Modified tmp.c virec.c config.h and added module tnamerec.c to allow editing multiple instances of the same file at once. May want to just put tnamerec.c into virec.c since that is the only place it is used. The temp file name now has the pid of the process added on to the end with a '-' in front of it (see TMPNAME in config.h). Also changed the tmpfile prefix from elv to El so that a filename would still fit in 14 chars (for sysV). see tnamerec.c for how virec handles this change. Added tnamerec to Makefile of course. note that this won't work for DOG, etc.. but there are suitable ifdefs to make it backwards compatible for those unfortunates. ***BUG*** -rw------- 1 mh 20089 Dec 20 22:23 redraw.c replaced constant 5 in nudgecursor() with macro NUDGE_COST because a move is always cheaper in PostScript than a string display. this will also allow other ports to define their NUDGE_COST's. should this be put in (w)config.h ?? -rw------- 1 mh 8026 Dec 21 12:56 main.c -rw-r--r-- 1 mh 2353 Dec 21 15:06 wconfig.h -rw------- 1 mh 13569 Dec 21 15:05 ow.c Added Customflags() macro to main(), this is to allow custom version of elvis to process any version specific flags without having to clutter up the standard elvis code with ifdefs's. in wconfig.h the macro is defined to a no-op for the standard tty version of elvis. for the openwindows version Customflags() is defined to be ow_customflags in ow.c. ow_customflags() is a good reference for someone wanting to make their own Customflags() function. -rw------- 1 mh 13569 Dec 21 15:05 ow.c -rw------- 1 mh 20227 Dec 21 14:57 redraw.c -rw-r--r-- 1 mh 2353 Dec 21 15:06 wconfig.h Made final fixes to ow termcap modules to switch to using the standard termcap functions if no server is running the Ow.tty global determines which display style to use. Rearranged various ow related globals into a single structure so that conversion to threads will be easier. something similar will have to be done for the regular elvis globals to make it threadable. -rw------- 1 mh 8026 Dec 30 21:52 main.c Changed a resume_curses() call in trapint() to the Resume_curses() macro front end. Somehow I missed this before. Without this fix your parent shell window will wack out if type ctrl C in it after starting an elvis window that is not backgrounded. -rw-r--r-- 1 mh 7852 Jan 1 14:47 elvis.ps Fixed a bug in the /RSR method of ElvisCanvas that left it's argument on the stack, this (eventually) would cause a stack overflow if you scrolled around in a file long enough -rw------- 1 mh 15041 Jan 1 18:18 ow.c -rw------- 1 mh 17635 Jan 1 18:23 tio.c -rw-r--r-- 1 mh 2533 Jan 1 18:21 wconfig.h isolated out the display specific parts of displaying a string on the msg line into the Rendermsg and Appendmsg macro's (in wconfig.h ) :: for the standard termcap interface they are rendermsg and appendmsg ( in tio.c ) :: for the OPENWINDOWS version as ow_rendermsg and ow_appendmsg now in ow.c -rw------- 1 mh 16672 Jan 1 23:20 input.c Replaced beep()'s with Beep()'s. this would mess up the display in subtle ways by trying to render a ^G on the display when using the display version -rw-r--r-- 1 mh 8580 Jan 1 23:06 elvis.ps -rw------- 1 mh 15544 Jan 1 20:29 ow.c Put in the cQ cX cV cI cR capabilities for the OPENWINDOWS version of elvis. Now the cursor changes shape when you switch from insert mode to command mode to the :ex command line -rw-r--r-- 1 mh 8627 Jan 2 20:04 elvis.ps Fixed bug that did not show up until mutiple cursor types were implemented. The ST did not hide the cursor before it started drawing text. this was OK with a simple block cursor because the text always blanked over the of the old cursor completely. -rw------- 1 mh 16880 Jan 4 00:31 input.c Fixed up autoindent a little more to make work work pretty much like the real vi. this was just a 4 or 5 line change below the interactive loop in input() see the MCH comment SHAR_EOF fi # end of overwriting check if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # combined Makefile for ELVIS - a clone of `vi` # # After editing this Makefile as described below, you should... # # Use `make` to compile all programs # Use `make install` to copy the programs to the BIN directory # Use `make clean` to remove all object files # Use `make clobber` to remove everything except source & documentation # Use `make tags` to build new "tags" and "refs" files # Use `make uue` to produce uuencoded compressed tar archives of the source # Use `make sh` to produce shar archives of the source # Use `make print` to print the Elvis documentation # # Several groups of Makefile settings are included below. Choose *ONE* group # of settings for your particular system, and leave the others commented out. # The meanings of these settings are: # O the filename extension for unlinked object files -- usually .o # E the filename extension for executable files -- usually null # EXTRA version-specific object files used in elvis # EXTRA2 version-specific object files used in elvis, virec, & refont # LIBS any special libraries, such as "-ltermcap" # BIN directory where executables should be installed # CC the C compiler command, possibly with "memory model" flags # CFLAGS compiler flags used to select compile-time options # OF link flag to control the output file's name -- usually -o<space> # RF flag used to denote "compile but don't link" -- usually -c # DATE a "cc" flag that defines "DATE". e.g. DATE=-DDATE=\"7/4/76\" # EVAL the word "eval", if DATE requires it # PROGS the list of all programs # CHMEM any extra commands to be run after ELVIS is linked # SORT if the "tags" file must be sorted, then SORT=-DSORT # INST installation method: inst.dos, inst.tos, inst.os9, or inst.unix # RM the name of a program that deletes files # PR1 used to print documentation -- typically "refont -c" # PR2 used to send text to printer -- typically "| lpr" # DUMMY usually nothing, but OS9 needs "dummy" # DOC name of "doc" directory, with a trailing slash #---- These settings are recommended for System-V UNIX and SCO XENIX-386 ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= -ltermcap #BIN= /usr/local/bin #CFLAGS= -DM_SYSV -O #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= -DSORT #INST= inst.unix #RM= rm -f #PR1= refont -c #PR2= | lp #DUMMY= #DOC= doc/ #---- These settings are recommended for SCO XENIX-286 ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= -ltermcap #BIN= /usr/local/bin #CC= cc -M2s -i #CFLAGS= -DM_SYSV -Ox -DCS_IBMPC #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= -DSORT #INST= inst.unix #RM= rm -f #PR1= refont -c #PR2= | lp #DUMMY= #DOC= doc/ #---- These settings are recommended for BSD 4.3 UNIX ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= -ltermcap #BIN= /usr/local/bin #CFLAGS= -Dbsd -O #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= -DSORT #INST= inst.unix #RM= rm -f #PR1= refont -c #PR2= | lpr #DUMMY= #DOC= doc/ #---- These settings are recommended for sunOS with OPENWINDOWS (X11/NeWS) CHOWN=echo "Chown turned off, would be --> chown" #CC=gcc -traditional -g CC=cc -O O= .o E= EXTRA= ow$O EXTRA2= LIBS=-lwire -lcps -ltermcap BIN=/usr/local/bin PS=$(BIN)/elvis.ps #PS=/usr/local/src/share/elvis.ps CFLAGS= -DMALLOC_DEBUG=0 -DSUNOS=1 -Dbsd -DRUNFILE=\"$(PS)\" -DOPENWINDOWS=1 \ -I$(OPENWINHOME)/include -L$(OPENWINHOME)/lib OF=-o RF= -c DATE= -DDATE=\'\"`date`\"\' EVAL= eval PROGS= elvis_cps.h elvis.ps elvis$E ctags$E ref$E virec$E refont$E CHMEM= SORT= -DSORT INST= inst.unix RM= rm -f PR1= refont -c PR2= | lpr DUMMY= DOC= doc/ #---- These settings are recommended for Coherent ---- #O=.o #E= #EXTRA= #EXTRA2= #LIBS= -lterm #BIN= /usr/bin #CC= cc #CFLAGS= -O -DCOHERENT -DCRUNCH -DNO_CHARATTR -DNO_CURSORSHAPE \ # -DNO_DIGRAPH -DNO_MKEXRC -VSUVAR #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= fixstack 2000 elvis$E #SORT= #INST= inst.unix #RM= rm -f #PR1= refont -b #PR2= | lpr #DUMMY= #DOC= doc/ #---- These settings are recommended for Minix-ST ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= #BIN= /usr/bin #CC= cc #CFLAGS= #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= chmem =18000 elvis #SORT= #INST= inst.unix #RM= rm -f #PR1= lpr #PR2= #DUMMY= #DOC= doc/ #---- These settings are recommended for Minix-PC ---- #O= .s #E= #EXTRA= tinytcap$O #EXTRA2= #LIBS= #BIN= /usr/bin #CC= cc -i #CFLAGS= -O -DCRUNCH -DNO_MKEXRC -DNO_CURSORSHAPE -DNO_CHARATTR \ # -DNO_SHOWMODE -DNO_MODELINE -DNO_OPTCOLS -DNO_DIGRAPH -DNO_ABBR \ # -DNO_AT -DNO_SENTENCE -DNO_ERRLIST #### (all but -DNO_EXTENSIONS, -DNO_RECYCLE, -DNO_MAGIC, and -DNO_CHARSEARCH) #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= #INST= inst.unix #RM= rm -f #PR1= lpr #PR2= #DUMMY= #DOC= doc/ #---- These settings are recommended for MS-DOS + MS-C + NDMAKE ---- #O= .obj #E= .exe #EXTRA= pc$O sysdos$O tinytcap$O #EXTRA2= #LIBS= #BIN= c:\dos #CC= cl /AM #CFLAGS= -O -DCS_IBMPC -DCS_SPECIAL #OF= -o #RF= -c #DATE= #EVAL= #PROGS= elvis$E ex$E ctags$E ref$E virec$E wildcard$E refont$E #CHMEM= #SORT= #INST= inst.dos #RM= del #PR1= refont -c #PR2= >PRN #DUMMY= #DOC= doc\ #---- These settings are recommended for Atari TOS + Mark Williams C ---- #O=.o #E=.ttp #EXTRA= sysdos$O tinytcap$O #EXTRA2= atari$O #LIBS= #BIN= c:\ #CC= cc -VPEEP #CFLAGS= -O -DCS_IBMPC -DCS_SPECIAL #OF= -o #RF= -c #DATE= #EVAL= #PROGS= elvis$E ctags$E ref$E virec$E wildcard$E shell$E refont$E #CHMEM= #SORT= #INST= inst.tos #RM= rm -f #PR1= refont -e #PR2= >PRT: #DUMMY= #DOC= 'doc\' #---- These settings are recommended for OS-9/68K V2.3 ---- #O= .r #E= #EXTRA= date$O #EXTRA2= osk$O #LIBS= -l=/dd/lib/termlib.l #BIN= /dd/usr/cmds #CC= cc #ODIR= /dd/usr/src/elvis #CFLAGS= -gq -m=2 #OF= -f=$(ODIR)/ #RF= -r #DATE= #EVAL= #PROGS= elvis$E vi$E view$E input$E ctags$E ref$E virec$E refont$E #CHMEM= touch date.r #SORT= #INST= inst.os9 #RM= del *.stb *.dbg #PR1= refont -b #PR2= >/p #DUMMY= dummy #DOC= doc/ ########################################################################### ########################################################################### ### ### ### The rest of this Makefile contains no user-servicable parts ### ### ### ########################################################################### ########################################################################### OBJS= blk$O cmd1$O cmd2$O curses$O cut$O ex$O input$O main$O misc$O \ modify$O move1$O move2$O move3$O move4$O move5$O opts$O recycle$O \ redraw$O regexp$O regsub$O system$O tio$O tmp$O vars$O vcmd$O vi$O ALIAS= alias$O DOCS= $(DOC)index.doc $(DOC)intro.doc $(DOC)visual.doc $(DOC)ex.doc \ $(DOC)regexp.doc $(DOC)options.doc $(DOC)cutbufs.doc $(DOC)differ.doc \ $(DOC)internal.doc $(DOC)cflags.doc $(DOC)termcap.doc \ $(DOC)environ.doc $(DOC)versions.doc SRC1= README KNOWN.BUGS $(DOC)intro.doc $(DOC)visual.doc $(DOC)ex.doc \ $(DOC)versions.doc $(DOC)cflags.doc $(DOC)differ.doc SRC2= $(DOC)cutbufs.doc $(DOC)options.doc $(DOC)environ.doc $(DOC)regexp.doc \ $(DOC)internal.doc $(DOC)termcap.doc $(DOC)index.doc $(DOC)ctags.man \ $(DOC)elvis.man $(DOC)ref.man $(DOC)refont.man $(DOC)virec.man SRC3= Elvis.lnk Elvis.mak Elvis.prj Makefile.mix alias.c atari.c \ ctags.c pc.c ref.c shell.c sysdos.c virec.c wildcard.c \ profile.sh osk.c osk.h date.c SRC4= blk.c cmd1.c cmd2.c config.h curses.c SRC5= curses.h cut.c ex.c input.c main.c misc.c SRC6= modify.c move1.c move2.c move3.c move4.c move5.c opts.c recycle.c \ redraw.c SRC7= regexp.c regexp.h regsub.c system.c tinytcap.c tio.c tmp.c SRC8= vars.c vcmd.c vi.c vi.h refont.c ########################################################################### all: $(PROGS) @echo done. elvis$E: $(OBJS) $(EXTRA) $(EXTRA2) $(CC) $(CFLAGS) $(OF) elvis$E $(OBJS) $(EXTRA) $(EXTRA2) $(LIBS) $(CHMEM) ctags$E: ctags.c $(CC) $(CFLAGS) $(SORT) $(OF)ctags$E ctags.c ref$E: ref.c $(CC) $(CFLAGS) $(OF)ref$E ref.c virec$E: virec.c tnamerec.c $(CC) $(CFLAGS) $(OF) virec$E virec.c tnamerec.c $(EXTRA2) view$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)view$E $(ALIAS) ex$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)ex$E $(ALIAS) vi$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)vi$E $(ALIAS) input$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)input$E $(ALIAS) shell$E: shell.c $(CC) $(CFLAGS) $(OF)shell$E shell.c wildcard$E: wildcard.c $(CC) $(CFLAGS) $(OF)wildcard$E wildcard.c refont$E: refont.c $(CC) $(CFLAGS) $(OF)refont$E refont.c $(EXTRA2) ############################################################################## # The file cmd1.c is compiled with the extra flag -DDATE="today's date". cmd1$O: cmd1.c vi.h config.h $(EVAL) $(CC) $(CFLAGS) $(RF) $(DATE) cmd1.c # "It all depends..." $(OBJS): vi.h curses.h config.h # OS9 must create a custom date.c file, and compile it. date$O: $(OBJS) @echo '/* compilation date of elvis */' >-date.c @echo -r 'char date[] = "' >+date.c @echo -r 'echo -r ' >-/dd/tmp/date.c @date >+/dd/tmp/date.c @shell /dd/tmp/date.c >+date.c @echo '";' >+date.c @del /dd/tmp/date.c $(CC) $(CFLAGS) $(RF) date.c ############################################################################## install: $(INST) @echo Installation complete. inst.unix: $(DUMMY) cp $(PROGS) $(BIN) (cd $(BIN); chmod 755 $(PROGS)) (cd $(BIN); $(CHOWN) bin $(PROGS)) -rm $(BIN)/vi; ln -s $(BIN)/elvis $(BIN)/vi -rm $(BIN)/ex; ln -s $(BIN)/elvis $(BIN)/ex -rm $(BIN)/view; ln -s $(BIN)/elvis $(BIN)/view -rm $(BIN)/input; ln -s $(BIN)/elvis $(BIN)/input inst.dos: $(DUMMY) copy $(PROGS) $(BIN) copy $(BIN)/ex$E $(BIN)/vi$E copy $(BIN)/ex$E $(BIN)/view$E copy $(BIN)/ex$E $(BIN)/input$E inst.tos: $(DUMMY) copy $(PROGS) $(BIN) inst.os9: $(DUMMY) copy $(PROGS) -rw=$(BIN) chd $(BIN); attr -epenprnpw $(PROGS) ############################################################################## clean: $(DUMMY) $(RM) *$O $(DOC)*.1 elvis?.uue elvis?.sh core clobber: clean $(RM) tags refs $(PROGS) ############################################################################## print: refont$E $(PR1) $(DOCS) $(PR2) tags refs: ctags$E ctags -r *.c *.h ############################################################################## uue: elvis1.uue elvis2.uue elvis3.uue elvis4.uue elvis5.uue \ elvis6.uue elvis7.uue elvis8.uue elvis1.uue: $(SRC1) tar cf elvis1.tar $(SRC1) compress -b13 elvis1.tar cp README elvis1.uue uue elvis1.tar.Z - >>elvis1.uue $(RM) elvis1.tar* elvis2.uue: $(SRC2) tar cf elvis2.tar $(SRC2) compress -b13 elvis2.tar uue elvis2.tar.Z $(RM) elvis2.tar* elvis3.uue: $(SRC3) tar cf elvis3.tar $(SRC3) compress -b13 elvis3.tar uuencode elvis3.tar.Z <elvis3.tar.Z >elvis3.uue $(RM) elvis3.tar* elvis4.uue: $(SRC4) tar cf elvis4.tar $(SRC4) compress -b13 elvis4.tar uuencode elvis4.tar.Z <elvis4.tar.Z >elvis4.uue $(RM) elvis4.tar* elvis5.uue: $(SRC5) tar cf elvis5.tar $(SRC5) compress -b13 elvis5.tar uuencode elvis5.tar.Z <elvis5.tar.Z >elvis5.uue $(RM) elvis5.tar* elvis6.uue: $(SRC6) tar cf elvis6.tar $(SRC6) compress -b13 elvis6.tar uuencode elvis6.tar.Z <elvis6.tar.Z >elvis6.uue $(RM) elvis6.tar* elvis7.uue: $(SRC7) tar cf elvis7.tar $(SRC7) compress -b13 elvis7.tar uuencode elvis7.tar.Z <elvis7.tar.Z >elvis7.uue $(RM) elvis7.tar* elvis8.uue: $(SRC8) tar cf elvis8.tar $(SRC8) compress -b13 elvis8.tar uuencode elvis8.tar.Z <elvis8.tar.Z >elvis8.uue $(RM) elvis8.tar* ############################################################################## sh: elvis1.sh elvis2.sh elvis3.sh elvis4.sh elvis5.sh elvis6.sh \ elvis7.sh elvis8.sh elvis1.sh: $(SRC1) cat >elvis1.sh README echo >>elvis1.sh ': ------------------------ CUT HERE --------------------' echo >>elvis1.sh 'test -d doc || mkdir doc || exit 2' shar >>elvis1.sh -h $(SRC1) elvis2.sh: $(SRC2) echo >elvis2.sh ': ------------------------ CUT HERE --------------------' echo >>elvis2.sh 'test -d doc || mkdir doc || exit 2' shar >>elvis2.sh -h $(SRC2) elvis3.sh: $(SRC3) shar $(SRC3) >elvis3.sh elvis4.sh: $(SRC4) shar $(SRC4) >elvis4.sh elvis5.sh: $(SRC5) shar $(SRC5) >elvis5.sh elvis6.sh: $(SRC6) shar $(SRC6) >elvis6.sh elvis7.sh: $(SRC7) shar $(SRC7) >elvis7.sh elvis8.sh: $(SRC8) shar $(SRC8) >elvis8.sh ############################################################################## # Under XENIX only! This stores all sources on a 3.5" 720k floppy disk. floppy: $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5) $(SRC6) $(SRC7) $(SRC8) tar c5v $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5) $(SRC6) $(SRC7) $(SRC8) changes: for i in *.[ch] M* ; do \ if test -f $i -a -w $i ; then \ echo $i \ fi;\ done dep: makedep -f $(CFLAGS) -I/usr/include *.c sed '/^#-- DO NOT EDIT FROM THIS LINE DOWN/,$$d' Makefile > tmp echo "#-- DO NOT EDIT FROM THIS LINE DOWN" >> tmp cat dependencies >> tmp mv tmp Makefile rm dependencies #-- DO NOT EDIT FROM THIS LINE DOWN wildcard.o: \ $(FRC) \ /usr/include/stdio.h \ /usr/include/ctype.h virec.o: \ $(FRC) \ config.h \ /usr/include/stdio.h \ /usr/include/ctype.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ osk.h \ /usr/include/time.h \ wildcard.c vi.o: \ $(FRC) \ config.h \ /usr/include/ctype.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h vcmd.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ /usr/include/string.h vars.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h tnamerec.o: \ $(FRC) \ config.h \ /usr/include/dirent.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/dirent.h tmp.o: \ $(FRC) \ config.h \ /usr/include/ctype.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ osk.h \ /usr/include/time.h tio.o: \ $(FRC) \ config.h \ /usr/include/setjmp.h \ /usr/include/machine/setjmp.h \ /usr/include/sun3/setjmp.h \ /usr/include/sun3x/setjmp.h \ /usr/include/sun4/setjmp.h \ /usr/include/sun4c/setjmp.h \ /usr/include/signal.h \ /usr/include/sys/signal.h \ /usr/include/vm/faultcode.h \ /usr/include/sys/stdtypes.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ /usr/include/varargs.h tinytcap.o: \ $(FRC) \ config.h system.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ /usr/include/signal.h \ /usr/include/sys/signal.h \ /usr/include/vm/faultcode.h \ /usr/include/string.h sysdos.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ /usr/include/string.h shell.o: \ $(FRC) \ /usr/include/stdio.h \ /usr/include/string.h \ /usr/include/sys/stdtypes.h regsub.o: \ $(FRC) \ /usr/include/ctype.h \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ regexp.h regexp.o: \ $(FRC) \ /usr/include/setjmp.h \ /usr/include/machine/setjmp.h \ /usr/include/sun3/setjmp.h \ /usr/include/sun3x/setjmp.h \ /usr/include/sun4/setjmp.h \ /usr/include/sun4c/setjmp.h \ /usr/include/ctype.h \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ regexp.h refont.o: \ $(FRC) \ /usr/include/stdio.h \ config.h ref.o: \ $(FRC) \ /usr/include/stdio.h redraw.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h recycle.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h pc.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h ow_tcap.o: \ $(FRC) \ /usr/include/varargs.h \ curses.h \ wconfig.h \ config.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h ow.o: \ $(FRC) \ /usr/include/stdio.h \ /usr/include/sys/time.h \ /usr/include/time.h \ /usr/include/sys/stdtypes.h \ /usr/include/signal.h \ /usr/include/sys/signal.h \ /usr/include/vm/faultcode.h \ /usr/include/assert.h \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ elvis_cps.h \ /usr/include/sys/file.h \ /usr/include/sgtty.h \ /usr/include/sys/ioctl.h \ /usr/include/sys/ttychars.h \ /usr/include/sys/ttydev.h \ /usr/include/sys/ttold.h \ /usr/include/sys/ioccom.h \ /usr/include/sys/ttycom.h \ /usr/include/sys/filio.h \ /usr/include/sys/sockio.h osk.o: \ $(FRC) \ /usr/include/stdio.h \ osk.h \ /usr/include/time.h \ /usr/include/sys/stdtypes.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/signal.h \ /usr/include/sys/signal.h \ /usr/include/vm/faultcode.h opts.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h move5.o: \ $(FRC) \ /usr/include/ctype.h \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h move4.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h move3.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h move2.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ regexp.h move1.o: \ $(FRC) \ config.h \ /usr/include/ctype.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h modify.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h misc.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h main.o: \ $(FRC) \ config.h \ /usr/include/signal.h \ /usr/include/sys/signal.h \ /usr/include/vm/faultcode.h \ /usr/include/sys/stdtypes.h \ /usr/include/setjmp.h \ /usr/include/machine/setjmp.h \ /usr/include/sun3/setjmp.h \ /usr/include/sun3x/setjmp.h \ /usr/include/sun4/setjmp.h \ /usr/include/sun4c/setjmp.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h input.o: \ $(FRC) \ /usr/include/ctype.h \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h ex.o: \ $(FRC) \ config.h \ /usr/include/ctype.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h cut.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h curses.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ /usr/include/termio.h \ /usr/include/sys/ioccom.h \ /usr/include/sys/termios.h \ /usr/include/sys/ttydev.h \ /usr/include/sys/ttycom.h \ /usr/include/sgtty.h \ /usr/include/sys/ioctl.h \ /usr/include/sys/ttychars.h \ /usr/include/sys/ttold.h \ /usr/include/sys/filio.h \ /usr/include/sys/sockio.h \ /usr/include/signal.h \ /usr/include/sys/signal.h \ /usr/include/vm/faultcode.h ctags.o: \ $(FRC) \ /usr/include/ctype.h \ /usr/include/stdio.h \ config.h \ wildcard.c cmd2.o: \ $(FRC) \ /usr/include/ctype.h \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ regexp.h \ osk.h \ /usr/include/time.h cmd1.o: \ $(FRC) \ config.h \ /usr/include/ctype.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h \ regexp.h blk.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h atari.o: \ $(FRC) \ config.h \ vi.h \ /usr/include/errno.h \ /usr/include/sys/errno.h \ /usr/include/sys/types.h \ /usr/include/sys/stdtypes.h \ /usr/include/sys/sysmacros.h \ /usr/include/sys/fcntl.h \ /usr/include/sys/fcntlcom.h \ /usr/include/sys/stat.h \ /usr/include/fcntl.h \ curses.h \ wconfig.h \ /usr/local/openwin/include/NeWS/wire.h \ /usr/local/openwin/include/NeWS/psmacros.h \ /usr/include/stdio.h \ /usr/local/openwin/include/NeWS/psio.h \ /usr/local/openwin/include/NeWS/wire_types.h alias.o: \ $(FRC) \ /usr/include/stdio.h \ config.h SHAR_EOF fi # end of overwriting check if test -f 'Makefile.mix' then echo shar: will not over-write existing file "'Makefile.mix'" else cat << \SHAR_EOF > 'Makefile.mix' # combined Makefile for ELVIS - a clone of `vi` # # After editing this Makefile as described below, you should... # # Use `make` to compile all programs # Use `make install` to copy the programs to the BIN directory # Use `make clean` to remove all object files # Use `make clobber` to remove everything except source & documentation # Use `make tags` to build new "tags" and "refs" files # Use `make uue` to produce uuencoded compressed tar archives of the source # Use `make sh` to produce shar archives of the source # Use `make print` to print the Elvis documentation # # Several groups of Makefile settings are included below. Choose *ONE* group # of settings for your particular system, and leave the others commented out. # The meanings of these settings are: # O the filename extension for unlinked object files -- usually .o # E the filename extension for executable files -- usually null # EXTRA version-specific object files used in elvis # EXTRA2 version-specific object files used in elvis, virec, & refont # LIBS any special libraries, such as "-ltermcap" # BIN directory where executables should be installed # CC the C compiler command, possibly with "memory model" flags # CFLAGS compiler flags used to select compile-time options # OF link flag to control the output file's name -- usually -o<space> # RF flag used to denote "compile but don't link" -- usually -c # DATE a "cc" flag that defines "DATE". e.g. DATE=-DDATE=\"7/4/76\" # EVAL the word "eval", if DATE requires it # PROGS the list of all programs # CHMEM any extra commands to be run after ELVIS is linked # SORT if the "tags" file must be sorted, then SORT=-DSORT # INST installation method: inst.dos, inst.tos, inst.os9, or inst.unix # RM the name of a program that deletes files # PR1 used to print documentation -- typically "refont -c" # PR2 used to send text to printer -- typically "| lpr" # DUMMY usually nothing, but OS9 needs "dummy" # DOC name of "doc" directory, with a trailing slash #---- These settings are recommended for System-V UNIX and SCO XENIX-386 ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= -ltermcap #BIN= /usr/local/bin #CFLAGS= -DM_SYSV -O #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= -DSORT #INST= inst.unix #RM= rm -f #PR1= refont -c #PR2= | lp #DUMMY= #DOC= doc/ #---- These settings are recommended for SCO XENIX-286 ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= -ltermcap #BIN= /usr/local/bin #CC= cc -M2s -i #CFLAGS= -DM_SYSV -Ox -DCS_IBMPC #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= -DSORT #INST= inst.unix #RM= rm -f #PR1= refont -c #PR2= | lp #DUMMY= #DOC= doc/ #---- These settings are recommended for BSD 4.3 UNIX ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= -ltermcap #BIN= /usr/local/bin #CFLAGS= -Dbsd -O #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= -DSORT #INST= inst.unix #RM= rm -f #PR1= refont -c #PR2= | lpr #DUMMY= #DOC= doc/ #---- These settings are recommended for Coherent ---- #O=.o #E= #EXTRA= #EXTRA2= #LIBS= -lterm #BIN= /usr/bin #CC= cc #CFLAGS= -O -DCOHERENT -DCRUNCH -DNO_CHARATTR -DNO_CURSORSHAPE \ # -DNO_DIGRAPH -DNO_MKEXRC -VSUVAR #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= fixstack 2000 elvis$E #SORT= #INST= inst.unix #RM= rm -f #PR1= refont -b #PR2= | lpr #DUMMY= #DOC= doc/ #---- These settings are recommended for Minix-ST ---- #O= .o #E= #EXTRA= #EXTRA2= #LIBS= #BIN= /usr/bin #CC= cc #CFLAGS= #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= chmem =18000 elvis #SORT= #INST= inst.unix #RM= rm -f #PR1= lpr #PR2= #DUMMY= #DOC= doc/ #---- These settings are recommended for Minix-PC ---- #O= .s #E= #EXTRA= tinytcap$O #EXTRA2= #LIBS= #BIN= /usr/bin #CC= cc -i #CFLAGS= -O -DCRUNCH -DNO_MKEXRC -DNO_CURSORSHAPE -DNO_CHARATTR \ # -DNO_SHOWMODE -DNO_MODELINE -DNO_OPTCOLS -DNO_DIGRAPH -DNO_ABBR \ # -DNO_AT -DNO_SENTENCE -DNO_ERRLIST #### (all but -DNO_EXTENSIONS, -DNO_RECYCLE, -DNO_MAGIC, and -DNO_CHARSEARCH) #OF= -o #RF= -c #DATE= -DDATE=\'\"`date`\"\' #EVAL= eval #PROGS= elvis$E ctags$E ref$E virec$E refont$E #CHMEM= #SORT= #INST= inst.unix #RM= rm -f #PR1= lpr #PR2= #DUMMY= #DOC= doc/ #---- These settings are recommended for MS-DOS + MS-C + NDMAKE ---- #O= .obj #E= .exe #EXTRA= pc$O sysdos$O tinytcap$O #EXTRA2= #LIBS= #BIN= c:\dos #CC= cl /AM #CFLAGS= -O -DCS_IBMPC -DCS_SPECIAL #OF= -o #RF= -c #DATE= #EVAL= #PROGS= elvis$E ex$E ctags$E ref$E virec$E wildcard$E refont$E #CHMEM= #SORT= #INST= inst.dos #RM= del #PR1= refont -c #PR2= >PRN #DUMMY= #DOC= doc\ #---- These settings are recommended for Atari TOS + Mark Williams C ---- #O=.o #E=.ttp #EXTRA= sysdos$O tinytcap$O #EXTRA2= atari$O #LIBS= #BIN= c:\ #CC= cc -VPEEP #CFLAGS= -O -DCS_IBMPC -DCS_SPECIAL #OF= -o #RF= -c #DATE= #EVAL= #PROGS= elvis$E ctags$E ref$E virec$E wildcard$E shell$E refont$E #CHMEM= #SORT= #INST= inst.tos #RM= rm -f #PR1= refont -e #PR2= >PRT: #DUMMY= #DOC= 'doc\' #---- These settings are recommended for OS-9/68K V2.3 ---- #O= .r #E= #EXTRA= date$O #EXTRA2= osk$O #LIBS= -l=/dd/lib/termlib.l #BIN= /dd/usr/cmds #CC= cc #ODIR= /dd/usr/src/elvis #CFLAGS= -gq -m=2 #OF= -f=$(ODIR)/ #RF= -r #DATE= #EVAL= #PROGS= elvis$E vi$E view$E input$E ctags$E ref$E virec$E refont$E #CHMEM= touch date.r #SORT= #INST= inst.os9 #RM= del *.stb *.dbg #PR1= refont -b #PR2= >/p #DUMMY= dummy #DOC= doc/ ########################################################################### ########################################################################### ### ### ### The rest of this Makefile contains no user-servicable parts ### ### ### ########################################################################### ########################################################################### OBJS= blk$O cmd1$O cmd2$O curses$O cut$O ex$O input$O main$O misc$O \ modify$O move1$O move2$O move3$O move4$O move5$O opts$O recycle$O \ redraw$O regexp$O regsub$O system$O tio$O tmp$O vars$O vcmd$O vi$O ALIAS= alias$O DOCS= $(DOC)index.doc $(DOC)intro.doc $(DOC)visual.doc $(DOC)ex.doc \ $(DOC)regexp.doc $(DOC)options.doc $(DOC)cutbufs.doc $(DOC)differ.doc \ $(DOC)internal.doc $(DOC)cflags.doc $(DOC)termcap.doc \ $(DOC)environ.doc $(DOC)versions.doc SRC1= README KNOWN.BUGS $(DOC)intro.doc $(DOC)visual.doc $(DOC)ex.doc \ $(DOC)versions.doc $(DOC)cflags.doc $(DOC)differ.doc SRC2= $(DOC)cutbufs.doc $(DOC)options.doc $(DOC)environ.doc $(DOC)regexp.doc \ $(DOC)internal.doc $(DOC)termcap.doc $(DOC)index.doc $(DOC)ctags.man \ $(DOC)elvis.man $(DOC)ref.man $(DOC)refont.man $(DOC)virec.man SRC3= Elvis.lnk Elvis.mak Elvis.prj Makefile.mix alias.c atari.c \ ctags.c pc.c ref.c shell.c sysdos.c virec.c wildcard.c \ profile.sh osk.c osk.h date.c SRC4= blk.c cmd1.c cmd2.c config.h curses.c SRC5= curses.h cut.c ex.c input.c main.c misc.c SRC6= modify.c move1.c move2.c move3.c move4.c move5.c opts.c recycle.c \ redraw.c SRC7= regexp.c regexp.h regsub.c system.c tinytcap.c tio.c tmp.c SRC8= vars.c vcmd.c vi.c vi.h refont.c ########################################################################### all: $(PROGS) @echo done. elvis$E: $(OBJS) $(EXTRA) $(EXTRA2) $(CC) $(CFLAGS) $(OF)elvis$E $(OBJS) $(EXTRA) $(EXTRA2) $(LIBS) $(CHMEM) ctags$E: ctags.c $(CC) $(CFLAGS) $(SORT) $(OF)ctags$E ctags.c ref$E: ref.c $(CC) $(CFLAGS) $(OF)ref$E ref.c virec$E: virec.c $(CC) $(CFLAGS) $(OF)virec$E virec.c $(EXTRA2) view$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)view$E $(ALIAS) ex$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)ex$E $(ALIAS) vi$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)vi$E $(ALIAS) input$E: $(ALIAS) $(CC) $(CFLAGS) $(OF)input$E $(ALIAS) shell$E: shell.c $(CC) $(CFLAGS) $(OF)shell$E shell.c wildcard$E: wildcard.c $(CC) $(CFLAGS) $(OF)wildcard$E wildcard.c refont$E: refont.c $(CC) $(CFLAGS) $(OF)refont$E refont.c $(EXTRA2) ############################################################################## # The file cmd1.c is compiled with the extra flag -DDATE="today's date". cmd1$O: cmd1.c vi.h config.h $(EVAL) $(CC) $(CFLAGS) $(RF) $(DATE) cmd1.c # "It all depends..." $(OBJS): vi.h curses.h config.h # OS9 must create a custom date.c file, and compile it. date$O: $(OBJS) @echo '/* compilation date of elvis */' >-date.c @echo -r 'char date[] = "' >+date.c @echo -r 'echo -r ' >-/dd/tmp/date.c @date >+/dd/tmp/date.c @shell /dd/tmp/date.c >+date.c @echo '";' >+date.c @del /dd/tmp/date.c $(CC) $(CFLAGS) $(RF) date.c ############################################################################## install: $(INST) @echo Installation complete. inst.unix: $(DUMMY) cp $(PROGS) $(BIN) (cd $(BIN); chmod 755 $(PROGS)) (cd $(BIN); chown bin $(PROGS)) -ln $(BIN)/elvis $(BIN)/vi -ln $(BIN)/elvis $(BIN)/ex -ln $(BIN)/elvis $(BIN)/view -ln $(BIN)/elvis $(BIN)/input inst.dos: $(DUMMY) copy $(PROGS) $(BIN) copy $(BIN)/ex$E $(BIN)/vi$E copy $(BIN)/ex$E $(BIN)/view$E copy $(BIN)/ex$E $(BIN)/input$E inst.tos: $(DUMMY) copy $(PROGS) $(BIN) inst.os9: $(DUMMY) copy $(PROGS) -rw=$(BIN) chd $(BIN); attr -epenprnpw $(PROGS) ############################################################################## clean: $(DUMMY) $(RM) *$O $(DOC)*.1 elvis?.uue elvis?.sh core clobber: clean $(RM) tags refs $(PROGS) ############################################################################## print: refont$E $(PR1) $(DOCS) $(PR2) tags refs: ctags$E ctags -r *.c *.h ############################################################################## uue: elvis1.uue elvis2.uue elvis3.uue elvis4.uue elvis5.uue \ elvis6.uue elvis7.uue elvis8.uue elvis1.uue: $(SRC1) tar cf elvis1.tar $(SRC1) compress -b13 elvis1.tar cp README elvis1.uue uue elvis1.tar.Z - >>elvis1.uue $(RM) elvis1.tar* elvis2.uue: $(SRC2) tar cf elvis2.tar $(SRC2) compress -b13 elvis2.tar uue elvis2.tar.Z $(RM) elvis2.tar* elvis3.uue: $(SRC3) tar cf elvis3.tar $(SRC3) compress -b13 elvis3.tar uuencode elvis3.tar.Z <elvis3.tar.Z >elvis3.uue $(RM) elvis3.tar* elvis4.uue: $(SRC4) tar cf elvis4.tar $(SRC4) compress -b13 elvis4.tar uuencode elvis4.tar.Z <elvis4.tar.Z >elvis4.uue $(RM) elvis4.tar* elvis5.uue: $(SRC5) tar cf elvis5.tar $(SRC5) compress -b13 elvis5.tar uuencode elvis5.tar.Z <elvis5.tar.Z >elvis5.uue $(RM) elvis5.tar* elvis6.uue: $(SRC6) tar cf elvis6.tar $(SRC6) compress -b13 elvis6.tar uuencode elvis6.tar.Z <elvis6.tar.Z >elvis6.uue $(RM) elvis6.tar* elvis7.uue: $(SRC7) tar cf elvis7.tar $(SRC7) compress -b13 elvis7.tar uuencode elvis7.tar.Z <elvis7.tar.Z >elvis7.uue $(RM) elvis7.tar* elvis8.uue: $(SRC8) tar cf elvis8.tar $(SRC8) compress -b13 elvis8.tar uuencode elvis8.tar.Z <elvis8.tar.Z >elvis8.uue $(RM) elvis8.tar* ############################################################################## sh: elvis1.sh elvis2.sh elvis3.sh elvis4.sh elvis5.sh elvis6.sh \ elvis7.sh elvis8.sh elvis1.sh: $(SRC1) cat >elvis1.sh README echo >>elvis1.sh ': ------------------------ CUT HERE --------------------' echo >>elvis1.sh 'test -d doc || mkdir doc || exit 2' shar >>elvis1.sh -h $(SRC1) elvis2.sh: $(SRC2) echo >elvis2.sh ': ------------------------ CUT HERE --------------------' echo >>elvis2.sh 'test -d doc || mkdir doc || exit 2' shar >>elvis2.sh -h $(SRC2) elvis3.sh: $(SRC3) shar $(SRC3) >elvis3.sh elvis4.sh: $(SRC4) shar $(SRC4) >elvis4.sh elvis5.sh: $(SRC5) shar $(SRC5) >elvis5.sh elvis6.sh: $(SRC6) shar $(SRC6) >elvis6.sh elvis7.sh: $(SRC7) shar $(SRC7) >elvis7.sh elvis8.sh: $(SRC8) shar $(SRC8) >elvis8.sh ############################################################################## # Under XENIX only! This stores all sources on a 3.5" 720k floppy disk. floppy: $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5) $(SRC6) $(SRC7) $(SRC8) tar c5v $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5) $(SRC6) $(SRC7) $(SRC8) SHAR_EOF fi # end of overwriting check if test -f 'config.h' then echo shar: will not over-write existing file "'config.h'" else cat << \SHAR_EOF > 'config.h' /* * vi configuration file * We try to automatically configure to various compilers and operating * systems. Extend the autoconf section as needed. */ /*************************** autoconf section ************************/ /* standard unix V (?) */ #ifdef M_SYSV # define UNIXV 1 #endif /* xelos system, University of Ulm */ #ifdef xelos # define UNIXV 1 #endif /* BSD UNIX? */ #ifdef bsd # define BSD 1 #endif /* Microsoft C: sorry, Watcom does the same thing */ #ifdef M_I86 # ifndef M_SYSV # define MSDOS 1 # define MICROSOFT 1 # define COMPILED_BY "Microsoft C 5.10" # endif #endif /* Borlands Turbo C */ #ifdef __TURBOC__ # define MSDOS 1 # define TURBOC 1 # define COMPILED_BY "Turbo C 2.00" #endif /* Tos Mark-Williams */ #ifdef M68000 # define TOS 1 # define COMPILED_BY "Mark Williams C" #endif /* OS9/68000 */ #ifdef OSK # define COMPILED_BY "Microware C V2.3 Edition 40" #endif /*************************** end of autoconf section ************************/ /* All undefined symbols are defined to zero here, to allow for older */ /* compilers which dont understand #if defined() or #if UNDEFINED_SYMBOL */ /*************************** operating systems *****************************/ #ifndef BSD # define BSD 0 /* UNIX - Berkeley 4.x */ #endif #ifndef UNIXV # define UNIXV 0 /* UNIX - AT&T SYSV */ #endif #ifndef UNIX7 # define UNIX7 0 /* UNIX - version 7 */ #endif #ifndef MSDOS # define MSDOS 0 /* PC */ #endif #ifndef TOS # define TOS 0 /* Atari ST */ #endif #ifndef AMIGA # define AMIGA 0 /* Commodore Amiga */ #endif #ifndef OSK # define OSK 0 /* OS-9 / 68k */ #endif #ifndef COHERENT # define COHERENT 0 /* Coherent */ #endif /* Minix has no predefines */ #if !BSD && !UNIXV && !UNIX7 && !MSDOS && !TOS && !AMIGA && !OSK && !COHERENT # define MINIX 1 #else # define MINIX 0 #endif /* generic combination of Unices */ #if UNIXV || UNIX7 || BSD || MINIX || COHERENT # define ANY_UNIX 1 #else # define ANY_UNIX 0 #endif /*************************** compilers **************************************/ #ifndef MICROSOFT # define MICROSOFT 0 #endif #ifndef TURBOC # define TURBOC 0 #endif /******************************* Credit ************************************/ #if OPENWINDOWS # define CREDIT "Ported to X11/NeWS by Mike Hoegeman" #endif #if MSDOS # define CREDIT "Ported to MS-DOS by Guntram Blohm & Martin Patzel" #endif #if TOS # define CREDIT "Ported to Atari/TOS by Guntram Blohm & Martin Patzel" #endif #if OSK # define CREDIT "Ported to Microware OS9/68k by Peter Reinig" #endif #if COHERENT # define CREDIT "Ported to Coherent by Esa Ahola" #endif /*************************** functions depending on OS *********************/ /* Only MSDOS, TOS, and OS9 need a special function for reading from the * keyboard. All others just read from file descriptor 0. */ #if !MSDOS && !TOS && !OSK && !OPENWINDOWS # define ttyread(buf, len) read(0, buf, (unsigned)len) /* raw read */ #endif #if !TOS && !OPENWINDOWS # define ttywrite(buf, len) write(1, buf, (unsigned)(len)) /* raw write */ #endif /* The strchr() function is an official standard now, so everybody has it * except Unix version 7 (which is old) and BSD Unix (which is academic). * Those guys use something called index() to do the same thing. */ #if BSD || UNIX7 || OSK # define strchr index #endif extern char *strchr(); /* BSD uses bcopy() instead of memcpy() */ #if BSD #define memcpy(dest, src, siz) bcopy(src, dest, siz) #endif /* text versa binary mode for read/write */ #if !TOS #define tread(fd,buf,n) read(fd,buf,(unsigned)(n)) #define twrite(fd,buf,n) write(fd,buf,(unsigned)(n)) #endif /**************************** Compiler quirks *********************************/ /* the UNIX version 7 and (some) TOS compilers, don't allow "void" */ #if UNIX7 || TOS # define void int #endif /* as far as I know, all compilers except version 7 support unsigned char */ /* NEWFLASH: the Minix-ST compiler has subtle problems with unsigned char */ #if UNIX7 || MINIX # define UCHAR(c) ((c) & 0xff) # define uchar char #else # define UCHAR(c) ((unsigned char)(c)) # define uchar unsigned char #endif /* Some compilers prefer to have malloc declared as returning a (void *) */ #if BSD extern void *malloc(); #else extern char *malloc(); #endif /* Most compilers could benefit from using the "register" storage class */ #if 1 # define REG register #endif /******************* Names of files and environment vars **********************/ #if ANY_UNIX # ifndef TMPDIR # if MINIX # define TMPDIR "/usr/tmp" /* Keep elvis' temp files off RAM disk! */ # else # define TMPDIR "/tmp" /* directory where temp files live */ # endif # endif # define MAXTMPNAMELEN 256 /* length for tmp file name buffer */ # define TMPNAME "%s/El%01x%04x%03x-%03x" /* temp file */ # define CUTNAME "%s/El_%04x%03x" /* cut buffer's temp file */ # ifndef EXRC # define EXRC ".exrc" /* init file in current directory */ # endif # define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */ # ifndef EXINIT # define EXINIT "EXINIT" # endif # ifndef SHELL # define SHELL "/bin/sh" /* default shell */ # endif # if COHERENT # ifndef REDIRECT # define REDIRECT ">" /* Coherent CC writes errors to stdout */ # endif # endif #endif #if MSDOS || TOS /* do not change TMPNAME, CUTNAME and SCRATCH*: they MUST begin with '%s\\'! */ # ifndef TMPDIR # define TMPDIR "C:\\tmp" /* directory where temp files live */ # endif # define TMPNAME "%s\\elv%x%04x.%03x" /* temp file */ # define CUTNAME "%s\\elv_%04x.%03x" /* cut buffer's temp file */ # if MSDOS # if MICROSOFT # define CC_COMMAND "cl -c" /* C compiler */ # else /* TURBO_C */ # define CC_COMMAND "tc" /* C compiler */ # endif # define MAXTMPNAMELEN 80 /* length for tmp file name buffer */ # endif # define SCRATCHIN "%s\\siXXXXXX" /* DOS ONLY - output of filter program */ # define SCRATCHOUT "%s\\soXXXXXX" /* temp file used as input to filter */ # define SLASH '\\' # ifndef SHELL # if TOS # define SHELL "shell.ttp" /* default shell */ # else # define SHELL "command.com" /* default shell */ # endif # endif # define NEEDSYNC TRUE /* assume ":se sync" by default */ # define REDIRECT ">" /* shell's redirection of stderr */ # ifndef MAXMAPS # define MAXMAPS 40 # endif # ifndef EXINIT # define EXINIT "EXINIT" # endif #endif #if OSK # ifndef TMPDIR # define TMPDIR "/dd/tmp" /* directory where temp files live */ # endif # define TMPNAME "%s/elv%x%04x%03x" /* temp file */ # define CUTNAME "%s/elv_%04x%03x" /* cut buffer's temp file */ # ifndef CC_COMMAND # define CC_COMMAND "cc -r" /* name of the compiler */ # endif # ifndef EXRC # define EXRC ".exrc" /* init file in current directory */ # endif # define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */ # ifndef SHELL # define SHELL "shell" /* default shell */ # endif # define FILEPERMS (S_IREAD|S_IWRITE) /* file permissions used for creat() */ # define REDIRECT ">>-" /* shell's redirection of stderr */ #endif #ifndef TAGS # define TAGS "tags" /* tags file */ #endif #ifndef TMPNAME # define TMPNAME "%s/elv%x%04x.%03x" /* temp file */ #endif #ifndef CUTNAME # define CUTNAME "%s/elv_%04x.%03x" /* cut buffer's temp file */ #endif #ifndef EXRC # define EXRC "elvis.rc" #endif #ifndef HMEXRC # if !MSDOS && !TOS # define HMEXRC EXRC # endif #endif #ifndef KEYWORDPRG # define KEYWORDPRG "ref" #endif #ifndef SCRATCHOUT # define SCRATCHIN "%s/SIXXXXXX" # define SCRATCHOUT "%s/SOXXXXXX" #endif #ifndef ERRLIST # define ERRLIST "errlist" #endif #ifndef SLASH # define SLASH '/' #endif #ifndef SHELL # define SHELL "shell" #endif #ifndef REG # define REG #endif #ifndef NEEDSYNC # define NEEDSYNC FALSE #endif #ifndef FILEPERMS # define FILEPERMS 0666 #endif #ifndef CC_COMMAND # define CC_COMMAND "cc -c" #endif #ifndef MAKE_COMMAND # define MAKE_COMMAND "make" #endif #ifndef REDIRECT # define REDIRECT "2>" #endif #ifndef MAXMAPS # define MAXMAPS 20 /* number of :map keys */ #endif #ifndef MAXDIGS # define MAXDIGS 30 /* number of :digraph combos */ #endif #ifndef MAXABBR # define MAXABBR 20 /* number of :abbr entries */ #endif SHAR_EOF fi # end of overwriting check if test -f 'curses.h' then echo shar: will not over-write existing file "'curses.h'" else cat << \SHAR_EOF > 'curses.h' /* curses.h */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ #include "wconfig.h" /* This is the header file for a small, fast, fake curses package */ /* termcap stuff */ extern char *Tgoto(); extern char *Tgetstr(); extern void Tputs(); #if MSDOS /* BIOS interface used instead of termcap for MS-DOS */ extern int vmode; extern void v_up(); extern void v_cb(); extern void v_cs(); extern void v_ce(); extern void v_cl(); extern void v_cd(); extern void v_al(); extern void v_dl(); extern void v_sr(); extern void v_move(); #endif /* faddch() is a function. a pointer to it is passed to Tputs() */ extern int faddch(); /* data types */ #define WINDOW char /* CONSTANTS & SYMBOLS */ #define TRUE 1 #define FALSE 0 #define A_NORMAL 0 #define A_STANDOUT 1 #define A_BOLD 2 #define A_UNDERLINE 3 #define A_ALTCHARSET 4 #if MSDOS #define KBSIZ (10*1024) #else #define KBSIZ (6*1024) #endif /* extern variables, defined in curses.c */ extern short ospeed; /* tty speed, eg B2400 */ #if OSK extern char PC_; /* Pad char */ #else extern char PC; /* Pad char */ #endif extern WINDOW *stdscr; /* pointer into kbuf[] */ extern WINDOW kbuf[KBSIZ]; /* a very large output buffer */ extern int LINES; /* :li#: number of rows */ extern int COLS; /* :co#: number of columns */ extern int AM; /* :am: boolean: auto margins? */ extern int PT; /* :pt: boolean: physical tabs? */ extern char *BC; /* :bc=: backspace char string */ extern char *VB; /* :vb=: visible bell */ extern char *UP; /* :up=: move cursor up */ extern char *SO; /* :so=: standout start */ extern char *SE; /* :se=: standout end */ extern char *US; /* :us=: underline start */ extern char *UE; /* :ue=: underline end */ extern char *MD; /* :md=: bold start */ extern char *ME; /* :me=: bold end */ extern char *AS; /* :as=: alternate (italic) start */ extern char *AE; /* :ae=: alternate (italic) end */ extern char *CM; /* :cm=: cursor movement */ extern char *CE; /* :ce=: clear to end of line */ extern char *CD; /* :cd=: clear to end of screen */ extern char *AL; /* :al=: add a line */ extern char *DL; /* :dl=: delete a line */ #if OSK extern char *SR_; /* :sr=: scroll reverse */ #else extern char *SR; /* :sr=: scroll reverse */ #endif extern char *KS; /* :ks=: init string for cursor */ extern char *KE; /* :ke=: restore string for cursor */ extern char *KU; /* :ku=: sequence sent by up key */ extern char *KD; /* :kd=: sequence sent by down key */ extern char *KL; /* :kl=: sequence sent by left key */ extern char *KR; /* :kr=: sequence sent by right key */ extern char *PU; /* :PU=: key sequence sent by PgUp key */ extern char *PD; /* :PD=: key sequence sent by PgDn key */ extern char *HM; /* :HM=: key sequence sent by Home key */ extern char *EN; /* :EN=: key sequence sent by End key */ extern char *IM; /* :im=: insert mode start */ extern char *IC; /* :ic=: insert following char */ extern char *EI; /* :ei=: insert mode end */ extern char *DC; /* :dc=: delete a character */ extern char *TI; /* :ti=: terminal init */ /* GB */ extern char *TE; /* :te=: terminal exit */ /* GB */ #ifndef NO_CURSORSHAPE extern char *CQ; /* :cQ=: normal cursor */ extern char *CX; /* :cX=: cursor used for EX command/entry */ extern char *CV; /* :cV=: cursor used for VI command mode */ extern char *CI; /* :cI=: cursor used for VI input mode */ extern char *CR; /* :cR=: cursor used for VI replace mode */ #endif extern char *aend; /* end an attribute -- either UE or ME */ extern char ERASEKEY; /* taken from the ioctl structure */ /* Msdos-versions may use bios; others always termcap. * Will emit some 'code has no effect' warnings in unix. */ #if MSDOS extern char o_pcbios[1]; /* BAH! */ #define CHECKBIOS(x,y) (*o_pcbios ? (x) : (y)) #define VOIDBIOS(x,y) {if (*o_pcbios) {x;} else {y;}} #else #define CHECKBIOS(x,y) (y) #define VOIDBIOS(x,y) {y;} #endif #define do_VB() VOIDBIOS(;, Tputs(VB, 1, faddch)) #define do_UP() VOIDBIOS(v_up(), Tputs(UP, 1, faddch)) #define do_SO() VOIDBIOS((vmode=A_STANDOUT), Tputs(SO, 1, faddch)) #define do_SE() VOIDBIOS((vmode=A_NORMAL), Tputs(SE, 1, faddch)) #define do_US() VOIDBIOS((vmode=A_UNDERLINE), Tputs(US, 1, faddch)) #define do_UE() VOIDBIOS((vmode=A_NORMAL), Tputs(UE, 1, faddch)) #define do_MD() VOIDBIOS((vmode=A_BOLD), Tputs(MD, 1, faddch)) #define do_ME() VOIDBIOS((vmode=A_NORMAL), Tputs(ME, 1, faddch)) #define do_AS() VOIDBIOS((vmode=A_ALTCHARSET), Tputs(AS, 1, faddch)) #define do_AE() VOIDBIOS((vmode=A_NORMAL), Tputs(AE, 1, faddch)) #undef do_CM /* move */ #define do_CE() VOIDBIOS(v_ce(), Tputs(CE, 1, faddch)) #define do_CD() VOIDBIOS(v_cd(), Tputs(CD, 1, faddch)) #define do_AL() VOIDBIOS(v_al(), Tputs(AL, LINES, faddch)) #define do_DL() VOIDBIOS(v_dl(), Tputs(DL, LINES, faddch)) #if OSK #define do_SR() VOIDBIOS(v_sr(), Tputs(SR_, 1, faddch)) #else #define do_SR() VOIDBIOS(v_sr(), Tputs(SR, 1, faddch)) #endif #define do_KS() VOIDBIOS(1, Tputs(KS, 1, faddch)) #define do_KE() VOIDBIOS(1, Tputs(KE, 1, faddch)) #define do_IM() VOIDBIOS(;, Tputs(IM, 1, faddch)) #define do_IC() VOIDBIOS(;, Tputs(IC, 1, faddch)) #define do_EI() VOIDBIOS(;, Tputs(EI, 1, faddch)) #define do_DC() VOIDBIOS(;, Tputs(DC, COLS, faddch)) #define do_TI() VOIDBIOS(;, (void)ttywrite(TI, (unsigned)strlen(TI))) #define do_TE() VOIDBIOS(;, (void)ttywrite(TE, (unsigned)strlen(TE))) #ifndef NO_CURSORSHAPE # define do_CQ() VOIDBIOS(v_cs(), Tputs(CQ, 1, faddch)) # define do_CX() VOIDBIOS(v_cs(), Tputs(CX, 1, faddch)) # define do_CV() VOIDBIOS(v_cs(), Tputs(CV, 1, faddch)) # define do_CI() VOIDBIOS(v_cb(), Tputs(CI, 1, faddch)) # define do_CR() VOIDBIOS(v_cb(), Tputs(CR, 1, faddch)) #endif #define do_aend() VOIDBIOS((vmode=A_NORMAL), Tputs(aend, 1, faddch)) #define has_AM CHECKBIOS(1, AM) #define has_PT CHECKBIOS(0, PT) #define has_VB CHECKBIOS((char *)0, VB) #define has_UP CHECKBIOS((char *)1, UP) #define has_SO CHECKBIOS((char)1, (*SO)) #define has_SE CHECKBIOS((char)1, (*SE)) #define has_US CHECKBIOS((char)1, (*US)) #define has_UE CHECKBIOS((char)1, (*UE)) #define has_MD CHECKBIOS((char)1, (*MD)) #define has_ME CHECKBIOS((char)1, (*ME)) #define has_AS CHECKBIOS((char)1, (*AS)) #define has_AE CHECKBIOS((char)1, (*AE)) #undef has_CM /* cursor move: don't need */ #define has_CB CHECKBIOS(1, 0) #define has_CS CHECKBIOS(1, 0) #define has_CE CHECKBIOS((char *)1, CE) #define has_CD CHECKBIOS((char *)1, CD) #define has_AL CHECKBIOS((char *)1, AL) #define has_DL CHECKBIOS((char *)1, DL) #if OSK #define has_SR CHECKBIOS((char *)1, SR_) #else #define has_SR CHECKBIOS((char *)1, SR) #endif #define has_KS CHECKBIOS((char)1, (*KS)) #define has_KE CHECKBIOS((char)1, (*KE)) #define has_KU CHECKBIOS("#H", KU) #define has_KD CHECKBIOS("#P", KD) #define has_KL CHECKBIOS("#K", KL) #define has_KR CHECKBIOS("#M", KR) #define has_HM CHECKBIOS("#G", HM) #define has_EN CHECKBIOS("#O", EN) #define has_PU CHECKBIOS("#I", PU) #define has_PD CHECKBIOS("#Q", PD) #define has_IM CHECKBIOS((char)0, (*IM)) #define has_IC CHECKBIOS((char)0, (*IC)) #define has_EI CHECKBIOS((char)0, (*EI)) #define has_DC CHECKBIOS((char *)0, DC) #define has_TI CHECKBIOS((char)0, (*TI)) #define has_TE CHECKBIOS((char)0, (*TE)) #ifndef NO_CURSORSHAPE #define has_CQ CHECKBIOS((char *)1, CQ) #endif /* (pseudo)-Curses-functions */ #ifdef lint # define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : (stdscr[-1] = '\n'))) #else # if OSK # define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\l') : (stdscr[-1] = stdscr[-1]))) # else # define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : 0)) #endif #endif #define qaddch(ch) CHECKBIOS(v_put(ch), (*stdscr++ = (ch))) #if OSK #define addch(ch) if (qaddch(ch) == '\n') qaddch('\l'); else #else #define addch(ch) if (qaddch(ch) == '\n') qaddch('\r'); else #endif extern void initscr(); extern void endwin(); extern void suspend_curses(); extern void resume_curses(); extern void attrset(); extern void insch(); extern void qaddstr(); #define addstr(str) {qaddstr(str); _addCR;} #define move(y,x) VOIDBIOS(v_move(x,y), \ Tputs(Tgoto(CM, x, y), 1, faddch)) #define mvaddch(y,x,ch) {move(y,x); addch(ch);} #define refresh() VOIDBIOS(;, wrefresh(stdscr)) #define wrefresh(w) if ((w) != kbuf) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (unsigned)((w) - kbuf)); (w) = kbuf;}) else #define wqrefresh(w) if ((w) - kbuf > 2000) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (unsigned)((w) - kbuf)); (w) = kbuf;}) else #define standout() do_SO() #define standend() do_SE() #define clrtoeol() do_CE() #define clrtobot() do_CD() #define insertln() do_AL() #define deleteln() do_DL() #define delch() do_DC() #define scrollok(w,b) #define raw() #define echo() #define cbreak() #define noraw() #define noecho() #define nocbreak() SHAR_EOF fi # end of overwriting check if test -f 'elvis_cps.h' then echo shar: will not over-write existing file "'elvis_cps.h'" else cat << \SHAR_EOF > 'elvis_cps.h' /* DO NOT EDIT THIS FILE. It contains C->PostScript communication definitions that were automatically generated from elvis_cps.cps */ #define ps_RunFile(P__0) pprintf(PostScript, _CPS_ps_RunFile, 6, P__0) static char _CPS_ps_RunFile[] = "%srun "; #define ps_RegisterTag(P__0,P__1) pprintf(PostScript, _CPS_ps_RegisterTag, 7, P__0, P__1) static char _CPS_ps_RegisterTag[] = "%s\2469%d\264"; #define ps_ST(P__0,L__0) pprintf(PostScript, _CPS_ps_ST, 11, L__0, P__0) static char _CPS_ps_ST[] = "%*s/ST C S "; #define ps_scroll_down(P__0) pprintf(PostScript, _CPS_ps_scroll_down, 10, P__0) static char _CPS_ps_scroll_down[] = "%d/SR C S "; #define ps_pswrite(P__0,L__0) pprintf(PostScript, _CPS_ps_pswrite, 3, L__0, P__0) static char _CPS_ps_pswrite[] = "%*p"; #define ps_Cr() pprintf(PostScript, _CPS_ps_Cr, 8) static char _CPS_ps_Cr[] = "/Cr C S "; #define ps_Nl() pprintf(PostScript, _CPS_ps_Nl, 8) static char _CPS_ps_Nl[] = "/Nl C S "; #define ps_CrNl() pprintf(PostScript, _CPS_ps_CrNl, 10) static char _CPS_ps_CrNl[] = "/CrNl C S "; #define ps_beep() pprintf(PostScript, _CPS_ps_beep, 6) static char _CPS_ps_beep[] = "beep\246\222"; #define ps_enable_cursor() pprintf(PostScript, _CPS_ps_enable_cursor, 8) static char _CPS_ps_enable_cursor[] = "/ve C S "; #define ps_disable_cursor() pprintf(PostScript, _CPS_ps_disable_cursor, 8) static char _CPS_ps_disable_cursor[] = "/vi C S "; #define ps_rendermsg(P__0) pprintf(PostScript, _CPS_ps_rendermsg, 24, P__0) static char _CPS_ps_rendermsg[] = "%s\246\220/setfooter win send "; #define ps_appendmsg(P__0,P__1) pprintf(PostScript, _CPS_ps_appendmsg, 32, P__0, P__1) static char _CPS_ps_appendmsg[] = "%s%sappend\246\220/setfooter win send "; #define ps_set_title(P__0) pprintf(PostScript, _CPS_ps_set_title, 94, P__0, P__0, P__0) static char _CPS_ps_set_title[] = "%s/setlabel win send\2463\246</ProcessName\226Elvis-%sappend\246\226%s/setlabel /Icon /sendsubframe win send "; #define ps_get_lines_and_cols(P__0,P__1) ( pprintf(PostScript, _CPS_ps_get_lines_and_cols, 35), ps_checkfor(PostScriptInput, PSIO_WAIT_TAG, 10) > 0 && (_CPS_RETURN_ps_get_lines_and_cols(P__0, P__1), 1)) #define _CPS_RETURN_ps_get_lines_and_cols(P__0, P__1) pscanf(PostScriptInput,"dd", P__0, P__1) static char _CPS_ps_get_lines_and_cols[] = "{\200\n\246\311Height\246\321Width\246\321flush } C send "; #ifndef PSMACROS_H #include <NeWS/psmacros.h> /* standard cdef macros */ #endif SHAR_EOF fi # end of overwriting check if test -f 'osk.h' then echo shar: will not over-write existing file "'osk.h'" else cat << \SHAR_EOF > 'osk.h' /* * OS9 stat : @(#)stat.h 1.2 87/19/12 */ /* @(#)stat.h 6.1 */ /* * Structure of the result of stat */ #ifndef CLK_TCK #include <time.h> #endif struct stat { int st_dev; long st_ino; unsigned short st_mode; unsigned short st_nlink; unsigned short st_uid; unsigned short st_gid; int st_rdev; long st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; }; SHAR_EOF fi # end of overwriting check if test -f 'regexp.h' then echo shar: will not over-write existing file "'regexp.h'" else cat << \SHAR_EOF > 'regexp.h' /* * Definitions etc. for regexp(3) routines. * * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], * not the System V one. */ #define NSUBEXP 10 typedef struct regexp { char *startp[NSUBEXP]; char *endp[NSUBEXP]; int minlen; /* length of shortest possible match */ char first; /* first character, if known; else \0 */ char bol; /* boolean: must start at beginning of line? */ char program[1]; /* Unwarranted chumminess with compiler. */ } regexp; extern regexp *regcomp(); extern int regexec(); extern void regsub(); extern void regerror(); SHAR_EOF fi # end of overwriting check if test -f 'vi.h' then echo shar: will not over-write existing file "'vi.h'" else cat << \SHAR_EOF > 'vi.h' /* vi.h */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This is the header file for my version of vi. */ #define VERSION "ELVIS 1.4, by Steve Kirkendall" #define COPYING "This version of ELVIS is freely redistributable." #include <errno.h> extern int errno; #if TOS #define ENOENT (-AEFILNF) #endif #if TOS # include <types.h> # define O_RDONLY 0 # define O_WRONLY 1 # define O_RDWR 2 #else # if OSK # include <modes.h> # define O_RDONLY S_IREAD # define O_WRONLY S_IWRITE # define O_RDWR (S_IREAD | S_IWRITE) # define ENOENT E_PNNF # else # include <sys/types.h> # if COHERENT # include <sys/fcntl.h> # else # include <fcntl.h> # endif # endif #endif #ifndef O_BINARY # define O_BINARY 0 #endif #include "curses.h" /*------------------------------------------------------------------------*/ /* Miscellaneous constants. */ #define INFINITY 2000000001L /* a very large integer */ #define LONGKEY 10 /* longest possible raw :map key */ #ifndef MAXRCLEN # define MAXRCLEN 1000 /* longest possible .exrc file */ #endif /*------------------------------------------------------------------------*/ /* These describe how temporary files are divided into blocks */ #define BLKSIZE 1024 /* size of blocks */ #define MAXBLKS (BLKSIZE / sizeof(unsigned short)) typedef union { char c[BLKSIZE]; /* for text blocks */ unsigned short n[MAXBLKS]; /* for the header block */ } BLK; /*------------------------------------------------------------------------*/ /* These are used manipulate BLK buffers. */ extern BLK hdr; /* buffer for the header block */ extern BLK *blkget(); /* given index into hdr.c[], reads block */ extern BLK *blkadd(); /* inserts a new block into hdr.c[] */ /*------------------------------------------------------------------------*/ /* These are used to keep track of various flags */ extern struct _viflags { short file; /* file flags */ } viflags; /* file flags */ #define NEWFILE 0x0001 /* the file was just created */ #define READONLY 0x0002 /* the file is read-only */ #define HADNUL 0x0004 /* the file contained NUL characters */ #define MODIFIED 0x0008 /* the file has been modified */ #define NOFILE 0x0010 /* no name is known for the current text */ #define ADDEDNL 0x0020 /* newlines were added to the file */ /* macros used to set/clear/test flags */ #define setflag(x,y) viflags.x |= y #define clrflag(x,y) viflags.x &= ~y #define tstflag(x,y) (viflags.x & y) #define initflags() viflags.file = 0; /* The options */ extern char o_autoindent[1]; extern char o_autoprint[1]; extern char o_autowrite[1]; #ifndef NO_ERRLIST extern char o_cc[30]; #endif #ifndef NO_CHARATTR extern char o_charattr[1]; #endif extern char o_columns[3]; extern char o_digraph[1]; extern char o_directory[30]; extern char o_edcompatible[1]; extern char o_errorbells[1]; extern char o_exrefresh[1]; #ifndef NO_DIGRAPH extern char o_flipcase[80]; #endif #ifndef NO_SENTENCE extern char o_hideformat[1]; #endif extern char o_ignorecase[1]; #ifndef NO_EXTENSIONS extern char o_inputmode[1]; #endif extern char o_keytime[3]; extern char o_keywordprg[80]; extern char o_lines[3]; extern char o_list[1]; #ifndef NO_MAGIC extern char o_magic[1]; #endif #ifndef NO_ERRLIST extern char o_make[30]; #endif #ifndef NO_MODELINE extern char o_modeline[1]; #endif #ifndef NO_SENTENCE extern char o_paragraphs[30]; #endif #if MSDOS extern char o_pcbios[1]; #endif extern char o_readonly[1]; extern char o_report[3]; extern char o_scroll[3]; #ifndef NO_SENTENCE extern char o_sections[30]; #endif extern char o_shell[60]; #ifndef NO_SHOWMATCH extern char o_showmatch[1]; #endif #ifndef NO_SHOWMODE extern char o_smd[1]; #endif extern char o_shiftwidth[3]; extern char o_sidescroll[3]; extern char o_sync[1]; extern char o_tabstop[3]; extern char o_term[30]; extern char o_vbell[1]; extern char o_warn[1]; extern char o_wrapmargin[3]; extern char o_wrapscan[1]; /*------------------------------------------------------------------------*/ /* These help support the single-line multi-change "undo" -- shift-U */ extern char U_text[BLKSIZE]; extern long U_line; /*------------------------------------------------------------------------*/ /* These are used to refer to places in the text */ typedef long MARK; #define markline(x) (long)((x) / BLKSIZE) #define markidx(x) (int)((x) & (BLKSIZE - 1)) #define MARK_UNSET ((MARK)0) #define MARK_FIRST ((MARK)BLKSIZE) #define MARK_LAST ((MARK)(nlines * BLKSIZE)) #define MARK_AT_LINE(x) ((MARK)((x) * BLKSIZE)) #define NMARKS 29 extern MARK mark[NMARKS]; /* marks a-z, plus mark ' and two temps */ extern MARK cursor; /* mark where line is */ /*------------------------------------------------------------------------*/ /* These are used to keep track of the current & previous files. */ extern long origtime; /* modification date&time of the current file */ extern char origname[256]; /* name of the current file */ extern char prevorig[256]; /* name of the preceding file */ extern long prevline; /* line number from preceding file */ /*------------------------------------------------------------------------*/ /* misc housekeeping variables & functions */ extern int tmpfd; /* fd used to access the tmp file */ extern long lnum[MAXBLKS]; /* last line# of each block */ extern long nlines; /* number of lines in the file */ extern char args[BLKSIZE]; /* file names given on the command line */ extern int argno; /* the current element of args[] */ extern int nargs; /* number of filenames in args */ extern long changes; /* counts changes, to prohibit short-cuts */ extern int significant; /* boolean: was a *REAL* change made? */ extern int mustredraw; /* boolean: force total redraw of screen? */ extern BLK tmpblk; /* a block used to accumulate changes */ extern long topline; /* file line number of top line */ extern int leftcol; /* column number of left col */ #define botline (topline + LINES - 2) #define rightcol (leftcol + COLS - 1) extern int physcol; /* physical column number that cursor is on */ extern int physrow; /* physical row number that cursor is on */ extern int exwrote; /* used to detect verbose ex commands */ extern int doingdot; /* boolean: are we doing the "." command? */ extern int doingglobal; /* boolean: are doing a ":g" command? */ extern long rptlines; /* number of lines affected by a command */ extern char *rptlabel; /* description of how lines were affected */ extern char *fetchline(); /* read a given line from tmp file */ extern char *parseptrn(); /* isolate a regexp in a line */ extern MARK paste(); /* paste from cut buffer to a given point */ extern char *wildcard(); /* expand wildcards in filenames */ extern MARK input(); /* inserts characters from keyboard */ extern char *linespec(); /* finds the end of a /regexp/ string */ #define ctrl(ch) ((ch)&037) #ifndef NO_RECYCLE extern long allocate(); /* allocate a free block of the tmp file */ #endif extern int trapint(); /* trap handler for SIGINT */ extern void blkdirty(); /* marks a block as being "dirty" */ extern void blkflush(); /* writes a single dirty block to the disk */ extern void blksync(); /* forces all "dirty" blocks to disk */ extern void blkinit(); /* resets the block cache to "empty" state */ extern void beep(); /* rings the terminal's bell */ extern void exrefresh(); /* writes text to the screen */ extern void msg(); /* writes a printf-style message to the screen */ extern void reset_msg(); /* resets the "manymsgs" flag */ extern void endmsgs(); /* if "manymsgs" is set, then scroll up 1 line */ extern void garbage(); /* reclaims any garbage blocks */ extern void redraw(); /* updates the screen after a change */ extern void resume_curses();/* puts the terminal in "cbreak" mode */ extern void beforedo(); /* saves current revision before a new change */ extern void afterdo(); /* marks end of a beforedo() change */ extern void abortdo(); /* like "afterdo()" followed by "undo()" */ extern int undo(); /* restores file to previous undo() */ extern void dumpkey(); /* lists key mappings to the screen */ extern void mapkey(); /* defines a new key mapping */ extern void savekeys(); /* lists key mappings to a file */ extern void redrawrange(); /* records clues from modify.c */ extern void cut(); /* saves text in a cut buffer */ extern void delete(); /* deletes text */ extern void add(); /* adds text */ extern void change(); /* deletes text, and then adds other text */ extern void cutswitch(); /* updates cut buffers when we switch files */ extern void do_abbr(); /* defines or lists abbreviations */ extern void do_digraph(); /* defines or lists digraphs */ extern void exstring(); /* execute a string as EX commands */ extern void dumpopts(); extern void setopts(); extern void saveopts(); #ifndef NO_DIGRAPH extern void savedigs(); #endif #ifndef NO_ABBR extern void saveabbr(); #endif extern void cutname(); extern void cutname(); extern void initopts(); extern void cutend(); /*------------------------------------------------------------------------*/ /* macros that are used as control structures */ #define BeforeAfter(before, after) for((before),bavar=1;bavar;(after),bavar=0) #define ChangeText BeforeAfter(beforedo(FALSE),afterdo()) extern int bavar; /* used only in BeforeAfter macros */ /*------------------------------------------------------------------------*/ /* These are the movement commands. Each accepts a mark for the starting */ /* location & number and returns a mark for the destination. */ extern MARK m_updnto(); /* k j G */ extern MARK m_right(); /* h */ extern MARK m_left(); /* l */ extern MARK m_tocol(); /* | */ extern MARK m_front(); /* ^ */ extern MARK m_rear(); /* $ */ extern MARK m_fword(); /* w */ extern MARK m_bword(); /* b */ extern MARK m_eword(); /* e */ extern MARK m_fWord(); /* W */ extern MARK m_bWord(); /* B */ extern MARK m_eWord(); /* E */ extern MARK m_fparagraph(); /* } */ extern MARK m_bparagraph(); /* { */ extern MARK m_fsection(); /* ]] */ extern MARK m_bsection(); /* [[ */ extern MARK m_match(); /* % */ #ifndef NO_SENTENCE extern MARK m_fsentence(); /* ) */ extern MARK m_bsentence(); /* ( */ #endif extern MARK m_tomark(); /* 'm */ extern MARK m_nsrch(); /* n */ extern MARK m_Nsrch(); /* N */ extern MARK m_fsrch(); /* /regexp */ extern MARK m_bsrch(); /* ?regexp */ #ifndef NO_CHARSEARCH extern MARK m__ch(); /* ; , */ extern MARK m_fch(); /* f */ extern MARK m_tch(); /* t */ extern MARK m_Fch(); /* F */ extern MARK m_Tch(); /* T */ #endif extern MARK m_row(); /* H L M */ extern MARK m_z(); /* z */ extern MARK m_scroll(); /* ^B ^F ^E ^Y ^U ^D */ /* Some stuff that is used by movement functions... */ extern MARK adjmove(); /* a helper fn, used by move fns */ /* This macro is used to set the default value of cnt */ #define DEFAULT(val) if (cnt < 1) cnt = (val) /* These are used to minimize calls to fetchline() */ extern int plen; /* length of the line */ extern long pline; /* line number that len refers to */ extern long pchgs; /* "changes" level that len refers to */ extern char *ptext; /* text of previous line, if valid */ extern void pfetch(); extern char digraph(); /* This is used to build a MARK that corresponds to a specific point in the * line that was most recently pfetch'ed. */ #define buildmark(text) (MARK)(BLKSIZE * pline + (int)((text) - ptext)) /*------------------------------------------------------------------------*/ /* These are used to handle EX commands. */ #define CMD_NULL 0 /* NOT A VALID COMMAND */ #define CMD_ABBR 1 /* "define an abbreviation" */ #define CMD_ARGS 2 /* "show me the args" */ #define CMD_APPEND 3 /* "insert lines after this line" */ #define CMD_AT 4 /* "execute a cut buffer's contents via EX" */ #define CMD_BANG 5 /* "run a single shell command" */ #define CMD_CC 6 /* "run `cc` and then do CMD_ERRLIST" */ #define CMD_CD 7 /* "change directories" */ #define CMD_CHANGE 8 /* "change some lines" */ #define CMD_COPY 9 /* "copy the selected text to a given place" */ #define CMD_DELETE 10 /* "delete the selected text" */ #define CMD_DIGRAPH 11 /* "add a digraph, or display them all" */ #define CMD_EDIT 12 /* "switch to a different file" */ #define CMD_EQUAL 13 /* "display a line number" */ #define CMD_ERRLIST 14 /* "locate the next error in a list" */ #define CMD_FILE 15 /* "show the file's status" */ #define CMD_GLOBAL 16 /* "globally search & do a command" */ #define CMD_INSERT 17 /* "insert lines before the current line" */ #define CMD_JOIN 18 /* "join the selected line & the one after" */ #define CMD_LIST 19 /* "print lines, making control chars visible" */ #define CMD_MAKE 20 /* "run `make` and then do CMD_ERRLIST" */ #define CMD_MAP 21 /* "adjust the keyboard map" */ #define CMD_MARK 22 /* "mark this line" */ #define CMD_MKEXRC 23 /* "make a .exrc file" */ #define CMD_MOVE 24 /* "move the selected text to a given place" */ #define CMD_NEXT 25 /* "switch to next file in args" */ #define CMD_NUMBER 26 /* "print lines from the file w/ line numbers" */ #define CMD_PRESERVE 27 /* "act as though vi crashed" */ #define CMD_PREVIOUS 28 /* "switch to the previous file in args" */ #define CMD_PRINT 29 /* "print the selected text" */ #define CMD_PUT 30 /* "insert any cut lines before this line" */ #define CMD_QUIT 31 /* "quit without writing the file" */ #define CMD_READ 32 /* "append the given file after this line */ #define CMD_RECOVER 33 /* "recover file after vi crashes" - USE -r FLAG */ #define CMD_REWIND 34 /* "rewind to first file" */ #define CMD_SET 35 /* "set a variable's value" */ #define CMD_SHELL 36 /* "run some lines through a command" */ #define CMD_SHIFTL 37 /* "shift lines left" */ #define CMD_SHIFTR 38 /* "shift lines right" */ #define CMD_SOURCE 39 /* "interpret a file's contents as ex commands" */ #define CMD_STOP 40 /* same as CMD_SUSPEND */ #define CMD_SUBAGAIN 41 /* "repeat the previous substitution" */ #define CMD_SUBSTITUTE 42 /* "substitute text in this line" */ #define CMD_SUSPEND 43 /* "suspend the vi session" */ #define CMD_TR 44 /* "transliterate chars in the selected lines" */ #define CMD_TAG 45 /* "go to a particular tag" */ #define CMD_UNABBR 46 /* "remove an abbreviation definition" */ #define CMD_UNDO 47 /* "undo the previous command" */ #define CMD_UNMAP 48 /* "remove a key sequence map */ #define CMD_VERSION 49 /* "describe which version this is" */ #define CMD_VGLOBAL 50 /* "apply a cmd to lines NOT containing an RE" */ #define CMD_VISUAL 51 /* "go into visual mode" */ #define CMD_WQUIT 52 /* "write this file out (any case) & quit" */ #define CMD_WRITE 53 /* "write the selected(?) text to a given file" */ #define CMD_XIT 54 /* "write this file out (if modified) & quit" */ #define CMD_YANK 55 /* "copy the selected text into the cut buffer" */ #ifdef DEBUG # define CMD_DEBUG 56 /* access to internal data structures */ # define CMD_VALIDATE 57 /* check for internal consistency */ #endif typedef int CMD; extern void ex(); extern void vi(); extern void doexcmd(); #ifndef NO_ABBR extern void cmd_abbr(); #endif extern void cmd_append(); extern void cmd_args(); #ifndef NO_AT extern void cmd_at(); #endif extern void cmd_cd(); extern void cmd_delete(); #ifndef NO_DIGRAPH extern void cmd_digraph(); #endif extern void cmd_edit(); #ifndef NO_ERRLIST extern void cmd_errlist(); #endif extern void cmd_file(); extern void cmd_global(); extern void cmd_join(); extern void cmd_mark(); #ifndef NO_ERRLIST extern void cmd_make(); #endif extern void cmd_map(); #ifndef NO_MKEXRC extern void cmd_mkexrc(); #endif extern void cmd_next(); extern void cmd_print(); extern void cmd_put(); extern void cmd_read(); extern void cmd_set(); extern void cmd_shell(); extern void cmd_shift(); extern void cmd_source(); extern void cmd_substitute(); extern void cmd_tag(); extern void cmd_undo(); extern void cmd_version(); extern void cmd_visual(); extern void cmd_write(); extern void cmd_xit(); extern void cmd_move(); #ifdef DEBUG extern void cmd_debug(); extern void cmd_validate(); #endif /*----------------------------------------------------------------------*/ /* These are used to handle VI commands */ extern MARK v_1ex(); /* : */ extern MARK v_mark(); /* m */ extern MARK v_quit(); /* Q */ extern MARK v_redraw(); /* ^L ^R */ extern MARK v_ulcase(); /* ~ */ extern MARK v_undo(); /* u */ extern MARK v_xchar(); /* x */ extern MARK v_Xchar(); /* X */ extern MARK v_replace(); /* r */ extern MARK v_overtype(); /* R */ extern MARK v_selcut(); /* " */ extern MARK v_paste(); /* p P */ extern MARK v_yank(); /* y Y */ extern MARK v_delete(); /* d D */ extern MARK v_join(); /* J */ extern MARK v_insert(); /* a A i I o O */ extern MARK v_change(); /* c C */ extern MARK v_subst(); /* s */ extern MARK v_lshift(); /* < */ extern MARK v_rshift(); /* > */ extern MARK v_filter(); /* ! */ extern MARK v_status(); /* ^G */ extern MARK v_switch(); /* ^^ */ extern MARK v_tag(); /* ^] */ extern MARK v_xit(); /* ZZ */ extern MARK v_undoline(); /* U */ extern MARK v_again(); /* & */ #ifndef NO_EXTENSIONS extern MARK v_keyword(); /* ^K */ extern MARK v_increment(); /* * */ #endif #ifndef NO_ERRLIST extern MARK v_errlist(); /* * */ #endif #ifndef NO_AT extern MARK v_at(); /* @ */ #endif /*----------------------------------------------------------------------*/ /* These describe what mode we're in */ #define MODE_EX 1 /* executing ex commands */ #define MODE_VI 2 /* executing vi commands */ #define MODE_COLON 3 /* executing an ex command from vi mode */ #define MODE_QUIT 4 extern int mode; #define WHEN_VICMD 1 /* getkey: we're reading a VI command */ #define WHEN_VIINP 2 /* getkey: we're in VI's INPUT mode */ #define WHEN_VIREP 4 /* getkey: we're in VI's REPLACE mode */ #define WHEN_EX 8 /* getkey: we're in EX mode */ #define WHEN_MSG 16 /* getkey: we're at a "more" prompt */ #define WHEN_INMV 256 /* in input mode, interpret the key in VICMD mode */ SHAR_EOF fi # end of overwriting check if test -f 'wconfig.h' then echo shar: will not over-write existing file "'wconfig.h'" else cat << \SHAR_EOF > 'wconfig.h' /* wconfig.h , window related configuration header file */ /* defining macros in this way allows us to fall back on using the dumb terminal functions if no window system is available at runtime the convention used is to make the macro the same name as the original dumb terminal name with the leading letter 'capped -MCH */ #ifndef _elvis_w_macs_ #define _elvis_w_macs_ 1 #include "config.h" #include <NeWS/wire.h> #if OPENWINDOWS /* || SomeOtherWindowSys || ... */ /* using a window system */ #if OPENWINDOWS /* keep all the flags in a single structure to make it easier to convert to threads later */ struct ow_data { /* flags */ int background; int tty; int wLINES; int wCOLS; /* */ wire_Wire mainWire; int keyFromNews; }; #define ow_data_init(op) {\ (op)->background = 0;\ (op)->tty = 0;\ (op)->wLINES = 44;\ (op)->wCOLS = 80;\ (op)->mainWire = (wire_Wire) NULL;\ (op)->keyFromNews = -1;\ } extern struct ow_data Ow; /* termcap stuff */ #define Tgetent ow_tgetent #define Tputs ow_tputs #define Tgetnum ow_tgetnum #define Tgoto ow_tgoto #define Tgetstr ow_tgetstr #define Tgetflag ow_tgetflag #define Customflags(av, ac_p) ow_customflags(av, ac_p) #define Vi() ow_vi() #define Ex() ow_ex() #define Initscr() ow_initscr() #define Beep() ow_beep() #define Rendermsg(msg) ow_rendermsg(msg); #define Appendmsg(old,new) ow_appendmsg(old,new); #define FlushDisplay() ow_flushdisplay(); #define Getsize ow_getsize #define Resume_curses(quietly) ow_resume_curses((quietly)) #define Suspend_curses() ow_suspend_curses() #define Tmpstart(fname) ow_tmpstart(fname) #define Scrolldown(l,y,x) ow_scrolldown(l,y,x) #define Scrollup(l,y,x) ow_scrollup(l,y,x) #endif #else /* no window system , just use the dumb terminal functions */ /* termcap stuff */ #define Tgetent tgetent #define Tputs tputs #define Tgetnum tgetnum #define Tgoto tgoto #define Tgetstr tgetstr #define Tgetflag tgetflag #define Customflags(av, ac_p) /* no-op */ #define Vi() vi() #define Ex() ex() #define Initscr() initscr() #define Beep() beep() #define Rendermsg(msg) rendermsg(msg); #define Appendmsg(old,new) appendmsg(old,new); #define FlushDisplay() #define Getsize getsize #define Resume_curses(quietly) resume_curses((quietly)) #define Suspend_curses() suspend_curses() #define Tmpstart(fname) tmpstart(fname) #define Scrolldown(l,y,x) scrolldown(l,y,x) #define Scrollup(l,y,x) scrollup(l,y,x) #endif #endif SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # alias.c # atari.c # blk.c # cmd1.c # cmd2.c # ctags.c # curses.c # cut.c # This archive created: Thu Jan 10 17:21:07 1991 export PATH; PATH=/bin:$PATH if test -f 'alias.c' then echo shar: will not over-write existing file "'alias.c'" else cat << \SHAR_EOF > 'alias.c' /* alias.c */ /* Author: * Peter Reinig * Universitaet Kaiserslautern * Postfach 3049 * 7650 Kaiserslautern * W. Germany * reinig@physik.uni-kl.de */ /* This tiny program executes elvis with the flags that are appropriate * for a given command name. This program is used only on systems that * don't allow UNIX-style file links. * * The benefit of this program is: instead of having 5 copies of elvis * on your disk, you only need one copy of elvis and 4 copies of this * little program. */ #include <stdio.h> #include "config.h" #if OSK #define ELVIS "/dd/usr/cmds/elvis" #else #define ELVIS "elvis" #endif extern char **environ; extern int errno; extern char *malloc(); main(argc, argv) int argc; char *argv[]; { int pid, i, j; int letter; char **argblk; #if OSK extern int chainc(); #endif /* allocate enough space for a copy of the argument list, plus a * terminating NULL, plus maybe an added flag. */ argblk = (char **) malloc((argc + 2) * sizeof(char *)); if (!argblk) { #if OSK _errmsg(errno, "Can't get enough memory\n"); #else perror(argv[0]); #endif exit(2); } /* find the last letter in the invocation name of this program */ i = strlen(argv[0]); #if MSDOS || TOS /* we almost certainly must bypass ".EXE" or ".TTP" from argv[0] */ if (i > 4 && argv[0][i - 4] == '.') i -= 4; #endif letter = argv[0][i - 1]; /* copy argv to argblk, possibly inserting a flag such as "-R" */ argblk[0] = ELVIS; i = j = 1; switch (letter) { case 'w': /* "view" */ case 'W': argblk[i++] = "-R"; break; #if !OSK case 'x': /* "ex" */ case 'X': argblk[i++] = "-e"; break; #endif case 't': /* "input" */ case 'T': argblk[i++] = "-i"; break; } while (j < argc) { argblk[i++] = argv[j++]; } argblk[i] = (char *)0; /* execute the real ELVIS program */ #if OSK pid = os9exec(chainc, argblk[0], argblk, environ, 0, 0, 3); fprintf(stderr, "%s: cannot execute\n", argblk[0]); #else (void)execvp(argblk[0], argblk); perror(ELVIS); #endif } SHAR_EOF fi # end of overwriting check if test -f 'atari.c' then echo shar: will not over-write existing file "'atari.c'" else cat << \SHAR_EOF > 'atari.c' /* atari.c */ /* Author: * Guntram Blohm * Buchenstrasse 19 * 7904 Erbach, West Germany * Tel. ++49-7305-6997 * sorry - no regular network connection */ /* * This file contains the 'standard' functions which are not supported * by Atari/Mark Williams, and some other TOS-only requirements. */ #include "config.h" #include "vi.h" #if TOS #include <osbind.h> /* vi uses mode==0 only ... */ int access(file, mode) char *file; { int fd=Fopen(file, 0); if (fd<0) return -1; Fclose(fd); return 0; } char *mktemp(template) char *template; { return template; } /* read -- text mode, compress \r\n to \n * warning: might fail when maxlen==1 and at eol */ int tread(fd, buf, maxlen) int fd; char *buf; int maxlen; { int i, j, nread=read(fd, buf, (unsigned)maxlen); if (nread && buf[nread-1]=='\r') { nread--; lseek(fd, -1l, 1); } for (i=j=0; j<nread; i++,j++) { if (buf[j]=='\r' && buf[j+1]=='\n') j++; buf[i]=buf[j]; } return i; } int twrite(fd, buf, maxlen) int fd; char *buf; int maxlen; { int i, j, nwritten=0, hadnl=0; char writbuf[BLKSIZE]; for (i=j=0; j<maxlen; ) { if ((writbuf[i++]=buf[j++])=='\n') { writbuf[i-1]='\r'; if (i<BLKSIZE) writbuf[i++]='\n'; else hadnl=1; } if (i==BLKSIZE) { write(fd, writbuf, (unsigned)i); i=0; } if (hadnl) { writbuf[i++]='\n'; hadnl=0; } } if (i) write(fd, writbuf, (unsigned)i); return j; } #endif SHAR_EOF fi # end of overwriting check if test -f 'blk.c' then echo shar: will not over-write existing file "'blk.c'" else cat << \SHAR_EOF > 'blk.c' /* blk.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the functions that get/put blocks from the temp file. * It also contains the "do" and "undo" functions. */ #include "config.h" #include "vi.h" #ifndef NBUFS # define NBUFS 5 /* must be at least 3 -- more is better */ #endif extern long lseek(); /*------------------------------------------------------------------------*/ BLK hdr; /* buffer for the header block */ static int b4cnt; /* used to count context of beforedo/afterdo */ static struct _blkbuf { BLK buf; /* contents of a text block */ unsigned short logical; /* logical block number */ int dirty; /* must the buffer be rewritten? */ } blk[NBUFS], /* buffers for text[?] blocks */ *toonew, /* buffer which shouldn't be recycled yet */ *newtoo, /* another buffer which should be recycled */ *recycle = blk; /* next block to be recycled */ /* This function wipes out all buffers */ void blkinit() { int i; for (i = 0; i < NBUFS; i++) { blk[i].logical = 0; blk[i].dirty = FALSE; } for (i = 0; i < MAXBLKS; i++) { hdr.n[i] = 0; } } /* This function allocates a buffer and fills it with a given block's text */ BLK *blkget(logical) int logical; /* logical block number to fetch */ { REG struct _blkbuf *this; /* used to step through blk[] */ REG int i; /* if logical is 0, just return the hdr buffer */ if (logical == 0) { return &hdr; } /* see if we have that block in mem already */ for (this = blk; this < &blk[NBUFS]; this++) { if (this->logical == logical) { newtoo = toonew; toonew = this; return &this->buf; } } /* choose a block to be recycled */ do { this = recycle++; if (recycle == &blk[NBUFS]) { recycle = blk; } } while (this == toonew || this == newtoo); /* if it contains a block, flush that block */ blkflush(this); /* fill this buffer with the desired block */ this->logical = logical; if (hdr.n[logical]) { /* it has been used before - fill it from tmp file */ lseek(tmpfd, (long)hdr.n[logical] * (long)BLKSIZE, 0); if (read(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE) { msg("Error reading back from tmp file!"); } } else { /* it is new - zero it */ for (i = 0; i < BLKSIZE; i++) { this->buf.c[i] = 0; } } /* This isn't really a change, but it does potentially invalidate * the kinds of shortcuts that the "changes" variable is supposed * to protect us from... so count it as a change. */ changes++; /* mark it as being "not dirty" */ this->dirty = 0; /* return it */ newtoo = toonew; toonew = this; return &this->buf; } /* This function writes a block out to the temporary file */ void blkflush(this) REG struct _blkbuf *this; /* the buffer to flush */ { long seekpos; /* seek position of the new block */ unsigned short physical; /* physical block number */ /* if its empty (an orphan blkadd() maybe?) then make it dirty */ if (this->logical && !*this->buf.c) { blkdirty(&this->buf); } /* if it's an empty buffer or a clean version is on disk, quit */ if (!this->logical || hdr.n[this->logical] && !this->dirty) { return; } /* find a free place in the file */ #ifndef NO_RECYCLE seekpos = allocate(); lseek(tmpfd, seekpos, 0); #else seekpos = lseek(tmpfd, 0L, 2); #endif physical = seekpos / BLKSIZE; /* put the block there */ if (write(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE) { msg("Trouble writing to tmp file"); } this->dirty = FALSE; /* update the header so it knows we put it there */ hdr.n[this->logical] = physical; } /* This function sets a block's "dirty" flag or deletes empty blocks */ void blkdirty(bp) BLK *bp; /* buffer returned by blkget() */ { REG int i, j; REG char *scan; REG int k; /* find the buffer */ for (i = 0; i < NBUFS && bp != &blk[i].buf; i++) { } #ifdef DEBUG if (i >= NBUFS) { msg("blkdirty() called with unknown buffer at 0x%lx", bp); return; } if (blk[i].logical == 0) { msg("blkdirty called with freed buffer"); return; } #endif /* if this block ends with line# INFINITY, then it must have been * allocated unnecessarily during tmpstart(). Forget it. */ if (lnum[blk[i].logical] == INFINITY) { #ifdef DEBUG if (blk[i].buf.c[0]) { msg("bkldirty called with non-empty extra BLK"); } #endif blk[i].logical = 0; blk[i].dirty = FALSE; return; } /* count lines in this block */ for (j = 0, scan = bp->c; *scan && scan < bp->c + BLKSIZE; scan++) { if (*scan == '\n') { j++; } } /* adjust lnum, if necessary */ k = blk[i].logical; j += (lnum[k - 1] - lnum[k]); if (j != 0) { nlines += j; while (k < MAXBLKS && lnum[k] != INFINITY) { lnum[k++] += j; } } /* if it still has text, mark it as dirty */ if (*bp->c) { blk[i].dirty = TRUE; } else /* empty block, so delete it */ { /* adjust the cache */ k = blk[i].logical; for (j = 0; j < NBUFS; j++) { if (blk[j].logical >= k) { blk[j].logical--; } } /* delete it from hdr.n[] and lnum[] */ blk[i].logical = 0; blk[i].dirty = FALSE; while (k < MAXBLKS - 1) { hdr.n[k] = hdr.n[k + 1]; lnum[k] = lnum[k + 1]; k++; } hdr.n[MAXBLKS - 1] = 0; lnum[MAXBLKS - 1] = INFINITY; } } /* insert a new block into hdr, and adjust the cache */ BLK *blkadd(logical) int logical; /* where to insert the new block */ { REG int i; /* adjust hdr and lnum[] */ for (i = MAXBLKS - 1; i > logical; i--) { hdr.n[i] = hdr.n[i - 1]; lnum[i] = lnum[i - 1]; } hdr.n[logical] = 0; lnum[logical] = lnum[logical - 1]; /* adjust the cache */ for (i = 0; i < NBUFS; i++) { if (blk[i].logical >= logical) { blk[i].logical++; } } /* return the new block, via blkget() */ return blkget(logical); } /* This function forces all dirty blocks out to disk */ void blksync() { int i; for (i = 0; i < NBUFS; i++) { /* blk[i].dirty = TRUE; */ blkflush(&blk[i]); } if (*o_sync) { sync(); } } /*------------------------------------------------------------------------*/ static MARK undocurs; /* where the cursor should go if undone */ static long oldnlines; static long oldlnum[MAXBLKS]; /* This function should be called before each command that changes the text. * It defines the state that undo() will reset the file to. */ void beforedo(forundo) int forundo; /* boolean: is this for an undo? */ { REG int i; REG long l; /* if this is a nested call to beforedo, quit! Use larger context */ if (b4cnt++ > 0) { return; } /* force all block buffers to disk */ blksync(); #ifndef NO_RECYCLE /* perform garbage collection on blocks from tmp file */ garbage(); #endif /* force the header out to disk */ lseek(tmpfd, 0L, 0); if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) != BLKSIZE) { msg("Trouble writing header to tmp file "); } /* copy or swap oldnlines <--> nlines, oldlnum <--> lnum */ if (forundo) { for (i = 0; i < MAXBLKS; i++) { l = lnum[i]; lnum[i] = oldlnum[i]; oldlnum[i] = l; } l = nlines; nlines = oldnlines; oldnlines = l; } else { for (i = 0; i < MAXBLKS; i++) { oldlnum[i] = lnum[i]; } oldnlines = nlines; } /* save the cursor position */ undocurs = cursor; /* upon return, the calling function continues and makes changes... */ } /* This function marks the end of a (nested?) change to the file */ void afterdo() { if (--b4cnt) { /* after abortdo(), b4cnt may decribe nested beforedo/afterdo * pairs incorrectly. If it is decremented to often, then * keep b4cnt sane but don't do anything else. */ if (b4cnt < 0) b4cnt = 0; return; } /* make sure the cursor wasn't left stranded in deleted text */ if (markline(cursor) > nlines) { cursor = MARK_LAST; } /* NOTE: it is still possible that markidx(cursor) is after the * end of a line, so the Vi mode will have to take care of that * itself */ /* if a significant change has been made to this file, then set the * MODIFIED flag. */ if (significant) { setflag(file, MODIFIED); } } /* This function cuts short the current set of changes. It is called after * a SIGINT. */ void abortdo() { /* finish the operation immediately. */ if (b4cnt > 0) { b4cnt = 1; afterdo(); } /* in visual mode, the screen is probably screwed up */ if (mode == MODE_COLON) { mode = MODE_VI; } if (mode == MODE_VI) { redraw(MARK_UNSET, FALSE); } } /* This function discards all changes made since the last call to beforedo() */ int undo() { BLK oldhdr; /* if beforedo() has never been run, fail */ if (!tstflag(file, MODIFIED)) { msg("You haven't modified this file yet."); return FALSE; } /* read the old header form the tmp file */ lseek(tmpfd, 0L, 0); if (read(tmpfd, oldhdr.c, (unsigned)BLKSIZE) != BLKSIZE) { msg("Trouble rereading the old header from tmp file"); } /* "do" the changed version, so we can undo the "undo" */ cursor = undocurs; beforedo(TRUE); afterdo(); /* wipe out the block buffers - we can't assume they're correct */ blkinit(); /* use the old header -- and therefore the old text blocks */ hdr = oldhdr; /* This is a change */ changes++; return TRUE; } SHAR_EOF fi # end of overwriting check if test -f 'cmd1.c' then echo shar: will not over-write existing file "'cmd1.c'" else cat << \SHAR_EOF > 'cmd1.c' /* cmd1.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains some of the EX commands - mostly ones that deal with * files, options, etc. -- anything except text. */ #include "config.h" #include <ctype.h> #include "vi.h" #include "regexp.h" #if MSDOS #define DATE __DATE__ #endif #ifdef DEBUG /* print the selected lines with info on the blocks */ /*ARGSUSED*/ void cmd_debug(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { REG char *scan; REG long l; REG int i; int len; /* scan lnum[] to determine which block its in */ l = markline(frommark); for (i = 1; l > lnum[i]; i++) { } do { /* fetch text of the block containing that line */ scan = blkget(i)->c; /* calculate its length */ if (scan[BLKSIZE - 1]) { len = BLKSIZE; } else { len = strlen(scan); } /* print block stats */ msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)", i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]); msg("##### len=%d, buf=0x%lx, %sdirty", len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not "); if (bang) { while (--len >= 0) { addch(*scan); scan++; } } exrefresh(); /* next block */ i++; } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark)); } /* This function checks a lot of conditions to make sure they aren't screwy */ /*ARGSUSED*/ void cmd_validate(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { char *scan; int i; int nlcnt; /* used to count newlines */ int len; /* counts non-NUL characters */ /* check lnum[0] */ if (lnum[0] != 0L) { msg("lnum[0] = %ld", lnum[0]); } /* check each block */ for (i = 1; lnum[i] <= nlines; i++) { scan = blkget(i)->c; if (scan[BLKSIZE - 1]) { msg("block %d has no NUL at the end", i); } else { for (nlcnt = len = 0; *scan; scan++, len++) { if (*scan == '\n') { nlcnt++; } } if (scan[-1] != '\n') { msg("block %d doesn't end with '\\n' (length %d)", i, len); } if (bang || nlcnt != lnum[i] - lnum[i - 1]) { msg("block %d (line %ld?) has %d lines, but should have %ld", i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]); } } exrefresh(); } /* check lnum again */ if (lnum[i] != INFINITY) { msg("hdr.n[%d] = %d, but lnum[%d] = %ld", i, hdr.n[i], i, lnum[i]); } msg("# = \"%s\", %% = \"%s\"", prevorig, origname); } #endif /* DEBUG */ /*ARGSUSED*/ void cmd_mark(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { /* validate the name of the mark */ if (!extra || *extra < 'a' || *extra > 'z' || extra[1]) { msg("Invalid mark name"); return; } mark[*extra - 'a'] = tomark; } /*ARGSUSED*/ void cmd_write(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { int fd; int append; /* boolean: write in "append" mode? */ REG long l; REG char *scan; REG int i; /* if all lines are to be written, use tmpsave() */ if (frommark == MARK_FIRST && tomark == MARK_LAST) { tmpsave(extra, bang); return; } /* see if we're going to do this in append mode or not */ append = FALSE; if (extra[0] == '>' && extra[1] == '>') { extra += 2; append = TRUE; } /* either the file must not exist, or we must have a ! or be appending */ if (access(extra, 0) == 0 && !bang && !append) { msg("File already exists - Use :w! to overwrite"); return; } /* else do it line-by-line, like cmd_print() */ if (append) { #ifdef O_APPEND fd = open(extra, O_WRONLY|O_APPEND); #else fd = open(extra, O_WRONLY); if (fd >= 0) { lseek(fd, 0L, 2); } #endif } else { fd = -1; /* so we know the file isn't open yet */ } if (fd < 0) { fd = creat(extra, FILEPERMS); if (fd < 0) { msg("Can't write to \"%s\"", extra); return; } } for (l = markline(frommark); l <= markline(tomark); l++) { /* get the next line */ scan = fetchline(l); i = strlen(scan); scan[i++] = '\n'; /* print the line */ twrite(fd, scan, i); } close(fd); } /*ARGSUSED*/ void cmd_shell(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { static char prevextra[80]; /* special case: ":sh" means ":!sh" */ if (cmd == CMD_SHELL) { extra = o_shell; frommark = tomark = 0L; } /* if extra is "!", substute previous command */ if (*extra == '!') { if (!*prevextra) { msg("No previous shell command to substitute for '!'"); return; } extra = prevextra; } else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1) { strcpy(prevextra, extra); } /* if no lines were specified, just run the command */ Suspend_curses(); if (frommark == 0L) { system(extra); } else /* pipe lines from the file through the command */ { filter(frommark, tomark, extra); } /* resume curses quietly for MODE_EX, but noisily otherwise */ Resume_curses(mode == MODE_EX); } /*ARGSUSED*/ void cmd_global(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; /* rest of the command line */ { char *cmdptr; /* the command from the command line */ char cmdln[100]; /* copy of the command from the command line */ char *line; /* a line from the file */ long l; /* used as a counter to move through lines */ long lqty; /* quantity of lines to be scanned */ long nchanged; /* number of lines changed */ regexp *re; /* the compiled search expression */ /* can't nest global commands */ if (doingglobal) { msg("Can't nest global commands."); rptlines = -1L; return; } /* ":g! ..." is the same as ":v ..." */ if (bang) { cmd = CMD_VGLOBAL; } /* make sure we got a search pattern */ if (*extra != '/' && *extra != '?') { msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v'); return; } /* parse & compile the search pattern */ cmdptr = parseptrn(extra); if (!extra[1]) { msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v'); return; } re = regcomp(extra + 1); if (!re) { /* regcomp found & described an error */ return; } /* for each line in the range */ doingglobal = TRUE; ChangeText { /* NOTE: we have to go through the lines in a forward order, * otherwise "g/re/p" would look funny. *BUT* for "g/re/d" * to work, simply adding 1 to the line# on each loop won't * work. The solution: count lines relative to the end of * the file. Think about it. */ for (l = nlines - markline(frommark), lqty = markline(tomark) - markline(frommark) + 1L, nchanged = 0L; lqty > 0 && nlines - l >= 0 && nchanged >= 0L; l--, lqty--) { /* fetch the line */ line = fetchline(nlines - l); /* if it contains the search pattern... */ if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL)) { /* move the cursor to that line */ cursor = MARK_AT_LINE(nlines - l); /* do the ex command (without mucking up * the original copy of the command line) */ strcpy(cmdln, cmdptr); rptlines = 0L; doexcmd(cmdln); nchanged += rptlines; } } } doingglobal = FALSE; /* free the regexp */ free(re); /* Reporting...*/ rptlines = nchanged; } /*ARGSUSED*/ void cmd_file(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { #ifndef CRUNCH /* if we're given a new filename, use it as this file's name */ if (extra && *extra) { strcpy(origname, extra); } #endif if (cmd == CMD_FILE) { msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]", *origname ? origname : "[NO FILE]", tstflag(file, MODIFIED) ? "[MODIFIED]" : "", tstflag(file, READONLY) ? "[READONLY]" : "", nlines, markline(frommark), markline(frommark) * 100 / nlines); } else if (markline(frommark) == markline(tomark)) { msg("%ld", markline(frommark)); } else { msg("range \"%ld,%ld\" contains %ld lines", markline(frommark), markline(tomark), markline(tomark) - markline(frommark) + 1L); } } /*ARGSUSED*/ void cmd_edit(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { long line = 1L; /* might be set to prevline */ /* Editing previous file? Then start at previous line */ if (!strcmp(extra, prevorig)) { line = prevline; } #ifndef CRUNCH /* if we were given an explicit starting line, then start there */ if (*extra == '+') { for (extra++, line = 0L; *extra >= '0' && *extra <= '9'; extra++) { line *= 10L; line += (*extra - '0'); } while (isascii(*extra) && isspace(*extra)) { extra++; } } #endif /* not CRUNCH */ /* switch files */ if (tmpabort(bang)) { Tmpstart(extra); if (line <= nlines && line >= 1L) { cursor = MARK_AT_LINE(line); } } else { msg("Use edit! to abort changes, or w to save changes"); /* so we can say ":e!#" next time... */ strcpy(prevorig, extra); prevline = 1L; } } /* This code is also used for rewind -- GB */ /*ARGSUSED*/ void cmd_next(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { int i, j; char *scan; char *build; /* if extra stuff given, use ":args" to define a new args list */ if (cmd == CMD_NEXT && extra && *extra) { cmd_args(frommark, tomark, cmd, bang, extra); } /* move to the next arg */ if (cmd == CMD_NEXT) { i = argno + 1; } else if (cmd == CMD_PREVIOUS) { i = argno - 1; } else /* cmd == CMD_REWIND */ { i = 0; } if (i < 0 || i >= nargs) { msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more "); return; } /* find & isolate the name of the file to edit */ for (j = i, scan = args; j > 0; j--) { while(!isascii(*scan) || !isspace(*scan)) { scan++; } while (isascii(*scan) && isspace(*scan)) { scan++; } } for (build = tmpblk.c; *scan && (!isascii(*scan) || !isspace(*scan)); ) { *build++ = *scan++; } *build = '\0'; /* switch to the next file */ if (tmpabort(bang)) { Tmpstart(tmpblk.c); argno = i; } else { msg("Use :%s! to abort changes, or w to save changes", cmd == CMD_NEXT ? "next" : cmd == CMD_PREVIOUS ? "previous" : "rewind"); } } /* also called from :wq -- always writes back in this case */ /*ARGSUSED*/ void cmd_xit(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { static long whenwarned; /* when the user was last warned of extra files */ int oldflag; /* if there are more files to edit, then warn user */ if (argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT)) { msg("More files to edit -- Use \":n\" to go to next file"); whenwarned = changes; return; } if (cmd == CMD_QUIT) { if (tmpabort(bang)) { mode = MODE_QUIT; } else { msg("Use q! to abort changes, or wq to save changes"); } } else { /* else try to save this file */ oldflag = tstflag(file, MODIFIED); if (cmd == CMD_WQUIT) setflag(file, MODIFIED); if (tmpend(bang)) { mode = MODE_QUIT; } else { msg("Could not save file -- use quit! to abort changes, or w filename"); } if (!oldflag) clrflag(file, MODIFIED); } } /*ARGSUSED*/ void cmd_args(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { char *scan; char *eow; int col; int arg; int addcols; int scrolled = 0; /* if no extra names given, or just current name, then report the args * we have now. */ if (!extra || !*extra) { for (scan = args, col=arg=0; *scan; ) { while (*scan && isascii(*scan) && isspace(*scan)) scan++; eow = scan; while (*eow && (!isascii(*++eow) || !isspace(*eow))) ; if (arg == argno) addcols = 2; else addcols = 0; if (col+addcols+(int)(eow-scan)+1>=COLS) { addch('\n'); scrolled=1; col=0; } else if (arg) { qaddch(' '); col++; } if (arg == argno) qaddch('['); while (scan < eow) { qaddch(*scan++); col++; } if (arg == argno) qaddch(']'); arg++; col+=addcols; } /* write a trailing newline */ if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col) addch('\n'); exrefresh(); } else /* new args list given */ { strcpy(args, extra); argno = -1; /* before the first, so :next will go to first */ /* count the names */ for (nargs = 0, scan = args; *scan; nargs++) { while (*scan && (!isascii(*scan) || !isspace(*scan))) { scan++; } while (isascii(*scan) && isspace(*scan)) { scan++; } } msg("%d files to edit", nargs); } } /*ARGSUSED*/ void cmd_cd(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { char *getenv(); /* default directory name is $HOME */ if (!*extra) { extra = getenv("HOME"); if (!extra) { msg("environment variable $HOME not set"); return; } } /* go to the directory */ if (chdir(extra) < 0) { perror(extra); } } /*ARGSUSED*/ void cmd_map(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { char *mapto; /* "map" with no extra will dump the map table contents */ if (!*extra) { dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD); } else { /* "extra" is key to map, followed my what it maps to */ for (mapto = extra; *mapto && *mapto != ' ' && *mapto!= '\t'; mapto++) { } while (*mapto == ' ' || *mapto == '\t') { *mapto++ = '\0'; } mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0); } } /*ARGSUSED*/ void cmd_set(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { if (!*extra) { dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */ } else if (!strcmp(extra, "all")) { dumpopts(TRUE); /* "TRUE" means "dump all" - even unset vars */ } else { setopts(extra); /* That option may have affected the appearence of text */ changes++; } } /*ARGSUSED*/ void cmd_tag(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { char *scan; /* used to scan through the tmpblk.c */ char *cmp; /* char of tag name we're comparing, or NULL */ char *end; /* marks the end of chars in tmpblk.c */ int fd; /* file descriptor used to read the file */ #ifndef NO_MAGIC char wasmagic; /* preserves the original state of o_magic */ #endif static char prevtag[30]; /* if no tag is given, use the previous tag */ if (!extra || !*extra) { if (!*prevtag) { msg("No previous tag"); return; } extra = prevtag; } else { strncpy(prevtag, extra, sizeof prevtag); } /* open the tags file */ fd = open(TAGS, O_RDONLY); if (fd < 0) { msg("No tags file"); return; } /* Hmmm... this would have been a lot easier with <stdio.h> */ /* find the line with our tag in it */ for(scan = end = tmpblk.c, cmp = extra; ; scan++) { /* read a block, if necessary */ if (scan >= end) { end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE); scan = tmpblk.c; if (scan >= end) { msg("tag \"%s\" not found", extra); close(fd); return; } } /* if we're comparing, compare... */ if (cmp) { /* matched??? wow! */ if (!*cmp && *scan == '\t') { break; } if (*cmp++ != *scan) { /* failed! skip to newline */ cmp = (char *)0; } } /* if we're skipping to newline, do it fast! */ if (!cmp) { while (scan < end && *scan != '\n') { scan++; } if (scan < end) { cmp = extra; } } } /* found it! get the rest of the line into memory */ for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; ) { *cmp++ = *scan++; } if (scan == end) { tread(fd, cmp, BLKSIZE - (cmp - tmpblk.c)); } /* we can close the tags file now */ close(fd); /* extract the filename from the line, and edit the file */ for (cmp = tmpblk.c; *cmp != '\t'; cmp++) { } *cmp++ = '\0'; if (strcmp(origname, tmpblk.c) != 0) { if (!tmpabort(bang)) { msg("Use :tag! to abort changes, or :w to save changes"); return; } Tmpstart(tmpblk.c); } /* move to the desired line (or to line 1 if that fails) */ #ifndef NO_MAGIC wasmagic = *o_magic; *o_magic = FALSE; #endif cursor = MARK_FIRST; linespec(cmp, &cursor); if (cursor == MARK_UNSET) { cursor = MARK_FIRST; } #ifndef NO_MAGIC *o_magic = wasmagic; #endif } /*ARGSUSED*/ void cmd_visual(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { mode = MODE_VI; msg(""); } /* describe this version of the program */ /*ARGSUSED*/ void cmd_version(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { #ifndef DATE msg("%s", VERSION); #else msg("%s (%s)", VERSION, DATE); #endif #ifdef COMPILED_BY msg("Compiled by %s", COMPILED_BY); #endif #ifdef CREDIT msg("%s", CREDIT); #endif #ifdef COPYING msg("%s", COPYING); #endif } #ifndef NO_MKEXRC /* make a .exrc file which describes the current configuration */ /*ARGSUSED*/ void cmd_mkexrc(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { int fd; /* the default name for the .exrc file EXRC */ if (!*extra) { extra = EXRC; } /* create the .exrc file */ fd = creat(extra, FILEPERMS); if (fd < 0) { msg("Couldn't create a new \"%s\" file", extra); return; } /* save stuff */ savekeys(fd); saveopts(fd); #ifndef NO_DIGRAPH savedigs(fd); #endif #ifndef NO_ABBR saveabbr(fd); #endif /* close the file */ close(fd); msg("Created a new \"%s\" file", extra); } #endif #ifndef NO_DIGRAPH /*ARGSUSED*/ void cmd_digraph(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { do_digraph(bang, extra); } #endif #ifndef NO_ERRLIST static char errfile[256]; /* the name of a file containing an error */ static long errline; /* the line number for an error */ /* This static function tries to parse an error message. * * For most compilers, the first word is taken to be the name of the erroneous * file, and the first number after that is taken to be the line number where * the error was detected. The description of the error follows, possibly * preceded by an "error ... :" or "warning ... :" label which is skipped. * * For Coherent, error messages look like "line#: filename: message". * * For non-error lines, or unparsable error lines, this function returns NULL. * Normally, though, it alters errfile and errline, and returns a pointer to * the description. */ static char *parse_errmsg(text) REG char *text; { REG char *cpy; long atol(); # if COHERENT || TOS /* any Mark Williams compiler */ /* Get the line number. If no line number, then ignore this line. */ errline = atol(text); if (errline == 0L) return (char *)0; /* Skip to the start of the filename */ while (*text && *text++ != ':') { } if (!*text++) return (char *)0; /* copy the filename to errfile */ for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; ) { } if (!*text++) return (char *)0; cpy[-1] = '\0'; return text; # else /* not a Mark Williams compiler */ char *errmsg; /* the error message is the whole line, by default */ errmsg = text; /* skip leading garbage */ while (*text && !(isascii(*text) && isalnum(*text))) { text++; } /* copy over the filename */ cpy = errfile; while(isascii(*text) && isalnum(*text) || *text == '.') { *cpy++ = *text++; } *cpy = '\0'; /* ignore the name "Error" and filenames that contain a '/' */ if (*text == '/' || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0) { return (char *)0; } /* skip garbage between filename and line number */ while (*text && !(isascii(*text) && isdigit(*text))) { text++; } /* if the number is part of a larger word, then ignore this line */ if (*text && isascii(text[-1]) && isalpha(text[-1])) { return (char *)0; } /* get the error line */ errline = 0L; while (isascii(*text) && isdigit(*text)) { errline *= 10; errline += (*text - '0'); text++; } /* any line which lacks a filename or line number should be ignored */ if (!errfile[0] || !errline) { return (char *)0; } /* locate the beginning of the error description */ while (*text && isascii(*text) && !isspace(*text)) { text++; } while (*text) { # ifndef CRUNCH /* skip "error #:" and "warning #:" clauses */ if (!strncmp(text + 1, "rror ", 5) || !strncmp(text + 1, "arning ", 7) || !strncmp(text + 1, "atal error", 10)) { do { text++; } while (*text && *text != ':'); continue; } # endif /* anything other than whitespace or a colon is important */ if (!isascii(*text) || (!isspace(*text) && *text != ':')) { errmsg = text; break; } /* else keep looking... */ text++; } return errmsg; # endif /* not COHERENT */ } /*ARGSUSED*/ void cmd_errlist(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { static long endline;/* original number of lines in this file */ static long offset; /* offset of the next line in the errlist file */ static int fd = -2;/* fd of the errlist file */ int i; char *errmsg; /* if a new errlist file is named, open it */ if (extra && extra[0]) { /* close the old one */ if (fd >= 0) { close(fd); } fd = open(extra, O_RDONLY); offset = 0L; } else if (fd < 0) { fd = open(ERRLIST, O_RDONLY); offset = 0L; } /* do we have an errlist file now? */ if (fd < 0) { msg("There is no errlist file"); beep(); return; } /* find the next error message in the file */ do { /* read the next line from the errlist */ lseek(fd, offset, 0); if (tread(fd, tmpblk.c, (unsigned)BLKSIZE) <= 0) { msg("No more errors"); beep(); close(fd); return; } for (i = 0; tmpblk.c[i] != '\n'; i++) { } tmpblk.c[i++] = 0; /* look for an error message in the line */ errmsg = parse_errmsg(tmpblk.c); if (!errmsg) { offset += i; } } while (!errmsg); /* switch to the file containing the error, if this isn't it */ if (strcmp(origname, errfile)) { if (!tmpabort(bang)) { msg("Use :er! to abort changes, or :w to save changes"); beep(); return; } Tmpstart(errfile); endline = nlines; } else if (endline == 0L) { endline = nlines; } /* go to the line where the error was detected */ cursor = MARK_AT_LINE(errline + (nlines - endline)); if (cursor > MARK_LAST) { cursor = MARK_LAST; } if (mode == MODE_VI) { redraw(cursor, FALSE); } /* display the error message */ if (nlines > endline) { msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg); } else if (nlines < endline) { msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg); } else { msg("line %ld: %.65s", errline, errmsg); } /* remember where the NEXT error line will start */ offset += i; } /*ARGSUSED*/ void cmd_make(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { BLK buf; /* if the file hasn't been saved, then complain unless ! */ if (tstflag(file, MODIFIED) && !bang) { msg("\"%s\" not saved yet", origname); return; } /* build the command */ sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST); qaddstr(buf.c); addch('\n'); /* run the command, with curses temporarily disabled */ Suspend_curses(); system(buf.c); Resume_curses(mode == MODE_EX); if (mode == MODE_COLON) mode = MODE_VI; /* run the "errlist" command */ cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST); } #endif #ifndef NO_ABBR /*ARGSUSED*/ void cmd_abbr(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; CMD cmd; int bang; char *extra; { do_abbr(extra); } #endif SHAR_EOF fi # end of overwriting check if test -f 'cmd2.c' then echo shar: will not over-write existing file "'cmd2.c'" else cat << \SHAR_EOF > 'cmd2.c' /* cmd2.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains some of the commands - mostly ones that change text */ #include <ctype.h> #include "config.h" #include "vi.h" #include "regexp.h" #if TOS # include <stat.h> #else # if OSK # include "osk.h" # else # include <sys/stat.h> # endif #endif /*ARGSUSED*/ void cmd_substitute(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; /* rest of the command line */ { char *line; /* a line from the file */ regexp *re; /* the compiled search expression */ char *subst; /* the substitution string */ char *opt; /* substitution options */ long l; /* a line number */ char *s, *d; /* used during subtitutions */ char *conf; /* used during confirmation */ long chline; /* # of lines changed */ long chsub; /* # of substitutions made */ static optp; /* boolean option: print when done? */ static optg; /* boolean option: substitute globally in line? */ static optc; /* boolean option: confirm before subst? */ /* for now, assume this will fail */ rptlines = -1L; if (cmd == CMD_SUBAGAIN) { #ifndef NO_MAGIC if (*o_magic) subst = "~"; else #endif subst = "\\~"; re = regcomp(""); /* if visual "&", then turn off the "p" and "c" options */ if (bang) { optp = optc = FALSE; } } else { /* make sure we got a search pattern */ if (*extra != '/' && *extra != '?') { msg("Usage: s/regular expression/new text/"); return; } /* parse & compile the search pattern */ subst = parseptrn(extra); re = regcomp(extra + 1); } /* abort if RE error -- error message already given by regcomp() */ if (!re) { return; } if (cmd == CMD_SUBSTITUTE) { /* parse the substitution string & find the option string */ for (opt = subst; *opt && *opt != *extra; opt++) { if (*opt == '\\' && opt[1]) { opt++; } } if (*opt) { *opt++ = '\0'; } /* analyse the option string */ if (!*o_edcompatible) { optp = optg = optc = FALSE; } while (*opt) { switch (*opt++) { case 'p': optp = !optp; break; case 'g': optg = !optg; break; case 'c': optc = !optc; break; case ' ': case '\t': break; default: msg("Subst options are p, c, and g -- not %c", opt[-1]); return; } } } /* if "c" or "p" flag was given, and we're in visual mode, then NEWLINE */ if ((optc || optp) && mode == MODE_VI) { addch('\n'); exrefresh(); } ChangeText { /* reset the change counters */ chline = chsub = 0L; /* for each selected line */ for (l = markline(frommark); l <= markline(tomark); l++) { /* fetch the line */ line = fetchline(l); /* if it contains the search pattern... */ if (regexec(re, line, TRUE)) { /* increment the line change counter */ chline++; /* initialize the pointers */ s = line; d = tmpblk.c; /* do once or globally ... */ do { #ifndef CRUNCH /* confirm, if necessary */ if (optc) { for (conf = line; conf < re->startp[0]; conf++) addch(*conf); standout(); for ( ; conf < re->endp[0]; conf++) addch(*conf); standend(); for (; *conf; conf++) addch(*conf); addch('\n'); exrefresh(); if (getkey(0) != 'y') { /* copy accross the original chars */ while (s < re->endp[0]) *d++ = *s++; /* skip to next match on this line, if any */ continue; } } #endif /* not CRUNCH */ /* increment the substitution change counter */ chsub++; /* this may be the first line to redraw */ redrawrange(l, l + 1L, l + 1L); /* copy stuff from before the match */ while (s < re->startp[0]) { *d++ = *s++; } /* substitute for the matched part */ regsub(re, subst, d); s = re->endp[0]; d += strlen(d); } while (optg && regexec(re, s, FALSE)); /* copy stuff from after the match */ while (*d++ = *s++) /* yes, ASSIGNMENT! */ { } /* replace the old version of the line with the new */ d[-1] = '\n'; d[0] = '\0'; change(MARK_AT_LINE(l), MARK_AT_LINE(l + 1), tmpblk.c); /* if supposed to print it, do so */ if (optp) { addstr(tmpblk.c); exrefresh(); } /* move the cursor to that line */ cursor = MARK_AT_LINE(l); } } } /* tweak for redrawing */ mustredraw = TRUE; /* free the regexp */ free(re); /* if done from within a ":g" command, then finish silently */ if (doingglobal) { rptlines = chline; rptlabel = "changed"; return; } /* Reporting */ if (chsub == 0) { msg("Substitution failed"); } else if (chline >= *o_report) { msg("%ld substitutions on %ld lines", chsub, chline); } } /*ARGSUSED*/ void cmd_delete(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { MARK curs2; /* an altered form of the cursor */ /* choose your cut buffer */ if (*extra == '"') { extra++; } if (*extra) { cutname(*extra); } /* make sure we're talking about whole lines here */ frommark = frommark & ~(BLKSIZE - 1); tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE; /* yank the lines */ cut(frommark, tomark); /* if CMD_DELETE then delete the lines */ if (cmd != CMD_YANK) { curs2 = cursor; ChangeText { /* delete the lines */ delete(frommark, tomark); } if (curs2 > tomark) { cursor = curs2 - tomark + frommark; } else if (curs2 > frommark) { cursor = frommark; } } } /*ARGSUSED*/ void cmd_append(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { long l; /* line counter */ ChangeText { /* if we're doing a change, delete the old version */ if (cmd == CMD_CHANGE) { /* delete 'em */ cmd_delete(frommark, tomark, cmd, bang, extra); } /* new lines start at the frommark line, or after it */ l = markline(frommark); if (cmd == CMD_APPEND) { l++; } /* get lines until no more lines, or "." line, and insert them */ while (vgets('\0', tmpblk.c, BLKSIZE) >= 0) { addch('\n'); if (!strcmp(tmpblk.c, ".")) { break; } strcat(tmpblk.c, "\n"); add(MARK_AT_LINE(l), tmpblk.c); l++; } } /* on the odd chance that we're calling this from vi mode ... */ redraw(MARK_UNSET, FALSE); } /*ARGSUSED*/ void cmd_put(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { /* choose your cut buffer */ if (*extra == '"') { extra++; } if (*extra) { cutname(*extra); } /* paste it */ ChangeText { cursor = paste(frommark, TRUE, FALSE); } } /*ARGSUSED*/ void cmd_join(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { long l; char *scan; int len; /* length of the new line */ /* if only one line is specified, assume the following one joins too */ if (markline(frommark) == nlines) { msg("Nothing to join with this line"); return; } if (markline(frommark) == markline(tomark)) { tomark += BLKSIZE; } /* get the first line */ l = markline(frommark); strcpy(tmpblk.c, fetchline(l)); len = strlen(tmpblk.c); /* build the longer line */ while (++l <= markline(tomark)) { /* get the next line */ scan = fetchline(l); /* remove any leading whitespace */ while (*scan == '\t' || *scan == ' ') { scan++; } /* see if the line will fit */ if (strlen(scan) + len + 3 > BLKSIZE) { msg("Can't join -- the resulting line would be too long"); return; } /* catenate it, with a space (or two) in between */ if (len >= 1 && (tmpblk.c[len - 1] == '.' || tmpblk.c[len - 1] == '?' || tmpblk.c[len - 1] == '!')) { tmpblk.c[len++] = ' '; } tmpblk.c[len++] = ' '; strcpy(tmpblk.c + len, scan); len += strlen(scan); } tmpblk.c[len++] = '\n'; tmpblk.c[len] = '\0'; /* make the change */ ChangeText { frommark &= ~(BLKSIZE - 1); tomark &= ~(BLKSIZE - 1); tomark += BLKSIZE; change(frommark, tomark, tmpblk.c); } /* Reporting... */ rptlines = markline(tomark) - markline(frommark) - 1L; rptlabel = "joined"; } /*ARGSUSED*/ void cmd_shift(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { long l; /* line number counter */ int oldidx; /* number of chars previously used for indent */ int newidx; /* number of chars in the new indent string */ int oldcol; /* previous indent amount */ int newcol; /* new indent amount */ char *text; /* pointer to the old line's text */ /* figure out how much of the screen we must redraw (for vi mode) */ if (markline(frommark) != markline(tomark)) { mustredraw = TRUE; redrawrange(markline(frommark), markline(tomark) + 1L, markline(tomark) + 1L); } ChangeText { /* for each line to shift... */ for (l = markline(frommark); l <= markline(tomark); l++) { /* get the line - ignore empty lines unless ! mode */ text = fetchline(l); if (!*text && !bang) continue; /* calc oldidx and oldcol */ for (oldidx = 0, oldcol = 0; text[oldidx] == ' ' || text[oldidx] == '\t'; oldidx++) { if (text[oldidx] == ' ') { oldcol += 1; } else { oldcol += *o_tabstop - (oldcol % *o_tabstop); } } /* calc newcol */ if (cmd == CMD_SHIFTR) { newcol = oldcol + (*o_shiftwidth & 0xff); } else { newcol = oldcol - (*o_shiftwidth & 0xff); if (newcol < 0) newcol = 0; } /* if no change, then skip to next line */ if (oldcol == newcol) continue; /* build a new indent string */ newidx = 0; while (newcol >= *o_tabstop) { tmpblk.c[newidx++] = '\t'; newcol -= *o_tabstop; } while (newcol > 0) { tmpblk.c[newidx++] = ' '; newcol--; } tmpblk.c[newidx] = '\0'; /* change the old indent string into the new */ change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c); } } /* Reporting... */ rptlines = markline(tomark) - markline(frommark) + 1L; if (cmd == CMD_SHIFTR) { rptlabel = ">ed"; } else { rptlabel = "<ed"; } } /*ARGSUSED*/ void cmd_read(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { int fd, rc; /* used while reading from the file */ char *scan; /* used for finding NUL characters */ int hadnul; /* boolean: any NULs found? */ int addnl; /* boolean: forced to add newlines? */ int len; /* number of chars in current line */ long lines; /* number of lines in current block */ struct stat statb; /* special case: if ":r !cmd" then let the filter() function do it */ if (extra[0] == '!') { filter(frommark, MARK_UNSET, extra + 1); return; } /* open the file */ fd = open(extra, O_RDONLY); if (fd < 0) { msg("Can't open \"%s\"", extra); return; } #ifndef CRUNCH if (stat(extra, &statb) < 0) { msg("Can't stat \"%s\"", extra); } # if TOS if (statb.st_mode & S_IJDIR) # else # if OSK if (statb.st_mode & S_IFDIR) # else if ((statb.st_mode & S_IFMT) != S_IFREG) # endif # endif { msg("\"%s\" is not a regular file", extra); return; } #endif /* not CRUNCH */ /* get blocks from the file, and add them */ ChangeText { /* insertion starts at the line following frommark */ tomark = frommark = (frommark | (BLKSIZE - 1L)) + 1L; len = 0; hadnul = addnl = FALSE; /* add an extra newline, so partial lines at the end of * the file don't trip us up */ add(tomark, "\n"); /* for each chunk of text... */ while ((rc = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0) { /* count newlines, convert NULs, etc. ... */ for (lines = 0, scan = tmpblk.c; rc > 0; rc--, scan++) { /* break up long lines */ if (*scan != '\n' && len + 2 > BLKSIZE) { *scan = '\n'; addnl = TRUE; } /* protect against NUL chars in file */ if (!*scan) { *scan = 0x80; hadnul = TRUE; } /* starting a new line? */ if (*scan == '\n') { /* reset length at newline */ len = 0; lines++; } else { len++; } } /* add the text */ *scan = '\0'; add(tomark, tmpblk.c); tomark += MARK_AT_LINE(lines) + len - markidx(tomark); } /* if partial last line, then retain that first newline */ if (len > 0) { msg("Last line had no newline"); tomark += BLKSIZE; /* <- for the rptlines calc */ } else /* delete that first newline */ { delete(tomark, (tomark | (BLKSIZE - 1L)) + 1L); } } /* close the file */ close(fd); /* Reporting... */ rptlines = markline(tomark) - markline(frommark); rptlabel = "read"; if (addnl) msg("Newlines were added to break up long lines"); if (hadnul) msg("NULs were converted to 0x80"); } /*ARGSUSED*/ void cmd_undo(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { undo(); } /* print the selected lines */ /*ARGSUSED*/ void cmd_print(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { REG char *scan; REG long l; REG int col; for (l = markline(frommark); l <= markline(tomark); l++) { /* display a line number, if CMD_NUMBER */ if (cmd == CMD_NUMBER) { sprintf(tmpblk.c, "%6ld ", l); qaddstr(tmpblk.c); col = 8; } else { col = 0; } /* get the next line & display it */ for (scan = fetchline(l); *scan; scan++) { /* expand tabs to the proper width */ if (*scan == '\t' && cmd != CMD_LIST) { do { qaddch(' '); col++; } while (col % *o_tabstop != 0); } else if (*scan >= 0 && *scan < ' ' || *scan == '\177') { qaddch('^'); qaddch(*scan ^ 0x40); col += 2; } else if ((*scan & 0x80) && cmd == CMD_LIST) { sprintf(tmpblk.c, "\\%03o", *scan); qaddstr(tmpblk.c); col += 4; } else { qaddch(*scan); col++; } /* wrap at the edge of the screen */ if (!has_AM && col >= COLS) { addch('\n'); col -= COLS; } } if (cmd == CMD_LIST) { qaddch('$'); } addch('\n'); exrefresh(); } } /* move or copy selected lines */ /*ARGSUSED*/ void cmd_move(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { MARK destmark; /* parse the destination linespec. No defaults. Line 0 is okay */ destmark = cursor; if (!strcmp(extra, "0")) { destmark = 0L; } else if (linespec(extra, &destmark) == extra || !destmark) { msg("invalid destination address"); return; } /* flesh the marks out to encompass whole lines */ frommark &= ~(BLKSIZE - 1); tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE; destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE; /* make sure the destination is valid */ if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark) { msg("invalid destination address"); } /* Do it */ ChangeText { /* save the text to a cut buffer */ cutname('\0'); cut(frommark, tomark); /* if we're not copying, delete the old text & adjust destmark */ if (cmd != CMD_COPY) { delete(frommark, tomark); if (destmark >= frommark) { destmark -= (tomark - frommark); } } /* add the new text */ paste(destmark, FALSE, FALSE); } /* move the cursor to the last line of the moved text */ cursor = destmark + (tomark - frommark) - BLKSIZE; if (cursor < MARK_FIRST || cursor >= MARK_LAST + BLKSIZE) { cursor = MARK_LAST; } /* Reporting... */ rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" ); } /* execute EX commands from a file */ /*ARGSUSED*/ void cmd_source(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { /* must have a filename */ if (!*extra) { msg("\"source\" requires a filename"); return; } doexrc(extra); } #ifndef NO_AT /*ARGSUSED*/ void cmd_at(frommark, tomark, cmd, bang, extra) MARK frommark; MARK tomark; CMD cmd; int bang; char *extra; { static nest = FALSE; int result; char buf[MAXRCLEN]; /* don't allow nested macros */ if (nest) { msg("@ macros can't be nested"); return; } nest = TRUE; /* require a buffer name */ if (*extra == '"') extra++; if (!*extra || !isascii(*extra) ||!islower(*extra)) { msg("@ requires a cut buffer name (a-z)"); } /* get the contents of the buffer */ result = cb2str(*extra, buf, (unsigned)(sizeof buf)); if (result <= 0) { msg("buffer \"%c is empty", *extra); } else if (result >= sizeof buf) { msg("buffer \"%c is too large to execute", *extra); } else { /* execute the contents of the buffer as ex commands */ exstring(buf, result); } nest = FALSE; } #endif SHAR_EOF fi # end of overwriting check if test -f 'ctags.c' then echo shar: will not over-write existing file "'ctags.c'" else cat << \SHAR_EOF > 'ctags.c' /* ctags.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the complete source to the ctags program. */ /* Special abilities: * Can also make a "refs" file for use by the "ref" program. */ /* Limitations: * This version of ctags always writes its output to the file "tags". * It assumes that every command-line argument (but "-r") is a C source file. * It does not sort the list of tags, unless CFLAGS=-DSORT. * It does not recognize duplicate definitions. * It does not try to handle "static" functions in a clever way. * It probably won't scan ANSI-C source code very well. */ /* Implementation: * Lines are scanned one-at-a-time. * The context of lines is tracked via a finite state machine. * Contexts are: * EXPECTFN - we're looking for a function name. * ARGS - between function name and its opening { * BODY - we found a function name, skip to end of body. * * Function tags are referenced by a search string, so that lines may be * inserted or deleted without mucking up the tag search. * * Macro tags are referenced by their line number, because 1) they usually * occur near the top of a file, so their line# won't change much; 2) They * often contain characters that are hard to search for; and 3) Their #define * line is likely to be altered. * * Each line of the resulting "tags" file describes one tag. Lines begin with * the tag name, then a tab, then the file name, then a tab, and then either * a line number or a slash-delimited search string. */ #include <ctype.h> #include <stdio.h> #include "config.h" #define REFS "refs" #if OSK #define NUMFMT "%%.%ds\t%%s\t%%ld\n" #define SRCHFMT "%%.%ds\t%%s\t/^%%s$/\n" #define MAINFMT "M%%.%ds\t%%s\t/^%%s$/\n" static char fmt[256]; #else #define NUMFMT "%.*s\t%s\t%ld\n" #define SRCHFMT "%.*s\t%s\t/^%s$/\n" #define MAINFMT "M%.*s\t%s\t/^%s$/\n" #endif #ifdef VERBOSE # define SAY(x) fprintf(stderr, "%s\n", x); #else # define SAY(x) #endif #define EXPECTFN 1 #define ARGS 2 #define BODY 3 extern char *fgets(); char *progname; /* argv[0], used for diagnostic output */ main(argc, argv) int argc; char **argv; { FILE *fp; int i; FILE *refs; /* used to write to the refs file */ #if MSDOS || TOS char **wildexpand(); argv=wildexpand(&argc, argv); #endif /* notice the program name */ progname = argv[0]; /* create the "refs" file if first arg is "-r" */ if (argc > 1 && !strcmp(argv[1], "-r")) { /* delete the "-r" flag from the args list */ argc--; argv++; /* open the "refs" file for writing */ refs = fopen(REFS, "w"); if (!refs) { fprintf(stderr, "%s: could not create \"%s\"\n", progname, REFS); exit(2); } } else { refs = (FILE *)0; } /* process each file named on the command line, or complain if none */ if (argc > 1) { /* redirect stdout to go to the "tags" file */ if (!freopen("tags", "w", stdout)) { fprintf(stderr, "%s: could not create \"%s\"\n", progname, TAGS); exit(2); } for (i = 1; i < argc; i++) { /* process this named file */ fp = fopen(argv[i], "r"); if (!fp) { fprintf(stderr, "%s: could not read \"%s\"\n", progname, argv[i]); continue; } ctags(fp, argv[i], refs); fclose(fp); } #ifdef SORT /* This is a hack which will sort the tags list. It should * on UNIX and Minix. You may have trouble with csh. Note * that the tags list only has to be sorted if you intend to * use it with the real vi; elvis permits unsorted tags. */ fflush(stdout); #if OSK fclose(stdout); system("qsort tags >-_tags; -nx; del tags; rename _tags tags"); #else system("sort tags >_tags$$; mv _tags$$ tags"); #endif #endif exit(0); } else { fprintf(stderr, "usage: %s *.[ch]\n", progname); exit(2); } } /* this function finds all tags in a given file */ ctags(fp, name, refs) FILE *fp; /* stream of the file to scan */ char *name; /* name of the file being scanned */ FILE *refs; /* NULL, or where to write refs lines */ { int context; /* context - either EXPECTFN, ARGS, or BODY */ long lnum; /* line number */ char text[1000]; /* a line of text from the file */ char *scan; /* used for searching through text */ int len; /* length of the line */ /* for each line of the file... */ for (context = EXPECTFN, lnum = 1; fgets(text, sizeof text, fp); lnum++) { #ifdef VERBOSE switch(context) { case EXPECTFN: scan = "EXPECTFN"; break; case ARGS: scan = "ARGS "; break; case BODY: scan = "BODY "; break; default: scan = "context?"; } fprintf(stderr, "%s:%s", scan, text); #endif /* start of body? */ if (text[0] == '{') { context = BODY; SAY("Start of BODY"); continue; } /* argument line, to be written to "refs" ? */ if (refs && context == ARGS) { if (text[0] != '\t') { putc('\t', refs); } fputs(text, refs); SAY("Argument line"); continue; } /* ignore empty or indented lines */ if (text[0] <= ' ') { SAY("Empty or indented"); continue; } /* end of body? */ if (text[0] == '}') { context = EXPECTFN; SAY("End of BODY"); continue; } /* ignore lines in the body of a function */ if (context != EXPECTFN) { SAY("BODY or ARGS"); continue; } /* strip the newline */ len = strlen(text); text[--len] = '\0'; /* a preprocessor line? */ if (text[0] == '#') { /* find the preprocessor directive */ for (scan = &text[1]; isspace(*scan); scan++) { } /* if it's a #define, make a tag out of it */ if (!strncmp(scan, "define", 6)) { /* find the start of the symbol name */ for (scan += 6; isspace(*scan); scan++) { } /* find the length of the symbol name */ for (len = 1; isalnum(scan[len]) || scan[len] == '_'; len++) { } #if OSK sprintf(fmt, NUMFMT, len); printf(fmt, scan, name, lnum); #else printf(NUMFMT, len, scan, name, lnum); #endif } SAY("Preprocessor line"); continue; } /* an extern or static declaration? */ if (text[len - 1] == ';' || !strncmp(text, "extern", 6) || !strncmp(text, "EXTERN", 6) || !strncmp(text, "static", 6) || !strncmp(text, "PRIVATE", 7)) { SAY("Extern or static"); continue; } /* if we get here & the first punctuation other than "*" is * a "(" which is immediately preceded by a name, then * assume the name is that of a function. */ for (scan = text; *scan; scan++) { if (ispunct(*scan) && !isspace(*scan) /* in BSD, spaces are punctuation?*/ && *scan != '*' && *scan != '_' && *scan != '(') { SAY("Funny punctuation"); goto ContinueContinue; } if (*scan == '(') { /* permit 0 or 1 spaces between name & '(' */ if (scan > text && scan[-1] == ' ') { scan--; } /* find the start & length of the name */ for (len = 0, scan--; scan >= text && (isalnum(*scan) || *scan == '_'); scan--, len++) { } scan++; /* did we find a function? */ if (len > 0) { /* found a function! */ if (len == 4 && !strncmp(scan, "main", 4)) { #if OSK sprintf(fmt, MAINFMT, strlen(name) - 2); printf(fmt, name, name, text); #else printf(MAINFMT, strlen(name) - 2, name, name, text); #endif } #if OSK sprintf(fmt, SRCHFMT, len); printf(fmt, scan, name, text); #else printf(SRCHFMT, len, scan, name, text); #endif context = ARGS; /* add a line to refs, if needed */ if (refs) { fputs(text, refs); putc('\n', refs); } goto ContinueContinue; } } else { SAY("No parenthesis"); } } SAY("No punctuation"); ContinueContinue:; } } #if MSDOS || TOS #define WILDCARD_NO_MAIN #include "wildcard.c" #endif SHAR_EOF fi # end of overwriting check if test -f 'curses.c' then echo shar: will not over-write existing file "'curses.c'" else cat << \SHAR_EOF > 'curses.c' /* curses.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the functions & variables needed for a tiny subset of * curses. The principle advantage of this version of curses is its * extreme speed. Disadvantages are potentially larger code, few supported * functions, limited compatibility with full curses, and only stdscr. */ #include "config.h" #include "vi.h" #if ANY_UNIX # if UNIXV # include <termio.h> # undef TIOCWINSZ /* we can't handle it correctly yet */ # else # include <sgtty.h> # endif #endif #if TOS # include <osbind.h> #endif #if OSK # include <sgstat.h> #endif #include <signal.h> extern char *getenv(); void starttcap(); /* variables, publicly available & used in the macros */ short ospeed; /* speed of the tty, eg B2400 */ #if OSK char PC_; /* Pad char */ #else char PC; /* Pad char */ #endif WINDOW *stdscr; /* pointer into kbuf[] */ WINDOW kbuf[KBSIZ]; /* a very large output buffer */ int LINES; /* :li#: number of rows */ int COLS; /* :co#: number of columns */ int AM; /* :am: boolean: auto margins? */ int PT; /* :pt: boolean: physical tabs? */ char *BC = "\b"; /* :bc backspace character string */ char *VB; /* :vb=: visible bell */ char *UP; /* :up=: move cursor up */ char *SO; /* :so=: standout start */ char *SE; /* :se=: standout end */ char *US = ""; /* :us=: underline start */ char *UE = ""; /* :ue=: underline end */ char *MD = ""; /* :md=: bold start */ char *ME = ""; /* :me=: bold end */ char *AS; /* :as=: alternate (italic) start */ char *AE; /* :ae=: alternate (italic) end */ char *CM; /* :cm=: cursor movement */ char *CE; /* :ce=: clear to end of line */ char *CD; /* :cd=: clear to end of screen */ char *AL; /* :al=: add a line */ char *DL; /* :dl=: delete a line */ #if OSK char *SR_; /* :sr=: scroll reverse */ #else char *SR; /* :sr=: scroll reverse */ #endif char *KS; /* :ks=: init string for cursor */ char *KE; /* :ke=: restore string for cursor */ char *KU; /* :ku=: key sequence sent by up arrow */ char *KD; /* :kd=: key sequence sent by down arrow */ char *KL; /* :kl=: key sequence sent by left arrow */ char *KR; /* :kr=: key sequence sent by right arrow */ char *HM; /* :HM=: key sequence sent by the <Home> key */ char *EN; /* :EN=: key sequence sent by the <End> key */ char *PU; /* :PU=: key sequence sent by the <PgUp> key */ char *PD; /* :PD=: key sequence sent by the <PgDn> key */ char *IM; /* :im=: insert mode start */ char *IC = ""; /* :ic=: insert the following character */ char *EI; /* :ei=: insert mode end */ char *DC; /* :dc=: delete a character */ char *TI; /* :ti=: terminal init */ /* GB */ char *TE; /* :te=: terminal exit */ /* GB */ #ifndef NO_CURSORSHAPE char *CQ = (char *)0;/* :cQ=: normal cursor */ char *CX = (char *)1;/* :cX=: cursor used for EX command/entry */ char *CV = (char *)2;/* :cV=: cursor used for VI command mode */ char *CI = (char *)3;/* :cI=: cursor used for VI input mode */ char *CR = (char *)4;/* :cR=: cursor used for VI replace mode */ #endif char *aend = ""; /* end an attribute -- either UE or ME */ char ERASEKEY; /* backspace key taken from ioctl structure */ #if ANY_UNIX # if UNIXV static struct termio oldtermio; /* original tty mode */ static struct termio newtermio; /* cbreak/noecho tty mode */ # else static struct sgttyb oldsgttyb; /* original tty mode */ static struct sgttyb newsgttyb; /* cbreak/nl/noecho tty mode */ static int oldint; /* ^C or DEL, the "intr" character */ # ifdef TIOCSLTC static int oldswitch; /* ^Z, the "suspend" character */ static int oldquote; /* ^V, the "quote next char" char */ # endif # endif #endif #if OSK static struct sgbuf oldsgttyb; /* orginal tty mode */ static struct sgbuf newsgttyb; /* noecho tty mode */ #endif static char *capbuf; /* capability string buffer */ void initscr() { /* make sure TERM variable is set */ #if MSDOS char *val; if (! (val = getenv("TERM")) || !strcmp(val, "pcbios")) #else if (!getenv("TERM")) #endif { #if ANY_UNIX write(2, "Environment variable TERM must be set\n", (unsigned)38); exit(1); #endif #if OSK writeln(2, "Environment variable TERM must be set\n", (unsigned)38); exit(1); #endif #if MSDOS || TOS Getsize(0); #endif } else { #if MSDOS *o_pcbios=0; #endif /* start termcap stuff */ starttcap(); } /* create stdscr and curscr */ stdscr = kbuf; /* change the terminal mode to cbreak/noecho */ #if ANY_UNIX # if UNIXV ioctl(2, TCGETA, &oldtermio); # else ioctl(2, TIOCGETP, &oldsgttyb); # endif #endif #if OSK _gs_opt(0, &oldsgttyb); #endif Resume_curses(TRUE); } void endwin() { /* change the terminal mode back the way it was */ Suspend_curses(); } static int curses_active = FALSE; void suspend_curses() { #if ANY_UNIX && !UNIXV struct tchars tbuf; # ifdef TIOCSLTC struct ltchars ltbuf; # endif #endif #ifndef NO_CURSORSHAPE if (has_CQ) { do_CQ(); } #endif if (has_TE) /* GB */ { do_TE(); } if (has_KE) { do_KE(); } refresh(); /* change the terminal mode back the way it was */ #if ANY_UNIX # if UNIXV ioctl(2, TCSETAW, &oldtermio); # else ioctl(2, TIOCSETP, &oldsgttyb); ioctl(2, TIOCGETC, &tbuf); tbuf.t_intrc = oldint; ioctl(2, TIOCSETC, &tbuf); # ifdef TIOCSLTC ioctl(2, TIOCGLTC, <buf); ltbuf.t_suspc = oldswitch; ltbuf.t_lnextc = oldquote; ioctl(2, TIOCSLTC, <buf); # endif # endif #endif #if OSK _ss_opt(0, &oldsgttyb); #endif curses_active = FALSE; } void resume_curses(quietly) int quietly; { if (!curses_active) { /* change the terminal mode to cbreak/noecho */ #if ANY_UNIX # if UNIXV ospeed = (oldtermio.c_cflag & CBAUD); ERASEKEY = oldtermio.c_cc[VERASE]; newtermio = oldtermio; newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK); newtermio.c_oflag &= ~OPOST; newtermio.c_lflag &= ISIG; newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */ newtermio.c_cc[VMIN] = 1; newtermio.c_cc[VTIME] = 0; # ifdef VSWTCH newtermio.c_cc[VSWTCH] = 0; # endif ioctl(2, TCSETAW, &newtermio); # else /* BSD or V7 or Coherent or Minix */ struct tchars tbuf; # ifdef TIOCSLTC struct ltchars ltbuf; # endif ospeed = oldsgttyb.sg_ospeed; ERASEKEY = oldsgttyb.sg_erase; newsgttyb = oldsgttyb; newsgttyb.sg_flags |= CBREAK; newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS); ioctl(2, TIOCSETP, &newsgttyb); ioctl(2, TIOCGETC, &tbuf); oldint = tbuf.t_intrc; tbuf.t_intrc = ctrl('C'); /* always use ^C for interrupts */ ioctl(2, TIOCSETC, &tbuf); # ifdef TIOCSLTC ioctl(2, TIOCGLTC, <buf); oldswitch = ltbuf.t_suspc; ltbuf.t_suspc = 0; /* disable ^Z for elvis */ oldquote = ltbuf.t_lnextc; ltbuf.t_lnextc = 0; /* disable ^V for elvis */ ioctl(2, TIOCSLTC, <buf); # endif # endif #endif #if OSK newsgttyb = oldsgttyb; newsgttyb.sg_echo = 0; newsgttyb.sg_eofch = 0; newsgttyb.sg_kbach = 0; newsgttyb.sg_kbich = ctrl('C'); _ss_opt(0, &newsgttyb); ospeed = oldsgttyb.sg_baud; ERASEKEY = oldsgttyb.sg_bspch; #endif if (has_TI) /* GB */ { do_TI(); } if (has_KS) { do_KS(); } curses_active = TRUE; } /* If we're supposed to quit quietly, then we're done */ if (quietly) { return; } signal(SIGINT, SIG_IGN); move(LINES - 1, 0); do_SO(); qaddstr("[Press <RETURN> to continue]"); do_SE(); refresh(); ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */ if (kbuf[0] == ':') { mode = MODE_COLON; addch('\n'); refresh(); } else { mode = MODE_VI; redraw(MARK_UNSET, FALSE); } exwrote = FALSE; #if TURBOC signal(SIGINT, (void(*)()) trapint); #else signal(SIGINT, trapint); #endif } static void lacking(s) char *s; { write(2, "This termcap entry lacks the :", (unsigned)30); write(2, s, (unsigned)2); write(2, "=: capability\n", (unsigned)14); #if OSK write(2, "\l", 1); #endif exit(1); } void starttcap() { char *str; static char cbmem[800]; #define MUSTHAVE(T,s) if (!(T = Tgetstr(s, &capbuf))) lacking(s) #define MAYHAVE(T,s) if (str = Tgetstr(s, &capbuf)) T = str #define PAIR(T,U,sT,sU) T=Tgetstr(sT,&capbuf);U=Tgetstr(sU,&capbuf);if (!T||!U)T=U="" /* allocate memory for capbuf */ capbuf = cbmem; /* get the termcap entry */ switch (Tgetent(kbuf, getenv("TERM"))) { case -1: write(2, "Can't read /etc/termcap\n", (unsigned)24); #if OSK write(2, "\l", 1); #endif exit(2); case 0: write(2, "Unrecognized TERM type\n", (unsigned)23); #if OSK write(2, "\l", 1); #endif exit(3); } /* get strings */ MUSTHAVE(UP, "up"); MAYHAVE(BC, "bc"); MAYHAVE(VB, "vb"); MUSTHAVE(CM, "cm"); PAIR(SO, SE, "so", "se"); PAIR(TI, TE, "ti", "te"); if (Tgetnum("ug") <= 0) { PAIR(US, UE, "us", "ue"); PAIR(MD, ME, "md", "me"); /* get italics, or have it default to underline */ PAIR(AS, AE, "as", "ae"); if (!*AS) { AS = US; AE = UE; } } MAYHAVE(AL, "al"); MAYHAVE(DL, "dl"); MUSTHAVE(CE, "ce"); MAYHAVE(CD, "cd"); #if OSK MAYHAVE(SR_, "sr"); #else MAYHAVE(SR, "sr"); #endif PAIR(IM, EI, "im", "ei"); MAYHAVE(IC, "ic"); MAYHAVE(DC, "dc"); /* other termcap stuff */ AM = Tgetflag("am"); PT = Tgetflag("pt"); Getsize(0); /* Key sequences */ PAIR(KS, KE, "ks", "ke"); MAYHAVE(KU, "ku"); /* up */ MAYHAVE(KD, "kd"); /* down */ MAYHAVE(KL, "kl"); /* left */ MAYHAVE(KR, "kr"); /* right */ MAYHAVE(PU, "kP"); /* PgUp */ MAYHAVE(PD, "kN"); /* PgDn */ MAYHAVE(HM, "kh"); /* Home */ MAYHAVE(EN, "kH"); /* End */ #ifndef CRUNCH if (!PU) MAYHAVE(PU, "K2"); /* "3x3 pad" names for PgUp, etc. */ if (!PD) MAYHAVE(PD, "K5"); if (!HM) MAYHAVE(HM, "K1"); if (!EN) MAYHAVE(EN, "K4"); MAYHAVE(PU, "PU"); /* old XENIX names for PgUp, etc. */ MAYHAVE(PD, "PD"); /* (overrides others, if used.) */ MAYHAVE(HM, "HM"); MAYHAVE(EN, "EN"); #endif #ifndef NO_CURSORSHAPE /* cursor shapes */ CQ = Tgetstr("cQ", &capbuf); if (has_CQ) { CX = Tgetstr("cX", &capbuf); if (!CX) CX = CQ; CV = Tgetstr("cV", &capbuf); if (!CV) CV = CQ; CI = Tgetstr("cI", &capbuf); if (!CI) CI = CQ; CR = Tgetstr("cR", &capbuf); if (!CR) CR = CQ; } # ifndef CRUNCH else { PAIR(CQ, CV, "ve", "vs"); CX = CI = CR = CQ; } # endif /* !CRUNCH */ #endif /* !NO_CURSORSHAPE */ #undef MUSTHAVE #undef MAYHAVE #undef PAIR } /* This function gets the window size. It uses the TIOCGWINSZ ioctl call if * your system has it, or Tgetnum("li") and Tgetnum("co") if it doesn't. * This function is called once during initialization, and thereafter it is * called whenever the SIGWINCH signal is sent to this process. */ int getsize(signo) int signo; { int lines; int cols; #ifdef TIOCGWINSZ struct winsize size; #endif #ifdef SIGWINCH /* reset the signal vector */ signal(SIGWINCH, getsize); #endif /* get the window size, one way or another. */ lines = cols = 0; #ifdef TIOCGWINSZ if (ioctl(2, TIOCGWINSZ, &size) >= 0) { lines = size.ws_row; cols = size.ws_col; } #endif if ((lines == 0 || cols == 0) && signo == 0) { LINES = CHECKBIOS(v_rows(), Tgetnum("li")); COLS = CHECKBIOS(v_cols(), Tgetnum("co")); } if (lines >= 2 && cols >= 30) { LINES = lines; COLS = cols; } /* Make sure we got values that we can live with */ if (LINES < 2 || COLS < 30) { write(2, "Screen too small\n", (unsigned)17); #if OSK write(2, "\l", 1); #endif endwin(); exit(2); } /* !!! copy the new values into Elvis' options */ { extern char o_columns[], o_lines[]; *o_columns = COLS; *o_lines = LINES; } return 0; } /* This is a function version of addch() -- it is used by tputs() */ int faddch(ch) int ch; { addch(ch); return 0; } /* These functions are equivelent to the macros of the same names... */ void qaddstr(str) char *str; { REG char *s_, *d_; #if MSDOS if (o_pcbios[0]) { while (*str) qaddch(*str++); return; } #endif for (s_=(str), d_=stdscr; *d_++ = *s_++; ) { } stdscr = d_ - 1; } void attrset(a) int a; { do_aend(); if (a == A_BOLD) { do_MD(); aend = ME; } else if (a == A_UNDERLINE) { do_US(); aend = UE; } else if (a == A_ALTCHARSET) { do_AS(); aend = AE; } else { aend = ""; } } void insch(ch) int ch; { if (has_IM) do_IM(); do_IC(); qaddch(ch); if (has_EI) do_EI(); } #if MSDOS static int alarmtime; /* raw read - #defined to read (0, ...) on non-MSDOS. * With MSDOS, am maximum of 1 byte is read. * If more bytes should be read, just change the loop. * The following code uses the IBM-PC-System-Timer, so probably wont't work * on non-compatibles. */ /*ARGSUSED*/ ttyread(buf, len) char *buf; int len; { volatile char far *biostimer; char oldtime; int nticks = 0; int pos = 0; biostimer = (char far *)0x0040006cl; oldtime = *biostimer; while (!pos && (!alarmtime || nticks<alarmtime)) { if (kbhit()) if ((buf[pos++] = getch()) == 0) /* function key */ buf[pos-1] = '#'; if (oldtime != *biostimer) { nticks++; oldtime = *biostimer; } } return pos; } alarm(time) int time; { alarmtime = 2 * time; /* ticks are 1/18 sec. */ } sleep(seconds) unsigned seconds; { volatile char far *biostimer = (char far *)0x0040006cl; char stop; stop = *biostimer + 18 * seconds; while (*biostimer != stop) { } } #endif #if TOS static int alarmtime; static long timer; static gettime() { timer = *(long *)(0x4ba); } /*ARGSUSED*/ ttyread(buf, len) char *buf; int len; { int pos=0; long l; long endtime; Supexec(gettime); endtime = timer+alarmtime; while (!pos && (!alarmtime || timer<endtime)) { if (Bconstat(2)) { l = Bconin(2); if ((buf[pos++]=l) == '\0') { buf[pos-1]='#'; buf[pos++]=l>>16; } } Supexec(gettime); } return pos; } alarm(time) int time; { alarmtime = 50 * time; /* ticks are 1/200 sec. */ } ttywrite(buf, len) char *buf; int len; { while (len--) Bconout(2, *buf++); } #endif #if OSK ttyread(buf, len) char *buf; int len; { REG int i; if ((i = _gs_rdy(0)) > 0) return read(0, buf, i < len ? i : len); else return read(0, buf, 1); } alarm(time) int time; { #define TIME(secs) ((secs << 8) | 0x80000000) static int alrmid; if (time) alrmid = alm_set(SIGQUIT, TIME(time)); else alm_delete(alrmid); } #endif /* OSK */ SHAR_EOF fi # end of overwriting check if test -f 'cut.c' then echo shar: will not over-write existing file "'cut.c'" else cat << \SHAR_EOF > 'cut.c' /* cut.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains function which manipulate the cut buffers. */ #include "config.h" #include "vi.h" #if TURBOC #include <process.h> /* needed for getpid */ #endif #if TOS #include <osbind.h> #define rename(a,b) Frename(0,a,b) #endif # define NANNONS 9 /* number of annonymous buffers */ static struct cutbuf { short *phys; /* pointer to an array of #s of BLKs containing text */ int nblks; /* number of blocks in phys[] array */ int start; /* offset into first block of start of cut */ int end; /* offset into last block of end of cut */ int fd; /* fd of tmp file, or -1 to use tmpfd */ char lnmode; /* boolean: line-mode cut? (as opposed to char-mode) */ } named[27], /* cut buffers "a through "z and ". */ annon[NANNONS]; /* annonymous cut buffers */ static char cbname; /* name chosen for next cut/paste operation */ #ifndef NO_RECYCLE /* This function builds a list of all blocks needed in the current tmp file * for the contents of cut buffers. * !!! WARNING: if you have more than ~450000 bytes of text in all of the * cut buffers, then this will fail disastrously, because buffer overflow * is *not* allowed for. */ int cutneeds(need) BLK *need; /* this is where we deposit the list */ { struct cutbuf *cb; /* used to count through cut buffers */ int i; /* used to count through blocks of a cut buffer */ int n; /* total number of blocks in list */ n = 0; /* first the named buffers... */ for (cb = named; cb < &named[27]; cb++) { if (cb->fd > 0) continue; for (i = cb->nblks; i-- > 0; ) { need->n[n++] = cb->phys[i]; } } /* then the anonymous buffers */ for (cb = annon; cb < &annon[NANNONS]; cb++) { if (cb->fd > 0) continue; for (i = cb->nblks; i-- > 0; ) { need->n[n++] = cb->phys[i]; } } return n; } #endif /* This function frees a cut buffer */ static void cutfree(buf) struct cutbuf *buf; { char cutfname[50]; int i; /* return immediately if the buffer is already empty */ if (buf->nblks <= 0) { return; } /* else free up stuff */ buf->nblks = 0; #ifdef DEBUG if (!buf->phys) msg("cutfree() tried to free an NULL buf->phys pointer."); #endif free((char *)buf->phys); /* see if anybody else needs this tmp file */ if (buf->fd >= 0) { for (i = 0; i < 27; i++) { if (named[i].nblks > 0 && named[i].fd == buf->fd) { break; } } } /* if nobody else needs it, then discard the tmp file */ if (buf->fd >= 0 && i == 27) { close(buf->fd); #if MSDOS || TOS strcpy(cutfname, o_directory); if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i-1])) cutfname[i++]=SLASH; sprintf(cutfname+i, CUTNAME+3, getpid(), buf->fd); #else sprintf(cutfname, CUTNAME, o_directory, getpid(), buf->fd); #endif unlink(cutfname); } } /* This function is called when we are about to abort a tmp file. If any * cut buffers still need the file, then a copy of the file should be * created for use by the cut buffers. * * To minimize the number of extra files lying around, only named cut buffers * are preserved in a file switch; the annonymous buffers just go away. */ void cutswitch(tmpname) char *tmpname; /* name of the tmp file */ { char cutfname[50]; /* used to build a new name for the tmp file */ int fd; /* a new fd for the current tmp file */ int i; #if MSDOS || TOS int j; #endif /* discard all annonymous cut buffers */ for (i = 0; i < NANNONS; i++) { cutfree(&annon[i]); } /* find the first named buffer that uses this tmp file */ for (i = 0; i < 27; i++) { if (named[i].nblks > 0 && named[i].fd < 0) { break; } } /* if none of them use this tmp file, then we're done */ if (i == 27) { return; } /* else we'll need this file and an fd a little longer */ #if MSDOS || TOS strcpy(cutfname, o_directory); if ((j = strlen(cutfname)) && !strchr(":/\\", cutfname[j-1])) cutfname[j++]=SLASH; close(tmpfd); fd = open(tmpname, O_RDONLY|O_BINARY); close(fd); sprintf(cutfname+j, CUTNAME+3, getpid(), fd); rename(tmpname, cutfname); fd = open(cutfname, O_RDONLY|O_BINARY); tmpfd = -1; /* we'll try to close this in tmp.c, but who cares? */ #else fd = dup(tmpfd); # if OSK sprintf(cutfname, CUTNAME, "", getpid(), fd); if (!link(tmpname, &cutfname[1])) /* skip slash */ unlink(tmpname); # else sprintf(cutfname, CUTNAME, o_directory, getpid(), fd); link(tmpname, cutfname) || unlink(tmpname); # endif #endif /* have all cut buffers use the new fd instead */ for (; i < 27; i++) { if (named[i].nblks > 0 && named[i].fd < 0) { named[i].fd = fd; } } } /* This function should be called just before termination of vi */ void cutend() { int i; /* free all named cut buffers, since they might be forcing an older * tmp file to be retained. */ for (i = 0; i < 27; i++) { cutfree(&named[i]); } } /* This function is used to select the cut buffer to be used next */ void cutname(name) int name; /* a single character */ { cbname = name; } /* This function copies a selected segment of text to a cut buffer */ void cut(from, to) MARK from; /* start of text to cut */ MARK to; /* end of text to cut */ { int first; /* logical number of first block in cut */ int last; /* logical number of last block used in cut */ long line; /* a line number */ int lnmode; /* boolean: will this be a line-mode cut? */ MARK delthru;/* end of text temporarily inserted for apnd */ REG struct cutbuf *cb; REG long l; REG int i; REG char *scan; char *blkc; /* detect whether this must be a line-mode cut or char-mode cut */ if (markidx(from) == 0 && markidx(to) == 0) lnmode = TRUE; else lnmode = FALSE; /* by default, we don't "delthru" anything */ delthru = MARK_UNSET; /* decide which cut buffer to use */ if (!cbname) { /* free up the last annonymous cut buffer */ cutfree(&annon[NANNONS - 1]); /* shift the annonymous cut buffers */ for (i = NANNONS - 1; i > 0; i--) { annon[i] = annon[i - 1]; } /* use the first annonymous cut buffer */ cb = annon; cb->nblks = 0; } else if (cbname >= 'a' && cbname <= 'z') { cb = &named[cbname - 'a']; cutfree(cb); } #ifndef CRUNCH else if (cbname >= 'A' && cbname <= 'Z') { cb = &named[cbname - 'A']; if (cb->nblks > 0) { /* resolve linemode/charmode differences */ if (!lnmode && cb->lnmode) { from &= ~(BLKSIZE - 1); if (markidx(to) != 0 || to == from) { to = to + BLKSIZE - markidx(to); } lnmode = TRUE; } /* insert the old cut-buffer before the new text */ mark[28] = to; delthru = paste(from, FALSE, TRUE); if (delthru == MARK_UNSET) { return; } delthru++; to = mark[28]; } cutfree(cb); } #endif /* not CRUNCH */ else if (cbname == '.') { cb = &named[26]; cutfree(cb); } else { msg("Invalid cut buffer name: \"%c", cbname); cbname = '\0'; return; } cbname = '\0'; cb->fd = -1; /* detect whether we're doing a line mode cut */ cb->lnmode = lnmode; /* ---------- */ /* Reporting... */ if (markidx(from) == 0 && markidx(to) == 0) { rptlines = markline(to) - markline(from); rptlabel = "yanked"; } /* ---------- */ /* make sure each block has a physical disk address */ blksync(); /* find the first block in the cut */ line = markline(from); for (first = 1; line > lnum[first]; first++) { } /* fetch text of the block containing that line */ blkc = scan = blkget(first)->c; /* find the mark in the block */ for (l = lnum[first - 1]; ++l < line; ) { while (*scan++ != '\n') { } } scan += markidx(from); /* remember the offset of the start */ cb->start = scan - blkc; /* ---------- */ /* find the last block in the cut */ line = markline(to); for (last = first; line > lnum[last]; last++) { } /* fetch text of the block containing that line */ if (last != first) { blkc = scan = blkget(last)->c; } else { scan = blkc; } /* find the mark in the block */ for (l = lnum[last - 1]; ++l < line; ) { while (*scan++ != '\n') { } } if (markline(to) <= nlines) { scan += markidx(to); } /* remember the offset of the end */ cb->end = scan - blkc; /* ------- */ /* remember the physical block numbers of all included blocks */ cb->nblks = last - first; if (cb->end > 0) { cb->nblks++; } #ifdef lint cb->phys = (short *)0; #else cb->phys = (short *)malloc((unsigned)(cb->nblks * sizeof(short))); #endif for (i = 0; i < cb->nblks; i++) { cb->phys[i] = hdr.n[first++]; } #ifndef CRUNCH /* if we temporarily inserted text for appending, then delete that * text now -- before the user sees it. */ if (delthru) { line = rptlines; delete(from, delthru); rptlines = line; rptlabel = "yanked"; } #endif /* not CRUNCH */ } static void readcutblk(cb, blkno) struct cutbuf *cb; int blkno; { int fd; /* either tmpfd or cb->fd */ /* decide which fd to use */ if (cb->fd >= 0) { fd = cb->fd; } else { fd = tmpfd; } /* get the block */ lseek(fd, (long)cb->phys[blkno] * (long)BLKSIZE, 0); if (read(fd, tmpblk.c, (unsigned)BLKSIZE) != BLKSIZE) { msg("Error reading back from tmp file for pasting!"); } } /* This function inserts text from a cut buffer, and returns the MARK where * insertion ended. Return MARK_UNSET on errors. */ MARK paste(at, after, retend) MARK at; /* where to insert the text */ int after; /* boolean: insert after mark? (rather than before) */ int retend; /* boolean: return end of text? (rather than start) */ { REG struct cutbuf *cb; REG int i; /* decide which cut buffer to use */ if (cbname >= 'A' && cbname <= 'Z') { cb = &named[cbname - 'A']; } else if (cbname >= 'a' && cbname <= 'z') { cb = &named[cbname - 'a']; } else if (cbname >= '1' && cbname <= '9') { cb = &annon[cbname - '1']; } else if (cbname == '.') { cb = &named[26]; } else if (!cbname) { cb = annon; } else { msg("Invalid cut buffer name: \"%c", cbname); cbname = '\0'; return MARK_UNSET; } /* make sure it isn't empty */ if (cb->nblks == 0) { if (cbname) msg("Cut buffer \"%c is empty", cbname); else msg("Cut buffer is empty"); cbname = '\0'; return MARK_UNSET; } cbname = '\0'; /* adjust the insertion MARK for "after" and line-mode cuts */ if (cb->lnmode) { at &= ~(BLKSIZE - 1); if (after) { at += BLKSIZE; } } else if (after) { /* careful! if markidx(at) == 0 we might be pasting into an * empty line -- so we can't blindly increment "at". */ if (markidx(at) == 0) { pfetch(markline(at)); if (plen != 0) { at++; } } else { at++; } } /* put a copy of the "at" mark in the mark[] array, so it stays in * sync with changes made via add(). */ mark[27] = at; /* simple one-block paste? */ if (cb->nblks == 1) { /* get the block */ readcutblk(cb, 0); /* isolate the text we need within it */ if (cb->end) { tmpblk.c[cb->end] = '\0'; } /* insert it */ ChangeText { add(at, &tmpblk.c[cb->start]); } } else { /* multi-block paste */ ChangeText { i = cb->nblks - 1; /* add text from the last block first */ if (cb->end > 0) { readcutblk(cb, i); tmpblk.c[cb->end] = '\0'; add(at, tmpblk.c); i--; } /* add intervening blocks */ while (i > 0) { readcutblk(cb, i); add(at, tmpblk.c); i--; } /* add text from the first cut block */ readcutblk(cb, 0); add(at, &tmpblk.c[cb->start]); } } /* Reporting... */ rptlines = markline(mark[27]) - markline(at); rptlabel = "pasted"; /* return the mark at the beginning/end of inserted text */ if (retend) { return mark[27] - 1L; } return at; } #ifndef NO_AT /* This function copies characters from a cut buffer into a string. * It returns the number of characters in the cut buffer. If the cut * buffer is too large to fit in the string (i.e. if cb2str() returns * a number >= size) then the characters will not have been copied. * It returns 0 if the cut buffer is empty, and -1 for invalid cut buffers. */ int cb2str(name, buf, size) int name; /* the name of a cut-buffer to get: a-z only! */ char *buf; /* where to put the string */ unsigned size; /* size of buf */ { REG struct cutbuf *cb; REG char *src; REG char *dest; /* decide which cut buffer to use */ if (name >= 'a' && name <= 'z') { cb = &named[name - 'a']; } else { return -1; } /* if the buffer is empty, return 0 */ if (cb->nblks == 0) { return 0; } /* !!! if not a single-block cut, then fail */ if (cb->nblks != 1) { return size; } /* if too big, return the size now, without doing anything */ if (cb->end - cb->start >= size) { return cb->end - cb->start; } /* get the block */ readcutblk(cb, 0); /* isolate the string within that blk */ if (cb->start == 0) { tmpblk.c[cb->end] = '\0'; } else { for (dest = tmpblk.c, src = dest + cb->start; src < tmpblk.c + cb->end; ) { *dest++ = *src++; } *dest = '\0'; } /* copy the string into the buffer */ if (buf != tmpblk.c) { strcpy(buf, tmpblk.c); } /* return the length */ return cb->end - cb->start; } #endif SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # date.c # ex.c # input.c # This archive created: Thu Jan 10 17:21:08 1991 export PATH; PATH=/bin:$PATH if test -f 'date.c' then echo shar: will not over-write existing file "'date.c'" else cat << \SHAR_EOF > 'date.c' SHAR_EOF fi # end of overwriting check if test -f 'ex.c' then echo shar: will not over-write existing file "'ex.c'" else cat << \SHAR_EOF > 'ex.c' /* ex.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the code for reading ex commands. */ #include "config.h" #include <ctype.h> #include "vi.h" #ifndef isascii # define isascii(c) !((c)&~0x7f) #endif /* This data type is used to describe the possible argument combinations */ typedef short ARGT; #define FROM 1 /* allow a linespec */ #define TO 2 /* allow a second linespec */ #define BANG 4 /* allow a ! after the command name */ #define EXTRA 8 /* allow extra args after command name */ #define XFILE 16 /* expand wildcards in extra part */ #define NOSPC 32 /* no spaces allowed in the extra part */ #define DFLALL 64 /* default file range is 1,$ */ #define DFLNONE 128 /* no default file range */ #define NODFL 256 /* do not default to the current file name */ #define EXRCOK 512 /* can be in a .exrc file */ #define NL 1024 /* if mode!=MODE_EX, then write a newline first */ #define PLUS 2048 /* allow a line number, as in ":e +32 foo" */ #define ZERO 4096 /* allow 0 to be given as a line number */ #define FILES (XFILE + EXTRA) /* multiple extra files allowed */ #define WORD1 (EXTRA + NOSPC) /* one extra word allowed */ #define FILE1 (FILES + NOSPC) /* 1 file allowed, defaults to current file */ #define NAMEDF (FILE1 + NODFL) /* 1 file allowed, defaults to "" */ #define NAMEDFS (FILES + NODFL) /* multiple files allowed, default is "" */ #define RANGE (FROM + TO) /* range of linespecs allowed */ #define NONE 0 /* no args allowed at all */ /* This array maps ex command names to command codes. The order in which * command names are listed below is significant -- ambiguous abbreviations * are always resolved to be the first possible match. (e.g. "r" is taken * to mean "read", not "rewind", because "read" comes before "rewind") */ static struct { char *name; /* name of the command */ CMD code; /* enum code of the command */ void (*fn)();/* function which executes the command */ ARGT argt; /* command line arguments permitted/needed/used */ } cmdnames[] = { /* cmd name cmd code function arguments */ {"append", CMD_APPEND, cmd_append, FROM+ZERO }, #ifdef DEBUG {"bug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL}, #endif {"change", CMD_CHANGE, cmd_append, RANGE }, {"delete", CMD_DELETE, cmd_delete, RANGE+WORD1 }, {"edit", CMD_EDIT, cmd_edit, BANG+FILE1+PLUS }, {"file", CMD_FILE, cmd_file, NAMEDF }, {"global", CMD_GLOBAL, cmd_global, RANGE+BANG+EXTRA+DFLALL}, {"insert", CMD_INSERT, cmd_append, FROM }, {"join", CMD_INSERT, cmd_join, RANGE }, {"k", CMD_MARK, cmd_mark, FROM+WORD1 }, {"list", CMD_LIST, cmd_print, RANGE+NL }, {"move", CMD_MOVE, cmd_move, RANGE+EXTRA }, {"next", CMD_NEXT, cmd_next, BANG+NAMEDFS }, {"Next", CMD_PREVIOUS, cmd_next, BANG }, {"print", CMD_PRINT, cmd_print, RANGE+NL }, {"quit", CMD_QUIT, cmd_xit, BANG }, {"read", CMD_READ, cmd_read, FROM+ZERO+NAMEDF}, {"substitute", CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA }, {"to", CMD_COPY, cmd_move, RANGE+EXTRA }, {"undo", CMD_UNDO, cmd_undo, NONE }, {"vglobal", CMD_VGLOBAL, cmd_global, RANGE+EXTRA+DFLALL}, {"write", CMD_WRITE, cmd_write, RANGE+BANG+FILE1+DFLALL}, {"xit", CMD_XIT, cmd_xit, BANG+NL }, {"yank", CMD_YANK, cmd_delete, RANGE+WORD1 }, {"!", CMD_BANG, cmd_shell, EXRCOK+RANGE+NAMEDFS+DFLNONE+NL}, {"<", CMD_SHIFTL, cmd_shift, RANGE }, {">", CMD_SHIFTR, cmd_shift, RANGE }, {"=", CMD_EQUAL, cmd_file, RANGE }, {"&", CMD_SUBAGAIN, cmd_substitute, RANGE }, #ifndef NO_AT {"@", CMD_AT, cmd_at, EXTRA }, #endif #ifndef NO_ABBR {"abbreviate", CMD_ABBR, cmd_abbr, EXRCOK+EXTRA }, #endif {"args", CMD_ARGS, cmd_args, EXRCOK+NAMEDFS }, #ifndef NO_ERRLIST {"cc", CMD_CC, cmd_make, BANG+FILES }, #endif {"cd", CMD_CD, cmd_cd, EXRCOK+NAMEDF }, {"copy", CMD_COPY, cmd_move, RANGE+EXTRA }, #ifndef NO_DIGRAPH {"digraph", CMD_DIGRAPH, cmd_digraph, EXRCOK+BANG+EXTRA}, #endif #ifndef NO_ERRLIST {"errlist", CMD_ERRLIST, cmd_errlist, BANG+NAMEDF }, #endif {"ex", CMD_EDIT, cmd_edit, BANG+FILE1 }, {"map", CMD_MAP, cmd_map, EXRCOK+BANG+EXTRA}, #ifndef NO_MKEXRC {"mkexrc", CMD_MKEXRC, cmd_mkexrc, NAMEDF }, #endif {"number", CMD_NUMBER, cmd_print, RANGE+NL }, {"put", CMD_PUT, cmd_put, FROM+ZERO+WORD1 }, {"set", CMD_SET, cmd_set, EXRCOK+EXTRA }, {"shell", CMD_SHELL, cmd_shell, NL }, {"source", CMD_SOURCE, cmd_source, EXRCOK+NAMEDF }, {"tag", CMD_TAG, cmd_tag, BANG+WORD1 }, {"version", CMD_VERSION, cmd_version, EXRCOK+NONE }, {"visual", CMD_VISUAL, cmd_visual, NONE }, {"wq", CMD_WQUIT, cmd_xit, NL }, #ifdef DEBUG {"debug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL}, {"validate", CMD_VALIDATE, cmd_validate, BANG+NL }, #endif {"chdir", CMD_CD, cmd_cd, EXRCOK+NAMEDF }, #ifndef NO_ERRLIST {"make", CMD_MAKE, cmd_make, BANG+NAMEDFS }, #endif {"mark", CMD_MARK, cmd_mark, FROM+WORD1 }, {"previous", CMD_PREVIOUS, cmd_next, BANG }, {"rewind", CMD_REWIND, cmd_next, BANG }, {"unmap", CMD_UNMAP, cmd_map, EXRCOK+BANG+EXTRA}, #ifndef NO_ABBR {"unabbreviate",CMD_UNABBR, cmd_abbr, EXRCOK+WORD1 }, #endif {(char *)0} }; /* This function parses a search pattern - given a pointer to a / or ?, * it replaces the ending / or ? with a \0, and returns a pointer to the * stuff that came after the pattern. */ char *parseptrn(ptrn) REG char *ptrn; { REG char *scan; for (scan = ptrn + 1; *scan && *scan != *ptrn; scan++) { /* allow backslashed versions of / and ? in the pattern */ if (*scan == '\\' && scan[1] != '\0') { scan++; } } if (*scan) { *scan++ = '\0'; } return scan; } /* This function parses a line specifier for ex commands */ char *linespec(s, markptr) REG char *s; /* start of the line specifier */ MARK *markptr; /* where to store the mark's value */ { long num; REG char *t; /* parse each ;-delimited clause of this linespec */ do { /* skip an initial ';', if any */ if (*s == ';') { s++; } /* skip leading spaces */ while (isascii(*s) && isspace(*s)) { s++; } /* dot means current position */ if (*s == '.') { s++; *markptr = cursor; } /* '$' means the last line */ else if (*s == '$') { s++; *markptr = MARK_LAST; } /* digit means an absolute line number */ else if (isascii(*s) && isdigit(*s)) { for (num = 0; isascii(*s) && isdigit(*s); s++) { num = num * 10 + *s - '0'; } *markptr = MARK_AT_LINE(num); } /* appostrophe means go to a set mark */ else if (*s == '\'') { s++; *markptr = m_tomark(cursor, 1L, (int)*s); s++; } /* slash means do a search */ else if (*s == '/' || *s == '?') { /* put a '\0' at the end of the search pattern */ t = parseptrn(s); /* search for the pattern */ *markptr &= ~(BLKSIZE - 1); if (*s == '/') { pfetch(markline(*markptr)); if (plen > 0) *markptr += plen - 1; *markptr = m_fsrch(*markptr, s); } else { *markptr = m_bsrch(*markptr, s); } /* adjust command string pointer */ s = t; } /* if linespec was faulty, quit now */ if (!*markptr) { return s; } /* maybe add an offset */ t = s; if (*t == '-' || *t == '+') { s++; for (num = 0; *s >= '0' && *s <= '9'; s++) { num = num * 10 + *s - '0'; } if (num == 0) { num = 1; } *markptr = m_updnto(*markptr, num, *t); } } while (*s == ';' || *s == '+' || *s == '-'); return s; } /* This function reads an ex command and executes it. */ void ex() { char cmdbuf[80]; REG int cmdlen; static long oldline; significant = FALSE; oldline = markline(cursor); while (mode == MODE_EX) { /* read a line */ cmdlen = vgets(':', cmdbuf, sizeof cmdbuf); if (cmdlen < 0) { return; } /* if empty line, assume ".+1" */ if (cmdlen == 0) { strcpy(cmdbuf, ".+1"); qaddch('\r'); clrtoeol(); } else { addch('\n'); } refresh(); /* parse & execute the command */ doexcmd(cmdbuf); /* handle autoprint */ if (significant || markline(cursor) != oldline) { significant = FALSE; oldline = markline(cursor); if (*o_autoprint && mode == MODE_EX) { cmd_print(cursor, cursor, CMD_PRINT, FALSE, ""); } } } } void doexcmd(cmdbuf) char *cmdbuf; /* string containing an ex command */ { REG char *scan; /* used to scan thru cmdbuf */ MARK frommark; /* first linespec */ MARK tomark; /* second linespec */ REG int cmdlen; /* length of the command name given */ CMD cmd; /* what command is this? */ ARGT argt; /* argument types for this command */ short forceit; /* bang version of a command? */ REG int cmdidx; /* index of command */ REG char *build; /* used while copying filenames */ int iswild; /* boolean: filenames use wildcards? */ int isdfl; /* using default line ranges? */ int didsub; /* did we substitute file names for % or # */ /* ex commands can't be undone via the shift-U command */ U_line = 0L; /* ignore command lines that start with a double-quote */ if (*cmdbuf == '"') { return; } /* permit extra colons at the start of the line */ while (*cmdbuf == ':') { cmdbuf++; } /* parse the line specifier */ scan = cmdbuf; if (nlines < 1) { /* no file, so don't allow addresses */ } else if (*scan == '%') { /* '%' means all lines */ frommark = MARK_FIRST; tomark = MARK_LAST; scan++; } else if (*scan == '0') { frommark = tomark = MARK_UNSET; scan++; } else { frommark = cursor; scan = linespec(scan, &frommark); tomark = frommark; if (frommark && *scan == ',') { scan++; scan = linespec(scan, &tomark); } if (!tomark) { /* faulty line spec -- fault already described */ return; } if (frommark > tomark) { msg("first address exceeds the second"); return; } } isdfl = (scan == cmdbuf); /* skip whitespace */ while (isascii(*scan) && isspace(*scan)) { scan++; } /* if no command, then just move the cursor to the mark */ if (!*scan) { cursor = tomark; return; } /* figure out how long the command name is */ if (isascii(*scan) && !isalpha(*scan)) { cmdlen = 1; } else { for (cmdlen = 1; !isascii(scan[cmdlen]) || isalpha(scan[cmdlen]); cmdlen++) { } } /* lookup the command code */ for (cmdidx = 0; cmdnames[cmdidx].name && strncmp(scan, cmdnames[cmdidx].name, cmdlen); cmdidx++) { } argt = cmdnames[cmdidx].argt; cmd = cmdnames[cmdidx].code; if (cmd == CMD_NULL) { #if OSK msg("Unknown command \"%s\"", scan); #else msg("Unknown command \"%.*s\"", cmdlen, scan); #endif return; } /* if the command ended with a bang, set the forceit flag */ scan += cmdlen; if ((argt & BANG) && *scan == '!') { scan++; forceit = 1; } else { forceit = 0; } /* skip any more whitespace, to leave scan pointing to arguments */ while (isascii(*scan) && isspace(*scan)) { scan++; } /* a couple of special cases for filenames */ if (argt & XFILE) { /* if names were given, process them */ if (*scan) { for (build = tmpblk.c, iswild = didsub = FALSE; *scan; scan++) { switch (*scan) { case '%': if (!*origname) { msg("No filename to substitute for %%"); return; } strcpy(build, origname); while (*build) { build++; } didsub = TRUE; break; case '#': if (!*prevorig) { msg("No filename to substitute for #"); return; } strcpy(build, prevorig); while (*build) { build++; } didsub = TRUE; break; case '*': case '?': #if !(MSDOS || TOS) case '[': case '`': case '{': /* } */ case '$': case '~': #endif *build++ = *scan; iswild = TRUE; break; default: *build++ = *scan; } } *build = '\0'; if (cmd == CMD_BANG || cmd == CMD_READ && tmpblk.c[0] == '!' || cmd == CMD_WRITE && tmpblk.c[0] == '!') { if (didsub) { if (mode != MODE_EX) { addch('\n'); } addstr(tmpblk.c); addch('\n'); exrefresh(); } } else { if (iswild && tmpblk.c[0] != '>') { scan = wildcard(tmpblk.c); } } } else /* no names given, maybe assume origname */ { if (!(argt & NODFL)) { strcpy(tmpblk.c, origname); } else { *tmpblk.c = '\0'; } } scan = tmpblk.c; } /* bad arguments? */ if (!(argt & EXRCOK) && nlines < 1L) { msg("Can't use the \"%s\" command in a %s file", cmdnames[cmdidx].name, EXRC); return; } if (!(argt & (ZERO | EXRCOK)) && frommark == MARK_UNSET) { msg("Can't use address 0 with \"%s\" command.", cmdnames[cmdidx].name); return; } if (!(argt & FROM) && frommark != cursor && nlines >= 1L) { msg("Can't use address with \"%s\" command.", cmdnames[cmdidx].name); return; } if (!(argt & TO) && tomark != frommark && nlines >= 1L) { msg("Can't use a range with \"%s\" command.", cmdnames[cmdidx].name); return; } if (!(argt & EXTRA) && *scan) { msg("Extra characters after \"%s\" command.", cmdnames[cmdidx].name); return; } if ((argt & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!'))) { build = scan; #ifndef CRUNCH if ((argt & PLUS) && *build == '+') { while (*build && !(isascii(*build) && isspace(*build))) { build++; } while (*build && isascii(*build) && isspace(*build)) { build++; } } #endif /* not CRUNCH */ for (; *build; build++) { if (isspace(*build)) { msg("Too many %s to \"%s\" command.", (argt & XFILE) ? "filenames" : "arguments", cmdnames[cmdidx].name); return; } } } /* some commands have special default ranges */ if (isdfl && (argt & DFLALL)) { frommark = MARK_FIRST; tomark = MARK_LAST; } else if (isdfl && (argt & DFLNONE)) { frommark = tomark = 0L; } /* write a newline if called from visual mode */ if ((argt & NL) && mode != MODE_EX && !exwrote) { addch('\n'); exrefresh(); } /* act on the command */ (*cmdnames[cmdidx].fn)(frommark, tomark, cmd, forceit, scan); } /* This function executes EX commands from a file. It returns 1 normally, or * 0 if the file could not be opened for reading. */ int doexrc(filename) char *filename; /* name of a ".exrc" file */ { int fd; /* file descriptor */ int len; /* length of the ".exrc" file */ char buf[MAXRCLEN]; /* buffer, holds the entire .exrc file */ /* open the file, read it, and close */ fd = open(filename, O_RDONLY); if (fd < 0) { return 0; } len = tread(fd, buf, MAXRCLEN); close(fd); /* execute the string */ exstring(buf, len); return 1; } void exstring(buf, len) char *buf; /* the commands to execute */ int len; /* the length of the string */ { char *cmd; /* start of a command */ char *end; /* used to search for the end of cmd */ /* find & do each command */ for (cmd = buf; cmd < &buf[len]; cmd = end + 1) { /* find the end of the command */ for (end = cmd; end < &buf[len] && *end != '\n' && *end != '|'; end++) { } *end = '\0'; /* do it */ doexcmd(cmd); } } SHAR_EOF fi # end of overwriting check if test -f 'input.c' then echo shar: will not over-write existing file "'input.c'" else cat << \SHAR_EOF > 'input.c' /* input.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the input() function, which implements vi's INPUT mode. * It also contains the code that supports digraphs. */ #include <ctype.h> #include "config.h" #include "vi.h" #ifndef NO_DIGRAPH static struct _DIG { struct _DIG *next; char key1; char key2; char dig; char save; } *digs; char digraph(key1, key2) char key1; /* the underlying character */ char key2; /* the second character */ { int newkey; REG struct _DIG *dp; /* if digraphs are disabled, then just return the new char */ if (!*o_digraph) { return key2; } /* remember the new key, so we can return it if this isn't a digraph */ newkey = key2; /* sort key1 and key2, so that their original order won't matter */ if (key1 > key2) { key2 = key1; key1 = newkey; } /* scan through the digraph chart */ for (dp = digs; dp && (dp->key1 != key1 || dp->key2 != key2); dp = dp->next) { } /* if this combination isn't in there, just use the new key */ if (!dp) { return newkey; } /* else use the digraph key */ return dp->dig; } /* this function lists or defines digraphs */ void do_digraph(bang, extra) int bang; char extra[]; { int dig; REG struct _DIG *dp; struct _DIG *prev; static int user_defined = FALSE; /* boolean: are all later digraphs user-defined? */ char listbuf[8]; /* if "extra" is NULL, then we've reached the end of the built-ins */ if (!extra) { user_defined = TRUE; return; } /* if no args, then display the existing digraphs */ if (*extra < ' ') { listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' '; listbuf[7] = '\0'; for (dig = 0, dp = digs; dp; dp = dp->next) { if (dp->save || bang) { dig += 7; if (dig >= COLS) { addch('\n'); exrefresh(); dig = 7; } listbuf[3] = dp->key1; listbuf[4] = dp->key2; listbuf[6] = dp->dig; qaddstr(listbuf); } } addch('\n'); exrefresh(); return; } /* make sure we have at least two characters */ if (!extra[1]) { msg("Digraphs must be composed of two characters"); return; } /* sort key1 and key2, so that their original order won't matter */ if (extra[0] > extra[1]) { dig = extra[0]; extra[0] = extra[1]; extra[1] = dig; } /* locate the new digraph character */ for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++) { } dig = extra[dig]; if (!bang && dig) { dig |= 0x80; } /* search for the digraph */ for (prev = (struct _DIG *)0, dp = digs; dp && (dp->key1 != extra[0] || dp->key2 != extra[1]); prev = dp, dp = dp->next) { } /* deleting the digraph? */ if (!dig) { if (!dp) { #ifndef CRUNCH msg("%c%c not a digraph", extra[0], extra[1]); #endif return; } if (prev) prev->next = dp->next; else digs = dp->next; free(dp); return; } /* if necessary, create a new digraph struct for the new digraph */ if (dig && !dp) { dp = (struct _DIG *)malloc(sizeof *dp); if (!dp) { msg("Out of space in the digraph table"); return; } if (prev) prev->next = dp; else digs = dp; dp->next = (struct _DIG *)0; } /* assign it the new digraph value */ dp->key1 = extra[0]; dp->key2 = extra[1]; dp->dig = dig; dp->save = user_defined; } # ifndef NO_MKEXRC void savedigs(fd) int fd; { static char buf[] = "digraph! XX Y\n"; REG struct _DIG *dp; for (dp = digs; dp; dp = dp->next) { if (dp->save) { buf[9] = dp->key1; buf[10] = dp->key2; buf[12] = dp->dig; write(fd, buf, (unsigned)14); } } } # endif #endif #ifndef NO_ABBR static struct _AB { struct _AB *next; char *large; /* the expanded form */ char small[1]; /* the abbreviated form (appended to struct) */ } *abbrev; /* This functions lists or defines abbreviations */ void do_abbr(extra) char *extra; { int smlen; /* length of the small form */ int lrg; /* index of the start of the large form */ REG struct _AB *ab; /* used to move through the abbrev list */ struct _AB *prev; /* no arguments? */ if (!*extra) { /* list all current abbreviations */ for (ab = abbrev; ab; ab = ab->next) { qaddstr("abbr "); qaddstr(ab->small); qaddch(' '); qaddstr(ab->large); addch('\n'); exrefresh(); } return; } /* else one or more arguments. Parse the first & look up in abbrev[] */ for (smlen = 0; extra[smlen] && isalnum(extra[smlen]); smlen++) { } for (prev = (struct _AB *)0, ab = abbrev; ab; prev = ab, ab = ab->next) { if (!strncmp(extra, ab->small, smlen) && !ab->small[smlen]) { break; } } /* locate the start of the large form, if any */ for (lrg = smlen; extra[lrg] && isascii(extra[lrg]) && isspace(extra[lrg]); lrg++) { } /* only one arg? */ if (!extra[lrg]) { /* trying to undo an abbreviation which doesn't exist? */ if (!ab) { #ifndef CRUNCH msg("\"%s\" not an abbreviation", extra); #endif return; } /* undo the abbreviation */ if (prev) prev->next = ab->next; else abbrev = ab->next; free(ab->large); free(ab); return; } /* multiple args - [re]define an abbreviation */ if (ab) { /* redefining - free the old large form */ free(ab->large); } else { /* adding a new definition - make a new struct */ ab = (struct _AB *)malloc((unsigned)(smlen + sizeof *ab)); #ifndef CRUNCH if (!ab) { msg("Out of memory -- Sorry"); return; } #endif strncpy(ab->small, extra, smlen); ab->small[smlen] = '\0'; ab->next = (struct _AB *)0; if (prev) prev->next = ab; else abbrev = ab; } /* store the new form */ ab->large = (char *)malloc((unsigned)(strlen(&extra[lrg]) + 1)); strcpy(ab->large, &extra[lrg]); } # ifndef NO_MKEXRC /* This function is called from cmd_mkexrc() to save the abbreviations */ void saveabbr(fd) int fd; /* fd to which the :abbr commands should be written */ { REG struct _AB *ab; for (ab = abbrev; ab; ab = ab->next) { twrite(fd, "abbr ", 5); twrite(fd, ab->small, strlen(ab->small)); twrite(fd, " ", 1); twrite(fd, ab->large, strlen(ab->large)); twrite(fd, "\n", 1); } } # endif /* This function should be called before each char is inserted. If the next * char is non-alphanumeric and we're at the end of a word, then that word * is checked against the abbrev[] array and expanded, if appropriate. Upon * returning from this function, the new char still must be inserted. */ static MARK expandabbr(m, ch) MARK m; /* the cursor position */ int ch; /* the character to insert */ { char *word; /* where the word starts */ int len; /* length of the word */ REG struct _AB *ab; /* if no abbreviations are in effect, or ch is aphanumeric, then * don't do anything */ if (!abbrev || !isascii(ch) || isalnum(ch)) { return m; } /* see where the preceding word starts */ pfetch(markline(m)); for (word = ptext + markidx(m), len = 0; --word >= ptext && (!isascii(*word) || isalnum(*word)); len++) { } word++; /* if zero-length, then it isn't a word, really -- so nothing */ if (len == 0) { return m; } /* look it up in the abbrev list */ for (ab = abbrev; ab; ab = ab->next) { if (!strncmp(ab->small, word, len) && !ab->small[len]) { break; } } /* not an abbreviation? then do nothing */ if (!ab) { return m; } /* else replace the small form with the large form */ add(m, ab->large); delete(m - len, m); /* return with the cursor after the end of the large form */ return m - len + strlen(ab->large); } #endif /* This function allows the user to replace an existing (possibly zero-length) * chunk of text with typed-in text. It returns the MARK of the last character * that the user typed in. */ MARK input(from, to, when, indentref) MARK from; /* where to start inserting text */ MARK to; /* extent of text to delete */ int when; /* either WHEN_VIINP or WHEN_VIREP */ long indentref; /* line rel to current mark to use for autoindent reference - MCH */ { char key[2]; /* key char followed by '\0' char */ char *build; /* used in building a newline+indent string */ char *scan; /* used while looking at the indent chars of a line */ MARK m; /* some place in the text */ #ifndef NO_EXTENSIONS int quit = FALSE; /* boolean: are we exiting after this? */ #endif #ifdef DEBUG /* if "from" and "to" are reversed, complain */ if (from > to) { msg("ERROR: input(%ld:%d, %ld:%d)", markline(from), markidx(from), markline(to), markidx(to)); return MARK_UNSET; } #endif key[1] = 0; /* if we're replacing text with new text, save the old stuff */ /* (Alas, there is no easy way to save text for replace mode) */ if (from != to) { cut(from, to); } ChangeText { /* if doing a dot command, then reuse the previous text */ if (doingdot) { /* delete the text that's there now */ if (from != to) { delete(from, to); } /* insert the previous text */ cutname('.'); cursor = paste(from, FALSE, TRUE) + 1L; } else /* interactive version */ { /* if doing a change within the line... */ if (from != to && markline(from) == markline(to)) { /* mark the end of the text with a "$" */ change(to - 1, to, "$"); } else { /* delete the old text right off */ if (from != to) { delete(from, to); } to = from; } /* handle autoindent of the first line, maybe */ cursor = from; if (*o_autoindent && markline(cursor) > 1L && markidx(cursor) == 0) { /* Only autoindent blank lines. */ pfetch(markline(cursor)); if (plen == 0) { /* Okay, we really want to autoindent */ pfetch(markline(cursor) + indentref); for (scan = ptext, build = tmpblk.c; *scan == ' ' || *scan == '\t'; ) { *build++ = *scan++; } if (build > tmpblk.c) { *build = '\0'; add(cursor, tmpblk.c); cursor += (build - tmpblk.c); } } } /* repeatedly add characters from the user */ for (;;) { /* Get a character */ redraw(cursor, TRUE); #ifdef DEBUG msg("cursor=%ld.%d, to=%ld.%d", markline(cursor), markidx(cursor), markline(to), markidx(to)); #endif key[0] = getkey(when); /* if whitespace & wrapmargin is set & we're * past the warpmargin, then change the * whitespace character into a newline */ if ((*key == ' ' || *key == '\t') && *o_wrapmargin != 0) { pfetch(markline(cursor)); if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff)) { *key = '\n'; } } /* process it */ switch (*key) { #ifndef NO_EXTENSIONS case 0: /* special movement mapped keys */ *key = getkey(0); switch (*key) { case 'h': m = m_left(cursor, 0L); break; case 'j': case 'k': m = m_updnto(cursor, 0L, *key); break; case 'l': m = cursor + 1; break; case 'b': m = m_bword(cursor, 0L); break; case 'w': m = m_fword(cursor, 0L); break; case '^': m = m_front(cursor, 0L); break; case '$': m = m_rear(cursor, 0L); break; case ctrl('B'): case ctrl('F'): m = m_scroll(cursor, 0L, *key); break; case 'x': m = v_xchar(cursor, 0L); break; case 'i': m = to = from = cursor; break; default: m = MARK_UNSET; break; } /* adjust the moved cursor */ m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0)); if (*key == '$' || (*key == 'l' && m <= cursor)) { m++; } /* if the cursor is reasonable, use it */ if (m == MARK_UNSET) { Beep(); } else { if (to > cursor) { delete(cursor, to); redraw(cursor, TRUE); } from = to = cursor = m; } break; case ctrl('Z'): if (getkey(0) == ctrl('Z')) { quit = TRUE; goto BreakBreak; } break; #endif case ctrl('['): #ifndef NO_ABBR cursor = expandabbr(cursor, ctrl('[')); #endif goto BreakBreak; case ctrl('U'): if (markline(cursor) == markline(from)) { cursor = from; } else { cursor &= ~(BLKSIZE - 1); } break; case ctrl('D'): case ctrl('T'): if (to > cursor) { delete(cursor, to); } mark[27] = cursor; cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, ""); if (mark[27]) { cursor = mark[27]; } else { cursor = m_front(cursor, 0L); } to = cursor; break; case '\b': if (cursor <= from) { Beep(); } else if (markidx(cursor) == 0) { cursor -= BLKSIZE; pfetch(markline(cursor)); cursor += plen; } else { cursor--; } break; case ctrl('W'): m = m_bword(cursor, 1L); if (markline(m) == markline(cursor) && m >= from) { cursor = m; if (from > cursor) { from = cursor; } } else { Beep(); } break; case '\n': #if OSK case '\l': #else case '\r': #endif #ifndef NO_ABBR cursor = expandabbr(cursor, '\n'); #endif build = tmpblk.c; *build++ = '\n'; if (*o_autoindent) { /* figure out indent for next line */ pfetch(markline(cursor)); for (scan = ptext; *scan == ' ' || *scan == '\t'; ) { *build++ = *scan++; } /* remove indent from this line, if blank */ if (!*scan && plen > 0) { to = cursor &= ~(BLKSIZE - 1); delete(cursor, cursor + plen); } } *build = 0; if (cursor >= to && when != WHEN_VIREP) { add(cursor, tmpblk.c); } else { change(cursor, to, tmpblk.c); } redraw(cursor, TRUE); to = cursor = (cursor & ~(BLKSIZE - 1)) + BLKSIZE + (int)(build - tmpblk.c) - 1; break; case ctrl('A'): case ctrl('P'): if (cursor < to) { delete(cursor, to); } if (*key == ctrl('A')) { cutname('.'); } to = cursor = paste(cursor, FALSE, TRUE) + 1L; break; case ctrl('V'): if (cursor >= to && when != WHEN_VIREP) { add(cursor, "^"); } else { change(cursor, to, "^"); to = cursor + 1; } redraw(cursor, TRUE); *key = getkey(0); if (*key == '\n') { /* '\n' too hard to handle */ #if OSK *key = '\l'; #else *key = '\r'; #endif } change(cursor, cursor + 1, key); cursor++; if (cursor > to) { to = cursor; } break; case ctrl('L'): case ctrl('R'): redraw(MARK_UNSET, FALSE); break; default: if (cursor >= to && when != WHEN_VIREP) { #ifndef NO_ABBR cursor = expandabbr(cursor, *key); #endif add(cursor, key); cursor++; to = cursor; } else { pfetch(markline(cursor)); if (markidx(cursor) == plen) { #ifndef NO_ABBR cursor = expandabbr(cursor, *key); #endif add(cursor, key); } else { #ifndef NO_DIGRAPH *key = digraph(ptext[markidx(cursor)], *key); #endif #ifndef NO_ABBR cursor = expandabbr(cursor, *key); #endif change(cursor, cursor + 1, key); } cursor++; } #ifndef NO_SHOWMATCH /* show matching "({[" if neceesary */ if (*o_showmatch && strchr(")}]", *key)) { redraw(cursor, TRUE); m = m_match(cursor - 1, 0L); if (markline(m) >= topline && markline(m) <= botline) { redraw(m, TRUE); refresh(); sleep(1); } } #endif } /* end switch(*key) */ } /* end for(;;) */ BreakBreak:; /* delete any excess characters */ /* this includes any whitespace on a whitespace only line if we are in autoindent mode - MCH */ if (*o_autoindent) { /* remove indent from this line, if blank */ pfetch(markline(cursor)); for (scan = ptext; *scan == ' ' || *scan == '\t'; ) *scan++; if (!*scan && plen > 0) { to = cursor &= ~(BLKSIZE - 1); delete(cursor, cursor + plen); } } if (cursor < to) { delete(cursor, to); } } /* end if doingdot else */ } /* end ChangeText */ /* put the new text into a cut buffer for possible reuse */ if (!doingdot) { blksync(); cutname('.'); cut(from, cursor); } /* move to last char that we inputted, unless it was newline */ if (markidx(cursor) != 0) { cursor--; } redraw(cursor, FALSE); #ifndef NO_EXTENSIONS if (quit) { /* if this is a nested "do", then cut it short */ abortdo(); /* exit, unless we can't write out the file */ cursor = v_xit(cursor, 0L, 'Z'); } #endif rptlines = 0L; return cursor; } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # main.c # misc.c # modify.c # move1.c # move2.c # move3.c # move4.c # move5.c # This archive created: Thu Jan 10 17:21:08 1991 export PATH; PATH=/bin:$PATH if test -f 'main.c' then echo shar: will not over-write existing file "'main.c'" else cat << \SHAR_EOF > 'main.c' /* main.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the main() function of vi */ #include "config.h" #include <signal.h> #include <setjmp.h> #include "vi.h" extern trapint(); /* defined below */ extern char *getenv(); jmp_buf jmpenv; #ifndef NO_DIGRAPH static init_digraphs(); #endif /*---------------------------------------------------------------------*/ void main(argc, argv) int argc; char *argv[]; { int i; char *cmd = (char *)0; char *tag = (char *)0; char *err = (char *)0; char *str; #if MSDOS || TOS char firstarg[256]; #else char *firstarg; #endif /* set mode to MODE_VI or MODE_EX depending on program name */ switch (argv[0][strlen(argv[0]) - 1]) { case 'x': /* "ex" */ mode = MODE_EX; break; case 'w': /* "view" */ mode = MODE_VI; *o_readonly = TRUE; break; #ifndef NO_EXTENSIONS case 't': /* "edit" or "input" */ mode = MODE_VI; *o_inputmode = TRUE; break; #endif default: /* "vi" or "elvis" */ mode = MODE_VI; } #ifndef DEBUG # ifdef SIGQUIT /* normally, we ignore SIGQUIT. SIGINT is trapped later */ signal(SIGQUIT, SIG_IGN); # endif #endif /* temporarily ignore SIGINT */ signal(SIGINT, SIG_IGN); /* Before we fire up whatever form of curses we are doing let special version of elvis get any flags it needs Customflags removes any custom flags from argv so the standard elvis does'nt have to know about them */ Customflags(argv, &argc); /* start curses */ Initscr(); cbreak(); noecho(); scrollok(stdscr, TRUE); /* initialize the options */ initopts(); /* map the arrow keys. The KU,KD,KL,and KR variables correspond to * the :ku=: (etc.) termcap capabilities. The variables are defined * as part of the curses package. */ if (has_KU) mapkey(has_KU, "k", WHEN_VICMD|WHEN_INMV, "<Up>"); if (has_KD) mapkey(has_KD, "j", WHEN_VICMD|WHEN_INMV, "<Down>"); if (has_KL) mapkey(has_KL, "h", WHEN_VICMD|WHEN_INMV, "<Left>"); if (has_KR) mapkey(has_KR, "l", WHEN_VICMD|WHEN_INMV, "<Right>"); if (has_HM) mapkey(has_HM, "^", WHEN_VICMD|WHEN_INMV, "<Home>"); if (has_EN) mapkey(has_EN, "$", WHEN_VICMD|WHEN_INMV, "<End>"); if (has_PU) mapkey(has_PU, "\002", WHEN_VICMD|WHEN_INMV, "<PgUp>"); if (has_PD) mapkey(has_PD, "\006", WHEN_VICMD|WHEN_INMV, "<PgDn>"); #if MSDOS if (*o_pcbios) { mapkey("#R", "i", WHEN_VICMD|WHEN_INMV, "<Insrt>"); mapkey("#S", "x", WHEN_VICMD|WHEN_INMV, "<Del>"); mapkey("#s", "B", WHEN_VICMD|WHEN_INMV, "^<left>"); mapkey("#t", "W", WHEN_VICMD|WHEN_INMV, "^<right>"); } #else if (ERASEKEY != '\177') { mapkey("\177", "x", WHEN_VICMD|WHEN_INMV, "<Del>"); } #endif #ifndef NO_DIGRAPH init_digraphs(); #endif /* NO_DIGRAPH */ /* process any flags */ for (i = 1; i < argc && *argv[i] == '-'; i++) { switch (argv[i][1]) { case 'R': /* readonly */ *o_readonly = TRUE; break; case 'r': /* recover */ msg("Use the `virec` program to recover lost files"); endmsgs(); refresh(); endwin(); exit(0); break; case 't': /* tag */ if (argv[i][2]) { tag = argv[i] + 2; } else { i++; tag = argv[i]; } break; case 'v': /* vi mode */ mode = MODE_VI; break; case 'e': /* ex mode */ mode = MODE_EX; break; #ifndef NO_EXTENSIONS case 'i': /* input mode */ *o_inputmode = TRUE; break; #endif #ifndef NO_ERRLIST case 'm': /* use "errlist" as the errlist */ if (argv[i][2]) { err = argv[i] + 2; } else if (i + 1 < argc) { i++; err = argv[i]; } else { err = ""; } break; #endif default: msg("Ignoring unknown flag \"%s\"", argv[i]); } } /* if we were given an initial ex command, save it... */ if (i < argc && *argv[i] == '+') { if (argv[i][1]) { cmd = argv[i++] + 1; } else { cmd = "$"; /* "vi + file" means start at EOF */ i++; } } /* the remaining args are file names. */ nargs = argc - i; if (nargs > 0) { #if ! ( MSDOS || TOS ) firstarg = argv[i]; #endif strcpy(args, argv[i]); while (++i < argc && strlen(args) + 1 + strlen(argv[i]) < sizeof args) { strcat(args, " "); strcat(args, argv[i]); } } #if ! ( MSDOS || TOS ) else { firstarg = ""; } #endif argno = 0; #if MSDOS || TOS if (nargs > 0) { strcpy(args, wildcard(args)); nargs = 1; for (i = 0; args[i]; i++) { if (args[i] == ' ') { nargs++; } } for (i = 0; args[i] && args[i] != ' '; i++) { firstarg[i] = args[i]; } firstarg[i] = '\0'; } else { firstarg[0] = '\0'; } #endif /* perform the .exrc files and EXINIT environment variable */ #ifdef SYSEXRC doexrc(SYSEXRC); #endif #ifdef HMEXRC str = getenv("HOME"); if (str) { sprintf(tmpblk.c, "%s%c%s", str, SLASH, HMEXRC); doexrc(tmpblk.c); } #endif doexrc(EXRC); #ifdef EXINIT str = getenv(EXINIT); if (str) { exstring(str, strlen(str)); } #endif /* search for a tag (or an error) now, if desired */ blkinit(); if (tag) { cmd_tag(MARK_FIRST, MARK_FIRST, CMD_TAG, 0, tag); } #ifndef NO_ERRLIST else if (err) { cmd_errlist(MARK_FIRST, MARK_FIRST, CMD_ERRLIST, 0, err); } #endif /* if no tag/err, or tag failed, then start with first arg */ if (tmpfd < 0 && Tmpstart(firstarg) == 0 && *origname) { ChangeText { } clrflag(file, MODIFIED); } /* now we do the immediate ex command that we noticed before */ if (cmd) { doexcmd(cmd); } /* repeatedly call ex() or vi() (depending on the mode) until the * mode is set to MODE_QUIT */ while (mode != MODE_QUIT) { if (setjmp(jmpenv)) { /* Maybe we just aborted a change? */ abortdo(); } #if TURBOC signal(SIGINT, (void(*)()) trapint); #else signal(SIGINT, trapint); #endif switch (mode) { case MODE_VI: Vi(); break; case MODE_EX: Ex(); break; #ifdef DEBUG default: msg("mode = %d?", mode); mode = MODE_QUIT; #endif } } /* free up the cut buffers */ cutend(); /* end curses */ #ifndef NO_CURSORSHAPE if (has_CQ) do_CQ(); #endif endmsgs(); move(LINES - 1, 0); clrtoeol(); refresh(); endwin(); exit(0); /*NOTREACHED*/ } /*ARGSUSED*/ int trapint(signo) int signo; { Resume_curses(FALSE); abortdo(); #if OSK sigmask(-1); #endif #if TURBO_C signal(signo, (void (*)())trapint); #else signal(signo, trapint); #endif longjmp(jmpenv, 1); return 0; } #ifndef NO_DIGRAPH /* This stuff us used to build the default digraphs table. */ static char digtable[][4] = { # if CS_IBMPC "C,\200", "u\"\1", "e'\2", "a^\3", "a\"\4", "a`\5", "a@\6", "c,\7", "e^\10", "e\"\211", "e`\12", "i\"\13", "i^\14", "i`\15", "A\"\16", "A@\17", "E'\20", "ae\21", "AE\22", "o^\23", "o\"\24", "o`\25", "u^\26", "u`\27", "y\"\30", "O\"\31", "U\"\32", "a'\240", "i'!", "o'\"", "u'#", "n~$", "N~%", "a-&", "o-'", "~?(", "~!-", "\"<.", "\">/", # if CS_SPECIAL "2/+", "4/,", "^+;", "^q<", "^c=", "^r>", "^t?", "pp]", "^^^", "oo_", "*a`", "*ba", "*pc", "*Sd", "*se", "*uf", "*tg", "*Ph", "*Ti", "*Oj", "*dk", "*Hl", "*hm", "*En", "*No", "eqp", "pmq", "ger", "les", "*It", "*iu", "*/v", "*=w", "sq{", "^n|", "^2}", "^3~", "^_\377", # endif /* CS_SPECIAL */ # endif /* CS_IBMPC */ # if CS_LATIN1 "~!!", "a-*", "\">+", "o-:", "\"<>", "~??", "A`@", "A'A", "A^B", "A~C", "A\"D", "A@E", "AEF", "C,G", "E`H", "E'I", "E^J", "E\"K", "I`L", "I'M", "I^N", "I\"O", "-DP", "N~Q", "O`R", "O'S", "O^T", "O~U", "O\"V", "O/X", "U`Y", "U'Z", "U^[", "U\"\\", "Y'_", "a``", "a'a", "a^b", "a~c", "a\"d", "a@e", "aef", "c,g", "e`h", "e'i", "e^j", "e\"k", "i`l", "i'm", "i^n", "i\"o", "-dp", "n~q", "o`r", "o's", "o^t", "o~u", "o\"v", "o/x", "u`y", "u'z", "u^{", "u\"|", "y'~", # endif /* CS_LATIN1 */ "" }; static init_digraphs() { int i; for (i = 0; *digtable[i]; i++) { do_digraph(FALSE, digtable[i]); } do_digraph(FALSE, (char *)0); } #endif /* NO_DIGRAPH */ SHAR_EOF fi # end of overwriting check if test -f 'misc.c' then echo shar: will not over-write existing file "'misc.c'" else cat << \SHAR_EOF > 'misc.c' /* misc.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains functions which didn't seem happy anywhere else */ #include "config.h" #include "vi.h" /* find a particular line & return a pointer to a copy of its text */ char *fetchline(line) long line; /* line number of the line to fetch */ { int i; REG char *scan; /* used to search for the line in a BLK */ long l; /* line number counter */ static BLK buf; /* holds ONLY the selected line (as string) */ REG char *cpy; /* used while copying the line */ static long nextline; /* } These four variables are used */ static long chglevel; /* } to implement a shortcut when */ static char *nextscan; /* } consecutive lines are fetched */ static long nextlnum; /* } */ /* can we do a shortcut? */ if (changes == chglevel && line == nextline) { scan = nextscan; } else { /* scan lnum[] to determine which block its in */ for (i = 1; line > lnum[i]; i++) { } nextlnum = lnum[i]; /* fetch text of the block containing that line */ scan = blkget(i)->c; /* find the line in the block */ for (l = lnum[i - 1]; ++l < line; ) { while (*scan++ != '\n') { } } } /* copy it into a block by itself, with no newline */ for (cpy = buf.c; *scan != '\n'; ) { *cpy++ = *scan++; } *cpy = '\0'; /* maybe speed up the next call to fetchline() ? */ if (line < nextlnum) { nextline = line + 1; chglevel = changes; nextscan = scan + 1; } else { nextline = 0; } /* Calls to fetchline() interfere with calls to pfetch(). Make sure * that pfetch() resets itself on its next invocation. */ pchgs = 0L; /* Return a pointer to the line's text */ return buf.c; } /* error message from the regexp code */ void regerror(txt) char *txt; /* an error message */ { msg("RE error: %s", txt); } /* This function is equivelent to the pfetch() macro */ void pfetch(l) long l; /* line number of line to fetch */ { if(l != pline || changes != pchgs) { pline = (l); ptext = fetchline(pline); plen = strlen(ptext); pchgs = changes; } } SHAR_EOF fi # end of overwriting check if test -f 'modify.c' then echo shar: will not over-write existing file "'modify.c'" else cat << \SHAR_EOF > 'modify.c' /* modify.c */ /* This file contains the low-level file modification functions: * delete(frommark, tomark) - removes line or portions of lines * add(frommark, text) - inserts new text * change(frommark, tomark, text) - delete, then add */ #include "config.h" #include "vi.h" #ifdef DEBUG # include <stdio.h> static FILE *dbg; /*VARARGS1*/ debout(msg, arg1, arg2, arg3, arg4, arg5) char *msg, *arg1, *arg2, *arg3, *arg4, *arg5; { if (!dbg) { dbg = fopen("debug.out", "w"); setbuf(dbg, (FILE *)0); } fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5); } #endif /* DEBUG */ /* delete a range of text from the file */ void delete(frommark, tomark) MARK frommark; /* first char to be deleted */ MARK tomark; /* AFTER last char to be deleted */ { int i; /* used to move thru logical blocks */ REG char *scan; /* used to scan thru text of the blk */ REG char *cpy; /* used when copying chars */ BLK *blk; /* a text block */ long l; /* a line number */ MARK m; /* a traveling version of frommark */ #ifdef DEBUG debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark)); #endif /* if not deleting anything, quit now */ if (frommark == tomark) { return; } /* This is a change */ changes++; significant = TRUE; /* if this is a multi-line change, then we'll have to redraw */ if (markline(frommark) != markline(tomark)) { mustredraw = TRUE; redrawrange(markline(frommark), markline(tomark), markline(frommark)); } /* adjust marks 'a through 'z and '' as needed */ l = markline(tomark); for (i = 0; i < NMARKS; i++) { if (mark[i] < frommark) { continue; } else if (mark[i] < tomark) { mark[i] = MARK_UNSET; } else if (markline(mark[i]) == l) { if (markline(frommark) == l) { mark[i] -= markidx(tomark) - markidx(frommark); } else { mark[i] -= markidx(tomark); } } else { mark[i] -= MARK_AT_LINE(l - markline(frommark)); } } /* Reporting... */ if (markidx(frommark) == 0 && markidx(tomark) == 0) { rptlines = markline(tomark) - markline(frommark); rptlabel = "deleted"; } /* find the block containing frommark */ l = markline(frommark); for (i = 1; lnum[i] < l; i++) { } /* process each affected block... */ for (m = frommark; m < tomark && lnum[i] < INFINITY; m = MARK_AT_LINE(lnum[i - 1] + 1)) { /* fetch the block */ blk = blkget(i); /* find the mark in the block */ scan = blk->c; for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--) { while (*scan++ != '\n') { } } scan += markidx(m); /* figure out where the changes to this block end */ if (markline(tomark) > lnum[i]) { cpy = blk->c + BLKSIZE; } else if (markline(tomark) == markline(m)) { cpy = scan - markidx(m) + markidx(tomark); } else { cpy = scan; for (l = markline(tomark) - markline(m); l > 0; l--) { while (*cpy++ != '\n') { } } cpy += markidx(tomark); } /* delete the stuff by moving chars within this block */ while (cpy < blk->c + BLKSIZE) { *scan++ = *cpy++; } while (scan < blk->c + BLKSIZE) { *scan++ = '\0'; } /* adjust tomark to allow for lines deleted from this block */ tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m)); /* if this block isn't empty now, then advance i */ if (*blk->c) { i++; } /* the buffer has changed. Update hdr and lnum. */ blkdirty(blk); } /* must have at least 1 line */ if (nlines == 0) { blk = blkadd(1); blk->c[0] = '\n'; blkdirty(blk); cursor = MARK_FIRST; } } /* add some text at a specific place in the file */ void add(atmark, newtext) MARK atmark; /* where to insert the new text */ char *newtext; /* NUL-terminated string to insert */ { REG char *scan; /* used to move through string */ REG char *build; /* used while copying chars */ int addlines; /* number of lines we're adding */ int lastpart; /* size of last partial line */ BLK *blk; /* the block to be modified */ int blkno; /* the logical block# of (*blk) */ REG char *newptr; /* where new text starts in blk */ BLK buf; /* holds chars from orig blk */ BLK linebuf; /* holds part of line that didn't fit */ BLK *following; /* the BLK following the last BLK */ int i; long l; #ifdef DEBUG debout("add(%ld.%d, \"%s\")\n", markline(atmark), markidx(atmark), newtext); #endif #ifdef lint buf.c[0] = 0; #endif /* if not adding anything, return now */ if (!*newtext) { return; } /* This is a change */ changes++; significant = TRUE; /* count the number of lines in the new text */ for (scan = newtext, lastpart = addlines = 0; *scan; ) { if (*scan++ == '\n') { addlines++; lastpart = 0; } else { lastpart++; } } /* Reporting... */ if (lastpart == 0 && markidx(atmark) == 0) { rptlines = addlines; rptlabel = "added"; } /* extract the line# from atmark */ l = markline(atmark); /* if more than 0 lines, then we'll have to redraw the screen */ if (addlines > 0) { mustredraw = TRUE; if (markidx(atmark) == 0 && lastpart == 0) { redrawrange(l, l, l + addlines); } else { /* make sure the last line gets redrawn -- it was * split, so its appearance has changed */ redrawrange(l, l + 1L, l + addlines + 1L); } } /* adjust marks 'a through 'z and '' as needed */ for (i = 0; i < NMARKS; i++) { if (mark[i] < atmark) { /* earlier line, or earlier in same line: no change */ continue; } else if (markline(mark[i]) > l) { /* later line: move down a whole number of lines */ mark[i] += MARK_AT_LINE(addlines); } else { /* later in same line */ if (addlines > 0) { /* multi-line add, which split this line: * move down, and possibly left or right, * depending on where the split was and how * much text was inserted after the last \n */ mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark); } else { /* totally within this line: move right */ mark[i] += lastpart; } } } /* get the block to be modified */ for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++) { } blk = blkget(blkno); buf = *blk; /* figure out where the new text starts */ for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1; l > 0; l--) { while (*newptr++ != '\n') { } } newptr += markidx(atmark); /* keep start of old block */ build = blk->c + (newptr - buf.c); /* fill this block (or blocks) from the newtext string */ while (*newtext) { while (*newtext && build < blk->c + BLKSIZE - 1) { *build++ = *newtext++; } if (*newtext) { /* save the excess */ for (scan = linebuf.c + BLKSIZE; build > blk->c && build[-1] != '\n'; ) { *--scan = *--build; } /* write the block */ while (build < blk->c + BLKSIZE) { *build++ = '\0'; } blkdirty(blk); /* add another block */ blkno++; blk = blkadd(blkno); /* copy in the excess from last time */ for (build = blk->c; scan < linebuf.c + BLKSIZE; ) { *build++ = *scan++; } } } /* fill this block(s) from remainder of orig block */ while (newptr < buf.c + BLKSIZE && *newptr) { while (newptr < buf.c + BLKSIZE && *newptr && build < blk->c + BLKSIZE - 1) { *build++ = *newptr++; } if (newptr < buf.c + BLKSIZE && *newptr) { /* save the excess */ for (scan = linebuf.c + BLKSIZE; build > blk->c && build[-1] != '\n'; ) { *--scan = *--build; } /* write the block */ while (build < blk->c + BLKSIZE) { *build++ = '\0'; } blkdirty(blk); /* add another block */ blkno++; blk = blkadd(blkno); /* copy in the excess from last time */ for (build = blk->c; scan < linebuf.c + BLKSIZE; ) { *build++ = *scan++; } } } /* see if we can combine our last block with the following block */ if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6)) { /* hey, we probably can! Get the following block & see... */ following = blkget(blkno + 1); if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1) { /* we can! Copy text from following to blk */ for (scan = following->c; *scan; ) { *build++ = *scan++; } while (build < blk->c + BLKSIZE) { *build++ = '\0'; } blkdirty(blk); /* pretend the following was the last blk */ blk = following; build = blk->c; } } /* that last block is dirty by now */ while (build < blk->c + BLKSIZE) { *build++ = '\0'; } blkdirty(blk); } /* change the text of a file */ void change(frommark, tomark, newtext) MARK frommark, tomark; char *newtext; { int i; long l; char *text; BLK *blk; #ifdef DEBUG debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext); #endif /* optimize for single-character replacement */ if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n') { /* find the block containing frommark */ l = markline(frommark); for (i = 1; lnum[i] < l; i++) { } /* get the block */ blk = blkget(i); /* find the line within the block */ for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++) { if (*text == '\n') { i--; } } /* replace the char */ text += markidx(frommark); if (*text == newtext[0]) { /* no change was needed - same char */ return; } else if (*text != '\n') { /* This is a change */ changes++; significant = TRUE; ChangeText { *text = newtext[0]; blkdirty(blk); } return; } /* else it is a complex change involving newline... */ } /* couldn't optimize, so do delete & add */ ChangeText { delete(frommark, tomark); add(frommark, newtext); rptlabel = "changed"; } } SHAR_EOF fi # end of overwriting check if test -f 'move1.c' then echo shar: will not over-write existing file "'move1.c'" else cat << \SHAR_EOF > 'move1.c' /* move1.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains most movement functions */ #include "config.h" #include <ctype.h> #include "vi.h" #ifndef isascii # define isascii(c) !((c) & ~0x7f) #endif MARK m_updnto(m, cnt, cmd) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { DEFAULT(cmd == 'G' ? nlines : 1L); /* move up or down 'cnt' lines */ switch (cmd) { case ('P'&0x1f): case '-': case 'k': m -= MARK_AT_LINE(cnt); break; case 'G': if (cnt < 1L || cnt > nlines) { msg("Only %ld lines", nlines); return MARK_UNSET; } m = MARK_AT_LINE(cnt); break; default: m += MARK_AT_LINE(cnt); } /* if that left us screwed up, then fail */ if (m < MARK_FIRST || markline(m) > nlines) { return MARK_UNSET; } return m; } /*ARGSUSED*/ MARK m_right(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { int idx; /* index of the new cursor position */ DEFAULT(1); /* move to right, if that's OK */ pfetch(markline(m)); idx = markidx(m) + cnt; if (idx < plen) { m += cnt; } else { return MARK_UNSET; } return m; } /*ARGSUSED*/ MARK m_left(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { DEFAULT(1); /* move to the left, if that's OK */ if (markidx(m) >= cnt) { m -= cnt; } else { return MARK_UNSET; } return m; } /*ARGSUSED*/ MARK m_tocol(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { char *text; /* text of the line */ int col; /* column number */ int idx; /* index into the line */ DEFAULT(1); /* internally, columns are numbered 0..COLS-1, not 1..COLS */ cnt--; /* if 0, that's easy */ if (cnt == 0) { m &= ~(BLKSIZE - 1); return m; } /* find that column within the line */ pfetch(markline(m)); text = ptext; for (col = idx = 0; col < cnt && *text; text++, idx++) { if (*text == '\t' && !*o_list) { col += *o_tabstop; col -= col % *o_tabstop; } else if (UCHAR(*text) < ' ' || *text == '\177') { col += 2; } #ifndef NO_CHARATTR else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more as part of for loop */ } #endif else { col++; } } if (!*text) { return MARK_UNSET; } else { m = (m & ~(BLKSIZE - 1)) + idx; } return m; } /*ARGSUSED*/ MARK m_front(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument (ignored) */ { char *scan; /* move to the first non-whitespace character */ pfetch(markline(m)); scan = ptext; m &= ~(BLKSIZE - 1); while (*scan == ' ' || *scan == '\t') { scan++; m++; } return m; } /*ARGSUSED*/ MARK m_rear(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument (ignored) */ { /* Try to move *EXTREMELY* far to the right. It is fervently hoped * that other code will convert this to a more reasonable MARK before * anything tries to actually use it. (See adjmove() in vi.c) */ return m | (BLKSIZE - 1); } #ifndef NO_SENTENCE /*ARGSUSED*/ MARK m_fsentence(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { REG char *text; REG long l; DEFAULT(1); /* get the current line */ l = markline(m); pfetch(l); text = ptext + markidx(m); /* for each requested sentence... */ while (cnt-- > 0) { /* search forward for one of [.?!] followed by spaces or EOL */ do { /* wrap at end of line */ if (!text[0]) { if (l >= nlines) { return MARK_UNSET; } l++; pfetch(l); text = ptext; } else { text++; } } while (text[0] != '.' && text[0] != '?' && text[0] != '!' || text[1] && (text[1] != ' ' || text[2] && text[2] != ' ')); } /* construct a mark for this location */ m = buildmark(text); /* move forward to the first word of the next sentence */ m = m_fword(m, 1L); return m; } /*ARGSUSED*/ MARK m_bsentence(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { REG char *text; /* used to scan thru text */ REG long l; /* current line number */ int flag; /* have we passed at least one word? */ DEFAULT(1); /* get the current line */ l = markline(m); pfetch(l); text = ptext + markidx(m); /* for each requested sentence... */ flag = TRUE; while (cnt-- > 0) { /* search backward for one of [.?!] followed by spaces or EOL */ do { /* wrap at beginning of line */ if (text == ptext) { do { if (l <= 1) { return MARK_UNSET; } l--; pfetch(l); } while (!*ptext); text = ptext + plen - 1; } else { text--; } /* are we moving past a "word"? */ if (text[0] >= '0') { flag = FALSE; } } while (flag || text[0] != '.' && text[0] != '?' && text[0] != '!' || text[1] && (text[1] != ' ' || text[2] && text[2] != ' ')); } /* construct a mark for this location */ m = buildmark(text); /* move to the front of the following sentence */ m = m_fword(m, 1L); return m; } #endif /*ARGSUSED*/ MARK m_fparagraph(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { char *text; char *pscn; /* used to scan thru value of "paragraphs" option */ long l; DEFAULT(1); for (l = markline(m); cnt > 0 && l++ < nlines; ) { text = fetchline(l); if (!*text) { cnt--; } #ifndef NO_SENTENCE else if (*text == '.') { for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2) { if (pscn[0] == text[1] && pscn[1] == text[2]) { cnt--; break; } } } #endif } if (l <= nlines) { m = MARK_AT_LINE(l); } else { m = MARK_LAST; } return m; } /*ARGSUSED*/ MARK m_bparagraph(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ { char *text; char *pscn; /* used to scan thru value of "paragraph" option */ long l; DEFAULT(1); for (l = markline(m); cnt > 0 && l-- > 1; ) { text = fetchline(l); if (!*text) { cnt--; } #ifndef NO_SENTENCE else if (*text == '.') { for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2) { if (pscn[0] == text[1] && pscn[1] == text[2]) { cnt--; break; } } } #endif } if (l >= 1) { m = MARK_AT_LINE(l); } else { m = MARK_FIRST; } return m; } /*ARGSUSED*/ MARK m_fsection(m, cnt, key) MARK m; /* movement is relative to this mark */ long cnt; /* (ignored) */ int key; /* second key stroke - must be ']' */ { char *text; char *sscn; /* used to scan thru value of "sections" option */ long l; /* make sure second key was ']' */ if (key != ']') { return MARK_UNSET; } for (l = markline(m); l++ < nlines; ) { text = fetchline(l); if (*text == '{') { break; } #ifndef NO_SENTENCE else if (*text == '.') { for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2) { if (sscn[0] == text[1] && sscn[1] == text[2]) { goto BreakBreak; } } } #endif } BreakBreak: if (l <= nlines) { m = MARK_AT_LINE(l); } else { m = MARK_LAST; } return m; } /*ARGSUSED*/ MARK m_bsection(m, cnt, key) MARK m; /* movement is relative to this mark */ long cnt; /* (ignored) */ int key; /* second key stroke - must be '[' */ { char *text; char *sscn; /* used to scan thru value of "sections" option */ long l; /* make sure second key was '[' */ if (key != '[') { return MARK_UNSET; } for (l = markline(m); l-- > 1; ) { text = fetchline(l); if (*text == '{') { break; } #ifndef NO_SENTENCE else if (*text == '.') { for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2) { if (sscn[0] == text[1] && sscn[1] == text[2]) { goto BreakBreak; } } } #endif } BreakBreak: if (l >= 1) { m = MARK_AT_LINE(l); } else { m = MARK_FIRST; } return m; } /*ARGSUSED*/ MARK m_match(m, cnt) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument (ignored) */ { long l; REG char *text; REG char match; REG char nest; REG int count; /* get the current line */ l = markline(m); pfetch(l); text = ptext + markidx(m); /* search forward within line for one of "[](){}" */ for (match = '\0'; !match && *text; text++) { /* tricky way to recognize 'em in ASCII */ nest = *text; if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[') { match = nest ^ ('[' ^ ']'); } else if ((nest & 0xfe) == '(') { match = nest ^ ('(' ^ ')'); } else { match = 0; } } if (!match) { return MARK_UNSET; } text--; /* search forward or backward for match */ if (match == '(' || match == '[' || match == '{') { /* search backward */ for (count = 1; count > 0; ) { /* wrap at beginning of line */ if (text == ptext) { do { if (l <= 1L) { return MARK_UNSET; } l--; pfetch(l); } while (!*ptext); text = ptext + plen - 1; } else { text--; } /* check the char */ if (*text == match) count--; else if (*text == nest) count++; } } else { /* search forward */ for (count = 1; count > 0; ) { /* wrap at end of line */ if (!*text) { if (l >= nlines) { return MARK_UNSET; } l++; pfetch(l); text = ptext; } else { text++; } /* check the char */ if (*text == match) count--; else if (*text == nest) count++; } } /* construct a mark for this place */ m = buildmark(text); return m; } /*ARGSUSED*/ MARK m_tomark(m, cnt, key) MARK m; /* movement is relative to this mark */ long cnt; /* (ignored) */ int key; /* keystroke - the mark to move to */ { /* mark '' is a special case */ if (key == '\'' || key == '`') { if (mark[26] == MARK_UNSET) { return MARK_FIRST; } else { return mark[26]; } } /* if not a valid mark number, don't move */ if (key < 'a' || key > 'z') { return MARK_UNSET; } /* return the selected mark -- may be MARK_UNSET */ if (!mark[key - 'a']) { msg("mark '%c is unset", key); } return mark[key - 'a']; } SHAR_EOF fi # end of overwriting check if test -f 'move2.c' then echo shar: will not over-write existing file "'move2.c'" else cat << \SHAR_EOF > 'move2.c' /* move2.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This function contains the movement functions that perform RE searching */ #include "config.h" #include "vi.h" #include "regexp.h" extern long atol(); static regexp *re; /* compiled version of the pattern to search for */ static prevsf; /* boolean: previous search direction was forward? */ MARK m_nsrch(m) MARK m; /* where to start searching */ { if (prevsf) { m = m_fsrch(m, (char *)0); prevsf = TRUE; } else { m = m_bsrch(m, (char *)0); prevsf = FALSE; } return m; } MARK m_Nsrch(m) MARK m; /* where to start searching */ { if (prevsf) { m = m_bsrch(m, (char *)0); prevsf = TRUE; } else { m = m_fsrch(m, (char *)0); prevsf = FALSE; } return m; } MARK m_fsrch(m, ptrn) MARK m; /* where to start searching */ char *ptrn; /* pattern to search for */ { long l; /* line# of line to be searched */ char *line; /* text of line to be searched */ int wrapped;/* boolean: has our search wrapped yet? */ int pos; /* where we are in the line */ long delta; /* line offset, for things like "/foo/+1" */ /* remember: "previous search was forward" */ prevsf = TRUE; delta = 0L; if (ptrn && *ptrn) { /* locate the closing '/', if any */ line = parseptrn(ptrn); if (*line) { delta = atol(line); } ptrn++; /* free the previous pattern */ if (re) free(re); /* compile the pattern */ re = regcomp(ptrn); if (!re) { return MARK_UNSET; } } else if (!re) { msg("No previous expression"); return MARK_UNSET; } /* search forward for the pattern */ pos = markidx(m) + 1; pfetch(markline(m)); if (pos >= plen) { pos = 0; m = (m | (BLKSIZE - 1)) + 1; } wrapped = FALSE; for (l = markline(m); l != markline(m) + 1 || !wrapped; l++) { /* wrap search */ if (l > nlines) { /* if we wrapped once already, then the search failed */ if (wrapped) { break; } /* else maybe we should wrap now? */ if (*o_wrapscan) { l = 0; wrapped = TRUE; continue; } else { break; } } /* get this line */ line = fetchline(l); /* check this line */ if (regexec(re, &line[pos], (pos == 0))) { /* match! */ if (wrapped && *o_warn) msg("(wrapped)"); if (delta != 0L) { l += delta; if (l < 1 || l > nlines) { msg("search offset too big"); return MARK_UNSET; } return m_front(MARK_AT_LINE(l), 0L); } return MARK_AT_LINE(l) + (int)(re->startp[0] - line); } pos = 0; } /* not found */ msg(*o_wrapscan ? "Not found" : "Hit bottom without finding RE"); return MARK_UNSET; } MARK m_bsrch(m, ptrn) MARK m; /* where to start searching */ char *ptrn; /* pattern to search for */ { long l; /* line# of line to be searched */ char *line; /* text of line to be searched */ int wrapped;/* boolean: has our search wrapped yet? */ int pos; /* last acceptable idx for a match on this line */ int last; /* remembered idx of the last acceptable match on this line */ int try; /* an idx at which we strat searching for another match */ /* remember: "previous search was not forward" */ prevsf = FALSE; if (ptrn && *ptrn) { /* locate the closing '?', if any */ line = parseptrn(ptrn); ptrn++; /* free the previous pattern, if any */ if (re) free(re); /* compile the pattern */ re = regcomp(ptrn); if (!re) { return MARK_UNSET; } } else if (!re) { msg("No previous expression"); return MARK_UNSET; } /* search backward for the pattern */ pos = markidx(m); wrapped = FALSE; for (l = markline(m); l != markline(m) - 1 || !wrapped; l--) { /* wrap search */ if (l < 1) { if (*o_wrapscan) { l = nlines + 1; wrapped = TRUE; continue; } else { break; } } /* get this line */ line = fetchline(l); /* check this line */ if (regexec(re, line, 1) && (int)(re->startp[0] - line) < pos) { /* match! now find the last acceptable one in this line */ do { last = (int)(re->startp[0] - line); try = (int)(re->endp[0] - line); } while (try > 0 && regexec(re, &line[try], FALSE) && (int)(re->startp[0] - line) < pos); if (wrapped && *o_warn) msg("(wrapped)"); return MARK_AT_LINE(l) + last; } pos = BLKSIZE; } /* not found */ msg(*o_wrapscan ? "Not found" : "Hit top without finding RE"); return MARK_UNSET; } SHAR_EOF fi # end of overwriting check if test -f 'move3.c' then echo shar: will not over-write existing file "'move3.c'" else cat << \SHAR_EOF > 'move3.c' /* move3.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains movement functions that perform character searches */ #include "config.h" #include "vi.h" #ifndef NO_CHARSEARCH static MARK (*prevfwdfn)(); /* function to search in same direction */ static MARK (*prevrevfn)(); /* function to search in opposite direction */ static char prev_key; /* sought cvhar from previous [fFtT] */ MARK m__ch(m, cnt, cmd) MARK m; /* current position */ long cnt; char cmd; /* command: either ',' or ';' */ { MARK (*tmp)(); if (!prevfwdfn) { msg("No previous f, F, t, or T command"); return MARK_UNSET; } if (cmd == ',') { m = (*prevrevfn)(m, cnt, prev_key); /* Oops! we didn't want to change the prev*fn vars! */ tmp = prevfwdfn; prevfwdfn = prevrevfn; prevrevfn = tmp; return m; } else { return (*prevfwdfn)(m, cnt, prev_key); } } /* move forward within this line to next occurrence of key */ MARK m_fch(m, cnt, key) MARK m; /* where to search from */ long cnt; char key; /* what to search for */ { REG char *text; DEFAULT(1); prevfwdfn = m_fch; prevrevfn = m_Fch; prev_key = key; pfetch(markline(m)); text = ptext + markidx(m); while (cnt-- > 0) { do { m++; text++; } while (*text && *text != key); } if (!*text) { return MARK_UNSET; } return m; } /* move backward within this line to previous occurrence of key */ MARK m_Fch(m, cnt, key) MARK m; /* where to search from */ long cnt; char key; /* what to search for */ { REG char *text; DEFAULT(1); prevfwdfn = m_Fch; prevrevfn = m_fch; prev_key = key; pfetch(markline(m)); text = ptext + markidx(m); while (cnt-- > 0) { do { m--; text--; } while (text >= ptext && *text != key); } if (text < ptext) { return MARK_UNSET; } return m; } /* move forward within this line almost to next occurrence of key */ MARK m_tch(m, cnt, key) MARK m; /* where to search from */ long cnt; char key; /* what to search for */ { /* skip the adjacent char */ pfetch(markline(m)); if (plen <= markidx(m)) { return MARK_UNSET; } m++; m = m_fch(m, cnt, key); if (m == MARK_UNSET) { return MARK_UNSET; } prevfwdfn = m_tch; prevrevfn = m_Tch; return m - 1; } /* move backward within this line almost to previous occurrence of key */ MARK m_Tch(m, cnt, key) MARK m; /* where to search from */ long cnt; char key; /* what to search for */ { /* skip the adjacent char */ if (markidx(m) == 0) { return MARK_UNSET; } m--; m = m_Fch(m, cnt, key); if (m == MARK_UNSET) { return MARK_UNSET; } prevfwdfn = m_Tch; prevrevfn = m_tch; return m + 1; } #endif SHAR_EOF fi # end of overwriting check if test -f 'move4.c' then echo shar: will not over-write existing file "'move4.c'" else cat << \SHAR_EOF > 'move4.c' /* move4.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains movement functions which are screen-relative */ #include "config.h" #include "vi.h" /* This moves the cursor to a particular row on the screen */ /*ARGSUSED*/ MARK m_row(m, cnt, key) MARK m; /* the cursor position */ long cnt; /* the row we'll move to */ int key; /* the keystroke of this move - H/L/M */ { DEFAULT(1); /* calculate destination line based on key */ cnt--; switch (key) { case 'H': cnt = topline + cnt; break; case 'M': cnt = topline + (LINES - 1) / 2; break; case 'L': cnt = botline - cnt; break; } /* return the mark of the destination line */ return MARK_AT_LINE(cnt); } /* This function repositions the current line to show on a given row */ /*ARGSUSED*/ MARK m_z(m, cnt, key) MARK m; /* the cursor */ long cnt; /* the line number we're repositioning */ int key; /* key struck after the z */ { long newtop; /* Which line are we talking about? */ if (cnt < 0 || cnt > nlines) { return MARK_UNSET; } if (cnt) { m = MARK_AT_LINE(cnt); newtop = cnt; } else { newtop = markline(m); } /* allow a "window size" number to be entered, but ignore it */ while (key >= '0' && key <= '9') { key = getkey(0); } /* figure out which line will have to be at the top of the screen */ switch (key) { case '\n': #if OSK case '\l': #else case '\r': #endif case '+': break; case '.': case 'z': newtop -= LINES / 2; break; case '-': newtop -= LINES - 1; break; default: return MARK_UNSET; } /* make the new topline take effect */ if (newtop >= 1) { topline = newtop; } else { topline = 1L; } mustredraw = TRUE; /* The cursor doesn't move */ return m; } /* This function scrolls the screen. It does this by calling redraw() with * an off-screen line as the argument. It will move the cursor if necessary * so that the cursor is on the new screen. */ /*ARGSUSED*/ MARK m_scroll(m, cnt, key) MARK m; /* the cursor position */ long cnt; /* for some keys: the number of lines to scroll */ int key; /* keystroke that causes this movement */ { MARK tmp; /* a temporary mark, used as arg to redraw() */ /* adjust cnt, and maybe *o_scroll, depending of key */ switch (key) { case ctrl('F'): case ctrl('B'): DEFAULT(1); mustredraw = TRUE; cnt = cnt * (LINES - 1) - 1; /* keeps one old line on screen */ break; case ctrl('E'): case ctrl('Y'): DEFAULT(1); break; case ctrl('U'): case ctrl('D'): if (cnt == 0) /* default */ { cnt = *o_scroll; } else { if (cnt > LINES - 1) { cnt = LINES - 1; } *o_scroll = cnt; } break; } /* scroll up or down, depending on key */ switch (key) { case ctrl('B'): case ctrl('Y'): case ctrl('U'): cnt = topline - cnt; if (cnt < 1L) { cnt = 1L; m = MARK_FIRST; } tmp = MARK_AT_LINE(cnt) + markidx(m); redraw(tmp, FALSE); if (markline(m) > botline) { m = MARK_AT_LINE(botline); } break; case ctrl('F'): case ctrl('E'): case ctrl('D'): cnt = botline + cnt; if (cnt > nlines) { cnt = nlines; m = MARK_LAST; } tmp = MARK_AT_LINE(cnt) + markidx(m); redraw(tmp, FALSE); if (markline(m) < topline) { m = MARK_AT_LINE(topline); } break; } /* arrange for ctrl-B and ctrl-F to redraw the smart line */ if (key == ctrl('B') || key == ctrl('F')) { changes++; /* also, erase the statusline. This happens naturally for * the scrolling commands, but the paging commands need to * explicitly clear the statusline. */ msg(""); } return m; } SHAR_EOF fi # end of overwriting check if test -f 'move5.c' then echo shar: will not over-write existing file "'move5.c'" else cat << \SHAR_EOF > 'move5.c' /* move5.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the word-oriented movement functions */ #include <ctype.h> #include "config.h" #include "vi.h" #ifndef isascii # define isascii(c) !((c) & ~0x7f) #endif MARK m_fword(m, cnt, cmd) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ int cmd; /* either 'w' or 'W' */ { REG long l; REG char *text; REG int i; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { i = *text++; if (cmd == 'W') { /* include any non-whitespace */ while (i && (!isascii(i) || !isspace(i))) { i = *text++; } } else if (!isascii(i) || isalnum(i) || i == '_') { /* include an alphanumeric word */ while (i && (!isascii(i) || isalnum(i) || i == '_')) { i = *text++; } } else { /* include contiguous punctuation */ while (i && isascii(i) && !isalnum(i) && !isspace(i)) { i = *text++; } } /* include trailing whitespace */ while (!i || isascii(i) && isspace(i)) { /* did we hit the end of this line? */ if (!i) { /* move to next line, if there is one */ l++; if (l > nlines) { return MARK_UNSET; } pfetch(l); text = ptext; } i = *text++; } text--; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK m_bword(m, cnt, cmd) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ int cmd; /* either 'b' or 'B' */ { REG long l; REG char *text; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { text--; /* include preceding whitespace */ while (text < ptext || isascii(*text) && isspace(*text)) { /* did we hit the end of this line? */ if (text < ptext) { /* move to preceding line, if there is one */ l--; if (l <= 0) { return MARK_UNSET; } pfetch(l); text = ptext + plen - 1; } else { text--; } } if (cmd == 'B') { /* include any non-whitespace */ while (text >= ptext && (!isascii(*text) || !isspace(*text))) { text--; } } else if (!isascii(*text) || isalnum(*text) || *text == '_') { /* include an alphanumeric word */ while (text >= ptext && (!isascii(*text) || isalnum(*text) || *text == '_')) { text--; } } else { /* include contiguous punctuation */ while (text >= ptext && isascii(*text) && !isalnum(*text) && !isspace(*text)) { text--; } } text++; } /* construct a MARK for this place */ m = buildmark(text); return m; } MARK m_eword(m, cnt, cmd) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ int cmd; /* either 'e' or 'E' */ { REG long l; REG char *text; REG int i; DEFAULT(1); l = markline(m); pfetch(l); text = ptext + markidx(m); while (cnt-- > 0) /* yes, ASSIGNMENT! */ { text++; i = *text++; /* include preceding whitespace */ while (!i || isascii(i) && isspace(i)) { /* did we hit the end of this line? */ if (!i) { /* move to next line, if there is one */ l++; if (l > nlines) { return MARK_UNSET; } pfetch(l); text = ptext; } i = *text++; } if (cmd == 'E') { /* include any non-whitespace */ while (i && (!isascii(i) || !isspace(i))) { i = *text++; } } else if (!isascii(i) || isalnum(i) || i == '_') { /* include an alphanumeric word */ while (i && (!isascii(i) || isalnum(i) || i == '_')) { i = *text++; } } else { /* include contiguous punctuation */ while (i && isascii(i) && !isalnum(i) && !isspace(i)) { i = *text++; } } text -= 2; } /* construct a MARK for this place */ m = buildmark(text); return m; } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # opts.c # osk.c # ow.c # ow_tcap.c # This archive created: Thu Jan 10 17:21:09 1991 export PATH; PATH=/bin:$PATH if test -f 'opts.c' then echo shar: will not over-write existing file "'opts.c'" else cat << \SHAR_EOF > 'opts.c' /* opts.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the code that manages the run-time options -- The * values that can be modified via the "set" command. */ #include "config.h" #include "vi.h" #ifndef NULL #define NULL (char *)0 #endif extern char *getenv(); /* maximum width to permit for strings, including ="" */ #define MAXWIDTH 20 /* These are the default values of all options */ char o_autoindent[1] = {FALSE}; char o_autoprint[1] = {TRUE}; char o_autowrite[1] = {FALSE}; #ifndef NO_ERRLIST char o_cc[30] = {CC_COMMAND}; #endif #ifndef NO_CHARATTR char o_charattr[1] = {FALSE}; #endif char o_columns[3] = {80, 32, 255}; #ifndef NO_DIGRAPH char o_digraph[1] = {FALSE}; #endif char o_directory[30] = TMPDIR; char o_edcompatible[1] = {FALSE}; char o_errorbells[1] = {TRUE}; char o_exrefresh[1] = {TRUE}; #ifndef NO_DIGRAPH char o_flipcase[80] # if CS_IBMPC = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"} # endif # if CS_LATIN1 /* initialized by initopts() */ # endif ; #endif #ifndef NO_SENTENCE char o_hideformat[1] = {FALSE}; #endif char o_ignorecase[1] = {FALSE}; #ifndef NO_EXTENSIONS char o_inputmode[1] = {FALSE}; #endif char o_keytime[3] = {2, 0, 5}; char o_keywordprg[80] = {KEYWORDPRG}; char o_lines[3] = {25, 2, 50}; /* More lines? Enlarge kbuf */ char o_list[1] = {FALSE}; #ifndef NO_MAGIC char o_magic[1] = {TRUE}; #endif #ifndef NO_ERRLIST char o_make[30] = {MAKE_COMMAND}; #endif #ifndef NO_MODELINE char o_modeline[1] = {FALSE}; #endif #ifndef NO_SENTENCE char o_paragraphs[30] = "PPppIPLPQP"; #endif #if MSDOS char o_pcbios[1] = {TRUE}; #endif char o_readonly[1] = {FALSE}; char o_report[3] = {5, 1, 127}; char o_scroll[3] = {12, 1, 127}; #ifndef NO_SENTENCE char o_sections[30] = "NHSHSSSEse"; #endif char o_shell[60] = SHELL; char o_shiftwidth[3] = {8, 1, 255}; #ifndef NO_SHOWMATCH char o_showmatch[1] = {FALSE}; #endif #ifndef NO_SHOWMODE char o_smd[1] = {FALSE}; #endif char o_sidescroll[3] = {8, 1, 40}; char o_sync[1] = {NEEDSYNC}; char o_tabstop[3] = {8, 1, 40}; char o_term[30] = "?"; char o_vbell[1] = {TRUE}; char o_warn[1] = {TRUE}; char o_wrapmargin[3] = {0, 0, 255}; char o_wrapscan[1] = {TRUE}; /* The following describes the names & types of all options */ #define BOOL 0 #define NUM 1 #define STR 2 #define SET 0x01 /* this option has had its value altered */ #define CANSET 0x02 /* this option can be set at any time */ #define RCSET 0x06 /* this option can be set in a .exrc file only */ #define MR 0x40 /* does this option affect the way text is displayed? */ struct { char *name; /* name of an option */ char *nm; /* short name of an option */ char type; /* type of an option */ char flags; /* boolean: has this option been set? */ char *value; /* value */ } opts[] = { /* name type flags redraw value */ { "autoindent", "ai", BOOL, CANSET , o_autoindent }, { "autoprint", "ap", BOOL, CANSET , o_autoprint }, { "autowrite", "aw", BOOL, CANSET , o_autowrite }, #ifndef NO_ERRLIST { "cc", "cc", STR, CANSET , o_cc }, #endif #ifndef NO_CHARATTR { "charattr", "ca", BOOL, CANSET | MR, o_charattr }, #endif { "columns", "co", NUM, SET , o_columns }, #ifndef NO_DIGRAPH { "digraph", "dig", BOOL, CANSET , o_digraph }, #endif { "directory", "dir", STR, RCSET , o_directory }, { "edcompatible","ed", BOOL, CANSET , o_edcompatible }, { "errorbells", "eb", BOOL, CANSET , o_errorbells }, { "exrefresh", "er", BOOL, CANSET , o_exrefresh }, #ifndef NO_DIGRAPH { "flipcase", "fc", STR, CANSET , o_flipcase }, #endif #ifndef NO_SENTENCE { "hideformat", "hf", BOOL, CANSET | MR, o_hideformat }, #endif { "ignorecase", "ic", BOOL, CANSET , o_ignorecase }, #ifndef NO_EXTENSIONS { "inputmode", "im", BOOL, CANSET , o_inputmode }, #endif { "keytime", "kt", NUM, CANSET , o_keytime }, { "keywordprg", "kp", STR, CANSET , o_keywordprg }, { "lines", "ls", NUM, SET , o_lines }, { "list", "li", BOOL, CANSET | MR, o_list }, #ifndef NO_MAGIC { "magic", "ma", BOOL, CANSET , o_magic }, #endif #ifndef NO_ERRLIST { "make", "mk", STR, CANSET , o_make }, #endif #ifndef NO_MODELINE { "modeline", "ml", BOOL, CANSET , o_modeline }, #endif #ifndef NO_SENTENCE { "paragraphs", "pa", STR, CANSET , o_paragraphs }, #endif #if MSDOS { "pcbios", "pc", BOOL, SET , o_pcbios }, #endif { "readonly", "ro", BOOL, CANSET , o_readonly }, { "report", "re", NUM, CANSET , o_report }, { "scroll", "sc", NUM, CANSET , o_scroll }, #ifndef NO_SENTENCE { "sections", "se", STR, CANSET , o_sections }, #endif { "shell", "sh", STR, CANSET , o_shell }, #ifndef NO_SHOWMATCH { "showmatch", "sm", BOOL, CANSET , o_showmatch }, #endif #ifndef NO_SHOWMODE { "showmode", "smd", BOOL, CANSET , o_smd }, #endif { "shiftwidth", "sw", NUM, CANSET , o_shiftwidth }, { "sidescroll", "ss", NUM, CANSET , o_sidescroll }, { "sync", "sy", BOOL, CANSET , o_sync }, { "tabstop", "ts", NUM, CANSET | MR, o_tabstop }, { "term", "te", STR, SET , o_term }, { "vbell", "vb", BOOL, CANSET , o_vbell }, { "warn", "wa", BOOL, CANSET , o_warn }, { "wrapmargin", "wm", NUM, CANSET , o_wrapmargin }, { "wrapscan", "ws", BOOL, CANSET , o_wrapscan }, { NULL, NULL, 0, CANSET, NULL } }; /* This function initializes certain options from environment variables, etc. */ void initopts() { char *val; int i; /* set some stuff from environment variables */ #if MSDOS if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */ #else if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */ #endif { strcpy(o_shell, val); } #if ANY_UNIX if (val = getenv("TERM")) /* yes, ASSIGNMENT! */ { strcpy(o_term, val); } #endif #if TOS val = "vt52"; strcpy(o_term, val); #endif #if MSDOS if ((val = getenv("TERM")) /* yes, ASSIGNMENT! */ && strcmp(val, "pcbios")) { strcpy(o_term, val); o_pcbios[0] = 0; } else { strcpy(o_term, "pcbios"); o_pcbios[0] = 1; } #endif #if MSDOS || TOS if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */ || (val = getenv("TEMP"))) strcpy(o_directory, val); #endif *o_scroll = LINES / 2 - 1; /* disable the vbell option if we don't know how to do a vbell */ if (!has_VB) { for (i = 0; opts[i].value != o_vbell; i++) { } opts[i].flags &= ~CANSET; *o_vbell = FALSE; } #ifndef NO_DIGRAPH # ifdef CS_LATIN1 for (i = 0, val = o_flipcase; i < 32; i++) { /* leave out the multiply/divide symbols */ if (i == 23) continue; /* add upper/lowercase pair */ *val++ = i + 0xc0; *val++ = i + 0xe0; } *val = '\0'; # endif /* CS_LATIN1 */ #endif /* not NO_DIGRAPH */ } /* This function lists the current values of all options */ void dumpopts(all) int all; /* boolean: dump all options, or just set ones? */ { #ifndef NO_OPTCOLS int i, j, k; char nbuf[4]; /* used for converting numbers to ASCII */ int widths[5]; /* width of each column, including gap */ int ncols; /* number of columns */ int nrows; /* number of options per column */ int nset; /* number of options to be output */ int width; /* width of a particular option */ int todump[50]; /* indicies of options to be dumped */ /* step 1: count the number of set options */ for (nset = i = 0; opts[i].name; i++) { if (all || (opts[i].flags & SET)) { todump[nset++] = i; } } /* step two: try to use as many columns as possible */ for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--) { /* how many would go in this column? */ nrows = (nset + ncols - 1) / ncols; /* figure out the width of each column */ for (i = 0; i < ncols; i++) { widths[i] = 0; for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++) { /* figure out the width of a particular option */ switch (opts[todump[k]].type) { case BOOL: if (!*opts[todump[k]].value) width = 2; else width = 0; break; case STR: width = 3 + strlen(opts[todump[k]].value); if (width > MAXWIDTH) width = MAXWIDTH; break; case NUM: width = 4; break; } width += strlen(opts[todump[k]].name); /* if this is the widest so far, widen col */ if (width > widths[i]) { widths[i] = width; } } } /* if the total width is narrow enough, then use it */ for (width = -2, i = 0; i < ncols; i++) { width += widths[i] + 2; } if (width < COLS - 1) { break; } } /* step 3: output the columns */ nrows = (nset + ncols - 1) / ncols; for (i = 0; i < nrows; i++) { for (j = 0; j < ncols; j++) { /* if we hit the end of the options, quit */ k = i + j * nrows; if (k >= nset) { break; } /* output this option's value */ width = 0; switch (opts[todump[k]].type) { case BOOL: if (!*opts[todump[k]].value) { qaddch('n'); qaddch('o'); width = 2; } qaddstr(opts[todump[k]].name); width += strlen(opts[todump[k]].name); break; case NUM: sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value)); qaddstr(opts[todump[k]].name); qaddch('='); qaddstr(nbuf); width = 4 + strlen(opts[todump[k]].name); break; case STR: qaddstr(opts[todump[k]].name); qaddch('='); qaddch('"'); strcpy(tmpblk.c, opts[todump[k]].value); width = 3 + strlen(tmpblk.c); if (width > MAXWIDTH) { width = MAXWIDTH; strcpy(tmpblk.c + MAXWIDTH - 6, "..."); } qaddstr(tmpblk.c); qaddch('"'); width += strlen(opts[todump[k]].name); break; } /* pad the field to the correct size */ if (k + nrows <= nset) { while (width < widths[j] + 2) { qaddch(' '); width++; } } } addch('\n'); exrefresh(); } #else int i; int col; char nbuf[4]; for (i = col = 0; opts[i].name; i++) { /* if not set and not all, ignore this option */ if (!all && !(opts[i].flags & SET)) { continue; } /* align this option in one of the columns */ if (col > 52) { addch('\n'); col = 0; } else if (col > 26) { while (col < 52) { qaddch(' '); col++; } } else if (col > 0) { while (col < 26) { qaddch(' '); col++; } } switch (opts[i].type) { case BOOL: if (!*opts[i].value) { qaddch('n'); qaddch('o'); col += 2; } qaddstr(opts[i].name); col += strlen(opts[i].name); break; case NUM: sprintf(nbuf, "%-3d", UCHAR(*opts[i].value)); qaddstr(opts[i].name); qaddch('='); qaddstr(nbuf); col += 4 + strlen(opts[i].name); break; case STR: qaddstr(opts[i].name); qaddch('='); qaddch('"'); qaddstr(opts[i].value); qaddch('"'); col += 3 + strlen(opts[i].name) + strlen(opts[i].value); break; } exrefresh(); } if (col > 0) { addch('\n'); exrefresh(); } #endif } #ifndef NO_MKEXRC /* This function saves the current configuarion of options to a file */ void saveopts(fd) int fd; /* file descriptor to write to */ { int i; char buf[256], *pos; /* write each set options */ for (i = 0; opts[i].name; i++) { /* if unset or unsettable, ignore this option */ if (!(opts[i].flags & SET) || !(opts[i].flags & CANSET)) { continue; } strcpy(buf, "set "); pos = &buf[4]; switch (opts[i].type) { case BOOL: if (!*opts[i].value) { *pos++='n'; *pos++='o'; } strcpy(pos, opts[i].name); strcat(pos, "\n"); break; case NUM: sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff); break; case STR: sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value); break; } twrite(fd, buf, strlen(buf)); } } #endif /* This function changes the values of one or more options. */ void setopts(assignments) char *assignments; /* a string containing option assignments */ { char *name; /* name of variable in assignments */ char *value; /* value of the variable */ char *scan; /* used for moving through strings */ int i, j; /* for each assignment... */ for (name = assignments; *name; ) { /* skip whitespace */ if (*name == ' ' || *name == '\t') { name++; continue; } /* find the value, if any */ for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++) { } if (*scan == '=') { *scan++ = '\0'; if (*scan == '"') { value = ++scan; while (*scan && *scan != '"') { scan++; } if (*scan) { *scan++ = '\0'; } } else { value = scan; while (*scan && *scan != ' ' && *scan != '\t') { scan++; } if (*scan) { *scan++ = '\0'; } } } else { if (*scan) { *scan++ = '\0'; } value = NULL; if (name[0] == 'n' && name[1] == 'o') { name += 2; } } /* find the variable */ for (i = 0; opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name); i++) { } /* change the variable */ if (!opts[i].name) { msg("invalid option name \"%s\"", name); } else if ((opts[i].flags & CANSET) != CANSET) { msg("option \"%s\" can't be altered", name); } else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L) { msg("option \"%s\" can only be set in a %s file", name, EXRC); } else if (value) { switch (opts[i].type) { case BOOL: msg("option \"[no]%s\" is boolean", name); break; case NUM: j = atoi(value); if (j == 0 && *value != '0') { msg("option \"%s\" must have a numeric value", name); } else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff)) { msg("option \"%s\" must have a value between %d and %d", name, opts[i].value[1], opts[i].value[2] & 0xff); } else { *opts[i].value = atoi(value); opts[i].flags |= SET; } break; case STR: strcpy(opts[i].value, value); opts[i].flags |= SET; break; } if (opts[i].flags & MR) { mustredraw = TRUE; } } else /* valid option, no value */ { if (opts[i].type == BOOL) { *opts[i].value = (name[-1] != 'o'); opts[i].flags |= SET; if (opts[i].flags & MR) { mustredraw = TRUE; } } else { msg("option \"%s\" must be given a value", name); } } /* move on to the next option */ name = scan; } /* special processing ... */ /* if "readonly" then set the READONLY flag for this file */ if (*o_readonly) { setflag(file, READONLY); } } SHAR_EOF fi # end of overwriting check if test -f 'osk.c' then echo shar: will not over-write existing file "'osk.c'" else cat << \SHAR_EOF > 'osk.c' /* osk.c */ /* ------------------------------------------------------------------- * | | OS9Lib: stat(), fstat() | | | Copyright (c) 1988 by Wolfgang Ocker, Puchheim, | Ulli Dessauer, Germering and | Reimer Mellin, Muenchen | (W-Germany) | | This programm can be copied and distributed freely for any | non-commercial purposes. It can only be incorporated into | commercial software with the written permission of the authors. | | If you should modify this program, the authors would appreciate | a notice about the changes. Please send a (context) diff or the | complete source to: | | address: Wolfgang Ocker | Lochhauserstrasse 35a | D-8039 Puchheim | West Germany | | e-mail: weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP | pyramid!tmpmbx!recco!weo | pyramid!tmpmbx!nitmar!ud | pyramid!tmpmbx!ramsys!ram | * ----------------------------------------------------------------- */ #ifdef OSK #define PATCHLEVEL 1 #ifndef VIREC #include <stdio.h> #include "osk.h" #include <modes.h> #include <errno.h> #endif #include <signal.h> #include <sgstat.h> #include <sg_codes.h> #include <direct.h> /* * f s t a t */ int fstat(fd, buff) int fd; struct stat *buff; { struct fildes ftmp; struct tm ttmp; struct _sgr fopt; if (_gs_gfd(fd, &ftmp, 16) < 0) /* 16 insteat of sizeof(struct fildes) */ return(-1); /* used due to a bug in stupid os9net */ if (_gs_opt(fd, &fopt) < 0) return(-1); ttmp.tm_year = (int) ftmp.fd_date[0]; ttmp.tm_mon = (int) ftmp.fd_date[1] - 1; ttmp.tm_mday = (int) ftmp.fd_date[2]; ttmp.tm_hour = (int) ftmp.fd_date[3]; ttmp.tm_min = (int) ftmp.fd_date[4]; ttmp.tm_sec = 0; ttmp.tm_isdst = -1; buff->st_atime = buff->st_mtime = mktime(&ttmp); ttmp.tm_year = (int) ftmp.fd_dcr[0]; ttmp.tm_mon = (int) ftmp.fd_dcr[1] - 1; ttmp.tm_mday = (int) ftmp.fd_dcr[2]; ttmp.tm_hour = ttmp.tm_min = ttmp.tm_sec = 0; ttmp.tm_isdst = -1; buff->st_ctime = mktime(&ttmp); memcpy(&(buff->st_size), ftmp.fd_fsize, sizeof(long)); /* misalignment! */ buff->st_uid = ftmp.fd_own[1]; buff->st_gid = ftmp.fd_own[0]; buff->st_mode = ftmp.fd_att; buff->st_nlink = ftmp.fd_link; buff->st_ino = fopt._sgr_fdpsn; buff->st_dev = fopt._sgr_dvt; return(0); } /* * s t a t */ int stat(filename, buff) char *filename; struct stat *buff; { register int i, ret; if ((i = open(filename, S_IREAD)) < 0) if ((i = open(filename, S_IFDIR | S_IREAD)) < 0) return(-1); ret = fstat(i, buff); close(i); return(ret); } /* unix library functions mist in OSK Author: Peter Reinig */ /* NOTE: this version of link() is only capable of renaming files, not true * UNIX-style linking. That's okay, though, because elvis only uses it for * renaming. */ link(from,to) char *from,*to; { char *buffer; int status; char *malloc(); if ((buffer = malloc(strlen(from) + strlen(to) + 12)) == NULL) return -1; sprintf(buffer,"rename %s %s\n",from,to); status = system(buffer); free(buffer); return status; } typedef (*procref)(); #define MAX_SIGNAL 10 extern exit(); static int (*sig_table[MAX_SIGNAL])(); static int _sig_install = 0; sig_handler(sig) int sig; { if ((int) sig_table[sig] > MAX_SIGNAL) sig_table[sig](sig); } procref signal(sig,func) int sig; int (*func)(); { int i, (*sav)(); if (!_sig_install) { for (i=0; i < MAX_SIGNAL; i++) sig_table[i] = exit; _sig_install = 1; intercept(sig_handler); } sav = sig_table[sig]; switch ((int) func) { case SIG_DFL : sig_table[sig] = exit; break; case SIG_IGN : sig_table[sig] = 0; break; default : sig_table[sig] = func; break; } return sav; } perror(str) char *str; { static int path = 0; if (!path && (path = open("/dd/sys/Errmsg", S_IREAD)) == -1) { fprintf(stderr,"Can\'t open error message file\n"); path = 0; } if (str && *str) { fprintf(stderr,"%s: ",str); fflush(stderr); } prerr(path,(short) errno); } isatty(fd) int fd; { struct sgbuf buffer; char type; _gs_opt(fd,&buffer); type = buffer.sg_class; if (type == DT_SCF) return 1; else return 0; } #endif /* OSK */ SHAR_EOF fi # end of overwriting check if test -f 'ow.c' then echo shar: will not over-write existing file "'ow.c'" else cat << \SHAR_EOF > 'ow.c' #if OPENWINDOWS #include <stdio.h> #include <sys/time.h> #include <signal.h> #include <assert.h> #include "config.h" #include "vi.h" #include "curses.h" #include "elvis_cps.h" #define PS_ESC '\200' #define TTY 1 /* conditional for compiling in dumb tty support */ #ifndef RUNFILE #define RUNFILE "/usr/local/lib/elvis.ps" /* server side PostScript code */ #endif /* openwindows related elvis stuff */ /* author: mike hoegeman , mh@wlv.imsd.contel.com*/ struct ow_data Ow; int ElvisDestroyTag; extern void destroyProc(); int ElvisKeyTag; extern void keyProc(); int ElvisMiscTag; extern void miscProc(); int ElvisResizeTag; extern void resizeProc(); int ElvisDamageTag; extern void damageProc(); int *NewsTags[] = { &ElvisDestroyTag, &ElvisKeyTag, &ElvisMiscTag, &ElvisResizeTag, &ElvisDamageTag, (int *) 0 }; void destroyProc(tag, data) int tag; caddr_t *data; { ow_beep(); wire_ReadTag(); return; } void damageProc(tag, data) int tag; caddr_t *data; { int i; if (tag >= 0) i = wire_ReadTag(); redraw(MARK_UNSET, FALSE); redraw(cursor, 1); refresh(); return; } void resizeProc(tag, data) int tag; caddr_t *data; { int i; i = wire_ReadTag(); LINES = Ow.wLINES = wire_ReadInt(); COLS = Ow.wCOLS = wire_ReadInt(); return; } void keyProc(tag, data) int tag; caddr_t *data; { int t; t = wire_ReadTag(); Ow.keyFromNews = wire_ReadInt(); wire_ExitNotifier(); return; } int ow_tmpstart(fname) char *fname; { int x; x = tmpstart(fname); if (!Ow.tty) { ps_set_title(*fname == '\0' ? "Elvis" : fname); ps_flush_PostScript(); } return x; } int ow_beep() { #ifdef TTY if (Ow.tty) { beep(); return 0; } # endif ps_beep(); return 0; } int ow_rendermsg(msgtxt) char *msgtxt; { #ifdef TTY if (Ow.tty) return(rendermsg(msgtxt)); #endif ps_rendermsg(msgtxt); return 0; } int ow_appendmsg(old, new) char *old, *new; { /* we could get 'old' from the window but since it's handy here on the c side we might as well use it */ #ifdef TTY if (Ow.tty) return(appendmsg(old, new)); #endif ps_appendmsg(old, new); return 0; } #define DBG #ifdef DBG static int SHOW_OUTPUT = -1; sh(o, s, l, c) int o; char *s; int l, c; { putchar(o); while (l > 0) { putchar(*s++); l--; } putchar(c); return (0); } #define Print if (SHOW_OUTPUT) printf #define SH if (SHOW_OUTPUT) sh #else #define Print #define SH #endif int ttywrite(buf, len) register char *buf; register int len; { #define binc() buf++,len-- #define flushstr() {\ if (string) {\ SH('(', string, buf-string, ')');\ ps_ST(string, buf-string);\ string = (char *)0;\ }\ } #ifdef DBG if (SHOW_OUTPUT < 0) { extern char *getenv(); SHOW_OUTPUT = (getenv("SHOW_OUTPUT") == (char *) 0) ? 0 : 1; } #endif /* this is where we bury all the smarts for display */ if (!Ow.tty) { #define Return(x) {\ if (cursor_disabled)\ {\ ps_enable_cursor();\ Print("{{true /EC C S }}\n");\ }\ ps_flush_PostScript();\ Print("------------------------------------------\n");\ return(x);\ } #define ErrReturn(x) {\ msg("Garbled output, is this a binary file?");\ Print("Garbled output, is this a binary file?");\ Return(x);\ } char *string = (char *) 0; int rval = len; int cursor_disabled = 0; wire_SetCurrent(Ow.mainWire); /* if we have a fair chunk of stuff in our buffer, then just turn off the cursor completely till we are all done then turn it back on at the end. The turning on is done in 'Return' */ if (len > 30) { cursor_disabled++; Print("{{false /EC C S }}\n"); ps_disable_cursor(); } while (len > 0) { switch (*buf) { case PS_ESC: flushstr(); { register char *p; binc(); p = buf; while (*buf != PS_ESC) { if (!*buf) ErrReturn(rval); binc(); } ps_pswrite(p, buf - p); Print("\n"); SH('{', p, buf - p, '}'); Print("\n"); } binc(); break; default: switch (*buf) { case '\r': flushstr(); if (*(buf + 1) == '\n') { Print("<crnl>\n"); ps_CrNl(); binc(); } else { Print("<cr>"); ps_Cr(); } break; case '\n': flushstr(); if (*(buf + 1) == '\r') { Print("<crnl>\n"); ps_CrNl(); binc(); } else { Print("<nl>\n"); ps_Nl(); } break; /* move up one line */ case '\0': /* some binary file ?? , punt */ ErrReturn(rval); default: if (!string) string = buf; break; } binc(); break; } } flushstr(); Return(rval); #undef Return #undef ErrReturn } #ifdef TTY return (write(1, buf, len)); #else return -1; #endif } int ttyread(buf, len) char *buf; int len; { int rlen = 0; #ifdef TTY if (Ow.tty) return read(0, buf, len); #endif Ow.keyFromNews = -1; wire_EnterNotifier(); if (Ow.keyFromNews < 0) return -1; else { *buf++ = Ow.keyFromNews; rlen++; } return rlen; } void miscProc(tag, data) int tag; caddr_t *data; { return; } ow_vi() { extern char *getenv(); if (Ow.tty) { vi(); return 0; } if (getenv("ELVIS_DEBUG") == (char *) 0 && Ow.background) background(); vi(); return; } ow_ex() { ex(); return 0; } int ow_suspend_curses() { #ifdef TTY if (Ow.tty) { suspend_curses(); return 0; } #endif #ifndef NO_CURSORSHAPE if (has_CQ) { do_CQ(); } #endif return 0; } int ow_resume_curses(quietly) int quietly; { /* If we're supposed to quit quietly, then we're done */ void (*proc) (); # ifdef TTY if (Ow.tty) { resume_curses(quietly); return 0; } # endif if (quietly) return; proc = signal(SIGINT, SIG_IGN); { move(LINES - 1, 0); do_SO(); qaddstr("[Press <RETURN> to continue]"); do_SE(); refresh(); ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */ if (kbuf[0] == ':') { mode = MODE_COLON; addch('\n'); refresh(); } else { mode = MODE_VI; redraw(MARK_UNSET, FALSE); } exwrote = FALSE; } signal(SIGINT, proc); return 0; } #define register_tag(tag_name, tag_value, tag_proc, proc_data)\ wire_RegisterTag(tag_value, tag_proc, proc_data);\ ps_RegisterTag(tag_name, tag_value); int ow_initscr() { extern char *getenv(); extern void starttcap(); char *server; #ifdef TTY if (Ow.tty) { initscr(); return 0; } #endif if (!(server = getenv("NEWSSERVER"))) { server = getenv("DISPLAY"); if (!server || !strncmp(server, "unix", strlen("unix")) || !strncmp(server, "unix", strlen("UNIX"))) server = "localhost"; } Ow.mainWire = wire_Open(server); if (Ow.mainWire == wire_INVALID_WIRE) { /* wire_Perror("elvis"); */ Ow.tty = 1; initscr(); return 0; } else { static int firstime = 1; if (firstime) { wire_ReserveTags(100); wire_AllocateNamedTags(NewsTags); register_tag("ElvisDestroyTag", ElvisDestroyTag, destroyProc, NULL); register_tag("ElvisKeyTag", ElvisKeyTag, keyProc, NULL); register_tag("ElvisMiscTag", ElvisMiscTag, miscProc, NULL); register_tag("ElvisResizeTag", ElvisResizeTag, resizeProc, NULL); register_tag("ElvisDamageTag", ElvisDamageTag, damageProc, NULL); wire_SetCurrent(Ow.mainWire); ps_RunFile(RUNFILE); ps_flush_PostScript(); } else firstime = !firstime; stdscr = kbuf; starttcap(); return 0; } } int ow_getsize(sig) int sig; { extern char o_columns[], o_lines[]; #ifdef TTY if (Ow.tty) return getsize(sig); #endif /* copy the new values into Elvis' options */ *o_columns = COLS = Ow.wCOLS; *o_lines = LINES = Ow.wLINES; return 0; } /* termcap */ /*ARGSUSED*/ int ow_tgetent(bp, name) char *bp; /* buffer for entry */ char *name; /* name of the entry */ { #ifdef TTY if (Ow.tty) return(tgetent(bp,name)); #endif *bp = '\0'; return 1; } #define CAP(str) CAP2((str)[0], (str)[1]) #define CAP2(a,b) (((a) << 8) + ((b) & 0xff)) int ow_tgetnum(id) char *id; { #ifdef TTY if (Ow.tty) return(tgetnum(id)); #endif switch (CAP(id)) { /* # lines of lines on screen or page */ case CAP2('l', 'i'): return 44; /* # of columns in a line */ case CAP2('c', 'o'): return 80; /* # of garbage chars left by so or se */ case CAP2('s', 'g'): return 0; /* # of garbage chars left by us or ue */ case CAP2('u', 'g'): return 0; default: return -1; } } int ow_tgetflag(id) char *id; { #ifdef TTY if (Ow.tty) return(tgetflag(id)); #endif switch (CAP(id)) { /* terminal has **no** automatic margins */ case CAP2('a', 'm'): return 0; /* terminal has backspace capability */ case CAP2('b', 's'): return 1; /* safe to move while in insert mode */ case CAP2('m', 'i'): return 1; default: return 0; } } #define VAL2(v,a) (a) #define VAL3(a,b,c) (a) char * ow_tgetstr(id, bp) char *id; char **bp; /* pointer to pointer to buffer - ignored */ { #ifdef TTY extern char *tgetstr(); if (Ow.tty) return(tgetstr(id,bp)); #endif /* send method id to 'C', 'S' is a shorthand for 'send' */ #define RETURN(FIRSTLETTER,SECONDLETTER) {\ static char tp[] = {\ PS_ESC,\ '/', FIRSTLETTER, SECONDLETTER, ' ',\ 'C',' ','S',' ',\ PS_ESC\ };\ return tp;\ } switch (CAP(id)) { /* clear to end of line */ case CAP2('c', 'e'): RETURN('c', 'e'); /* clear to end of screen and home cursor */ case CAP2('c', 'l'): RETURN('c', 'l'); /* scroll text down */ case CAP2('s', 'r'): RETURN('s', 'r'); /* cursor invisible */ case CAP2('v', 'i'): RETURN('v', 'i'); /* cursor visible */ case CAP2('v', 'e'): RETURN('v', 'e'); /*- case CAP2('a', 'l'): RETURN('a', 'l'); case CAP2('d', 'l'): RETURN('d', 'l'); */ /* start bold */ case CAP2('s', 'o'): RETURN('s', 'o'); /* end bold */ case CAP2('s', 'e'): RETURN('s', 'e'); /* start underline */ case CAP2('u', 's'): RETURN('u', 's'); /* end underline */ case CAP2('u', 'e'): RETURN('u', 'e'); /* ------ cursor style change commands --------*/ /* change to normal cursor */ case CAP2('c', 'Q'): RETURN('c', 'Q'); /* change to ex command entry cursor */ case CAP2('c', 'X'): RETURN('c', 'X'); /* change to vi command mode cursor */ case CAP2('c', 'V'): RETURN('c', 'V'); /* change to vi input mode cursor */ case CAP2('c', 'I'): RETURN('c', 'I'); /* change to vi replace mode cursor */ case CAP2('c', 'R'): RETURN('c', 'R'); #if 0 case CAP2('V', 'B'): RETURN('V', 'B'); case CAP2('V', 'b'): RETURN('V', 'b'); case CAP2('d', 'o'): RETURN('d', 'o'); case CAP2('n', 'd'): RETURN('n', 'd'); case CAP2('t', 'i'): RETURN('t', 'i'); case CAP2('t', 'e'): return ""; case CAP2('k', 'u'): return "#H"; case CAP2('k', 'd'): return "#P"; case CAP2('k', 'l'): return "#K"; case CAP2('k', 'r'): return "#M"; case CAP2('H', 'M'): return "#G"; case CAP2('E', 'N'): return "#O"; case CAP2('P', 'U'): return "#I"; case CAP2('P', 'D'): #endif /* move up one line */ case CAP2('u', 'p'): RETURN('u', 'p'); /* backspace */ case CAP2('b', 'c'): RETURN('b', 'c'); /* cursor motion */ case CAP2('c', 'm'): { static char *tp = "\200%d %d /cm C S \200"; return tp; } default: return (char *) 0; } } /*ARGSUSED*/ char * ow_tgoto(cm, destcol, destrow) char *cm; /* cursor movement string -- ignored */ int destcol; /* destination column, 0 - 79 */ int destrow; /* destination row, 0 - 24 */ { static char buf[30]; #ifdef TTY extern char *tgoto(); if (Ow.tty) return (tgoto(cm, destcol, destrow)); #endif sprintf(buf, "\200%d %d /cm C S \200", destcol, destrow); return buf; } /* declaring cp a register makes gcc blow up ?? ! ?? */ void ow_tputs(cp, affcnt, outfn) char *cp; int affcnt; /* number of affected lines -- ignored */ int (*outfn) (); /* the output function */ { #ifdef TTY if (Ow.tty) { tputs(cp,affcnt,outfn); return; }; #endif while (*cp != '\0') { (*outfn)(*cp); cp++; } return; } int ow_scrolldown(l, y, x) long l; int y, x; { extern void drawtext(); REG char *text; char buf[80]; #ifdef TTY if (Ow.tty) return(scrolldown(l, y, x)); #endif /*- do ... - a move(y, x) - topline-l do_SR()'s - a move(topline-l-1, 0); */ sprintf( buf, "\200 %d %d /cm C S %d /SR C S %d %d /cm C S \200", y, x, (topline-l), (topline-1)-1, 0 ); qaddstr(buf); move((topline - l) - 1, 0); while (l < topline) { topline--; text = fetchline(topline); drawtext(text, FALSE); do_UP(); do_UP(); } move(LINES - 1, 0); clrtoeol(); return 0; } int ow_scrollup(l, y, x) long l; int y,x; { REG char *text; char buf[80]; #ifdef TTY if (Ow.tty) return(scrollup(l, y, x)); #endif move(y,x); clrtoeol(); sprintf(buf, "\200 %d /RSR C S \200", l-(botline)); qaddstr(buf); move(y - (l-botline), 0); while (l > botline) { topline++; /* <-- also adjusts botline */ text = fetchline(botline); drawtext(text, FALSE); } return 0; } /*+ X11/NeWS specific flags: -tty Force elvis to use the plain termcap interface and not the window interface. elvis will revert to the termcap interface automatically if it cannot connect to the X11/NeWS server. -bkg Have elvis run in the background, disassociated from the parent process. If "elvis" is the name of this program this is the default. +bkg Force elvis to run in the forground process. If the name of the program is not elvis ("vi" for example). then this is the default. -*/ int ow_customflags(argv, argc_p) char *argv[]; int *argc_p; { int x, e; # if MALLOC_DEBUG malloc_debug(MALLOC_DEBUG); # endif # define eq(a,b) (!strcmp(a,b)) # define skip() x++ # define shift() \ {\ int i;\ for (e = *argc_p, i=x; i<e; i++)\ argv[i] = argv[i+1];\ (*argc_p)--;\ } ow_data_init(&Ow); # ifndef NO_AUTO_BACKGROUND { extern char *strrchr(); char *p = strchr(argv[0], '/'); p = p ? p : argv[0]; if (eq(argv[0], "elvis")) Ow.background = 1; } # endif for(x=1; x<*argc_p;) { if (*argv[x] != '-' && *argv[x] != '+') skip(); else { if (eq(argv[x], "-bkg")) { Ow.background = 1; shift(); } else if (eq(argv[x], "+bkg")) { Ow.background = 0; shift(); } else if (eq(argv[x], "-tty")) { Ow.tty = 1; shift(); } else { skip(); } } } return 0; # undef eq # undef skip # undef shift } #endif #if BSD #include <sys/file.h> #include <sgtty.h> int background() { int fd, p; p = fork(); switch (p) { case -1: perror("fork"); exit(1); default: exit(0); case 0: break; } (void) setpgrp(0, getpid()); if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, 0); close(fd); } return 0; } #endif SHAR_EOF fi # end of overwriting check if test -f 'ow_tcap.c' then echo shar: will not over-write existing file "'ow_tcap.c'" else cat << \SHAR_EOF > 'ow_tcap.c' #include <varargs.h> #include "curses.h" /* implemenatation of the wprintw curses function */ void ow_printw(va_alist) va_dcl { char *fmt; WINDOW *win; va_list args; char tmpbuf[512]; va_start(args); win = va_arg(args, char *); fmt = va_arg(args, char *); vsprintf(tmpbuf, fmt, args); va_end(args); waddstr(win, tmpbuf); return; } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # pc.c # recycle.c # redraw.c # ref.c # refont.c # regexp.c # regsub.c # This archive created: Thu Jan 10 17:21:09 1991 export PATH; PATH=/bin:$PATH if test -f 'pc.c' then echo shar: will not over-write existing file "'pc.c'" else cat << \SHAR_EOF > 'pc.c' /* pc.c */ /* Author: * Guntram Blohm * Buchenstrasse 19 * 7904 Erbach, West Germany * Tel. ++49-7305-6997 * sorry - no regular network connection */ /* This file implements the ibm pc bios interface. See IBM documentation * for details. * If TERM is set upon invocation of elvis, this code is ignored completely, * and the standard termcap functions are used, thus, even not-so-close * compatibles can run elvis. For close compatibles however, bios output * is much faster (and permits reverse scrolling, adding and deleting lines, * and much more ansi.sys isn't capable of). GB. */ #include "config.h" #include "vi.h" #if MSDOS #include <dos.h> static void video(); /* vmode contains the screen attribute index and is set by attrset.*/ int vmode; /* The following array contains attribute definitions for * color/monochrome attributes. Screen selects one of the sets. * Maybe i'll put them into elvis options one day. */ static int screen; static char attr[2][5] = { /* :se: :so: :VB: :ul: :as: */ { 0x1f, 0x1d, 0x1e, 0x1a, 0x1c, }, /* color */ { 0x07, 0x70, 0x0f, 0x01, 0x0f, }, /* monochrome */ }; /* * bios interface functions for elvis - pc version */ /* cursor up: determine current position, decrement row, set position */ void v_up() { int dx; video(0x300,(int *)0,&dx); dx-=0x100; video(0x200,(int *)0,&dx); } #ifndef NO_CURSORSHAPE /* cursor big: set begin scan to end scan - 4 */ void v_cb() { int cx; video(0x300, &cx, (int *)0); cx=((cx&0xff)|(((cx&0xff)-4)<<8)); video(0x100, &cx, (int *)0); } /* cursor small: set begin scan to end scan - 1 */ void v_cs() { int cx; video(0x300, &cx, (int *)0); cx=((cx&0xff)|(((cx&0xff)-1)<<8)); video(0x100, &cx, (int *)0); } #endif /* clear to end: get cursor position and emit the aproppriate number * of spaces, without moving cursor. */ void v_ce() { int cx, dx; video(0x300,(int *)0,&dx); cx=COLS-(dx&0xff); video(0x920,&cx,(int *)0); } /* clear screen: clear all and set cursor home */ void v_cl() { int cx=0, dx=((LINES-1)<<8)+COLS-1; video(0x0600,&cx,&dx); dx=0; video(0x0200,&cx,&dx); } /* clear to bottom: get position, clear to eol, clear next line to end */ void v_cd() { int cx, dx, dxtmp; video(0x0300,(int *)0,&dx); dxtmp=(dx&0xff00)|(COLS-1); cx=dx; video(0x0600,&cx,&dxtmp); cx=(dx&0xff00)+0x100; dx=((LINES-1)<<8)+COLS-1; video(0x600,&cx,&dx); } /* add line: scroll rest of screen down */ void v_al() { int cx,dx; video(0x0300,(int *)0,&dx); cx=(dx&0xff00); dx=((LINES-1)<<8)+COLS-1; video(0x701,&cx,&dx); } /* delete line: scroll rest up */ void v_dl() { int cx,dx; video(0x0300,(int *)0,&dx); cx=(dx&0xff00)/*+0x100*/; dx=((LINES-1)<<8)+COLS-1; video(0x601,&cx,&dx); } /* scroll reverse: scroll whole screen */ void v_sr() { int cx=0, dx=((LINES-1)<<8)+COLS-1; video(0x0701,&cx,&dx); } /* set cursor */ void v_move(x,y) int x, y; { int dx=(y<<8)+x; video(0x200,(int *)0,&dx); } /* put character: set attribute first, then execute char. * Also remember if current line has changed. */ int v_put(ch) int ch; { int cx=1; ch&=0xff; if (ch>=' ') video(0x900|ch,&cx,(int *)0); video(0xe00|ch,(int *)0, (int *)0); if (ch=='\n') { exwrote = TRUE; video(0xe0d, (int *)0, (int *)0); } return ch; } /* determine number of screen columns. Also set attrset according * to monochrome/color screen. */ int v_cols() { union REGS regs; regs.h.ah=0x0f; int86(0x10, ®s, ®s); if (regs.h.al==7) /* monochrome mode ? */ screen=1; else screen=0; return regs.h.ah; } /* Getting the number of rows is hard. Most screens support 25 only, * EGA/VGA also support 43/50 lines, and some OEM's even more. * Unfortunately, there is no standard bios variable for the number * of lines, and the bios screen memory size is always rounded up * to 0x1000. So, we'll really have to cheat. * When using the screen memory size, keep in mind that each character * byte has an associated attribute byte. * * uses: word at 40:4c contains memory size * byte at 40:84 # of rows-1 (sometimes) * byte at 40:4a # of columns */ int v_rows() { int line, oldline; /* screen size less then 4K? then we have 25 lines only */ if (*(int far *)(0x0040004cl)<=4096) return 25; /* VEGA vga uses the bios byte at 0x40:0x84 for # of rows. * Use that byte, if it makes sense together with memory size. */ if ((((*(unsigned char far *)(0x0040004aL)*2* (*(unsigned char far *)(0x00400084L)+1))+0xfff)&(~0xfff))== *(unsigned int far *)(0x0040004cL)) return *(unsigned char far *)(0x00400084L)+1; /* uh oh. Emit '\n's until screen starts scrolling. */ v_move(oldline=0, 0); for (;;) { video(0xe0a,(int *)0,(int *)0); video(0x300,(int *)0,&line); line>>=8; if (oldline==line) return line+1; oldline=line; } } /* the REAL bios interface -- used internally only. */ static void video(ax, cx, dx) int ax, *cx, *dx; { union REGS regs; regs.x.ax=ax; if ((ax&0xff00)==0x600 || (ax&0xff00)==0x700) regs.h.bh=attr[screen][vmode]; else { regs.h.bh=0; regs.h.bl=attr[screen][vmode]; } if (cx) regs.x.cx=*cx; if (dx) regs.x.dx=*dx; int86(0x10, ®s, ®s); if (dx) *dx=regs.x.dx; if (cx) *cx=regs.x.cx; } /* The following function determines which character is used for * commandline-options by command.com. This system call is undocumented * and valid for versions < 4.00 only. */ int switchar() { union REGS regs; regs.x.ax=0x3700; int86(0x21, ®s, ®s); return regs.h.dl; } #endif SHAR_EOF fi # end of overwriting check if test -f 'recycle.c' then echo shar: will not over-write existing file "'recycle.c'" else cat << \SHAR_EOF > 'recycle.c' /* recycle.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the functions perform garbage collection and allocate * reusable blocks. */ #include "config.h" #include "vi.h" #ifndef NO_RECYCLE /* this whole file would have be skipped if NO_RECYCLE is defined */ extern long lseek(); #define BTST(bitno, byte) ((byte) & (1 << (bitno))) #define BSET(bitno, byte) ((byte) |= (1 << (bitno))) #define BCLR(bitno, byte) ((byte) &= ~(1 << (bitno))) #define TST(blkno) ((blkno) < MAXBIT ? BTST((blkno) & 7, bitmap[(blkno) >> 3]) : 1) #define SET(blkno) if ((blkno) < MAXBIT) BSET((blkno) & 7, bitmap[(blkno) >> 3]) #define CLR(blkno) if ((blkno) < MAXBIT) BCLR((blkno) & 7, bitmap[(blkno) >> 3]) /* bitmap of free blocks in first 4096k of tmp file */ static unsigned char bitmap[512]; #define MAXBIT (sizeof bitmap << 3) /* this function locates all free blocks in the current tmp file */ void garbage() { int i; BLK oldhdr; /* start by assuming every block is free */ for (i = 0; i < sizeof bitmap; i++) { bitmap[i] = 255; } /* header block isn't free */ #ifndef lint CLR(0); #endif /* blocks needed for current hdr aren't free */ for (i = 1; i < MAXBLKS; i++) { CLR(hdr.n[i]); } /* blocks needed for undo version aren't free */ lseek(tmpfd, 0L, 0); if (read(tmpfd, &oldhdr, (unsigned)sizeof oldhdr) != sizeof oldhdr) { msg("garbage() failed to read oldhdr??"); for (i = 0; i < sizeof bitmap; i++) { bitmap[i] = 0; } return; } for (i = 1; i < MAXBLKS; i++) { CLR(oldhdr.n[i]); } /* blocks needed for cut buffers aren't free */ for (i = cutneeds(&oldhdr) - 1; i >= 0; i--) { CLR(oldhdr.n[i]); } } /* This function allocates the first available block in the tmp file */ long allocate() { int i; long offset; /* search for the first byte with a free bit set */ for (i = 0; i < sizeof bitmap && bitmap[i] == 0; i++) { } /* if we hit the end of the bitmap, return the end of the file */ if (i == sizeof bitmap) { offset = lseek(tmpfd, 0L, 2); } else /* compute the offset for the free block */ { for (i <<= 3; TST(i) == 0; i++) { } offset = (long)i * (long)BLKSIZE; /* mark the block as "allocated" */ CLR(i); } return offset; } #endif SHAR_EOF fi # end of overwriting check if test -f 'redraw.c' then echo shar: will not over-write existing file "'redraw.c'" else cat << \SHAR_EOF > 'redraw.c' /* redraw.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains functions that draw text on the screen. The major entry * points are: * redrawrange() - called from modify.c to give hints about what parts * of the screen need to be redrawn. * redraw() - redraws the screen (or part of it) and positions * the cursor where it belongs. * idx2col() - converts a markidx() value to a logical column number. */ #include "config.h" #include "vi.h" /* This variable contains the line number that smartdrawtext() knows best */ static long smartlno; /* This function remebers where changes were made, so that the screen can be * redraw in a more efficient manner. */ static long redrawafter; /* line# of first line that must be redrawn */ static long preredraw; /* line# of last line changed, before change */ static long postredraw; /* line# of last line changed, after change */ void redrawrange(after, pre, post) long after; /* lower bound of redrawafter */ long pre; /* upper bound of preredraw */ long post; /* upper bound of postredraw */ { if (after == redrawafter) { /* multiple insertions/deletions at the same place -- combine * them */ preredraw -= (post - pre); if (postredraw < post) { preredraw += (post - postredraw); postredraw = post; } if (redrawafter > preredraw) { redrawafter = preredraw; } if (redrawafter < 1L) { redrawafter = 0L; preredraw = postredraw = INFINITY; } } else if (postredraw > 0L) { /* multiple changes in different places -- redraw everything * after "after". */ postredraw = preredraw = INFINITY; if (after < redrawafter) redrawafter = after; } else { /* first change */ redrawafter = after; preredraw = pre; postredraw = post; } } #ifndef NO_CHARATTR /* see if a given line uses character attribute strings */ static int hasattr(lno, text) long lno; /* the line# of the cursor */ REG char *text; /* the text of the line, from fetchline */ { static long plno; /* previous line number */ static long chgs; /* previous value of changes counter */ static int panswer;/* previous answer */ char *scan; /* if charattr is off, then the answer is "no, it doesn't" */ if (!*o_charattr) { chgs = 0; /* <- forces us to check if charattr is later set */ return FALSE; } /* if we already know the answer, return it... */ if (lno == plno && chgs == changes) { return panswer; } /* get the line & look for "\fX" */ if (!text[0] || !text[1] || !text[2]) { panswer = FALSE; } else { for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++) { } panswer = (scan[2] != '\0'); } /* save the results */ plno = lno; chgs = changes; /* return the results */ return panswer; } #endif /* This function converts a MARK to a column number. It doesn't automatically * adjust for leftcol; that must be done by the calling function */ int idx2col(curs, text, inputting) MARK curs; /* the line# & index# of the cursor */ REG char *text; /* the text of the line, from fetchline */ int inputting; /* boolean: called from input() ? */ { static MARK pcursor;/* previous cursor, for possible shortcut */ static MARK pcol; /* column number for pcol */ static long chgs; /* previous value of changes counter */ REG int col; /* used to count column numbers */ REG int idx; /* used to count down the index */ REG int i; /* for now, assume we have to start counting at the left edge */ col = 0; idx = markidx(curs); /* if the file hasn't changed & line number is the same & it has no * embedded character attribute strings, can we do shortcuts? */ if (chgs == changes && !((curs ^ pcursor) & ~(BLKSIZE - 1)) #ifndef NO_CHARATTR && !hasattr(markline(curs), text) #endif ) { /* no movement? */ if (curs == pcursor) { /* return the column of the char; for tabs, return its last column */ if (text[idx] == '\t' && !inputting && !*o_list) { return pcol + *o_tabstop - (pcol % *o_tabstop) - 1; } else { return pcol; } } /* movement to right? */ if (curs > pcursor) { /* start counting from previous place */ col = pcol; idx = markidx(curs) - markidx(pcursor); text += markidx(pcursor); } } /* count over to the char after the idx position */ while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */ { if (i == '\t' && !*o_list) { col += *o_tabstop; col -= col % *o_tabstop; } else if (i >= '\0' && i < ' ' || i == '\177') { col += 2; } #ifndef NO_CHARATTR else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more at bottom of loop */ idx -= 2; } #endif else { col++; } text++; idx--; } /* save stuff to speed next call */ pcursor = curs; pcol = col; chgs = changes; /* return the column of the char; for tabs, return its last column */ if (*text == '\t' && !inputting && !*o_list) { return col + *o_tabstop - (col % *o_tabstop) - 1; } else { return col; } } /* This function is similar to idx2col except that it takes care of sideways * scrolling - for the given line, at least. */ int mark2phys(m, text, inputting) MARK m; /* a mark to convert */ char *text; /* the line that m refers to */ int inputting; /* boolean: caled from input() ? */ { int i; i = idx2col(m, text, inputting); while (i < leftcol) { leftcol -= *o_sidescroll; mustredraw = TRUE; redrawrange(1L, INFINITY, INFINITY); qaddch('\r'); /* drawtext(text); */ } while (i > rightcol) { leftcol += *o_sidescroll; mustredraw = TRUE; redrawrange(1L, INFINITY, INFINITY); qaddch('\r'); /* drawtext(text); */ } physcol = i - leftcol; physrow = markline(m) - topline; return physcol; } /* This function draws a single line of text on the screen. The screen's * cursor is assumed to be located at the leftmost column of the appropriate * row. */ void drawtext(text, clr) REG char *text; /* the text to draw */ int clr; /* boolean: do a clrtoeol? */ { REG int col; /* column number */ REG int i; REG int tabstop; /* *o_tabstop */ REG int limitcol; /* leftcol or leftcol + COLS */ int abnormal; /* boolean: charattr != A_NORMAL? */ #ifndef NO_SENTENCE /* if we're hiding format lines, and this is one of them, then hide it */ if (*o_hideformat && *text == '.') { clrtoeol(); #if OSK qaddch('\l'); #else qaddch('\n'); #endif return; } #endif /* move some things into registers... */ limitcol = leftcol; tabstop = *o_tabstop; abnormal = FALSE; #ifndef CRUNCH if (clr) clrtoeol(); #endif /* skip stuff that was scrolled off left edge */ for (col = 0; (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */ text++) { if (i == '\t' && !*o_list) { col = col + tabstop - (col % tabstop); } else if (i >= 0 && i < ' ' || i == '\177') { col += 2; } #ifndef NO_CHARATTR else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more as part of "for" loop */ /* since this attribute might carry over, we need it */ switch (*text) { case 'R': case 'P': attrset(A_NORMAL); abnormal = FALSE; break; case 'B': attrset(A_BOLD); abnormal = TRUE; break; case 'U': attrset(A_UNDERLINE); abnormal = TRUE; break; case 'I': attrset(A_ALTCHARSET); abnormal = TRUE; break; } } #endif else { col++; } } /* adjust for control char that was partially visible */ while (col > limitcol) { qaddch(' '); limitcol++; } /* now for the visible characters */ for (limitcol = leftcol + COLS; (i = *text) && col < limitcol; text++) { if (i == '\t' && !*o_list) { i = col + tabstop - (col % tabstop); if (i < limitcol) { #ifdef CRUNCH if (!clr && has_PT && !((i - leftcol) & 7)) #else if (has_PT && !((i - leftcol) & 7)) #endif { do { qaddch('\t'); col += 8; /* not exact! */ } while (col < i); col = i; /* NOW it is exact */ } else { do { qaddch(' '); col++; } while (col < i); } } else /* tab ending after screen? next line! */ { col = limitcol; if (has_AM) { addch('\n'); /* GB */ } } } else if (i >= 0 && i < ' ' || i == '\177') { col += 2; qaddch('^'); if (col <= limitcol) { qaddch(i ^ '@'); } } #ifndef NO_CHARATTR else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more as part of "for" loop */ switch (*text) { case 'R': case 'P': attrset(A_NORMAL); abnormal = FALSE; break; case 'B': attrset(A_BOLD); abnormal = TRUE; break; case 'U': attrset(A_UNDERLINE); abnormal = TRUE; break; case 'I': attrset(A_ALTCHARSET); abnormal = TRUE; break; } } #endif else { col++; qaddch(i); } } /* get ready for the next line */ #ifndef NO_CHARATTR if (abnormal) { attrset(A_NORMAL); } #endif if (*o_list && col < limitcol) { qaddch('$'); col++; } #ifdef CRUNCH if (clr && col < limitcol) { clrtoeol(); } #endif if (!has_AM || col < limitcol) { addch('\n'); } } #if OPENWINDOWS # define NUDGE_COST (Ow.tty ? 1 : 5) /* move is always cheaper in NeWS */ #else # define NUDGE_COST 5 #endif #ifndef CRUNCH static void nudgecursor(same, scan, new, lno) int same; /* number of chars to be skipped over */ char *scan; /* where the same chars end */ char *new; /* where the visible part of the line starts */ long lno; /* line number of this line */ { if (same > 0) { if (same < NUDGE_COST) { /* move the cursor by overwriting */ while (same > 0) { qaddch(scan[-same]); same--; } } else { /* move the cursor by calling move() */ move((int)(lno - topline), (int)(scan - new)); } } } #endif /* not CRUNCH */ /* This function draws a single line of text on the screen, possibly with * some cursor optimization. The cursor is repositioned before drawing * begins, so its position before doesn't really matter. */ static void smartdrawtext(text, lno) REG char *text; /* the text to draw */ long lno; /* line number of the text */ { #ifdef CRUNCH move((int)(lno - topline), 0); drawtext(text, TRUE); #else /* not CRUNCH */ static char old[256]; /* how the line looked last time */ char new[256]; /* how it looks now */ char *build; /* used to put chars into new[] */ char *scan; /* used for moving thru new[] or old[] */ char *end; /* last non-blank changed char */ char *shift; /* used to insert/delete chars */ int same; /* length of a run of unchanged chars */ int limitcol; int col; int i; # ifndef NO_CHARATTR /* if this line has attributes, do it the dumb way instead */ if (hasattr(lno, text)) { move((int)(lno - topline), 0); drawtext(text, TRUE); return; } # endif # ifndef NO_SENTENCE /* if this line is a format line, & we're hiding format lines, then * let the dumb drawtext() function handle it */ if (*o_hideformat && *text == '.') { move((int)(lno - topline), 0); drawtext(text, TRUE); return; } # endif /* skip stuff that was scrolled off left edge */ limitcol = leftcol; for (col = 0; (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */ text++) { if (i == '\t' && !*o_list) { col = col + *o_tabstop - (col % *o_tabstop); } else if (i >= 0 && i < ' ' || i == '\177') { col += 2; } else { col++; } } /* adjust for control char that was partially visible */ build = new; while (col > limitcol) { *build++ = ' '; limitcol++; } /* now for the visible characters */ for (limitcol = leftcol + COLS; (i = *text) && col < limitcol; text++) { if (i == '\t' && !*o_list) { i = col + *o_tabstop - (col % *o_tabstop); while (col < i && col < limitcol) { *build++ = ' '; col++; } } else if (i >= 0 && i < ' ' || i == '\177') { col += 2; *build++ = '^'; if (col <= limitcol) { *build++ = (i ^ '@'); } } else { col++; *build++ = i; } } if (col < limitcol && *o_list) { *build++ = '$'; col++; } end = build; while (col < limitcol) { *build++ = ' '; col++; } /* locate the last non-blank character */ while (end > new && end[-1] == ' ') { end--; } /* can we optimize the displaying of this line? */ if (lno != smartlno) { /* nope, can't optimize - different line */ move((int)(lno - topline), 0); for (scan = new, build = old; scan < end; ) { qaddch(*scan); *build++ = *scan++; } if (end < new + COLS) { clrtoeol(); while (build < old + COLS) { *build++ = ' '; } } smartlno = lno; return; } /* skip any initial unchanged characters */ for (scan = new, build = old; scan < end && *scan == *build; scan++, build++) { } move((int)(lno - topline), (int)(scan - new)); /* The in-between characters must be changed */ same = 0; while (scan < end) { /* is this character a match? */ if (scan[0] == build[0]) { same++; } else /* do we want to insert? */ if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM)) { nudgecursor(same, scan, new, lno); same = 0; insch(*scan); for (shift = old + COLS; --shift > build; ) { shift[0] = shift[-1]; } *build = *scan; } else /* do we want to delete? */ if (build < old + COLS - 1 && scan[0] == build[1] && has_DC) { nudgecursor(same, scan, new, lno); same = 0; delch(); same++; for (shift = build; shift < old + COLS - 1; shift++) { shift[0] = shift[1]; } *shift = ' '; } else /* we must overwrite */ { nudgecursor(same, scan, new, lno); same = 0; addch(*scan); *build = *scan; } build++; scan++; } /* maybe clear to EOL */ while (build < old + COLS && *build == ' ') { build++; } if (build < old + COLS) { nudgecursor(same, scan, new, lno); same = 0; clrtoeol(); while (build < old + COLS) { *build++ = ' '; } } #endif /* not CRUNCH */ } /* This function is used in visual mode for drawing the screen (or just parts * of the screen, if that's all thats needed). It also takes care of * scrolling. */ void redraw(curs, inputting) MARK curs; /* where to leave the screen's cursor */ int inputting; /* boolean: being called from input() ? */ { char *text; /* a line of text to display */ static long chgs; /* previous changes level */ long l; int i; /* if curs == MARK_UNSET, then we should reset internal vars */ if (curs == MARK_UNSET) { if (topline < 1 || topline > nlines) { topline = 1L; } else { move(LINES - 1, 0); clrtoeol(); } leftcol = 0; mustredraw = TRUE; redrawafter = INFINITY; preredraw = 0L; postredraw = 0L; chgs = 0; smartlno = 0L; return; } /* figure out which column the cursor will be in */ l = markline(curs); text = fetchline(l); mark2phys(curs, text, inputting); /* adjust topline, if necessary, to get the cursor on the screen */ if (l >= topline && l <= botline) { /* it is on the screen already */ /* if the file was changed but !mustredraw, then redraw line */ if (chgs != changes && !mustredraw) { smartdrawtext(text, l); } } else if (l < topline && l > topline - LINES && (has_SR || has_AL)) { /* near top - scroll down */ if (!mustredraw) { Scrolldown(l, 0, 0); } else { topline = l; redrawafter = INFINITY; preredraw = 0L; postredraw = 0L; } } else if (l > topline && l < botline + LINES) { /* near bottom -- scroll up */ if (!mustredraw #if 1 || redrawafter == preredraw && preredraw == botline && postredraw == l #endif ) { Scrollup(l, LINES-1, 0); mustredraw = FALSE; } else { topline = l - (LINES - 2); redrawafter = INFINITY; preredraw = 0L; postredraw = 0L; } } else { /* distant line - center it & force a redraw */ topline = l - (LINES / 2) - 1; if (topline < 1) { topline = 1; } mustredraw = TRUE; redrawafter = INFINITY; preredraw = 0L; postredraw = 0L; } /* Now... do we really have to redraw? */ if (mustredraw) { /* If redrawfter (and friends) aren't set, assume we should * redraw everything. */ if (redrawafter == INFINITY) { redrawafter = 0L; preredraw = postredraw = INFINITY; } /* adjust smartlno to correspond with inserted/deleted lines */ if (smartlno >= redrawafter) { if (smartlno < preredraw) { smartlno = 0L; } else { smartlno += (postredraw - preredraw); } } /* should we insert some lines into the screen? */ if (preredraw < postredraw && preredraw <= botline) { /* lines were inserted into the file */ /* decide where insertion should start */ if (preredraw < topline) { l = topline; } else { l = preredraw; } /* insert the lines... maybe */ if (l + postredraw - preredraw > botline || !has_AL) { /* Whoa! a whole screen full - just redraw */ preredraw = postredraw = INFINITY; } else { /* really insert 'em */ move((int)(l - topline), 0); for (i = postredraw - preredraw; i > 0; i--) { insertln(); } /* NOTE: the contents of those lines will be * drawn as part of the regular redraw loop. */ /* clear the last line */ move(LINES - 1, 0); clrtoeol(); } } /* do we want to delete some lines from the screen? */ if (preredraw > postredraw && postredraw <= botline) { if (preredraw > botline || !has_DL) { postredraw = preredraw = INFINITY; } else /* we'd best delete some lines from the screen */ { /* clear the last line, so it doesn't look * ugly as it gets pulled up into the screen */ move(LINES - 1, 0); clrtoeol(); /* delete the lines */ move((int)(postredraw - topline), 0); for (l = postredraw; l < preredraw && l <= botline; l++) { deleteln(); } /* draw the lines that are now newly visible * at the bottom of the screen */ i = LINES - 1 + (postredraw - preredraw); move(i, 0); for (l = topline + i; l <= botline; l++) { /* clear this line */ clrtoeol(); /* draw the line, or ~ for non-lines */ if (l <= nlines) { text = fetchline(l); drawtext(text, FALSE); } else { addstr("~\n"); } } } } /* redraw the current line */ l = markline(curs); pfetch(l); smartdrawtext(ptext, l); /* decide where we should start redrawing from */ if (redrawafter < topline) { l = topline; } else { l = redrawafter; } move((int)(l - topline), 0); /* draw the other lines */ for (; l <= botline && l < postredraw; l++) { /* we already drew the current line, so skip it now */ /* smartlno is not always adjusted right. when it is fixed take out the stuff around the HACK comments */ if (l == smartlno /* HACK */ && 0 /* HACK */) { #if OSK qaddch('\l'); #else qaddch('\n'); #endif continue; } /* draw the line, or ~ for non-lines */ if (l <= nlines) { text = fetchline(l); drawtext(text, TRUE); } else { qaddch('~'); clrtoeol(); addch('\n'); } } mustredraw = FALSE; } /* force total (non-partial) redraw next time if not set */ redrawafter = INFINITY; preredraw = 0L; postredraw = 0L; /* move the cursor to where it belongs */ move((int)(markline(curs) - topline), physcol); wqrefresh(stdscr); chgs = changes; } int scrolldown(l,y,x) long l; int y, x; { char *text; move(y,x); while (l < topline) { topline--; if (has_SR) { do_SR(); } else { insertln(); } text = fetchline(topline); drawtext(text, FALSE); do_UP(); } /* blank out the last line */ move(LINES - 1, 0); clrtoeol(); return 0; } int scrollup(l, y, x) long l; int y,x; { char *text; move(y,x); clrtoeol(); while (l > botline) { topline++; /* <-- also adjusts botline */ text = fetchline(botline); drawtext(text, FALSE); } return 0; } SHAR_EOF fi # end of overwriting check if test -f 'ref.c' then echo shar: will not over-write existing file "'ref.c'" else cat << \SHAR_EOF > 'ref.c' /* ref.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This program looks up the declarations of library functions. */ #include <stdio.h> /* This is the list of files that are searched. */ #ifdef OSK char *refslist[] = { "refs", "/dd/usr/src/lib/refs", "../lib/refs", "/dd/usr/local/lib/refs", }; #else char *refslist[] = { "refs", "/usr/src/lib/refs", "../lib/refs", "/usr/local/lib/refs" }; #endif #define NREFS (sizeof refslist / sizeof(char *)) main(argc, argv) int argc; char **argv; { int i; /* used to step through the refslist */ /* make sure our arguments are OK */ if (argc != 2) { fprintf(stderr, "usage: %s function_name\n", *argv); exit(2); } /* check for the function in each database */ for (i = 0; i < NREFS; i++) { if (lookinfor(refslist[i], argv[1])) { exit(0); } } fprintf(stderr, "%s: don't know about %s\n", argv[0], argv[1]); exit(2); } /* This function checks a single file for the function. Returns 1 if found */ int lookinfor(filename, func) char *filename; /* name of file to look in */ char *func; /* name of function to look for */ { FILE *fp; /* stream used to access the database */ char linebuf[300]; /* NOTE: in actual use, the first character of linebuf is */ /* set to ' ' and then we use all EXCEPT the 1st character */ /* everywhere in this function. This is because the func */ /* which examines the linebuf could, in some circumstances */ /* examine the character before the used part of linebuf; */ /* we need to control what happens then. */ /* open the database file */ fp = fopen(filename, "r"); if (!fp) { return 0; } /* find the desired entry */ *linebuf = ' '; do { if (!fgets(linebuf + 1, (sizeof linebuf) - 1, fp)) { fclose(fp); return 0; } } while (!desired(linebuf + 1, func)); /* print it */ do { fputs(linebuf + 1, stdout); } while (fgets(linebuf + 1, sizeof linebuf, fp) && linebuf[1] == '\t'); /* cleanup & exit */ fclose(fp); return 1; } /* This function checks to see if a given line is the first line of the */ /* entry the user wants to see. If it is, return non-0 else return 0 */ desired(line, word) char *line; /* the line buffer */ char *word; /* the string it should contain */ { static wlen = -1;/* length of the "word" variable's value */ register char *scan; /* if this line starts with a tab, it couldn't be desired */ if (*line == '\t') { return 0; } /* if we haven't found word's length yet, do so */ if (wlen < 0) { wlen = strlen(word); } /* search for the word in the line */ for (scan = line; *scan != '('; scan++) { } while (*--scan == ' ') { } scan -= wlen; if (scan < line - 1 || *scan != ' ' && *scan != '\t' && *scan != '*') { return 0; } scan++; return !strncmp(scan, word, wlen); } SHAR_EOF fi # end of overwriting check if test -f 'refont.c' then echo shar: will not over-write existing file "'refont.c'" else cat << \SHAR_EOF > 'refont.c' /* refont.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the complete source code for the refont program */ /* The refont program converts font designations to the format of your choice. * Known font formats are: * -b overtype notation, using backspaces * -c overtype notation, using carriage returns * -d the "dot" command notation used by nroff (doesn't work well) * -e Epson-compatible line printer codes * -f the "\f" notation * -x none (strip out the font codes) * * Other flags are: * -I recognize \f and dot notations in input * -F output a formfeed character between files */ #include <stdio.h> #include "config.h" /* the program name, for diagnostics */ char *progname; /* remembers which output format to use */ int outfmt = 'f'; /* do we allow "dot" and "backslash-f" on input? */ int infmt = 0; /* do we insert formfeeds between input files? */ int add_form_feed = 0; main(argc, argv) int argc; /* number of command-line args */ char **argv; /* values of the command line args */ { FILE *fp; int i, j; int retcode; progname = argv[0]; /* parse the flags */ i = 1; if (i < argc && argv[i][0] == '-' && argv[i][1]) { for (j = 1; argv[i][j]; j++) { switch (argv[i][j]) { case 'b': #if !OSK case 'c': #endif case 'd': case 'e': case 'f': case 'x': outfmt = argv[i][j]; break; case 'I': infmt = 'I'; break; case 'F': add_form_feed = 1; break; default: usage(); } } i++; } retcode = 0; if (i == argc) { /* probably shouldn't read from keyboard */ if (isatty(fileno(stdin))) { usage(); } /* no files named, so use stdin */ refont(stdin); } else { for (; i < argc; i++) { fp = fopen(argv[i], "r"); if (!fp) { perror(argv[i]); retcode = 1; } else { refont(fp); if (i < argc - 1 && add_form_feed) { putchar('\f'); } fclose(fp); } } } exit(retcode); } usage() { fputs("usage: ", stderr); fputs(progname, stderr); fputs(" [-bcdefxFI] [filename]...\n", stderr); exit(2); } /* This function does the refont thing to a single file */ /* I apologize for the length of this function. It is gross. */ refont(fp) FILE *fp; { char textbuf[1025]; /* chars of a line of text */ char fontbuf[1025]; /* fonts of chars in fontbuf */ int col; /* where we are in the line */ int font; /* remembered font */ int more; /* more characters to be output? */ int ch; /* reset some stuff */ for (col = sizeof fontbuf; --col >= 0; ) { fontbuf[col] = 'R'; textbuf[col] = '\0'; } col = 0; font = 'R'; /* get the first char - quit if eof */ while ((ch = getc(fp)) != EOF) { /* if "dot" command, read the rest of the command */ if (infmt == 'I' && ch == '.' && col == 0) { textbuf[col++] = '.'; textbuf[col++] = getc(fp); textbuf[col++] = getc(fp); textbuf[col++] = ch = getc(fp); /* is it a font line? */ font = 0; if (textbuf[1] == 'u' && textbuf[2] == 'l') { font = 'U'; } else if (textbuf[1] == 'b' && textbuf[2] == 'o') { font = 'B'; } else if (textbuf[1] == 'i' && textbuf[2] == 't') { font = 'I'; } /* if it is, discard the stuff so far but remember font */ if (font) { while (col > 0) { textbuf[--col] = '\0'; } } else /* some other format line - write it literally */ { while (ch != '\n') { textbuf[col++] = ch = getc(fp); } fputs(textbuf, fp); while (col > 0) { textbuf[--col] = '\0'; } } continue; } /* is it a "\f" formatted font? */ if (infmt == 'I' && ch == '\\') { ch = getc(fp); if (ch == 'f') { font = getc(fp); } else { textbuf[col++] = '\\'; textbuf[col++] = ch; } continue; } /* is it an Epson font? */ if (ch == '\033') { ch = getc(fp); switch (ch) { case '4': font = 'I'; break; case 'E': case 'G': font = 'B'; break; case '5': case 'F': case 'H': font = 'R'; break; case '-': font = (getc(fp) & 1) ? 'U' : 'R'; break; } continue; } /* control characters? */ if (ch == '\b') { if (col > 0) col--; continue; } else if (ch == '\t') { do { if (textbuf[col] == '\0') { textbuf[col] = ' '; } col++; } while (col & 7); continue; } #if !OSK else if (ch == '\r') { col = 0; continue; } #endif else if (ch == ' ') { if (textbuf[col] == '\0') { textbuf[col] = ' '; fontbuf[col] = font; col++; } continue; } /* newline? */ if (ch == '\n') { more = 0; for (col = 0, font = 'R'; textbuf[col]; col++) { if (fontbuf[col] != font) { switch (outfmt) { case 'd': putchar('\n'); switch (fontbuf[col]) { case 'B': fputs(".bo\n", stdout); break; case 'I': fputs(".it\n", stdout); break; case 'U': fputs(".ul\n", stdout); break; } while (textbuf[col] == ' ') { col++; } break; case 'e': switch (fontbuf[col]) { case 'B': fputs("\033E", stdout); break; case 'I': fputs("\0334", stdout); break; case 'U': fputs("\033-1", stdout); break; default: switch (font) { case 'B': fputs("\033F", stdout); break; case 'I': fputs("\0335", stdout); break; case 'U': fputs("\033-0", stdout); break; } } break; case 'f': putchar('\\'); putchar('f'); putchar(fontbuf[col]); break; } font = fontbuf[col]; } if (fontbuf[col] != 'R' && textbuf[col] != ' ') { switch (outfmt) { case 'b': if (fontbuf[col] == 'B') { putchar(textbuf[col]); } else { putchar('_'); } putchar('\b'); break; #if !OSK case 'c': more = col + 1; break; #endif } } putchar(textbuf[col]); } #if !OSK /* another pass? */ if (more > 0) { putchar('\r'); for (col = 0; col < more; col++) { switch (fontbuf[col]) { case 'I': case 'U': putchar('_'); break; case 'B': putchar(textbuf[col]); break; default: putchar(' '); } } } #endif /* not OSK */ /* newline */ if (font != 'R') { switch (outfmt) { case 'f': putchar('\\'); putchar('f'); putchar('R'); break; case 'e': switch (font) { case 'B': fputs("\033F", stdout); break; case 'I': fputs("\0335", stdout); break; case 'U': fputs("\033-0", stdout); break; } } } putchar('\n'); /* reset some stuff */ for (col = sizeof fontbuf; --col >= 0; ) { fontbuf[col] = 'R'; textbuf[col] = '\0'; } col = 0; font = 'R'; continue; } /* normal character */ if (font != 'R') { textbuf[col] = ch; fontbuf[col] = font; } else if (textbuf[col] == '_') { textbuf[col] = ch; fontbuf[col] = 'U'; } else if (textbuf[col] && textbuf[col] != ' ' && ch == '_') { fontbuf[col] = 'U'; } else if (textbuf[col] == ch) { fontbuf[col] = 'B'; } else { textbuf[col] = ch; } col++; } } SHAR_EOF fi # end of overwriting check if test -f 'regexp.c' then echo shar: will not over-write existing file "'regexp.c'" else cat << \SHAR_EOF > 'regexp.c' /* regexp.c */ /* This file contains the code that compiles regular expressions and executes * them. It supports the same syntax and features as vi's regular expression * code. Specifically, the meta characters are: * ^ matches the beginning of a line * $ matches the end of a line * \< matches the beginning of a word * \> matches the end of a word * . matches any single character * [] matches any character in a character class * \( delimits the start of a subexpression * \) delimits the end of a subexpression * * repeats the preceding 0 or more times * NOTE: You cannot follow a \) with a *. * * The physical structure of a compiled RE is as follows: * - First, there is a one-byte value that says how many character classes * are used in this regular expression * - Next, each character class is stored as a bitmap that is 256 bits * (32 bytes) long. * - A mixture of literal characters and compiled meta characters follows. * This begins with M_BEGIN(0) and ends with M_END(0). All meta chars * are stored as a \n followed by a one-byte code, so they take up two * bytes apiece. Literal characters take up one byte apiece. \n can't * be used as a literal character. * * If NO_MAGIC is defined, then a different set of functions is used instead. * That right, this file contains TWO versions of the code. */ #include <setjmp.h> #include <ctype.h> #include "config.h" #include "vi.h" #include "regexp.h" static char *previous; /* the previous regexp, used when null regexp is given */ #ifndef NO_MAGIC /* THE REAL REGEXP PACKAGE IS USED UNLESS "NO_MAGIC" IS DEFINED */ /* These are used to classify or recognize meta-characters */ #define META '\0' #define BASE_META(m) ((m) - 256) #define INT_META(c) ((c) + 256) #define IS_META(m) ((m) >= 256) #define IS_CLASS(m) ((m) >= M_CLASS(0) && (m) <= M_CLASS(9)) #define IS_START(m) ((m) >= M_START(0) && (m) <= M_START(9)) #define IS_END(m) ((m) >= M_END(0) && (m) <= M_END(9)) #define IS_CLOSURE(m) ((m) >= M_SPLAT && (m) <= M_QMARK) #define ADD_META(s,m) (*(s)++ = META, *(s)++ = BASE_META(m)) #define GET_META(s) (*(s) == META ? INT_META(*++(s)) : *s) /* These are the internal codes used for each type of meta-character */ #define M_BEGLINE 256 /* internal code for ^ */ #define M_ENDLINE 257 /* internal code for $ */ #define M_BEGWORD 258 /* internal code for \< */ #define M_ENDWORD 259 /* internal code for \> */ #define M_ANY 260 /* internal code for . */ #define M_SPLAT 261 /* internal code for * */ #define M_PLUS 262 /* internal code for \+ */ #define M_QMARK 263 /* internal code for \? */ #define M_CLASS(n) (264+(n)) /* internal code for [] */ #define M_START(n) (274+(n)) /* internal code for \( */ #define M_END(n) (284+(n)) /* internal code for \) */ /* These are used during compilation */ static int class_cnt; /* used to assign class IDs */ static int start_cnt; /* used to assign start IDs */ static int end_stk[NSUBEXP];/* used to assign end IDs */ static int end_sp; static char *retext; /* points to the text being compiled */ /* error-handling stuff */ jmp_buf errorhandler; #define FAIL(why) regerror(why); longjmp(errorhandler, 1) /* This function builds a bitmap for a particular class */ static char *makeclass(text, bmap) REG char *text; /* start of the class */ REG char *bmap; /* the bitmap */ { REG int i; int complement = 0; # if TRACE printf("makeclass(\"%s\", 0x%lx)\n", text, (long)bmap); # endif /* zero the bitmap */ for (i = 0; bmap && i < 32; i++) { bmap[i] = 0; } /* see if we're going to complement this class */ if (*text == '^') { text++; complement = 1; } /* add in the characters */ while (*text && *text != ']') { /* is this a span of characters? */ if (text[1] == '-' && text[2]) { /* spans can't be backwards */ if (text[0] > text[2]) { FAIL("Backwards span in []"); } /* add each character in the span to the bitmap */ for (i = text[0]; bmap && i <= text[2]; i++) { bmap[i >> 3] |= (1 << (i & 7)); } /* move past this span */ text += 3; } else { /* add this single character to the span */ i = *text++; if (bmap) { bmap[i >> 3] |= (1 << (i & 7)); } } } /* make sure the closing ] is missing */ if (*text++ != ']') { FAIL("] missing"); } /* if we're supposed to complement this class, then do so */ if (complement && bmap) { for (i = 0; i < 32; i++) { bmap[i] = ~bmap[i]; } } return text; } /* This function gets the next character or meta character from a string. * The pointer is incremented by 1, or by 2 for \-quoted characters. For [], * a bitmap is generated via makeclass() (if re is given), and the * character-class text is skipped. */ static int gettoken(sptr, re) char **sptr; regexp *re; { int c; c = **sptr; ++*sptr; if (c == '\\') { c = **sptr; ++*sptr; switch (c) { case '<': return M_BEGWORD; case '>': return M_ENDWORD; case '(': if (start_cnt >= NSUBEXP) { FAIL("Too many \\(s"); } end_stk[end_sp++] = start_cnt; return M_START(start_cnt++); case ')': if (end_sp <= 0) { FAIL("Mismatched \\)"); } return M_END(end_stk[--end_sp]); case '*': return (*o_magic ? c : M_SPLAT); case '.': return (*o_magic ? c : M_ANY); case '+': return M_PLUS; case '?': return M_QMARK; default: return c; } } else if (*o_magic) { switch (c) { case '^': if (*sptr == retext + 1) { return M_BEGLINE; } return c; case '$': if (!**sptr) { return M_ENDLINE; } return c; case '.': return M_ANY; case '*': return M_SPLAT; case '[': /* make sure we don't have too many classes */ if (class_cnt >= 10) { FAIL("Too many []s"); } /* process the character list for this class */ if (re) { /* generate the bitmap for this class */ *sptr = makeclass(*sptr, re->program + 1 + 32 * class_cnt); } else { /* skip to end of the class */ *sptr = makeclass(*sptr, (char *)0); } return M_CLASS(class_cnt++); default: return c; } } else /* unquoted nomagic */ { switch (c) { case '^': if (*sptr == retext + 1) { return M_BEGLINE; } return c; case '$': if (!**sptr) { return M_ENDLINE; } return c; default: return c; } } /*NOTREACHED*/ } /* This function calculates the number of bytes that will be needed for a * compiled RE. Its argument is the uncompiled version. It is not clever * about catching syntax errors; that is done in a later pass. */ static unsigned calcsize(text) char *text; { unsigned size; int token; retext = text; class_cnt = 0; start_cnt = 1; end_sp = 0; size = 5; while ((token = gettoken(&text, (regexp *)0)) != 0) { if (IS_CLASS(token)) { size += 34; } else if (IS_META(token)) { size += 2; } else { size++; } } return size; } /* This function compiles a regexp. */ regexp *regcomp(text) char *text; { int needfirst; unsigned size; int token; int peek; char *build; regexp *re; /* prepare for error handling */ re = (regexp *)0; if (setjmp(errorhandler)) { if (re) { free(re); } return (regexp *)0; } /* if an empty regexp string was given, use the previous one */ if (*text == 0) { if (!previous) { FAIL("No previous RE"); } text = previous; } else /* non-empty regexp given, so remember it */ { if (previous) free(previous); previous = (char *)malloc((unsigned)(strlen(text) + 1)); if (previous) strcpy(previous, text); } /* allocate memory */ class_cnt = 0; start_cnt = 1; end_sp = 0; retext = text; size = calcsize(text) + sizeof(regexp); #ifdef lint re = ((regexp *)0) + size; #else re = (regexp *)malloc((unsigned)size); #endif if (!re) { FAIL("Not enough memory for this RE"); } /* compile it */ build = &re->program[1 + 32 * class_cnt]; re->program[0] = class_cnt; for (token = 0; token < NSUBEXP; token++) { re->startp[token] = re->endp[token] = (char *)0; } re->first = 0; re->bol = 0; re->minlen = 0; needfirst = 1; class_cnt = 0; start_cnt = 1; end_sp = 0; retext = text; for (token = M_START(0), peek = gettoken(&text, re); token; token = peek, peek = gettoken(&text, re)) { /* special processing for the closure operator */ if (IS_CLOSURE(peek)) { /* detect misuse of closure operator */ if (IS_START(token)) { FAIL("* or \\+ or \\? follows nothing"); } else if (IS_META(token) && token != M_ANY && !IS_CLASS(token)) { FAIL("* or \\+ or \\? can only follow a normal character or . or []"); } /* it is okay -- make it prefix instead of postfix */ ADD_META(build, peek); /* take care of "needfirst" - is this the first char? */ if (needfirst && peek == M_PLUS && !IS_META(token)) { re->first = token; } needfirst = 0; /* we used "peek" -- need to refill it */ peek = gettoken(&text, re); if (IS_CLOSURE(peek)) { FAIL("* or \\+ or \\? doubled up"); } } else if (!IS_META(token)) { /* normal char is NOT argument of closure */ if (needfirst) { re->first = token; needfirst = 0; } re->minlen++; } else if (token == M_ANY || IS_CLASS(token)) { /* . or [] is NOT argument of closure */ needfirst = 0; re->minlen++; } /* the "token" character is not closure -- process it normally */ if (token == M_BEGLINE) { /* set the BOL flag instead of storing M_BEGLINE */ re->bol = 1; } else if (IS_META(token)) { ADD_META(build, token); } else { *build++ = token; } } /* end it with a \) which MUST MATCH the opening \( */ ADD_META(build, M_END(0)); if (end_sp > 0) { FAIL("Not enough \\)s"); } return re; } /*---------------------------------------------------------------------------*/ /* This function checks for a match between a character and a token which is * known to represent a single character. It returns 0 if they match, or * 1 if they don't. */ int match1(re, ch, token) regexp *re; REG char ch; REG int token; { if (!ch) { /* the end of a line can't match any RE of width 1 */ return 1; } if (token == M_ANY) { return 0; } else if (IS_CLASS(token)) { if (re->program[1 + 32 * (token - M_CLASS(0)) + (ch >> 3)] & (1 << (ch & 7))) return 0; } else if (ch == token || (*o_ignorecase && isupper(ch) && tolower(ch) == token)) { return 0; } return 1; } /* This function checks characters up to and including the next closure, at * which point it does a recursive call to check the rest of it. This function * returns 0 if everything matches, or 1 if something doesn't match. */ int match(re, str, prog, here) regexp *re; /* the regular expression */ char *str; /* the string */ REG char *prog; /* a portion of re->program, an compiled RE */ REG char *here; /* a portion of str, the string to compare it to */ { REG int token; REG int nmatched; REG int closure; for (token = GET_META(prog); !IS_CLOSURE(token); prog++, token = GET_META(prog)) { switch (token) { /*case M_BEGLINE: can't happen; re->bol is used instead */ case M_ENDLINE: if (*here) return 1; break; case M_BEGWORD: if (here != str && (here[-1] == '_' || isascii(here[-1]) && isalnum(here[-1]))) return 1; break; case M_ENDWORD: if (here[0] == '_' || isascii(here[0]) && isalnum(here[0])) return 1; break; case M_START(0): case M_START(1): case M_START(2): case M_START(3): case M_START(4): case M_START(5): case M_START(6): case M_START(7): case M_START(8): case M_START(9): re->startp[token - M_START(0)] = (char *)here; break; case M_END(0): case M_END(1): case M_END(2): case M_END(3): case M_END(4): case M_END(5): case M_END(6): case M_END(7): case M_END(8): case M_END(9): re->endp[token - M_END(0)] = (char *)here; if (token == M_END(0)) { return 0; } break; default: /* literal, M_CLASS(n), or M_ANY */ if (match1(re, *here, token) != 0) return 1; here++; } } /* C L O S U R E */ /* step 1: see what we have to match against, and move "prog" to point * the the remainder of the compiled RE. */ closure = token; prog++, token = GET_META(prog); prog++; /* step 2: see how many times we can match that token against the string */ for (nmatched = 0; (closure != M_QMARK || nmatched < 1) && *here && match1(re, *here, token) == 0; nmatched++, here++) { } /* step 3: try to match the remainder, and back off if it doesn't */ while (nmatched >= 0 && match(re, str, prog, here) != 0) { nmatched--; here--; } /* so how did it work out? */ if (nmatched >= ((closure == M_PLUS) ? 1 : 0)) return 0; return 1; } /* This function searches through a string for text that matches an RE. */ int regexec(re, str, bol) regexp *re; /* the compiled regexp to search for */ char *str; /* the string to search through */ int bol; /* boolean: does str start at the beginning of a line? */ { char *prog; /* the entry point of re->program */ int len; /* length of the string */ REG char *here; /* if must start at the beginning of a line, and this isn't, then fail */ if (re->bol && !bol) { return 0; } len = strlen(str); prog = re->program + 1 + 32 * re->program[0]; /* search for the RE in the string */ if (re->bol) { /* must occur at BOL */ if ((re->first && match1(re, *(char *)str, re->first))/* wrong first letter? */ || len < re->minlen /* not long enough? */ || match(re, (char *)str, prog, str)) /* doesn't match? */ return 0; /* THEN FAIL! */ } #ifndef CRUNCH else if (!*o_ignorecase) { /* can occur anywhere in the line, noignorecase */ for (here = (char *)str; (re->first && re->first != *here) || match(re, (char *)str, prog, here); here++, len--) { if (len < re->minlen) return 0; } } #endif else { /* can occur anywhere in the line, ignorecase */ for (here = (char *)str; (re->first && match1(re, *here, (int)re->first)) || match(re, (char *)str, prog, here); here++, len--) { if (len < re->minlen) return 0; } } /* if we didn't fail, then we must have succeeded */ return 1; } #else /* NO_MAGIC */ regexp *regcomp(exp) char *exp; { char *src; char *dest; regexp *re; int i; /* allocate a big enough regexp structure */ #ifdef lint re = (regexp *)0; #else re = (regexp *)malloc((unsigned)(strlen(exp) + 1 + sizeof(struct regexp))); #endif if (!re) { regerror("Could not malloc a regexp structure"); return (regexp *)0; } /* initialize all fields of the structure */ for (i = 0; i < NSUBEXP; i++) { re->startp[i] = re->endp[i] = (char *)0; } re->minlen = 0; re->first = 0; re->bol = 0; /* copy the string into it, translating ^ and $ as needed */ for (src = exp, dest = re->program + 1; *src; src++) { switch (*src) { case '^': if (src == exp) { re->bol += 1; } else { *dest++ = '^'; re->minlen++; } break; case '$': if (!src[1]) { re->bol += 2; } else { *dest++ = '$'; re->minlen++; } break; case '\\': if (src[1]) { *dest++ = *++src; re->minlen++; } else { regerror("extra \\ at end of regular expression"); } break; default: *dest++ = *src; re->minlen++; } } *dest = '\0'; return re; } /* This "helper" function checks for a match at a given location. It returns * 1 if it matches, 0 if it doesn't match here but might match later on in the * string, or -1 if it could not possibly match */ static int reghelp(prog, string, bolflag) struct regexp *prog; char *string; int bolflag; { char *scan; char *str; /* if ^, then require bolflag */ if ((prog->bol & 1) && !bolflag) { return -1; } /* if it matches, then it will start here */ prog->startp[0] = string; /* compare, possibly ignoring case */ if (*o_ignorecase) { for (scan = &prog->program[1]; *scan; scan++, string++) if (tolower(*scan) != tolower(*string)) return *string ? 0 : -1; } else { for (scan = &prog->program[1]; *scan; scan++, string++) if (*scan != *string) return *string ? 0 : -1; } /* if $, then require string to end here, too */ if ((prog->bol & 2) && *string) { return 0; } /* if we get to here, it matches */ prog->endp[0] = string; return 1; } int regexec(prog, string, bolflag) struct regexp *prog; char *string; int bolflag; { int rc; /* keep trying to match it */ for (rc = reghelp(prog, string, bolflag); rc == 0; rc = reghelp(prog, string, 0)) { string++; } /* did we match? */ return rc == 1; } #endif SHAR_EOF fi # end of overwriting check if test -f 'regsub.c' then echo shar: will not over-write existing file "'regsub.c'" else cat << \SHAR_EOF > 'regsub.c' /* regsub.c */ /* This file contains the regsub() function, which performs substitutions * after a regexp match has been found. */ #include <ctype.h> #include "config.h" #include "vi.h" #include "regexp.h" static char *previous; /* a copy of the text from the previous substitution */ /* perform substitutions after a regexp match */ void regsub(re, src, dst) regexp *re; REG char *src; REG char *dst; { REG char *cpy; REG char *end; REG char c; char *start; #ifndef CRUNCH int mod; mod = 0; #endif start = src; while ((c = *src++) != '\0') { #ifndef NO_MAGIC /* recognize any meta characters */ if (c == '&' && *o_magic) { cpy = re->startp[0]; end = re->endp[0]; } else if (c == '~' && *o_magic) { cpy = previous; if (cpy) end = cpy + strlen(cpy); } else #endif /* not NO_MAGIC */ if (c == '\\') { c = *src++; switch (c) { #ifndef NO_MAGIC case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* \0 thru \9 mean "copy subexpression" */ c -= '0'; cpy = re->startp[c]; end = re->endp[c]; break; # ifndef CRUNCH case 'U': case 'u': case 'L': case 'l': /* \U and \L mean "convert to upper/lowercase" */ mod = c; continue; case 'E': case 'e': /* \E ends the \U or \L */ mod = 0; continue; # endif /* not CRUNCH */ case '&': /* "\&" means "original text" */ if (*o_magic) { *dst++ = c; continue; } cpy = re->startp[0]; end = re->endp[0]; break; case '~': /* "\~" means "previous text, if any" */ if (*o_magic) { *dst++ = c; continue; } cpy = previous; if (cpy) end = cpy + strlen(cpy); break; #else /* NO_MAGIC */ case '&': /* "\&" means "original text" */ cpy = re->startp[0]; end = re->endp[0]; break; case '~': /* "\~" means "previous text, if any" */ cpy = previous; if (cpy) end = cpy + strlen(cpy); break; #endif /* NO_MAGIC */ default: /* ordinary char preceded by backslash */ *dst++ = c; continue; } } else { /* ordinary character, so just copy it */ *dst++ = c; continue; } /* Note: to reach this point in the code, we must have evaded * all "continue" statements. To do that, we must have hit * a metacharacter that involves copying. */ /* if there is nothing to copy, loop */ if (!cpy) continue; /* copy over a portion of the original */ while (cpy < end) { #ifndef NO_MAGIC # ifndef CRUNCH switch (mod) { case 'U': case 'u': /* convert to uppercase */ if (isascii(*cpy) && islower(*cpy)) { *dst++ = toupper(*cpy); cpy++; } else { *dst++ = *cpy++; } break; case 'L': case 'l': /* convert to lowercase */ if (isascii(*cpy) && isupper(*cpy)) { *dst++ = tolower(*cpy); cpy++; } else { *dst++ = *cpy++; } break; default: /* copy without any conversion */ *dst++ = *cpy++; } /* \u and \l end automatically after the first char */ if (mod && (mod == 'u' || mod == 'l')) { mod = 0; } # else /* CRUNCH */ *dst++ = *cpy++; # endif /* CRUNCH */ #else /* NO_MAGIC */ *dst++ = *cpy++; #endif /* NO_MAGIC */ } } *dst = '\0'; /* remember what text we inserted this time */ if (previous) free(previous); previous = (char *)malloc((unsigned)(strlen(start) + 1)); if (previous) strcpy(previous, start); } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # shell.c # sysdos.c # system.c # tinytcap.c # tio.c # tmp.c # tnamerec.c # This archive created: Thu Jan 10 17:21:10 1991 export PATH; PATH=/bin:$PATH if test -f 'shell.c' then echo shar: will not over-write existing file "'shell.c'" else cat << \SHAR_EOF > 'shell.c' /* shell.c */ /* Author: * Guntram Blohm * Buchenstrasse 19 * 7904 Erbach, West Germany * Tel. ++49-7305-6997 * sorry - no regular network connection */ /* * This file contains a minimal version of a shell for TOS. It allows the * setting of an environment, calling programs, and exiting. * If you don't have another one, this might be sufficient, but you should * prefer *any* other shell. * You may, however, want to set your SHELL environment variable to this * shell: it implements the -c switch, which is required by Elvis, and * not supported by most other atari shells. */ #include <stdio.h> #include <string.h> #include <osbind.h> extern char *getenv(), *malloc(); extern char **environ; long _stksize=16384; #define MAXENV 50 struct { char *name; char *value; } myenv[MAXENV]; int cmd_set(), cmd_exit(); struct buildins { char *name; int (*func)(); } buildins[]= { "exit", cmd_exit, "set", cmd_set, 0, }; main(argc, argv) int argc; char **argv; { char buf[128]; int i; for (i=0; environ[i] && strncmp(environ[i],"ARGV=",5); i++) cmd_set(environ[i]); script("profile.sh"); if (argc>1 && !strcmp(argv[1], "-c")) { buf[0]='\0'; for (i=2; i<argc; i++) { if (i>2) strcat(buf, " "); strcat(buf, argv[i]); } execute(buf); } else while (fputs("$ ", stdout), gets(buf)) execute(buf); } execute(buf) char *buf; { char *scan=buf; char cmd[80]; char line[128]; char env[4096], *ep=env; int i; while (*scan==' ') scan++; if (!*scan) return; while (*scan && *scan!=' ') scan++; if (*scan) *scan++='\0'; for (i=0; buildins[i].name; i++) if (!strcmp(buf, buildins[i].name)) return (*buildins[i].func)(scan); if (!searchpath(buf, cmd)) { printf("%s: not found\n", buf); return -1; } strcpy(line+1, scan); line[0]=strlen(scan); for (i=0; i<MAXENV && myenv[i].name; i++) { strcpy(ep, myenv[i].name); strcat(ep, "="); strcat(ep, myenv[i].value); ep+=strlen(ep)+1; } *ep='\0'; return Pexec(0, cmd, line, env); } searchpath(from, to) char *from, *to; { char *path=""; char *scan; char *end; char *q; int i; for (i=0; i<MAXENV && myenv[i].name; i++) if (!strcmp(myenv[i].name,"PATH")) path=myenv[i].value; for (scan=from; *scan; scan++) if (*scan==':' || *scan=='\\') { path=0; break; } if (!path) { strcpy(to, from); end=to+strlen(to); strcpy(end, ".prg"); if (try(to)) return 1; strcpy(end, ".ttp"); if (try(to)) return 1; strcpy(end, ".tos"); if (try(to)) return 1; *to='\0'; return 0; } for (scan=path; *scan; ) { for (q=to; *scan && *scan!=';' && *scan!=','; scan++) *q++=*scan; if (*scan==';' || *scan==',') scan++; *q++='\\'; *q='\0'; strcpy(q, from); end=q+strlen(q); strcpy(end, ".prg"); if (try(to)) return 1; strcpy(end, ".ttp"); if (try(to)) return 1; strcpy(end, ".tos"); if (try(to)) return 1; } *to='\0'; return 0; } try(name) char *name; { if (Fattrib(name, 0, 0) < 0) return 0; return 1; } cmd_exit() { exit(0); } cmd_set(line) char *line; { char *value; int i; if (!*line) { for (i=0; i<MAXENV && myenv[i].name; i++) printf("%s=%s\n", myenv[i].name, myenv[i].value); return 0; } for (value=line; *value && *value!='='; value++) ; if (!*value) { printf("Usage: set name=var\n"); return -1; } *value++='\0'; doset(line, value); } doset(line, value) char *line, *value; { int i; for (i=0; i<MAXENV && myenv[i].name && strcmp(myenv[i].name, line); i++) ; if (i==MAXENV) { printf("No Space\n"); return -1; } if (!myenv[i].name) { myenv[i].name=malloc(strlen(line)+1); strcpy(myenv[i].name, line); } if (myenv[i].value) free(myenv[i].value); myenv[i].value=malloc(strlen(value)+1); strcpy(myenv[i].value, value); return 0; } script(name) char *name; { FILE *fp; char buf[128], *p; if ((fp=fopen(name, "r"))==0) return; while (fgets(buf, sizeof buf, fp)) { if ((p=strchr(buf, '\n'))!=0) *p='\0'; execute(buf); } fclose(fp); } SHAR_EOF fi # end of overwriting check if test -f 'sysdos.c' then echo shar: will not over-write existing file "'sysdos.c'" else cat << \SHAR_EOF > 'sysdos.c' /* sysdos.c -- DOS version of system.c */ /* Author: * Guntram Blohm * Buchenstrasse 19 * 7904 Erbach, West Germany * Tel. ++49-7305-6997 * sorry - no regular network connection */ /* This file is derived from Steve Kirkendall's system.c. * * Entry points are: * system(cmd) - run a single shell command * wildcard(names) - expand wildcard characters in filanames * * This file is for use with DOS and TOS. For OS/2, slight modifications * might be sufficient. For UNIX, use system.c. For Amiga, completely * rewrite this stuff. * * Another system function, filter, is the same on DOS and UNIX and thus * can be found in the original system.c. */ #include "config.h" #include "vi.h" extern char **environ; #if MSDOS #include <process.h> extern unsigned char _osmajor; #endif #if TOS #include <osbind.h> #endif #if MSDOS || TOS #include <string.h> /* * Calling command is a bit nasty because of the undocumented yet sometimes * used feature to change the option char to something else than /. * Versions 2.x and 3.x support this, 4.x doesn't. * * For Atari, some shells define a shortcut entry which is faster than * shell -c. Also, Mark Williams uses a special ARGV environment variable * to pass more than 128 chars to a called command. * We try to support all of these features here. */ int system(cmd) const char *cmd; { #if MSDOS char *cmdswitch="/c"; if (_osmajor<4) cmdswitch[0]=switchar(); return spawnle(P_WAIT, o_shell, o_shell, cmdswitch, cmd, (char *)0, environ); #else long ssp; int (*shell)(); char line[130]; char env[4096], *ep=env; int i; /* does our shell have a shortcut, that we can use? */ ssp = Super(0L); shell = *((int (**)())0x4F6); Super(ssp); if (shell) return (*shell)(cmd); /* else we'll have to call a shell ... */ for (i=0; environ[i] && strncmp(environ[i], "ARGV=", 5); i++) { strcpy(ep, environ[i]); ep+=strlen(ep)+1; } if (environ[i]) { strcpy(ep, environ[i]); ep+=strlen(ep)+1; strcpy(ep, o_shell); ep+=strlen(ep)+1; strcpy(ep, "-c"); ep+=3; strcpy(ep, cmd); ep+=strlen(ep)+1; } *ep='\0'; strcpy(line+1, "-c "); strncat(line+1, cmd, 126); line[0]=strlen(line+1); return Pexec(0, o_shell, line, env); #endif } /* This private function opens a pipe from a filter. It is similar to the * system() function above, and to popen(cmd, "r"). * sorry - i cant use cmdstate until rpclose, but get it from spawnle. */ static int cmdstate; static char output[80]; int rpipe(cmd, in) char *cmd; /* the filter command to use */ int in; /* the fd to use for stdin */ { int fd, old0, old1, old2; /* create the file that will collect the filter's output */ strcpy(output, o_directory); if ((fd=strlen(output)) && !strchr("/\\:", output[fd-1])) output[fd++]=SLASH; strcpy(output+fd, SCRATCHIN+3); mktemp(output); close(creat(output, 0666)); if ((fd=open(output, O_RDWR))==-1) { unlink(output); return -1; } /* save and redirect stdin, stdout, and stderr */ old0=dup(0); old1=dup(1); if (in) { dup2(in, 0); close(in); } dup2(fd, 1); /* call command */ cmdstate=system(cmd); /* restore old std... */ dup2(old0, 0); close(old0); dup2(old1, 1); close(old1); /* rewind command output */ lseek(fd, 0L, 0); return fd; } /* This function closes the pipe opened by rpipe(), and returns 0 for success */ int rpclose(fd) int fd; { int status; close(fd); unlink(output); return cmdstate; } #endif SHAR_EOF fi # end of overwriting check if test -f 'system.c' then echo shar: will not over-write existing file "'system.c'" else cat << \SHAR_EOF > 'system.c' /* system.c -- UNIX version */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains a new version of the system() function and related stuff. * * Entry points are: * system(cmd) - run a single shell command * wildcard(names) - expand wildcard characters in filanames * filter(m,n,cmd) - run text lines through a filter program * * This is probably the single least portable file in the program. The code * shown here should work correctly if it links at all; it will work on UNIX * and any O.S./Compiler combination which adheres to UNIX forking conventions. */ #include "config.h" #include "vi.h" #include <signal.h> extern char **environ; #if ANY_UNIX /* This is a new version of the system() function. The only difference * between this one and the library one is: this one uses the o_shell option. */ int system(cmd) char *cmd; /* a command to run */ { int status; /* exit status of the command */ /* warn the user if the file hasn't been saved yet */ if (*o_warn && tstflag(file, MODIFIED)) { if (mode == MODE_VI) { mode = MODE_COLON; } msg("Warning: \"%s\" has been modified but not yet saved", origname); } signal(SIGINT, SIG_IGN); switch (fork()) { case -1: /* error */ msg("fork() failed"); status = -1; break; case 0: /* child */ /* for the child, close all files except stdin/out/err */ for (status = 3; status < 60 && (close(status), errno != EINVAL); status++) { } signal(SIGINT, SIG_DFL); if (cmd == o_shell) { execle(o_shell, o_shell, (char *)0, environ); } else { execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); } msg("execle(\"%s\", ...) failed", o_shell); exit(1); /* if we get here, the exec failed */ default: /* parent */ wait(&status); signal(SIGINT, trapint); } return status; } /* This private function opens a pipe from a filter. It is similar to the * system() function above, and to popen(cmd, "r"). */ static int rpipe(cmd, in) char *cmd; /* the filter command to use */ int in; /* the fd to use for stdin */ { int r0w1[2];/* the pipe fd's */ /* make the pipe */ if (pipe(r0w1) < 0) { return -1; /* pipe failed */ } /* The parent process (elvis) ignores signals while the filter runs. * The child (the filter program) will reset this, so that it can * catch the signal. */ signal(SIGINT, SIG_IGN); switch (fork()) { case -1: /* error */ return -1; case 0: /* child */ /* close the "read" end of the pipe */ close(r0w1[0]); /* redirect stdout to go to the "write" end of the pipe */ close(1); dup(r0w1[1]); close(2); dup(r0w1[1]); close(r0w1[1]); /* redirect stdin */ if (in != 0) { close(0); dup(in); close(in); } /* the filter should accept SIGINT signals */ signal(SIGINT, SIG_DFL); /* exec the shell to run the command */ execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); exit(1); /* if we get here, exec failed */ default: /* parent */ /* close the "write" end of the pipe */ close(r0w1[1]); return r0w1[0]; } } #endif /* non-DOS */ #if OSK /* This private function opens a pipe from a filter. It is similar to the * system() function above, and to popen(cmd, "r"). */ static int rpipe(cmd, in) char *cmd; /* the filter command to use */ int in; /* the fd to use for stdin */ { char **argblk; char *p, *buffer, *command; int stdinp, stdoutp; unsigned addstack = 0; int words, len, loop = 1; int fp, pipe_pid; extern int os9forkc(); extern char *index(); command = cmd; words = 0; if ((buffer = (char*) malloc(strlen(cmd))) == (char*) 0) return 0; do { if (!(p = index(command, ' '))) { loop--; len = strlen(command); } else len = p - command; words++; while (command[len] && command[len] == ' ') len++; if (!command[len]) break; command = command + len; } while (loop); if ((argblk = (char **)malloc((words+1) * sizeof(char*))) == (char **)0) return 0; command = cmd; words = 0; do { if (!(p = index(command, ' '))) { loop--; len = strlen(command); } else len = p - command; strncpy(buffer, command, len); argblk[words++] = buffer; buffer += len; *buffer++ = '\0'; while (command[len] && command[len] == ' ') len++; if (!command[len]) break; command = command + len; } while (loop); if (argblk[words - 1][0] == '#') addstack = 1024 * atoi(&argblk[--words][1]); argblk[words] = 0; stdoutp = dup(1); close(1); /* close stdout */ if ((fp = open("/pipe",S_IREAD)) < 0) { dup(stdoutp); close(stdoutp); return 0; } if (in != 0) { stdinp = dup(0); close(0); dup(in); close(in); } pipe_pid = os9exec(os9forkc,argblk[0],argblk,environ,addstack,0,3); if (pipe_pid == -1) { fclose(fp); dup(stdoutp); close(stdoutp); if (in != 0) { close(0); dup(stdinp); } return 0; } fp = (short)dup(1); /* save pipe */ close(1); /* get rid of the pipe */ dup(stdoutp); /* restore old stdout */ close(stdoutp); /* close path to stdout copy */ if (in != 0) { close(0); dup(stdinp); } return fp; } #endif #if ANY_UNIX || OSK /* This function closes the pipe opened by rpipe(), and returns 0 for success */ static int rpclose(fd) int fd; { int status; close(fd); wait(&status); signal(SIGINT, trapint); return status; } #endif /* non-DOS */ /* This function expands wildcards in a filename or filenames. It does this * by running the "echo" command on the filenames via the shell; it is assumed * that the shell will expand the names for you. If for any reason it can't * run echo, then it returns the names unmodified. */ #if MSDOS || TOS #define PROG "wildcard " #define PROGLEN 9 #include <string.h> #else #define PROG "echo " #define PROGLEN 5 #endif char *wildcard(names) char *names; { int i, j, fd; REG char *s, *d; /* build the echo command */ if (names != tmpblk.c) { /* the names aren't in tmpblk.c, so we can do it the easy way */ strcpy(tmpblk.c, PROG); strcat(tmpblk.c, names); } else { /* the names are already in tmpblk.c, so shift them to make * room for the word "echo " */ for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; ) { *--d = *--s; } strncpy(names, PROG, PROGLEN); } /* run the command & read the resulting names */ fd = rpipe(tmpblk.c, 0); if (fd < 0) return names; i = 0; do { j = tread(fd, tmpblk.c + i, BLKSIZE - i); i += j; } while (j > 0); /* successful? */ if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0) { tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */ return tmpblk.c; } else { return names; } } /* This function runs a range of lines through a filter program, and replaces * the original text with the filtered version. As a special case, if "to" * is MARK_UNSET, then it runs the filter program with stdin coming from * /dev/null, and inserts any output lines. */ int filter(from, to, cmd) MARK from, to; /* the range of lines to filter */ char *cmd; /* the filter command */ { int scratch; /* fd of the scratch file */ int fd; /* fd of the pipe from the filter */ char scrout[50]; /* name of the scratch out file */ MARK new; /* place where new text should go */ int i; /* write the lines (if specified) to a temp file */ if (to) { /* we have lines */ #if MSDOS || TOS strcpy(scrout, o_directory); if ((i=strlen(scrout)) && strchr("\\/:", scrout[i-1])) scrout[i++]=SLASH; strcpy(scrout+i, SCRATCHOUT+3); #else sprintf(scrout, SCRATCHOUT, o_directory); #endif mktemp(scrout); cmd_write(from, to, CMD_BANG, 0, scrout); /* use those lines as stdin */ scratch = open(scrout, O_RDONLY); if (scratch < 0) { unlink(scrout); return -1; } } else { scratch = 0; } /* start the filter program */ fd = rpipe(cmd, scratch); if (fd < 0) { if (to) { close(scratch); unlink(scrout); } return -1; } ChangeText { /* adjust MARKs for whole lines, and set "new" */ from &= ~(BLKSIZE - 1); if (to) { to &= ~(BLKSIZE - 1); to += BLKSIZE; new = to; } else { new = from + BLKSIZE; } /* repeatedly read in new text and add it */ while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0) { tmpblk.c[i] = '\0'; add(new, tmpblk.c); for (i = 0; tmpblk.c[i]; i++) { if (tmpblk.c[i] == '\n') { new = (new & ~(BLKSIZE - 1)) + BLKSIZE; } else { new++; } } } } /* delete old text, if any */ if (to) { delete(from, to); } /* Reporting... */ rptlabel = "more"; if (rptlines < 0) { rptlines = -rptlines; rptlabel = "less"; } /* cleanup */ rpclose(fd); if (to) { close(scratch); unlink(scrout); } return 0; } SHAR_EOF fi # end of overwriting check if test -f 'tinytcap.c' then echo shar: will not over-write existing file "'tinytcap.c'" else cat << \SHAR_EOF > 'tinytcap.c' /* tinytcap.c */ /* This file contains functions which simulate the termcap functions, but which * can only describe the capabilities of the ANSI.SYS and NANSI.SYS drivers on * an MS-DOS system or the VT-52 emulator of an Atari-ST. These functions * do *NOT* access a "termcap" database file. */ #include "config.h" #if MSDOS || TOS || MINIX || COHERENT #define CAP(str) CAP2((str)[0], (str)[1]) #define CAP2(a,b) (((a) << 8) + ((b) & 0xff)) #if MSDOS # define VAL2(v,a) (a) # define VAL3(v,a,n) (nansi ? (n) : (a)) static int nansi; #endif #if TOS # define VAL2(v,a) (v) # define VAL3(v,a,n) (v) #endif #if MINIX || COHERENT # define VAL2(v,a) (a) # define VAL3(v,a,n) (n) #endif /*ARGSUSED*/ int tgetent(bp, name) char *bp; /* buffer for storing the entry -- ignored */ char *name; /* name of the entry */ { #if MSDOS nansi = strcmp(name, "ansi"); #endif return 1; } int tgetnum(id) char *id; { switch (CAP(id)) { case CAP2('l','i'): return 25; case CAP2('c','o'): return 80; case CAP2('s','g'): return 0; case CAP2('u','g'): return 0; default: return -1; } } int tgetflag(id) char *id; { switch (CAP(id)) { #if !MINIX || COHERENT case CAP2('a','m'): return 1; #endif case CAP2('b','s'): return 1; case CAP2('m','i'): return 1; default: return 0; } } /*ARGSUSED*/ char *tgetstr(id, bp) char *id; char **bp; /* pointer to pointer to buffer - ignored */ { switch (CAP(id)) { case CAP2('c','e'): return VAL2("\033K", "\033[K"); case CAP2('c','l'): return VAL2("\033E", "\033[2J"); case CAP2('a','l'): return VAL3("\033L", (char *)0, "\033[L"); case CAP2('d','l'): return VAL3("\033M", (char *)0, "\033[M"); case CAP2('c','m'): return VAL2("\033Y%i%+ %+ ", "\033[%i%d;%dH"); case CAP2('d','o'): return VAL2("\033B", "\033[B"); case CAP2('n','d'): return VAL2("\033C", "\033[C"); case CAP2('u','p'): return VAL2("\033A", "\033[A"); case CAP2('t','i'): return VAL2("\033e", ""); case CAP2('t','e'): return VAL2("", ""); case CAP2('s','o'): return VAL2("\033p", "\033[7m"); case CAP2('s','e'): return VAL2("\033q", "\033[m"); case CAP2('u','s'): return VAL2((char *)0, "\033[4m"); case CAP2('u','e'): return VAL2((char *)0, "\033[m"); case CAP2('m','d'): return VAL2((char *)0, "\033[1m"); case CAP2('m','e'): return VAL2((char *)0, "\033[m"); #if MINIX || COHERENT case CAP2('k','u'): return "\033[A"; case CAP2('k','d'): return "\033[B"; case CAP2('k','l'): return "\033[D"; case CAP2('k','r'): return "\033[C"; case CAP2('k','P'): return "\033[V"; case CAP2('k','N'): return "\033[U"; case CAP2('k','h'): return "\033[H"; # if MINIX case CAP2('k','H'): return "\033[Y"; # else /* COHERENT */ case CAP2('k','H'): return "\033[24H"; # endif #else /* MS-DOS or TOS */ case CAP2('k','u'): return "#H"; case CAP2('k','d'): return "#P"; case CAP2('k','l'): return "#K"; case CAP2('k','r'): return "#M"; case CAP2('k','h'): return "#G"; case CAP2('k','H'): return "#O"; case CAP2('k','P'): return "#I"; case CAP2('k','N'): return "#Q"; #endif default: return (char *)0; } } /*ARGSUSED*/ char *tgoto(cm, destcol, destrow) char *cm; /* cursor movement string -- ignored */ int destcol;/* destination column, 0 - 79 */ int destrow;/* destination row, 0 - 24 */ { static char buf[30]; #if MSDOS || MINIX || COHERENT sprintf(buf, "\033[%d;%dH", destrow + 1, destcol + 1); #endif #if TOS sprintf(buf, "\033Y%c%c", ' ' + destrow, ' ' + destcol); #endif return buf; } /*ARGSUSED*/ void tputs(cp, affcnt, outfn) char *cp; /* the string to output */ int affcnt; /* number of affected lines -- ignored */ int (*outfn)(); /* the output function */ { while (*cp) { (*outfn)(*cp); cp++; } } #endif SHAR_EOF fi # end of overwriting check if test -f 'tio.c' then echo shar: will not over-write existing file "'tio.c'" else cat << \SHAR_EOF > 'tio.c' /* tio.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains terminal I/O functions */ #include "config.h" #if BSD || COHERENT # include <setjmp.h> #endif #include <signal.h> #include "vi.h" /* This function reads in a line from the terminal. */ int vgets(prompt, buf, bsize) char prompt; /* the prompt character, or '\0' for none */ char *buf; /* buffer into which the string is read */ int bsize; /* size of the buffer */ { int len; /* how much we've read so far */ int ch; /* a character from the user */ int quoted; /* is the next char quoted? */ int tab; /* column position of cursor */ char widths[132]; /* widths of characters */ #ifndef NO_DIGRAPH int erased; /* 0, or first char of a digraph */ #endif /* show the prompt */ move(LINES - 1, 0); tab = 0; if (prompt) { addch(prompt); tab = 1; } clrtoeol(); refresh(); /* read in the line */ #ifndef NO_DIGRAPH erased = #endif quoted = len = 0; for (;;) { ch = getkey(quoted ? 0 : WHEN_EX); /* some special conversions */ if (ch == ctrl('D') && len == 0) ch = ctrl('['); #ifndef NO_DIGRAPH if (*o_digraph && erased != 0 && ch != '\b') { ch = digraph(erased, ch); erased = 0; } #endif /* inhibit detection of special chars (except ^J) after a ^V */ if (quoted && ch != '\n') { ch |= 256; } /* process the character */ switch(ch) { case ctrl('V'): qaddch('^'); qaddstr("BC"); quoted = TRUE; break; case ctrl('['): return -1; case '\n': #if OSK case '\l': #else case '\r': #endif clrtoeol(); goto BreakBreak; case '\b': if (len > 0) { int b; len--; #ifndef NO_DIGRAPH erased = buf[len]; #endif for (b = 8 - widths[len]; b < 8; b++) { qaddstr(BC); } if (mode == MODE_EX) { clrtoeol(); } tab -= widths[len]; } else { return -1; } break; default: /* strip off quotation bit */ if (ch & 256) { ch &= ~256; quoted = FALSE; qaddch(' '); qaddstr(BC); } /* add & echo the char */ if (len < bsize - 1) { if (ch == '\t') { widths[len] = *o_tabstop - (tab % *o_tabstop); addstr(" " + 8 - widths[len]); tab += widths[len]; } else if (ch > 0 && ch < ' ') /* > 0 by GB */ { addch('^'); addch(ch + '@'); widths[len] = 2; tab += 2; } else if (ch == '\177') { addch('^'); addch('?'); widths[len] = 2; tab += 2; } else { addch(ch); widths[len] = 1; tab++; } buf[len++] = ch; } else { Beep(); } } } BreakBreak: refresh(); buf[len] = '\0'; return len; } /* ring the terminal's bell */ void beep() { if (*o_vbell) { do_VB(); refresh(); } else if (*o_errorbells) { ttywrite("\007", 1); } } static int manymsgs; /* This variable keeps msgs from overwriting each other */ static char pmsg[80]; /* previous message (waiting to be displayed) */ /*- The Appendmsg() and Rendermsg() macros exist to isolate the mechanics behind displaying something on the msg line. this is to accomodate window versions of elvis which may display the message line somewhere other than the main editing window. appendmsg() and rendermsg() are the simple tty based versions of Rendermsg() and Appendmsg(). See wconfig.h for what Rendermsg and Appendmsg are defined as. Note that they must stay non-static this is so window versions can use them if they must fall back on using the tty they were started from - MCH */ int appendmsg(orig, new) char *orig, *new; { # ifdef lint orig = orig; /* orig param unused by tty version */ # endif qaddstr(new); refresh(); return 0; } int rendermsg(msgtxt) char *msgtxt; { move(LINES - 1, 0); if (*msgtxt) { standout(); qaddch(' '); qaddstr(msgtxt); qaddch(' '); standend(); } clrtoeol(); return 0; } static int showmsg() { /* if there is no message to show, then don't */ if (!manymsgs) return FALSE; Rendermsg(pmsg); /* does the actual rendering */ manymsgs = FALSE; return TRUE; } void endmsgs() { if (manymsgs) { showmsg(); addch('\n'); } } /* Write a message in an appropriate way. This should really be a varargs * function, but there is no such thing as vwprintw. Hack!!! * * In MODE_EX or MODE_COLON, the message is written immediately, with a * newline at the end. * * In MODE_VI, the message is stored in a character buffer. It is not * displayed until getkey() is called. msg() will call getkey() itself, * if necessary, to prevent messages from being lost. * * msg("") - clears the message line * msg("%s %d", ...) - does a printf onto the message line */ #ifdef NO_VSPRINTF /* use this *only* if you do not have vsprintf this is dangerous on things like a sparc chip - MCH */ /*VARARGS1*/ void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) char *fmt; long arg1, arg2, arg3, arg4, arg5, arg6, arg7; { if (mode != MODE_VI) { sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7); qaddstr(pmsg); addch('\n'); exrefresh(); } else { /* wait for keypress between consecutive msgs */ if (manymsgs) { getkey(WHEN_MSG); } /* real message */ sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7); manymsgs = TRUE; } } #else #include <varargs.h> void msg(va_alist) va_dcl { char *fmt; va_list args; va_start(args); fmt = va_arg(args, char *); if (mode != MODE_VI) { vsprintf(pmsg, fmt, args); qaddstr(pmsg); addch('\n'); exrefresh(); } else { /* wait for keypress between consecutive msgs */ if (manymsgs) { getkey(WHEN_MSG); } /* real message */ vsprintf(pmsg, fmt, args); manymsgs = TRUE; } va_end(args); return; } #endif /* This function calls refresh() if the option exrefresh is set */ void exrefresh() { char *scan; /* If this ex command wrote ANYTHING set exwrote so vi's : command * can tell that it must wait for a user keystroke before redrawing. */ for (scan=kbuf; scan<stdscr; scan++) if (*scan == '\n') exwrote = TRUE; #if MICROSOFT /* avoid compiler bug */ scan = stdscr; #define stdscr scan #endif /* now we do the refresh thing */ if (*o_exrefresh) { refresh(); } else { wqrefresh(stdscr); } #if MICROSOFT #undef stdscr stdscr = scan; #endif if (mode != MODE_VI) { manymsgs = FALSE; } } /* These are used for typeahead, and also for fudging the visual @ command */ static char keybuf[100]; /* array of already-read keys */ static int nkeys; /* total number of keys in keybuf */ static int next; /* index of next key to return */ #ifndef NO_AT static int atnext; /* index of next key for "@", or 0 normally */ int fromcutbuf(cbname) int cbname; { int len; /* fail if we're already doing an @ macro */ if (atnext > 0 && keybuf[atnext]) { msg("Can't nest @ commands"); return FALSE; } /* use the empty portion of keybuf[] to get chars from the cut buffer */ len = cb2str(cbname, keybuf + nkeys, sizeof keybuf - nkeys); if (len < 0) { msg("Invalid cut buffer name. Must be a-z"); return FALSE; } if (len == 0) { msg("Cut buffer \"%c is empty", cbname); return FALSE; } else if (len >= sizeof keybuf - nkeys) { msg("Cut buffer \"%c is too large to execute", cbname); return FALSE; } /* prepare to "read" those keys on subsequent getkey() calls */ atnext = nkeys; return TRUE; } #endif /* This array describes mapped key sequences */ static struct _keymap { char *name; /* name of the key, or NULL */ char rawin[LONGKEY]; /* the unmapped version of input */ char cooked[80]; /* the mapped version of input */ int len; /* length of the unmapped version */ int when; /* when is this key mapped? */ } mapped[MAXMAPS]; #if !MSDOS && !TOS # if BSD || COHERENT static jmp_buf env_timeout; static int dummy() { longjmp(env_timeout, 1); return 0; } # else static int dummy() { } # endif #endif /* This function reads in a keystroke for VI mode. It automatically handles * key mapping. */ int getkey(when) int when; /* which bits must be ON? */ { static char *cooked; /* rawin, or pointer to converted key */ static int oldwhen; /* "when" from last time */ static int oldleft; static long oldtop; static long oldnlines; static char *cshape; /* current cursor shape */ REG char *kptr; /* &keybuf[next] */ REG struct _keymap *km; /* used to count through keymap */ REG int i, j, k; #ifdef DEBUG watch(); #endif /* if this key is needed for delay between multiple error messages, * then reset the manymsgs flag and abort any mapped key sequence. */ if (showmsg()) { if (when == WHEN_MSG) { Appendmsg(pmsg, "[More...]"); cooked = (char *)0; } else if (when == WHEN_VIINP || when == WHEN_VIREP) { redraw(cursor, TRUE); } } #ifndef NO_AT /* if we're in the middle of a visual @ macro, take atnext */ if (atnext > 0) { if (keybuf[atnext]) { return keybuf[atnext++]; } atnext = 0; } #endif /* if we're doing a mapped key, get the next char */ if (cooked && *cooked) { return *cooked++; } /* if keybuf is empty, fill it */ if (next == nkeys) { #ifndef NO_CURSORSHAPE /* make sure the cursor is the right shape */ if (has_CQ) { cooked = cshape; switch (when) { case WHEN_EX: cooked = CX; break; case WHEN_VICMD: cooked = CV; break; case WHEN_VIINP: cooked = CI; break; case WHEN_VIREP: cooked = CR; break; } if (cooked != cshape) { cshape = cooked; switch (when) { case WHEN_EX: do_CX(); break; case WHEN_VICMD: do_CV(); break; case WHEN_VIINP: do_CI(); break; case WHEN_VIREP: do_CR(); break; } } cooked = (char *)0; } #endif #ifndef NO_SHOWMODE /* if "showmode" then say which mode we're in */ if (*o_smd && mode == MODE_VI && (when != oldwhen || topline != oldtop || leftcol != oldleft || nlines != oldnlines)) { oldwhen = when; oldtop = topline; oldleft = leftcol; oldnlines = nlines; if (when & WHEN_VICMD) { redraw(cursor, FALSE); move(LINES - 1, COLS - 10); standout(); addstr("Command"); standend(); redraw(cursor, FALSE); } else if (when & WHEN_VIINP) { redraw(cursor, TRUE); move(LINES - 1, COLS - 10); standout(); addstr(" Input "); standend(); redraw(cursor, TRUE); } else if (when & WHEN_VIREP) { redraw(cursor, TRUE); move(LINES - 1, COLS - 10); standout(); addstr("Replace"); standend(); redraw(cursor, TRUE); } } else #endif /* redraw if getting a VI command */ if (when & WHEN_VICMD) { redraw(cursor, FALSE); } /* read the rawin keystrokes */ refresh(); while ((nkeys = ttyread(keybuf, sizeof keybuf)) < 0) { /* terminal was probably resized */ *o_lines = LINES; *o_columns = COLS; if (when & (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)) { redraw(MARK_UNSET, FALSE); redraw(cursor, (when & WHEN_VICMD) == 0); refresh(); } } next = 0; /* if nkeys == 0 then we've reached EOF of an ex script. */ if (nkeys == 0) { tmpabort(TRUE); move(LINES - 1, 0); clrtoeol(); refresh(); endwin(); exit(1); } } /* see how many mapped keys this might be */ kptr = &keybuf[next]; for (i = j = 0, k = -1, km = mapped; i < MAXMAPS; i++, km++) { if ((km->when & when) && km->len > 0 && *km->rawin == *kptr) { if (km->len > nkeys - next) { if (!strncmp(km->rawin, kptr, nkeys - next)) { j++; } } else { if (!strncmp(km->rawin, kptr, km->len)) { j++; k = i; } } } } /* if more than one, try to read some more */ while (j > 1) { #if BSD || COHERENT if (setjmp(env_timeout)) { /* we timed out - assume no mapping */ j = 0; break; } #endif #if ANY_UNIX signal(SIGALRM, dummy); #endif #if OSK signal(SIGQUIT, dummy); #endif alarm((unsigned)*o_keytime); i = nkeys; if ((k = ttyread(keybuf + nkeys, sizeof keybuf - nkeys)) >= 0) { nkeys += k; } alarm(0); #if OSK # ifndef DEBUG signal(SIGQUIT, SIG_IGN); # endif #endif /* if we couldn't read any more, pretend 0 mapped keys */ if (i == nkeys) { j = 0; } else /* else we got some more - try again */ { for (i = j = 0, k = -1, km = mapped; i < MAXMAPS; i++, km++) { if ((km->when & when) && km->len > 0 && *km->rawin == *kptr) { if (km->len > nkeys - next) { if (!strncmp(km->rawin, kptr, nkeys - next)) { j++; } } else { if (!strncmp(km->rawin, kptr, km->len)) { j++; k = i; } } } } } } /* if unambiguously mapped key, use it! */ if (j == 1 && k >= 0) { next += mapped[k].len; cooked = mapped[k].cooked; #ifndef NO_EXTENSIONS if ((when & (WHEN_VIINP|WHEN_VIREP)) && (mapped[k].when & WHEN_INMV)) { return 0; /* special case, means "a movement char follows" */ } else #endif { return *cooked++; } } else /* assume key is unmapped, but still translate weird erase key to '\b' */ if (keybuf[next] == ERASEKEY && when != 0) { next++; return '\b'; } else if (keybuf[next] == '\0') { next++; return ('A' & 0x1f); } else { return keybuf[next++]; } } /* This function maps or unmaps a key */ void mapkey(rawin, cooked, when, name) char *rawin; /* the input key sequence, before mapping */ char *cooked;/* after mapping */ short when; /* bitmap of when mapping should happen */ char *name; /* name of the key, if any */ { int i, j; #ifndef NO_EXTENSIONS /* if the mapped version starts with the word "visual" then set WHEN_INMV */ if (!strncmp(cooked, "visual ", 7)) { when |= WHEN_INMV; cooked += 7; } /* if WHEN_INMV is set, then WHEN_VIINP and WHEN_VIREP must be set */ if (when & WHEN_INMV) { when |= (WHEN_VIINP | WHEN_VIREP); } #endif /* see if the key sequence was mapped before */ j = strlen(rawin); for (i = 0; i < MAXMAPS; i++) { if (mapped[i].len == j && !strncmp(mapped[i].rawin, rawin, j) && (mapped[i].when & when)) { break; } } /* if not already mapped, then try to find a new slot to use */ if (i == MAXMAPS) { for (i = 0; i < MAXMAPS && mapped[i].len > 0; i++) { } } /* no room for the new key? */ if (i == MAXMAPS) { msg("No room left in the key map table"); return; } /* map the key */ if (cooked && *cooked) { /* Map the key */ mapped[i].len = j; strncpy(mapped[i].rawin, rawin, j); strcpy(mapped[i].cooked, cooked); mapped[i].when = when; mapped[i].name = name; } else /* unmap the key */ { mapped[i].len = 0; } } /* Dump keys of a given type - WHEN_VICMD dumps the ":map" keys, and * WHEN_VIINP|WHEN_VIREP dumps the ":map!" keys */ void dumpkey(when) int when; /* WHEN_XXXX of mappings to be dumped */ { int i, len, mlen; char *scan; char *mraw; for (i = 0; i < MAXMAPS; i++) { /* skip unused entries, or entries that don't match "when" */ if (mapped[i].len <= 0 || !(mapped[i].when & when)) { continue; } /* dump the key label, if any */ len = 8; if (mapped[i].name) { qaddstr(mapped[i].name); len -= strlen(mapped[i].name); } do { qaddch(' '); } while (len-- > 0); /* dump the raw version */ len = 0; mlen = mapped[i].len; mraw = mapped[i].rawin; for (scan = mraw; scan < mraw + mlen; scan++) { if (UCHAR(*scan) < ' ' || *scan == '\177') { qaddch('^'); qaddch(*scan ^ '@'); len += 2; } else { qaddch(*scan); len++; } } do { qaddch(' '); } while (++len < 8); /* dump the mapped version */ #ifndef NO_EXTENSIONS if ((mapped[i].when & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP))) { qaddstr("visual "); } #endif for (scan = mapped[i].cooked; *scan; scan++) { if (UCHAR(*scan) < ' ' || *scan == '\177') { qaddch('^'); qaddch(*scan ^ '@'); } else { qaddch(*scan); } } addch('\n'); exrefresh(); } } #ifndef MKEXRC /* This function saves the current configuration of mapped keys to a file */ void savekeys(fd) int fd; /* file descriptor to save them to */ { int i; char buf[80]; /* now write a map command for each key other than the arrows */ for (i = 0; i < MAXMAPS; i++) { /* ignore keys that came from termcap */ if (mapped[i].name) { continue; } /* If this isn't used, ignore it */ if (mapped[i].len <= 0) { continue; } /* write the map command */ #ifndef NO_EXTENSIONS if (mapped[i].when & WHEN_INMV) { #if OSK char fmt[80]; sprintf(fmt, "map%%s %%.%ds %%s\n", mapped[i].len); sprintf(buf, fmt, (mapped[i].when & WHEN_VICMD) ? "" : "!", #else sprintf(buf, "map%s %.*s visual %s\n", (mapped[i].when & WHEN_VICMD) ? "" : "!", mapped[i].len, #endif mapped[i].rawin, mapped[i].cooked); twrite(fd, buf, strlen(buf)); } else #endif { if (mapped[i].when & WHEN_VICMD) { #if OSK char fmt[80]; sprintf(fmt, "map %%.%ds %%s\n", mapped[i].len); sprintf(buf, fmt, #else sprintf(buf, "map %.*s %s\n", mapped[i].len, #endif mapped[i].rawin, mapped[i].cooked); twrite(fd, buf, strlen(buf)); } if (mapped[i].when & (WHEN_VIINP | WHEN_VIREP)) { #if OSK char fmt[80]; sprintf(fmt, "map! %%.%ds %%s\n", mapped[i].len); sprintf(buf, fmt, #else sprintf(buf, "map! %.*s %s\n", mapped[i].len, #endif mapped[i].rawin, mapped[i].cooked); twrite(fd, buf, strlen(buf)); } } } } #endif SHAR_EOF fi # end of overwriting check if test -f 'tmp.c' then echo shar: will not over-write existing file "'tmp.c'" else cat << \SHAR_EOF > 'tmp.c' /* tmpfile.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains functions which create & readback a TMPFILE */ #include "config.h" #include <ctype.h> #include "vi.h" #if TOS # include <stat.h> #else # if OSK # include "osk.h" # else # include <sys/stat.h> # endif #endif #ifndef NO_MODELINE static void do_modeline(l, stop) long l; /* line number to start at */ long stop; /* line number to stop at */ { char *str; /* used to scan through the line */ char *start; /* points to the start of the line */ char buf[80]; /* if modelines are disabled, then do nothing */ if (!*o_modeline) { return; } /* for each line... */ for (l = 1; l <= stop; l++) { /* for each position in the line.. */ for (str = fetchline(l); *str; str++) { /* if it is the start of a modeline command... */ if ((str[0] == 'e' && str[1] == 'x' || str[0] == 'v' && str[1] == 'i') && str[2] == ':') { start = str += 3; /* find the end */ while (*str && *str != ':') { str++; } /* if it is a well-formed modeline, execute it */ if (*str && str - start < sizeof buf) { strncpy(buf, start, (int)(str - start)); buf[str - start] = '\0'; doexcmd(buf); break; } } } } } #endif /* The FAIL() macro prints an error message and then exits. */ #define FAIL(why,arg) mode = MODE_EX; msg(why, arg); endwin(); exit(9) /* This is the name of the temp file */ static char tmpname[MAXTMPNAMELEN]; /* This function creates the temp file and copies the original file into it. * Returns if successful, or stops execution if it fails. */ int tmpstart(filename) char *filename; /* name of the original file */ { int origfd; /* fd used for reading the original file */ struct stat statb; /* stat buffer, used to examine inode */ REG BLK *this; /* pointer to the current block buffer */ REG BLK *next; /* pointer to the next block buffer */ int inbuf; /* number of characters in a buffer */ int nread; /* number of bytes read */ REG int j, k; int i; int sum; /* used for calculating a checksum for this */ char *scan; long nbytes; /* switching to a different file certainly counts as a change */ changes++; redraw(MARK_UNSET, FALSE); /* open the original file for reading */ *origname = '\0'; if (filename && *filename) { strcpy(origname, filename); origfd = open(origname, O_RDONLY); if (origfd < 0 && errno != ENOENT) { msg("Can't open \"%s\"", origname); return Tmpstart(""); } if (origfd >= 0) { if (stat(origname, &statb) < 0) { FAIL("Can't stat \"%s\"", origname); } #if TOS if (origfd >= 0 && (statb.st_mode & S_IJDIR)) #else # if OSK if (origfd >= 0 && (statb.st_mode & S_IFDIR)) # else if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG) # endif #endif { msg("\"%s\" is not a regular file", origname); return Tmpstart(""); } } else { stat(".", &statb); } if (origfd >= 0) { origtime = statb.st_mtime; #if MSDOS || OSK if (*o_readonly || !(statb.st_mode & S_IWRITE)) #endif #if TOS if (*o_readonly || (statb.st_mode & S_IJRON)) #endif #if ANY_UNIX if (*o_readonly || !(statb.st_mode & (statb.st_uid != geteuid() ? 0022 : 0200))) #endif { setflag(file, READONLY); } } else { origtime = 0L; } } else { setflag(file, NOFILE); origfd = -1; origtime = 0L; stat(".", &statb); } /* generate a checksum from the file's name */ for (sum = 0, scan = origname + strlen(origname); --scan >= origname && (isascii(*scan) && isalnum(*scan) || *scan == '.'); sum = sum + *scan) { } sum &= 0xf; /* make a name for the tmp file */ #if MSDOS || TOS /* MS-Dos doesn't allow multiple slashes, but supports drives * with current directories. * This relies on TMPNAME beginning with "%s\\"!!!! */ strcpy(tmpname, o_directory); if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1])) tmpname[i++]=SLASH; sprintf(tmpname+i, TMPNAME+3, sum, statb.st_ino, statb.st_dev); #else /* throw the pid into the name so we can edit the same file more * than once MCH */ sprintf(tmpname, TMPNAME, o_directory, sum, statb.st_ino, statb.st_dev, getpid()); #endif /* make sure nobody else is editing the same file */ if (access(tmpname, 0) == 0) { if (*origname) { msg("\"%s\" is busy", filename); return Tmpstart(""); } FAIL("\"%s\" is busy", filename); } /* create the temp file */ #if ANY_UNIX close(creat(tmpname, 0600)); /* only we can read it */ #else close(creat(tmpname, FILEPERMS)); /* anybody body can read it, alas */ #endif tmpfd = open(tmpname, O_RDWR | O_BINARY); if (tmpfd < 0) { FAIL("Can't create temporary file, errno=%d", errno); return 1; } /* allocate space for the header in the file */ write(tmpfd, hdr.c, (unsigned)BLKSIZE); #ifndef NO_RECYCLE /* initialize the block allocator */ /* This must already be done here, before the first attempt * to write to the new file! GB */ garbage(); #endif /* initialize lnum[] */ for (i = 1; i < MAXBLKS; i++) { lnum[i] = INFINITY; } lnum[0] = 0; /* if there is no original file, then create a 1-line file */ if (origfd < 0) { hdr.n[0] = 0; /* invalid inode# denotes new file */ this = blkget(1); /* get the new text block */ strcpy(this->c, "\n"); /* put a line in it */ lnum[1] = 1L; /* block 1 ends with line 1 */ nlines = 1L; /* there is 1 line in the file */ nbytes = 1L; if (*origname) { msg("\"%s\" [NEW FILE] 1 line, 1 char", origname); } else { msg("\"[NO FILE]\" 1 line, 1 char"); } } else /* there is an original file -- read it in */ { hdr.n[0] = statb.st_ino; nbytes = nlines = 0; /* preallocate 1 "next" buffer */ i = 1; next = blkget(i); inbuf = 0; /* loop, moving blocks from orig to tmp */ for (;;) { /* "next" buffer becomes "this" buffer */ this = next; /* read [more] text into this block */ nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf); if (nread < 0) { close(origfd); close(tmpfd); tmpfd = -1; unlink(tmpname); FAIL("Error reading \"%s\"", origname); } /* convert NUL characters to something else */ for (k = inbuf; k < inbuf + nread; k++) { if (!this->c[k]) { setflag(file, HADNUL); this->c[k] = 0x80; } } inbuf += nread; /* if the buffer is empty, quit */ if (inbuf == 0) { goto FoundEOF; } #if MSDOS || TOS /* BAH! MS text mode read fills inbuf, then compresses eliminating \r but leaving garbage at end of buf. The same is true for TURBOC. GB. */ memset(this->c + inbuf, '\0', BLKSIZE - inbuf); #endif /* search backward for last newline */ for (k = inbuf; --k >= 0 && this->c[k] != '\n';) { } if (k++ < 0) { if (inbuf >= BLKSIZE - 1) { k = 80; } else { k = inbuf; } } /* allocate next buffer */ next = blkget(++i); /* move fragmentary last line to next buffer */ inbuf -= k; for (j = 0; k < BLKSIZE; j++, k++) { next->c[j] = this->c[k]; this->c[k] = 0; } /* if necessary, add a newline to this buf */ for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; ) { } if (this->c[k] != '\n') { setflag(file, ADDEDNL); this->c[k + 1] = '\n'; } /* count the lines in this block */ for (k = 0; k < BLKSIZE && this->c[k]; k++) { if (this->c[k] == '\n') { nlines++; } nbytes++; } lnum[i - 1] = nlines; } FoundEOF: /* if this is a zero-length file, add 1 line */ if (nlines == 0) { this = blkget(1); /* get the new text block */ strcpy(this->c, "\n"); /* put a line in it */ lnum[1] = 1; /* block 1 ends with line 1 */ nlines = 1; /* there is 1 line in the file */ nbytes = 1; } #if MSDOS || TOS /* each line has an extra CR that we didn't count yet */ nbytes += nlines; #endif /* report the number of lines in the file */ msg("\"%s\" %s %ld line%s, %ld char%s", origname, (tstflag(file, READONLY) ? "[READONLY]" : ""), nlines, nlines == 1 ? "" : "s", nbytes, nbytes == 1 ? "" : "s"); } /* initialize the cursor to start of line 1 */ cursor = MARK_FIRST; /* close the original file */ close(origfd); /* any other messages? */ if (tstflag(file, HADNUL)) { msg("This file contained NULs. They've been changed to \\x80 chars"); } if (tstflag(file, ADDEDNL)) { msg("Newline characters have been inserted to break up long lines"); } #ifndef NO_MODELINE if (nlines > 10) { do_modeline(1L, 5L); do_modeline(nlines - 4L, nlines); } else { do_modeline(1L, nlines); } #endif return 0; } /* This function copies the temp file back onto an original file. * Returns TRUE if successful, or FALSE if the file could NOT be saved. */ int tmpsave(filename, bang) char *filename; /* the name to save it to */ int bang; /* forced write? */ { int fd; /* fd of the file we're writing to */ REG int len; /* length of a text block */ REG BLK *this; /* a text block */ long bytes; /* byte counter */ REG int i; /* if no filename is given, assume the original file name */ if (!filename || !*filename) { filename = origname; } /* if still no file name, then fail */ if (!*filename) { msg("Don't know a name for this file -- NOT WRITTEN"); return FALSE; } /* can't rewrite a READONLY file */ if (!strcmp(filename, origname) && *o_readonly && !bang) { msg("\"%s\" [READONLY] -- NOT WRITTEN", filename); return FALSE; } /* open the file */ if (*filename == '>' && filename[1] == '>') { filename += 2; while (*filename == ' ' || *filename == '\t') { filename++; } #ifdef O_APPEND fd = open(filename, O_WRONLY|O_APPEND); #else fd = open(filename, O_WRONLY); lseek(fd, 0L, 2); #endif } else { /* either the file must not exist, or it must be the original * file, or we must have a bang */ if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang) { msg("File already exists - Use :w! to overwrite"); return FALSE; } fd = creat(filename, FILEPERMS); } if (fd < 0) { msg("Can't write to \"%s\" -- NOT WRITTEN", filename); return FALSE; } /* write each text block to the file */ bytes = 0L; for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++) { for (len = 0; len < BLKSIZE && this->c[len]; len++) { } twrite(fd, this->c, len); bytes += len; } /* reset the "modified" flag */ clrflag(file, MODIFIED); significant = FALSE; /* report lines & characters */ #if MSDOS || TOS bytes += nlines; /* for the inserted carriage returns */ #endif if (strncmp(filename, o_directory, strlen(o_directory))) { msg("Wrote \"%s\" %ld lines, %ld characters", filename, nlines, bytes); } /* close the file */ close(fd); return TRUE; } /* This function deletes the temporary file. If the file has been modified * and "bang" is FALSE, then it returns FALSE without doing anything; else * it returns TRUE. * * If the "autowrite" option is set, then instead of returning FALSE when * the file has been modified and "bang" is false, it will call tmpend(). */ int tmpabort(bang) int bang; { /* if there is no file, return successfully */ if (tmpfd < 0) { return TRUE; } /* see if we must return FALSE -- can't quit */ if (!bang && tstflag(file, MODIFIED)) { /* if "autowrite" is set, then act like tmpend() */ if (*o_autowrite) return tmpend(bang); else return FALSE; } /* delete the tmp file */ cutswitch(tmpname); close(tmpfd); tmpfd = -1; unlink(tmpname); strcpy(prevorig, origname); prevline = markline(cursor); *origname = '\0'; origtime = 0L; blkinit(); nlines = 0; initflags(); return TRUE; } /* This function saves the file if it has been modified, and then deletes * the temporary file. Returns TRUE if successful, or FALSE if the file * needs to be saved but can't be. When it returns FALSE, it will not have * deleted the tmp file, either. */ int tmpend(bang) int bang; { /* save the file if it has been modified */ if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang) { return FALSE; } /* delete the tmp file */ tmpabort(TRUE); return TRUE; } /* If the tmp file has been changed, then this function will force those * changes to be written to the disk, so that the tmp file will survive a * system crash or power failure. */ #if MSDOS || TOS || OSK sync() { # if OSK /* OS9 doesn't need an explicit sync operation, but the linker * demands something called sync(), so this is a dummy function. */ #else /* MS-DOS and TOS don't flush their buffers until the file is closed, * so here we close the tmp file and then immediately reopen it. */ close(tmpfd); tmpfd = open(tmpname, O_RDWR | O_BINARY); #endif } #endif SHAR_EOF fi # end of overwriting check if test -f 'tnamerec.c' then echo shar: will not over-write existing file "'tnamerec.c'" else cat << \SHAR_EOF > 'tnamerec.c' #include "config.h" # if SUNOS || UNIXV /* systems using X/OPEN type directory routines */ # define USING_DIRENT 1 # define USING_DIRECT 0 # include <dirent.h> # endif /* not implemented yet, should be real easy to do though just hack the X/OPEN style version */ # if 0 /* put systems using struct direct here, 4.2 etc.. */ # define USING_DIRENT 0 # define USING_DIRECT 1 # endif # endif #if MSDOS || TOS # define NO_PID_IN_TMP_NAME 1 # define USING_DIRENT 0 # define USING_DIRECT 0 #endif /* int tnamerec(template) * char *template; * ==== * Find the true name of a temp file given a template which has nonsense * in the pid portion (the part after the dash) * This is mainly for use by virec program * ==== * -2 indicates the argument supplied is malformed * -1 indicates tmp file with the supplied template was not found * 0 indicates the argument has been converted properly * >0 indicates an argument has been converted OK but there is more * than one tmp file which matches the template * ==== * As a side effect , template is modified to contain the last filename * that matched template. * ==== * note: this module is highly dependent on TMPNAME #define in config.h */ #ifdef NO_PID_IN_TMPNAME int tnamerec(template) char *template; { return 0; } #endif #if USING_DIRENT || USING_DIRECT int tnamerec(template) char *template; { # if USING_DIRECT {{{{{{{{ to be done # endif # if USING_DIRENT DIR *dirp; struct dirent *entry; # endif extern char *strrchr(); int c; char *p; char *suff; int count = -1; int cmplen; if ( !(p = strrchr(template, '/'))) return -2; if (!(suff = strrchr(p, '-'))) return -2; cmplen = suff - p; c = *p; *p = '\0'; /* temporarily truncate off the filename */ if (!(dirp = opendir(template))) { *p = c; return -1; } *p++ = c; /* put filename back on */ /* scan the directory looking for a file which matches 'template' if the two are the same length and the stuff up to the dash is the same and the suffix is a number it's a match */ # if USING_DIRECT {{{{{to_be_done{{{{ # endif # if USING_DIRENT for (entry = readdir(dirp); entry; entry = readdir(dirp)) { if ( !strncmp(entry->d_name, p, cmplen) && (strlen(p) == strlen(entry->d_name)) ) { char *ext_suff = strchr(entry->d_name, '-'); if (ext_suff && atoi((ext_suff+1)) > 0) { strcpy(p, entry->d_name); count++; } } } return count; # endif } #endif SHAR_EOF fi # end of overwriting check # End of shell archive exit 0
mh@roger.imsd.contel.com (Mike H.) (01/11/91)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # vars.c # vcmd.c # vi.c # virec.c # wildcard.c # This archive created: Thu Jan 10 17:21:11 1991 export PATH; PATH=/bin:$PATH if test -f 'vars.c' then echo shar: will not over-write existing file "'vars.c'" else cat << \SHAR_EOF > 'vars.c' /* vars.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains variables which weren't happy anyplace else */ #include "config.h" #include "vi.h" /*------------------------------------------------------------------------*/ /* used to remember whether the file has been modified */ struct _viflags viflags; /* used to access the tmp file */ long lnum[MAXBLKS]; long nlines; int tmpfd = -1; /* used to keep track of the current file & alternate file */ long origtime; char origname[256]; char prevorig[256]; long prevline = 1; /* used to track various places in the text */ MARK mark[NMARKS]; /* marks 'a through 'z, plus mark '' */ MARK cursor; /* the cursor position within the file */ /* which mode of the editor we're in */ int mode; /* vi mode? ex mode? quitting? */ /* used to manage the args list */ char args[BLKSIZE]; /* list of filenames to edit */ int argno; /* index of current file in args list */ int nargs; /* number of filenames in args[] */ /* dummy var, never explicitly referenced */ int bavar; /* used only in BeforeAfter macros */ /* have we made a multi-line change? */ int mustredraw; /* must we redraw the whole screen? */ /* used to detect changes that invalidate cached text/blocks */ long changes; /* incremented when file is changed */ int significant; /* boolean: was a *REAL* change made? */ /* used to support the pfetch() macro */ int plen; /* length of the line */ long pline; /* line number that len refers to */ long pchgs; /* "changes" level that len refers to */ char *ptext; /* text of previous line, if valid */ /* misc temporary storage - mostly for strings */ BLK tmpblk; /* a block used to accumulate changes */ /* screen oriented stuff */ long topline; /* file line number of top line */ int leftcol; /* column number of left col */ int physcol; /* physical column number that cursor is on */ int physrow; /* physical row number that cursor is on */ /* used to help minimize that "[Hit a key to continue]" message */ int exwrote; /* Boolean: was the last ex command wordy? */ /* This variable affects the behaviour of certain functions -- most importantly * the input function. */ int doingdot; /* boolean: are we doing the "." command? */ /* This variable affects the behaviour of the ":s" command, and it is also * used to detect & prohibit nesting of ":g" commands */ int doingglobal; /* boolean: are doing a ":g" command? */ /* These are used for reporting multi-line changes to the user */ long rptlines; /* number of lines affected by a command */ char *rptlabel; /* description of how lines were affected */ /* These store info that pertains to the shift-U command */ long U_line; /* line# of the undoable line, or 0l for none */ char U_text[BLKSIZE]; /* contents of the undoable line */ /* Bigger stack req'ed for TOS */ #if TOS long _stksize = 16384; #endif SHAR_EOF fi # end of overwriting check if test -f 'vcmd.c' then echo shar: will not over-write existing file "'vcmd.c'" else cat << \SHAR_EOF > 'vcmd.c' /* vcmd.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the functions that handle VI commands */ #include "config.h" #include "vi.h" #if MSDOS #include <process.h> #include <string.h> #endif #if TOS #include <osbind.h> #include <string.h> #endif #if OSK # include <stdio.h> #endif /* This function puts the editor in EX mode */ MARK v_quit() { move(LINES - 1, 0); mode = MODE_EX; return cursor; } /* This function causes the screen to be redrawn */ MARK v_redraw() { redraw(MARK_UNSET, FALSE); return cursor; } /* This function executes a single EX command, and waits for a user keystroke * before returning to the VI screen. If that keystroke is another ':', then * another EX command is read and executed. */ /*ARGSUSED*/ MARK v_1ex(m, text) MARK m; /* the current line */ char *text; /* the first command to execute */ { /* run the command. be careful about modes & output */ exwrote = (mode == MODE_COLON); doexcmd(text); exrefresh(); /* if mode is no longer MODE_VI, then we should quit right away! */ if (mode != MODE_VI && mode != MODE_COLON) return cursor; /* The command did some output. Wait for a keystoke. */ if (exwrote) { mode = MODE_VI; msg("[Hit <RETURN> to continue]"); if (getkey(0) == ':') { mode = MODE_COLON; addch('\n'); } else redraw(MARK_UNSET, FALSE); } return cursor; } /* This function undoes the last change */ /*ARGSUSED*/ MARK v_undo(m) MARK m; /* (ignored) */ { if (undo()) { redraw(MARK_UNSET, FALSE); } return cursor; } /* This function deletes the character(s) that the cursor is on */ MARK v_xchar(m, cnt, cmd) MARK m; /* where to start deletions */ long cnt; /* number of chars to delete */ int cmd; /* either 'x' or 'X' */ { DEFAULT(1); /* for 'X', adjust so chars are deleted *BEFORE* cursor */ if (cmd == 'X') { if (markidx(m) < cnt) return MARK_UNSET; m -= cnt; } /* make sure we don't try to delete more thars than there are */ pfetch(markline(m)); if (markidx(m + cnt) > plen) { cnt = plen - markidx(m); } if (cnt == 0L) { return MARK_UNSET; } /* do it */ ChangeText { cut(m, m + cnt); delete(m, m + cnt); } return m; } /* This function defines a mark */ /*ARGSUSED*/ MARK v_mark(m, count, key) MARK m; /* where the mark will be */ long count; /* (ignored) */ int key; /* the ASCII label of the mark */ { if (key < 'a' || key > 'z') { msg("Marks must be from a to z"); } else { mark[key - 'a'] = m; } return m; } /* This function toggles upper & lower case letters */ MARK v_ulcase(m, cnt) MARK m; /* where to make the change */ long cnt; /* number of chars to flip */ { REG char *pos; REG int i, j; static char flip[] = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ[](){}<>"; DEFAULT(1); /* fetch the current version of the line */ pfetch(markline(m)); /* for each position in the line */ for (j = 0, i = markidx(m); j < cnt && ptext[i]; j++, i++) { tmpblk.c[j] = 0; /* one of the standard chars? */ for (pos = flip; *pos && *pos != ptext[i]; pos++) { } if (*pos) { tmpblk.c[j] = flip[(int)(pos - flip) ^ 1]; } #ifndef NO_DIGRAPH else /* one of the non-standard chars? */ { for (pos = o_flipcase; *pos && *pos != ptext[i]; pos++) { } if (*pos) { tmpblk.c[j] = o_flipcase[(int)(pos - o_flipcase) ^ 1]; } } #endif /* if nothing special, then don't change it */ if (tmpblk.c[j] == 0) { tmpblk.c[j] = ptext[i]; } } /* if the new text is different from the old, then change it */ if (strncmp(tmpblk.c, &ptext[markidx(m)], j)) { ChangeText { tmpblk.c[j] = '\0'; change(m, m + j, tmpblk.c); } } return m + j; } MARK v_replace(m, cnt, key) MARK m; /* first char to be replaced */ long cnt; /* number of chars to replace */ int key; /* what to replace them with */ { REG char *text; REG int i; DEFAULT(1); /* map ^M to '\n' */ if (key == '\r') { key = '\n'; } /* make sure the resulting line isn't too long */ if (cnt > BLKSIZE - 2 - markidx(m)) { cnt = BLKSIZE - 2 - markidx(m); } /* build a string of the desired character with the desired length */ for (text = tmpblk.c, i = cnt; i > 0; i--) { *text++ = key; } *text = '\0'; /* make sure cnt doesn't extend past EOL */ pfetch(markline(m)); key = markidx(m); if (key + cnt > plen) { cnt = plen - key; } /* do the replacement */ ChangeText { change(m, m + cnt, tmpblk.c); } if (*tmpblk.c == '\n') { return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE; } else { return m + cnt - 1; } } MARK v_overtype(m) MARK m; /* where to start overtyping */ { MARK end; /* end of a substitution */ static long width; /* width of a single-line replace */ /* the "doingdot" version of replace is really a substitution */ if (doingdot) { /* was the last one really repeatable? */ if (width < 0) { msg("Can't repeat a multi-line overtype command"); return MARK_UNSET; } /* replacing nothing by nothing? Don't bother */ if (width == 0) { return m; } /* replace some chars by repeated text */ return v_subst(m, width); } /* Normally, we input starting here, in replace mode */ ChangeText { end = input(m, m, WHEN_VIREP, -1L); } /* if we ended on the same line we started on, then this * overtype is repeatable via the dot key. */ if (markline(end) == markline(m) && end >= m - 1L) { width = end - m + 1L; } else /* it isn't repeatable */ { width = -1L; } return end; } /* This function selects which cut buffer to use */ /*ARGSUSED*/ MARK v_selcut(m, cnt, key) MARK m; long cnt; int key; { cutname(key); return m; } /* This function pastes text from a cut buffer */ /*ARGSUSED*/ MARK v_paste(m, cnt, cmd) MARK m; /* where to paste the text */ long cnt; /* (ignored) */ int cmd; /* either 'p' or 'P' */ { ChangeText { m = paste(m, cmd == 'p', FALSE); } return m; } /* This function yanks text into a cut buffer */ MARK v_yank(m, n) MARK m, n; /* range of text to yank */ { cut(m, n); return m; } /* This function deletes a range of text */ MARK v_delete(m, n) MARK m, n; /* range of text to delete */ { /* illegal to try and delete nothing */ if (n <= m) { return MARK_UNSET; } /* Do it */ ChangeText { cut(m, n); delete(m, n); } return m; } /* This starts input mode without deleting anything */ MARK v_insert(m, cnt, key) MARK m; /* where to start (sort of) */ long cnt; /* repeat how many times? */ int key; /* what command is this for? {a,A,i,I,o,O} */ { int wasdot; long reps; int after; /* are we appending or inserting? */ long indentref = -1L; DEFAULT(1); ChangeText { /* tweak the insertion point, based on command key */ switch (key) { case 'i': after = FALSE; break; case 'a': pfetch(markline(m)); if (plen > 0) { m++; } after = TRUE; break; case 'I': m = m_front(m, 1L); after = FALSE; break; case 'A': pfetch(markline(m)); m = (m & ~(BLKSIZE - 1)) + plen; after = TRUE; break; case 'O': m &= ~(BLKSIZE - 1); add(m, "\n"); after = FALSE; indentref = 1L; break; case 'o': m = (m & ~(BLKSIZE - 1)) + BLKSIZE; add(m, "\n"); after = FALSE; break; } /* insert the same text once or more */ for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE) { m = input(m, m, WHEN_VIINP, indentref); if (after) { m++; } } if (after) { m--; } doingdot = wasdot; } #ifndef CRUNCH # ifndef NO_EXTENSIONS if (key == 'i' && *o_inputmode && mode == MODE_VI) { msg("Now in visual command mode! To return to input mode, hit <i>."); } # endif #endif return m; } /* This starts input mode with some text deleted */ MARK v_change(m, n) MARK m, n; /* the range of text to change */ { int lnmode; /* is this a line-mode change? */ /* swap them if they're in reverse order */ if (m > n) { MARK tmp; tmp = m; m = n; n = tmp; } /* for line mode, retain the last newline char */ lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n); if (lnmode) { n -= BLKSIZE; pfetch(markline(n)); n = (n & ~(BLKSIZE - 1)) + plen; } ChangeText { cut(m, n); m = input(m, n, WHEN_VIINP, -1L); } return m; } /* This function replaces a given number of characters with input */ MARK v_subst(m, cnt) MARK m; /* where substitutions start */ long cnt; /* number of chars to replace */ { DEFAULT(1); /* make sure we don't try replacing past EOL */ pfetch(markline(m)); if (markidx(m) + cnt > plen) { cnt = plen - markidx(m); } /* Go for it! */ ChangeText { cut(m, m + cnt); m = input(m, m + cnt, WHEN_VIINP, -1L); } return m; } /* This calls the ex "join" command to join some lines together */ MARK v_join(m, cnt) MARK m; /* the first line to be joined */ long cnt; /* number of other lines to join */ { MARK joint; /* where the lines were joined */ DEFAULT(1); /* figure out where the joint will be */ pfetch(markline(m)); joint = (m & ~(BLKSIZE - 1)) + plen; /* join the lines */ cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, ""); mustredraw = TRUE; /* the cursor should be left at the joint */ return joint; } /* This calls the ex shifter command to shift some lines */ static MARK shift_help(m, n, excmd) MARK m, n; /* range of lines to shift */ CMD excmd; /* which way do we shift? */ { /* adjust for inclusive endmarks in ex */ n -= BLKSIZE; cmd_shift(m, n, excmd, 0, ""); return m; } /* This calls the ex "<" command to shift some lines left */ MARK v_lshift(m, n) MARK m, n; /* range of lines to shift */ { return shift_help(m, n, CMD_SHIFTL); } /* This calls the ex ">" command to shift some lines right */ MARK v_rshift(m, n) MARK m, n; /* range of lines to shift */ { return shift_help(m, n, CMD_SHIFTR); } /* This runs some lines through a filter program */ MARK v_filter(m, n) MARK m, n; /* range of lines to shift */ { char cmdln[100]; /* a shell command line */ /* adjust for inclusive endmarks in ex */ n -= BLKSIZE; if (vgets('!', cmdln, sizeof(cmdln)) > 0) { filter(m, n, cmdln); } redraw(MARK_UNSET, FALSE); return m; } /* This function runs the ex "file" command to show the file's status */ MARK v_status() { cmd_file(cursor, cursor, CMD_FILE, 0, ""); return cursor; } /* This function runs the ":&" command to repeat the previous :s// */ MARK v_again(m, n) MARK m, n; { cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, ""); return cursor; } /* This function switches to the previous file, if possible */ MARK v_switch() { if (!*prevorig) msg("No previous file"); else { strcpy(tmpblk.c, prevorig); cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c); } return cursor; } /* This function does a tag search on a keyword */ /*ARGSUSED*/ MARK v_tag(keyword, m, cnt) char *keyword; MARK m; long cnt; { /* move the cursor to the start of the tag name, where m is */ cursor = m; /* perform the tag search */ cmd_tag(cursor, cursor, CMD_TAG, 0, keyword); return cursor; } #ifndef NO_EXTENSIONS /* This function looks up a keyword by calling the helpprog program */ /*ARGSUSED*/ MARK v_keyword(keyword, m, cnt) char *keyword; MARK m; long cnt; { int waswarn; char cmdline[130]; move(LINES - 1, 0); addstr("---------------------------------------------------------\n"); clrtoeol(); refresh(); sprintf(cmdline, "%s %s", o_keywordprg, keyword); waswarn = *o_warn; *o_warn = FALSE; Suspend_curses(); if (system(cmdline)) { addstr("<<< failed >>>\n"); } Resume_curses(FALSE); mode = MODE_VI; redraw(MARK_UNSET, FALSE); *o_warn = waswarn; return m; } MARK v_increment(keyword, m, cnt) char *keyword; MARK m; long cnt; { static sign; char newval[12]; long atol(); DEFAULT(1); /* get one more keystroke, unless doingdot */ if (!doingdot) { sign = getkey(0); } /* adjust the number, based on that second keystroke */ switch (sign) { case '+': case '#': cnt = atol(keyword) + cnt; break; case '-': cnt = atol(keyword) - cnt; break; case '=': break; default: return MARK_UNSET; } sprintf(newval, "%ld", cnt); ChangeText { change(m, m + strlen(keyword), newval); } return m; } #endif /* This function acts like the EX command "xit" */ /*ARGSUSED*/ MARK v_xit(m, cnt, key) MARK m; /* ignored */ long cnt; /* ignored */ int key; /* must be a second 'Z' */ { /* if second char wasn't 'Z', fail */ if (key != 'Z') { return MARK_UNSET; } /* move the cursor to the bottom of the screen */ move(LINES - 1, 0); clrtoeol(); /* do the xit command */ cmd_xit(m, m, CMD_XIT, FALSE, ""); /* return the cursor */ return m; } /* This function undoes changes to a single line, if possible */ MARK v_undoline(m) MARK m; /* where we hope to undo the change */ { /* make sure we have the right line in the buffer */ if (markline(m) != U_line) { return MARK_UNSET; } /* fix it */ ChangeText { strcat(U_text, "\n"); change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text); } /* nothing in the buffer anymore */ U_line = -1L; /* return, with the cursor at the front of the line */ return m & ~(BLKSIZE - 1); } #ifndef NO_ERRLIST MARK v_errlist(m) MARK m; { cmd_errlist(m, m, CMD_ERRLIST, FALSE, ""); return cursor; } #endif #ifndef NO_AT /*ARGSUSED*/ MARK v_at(m, cnt, key) MARK m; long cnt; int key; { if (!fromcutbuf(key)) { return MARK_UNSET; } return cursor; } #endif SHAR_EOF fi # end of overwriting check if test -f 'vi.c' then echo shar: will not over-write existing file "'vi.c'" else cat << \SHAR_EOF > 'vi.c' /* vi.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ #include "config.h" #include <ctype.h> #include "vi.h" /* This array describes what each key does */ #define NO_FUNC (MARK (*)())0 #define NO_ARGS 0 #define CURSOR_COUNT 1 #define CURSOR 2 #define CURSOR_CNT_KEY 3 #define CURSOR_MOVED 4 #define CURSOR_EOL 5 #define ZERO 6 #define DIGIT 7 #define CURSOR_TEXT 8 #define CURSOR_CNT_CMD 9 #define KEYWORD 10 #define NO_FLAGS 0x00 #define MVMT 0x01 /* this is a movement command */ #define PTMV 0x02 /* this can be *part* of a movement command */ #define FRNT 0x04 /* after move, go to front of line */ #define INCL 0x08 /* include last char when used with c/d/y */ #define LNMD 0x10 /* use line mode of c/d/y */ #define NCOL 0x20 /* this command can't change the column# */ #define NREL 0x40 /* this is "non-relative" -- set the '' mark */ #define SDOT 0x80 /* set the "dot" variables, for the "." cmd */ static struct keystru { MARK (*func)(); /* the function to run */ uchar args; /* description of the args needed */ uchar flags; /* other stuff */ } vikeys[] = { /* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^B page backward */ {m_scroll, CURSOR_CNT_CMD, FRNT}, /* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^D scroll dn 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL}, /* ^E scroll up */ {m_scroll, CURSOR_CNT_CMD, NCOL}, /* ^F page forward */ {m_scroll, CURSOR_CNT_CMD, FRNT}, /* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS}, /* ^H move left, like h*/ {m_left, CURSOR_COUNT, MVMT}, /* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^J move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD}, /* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS}, /* ^M mv front next ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD}, /* ^N move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD}, /* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^P move up */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD}, /* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS}, /* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^U scroll up 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL}, /* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^X not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^Y scroll down */ {m_scroll, CURSOR_CNT_CMD, NCOL}, /* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS}, /* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS}, /* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* SPC move right,like l*/ {m_right, CURSOR_COUNT, MVMT}, /* ! run thru filter */ {v_filter, CURSOR_MOVED, FRNT|LNMD|INCL}, /* " select cut buffer*/ {v_selcut, CURSOR_CNT_KEY, PTMV}, #ifndef NO_EXTENSIONS /* # increment number */ {v_increment, KEYWORD, SDOT}, #else /* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* $ move to rear */ {m_rear, CURSOR, MVMT|INCL}, /* % move to match */ {m_match, CURSOR, MVMT|INCL}, /* & repeat subst */ {v_again, CURSOR_MOVED, SDOT|NCOL|LNMD|INCL}, /* ' move to a mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|FRNT|NREL|LNMD|INCL}, #ifndef NO_SENTENCE /* ( mv back sentence */ {m_bsentence, CURSOR_COUNT, MVMT}, /* ) mv fwd sentence */ {m_fsentence, CURSOR_COUNT, MVMT}, #else /* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif #ifndef NO_ERRLIST /* * errlist */ {v_errlist, CURSOR, FRNT|NREL}, #else /* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* + mv front next ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD}, #ifndef NO_CHARSEARCH /* , reverse [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL}, #else /* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* - mv front prev ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD}, /* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL}, /* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV}, /* 1 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 2 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 3 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 4 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 5 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 6 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 7 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 8 part of count */ {NO_FUNC, DIGIT, PTMV}, /* 9 part of count */ {NO_FUNC, DIGIT, PTMV}, /* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS}, #ifndef NO_CHARSEARCH /* ; repeat [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL}, #else /* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL}, /* = not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL}, /* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL}, #ifndef NO_AT /* @ execute a cutbuf */ {v_at, CURSOR_CNT_KEY, NO_FLAGS}, #else /* @ undefined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* A append at EOL */ {v_insert, CURSOR_CNT_CMD, SDOT}, /* B move back Word */ {m_bword, CURSOR_CNT_CMD, MVMT}, /* C change to EOL */ {v_change, CURSOR_EOL, SDOT}, /* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT}, /* E move end of Word */ {m_eword, CURSOR_CNT_CMD, MVMT|INCL}, #ifndef NO_CHARSEARCH /* F move bk to char */ {m_Fch, CURSOR_CNT_KEY, MVMT|INCL}, #else /* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* G move to line # */ {m_updnto, CURSOR_CNT_CMD, MVMT|NREL|LNMD|FRNT|INCL}, /* H move to row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT}, /* I insert at front */ {v_insert, CURSOR_CNT_CMD, SDOT}, /* J join lines */ {v_join, CURSOR_COUNT, SDOT}, #ifndef NO_EXTENSIONS /* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS}, #else /* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* L move to last row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT}, /* M move to mid row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT}, /* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT}, /* O insert above line*/ {v_insert, CURSOR_CNT_CMD, SDOT}, /* P paste before */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS}, /* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS}, /* R overtype */ {v_overtype, CURSOR, SDOT}, /* S change line */ {v_change, CURSOR_MOVED, SDOT}, #ifndef NO_CHARSEARCH /* T move bk to char */ {m_Tch, CURSOR_CNT_KEY, MVMT|INCL}, #else /* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* U undo whole line */ {v_undoline, CURSOR, FRNT}, /* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* W move forward Word*/ {m_fword, CURSOR_CNT_CMD, MVMT}, /* X delete to left */ {v_xchar, CURSOR_CNT_CMD, SDOT}, /* Y yank text */ {v_yank, CURSOR_MOVED, NCOL}, /* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS}, /* [ move back section*/ {m_bsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL}, /* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ] move fwd section */ {m_fsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL}, /* ^ move to front */ {m_front, CURSOR, MVMT}, /* _ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ` move to mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|NREL}, /* a append at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT}, /* b move back word */ {m_bword, CURSOR_CNT_CMD, MVMT}, /* c change text */ {v_change, CURSOR_MOVED, SDOT}, /* d delete op */ {v_delete, CURSOR_MOVED, SDOT|NCOL}, /* e move end word */ {m_eword, CURSOR_CNT_CMD, MVMT|INCL}, #ifndef NO_CHARSEARCH /* f move fwd for char*/ {m_fch, CURSOR_CNT_KEY, MVMT|INCL}, #else /* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* h move left */ {m_left, CURSOR_COUNT, MVMT}, /* i insert at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT}, /* j move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|NCOL|LNMD}, /* k move up */ {m_updnto, CURSOR_CNT_CMD, MVMT|NCOL|LNMD}, /* l move right */ {m_right, CURSOR_COUNT, MVMT}, /* m define a mark */ {v_mark, CURSOR_CNT_KEY, NO_FLAGS}, /* n repeat prev srch */ {m_nsrch, CURSOR, MVMT}, /* o insert below line*/ {v_insert, CURSOR_CNT_CMD, SDOT}, /* p paste after */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS}, /* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* r replace chars */ {v_replace, CURSOR_CNT_KEY, SDOT}, /* s subst N chars */ {v_subst, CURSOR_COUNT, SDOT}, #ifndef NO_CHARSEARCH /* t move fwd to char */ {m_tch, CURSOR_CNT_KEY, MVMT|INCL}, #else /* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif /* u undo */ {v_undo, CURSOR, NO_FLAGS}, /* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* w move fwd word */ {m_fword, CURSOR_CNT_CMD, MVMT}, /* x delete character */ {v_xchar, CURSOR_CNT_CMD, SDOT}, /* y yank text */ {v_yank, CURSOR_MOVED, NCOL}, /* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL}, /* { back paragraph */ {m_bparagraph, CURSOR_COUNT, MVMT|LNMD}, /* | move to column */ {m_tocol, CURSOR_COUNT, NREL}, /* } fwd paragraph */ {m_fparagraph, CURSOR_COUNT, MVMT|LNMD}, /* ~ upper/lowercase */ {v_ulcase, CURSOR_COUNT, SDOT}, /* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS} }; void vi() { REG int key; /* keystroke from user */ long count; /* numeric argument to some functions */ REG struct keystru *keyptr;/* pointer to vikeys[] element */ MARK tcurs; /* temporary cursor */ int prevkey;/* previous key, if d/c/y/</>/! */ MARK range; /* start of range for d/c/y/</>/! */ char text[100]; int dotkey; /* last "key" of a change */ int dotpkey;/* last "prevkey" of a change */ int dotkey2;/* last extra "getkey()" of a change */ int dotcnt; /* last "count" of a change */ int firstkey; REG int i; /* tell the redraw() function to start from scratch */ redraw(MARK_UNSET, FALSE); #ifdef lint /* lint says that "range" might be used before it is set. This * can't really happen due to the way "range" and "prevkey" are used, * but lint doesn't know that. This line is here ONLY to keep lint * happy. */ range = 0L; #endif /* safeguard against '.' with no previous command */ dotkey = 0; /* go immediately into insert mode, if ":set inputmode" */ firstkey = 0; #ifndef NO_EXTENSIONS if (*o_inputmode) { firstkey = 'i'; } #endif /* Repeatedly handle VI commands */ for (count = 0, prevkey = '\0'; mode == MODE_VI; ) { /* if we've moved off the undoable line, then we can't undo it at all */ if (markline(cursor) != U_line) { U_line = 0L; } /* report any changes from the previous command */ if (rptlines >= *o_report) { redraw(cursor, FALSE); msg("%ld lines %s", rptlines, rptlabel); } rptlines = 0L; /* get the next command key. It must be ASCII */ if (firstkey) { key = firstkey; firstkey = 0; } else { do { key = getkey(WHEN_VICMD); } while (key < 0 || key > 127); } /* change cw and cW commands to ce and cE, respectively */ /* (Why? because the real vi does it that way!) */ if (prevkey == 'c') { if (key == 'w') key = 'e'; else if (key == 'W') key = 'E'; /* wouldn't work right at the end of a word unless we * backspace one character before doing the move. This * will fix most cases. !!! but not all. */ if (markidx(cursor) > 0 && (key == 'e' || key == 'E')) { cursor--; } } /* look up the structure describing this command */ keyptr = &vikeys[key]; /* if we're in the middle of a d/c/y/</>/! command, reject * anything but movement or a doubled version like "dd". */ if (prevkey && key != prevkey && !(keyptr->flags & (MVMT|PTMV))) { Beep(); prevkey = 0; count = 0; continue; } /* set the "dot" variables, if we're supposed to */ if ((keyptr->flags & SDOT) || (prevkey && vikeys[prevkey].flags & SDOT)) { dotkey = key; dotpkey = prevkey; dotkey2 = '\0'; dotcnt = count; /* remember the line before any changes are made */ if (U_line != markline(cursor)) { U_line = markline(cursor); strcpy(U_text, fetchline(U_line)); } } /* if this is "." then set other vars from the "dot" vars */ if (key == '.') { key = dotkey; keyptr = &vikeys[key]; prevkey = dotpkey; if (prevkey) { range = cursor; } if (count == 0) { count = dotcnt; } doingdot = TRUE; /* remember the line before any changes are made */ if (U_line != markline(cursor)) { U_line = markline(cursor); strcpy(U_text, fetchline(U_line)); } } else { doingdot = FALSE; } /* process the key as a command */ tcurs = cursor; switch (keyptr->args) { case ZERO: if (count == 0) { tcurs = cursor & ~(BLKSIZE - 1); break; } /* else fall through & treat like other digits... */ case DIGIT: count = count * 10 + key - '0'; break; case KEYWORD: /* if not on a keyword, fail */ pfetch(markline(cursor)); key = markidx(cursor); if (isascii(ptext[key]) && !isalnum(ptext[key]) && ptext[key] != '_') { tcurs = MARK_UNSET; break; } /* find the start of the keyword */ while (key > 0 && (!isascii(ptext[key-1]) || isalnum(ptext[key - 1]) || ptext[key - 1] == '_')) { key--; } tcurs = (cursor & ~(BLKSIZE - 1)) + key; /* copy it into a buffer, and NUL-terminate it */ i = 0; do { text[i++] = ptext[key++]; } while (!isascii(ptext[key]) || isalnum(ptext[key]) || ptext[key] == '_'); text[i] = '\0'; /* call the function */ tcurs = (*keyptr->func)(text, tcurs, count); count = 0L; break; case NO_ARGS: if (keyptr->func) { (*keyptr->func)(); } else { Beep(); } count = 0L; break; case CURSOR_COUNT: tcurs = (*keyptr->func)(cursor, count); count = 0L; break; case CURSOR: tcurs = (*keyptr->func)(cursor); count = 0L; break; case CURSOR_CNT_KEY: if (doingdot) { tcurs = (*keyptr->func)(cursor, count, dotkey2); } else { /* get a key */ i = getkey(0); if (i == '\033') /* ESC */ { count = 0; tcurs = MARK_UNSET; break; /* exit from "case CURSOR_CNT_KEY" */ } else if (i == ('V' & 0x1f)) { i = getkey(0); } /* if part of an SDOT command, remember it */ if (keyptr->flags & SDOT || (prevkey && vikeys[prevkey].flags & SDOT)) { dotkey2 = i; } /* do it */ tcurs = (*keyptr->func)(cursor, count, i); } count = 0L; break; case CURSOR_MOVED: /* '&' and uppercase keys always act like doubled */ if (key == '&' || isascii(key) && isupper(key)) { prevkey = key; } if (prevkey) { /* doubling up a command */ if (!count) count = 1L; range = cursor; tcurs = range + MARK_AT_LINE(count - 1L); count = 0L; } else { prevkey = key; range = cursor; key = -1; /* so we don't think we doubled yet */ } break; case CURSOR_EOL: prevkey = key; /* a zero-length line needs special treatment */ pfetch(markline(cursor)); if (plen == 0) { /* act on a zero-length section of text */ range = tcurs = cursor; key = ' '; } else { /* act like CURSOR_MOVED with '$' movement */ range = cursor; tcurs = m_rear(cursor, 1L); key = '$'; } count = 0L; keyptr = &vikeys[key]; break; case CURSOR_TEXT: do { text[0] = key; if (vgets(key, text + 1, sizeof text - 1) >= 0) { /* reassure user that <CR> was hit */ qaddch('\r'); refresh(); /* call the function with the text */ tcurs = (*keyptr->func)(cursor, text); } else { if (exwrote || mode == MODE_COLON) { redraw(MARK_UNSET, FALSE); } mode = MODE_VI; } } while (mode == MODE_COLON); count = 0L; break; case CURSOR_CNT_CMD: tcurs = (*keyptr->func)(cursor, count, key); count = 0L; break; } /* if that command took us out of vi mode, then exit the loop * NOW, without tweaking the cursor or anything. This is very * important when mode == MODE_QUIT. */ if (mode != MODE_VI) { break; } /* now move the cursor, as appropriate */ if (keyptr->args == CURSOR_MOVED) { /* the < and > keys have FRNT, * but it shouldn't be applied yet */ tcurs = adjmove(cursor, tcurs, 0); } else { tcurs = adjmove(cursor, tcurs, (int)keyptr->flags); } /* was that the end of a d/c/y/</>/! command? */ if (prevkey && (prevkey == key || (keyptr->flags & MVMT)) && count == 0L) { /* if the movement command failed, cancel operation */ if (tcurs == MARK_UNSET) { prevkey = 0; count = 0; continue; } /* make sure range=front and tcurs=rear. Either way, * leave cursor=range since that's where we started. */ cursor = range; if (tcurs < range) { range = tcurs; tcurs = cursor; } /* adjust for line mode & inclusion of last char/line */ i = (keyptr->flags | vikeys[prevkey].flags); if (key == prevkey) { i |= (INCL|LNMD); } switch (i & (INCL|LNMD)) { case INCL: tcurs++; break; case INCL|LNMD: tcurs += BLKSIZE; /* fall through... */ case LNMD: range &= ~(BLKSIZE - 1); tcurs &= ~(BLKSIZE - 1); break; } /* run the function */ tcurs = (*vikeys[prevkey].func)(range, tcurs); (void)adjmove(cursor, cursor, 0); cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags); /* cleanup */ prevkey = 0; } else if (!prevkey) { cursor = tcurs; } } } /* This function adjusts the MARK value that they return; here we make sure * it isn't past the end of the line, and that the column hasn't been * *accidentally* changed. */ MARK adjmove(old, new, flags) MARK old; /* the cursor position before the command */ REG MARK new; /* the cursor position after the command */ int flags; /* various flags regarding cursor mvmt */ { static int colno; /* the column number that we want */ REG char *text; /* used to scan through the line's text */ REG int i; #ifdef DEBUG watch(); #endif /* if the command failed, bag it! */ if (new == MARK_UNSET) { Beep(); return old; } /* if this is a non-relative movement, set the '' mark */ if (flags & NREL) { mark[26] = old; } /* make sure it isn't past the end of the file */ if (markline(new) < 1) { new = MARK_FIRST; } else if (markline(new) > nlines) { new = MARK_LAST; } /* fetch the new line */ pfetch(markline(new)); /* move to the front, if we're supposed to */ if (flags & FRNT) { new = m_front(new, 1L); } /* change the column#, or change the mark to suit the column# */ if (!(flags & NCOL)) { /* change the column# */ i = markidx(new); if (i == BLKSIZE - 1) { new &= ~(BLKSIZE - 1); if (plen > 0) { new += plen - 1; } colno = BLKSIZE * 8; /* one heck of a big colno */ } else if (plen > 0) { if (i >= plen) { new = (new & ~(BLKSIZE - 1)) + plen - 1; } colno = idx2col(new, ptext, FALSE); } else { new &= ~(BLKSIZE - 1); colno = 0; } } else { /* adjust the mark to get as close as possible to column# */ for (i = 0, text = ptext; i <= colno && *text; text++) { if (*text == '\t' && !*o_list) { i += *o_tabstop - (i % *o_tabstop); } else if (UCHAR(*text) < ' ' || *text == 127) { i += 2; } #ifndef NO_CHARATTR else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2]) { text += 2; /* plus one more in "for()" stmt */ } #endif else { i++; } } if (text > ptext) { text--; } new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext); } return new; } #ifdef DEBUG watch() { static wasset; if (*origname) { wasset = TRUE; } else if (wasset) { msg("origname was clobbered"); endwin(); abort(); } if (nlines == 0) { msg("nlines=0"); endwin(); abort(); } } #endif SHAR_EOF fi # end of overwriting check if test -f 'virec.c' then echo shar: will not over-write existing file "'virec.c'" else cat << \SHAR_EOF > 'virec.c' /* virec.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the file recovery program */ #include "config.h" #include <stdio.h> #include <ctype.h> #include "vi.h" #if TOS # include <stat.h> #else # if OSK # include "osk.h" # else # include <sys/stat.h> # endif #endif extern char *getenv(); struct stat stbuf; BLK hdr; BLK text; /* the name of the directory where tmp files are stored. */ char o_directory[30] = TMPDIR; char *progname; main(argc, argv) int argc; char **argv; { char *tmp; void recover(); #if MSDOS || TOS char **wildexpand(); argv = wildexpand(&argc, argv); #endif progname = argv[0]; /* set the o_directory variable */ if ((tmp = getenv("TMP")) /* yes, ASSIGNMENT! */ || (tmp = getenv("TEMP"))) /* yes, ASSIGNMENT! */ { strcpy(o_directory, tmp); } if (argc >= 3 && !strcmp(argv[1], "-d")) { strcpy(o_directory, argv[2]); argc -= 2; argv += 2; } /* process the arguments */ if (argc < 2) { /* maybe stdin comes from a file? */ if (isatty(0)) { fprintf(stderr, "usage: %s [-d tmpdir] lostfile...\n", progname); } else if (read(0, &hdr, (unsigned)BLKSIZE) != BLKSIZE) { fprintf(stderr, "couldn't get header\n"); } else { copytext(0, stdout); } } else { while (--argc > 0) { recover(*++argv); } } exit(0); } /* This function recovers a single file */ void recover(filename) char *filename; { char tmpname[100]; int tmpfd; int count; FILE *fp; long mtime; int i, j; int sum; /* used for calculating a checksum for this */ char *scan; /* get the file's status info */ if (stat(filename, &stbuf) < 0) { /* if serious error, give up on this file */ if (errno != ENOENT) { perror(filename); return; } /* else fake it for a new file */ stat(".", &stbuf); #if OSK stbuf.st_mode = S_IREAD; #else stbuf.st_mode = S_IFREG; #endif stbuf.st_mtime = 0L; } /* generate a checksum from the file's name */ for (sum = 0, scan = filename + strlen(filename); --scan >= filename && (isascii(*scan) && isalnum(*scan) || *scan == '.'); sum = sum + *scan) { } sum &= 0xf; /* find the tmp file */ #if MSDOS || TOS /* MS-Dos doesn't allow multiple slashes, but supports drives * with current directories. * This relies on TMPNAME beginning with "%s\\"!!!! */ strcpy(tmpname, o_directory); if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1])) tmpname[i++]=SLASH; sprintf(tmpname+i, TMPNAME+3, sum, stbuf.st_ino, stbuf.st_dev); #else sprintf(tmpname, TMPNAME, o_directory, sum, stbuf.st_ino, stbuf.st_dev, 0); #endif count = tnamerec(tmpname, TMPNAME); tmpfd = open(tmpname, O_RDONLY | O_BINARY); if (tmpfd < 0) { char buf[512]; sprintf(buf, "recoverable version of %s", filename); perror(buf); fprintf(stderr, "make sure your TMP or TEMP environment variable is correct\n"); return; } /* make sure the file hasn't been modified more recently */ mtime = stbuf.st_mtime; fstat(tmpfd, &stbuf); if (stbuf.st_mtime < mtime || count > 0) { if (count > 0) { printf("%d temp files are recoverable\n", count+1); printf("\tyou may want to do more than one recover\n"); printf("\tsince the one that *is* recovered is picked\n"); printf("\tat random.\n"); } printf("\"%s\" has been modified more recently than its recoverable version\n", filename); puts("Do you still want to recover it?\n"); puts("\ty - Yes, discard the current version and recover it.\n"); puts("\tn - No, discard the recoverable version and keep the current version\n"); puts("\tq - Quit without doing anything for this file.\n"); puts("Enter y, n, or q --> "); fflush(stdout); for (;;) { switch (getchar()) { case 'y': case 'Y': goto BreakBreak; case 'n': case 'N': close(tmpfd); unlink(tmpname); return; case 'q': case 'Q': close(tmpfd); return; } } BreakBreak:; } /* make sure this tmp file is intact */ if (read(tmpfd, &hdr, (unsigned)BLKSIZE) != BLKSIZE) { fprintf(stderr, "%s: bad header in tmp file\n", filename); close(tmpfd); unlink(tmpname); return; } for (i = j = 1; i < MAXBLKS && hdr.n[i]; i++) { if (hdr.n[i] > j) { j = hdr.n[i]; } } lseek(tmpfd, (long)j * (long)BLKSIZE, 0); if (read(tmpfd, &text, (unsigned)BLKSIZE) != BLKSIZE) { fprintf(stderr, "%s: bad data block in tmp file\n", filename); close(tmpfd); unlink(tmpname); return; } /* open the normal text file for writing */ fp = fopen(filename, "w"); if (!fp) { perror(filename); close(tmpfd); return; } /* copy the text */ copytext(tmpfd, fp); /* cleanup */ close(tmpfd); fclose(fp); unlink(tmpname); } /* This function moves text from the tmp file to the normal file */ copytext(tmpfd, fp) int tmpfd; /* fd of the tmp file */ FILE *fp; /* the stream to write it to */ { int i; /* write the data blocks to the normal text file */ for (i = 1; i < MAXBLKS && hdr.n[i]; i++) { lseek(tmpfd, (long)hdr.n[i] * (long)BLKSIZE, 0); read(tmpfd, &text, (unsigned)BLKSIZE); fputs(text.c, fp); } } #if MSDOS || TOS #define WILDCARD_NO_MAIN #include "wildcard.c" #endif SHAR_EOF fi # end of overwriting check if test -f 'wildcard.c' then echo shar: will not over-write existing file "'wildcard.c'" else cat << \SHAR_EOF > 'wildcard.c' /* wildcard.c */ /* Author: * Guntram Blohm * Buchenstrasse 19 * 7904 Erbach, West Germany * Tel. ++49-7305-6997 * sorry - no regular network connection */ /* this program implements wildcard expansion for elvis/dos. It works * like UNIX echo, but uses the dos wildcard conventions * (*.* matches all files, * matches files without extension only, * filespecs may contain drive letters, wildcards not allowed in directory * names). * * It is also #included into ctags.c, ref.c, ...; in this case, * we don't want a main function here. */ #include <stdio.h> #include <ctype.h> #ifdef __TURBOC__ #include <dir.h> #endif #ifdef M_I86 #define findfirst(a,b,c) _dos_findfirst(a,c,b) #define findnext _dos_findnext #define ffblk find_t #define ff_name name #include <dos.h> #endif #ifdef M68000 #include <stat.h> #include <osbind.h> #define findfirst(a,b,c) (Fsetdta(b), (Fsfirst(a,c))) #define findnext(x) (Fsnext()) #define ff_name d_fname #endif #define MAXFILES 1000 int pstrcmp(); extern char *calloc(); char *files[MAXFILES]; int nfiles; #ifndef WILDCARD_NO_MAIN main(argc, argv) char **argv; { int i; for (i=1; i<argc; i++) expand(argv[i]); if (nfiles) printf("%s", files[0]); for (i=1; i<nfiles; i++) { printf(" %s", files[i]); } putchar('\n'); return 0; } #else char **wildexpand(argc, argv) int *argc; char **argv; { int i; for (i=0; i<*argc; i++) expand(argv[i]); *argc=nfiles; return files; } #endif expand(name) char *name; { char *filespec; int wildcard=0; #ifdef M68000 DMABUFFER findbuf; #else struct ffblk findbuf; #endif int err; char buf[80]; int lastn; strcpy(buf, name); for (filespec=buf; *filespec; filespec++) ; while (--filespec>=buf) { if (*filespec=='?' || *filespec=='*') wildcard=1; if (*filespec=='/' || *filespec=='\\' || *filespec==':') break; } if (!wildcard) addfile(buf); else { lastn=nfiles; filespec++; if ((err=findfirst(buf, &findbuf, 0))!=0) addfile(buf); while (!err) { strcpy(filespec, findbuf.ff_name); addfile(buf); err=findnext(&findbuf); } if (lastn!=nfiles) qsort(files+lastn, nfiles-lastn, sizeof(char *), pstrcmp); } } addfile(buf) char *buf; { char *p; for (p=buf; *p; p++) *p=tolower(*p); if (nfiles<MAXFILES && (files[nfiles]=calloc(strlen(buf)+1, 1))!=0) strcpy(files[nfiles++], buf); } int pstrcmp(a, b) char **a, **b; { return strcmp(*a, *b); } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0