home *** CD-ROM | disk | FTP | other *** search
- From: kirkenda@eecs.cs.pdx.edu (Steve Kirkendall)
- Newsgroups: alt.sources
- Subject: Elvis 1.4, part 5 of 8
- Message-ID: <829@pdxgate.UUCP>
- Date: 3 Dec 90 21:32:42 GMT
-
- # --------------------------- cut here ----------------------------
- # This is a shar archive. To unpack it, save it to a file, and delete
- # anything above the "cut here" line. Then run sh on the file.
- #
- # -rw-r--r-- 1 kirkenda 8819 Dec 2 17:57 curses.h
- # -rw-r--r-- 1 kirkenda 13222 Dec 2 17:57 cut.c
- # -rw-r--r-- 1 kirkenda 15130 Dec 2 17:57 ex.c
- # -rw-r--r-- 1 kirkenda 16368 Dec 2 17:57 input.c
- # -rw-r--r-- 1 kirkenda 7778 Dec 2 17:57 main.c
- # -rw-r--r-- 1 kirkenda 2166 Dec 2 17:57 misc.c
- #
-
- if test -f curses.h -a "$1" != -f
- then
- echo Will not overwrite curses.h
- else
- echo Extracting curses.h
- sed 's/^X//' >curses.h <<\eof
- X/* curses.h */
- X
- X/* Author:
- X * Steve Kirkendall
- X * 14407 SW Teal Blvd. #C
- X * Beaverton, OR 97005
- X * kirkenda@cs.pdx.edu
- X */
- X
- X
- X/* This is the header file for a small, fast, fake curses package */
- X
- X/* termcap stuff */
- Xextern char *tgoto();
- Xextern char *tgetstr();
- Xextern void tputs();
- X
- X#if MSDOS
- X/* BIOS interface used instead of termcap for MS-DOS */
- Xextern int vmode;
- Xextern void v_up();
- Xextern void v_cb();
- Xextern void v_cs();
- Xextern void v_ce();
- Xextern void v_cl();
- Xextern void v_cd();
- Xextern void v_al();
- Xextern void v_dl();
- Xextern void v_sr();
- Xextern void v_move();
- X#endif
- X
- X/* faddch() is a function. a pointer to it is passed to tputs() */
- Xextern int faddch();
- X
- X/* data types */
- X#define WINDOW char
- X
- X/* CONSTANTS & SYMBOLS */
- X#define TRUE 1
- X#define FALSE 0
- X#define A_NORMAL 0
- X#define A_STANDOUT 1
- X#define A_BOLD 2
- X#define A_UNDERLINE 3
- X#define A_ALTCHARSET 4
- X#if MSDOS
- X#define KBSIZ (10*1024)
- X#else
- X#define KBSIZ (6*1024)
- X#endif
- X
- X/* extern variables, defined in curses.c */
- Xextern short ospeed; /* tty speed, eg B2400 */
- X#if OSK
- Xextern char PC_; /* Pad char */
- Xextern char *BC; /* Backspace char string */
- X#else
- Xextern char PC; /* Pad char */
- X#endif
- Xextern WINDOW *stdscr; /* pointer into kbuf[] */
- Xextern WINDOW kbuf[KBSIZ]; /* a very large output buffer */
- Xextern int LINES; /* :li#: number of rows */
- Xextern int COLS; /* :co#: number of columns */
- Xextern int AM; /* :am: boolean: auto margins? */
- Xextern int PT; /* :pt: boolean: physical tabs? */
- Xextern char *VB; /* :vb=: visible bell */
- Xextern char *UP; /* :up=: move cursor up */
- Xextern char *SO; /* :so=: standout start */
- Xextern char *SE; /* :se=: standout end */
- Xextern char *US; /* :us=: underline start */
- Xextern char *UE; /* :ue=: underline end */
- Xextern char *MD; /* :md=: bold start */
- Xextern char *ME; /* :me=: bold end */
- Xextern char *AS; /* :as=: alternate (italic) start */
- Xextern char *AE; /* :ae=: alternate (italic) end */
- Xextern char *CM; /* :cm=: cursor movement */
- Xextern char *CE; /* :ce=: clear to end of line */
- Xextern char *CD; /* :cd=: clear to end of screen */
- Xextern char *AL; /* :al=: add a line */
- Xextern char *DL; /* :dl=: delete a line */
- X#if OSK
- Xextern char *SR_; /* :sr=: scroll reverse */
- X#else
- Xextern char *SR; /* :sr=: scroll reverse */
- X#endif
- Xextern char *KS; /* :ks=: init string for cursor */
- Xextern char *KE; /* :ke=: restore string for cursor */
- Xextern char *KU; /* :ku=: sequence sent by up key */
- Xextern char *KD; /* :kd=: sequence sent by down key */
- Xextern char *KL; /* :kl=: sequence sent by left key */
- Xextern char *KR; /* :kr=: sequence sent by right key */
- Xextern char *PU; /* :PU=: key sequence sent by PgUp key */
- Xextern char *PD; /* :PD=: key sequence sent by PgDn key */
- Xextern char *HM; /* :HM=: key sequence sent by Home key */
- Xextern char *EN; /* :EN=: key sequence sent by End key */
- Xextern char *IM; /* :im=: insert mode start */
- Xextern char *IC; /* :ic=: insert following char */
- Xextern char *EI; /* :ei=: insert mode end */
- Xextern char *DC; /* :dc=: delete a character */
- Xextern char *TI; /* :ti=: terminal init */ /* GB */
- Xextern char *TE; /* :te=: terminal exit */ /* GB */
- X#ifndef NO_CURSORSHAPE
- Xextern char *CQ; /* :cQ=: normal cursor */
- Xextern char *CX; /* :cX=: cursor used for EX command/entry */
- Xextern char *CV; /* :cV=: cursor used for VI command mode */
- Xextern char *CI; /* :cI=: cursor used for VI input mode */
- Xextern char *CR; /* :cR=: cursor used for VI replace mode */
- X#endif
- Xextern char *aend; /* end an attribute -- either UE or ME */
- Xextern char ERASEKEY; /* taken from the ioctl structure */
- X
- X/* Msdos-versions may use bios; others always termcap.
- X * Will emit some 'code has no effect' warnings in unix.
- X */
- X
- X#if MSDOS
- Xextern char o_pcbios[1]; /* BAH! */
- X#define CHECKBIOS(x,y) (*o_pcbios ? (x) : (y))
- X#define VOIDBIOS(x,y) {if (*o_pcbios) {x;} else {y;}}
- X#else
- X#define CHECKBIOS(x,y) (y)
- X#define VOIDBIOS(x,y) {y;}
- X#endif
- X
- X#define do_VB() VOIDBIOS(;, tputs(VB, 1, faddch))
- X#define do_UP() VOIDBIOS(v_up(), tputs(UP, 1, faddch))
- X#define do_SO() VOIDBIOS((vmode=A_STANDOUT), tputs(SO, 1, faddch))
- X#define do_SE() VOIDBIOS((vmode=A_NORMAL), tputs(SE, 1, faddch))
- X#define do_US() VOIDBIOS((vmode=A_UNDERLINE), tputs(US, 1, faddch))
- X#define do_UE() VOIDBIOS((vmode=A_NORMAL), tputs(UE, 1, faddch))
- X#define do_MD() VOIDBIOS((vmode=A_BOLD), tputs(MD, 1, faddch))
- X#define do_ME() VOIDBIOS((vmode=A_NORMAL), tputs(ME, 1, faddch))
- X#define do_AS() VOIDBIOS((vmode=A_ALTCHARSET), tputs(AS, 1, faddch))
- X#define do_AE() VOIDBIOS((vmode=A_NORMAL), tputs(AE, 1, faddch))
- X#undef do_CM /* move */
- X#define do_CE() VOIDBIOS(v_ce(), tputs(CE, 1, faddch))
- X#define do_CD() VOIDBIOS(v_cd(), tputs(CD, 1, faddch))
- X#define do_AL() VOIDBIOS(v_al(), tputs(AL, LINES, faddch))
- X#define do_DL() VOIDBIOS(v_dl(), tputs(DL, LINES, faddch))
- X#if OSK
- X#define do_SR() VOIDBIOS(v_sr(), tputs(SR_, 1, faddch))
- X#else
- X#define do_SR() VOIDBIOS(v_sr(), tputs(SR, 1, faddch))
- X#endif
- X#define do_KS() VOIDBIOS(1, tputs(KS, 1, faddch))
- X#define do_KE() VOIDBIOS(1, tputs(KE, 1, faddch))
- X#define do_IM() VOIDBIOS(;, tputs(IM, 1, faddch))
- X#define do_IC() VOIDBIOS(;, tputs(IC, 1, faddch))
- X#define do_EI() VOIDBIOS(;, tputs(EI, 1, faddch))
- X#define do_DC() VOIDBIOS(;, tputs(DC, COLS, faddch))
- X#define do_TI() VOIDBIOS(;, (void)ttywrite(TI, (unsigned)strlen(TI)))
- X#define do_TE() VOIDBIOS(;, (void)ttywrite(TE, (unsigned)strlen(TE)))
- X#ifndef NO_CURSORSHAPE
- X# define do_CQ() VOIDBIOS(v_cs(), tputs(CQ, 1, faddch))
- X# define do_CX() VOIDBIOS(v_cs(), tputs(CX, 1, faddch))
- X# define do_CV() VOIDBIOS(v_cs(), tputs(CV, 1, faddch))
- X# define do_CI() VOIDBIOS(v_cb(), tputs(CI, 1, faddch))
- X# define do_CR() VOIDBIOS(v_cb(), tputs(CR, 1, faddch))
- X#endif
- X#define do_aend() VOIDBIOS((vmode=A_NORMAL), tputs(aend, 1, faddch))
- X
- X#define has_AM CHECKBIOS(1, AM)
- X#define has_PT CHECKBIOS(0, PT)
- X#define has_VB CHECKBIOS((char *)0, VB)
- X#define has_UP CHECKBIOS((char *)1, UP)
- X#define has_SO CHECKBIOS((char)1, (*SO))
- X#define has_SE CHECKBIOS((char)1, (*SE))
- X#define has_US CHECKBIOS((char)1, (*US))
- X#define has_UE CHECKBIOS((char)1, (*UE))
- X#define has_MD CHECKBIOS((char)1, (*MD))
- X#define has_ME CHECKBIOS((char)1, (*ME))
- X#define has_AS CHECKBIOS((char)1, (*AS))
- X#define has_AE CHECKBIOS((char)1, (*AE))
- X#undef has_CM /* cursor move: don't need */
- X#define has_CB CHECKBIOS(1, 0)
- X#define has_CS CHECKBIOS(1, 0)
- X#define has_CE CHECKBIOS((char *)1, CE)
- X#define has_CD CHECKBIOS((char *)1, CD)
- X#define has_AL CHECKBIOS((char *)1, AL)
- X#define has_DL CHECKBIOS((char *)1, DL)
- X#if OSK
- X#define has_SR CHECKBIOS((char *)1, SR_)
- X#else
- X#define has_SR CHECKBIOS((char *)1, SR)
- X#endif
- X#define has_KS CHECKBIOS((char)1, (*KS))
- X#define has_KE CHECKBIOS((char)1, (*KE))
- X#define has_KU CHECKBIOS("#H", KU)
- X#define has_KD CHECKBIOS("#P", KD)
- X#define has_KL CHECKBIOS("#K", KL)
- X#define has_KR CHECKBIOS("#M", KR)
- X#define has_HM CHECKBIOS("#G", HM)
- X#define has_EN CHECKBIOS("#O", EN)
- X#define has_PU CHECKBIOS("#I", PU)
- X#define has_PD CHECKBIOS("#Q", PD)
- X#define has_IM CHECKBIOS((char)0, (*IM))
- X#define has_IC CHECKBIOS((char)0, (*IC))
- X#define has_EI CHECKBIOS((char)0, (*EI))
- X#define has_DC CHECKBIOS((char *)0, DC)
- X#define has_TI CHECKBIOS((char)0, (*TI))
- X#define has_TE CHECKBIOS((char)0, (*TE))
- X#ifndef NO_CURSORSHAPE
- X#define has_CQ CHECKBIOS((char *)1, CQ)
- X#endif
- X
- X/* (pseudo)-Curses-functions */
- X
- X#ifdef lint
- X# define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : (stdscr[-1] = '\n')))
- X#else
- X# if OSK
- X# define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\l') : (stdscr[-1] = stdscr[-1])))
- X# else
- X# define _addCR VOIDBIOS(;, (stdscr[-1] == '\n' ? qaddch('\r') : 0))
- X#endif
- X#endif
- X#define qaddch(ch) CHECKBIOS(v_put(ch), (*stdscr++ = (ch)))
- X#if OSK
- X#define addch(ch) if (qaddch(ch) == '\n') qaddch('\l'); else
- X#else
- X#define addch(ch) if (qaddch(ch) == '\n') qaddch('\r'); else
- X#endif
- X
- Xextern void initscr();
- Xextern void endwin();
- Xextern void suspend_curses();
- Xextern void resume_curses();
- Xextern void attrset();
- Xextern void insch();
- Xextern void qaddstr();
- X#define addstr(str) {qaddstr(str); _addCR;}
- X#define move(y,x) VOIDBIOS(v_move(x,y), \
- X tputs(tgoto(CM, x, y), 1, faddch))
- X#define mvaddch(y,x,ch) {move(y,x); addch(ch);}
- X#define refresh() VOIDBIOS(;, wrefresh(stdscr))
- X#define wrefresh(w) if ((w) != kbuf) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (unsigned)((w) - kbuf)); (w) = kbuf;}) else
- X#define wqrefresh(w) if ((w) - kbuf > 2000) VOIDBIOS((w) = kbuf, {ttywrite(kbuf, (unsigned)((w) - kbuf)); (w) = kbuf;}) else
- X#define standout() do_SO()
- X#define standend() do_SE()
- X#define clrtoeol() do_CE()
- X#define clrtobot() do_CD()
- X#define insertln() do_AL()
- X#define deleteln() do_DL()
- X#define delch() do_DC()
- X#define scrollok(w,b)
- X#define raw()
- X#define echo()
- X#define cbreak()
- X#define noraw()
- X#define noecho()
- X#define nocbreak()
- eof
- if test `wc -c <curses.h` -ne 8819
- then
- echo curses.h damaged!
- fi
- fi
-
- if test -f cut.c -a "$1" != -f
- then
- echo Will not overwrite cut.c
- else
- echo Extracting cut.c
- sed 's/^X//' >cut.c <<\eof
- X/* cut.c */
- X
- X/* Author:
- X * Steve Kirkendall
- X * 14407 SW Teal Blvd. #C
- X * Beaverton, OR 97005
- X * kirkenda@cs.pdx.edu
- X */
- X
- X
- X/* This file contains function which manipulate the cut buffers. */
- X
- X#include "config.h"
- X#include "vi.h"
- X#if TURBOC
- X#include <process.h> /* needed for getpid */
- X#endif
- X#if TOS
- X#include <osbind.h>
- X#define rename(a,b) Frename(0,a,b)
- X#endif
- X
- X# define NANNONS 9 /* number of annonymous buffers */
- X
- Xstatic struct cutbuf
- X{
- X short *phys; /* pointer to an array of #s of BLKs containing text */
- X int nblks; /* number of blocks in phys[] array */
- X int start; /* offset into first block of start of cut */
- X int end; /* offset into last block of end of cut */
- X int fd; /* fd of tmp file, or -1 to use tmpfd */
- X char lnmode; /* boolean: line-mode cut? (as opposed to char-mode) */
- X}
- X named[27], /* cut buffers "a through "z and ". */
- X annon[NANNONS]; /* annonymous cut buffers */
- X
- Xstatic char cbname; /* name chosen for next cut/paste operation */
- X
- X
- X#ifndef NO_RECYCLE
- X/* This function builds a list of all blocks needed in the current tmp file
- X * for the contents of cut buffers.
- X * !!! WARNING: if you have more than ~450000 bytes of text in all of the
- X * cut buffers, then this will fail disastrously, because buffer overflow
- X * is *not* allowed for.
- X */
- Xint cutneeds(need)
- X BLK *need; /* this is where we deposit the list */
- X{
- X struct cutbuf *cb; /* used to count through cut buffers */
- X int i; /* used to count through blocks of a cut buffer */
- X int n; /* total number of blocks in list */
- X
- X n = 0;
- X
- X /* first the named buffers... */
- X for (cb = named; cb < &named[27]; cb++)
- X {
- X if (cb->fd > 0)
- X continue;
- X
- X for (i = cb->nblks; i-- > 0; )
- X {
- X need->n[n++] = cb->phys[i];
- X }
- X }
- X
- X /* then the anonymous buffers */
- X for (cb = annon; cb < &annon[NANNONS]; cb++)
- X {
- X if (cb->fd > 0)
- X continue;
- X
- X for (i = cb->nblks; i-- > 0; )
- X {
- X need->n[n++] = cb->phys[i];
- X }
- X }
- X
- X return n;
- X}
- X#endif
- X
- X/* This function frees a cut buffer */
- Xstatic void cutfree(buf)
- X struct cutbuf *buf;
- X{
- X char cutfname[50];
- X int i;
- X
- X /* return immediately if the buffer is already empty */
- X if (buf->nblks <= 0)
- X {
- X return;
- X }
- X
- X /* else free up stuff */
- X buf->nblks = 0;
- X#ifdef DEBUG
- X if (!buf->phys)
- X msg("cutfree() tried to free an NULL buf->phys pointer.");
- X#endif
- X free((char *)buf->phys);
- X
- X /* see if anybody else needs this tmp file */
- X if (buf->fd >= 0)
- X {
- X for (i = 0; i < 27; i++)
- X {
- X if (named[i].nblks > 0 && named[i].fd == buf->fd)
- X {
- X break;
- X }
- X }
- X }
- X
- X /* if nobody else needs it, then discard the tmp file */
- X if (buf->fd >= 0 && i == 27)
- X {
- X close(buf->fd);
- X#if MSDOS || TOS
- X strcpy(cutfname, o_directory);
- X if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i-1]))
- X cutfname[i++]=SLASH;
- X sprintf(cutfname+i, CUTNAME+3, getpid(), buf->fd);
- X#else
- X sprintf(cutfname, CUTNAME, o_directory, getpid(), buf->fd);
- X#endif
- X unlink(cutfname);
- X }
- X}
- X
- X/* This function is called when we are about to abort a tmp file. If any
- X * cut buffers still need the file, then a copy of the file should be
- X * created for use by the cut buffers.
- X *
- X * To minimize the number of extra files lying around, only named cut buffers
- X * are preserved in a file switch; the annonymous buffers just go away.
- X */
- Xvoid cutswitch(tmpname)
- X char *tmpname; /* name of the tmp file */
- X{
- X char cutfname[50]; /* used to build a new name for the tmp file */
- X int fd; /* a new fd for the current tmp file */
- X int i;
- X#if MSDOS || TOS
- X int j;
- X#endif
- X
- X /* discard all annonymous cut buffers */
- X for (i = 0; i < NANNONS; i++)
- X {
- X cutfree(&annon[i]);
- X }
- X
- X /* find the first named buffer that uses this tmp file */
- X for (i = 0; i < 27; i++)
- X {
- X if (named[i].nblks > 0 && named[i].fd < 0)
- X {
- X break;
- X }
- X }
- X
- X /* if none of them use this tmp file, then we're done */
- X if (i == 27)
- X {
- X return;
- X }
- X
- X /* else we'll need this file and an fd a little longer */
- X#if MSDOS || TOS
- X strcpy(cutfname, o_directory);
- X if ((j = strlen(cutfname)) && !strchr(":/\\", cutfname[j-1]))
- X cutfname[j++]=SLASH;
- X close(tmpfd);
- X fd = open(tmpname, O_RDONLY|O_BINARY);
- X close(fd);
- X sprintf(cutfname+j, CUTNAME+3, getpid(), fd);
- X rename(tmpname, cutfname);
- X fd = open(cutfname, O_RDONLY|O_BINARY);
- X tmpfd = -1; /* we'll try to close this in tmp.c, but who cares? */
- X#else
- X fd = dup(tmpfd);
- X# if OSK
- X sprintf(cutfname, CUTNAME, "", getpid(), fd);
- X if (!link(tmpname, &cutfname[1])) /* skip slash */
- X unlink(tmpname);
- X# else
- X sprintf(cutfname, CUTNAME, o_directory, getpid(), fd);
- X link(tmpname, cutfname) || unlink(tmpname);
- X# endif
- X#endif
- X
- X /* have all cut buffers use the new fd instead */
- X for (; i < 27; i++)
- X {
- X if (named[i].nblks > 0 && named[i].fd < 0)
- X {
- X named[i].fd = fd;
- X }
- X }
- X}
- X
- X/* This function should be called just before termination of vi */
- Xvoid cutend()
- X{
- X int i;
- X
- X /* free all named cut buffers, since they might be forcing an older
- X * tmp file to be retained.
- X */
- X for (i = 0; i < 27; i++)
- X {
- X cutfree(&named[i]);
- X }
- X}
- X
- X
- X/* This function is used to select the cut buffer to be used next */
- Xvoid cutname(name)
- X int name; /* a single character */
- X{
- X cbname = name;
- X}
- X
- X
- X
- X
- X/* This function copies a selected segment of text to a cut buffer */
- Xvoid cut(from, to)
- X MARK from; /* start of text to cut */
- X MARK to; /* end of text to cut */
- X{
- X int first; /* logical number of first block in cut */
- X int last; /* logical number of last block used in cut */
- X long line; /* a line number */
- X int lnmode; /* boolean: will this be a line-mode cut? */
- X MARK delthru;/* end of text temporarily inserted for apnd */
- X REG struct cutbuf *cb;
- X REG long l;
- X REG int i;
- X REG char *scan;
- X char *blkc;
- X
- X /* detect whether this must be a line-mode cut or char-mode cut */
- X if (markidx(from) == 0 && markidx(to) == 0)
- X lnmode = TRUE;
- X else
- X lnmode = FALSE;
- X
- X /* by default, we don't "delthru" anything */
- X delthru = MARK_UNSET;
- X
- X /* decide which cut buffer to use */
- X if (!cbname)
- X {
- X /* free up the last annonymous cut buffer */
- X cutfree(&annon[NANNONS - 1]);
- X
- X /* shift the annonymous cut buffers */
- X for (i = NANNONS - 1; i > 0; i--)
- X {
- X annon[i] = annon[i - 1];
- X }
- X
- X /* use the first annonymous cut buffer */
- X cb = annon;
- X cb->nblks = 0;
- X }
- X else if (cbname >= 'a' && cbname <= 'z')
- X {
- X cb = &named[cbname - 'a'];
- X cutfree(cb);
- X }
- X#ifndef CRUNCH
- X else if (cbname >= 'A' && cbname <= 'Z')
- X {
- X cb = &named[cbname - 'A'];
- X if (cb->nblks > 0)
- X {
- X /* resolve linemode/charmode differences */
- X if (!lnmode && cb->lnmode)
- X {
- X from &= ~(BLKSIZE - 1);
- X if (markidx(to) != 0 || to == from)
- X {
- X to = to + BLKSIZE - markidx(to);
- X }
- X lnmode = TRUE;
- X }
- X
- X /* insert the old cut-buffer before the new text */
- X mark[28] = to;
- X delthru = paste(from, FALSE, TRUE);
- X if (delthru == MARK_UNSET)
- X {
- X return;
- X }
- X delthru++;
- X to = mark[28];
- X }
- X cutfree(cb);
- X }
- X#endif /* not CRUNCH */
- X else if (cbname == '.')
- X {
- X cb = &named[26];
- X cutfree(cb);
- X }
- X else
- X {
- X msg("Invalid cut buffer name: \"%c", cbname);
- X cbname = '\0';
- X return;
- X }
- X cbname = '\0';
- X cb->fd = -1;
- X
- X /* detect whether we're doing a line mode cut */
- X cb->lnmode = lnmode;
- X
- X /* ---------- */
- X
- X /* Reporting... */
- X if (markidx(from) == 0 && markidx(to) == 0)
- X {
- X rptlines = markline(to) - markline(from);
- X rptlabel = "yanked";
- X }
- X
- X /* ---------- */
- X
- X /* make sure each block has a physical disk address */
- X blksync();
- X
- X /* find the first block in the cut */
- X line = markline(from);
- X for (first = 1; line > lnum[first]; first++)
- X {
- X }
- X
- X /* fetch text of the block containing that line */
- X blkc = scan = blkget(first)->c;
- X
- X /* find the mark in the block */
- X for (l = lnum[first - 1]; ++l < line; )
- X {
- X while (*scan++ != '\n')
- X {
- X }
- X }
- X scan += markidx(from);
- X
- X /* remember the offset of the start */
- X cb->start = scan - blkc;
- X
- X /* ---------- */
- X
- X /* find the last block in the cut */
- X line = markline(to);
- X for (last = first; line > lnum[last]; last++)
- X {
- X }
- X
- X /* fetch text of the block containing that line */
- X if (last != first)
- X {
- X blkc = scan = blkget(last)->c;
- X }
- X else
- X {
- X scan = blkc;
- X }
- X
- X /* find the mark in the block */
- X for (l = lnum[last - 1]; ++l < line; )
- X {
- X while (*scan++ != '\n')
- X {
- X }
- X }
- X if (markline(to) <= nlines)
- X {
- X scan += markidx(to);
- X }
- X
- X /* remember the offset of the end */
- X cb->end = scan - blkc;
- X
- X /* ------- */
- X
- X /* remember the physical block numbers of all included blocks */
- X cb->nblks = last - first;
- X if (cb->end > 0)
- X {
- X cb->nblks++;
- X }
- X#ifdef lint
- X cb->phys = (short *)0;
- X#else
- X cb->phys = (short *)malloc((unsigned)(cb->nblks * sizeof(short)));
- X#endif
- X for (i = 0; i < cb->nblks; i++)
- X {
- X cb->phys[i] = hdr.n[first++];
- X }
- X
- X#ifndef CRUNCH
- X /* if we temporarily inserted text for appending, then delete that
- X * text now -- before the user sees it.
- X */
- X if (delthru)
- X {
- X line = rptlines;
- X delete(from, delthru);
- X rptlines = line;
- X rptlabel = "yanked";
- X }
- X#endif /* not CRUNCH */
- X}
- X
- X
- Xstatic void readcutblk(cb, blkno)
- X struct cutbuf *cb;
- X int blkno;
- X{
- X int fd; /* either tmpfd or cb->fd */
- X
- X /* decide which fd to use */
- X if (cb->fd >= 0)
- X {
- X fd = cb->fd;
- X }
- X else
- X {
- X fd = tmpfd;
- X }
- X
- X /* get the block */
- X lseek(fd, (long)cb->phys[blkno] * (long)BLKSIZE, 0);
- X if (read(fd, tmpblk.c, (unsigned)BLKSIZE) != BLKSIZE)
- X {
- X msg("Error reading back from tmp file for pasting!");
- X }
- X}
- X
- X
- X/* This function inserts text from a cut buffer, and returns the MARK where
- X * insertion ended. Return MARK_UNSET on errors.
- X */
- XMARK paste(at, after, retend)
- X MARK at; /* where to insert the text */
- X int after; /* boolean: insert after mark? (rather than before) */
- X int retend; /* boolean: return end of text? (rather than start) */
- X{
- X REG struct cutbuf *cb;
- X REG int i;
- X
- X /* decide which cut buffer to use */
- X if (cbname >= 'A' && cbname <= 'Z')
- X {
- X cb = &named[cbname - 'A'];
- X }
- X else if (cbname >= 'a' && cbname <= 'z')
- X {
- X cb = &named[cbname - 'a'];
- X }
- X else if (cbname >= '1' && cbname <= '9')
- X {
- X cb = &annon[cbname - '1'];
- X }
- X else if (cbname == '.')
- X {
- X cb = &named[26];
- X }
- X else if (!cbname)
- X {
- X cb = annon;
- X }
- X else
- X {
- X msg("Invalid cut buffer name: \"%c", cbname);
- X cbname = '\0';
- X return MARK_UNSET;
- X }
- X
- X /* make sure it isn't empty */
- X if (cb->nblks == 0)
- X {
- X if (cbname)
- X msg("Cut buffer \"%c is empty", cbname);
- X else
- X msg("Cut buffer is empty");
- X cbname = '\0';
- X return MARK_UNSET;
- X }
- X cbname = '\0';
- X
- X /* adjust the insertion MARK for "after" and line-mode cuts */
- X if (cb->lnmode)
- X {
- X at &= ~(BLKSIZE - 1);
- X if (after)
- X {
- X at += BLKSIZE;
- X }
- X }
- X else if (after)
- X {
- X /* careful! if markidx(at) == 0 we might be pasting into an
- X * empty line -- so we can't blindly increment "at".
- X */
- X if (markidx(at) == 0)
- X {
- X pfetch(markline(at));
- X if (plen != 0)
- X {
- X at++;
- X }
- X }
- X else
- X {
- X at++;
- X }
- X }
- X
- X /* put a copy of the "at" mark in the mark[] array, so it stays in
- X * sync with changes made via add().
- X */
- X mark[27] = at;
- X
- X /* simple one-block paste? */
- X if (cb->nblks == 1)
- X {
- X /* get the block */
- X readcutblk(cb, 0);
- X
- X /* isolate the text we need within it */
- X if (cb->end)
- X {
- X tmpblk.c[cb->end] = '\0';
- X }
- X
- X /* insert it */
- X ChangeText
- X {
- X add(at, &tmpblk.c[cb->start]);
- X }
- X }
- X else
- X {
- X /* multi-block paste */
- X
- X ChangeText
- X {
- X i = cb->nblks - 1;
- X
- X /* add text from the last block first */
- X if (cb->end > 0)
- X {
- X readcutblk(cb, i);
- X tmpblk.c[cb->end] = '\0';
- X add(at, tmpblk.c);
- X i--;
- X }
- X
- X /* add intervening blocks */
- X while (i > 0)
- X {
- X readcutblk(cb, i);
- X add(at, tmpblk.c);
- X i--;
- X }
- X
- X /* add text from the first cut block */
- X readcutblk(cb, 0);
- X add(at, &tmpblk.c[cb->start]);
- X }
- X }
- X
- X /* Reporting... */
- X rptlines = markline(mark[27]) - markline(at);
- X rptlabel = "pasted";
- X
- X /* return the mark at the beginning/end of inserted text */
- X if (retend)
- X {
- X return mark[27] - 1L;
- X }
- X return at;
- X}
- X
- X
- X
- X
- X#ifndef NO_AT
- X
- X/* This function copies characters from a cut buffer into a string.
- X * It returns the number of characters in the cut buffer. If the cut
- X * buffer is too large to fit in the string (i.e. if cb2str() returns
- X * a number >= size) then the characters will not have been copied.
- X * It returns 0 if the cut buffer is empty, and -1 for invalid cut buffers.
- X */
- Xint cb2str(name, buf, size)
- X int name; /* the name of a cut-buffer to get: a-z only! */
- X char *buf; /* where to put the string */
- X unsigned size; /* size of buf */
- X{
- X REG struct cutbuf *cb;
- X REG char *src;
- X REG char *dest;
- X
- X /* decide which cut buffer to use */
- X if (name >= 'a' && name <= 'z')
- X {
- X cb = &named[name - 'a'];
- X }
- X else
- X {
- X return -1;
- X }
- X
- X /* if the buffer is empty, return 0 */
- X if (cb->nblks == 0)
- X {
- X return 0;
- X }
- X
- X /* !!! if not a single-block cut, then fail */
- X if (cb->nblks != 1)
- X {
- X return size;
- X }
- X
- X /* if too big, return the size now, without doing anything */
- X if (cb->end - cb->start >= size)
- X {
- X return cb->end - cb->start;
- X }
- X
- X /* get the block */
- X readcutblk(cb, 0);
- X
- X /* isolate the string within that blk */
- X if (cb->start == 0)
- X {
- X tmpblk.c[cb->end] = '\0';
- X }
- X else
- X {
- X for (dest = tmpblk.c, src = dest + cb->start; src < tmpblk.c + cb->end; )
- X {
- X *dest++ = *src++;
- X }
- X *dest = '\0';
- X }
- X
- X /* copy the string into the buffer */
- X if (buf != tmpblk.c)
- X {
- X strcpy(buf, tmpblk.c);
- X }
- X
- X /* return the length */
- X return cb->end - cb->start;
- X}
- X#endif
- eof
- if test `wc -c <cut.c` -ne 13222
- then
- echo cut.c damaged!
- fi
- fi
-
- if test -f ex.c -a "$1" != -f
- then
- echo Will not overwrite ex.c
- else
- echo Extracting ex.c
- sed 's/^X//' >ex.c <<\eof
- X/* ex.c */
- X
- X/* Author:
- X * Steve Kirkendall
- X * 14407 SW Teal Blvd. #C
- X * Beaverton, OR 97005
- X * kirkenda@cs.pdx.edu
- X */
- X
- X
- X/* This file contains the code for reading ex commands. */
- X
- X#include "config.h"
- X#include <ctype.h>
- X#include "vi.h"
- X
- X#ifndef isascii
- X# define isascii(c) !((c)&~0x7f)
- X#endif
- X
- X/* This data type is used to describe the possible argument combinations */
- Xtypedef short ARGT;
- X#define FROM 1 /* allow a linespec */
- X#define TO 2 /* allow a second linespec */
- X#define BANG 4 /* allow a ! after the command name */
- X#define EXTRA 8 /* allow extra args after command name */
- X#define XFILE 16 /* expand wildcards in extra part */
- X#define NOSPC 32 /* no spaces allowed in the extra part */
- X#define DFLALL 64 /* default file range is 1,$ */
- X#define DFLNONE 128 /* no default file range */
- X#define NODFL 256 /* do not default to the current file name */
- X#define EXRCOK 512 /* can be in a .exrc file */
- X#define NL 1024 /* if mode!=MODE_EX, then write a newline first */
- X#define PLUS 2048 /* allow a line number, as in ":e +32 foo" */
- X#define ZERO 4096 /* allow 0 to be given as a line number */
- X#define FILES (XFILE + EXTRA) /* multiple extra files allowed */
- X#define WORD1 (EXTRA + NOSPC) /* one extra word allowed */
- X#define FILE1 (FILES + NOSPC) /* 1 file allowed, defaults to current file */
- X#define NAMEDF (FILE1 + NODFL) /* 1 file allowed, defaults to "" */
- X#define NAMEDFS (FILES + NODFL) /* multiple files allowed, default is "" */
- X#define RANGE (FROM + TO) /* range of linespecs allowed */
- X#define NONE 0 /* no args allowed at all */
- X
- X/* This array maps ex command names to command codes. The order in which
- X * command names are listed below is significant -- ambiguous abbreviations
- X * are always resolved to be the first possible match. (e.g. "r" is taken
- X * to mean "read", not "rewind", because "read" comes before "rewind")
- X */
- Xstatic struct
- X{
- X char *name; /* name of the command */
- X CMD code; /* enum code of the command */
- X void (*fn)();/* function which executes the command */
- X ARGT argt; /* command line arguments permitted/needed/used */
- X}
- X cmdnames[] =
- X{ /* cmd name cmd code function arguments */
- X {"append", CMD_APPEND, cmd_append, FROM+ZERO },
- X#ifdef DEBUG
- X {"bug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL},
- X#endif
- X {"change", CMD_CHANGE, cmd_append, RANGE },
- X {"delete", CMD_DELETE, cmd_delete, RANGE+WORD1 },
- X {"edit", CMD_EDIT, cmd_edit, BANG+FILE1+PLUS },
- X {"file", CMD_FILE, cmd_file, NAMEDF },
- X {"global", CMD_GLOBAL, cmd_global, RANGE+BANG+EXTRA+DFLALL},
- X {"insert", CMD_INSERT, cmd_append, FROM },
- X {"join", CMD_INSERT, cmd_join, RANGE },
- X {"k", CMD_MARK, cmd_mark, FROM+WORD1 },
- X {"list", CMD_LIST, cmd_print, RANGE+NL },
- X {"move", CMD_MOVE, cmd_move, RANGE+EXTRA },
- X {"next", CMD_NEXT, cmd_next, BANG+NAMEDFS },
- X {"Next", CMD_PREVIOUS, cmd_next, BANG },
- X {"print", CMD_PRINT, cmd_print, RANGE+NL },
- X {"quit", CMD_QUIT, cmd_xit, BANG },
- X {"read", CMD_READ, cmd_read, FROM+ZERO+NAMEDF},
- X {"substitute", CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA },
- X {"to", CMD_COPY, cmd_move, RANGE+EXTRA },
- X {"undo", CMD_UNDO, cmd_undo, NONE },
- X {"vglobal", CMD_VGLOBAL, cmd_global, RANGE+EXTRA+DFLALL},
- X {"write", CMD_WRITE, cmd_write, RANGE+BANG+FILE1+DFLALL},
- X {"xit", CMD_XIT, cmd_xit, BANG+NL },
- X {"yank", CMD_YANK, cmd_delete, RANGE+WORD1 },
- X
- X {"!", CMD_BANG, cmd_shell, EXRCOK+RANGE+NAMEDFS+DFLNONE+NL},
- X {"<", CMD_SHIFTL, cmd_shift, RANGE },
- X {">", CMD_SHIFTR, cmd_shift, RANGE },
- X {"=", CMD_EQUAL, cmd_file, RANGE },
- X {"&", CMD_SUBAGAIN, cmd_substitute, RANGE },
- X#ifndef NO_AT
- X {"@", CMD_AT, cmd_at, EXTRA },
- X#endif
- X
- X#ifndef NO_ABBR
- X {"abbreviate", CMD_ABBR, cmd_abbr, EXRCOK+EXTRA },
- X#endif
- X {"args", CMD_ARGS, cmd_args, EXRCOK+NAMEDFS },
- X#ifndef NO_ERRLIST
- X {"cc", CMD_CC, cmd_make, BANG+FILES },
- X#endif
- X {"cd", CMD_CD, cmd_cd, EXRCOK+NAMEDF },
- X {"copy", CMD_COPY, cmd_move, RANGE+EXTRA },
- X#ifndef NO_DIGRAPH
- X {"digraph", CMD_DIGRAPH, cmd_digraph, EXRCOK+BANG+EXTRA},
- X#endif
- X#ifndef NO_ERRLIST
- X {"errlist", CMD_ERRLIST, cmd_errlist, BANG+NAMEDF },
- X#endif
- X {"ex", CMD_EDIT, cmd_edit, BANG+FILE1 },
- X {"map", CMD_MAP, cmd_map, EXRCOK+BANG+EXTRA},
- X#ifndef NO_MKEXRC
- X {"mkexrc", CMD_MKEXRC, cmd_mkexrc, NAMEDF },
- X#endif
- X {"number", CMD_NUMBER, cmd_print, RANGE+NL },
- X {"put", CMD_PUT, cmd_put, FROM+ZERO+WORD1 },
- X {"set", CMD_SET, cmd_set, EXRCOK+EXTRA },
- X {"shell", CMD_SHELL, cmd_shell, NL },
- X {"source", CMD_SOURCE, cmd_source, EXRCOK+NAMEDF },
- X {"tag", CMD_TAG, cmd_tag, BANG+WORD1 },
- X {"version", CMD_VERSION, cmd_version, EXRCOK+NONE },
- X {"visual", CMD_VISUAL, cmd_visual, NONE },
- X {"wq", CMD_WQUIT, cmd_xit, NL },
- X
- X#ifdef DEBUG
- X {"debug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL},
- X {"validate", CMD_VALIDATE, cmd_validate, BANG+NL },
- X#endif
- X {"chdir", CMD_CD, cmd_cd, EXRCOK+NAMEDF },
- X#ifndef NO_ERRLIST
- X {"make", CMD_MAKE, cmd_make, BANG+NAMEDFS },
- X#endif
- X {"mark", CMD_MARK, cmd_mark, FROM+WORD1 },
- X {"previous", CMD_PREVIOUS, cmd_next, BANG },
- X {"rewind", CMD_REWIND, cmd_next, BANG },
- X {"unmap", CMD_UNMAP, cmd_map, EXRCOK+BANG+EXTRA},
- X#ifndef NO_ABBR
- X {"unabbreviate",CMD_UNABBR, cmd_abbr, EXRCOK+WORD1 },
- X#endif
- X
- X {(char *)0}
- X};
- X
- X
- X/* This function parses a search pattern - given a pointer to a / or ?,
- X * it replaces the ending / or ? with a \0, and returns a pointer to the
- X * stuff that came after the pattern.
- X */
- Xchar *parseptrn(ptrn)
- X REG char *ptrn;
- X{
- X REG char *scan;
- X
- X for (scan = ptrn + 1;
- X *scan && *scan != *ptrn;
- X scan++)
- X {
- X /* allow backslashed versions of / and ? in the pattern */
- X if (*scan == '\\' && scan[1] != '\0')
- X {
- X scan++;
- X }
- X }
- X if (*scan)
- X {
- X *scan++ = '\0';
- X }
- X
- X return scan;
- X}
- X
- X
- X/* This function parses a line specifier for ex commands */
- Xchar *linespec(s, markptr)
- X REG char *s; /* start of the line specifier */
- X MARK *markptr; /* where to store the mark's value */
- X{
- X long num;
- X REG char *t;
- X
- X /* parse each ;-delimited clause of this linespec */
- X do
- X {
- X /* skip an initial ';', if any */
- X if (*s == ';')
- X {
- X s++;
- X }
- X
- X /* skip leading spaces */
- X while (isascii(*s) && isspace(*s))
- X {
- X s++;
- X }
- X
- X /* dot means current position */
- X if (*s == '.')
- X {
- X s++;
- X *markptr = cursor;
- X }
- X /* '$' means the last line */
- X else if (*s == '$')
- X {
- X s++;
- X *markptr = MARK_LAST;
- X }
- X /* digit means an absolute line number */
- X else if (isascii(*s) && isdigit(*s))
- X {
- X for (num = 0; isascii(*s) && isdigit(*s); s++)
- X {
- X num = num * 10 + *s - '0';
- X }
- X *markptr = MARK_AT_LINE(num);
- X }
- X /* appostrophe means go to a set mark */
- X else if (*s == '\'')
- X {
- X s++;
- X *markptr = m_tomark(cursor, 1L, (int)*s);
- X s++;
- X }
- X /* slash means do a search */
- X else if (*s == '/' || *s == '?')
- X {
- X /* put a '\0' at the end of the search pattern */
- X t = parseptrn(s);
- X
- X /* search for the pattern */
- X *markptr &= ~(BLKSIZE - 1);
- X if (*s == '/')
- X {
- X pfetch(markline(*markptr));
- X if (plen > 0)
- X *markptr += plen - 1;
- X *markptr = m_fsrch(*markptr, s);
- X }
- X else
- X {
- X *markptr = m_bsrch(*markptr, s);
- X }
- X
- X /* adjust command string pointer */
- X s = t;
- X }
- X
- X /* if linespec was faulty, quit now */
- X if (!*markptr)
- X {
- X return s;
- X }
- X
- X /* maybe add an offset */
- X t = s;
- X if (*t == '-' || *t == '+')
- X {
- X s++;
- X for (num = 0; *s >= '0' && *s <= '9'; s++)
- X {
- X num = num * 10 + *s - '0';
- X }
- X if (num == 0)
- X {
- X num = 1;
- X }
- X *markptr = m_updnto(*markptr, num, *t);
- X }
- X } while (*s == ';' || *s == '+' || *s == '-');
- X
- X return s;
- X}
- X
- X
- X
- X/* This function reads an ex command and executes it. */
- Xvoid ex()
- X{
- X char cmdbuf[80];
- X REG int cmdlen;
- X static long oldline;
- X
- X significant = FALSE;
- X oldline = markline(cursor);
- X
- X while (mode == MODE_EX)
- X {
- X /* read a line */
- X cmdlen = vgets(':', cmdbuf, sizeof cmdbuf);
- X if (cmdlen < 0)
- X {
- X return;
- X }
- X
- X /* if empty line, assume ".+1" */
- X if (cmdlen == 0)
- X {
- X strcpy(cmdbuf, ".+1");
- X qaddch('\r');
- X clrtoeol();
- X }
- X else
- X {
- X addch('\n');
- X }
- X refresh();
- X
- X /* parse & execute the command */
- X doexcmd(cmdbuf);
- X
- X /* handle autoprint */
- X if (significant || markline(cursor) != oldline)
- X {
- X significant = FALSE;
- X oldline = markline(cursor);
- X if (*o_autoprint && mode == MODE_EX)
- X {
- X cmd_print(cursor, cursor, CMD_PRINT, FALSE, "");
- X }
- X }
- X }
- X}
- X
- Xvoid doexcmd(cmdbuf)
- X char *cmdbuf; /* string containing an ex command */
- X{
- X REG char *scan; /* used to scan thru cmdbuf */
- X MARK frommark; /* first linespec */
- X MARK tomark; /* second linespec */
- X REG int cmdlen; /* length of the command name given */
- X CMD cmd; /* what command is this? */
- X ARGT argt; /* argument types for this command */
- X short forceit; /* bang version of a command? */
- X REG int cmdidx; /* index of command */
- X REG char *build; /* used while copying filenames */
- X int iswild; /* boolean: filenames use wildcards? */
- X int isdfl; /* using default line ranges? */
- X int didsub; /* did we substitute file names for % or # */
- X
- X
- X /* ex commands can't be undone via the shift-U command */
- X U_line = 0L;
- X
- X /* ignore command lines that start with a double-quote */
- X if (*cmdbuf == '"')
- X {
- X return;
- X }
- X
- X /* permit extra colons at the start of the line */
- X while (*cmdbuf == ':')
- X {
- X cmdbuf++;
- X }
- X
- X /* parse the line specifier */
- X scan = cmdbuf;
- X if (nlines < 1)
- X {
- X /* no file, so don't allow addresses */
- X }
- X else if (*scan == '%')
- X {
- X /* '%' means all lines */
- X frommark = MARK_FIRST;
- X tomark = MARK_LAST;
- X scan++;
- X }
- X else if (*scan == '0')
- X {
- X frommark = tomark = MARK_UNSET;
- X scan++;
- X }
- X else
- X {
- X frommark = cursor;
- X scan = linespec(scan, &frommark);
- X tomark = frommark;
- X if (frommark && *scan == ',')
- X {
- X scan++;
- X scan = linespec(scan, &tomark);
- X }
- X if (!tomark)
- X {
- X /* faulty line spec -- fault already described */
- X return;
- X }
- X if (frommark > tomark)
- X {
- X msg("first address exceeds the second");
- X return;
- X }
- X }
- X isdfl = (scan == cmdbuf);
- X
- X /* skip whitespace */
- X while (isascii(*scan) && isspace(*scan))
- X {
- X scan++;
- X }
- X
- X /* if no command, then just move the cursor to the mark */
- X if (!*scan)
- X {
- X cursor = tomark;
- X return;
- X }
- X
- X /* figure out how long the command name is */
- X if (isascii(*scan) && !isalpha(*scan))
- X {
- X cmdlen = 1;
- X }
- X else
- X {
- X for (cmdlen = 1;
- X !isascii(scan[cmdlen]) || isalpha(scan[cmdlen]);
- X cmdlen++)
- X {
- X }
- X }
- X
- X /* lookup the command code */
- X for (cmdidx = 0;
- X cmdnames[cmdidx].name && strncmp(scan, cmdnames[cmdidx].name, cmdlen);
- X cmdidx++)
- X {
- X }
- X argt = cmdnames[cmdidx].argt;
- X cmd = cmdnames[cmdidx].code;
- X if (cmd == CMD_NULL)
- X {
- X#if OSK
- X msg("Unknown command \"%s\"", scan);
- X#else
- X msg("Unknown command \"%.*s\"", cmdlen, scan);
- X#endif
- X return;
- X }
- X
- X /* if the command ended with a bang, set the forceit flag */
- X scan += cmdlen;
- X if ((argt & BANG) && *scan == '!')
- X {
- X scan++;
- X forceit = 1;
- X }
- X else
- X {
- X forceit = 0;
- X }
- X
- X /* skip any more whitespace, to leave scan pointing to arguments */
- X while (isascii(*scan) && isspace(*scan))
- X {
- X scan++;
- X }
- X
- X /* a couple of special cases for filenames */
- X if (argt & XFILE)
- X {
- X /* if names were given, process them */
- X if (*scan)
- X {
- X for (build = tmpblk.c, iswild = didsub = FALSE; *scan; scan++)
- X {
- X switch (*scan)
- X {
- X case '%':
- X if (!*origname)
- X {
- X msg("No filename to substitute for %%");
- X return;
- X }
- X strcpy(build, origname);
- X while (*build)
- X {
- X build++;
- X }
- X didsub = TRUE;
- X break;
- X
- X case '#':
- X if (!*prevorig)
- X {
- X msg("No filename to substitute for #");
- X return;
- X }
- X strcpy(build, prevorig);
- X while (*build)
- X {
- X build++;
- X }
- X didsub = TRUE;
- X break;
- X
- X case '*':
- X case '?':
- X#if !(MSDOS || TOS)
- X case '[':
- X case '`':
- X case '{': /* } */
- X case '$':
- X case '~':
- X#endif
- X *build++ = *scan;
- X iswild = TRUE;
- X break;
- X
- X default:
- X *build++ = *scan;
- X }
- X }
- X *build = '\0';
- X
- X if (cmd == CMD_BANG
- X || cmd == CMD_READ && tmpblk.c[0] == '!'
- X || cmd == CMD_WRITE && tmpblk.c[0] == '!')
- X {
- X if (didsub)
- X {
- X if (mode != MODE_EX)
- X {
- X addch('\n');
- X }
- X addstr(tmpblk.c);
- X addch('\n');
- X exrefresh();
- X }
- X }
- X else
- X {
- X if (iswild && tmpblk.c[0] != '>')
- X {
- X scan = wildcard(tmpblk.c);
- X }
- X }
- X }
- X else /* no names given, maybe assume origname */
- X {
- X if (!(argt & NODFL))
- X {
- X strcpy(tmpblk.c, origname);
- X }
- X else
- X {
- X *tmpblk.c = '\0';
- X }
- X }
- X
- X scan = tmpblk.c;
- X }
- X
- X /* bad arguments? */
- X if (!(argt & EXRCOK) && nlines < 1L)
- X {
- X msg("Can't use the \"%s\" command in a %s file", cmdnames[cmdidx].name, EXRC);
- X return;
- X }
- X if (!(argt & (ZERO | EXRCOK)) && frommark == MARK_UNSET)
- X {
- X msg("Can't use address 0 with \"%s\" command.", cmdnames[cmdidx].name);
- X return;
- X }
- X if (!(argt & FROM) && frommark != cursor && nlines >= 1L)
- X {
- X msg("Can't use address with \"%s\" command.", cmdnames[cmdidx].name);
- X return;
- X }
- X if (!(argt & TO) && tomark != frommark && nlines >= 1L)
- X {
- X msg("Can't use a range with \"%s\" command.", cmdnames[cmdidx].name);
- X return;
- X }
- X if (!(argt & EXTRA) && *scan)
- X {
- X msg("Extra characters after \"%s\" command.", cmdnames[cmdidx].name);
- X return;
- X }
- X if ((argt & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!')))
- X {
- X build = scan;
- X#ifndef CRUNCH
- X if ((argt & PLUS) && *build == '+')
- X {
- X while (*build && !(isascii(*build) && isspace(*build)))
- X {
- X build++;
- X }
- X while (*build && isascii(*build) && isspace(*build))
- X {
- X build++;
- X }
- X }
- X#endif /* not CRUNCH */
- X for (; *build; build++)
- X {
- X if (isspace(*build))
- X {
- X msg("Too many %s to \"%s\" command.",
- X (argt & XFILE) ? "filenames" : "arguments",
- X cmdnames[cmdidx].name);
- X return;
- X }
- X }
- X }
- X
- X /* some commands have special default ranges */
- X if (isdfl && (argt & DFLALL))
- X {
- X frommark = MARK_FIRST;
- X tomark = MARK_LAST;
- X }
- X else if (isdfl && (argt & DFLNONE))
- X {
- X frommark = tomark = 0L;
- X }
- X
- X /* write a newline if called from visual mode */
- X if ((argt & NL) && mode != MODE_EX && !exwrote)
- X {
- X addch('\n');
- X exrefresh();
- X }
- X
- X /* act on the command */
- X (*cmdnames[cmdidx].fn)(frommark, tomark, cmd, forceit, scan);
- X}
- X
- X
- X/* This function executes EX commands from a file. It returns 1 normally, or
- X * 0 if the file could not be opened for reading.
- X */
- Xint doexrc(filename)
- X char *filename; /* name of a ".exrc" file */
- X{
- X int fd; /* file descriptor */
- X int len; /* length of the ".exrc" file */
- X char buf[MAXRCLEN]; /* buffer, holds the entire .exrc file */
- X
- X /* open the file, read it, and close */
- X fd = open(filename, O_RDONLY);
- X if (fd < 0)
- X {
- X return 0;
- X }
- X len = tread(fd, buf, MAXRCLEN);
- X close(fd);
- X
- X /* execute the string */
- X exstring(buf, len);
- X
- X return 1;
- X}
- X
- Xvoid exstring(buf, len)
- X char *buf; /* the commands to execute */
- X int len; /* the length of the string */
- X{
- X char *cmd; /* start of a command */
- X char *end; /* used to search for the end of cmd */
- X
- X /* find & do each command */
- X for (cmd = buf; cmd < &buf[len]; cmd = end + 1)
- X {
- X /* find the end of the command */
- X for (end = cmd; end < &buf[len] && *end != '\n' && *end != '|'; end++)
- X {
- X }
- X *end = '\0';
- X
- X /* do it */
- X doexcmd(cmd);
- X }
- X}
- eof
- if test `wc -c <ex.c` -ne 15130
- then
- echo ex.c damaged!
- fi
- fi
-
- if test -f input.c -a "$1" != -f
- then
- echo Will not overwrite input.c
- else
- echo Extracting input.c
- sed 's/^X//' >input.c <<\eof
- X/* input.c */
- X
- X/* Author:
- X * Steve Kirkendall
- X * 14407 SW Teal Blvd. #C
- X * Beaverton, OR 97005
- X * kirkenda@cs.pdx.edu
- X */
- X
- X
- X/* This file contains the input() function, which implements vi's INPUT mode.
- X * It also contains the code that supports digraphs.
- X */
- X
- X#include <ctype.h>
- X#include "config.h"
- X#include "vi.h"
- X
- X
- X#ifndef NO_DIGRAPH
- Xstatic struct _DIG
- X{
- X struct _DIG *next;
- X char key1;
- X char key2;
- X char dig;
- X char save;
- X} *digs;
- X
- Xchar digraph(key1, key2)
- X char key1; /* the underlying character */
- X char key2; /* the second character */
- X{
- X int newkey;
- X REG struct _DIG *dp;
- X
- X /* if digraphs are disabled, then just return the new char */
- X if (!*o_digraph)
- X {
- X return key2;
- X }
- X
- X /* remember the new key, so we can return it if this isn't a digraph */
- X newkey = key2;
- X
- X /* sort key1 and key2, so that their original order won't matter */
- X if (key1 > key2)
- X {
- X key2 = key1;
- X key1 = newkey;
- X }
- X
- X /* scan through the digraph chart */
- X for (dp = digs;
- X dp && (dp->key1 != key1 || dp->key2 != key2);
- X dp = dp->next)
- X {
- X }
- X
- X /* if this combination isn't in there, just use the new key */
- X if (!dp)
- X {
- X return newkey;
- X }
- X
- X /* else use the digraph key */
- X return dp->dig;
- X}
- X
- X/* this function lists or defines digraphs */
- Xvoid do_digraph(bang, extra)
- X int bang;
- X char extra[];
- X{
- X int dig;
- X REG struct _DIG *dp;
- X struct _DIG *prev;
- X static int user_defined = FALSE; /* boolean: are all later digraphs user-defined? */
- X char listbuf[8];
- X
- X /* if "extra" is NULL, then we've reached the end of the built-ins */
- X if (!extra)
- X {
- X user_defined = TRUE;
- X return;
- X }
- X
- X /* if no args, then display the existing digraphs */
- X if (*extra < ' ')
- X {
- X listbuf[0] = listbuf[1] = listbuf[2] = listbuf[5] = ' ';
- X listbuf[7] = '\0';
- X for (dig = 0, dp = digs; dp; dp = dp->next)
- X {
- X if (dp->save || bang)
- X {
- X dig += 7;
- X if (dig >= COLS)
- X {
- X addch('\n');
- X exrefresh();
- X dig = 7;
- X }
- X listbuf[3] = dp->key1;
- X listbuf[4] = dp->key2;
- X listbuf[6] = dp->dig;
- X qaddstr(listbuf);
- X }
- X }
- X addch('\n');
- X exrefresh();
- X return;
- X }
- X
- X /* make sure we have at least two characters */
- X if (!extra[1])
- X {
- X msg("Digraphs must be composed of two characters");
- X return;
- X }
- X
- X /* sort key1 and key2, so that their original order won't matter */
- X if (extra[0] > extra[1])
- X {
- X dig = extra[0];
- X extra[0] = extra[1];
- X extra[1] = dig;
- X }
- X
- X /* locate the new digraph character */
- X for (dig = 2; extra[dig] == ' ' || extra[dig] == '\t'; dig++)
- X {
- X }
- X dig = extra[dig];
- X if (!bang && dig)
- X {
- X dig |= 0x80;
- X }
- X
- X /* search for the digraph */
- X for (prev = (struct _DIG *)0, dp = digs;
- X dp && (dp->key1 != extra[0] || dp->key2 != extra[1]);
- X prev = dp, dp = dp->next)
- X {
- X }
- X
- X /* deleting the digraph? */
- X if (!dig)
- X {
- X if (!dp)
- X {
- X#ifndef CRUNCH
- X msg("%c%c not a digraph", extra[0], extra[1]);
- X#endif
- X return;
- X }
- X if (prev)
- X prev->next = dp->next;
- X else
- X digs = dp->next;
- X free(dp);
- X return;
- X }
- X
- X /* if necessary, create a new digraph struct for the new digraph */
- X if (dig && !dp)
- X {
- X dp = (struct _DIG *)malloc(sizeof *dp);
- X if (!dp)
- X {
- X msg("Out of space in the digraph table");
- X return;
- X }
- X if (prev)
- X prev->next = dp;
- X else
- X digs = dp;
- X dp->next = (struct _DIG *)0;
- X }
- X
- X /* assign it the new digraph value */
- X dp->key1 = extra[0];
- X dp->key2 = extra[1];
- X dp->dig = dig;
- X dp->save = user_defined;
- X}
- X
- X# ifndef NO_MKEXRC
- Xvoid savedigs(fd)
- X int fd;
- X{
- X static char buf[] = "digraph! XX Y\n";
- X REG struct _DIG *dp;
- X
- X for (dp = digs; dp; dp = dp->next)
- X {
- X if (dp->save)
- X {
- X buf[9] = dp->key1;
- X buf[10] = dp->key2;
- X buf[12] = dp->dig;
- X write(fd, buf, (unsigned)14);
- X }
- X }
- X}
- X# endif
- X#endif
- X
- X
- X#ifndef NO_ABBR
- Xstatic struct _AB
- X{
- X struct _AB *next;
- X char *large; /* the expanded form */
- X char small[1]; /* the abbreviated form (appended to struct) */
- X}
- X *abbrev;
- X
- X/* This functions lists or defines abbreviations */
- Xvoid do_abbr(extra)
- X char *extra;
- X{
- X int smlen; /* length of the small form */
- X int lrg; /* index of the start of the large form */
- X REG struct _AB *ab; /* used to move through the abbrev list */
- X struct _AB *prev;
- X
- X /* no arguments? */
- X if (!*extra)
- X {
- X /* list all current abbreviations */
- X for (ab = abbrev; ab; ab = ab->next)
- X {
- X qaddstr("abbr ");
- X qaddstr(ab->small);
- X qaddch(' ');
- X qaddstr(ab->large);
- X addch('\n');
- X exrefresh();
- X }
- X return;
- X }
- X
- X /* else one or more arguments. Parse the first & look up in abbrev[] */
- X for (smlen = 0; extra[smlen] && isalnum(extra[smlen]); smlen++)
- X {
- X }
- X for (prev = (struct _AB *)0, ab = abbrev; ab; prev = ab, ab = ab->next)
- X {
- X if (!strncmp(extra, ab->small, smlen) && !ab->small[smlen])
- X {
- X break;
- X }
- X }
- X
- X /* locate the start of the large form, if any */
- X for (lrg = smlen; extra[lrg] && isascii(extra[lrg]) && isspace(extra[lrg]); lrg++)
- X {
- X }
- X
- X /* only one arg? */
- X if (!extra[lrg])
- X {
- X /* trying to undo an abbreviation which doesn't exist? */
- X if (!ab)
- X {
- X#ifndef CRUNCH
- X msg("\"%s\" not an abbreviation", extra);
- X#endif
- X return;
- X }
- X
- X /* undo the abbreviation */
- X if (prev)
- X prev->next = ab->next;
- X else
- X abbrev = ab->next;
- X free(ab->large);
- X free(ab);
- X
- X return;
- X }
- X
- X /* multiple args - [re]define an abbreviation */
- X if (ab)
- X {
- X /* redefining - free the old large form */
- X free(ab->large);
- X }
- X else
- X {
- X /* adding a new definition - make a new struct */
- X ab = (struct _AB *)malloc((unsigned)(smlen + sizeof *ab));
- X#ifndef CRUNCH
- X if (!ab)
- X {
- X msg("Out of memory -- Sorry");
- X return;
- X }
- X#endif
- X strncpy(ab->small, extra, smlen);
- X ab->small[smlen] = '\0';
- X ab->next = (struct _AB *)0;
- X if (prev)
- X prev->next = ab;
- X else
- X abbrev = ab;
- X }
- X
- X /* store the new form */
- X ab->large = (char *)malloc((unsigned)(strlen(&extra[lrg]) + 1));
- X strcpy(ab->large, &extra[lrg]);
- X}
- X
- X
- X# ifndef NO_MKEXRC
- X/* This function is called from cmd_mkexrc() to save the abbreviations */
- Xvoid saveabbr(fd)
- X int fd; /* fd to which the :abbr commands should be written */
- X{
- X REG struct _AB *ab;
- X
- X for (ab = abbrev; ab; ab = ab->next)
- X {
- X twrite(fd, "abbr ", 5);
- X twrite(fd, ab->small, strlen(ab->small));
- X twrite(fd, " ", 1);
- X twrite(fd, ab->large, strlen(ab->large));
- X twrite(fd, "\n", 1);
- X }
- X}
- X# endif
- X
- X/* This function should be called before each char is inserted. If the next
- X * char is non-alphanumeric and we're at the end of a word, then that word
- X * is checked against the abbrev[] array and expanded, if appropriate. Upon
- X * returning from this function, the new char still must be inserted.
- X */
- Xstatic MARK expandabbr(m, ch)
- X MARK m; /* the cursor position */
- X int ch; /* the character to insert */
- X{
- X char *word; /* where the word starts */
- X int len; /* length of the word */
- X REG struct _AB *ab;
- X
- X /* if no abbreviations are in effect, or ch is aphanumeric, then
- X * don't do anything
- X */
- X if (!abbrev || !isascii(ch) || isalnum(ch))
- X {
- X return m;
- X }
- X
- X /* see where the preceding word starts */
- X pfetch(markline(m));
- X for (word = ptext + markidx(m), len = 0;
- X --word >= ptext && (!isascii(*word) || isalnum(*word));
- X len++)
- X {
- X }
- X word++;
- X
- X /* if zero-length, then it isn't a word, really -- so nothing */
- X if (len == 0)
- X {
- X return m;
- X }
- X
- X /* look it up in the abbrev list */
- X for (ab = abbrev; ab; ab = ab->next)
- X {
- X if (!strncmp(ab->small, word, len) && !ab->small[len])
- X {
- X break;
- X }
- X }
- X
- X /* not an abbreviation? then do nothing */
- X if (!ab)
- X {
- X return m;
- X }
- X
- X /* else replace the small form with the large form */
- X add(m, ab->large);
- X delete(m - len, m);
- X
- X /* return with the cursor after the end of the large form */
- X return m - len + strlen(ab->large);
- X}
- X#endif
- X
- X
- X/* This function allows the user to replace an existing (possibly zero-length)
- X * chunk of text with typed-in text. It returns the MARK of the last character
- X * that the user typed in.
- X */
- XMARK input(from, to, when)
- X MARK from; /* where to start inserting text */
- X MARK to; /* extent of text to delete */
- X int when; /* either WHEN_VIINP or WHEN_VIREP */
- X{
- X char key[2]; /* key char followed by '\0' char */
- X char *build; /* used in building a newline+indent string */
- X char *scan; /* used while looking at the indent chars of a line */
- X MARK m; /* some place in the text */
- X#ifndef NO_EXTENSIONS
- X int quit = FALSE; /* boolean: are we exiting after this? */
- X#endif
- X
- X#ifdef DEBUG
- X /* if "from" and "to" are reversed, complain */
- X if (from > to)
- X {
- X msg("ERROR: input(%ld:%d, %ld:%d)",
- X markline(from), markidx(from),
- X markline(to), markidx(to));
- X return MARK_UNSET;
- X }
- X#endif
- X
- X key[1] = 0;
- X
- X /* if we're replacing text with new text, save the old stuff */
- X /* (Alas, there is no easy way to save text for replace mode) */
- X if (from != to)
- X {
- X cut(from, to);
- X }
- X
- X ChangeText
- X {
- X /* if doing a dot command, then reuse the previous text */
- X if (doingdot)
- X {
- X /* delete the text that's there now */
- X if (from != to)
- X {
- X delete(from, to);
- X }
- X
- X /* insert the previous text */
- X cutname('.');
- X cursor = paste(from, FALSE, TRUE) + 1L;
- X }
- X else /* interactive version */
- X {
- X /* if doing a change within the line... */
- X if (from != to && markline(from) == markline(to))
- X {
- X /* mark the end of the text with a "$" */
- X change(to - 1, to, "$");
- X }
- X else
- X {
- X /* delete the old text right off */
- X if (from != to)
- X {
- X delete(from, to);
- X }
- X to = from;
- X }
- X
- X /* handle autoindent of the first line, maybe */
- X cursor = from;
- X if (*o_autoindent && markline(cursor) > 1L && markidx(cursor) == 0)
- X {
- X /* Only autoindent blank lines. */
- X pfetch(markline(cursor));
- X if (plen == 0)
- X {
- X /* Okay, we really want to autoindent */
- X pfetch(markline(cursor) - 1L);
- X for (scan = ptext, build = tmpblk.c;
- X *scan == ' ' || *scan == '\t';
- X )
- X {
- X *build++ = *scan++;
- X }
- X if (build > tmpblk.c)
- X {
- X *build = '\0';
- X add(cursor, tmpblk.c);
- X cursor += (build - tmpblk.c);
- X }
- X }
- X }
- X
- X /* repeatedly add characters from the user */
- X for (;;)
- X {
- X /* Get a character */
- X redraw(cursor, TRUE);
- X#ifdef DEBUG
- X msg("cursor=%ld.%d, to=%ld.%d",
- X markline(cursor), markidx(cursor),
- X markline(to), markidx(to));
- X#endif
- X key[0] = getkey(when);
- X
- X /* if whitespace & wrapmargin is set & we're
- X * past the warpmargin, then change the
- X * whitespace character into a newline
- X */
- X if ((*key == ' ' || *key == '\t')
- X && *o_wrapmargin != 0)
- X {
- X pfetch(markline(cursor));
- X if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
- X {
- X *key = '\n';
- X }
- X }
- X
- X /* process it */
- X switch (*key)
- X {
- X#ifndef NO_EXTENSIONS
- X case 0: /* special movement mapped keys */
- X *key = getkey(0);
- X switch (*key)
- X {
- X case 'h': m = m_left(cursor, 0L); break;
- X case 'j':
- X case 'k': m = m_updnto(cursor, 0L, *key); break;
- X case 'l': m = cursor + 1; break;
- X case 'b': m = m_bword(cursor, 0L); break;
- X case 'w': m = m_fword(cursor, 0L); break;
- X case '^': m = m_front(cursor, 0L); break;
- X case '$': m = m_rear(cursor, 0L); break;
- X case ctrl('B'):
- X case ctrl('F'):
- X m = m_scroll(cursor, 0L, *key); break;
- X case 'x': m = v_xchar(cursor, 0L); break;
- X case 'i': m = to = from = cursor; break;
- X default: m = MARK_UNSET; break;
- X }
- X /* adjust the moved cursor */
- X m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0));
- X if (*key == '$' || (*key == 'l' && m <= cursor))
- X {
- X m++;
- X }
- X /* if the cursor is reasonable, use it */
- X if (m == MARK_UNSET)
- X {
- X beep();
- X }
- X else
- X {
- X if (to > cursor)
- X {
- X delete(cursor, to);
- X redraw(cursor, TRUE);
- X }
- X from = to = cursor = m;
- X }
- X break;
- X
- X case ctrl('Z'):
- X if (getkey(0) == ctrl('Z'))
- X {
- X quit = TRUE;
- X goto BreakBreak;
- X }
- X break;
- X#endif
- X
- X case ctrl('['):
- X#ifndef NO_ABBR
- X cursor = expandabbr(cursor, ctrl('['));
- X#endif
- X goto BreakBreak;
- X
- X case ctrl('U'):
- X if (markline(cursor) == markline(from))
- X {
- X cursor = from;
- X }
- X else
- X {
- X cursor &= ~(BLKSIZE - 1);
- X }
- X break;
- X
- X case ctrl('D'):
- X case ctrl('T'):
- X if (to > cursor)
- X {
- X delete(cursor, to);
- X }
- X mark[27] = cursor;
- X cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
- X if (mark[27])
- X {
- X cursor = mark[27];
- X }
- X else
- X {
- X cursor = m_front(cursor, 0L);
- X }
- X to = cursor;
- X break;
- X
- X case '\b':
- X if (cursor <= from)
- X {
- X beep();
- X }
- X else if (markidx(cursor) == 0)
- X {
- X cursor -= BLKSIZE;
- X pfetch(markline(cursor));
- X cursor += plen;
- X }
- X else
- X {
- X cursor--;
- X }
- X break;
- X
- X case ctrl('W'):
- X m = m_bword(cursor, 1L);
- X if (markline(m) == markline(cursor) && m >= from)
- X {
- X cursor = m;
- X if (from > cursor)
- X {
- X from = cursor;
- X }
- X }
- X else
- X {
- X beep();
- X }
- X break;
- X
- X case '\n':
- X#if OSK
- X case '\l':
- X#else
- X case '\r':
- X#endif
- X#ifndef NO_ABBR
- X cursor = expandabbr(cursor, '\n');
- X#endif
- X build = tmpblk.c;
- X *build++ = '\n';
- X if (*o_autoindent)
- X {
- X /* figure out indent for next line */
- X pfetch(markline(cursor));
- X for (scan = ptext; *scan == ' ' || *scan == '\t'; )
- X {
- X *build++ = *scan++;
- X }
- X
- X /* remove indent from this line, if blank */
- X if (!*scan && plen > 0)
- X {
- X to = cursor &= ~(BLKSIZE - 1);
- X delete(cursor, cursor + plen);
- X }
- X }
- X *build = 0;
- X if (cursor >= to && when != WHEN_VIREP)
- X {
- X add(cursor, tmpblk.c);
- X }
- X else
- X {
- X change(cursor, to, tmpblk.c);
- X }
- X redraw(cursor, TRUE);
- X to = cursor = (cursor & ~(BLKSIZE - 1))
- X + BLKSIZE
- X + (int)(build - tmpblk.c) - 1;
- X break;
- X
- X case ctrl('A'):
- X case ctrl('P'):
- X if (cursor < to)
- X {
- X delete(cursor, to);
- X }
- X if (*key == ctrl('A'))
- X {
- X cutname('.');
- X }
- X to = cursor = paste(cursor, FALSE, TRUE) + 1L;
- X break;
- X
- X case ctrl('V'):
- X if (cursor >= to && when != WHEN_VIREP)
- X {
- X add(cursor, "^");
- X }
- X else
- X {
- X change(cursor, to, "^");
- X to = cursor + 1;
- X }
- X redraw(cursor, TRUE);
- X *key = getkey(0);
- X if (*key == '\n')
- X {
- X /* '\n' too hard to handle */
- X#if OSK
- X *key = '\l';
- X#else
- X *key = '\r';
- X#endif
- X }
- X change(cursor, cursor + 1, key);
- X cursor++;
- X if (cursor > to)
- X {
- X to = cursor;
- X }
- X break;
- X
- X case ctrl('L'):
- X case ctrl('R'):
- X redraw(MARK_UNSET, FALSE);
- X break;
- X
- X default:
- X if (cursor >= to && when != WHEN_VIREP)
- X {
- X#ifndef NO_ABBR
- X cursor = expandabbr(cursor, *key);
- X#endif
- X add(cursor, key);
- X cursor++;
- X to = cursor;
- X }
- X else
- X {
- X pfetch(markline(cursor));
- X if (markidx(cursor) == plen)
- X {
- X#ifndef NO_ABBR
- X cursor = expandabbr(cursor, *key);
- X#endif
- X add(cursor, key);
- X }
- X else
- X {
- X#ifndef NO_DIGRAPH
- X *key = digraph(ptext[markidx(cursor)], *key);
- X#endif
- X#ifndef NO_ABBR
- X cursor = expandabbr(cursor, *key);
- X#endif
- X change(cursor, cursor + 1, key);
- X }
- X cursor++;
- X }
- X#ifndef NO_SHOWMATCH
- X /* show matching "({[" if neceesary */
- X if (*o_showmatch && strchr(")}]", *key))
- X {
- X redraw(cursor, TRUE);
- X m = m_match(cursor - 1, 0L);
- X if (markline(m) >= topline
- X && markline(m) <= botline)
- X {
- X redraw(m, TRUE);
- X refresh();
- X sleep(1);
- X }
- X }
- X#endif
- X } /* end switch(*key) */
- X } /* end for(;;) */
- XBreakBreak:;
- X
- X /* delete any excess characters */
- X if (cursor < to)
- X {
- X delete(cursor, to);
- X }
- X
- X } /* end if doingdot else */
- X
- X } /* end ChangeText */
- X
- X /* put the new text into a cut buffer for possible reuse */
- X if (!doingdot)
- X {
- X blksync();
- X cutname('.');
- X cut(from, cursor);
- X }
- X
- X /* move to last char that we inputted, unless it was newline */
- X if (markidx(cursor) != 0)
- X {
- X cursor--;
- X }
- X redraw(cursor, FALSE);
- X
- X#ifndef NO_EXTENSIONS
- X if (quit)
- X {
- X /* if this is a nested "do", then cut it short */
- X abortdo();
- X
- X /* exit, unless we can't write out the file */
- X cursor = v_xit(cursor, 0L, 'Z');
- X }
- X#endif
- X
- X rptlines = 0L;
- X return cursor;
- X}
- eof
- if test `wc -c <input.c` -ne 16368
- then
- echo input.c damaged!
- fi
- fi
-
- if test -f main.c -a "$1" != -f
- then
- echo Will not overwrite main.c
- else
- echo Extracting main.c
- sed 's/^X//' >main.c <<\eof
- X/* main.c */
- X
- X/* Author:
- X * Steve Kirkendall
- X * 14407 SW Teal Blvd. #C
- X * Beaverton, OR 97005
- X * kirkenda@cs.pdx.edu
- X */
- X
- X
- X/* This file contains the main() function of vi */
- X
- X#include "config.h"
- X#include <signal.h>
- X#include <setjmp.h>
- X#include "vi.h"
- X
- Xextern trapint(); /* defined below */
- Xextern char *getenv();
- Xjmp_buf jmpenv;
- X
- X#ifndef NO_DIGRAPH
- Xstatic init_digraphs();
- X#endif
- X
- X/*---------------------------------------------------------------------*/
- X
- Xvoid main(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X int i;
- X char *cmd = (char *)0;
- X char *tag = (char *)0;
- X char *err = (char *)0;
- X char *str;
- X#if MSDOS || TOS
- X char firstarg[256];
- X#else
- X char *firstarg;
- X#endif
- X
- X /* set mode to MODE_VI or MODE_EX depending on program name */
- X switch (argv[0][strlen(argv[0]) - 1])
- X {
- X case 'x': /* "ex" */
- X mode = MODE_EX;
- X break;
- X
- X case 'w': /* "view" */
- X mode = MODE_VI;
- X *o_readonly = TRUE;
- X break;
- X#ifndef NO_EXTENSIONS
- X case 't': /* "edit" or "input" */
- X mode = MODE_VI;
- X *o_inputmode = TRUE;
- X break;
- X#endif
- X default: /* "vi" or "elvis" */
- X mode = MODE_VI;
- X }
- X
- X#ifndef DEBUG
- X# ifdef SIGQUIT
- X /* normally, we ignore SIGQUIT. SIGINT is trapped later */
- X signal(SIGQUIT, SIG_IGN);
- X# endif
- X#endif
- X
- X /* temporarily ignore SIGINT */
- X signal(SIGINT, SIG_IGN);
- X
- X /* start curses */
- X initscr();
- X cbreak();
- X noecho();
- X scrollok(stdscr, TRUE);
- X
- X /* initialize the options */
- X initopts();
- X
- X /* map the arrow keys. The KU,KD,KL,and KR variables correspond to
- X * the :ku=: (etc.) termcap capabilities. The variables are defined
- X * as part of the curses package.
- X */
- X if (has_KU) mapkey(has_KU, "k", WHEN_VICMD|WHEN_INMV, "<Up>");
- X if (has_KD) mapkey(has_KD, "j", WHEN_VICMD|WHEN_INMV, "<Down>");
- X if (has_KL) mapkey(has_KL, "h", WHEN_VICMD|WHEN_INMV, "<Left>");
- X if (has_KR) mapkey(has_KR, "l", WHEN_VICMD|WHEN_INMV, "<Right>");
- X if (has_HM) mapkey(has_HM, "^", WHEN_VICMD|WHEN_INMV, "<Home>");
- X if (has_EN) mapkey(has_EN, "$", WHEN_VICMD|WHEN_INMV, "<End>");
- X if (has_PU) mapkey(has_PU, "\002", WHEN_VICMD|WHEN_INMV, "<PgUp>");
- X if (has_PD) mapkey(has_PD, "\006", WHEN_VICMD|WHEN_INMV, "<PgDn>");
- X#if MSDOS
- X if (*o_pcbios)
- X {
- X mapkey("#R", "i", WHEN_VICMD|WHEN_INMV, "<Insrt>");
- X mapkey("#S", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
- X mapkey("#s", "B", WHEN_VICMD|WHEN_INMV, "^<left>");
- X mapkey("#t", "W", WHEN_VICMD|WHEN_INMV, "^<right>");
- X }
- X#else
- X if (ERASEKEY != '\177')
- X {
- X mapkey("\177", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
- X }
- X#endif
- X
- X#ifndef NO_DIGRAPH
- X init_digraphs();
- X#endif /* NO_DIGRAPH */
- X
- X /* process any flags */
- X for (i = 1; i < argc && *argv[i] == '-'; i++)
- X {
- X switch (argv[i][1])
- X {
- X case 'R': /* readonly */
- X *o_readonly = TRUE;
- X break;
- X
- X case 'r': /* recover */
- X msg("Use the `virec` program to recover lost files");
- X endmsgs();
- X refresh();
- X endwin();
- X exit(0);
- X break;
- X
- X case 't': /* tag */
- X if (argv[i][2])
- X {
- X tag = argv[i] + 2;
- X }
- X else
- X {
- X i++;
- X tag = argv[i];
- X }
- X break;
- X
- X case 'v': /* vi mode */
- X mode = MODE_VI;
- X break;
- X
- X case 'e': /* ex mode */
- X mode = MODE_EX;
- X break;
- X#ifndef NO_EXTENSIONS
- X case 'i': /* input mode */
- X *o_inputmode = TRUE;
- X break;
- X#endif
- X#ifndef NO_ERRLIST
- X case 'm': /* use "errlist" as the errlist */
- X if (argv[i][2])
- X {
- X err = argv[i] + 2;
- X }
- X else if (i + 1 < argc)
- X {
- X i++;
- X err = argv[i];
- X }
- X else
- X {
- X err = "";
- X }
- X break;
- X#endif
- X default:
- X msg("Ignoring unknown flag \"%s\"", argv[i]);
- X }
- X }
- X
- X /* if we were given an initial ex command, save it... */
- X if (i < argc && *argv[i] == '+')
- X {
- X if (argv[i][1])
- X {
- X cmd = argv[i++] + 1;
- X }
- X else
- X {
- X cmd = "$"; /* "vi + file" means start at EOF */
- X i++;
- X }
- X }
- X
- X /* the remaining args are file names. */
- X nargs = argc - i;
- X if (nargs > 0)
- X {
- X#if ! ( MSDOS || TOS )
- X firstarg = argv[i];
- X#endif
- X strcpy(args, argv[i]);
- X while (++i < argc && strlen(args) + 1 + strlen(argv[i]) < sizeof args)
- X {
- X strcat(args, " ");
- X strcat(args, argv[i]);
- X }
- X }
- X#if ! ( MSDOS || TOS )
- X else
- X {
- X firstarg = "";
- X }
- X#endif
- X argno = 0;
- X
- X#if MSDOS || TOS
- X if (nargs > 0)
- X {
- X strcpy(args, wildcard(args));
- X nargs = 1;
- X for (i = 0; args[i]; i++)
- X {
- X if (args[i] == ' ')
- X {
- X nargs++;
- X }
- X }
- X for (i = 0; args[i] && args[i] != ' '; i++)
- X {
- X firstarg[i] = args[i];
- X }
- X firstarg[i] = '\0';
- X }
- X else
- X {
- X firstarg[0] = '\0';
- X }
- X#endif
- X
- X /* perform the .exrc files and EXINIT environment variable */
- X#ifdef SYSEXRC
- X doexrc(SYSEXRC);
- X#endif
- X#ifdef HMEXRC
- X str = getenv("HOME");
- X if (str)
- X {
- X sprintf(tmpblk.c, "%s%c%s", str, SLASH, HMEXRC);
- X doexrc(tmpblk.c);
- X }
- X#endif
- X doexrc(EXRC);
- X#ifdef EXINIT
- X str = getenv(EXINIT);
- X if (str)
- X {
- X exstring(str, strlen(str));
- X }
- X#endif
- X
- X /* search for a tag (or an error) now, if desired */
- X blkinit();
- X if (tag)
- X {
- X cmd_tag(MARK_FIRST, MARK_FIRST, CMD_TAG, 0, tag);
- X }
- X#ifndef NO_ERRLIST
- X else if (err)
- X {
- X cmd_errlist(MARK_FIRST, MARK_FIRST, CMD_ERRLIST, 0, err);
- X }
- X#endif
- X
- X /* if no tag/err, or tag failed, then start with first arg */
- X if (tmpfd < 0 && tmpstart(firstarg) == 0 && *origname)
- X {
- X ChangeText
- X {
- X }
- X clrflag(file, MODIFIED);
- X }
- X
- X /* now we do the immediate ex command that we noticed before */
- X if (cmd)
- X {
- X doexcmd(cmd);
- X }
- X
- X /* repeatedly call ex() or vi() (depending on the mode) until the
- X * mode is set to MODE_QUIT
- X */
- X while (mode != MODE_QUIT)
- X {
- X if (setjmp(jmpenv))
- X {
- X /* Maybe we just aborted a change? */
- X abortdo();
- X }
- X#if TURBOC
- X signal(SIGINT, (void(*)()) trapint);
- X#else
- X signal(SIGINT, trapint);
- X#endif
- X
- X switch (mode)
- X {
- X case MODE_VI:
- X vi();
- X break;
- X
- X case MODE_EX:
- X ex();
- X break;
- X#ifdef DEBUG
- X default:
- X msg("mode = %d?", mode);
- X mode = MODE_QUIT;
- X#endif
- X }
- X }
- X
- X /* free up the cut buffers */
- X cutend();
- X
- X /* end curses */
- X#ifndef NO_CURSORSHAPE
- X if (has_CQ)
- X do_CQ();
- X#endif
- X endmsgs();
- X move(LINES - 1, 0);
- X clrtoeol();
- X refresh();
- X endwin();
- X
- X exit(0);
- X /*NOTREACHED*/
- X}
- X
- X
- X/*ARGSUSED*/
- Xint trapint(signo)
- X int signo;
- X{
- X resume_curses(FALSE);
- X abortdo();
- X#if OSK
- X sigmask(-1);
- X#endif
- X#if TURBO_C
- X signal(signo, (void (*)())trapint);
- X#else
- X signal(signo, trapint);
- X#endif
- X longjmp(jmpenv, 1);
- X
- X return 0;
- X}
- X
- X
- X#ifndef NO_DIGRAPH
- X
- X/* This stuff us used to build the default digraphs table. */
- Xstatic char digtable[][4] =
- X{
- X# if CS_IBMPC
- X "C,\200", "u\"\1", "e'\2", "a^\3",
- X "a\"\4", "a`\5", "a@\6", "c,\7",
- X "e^\10", "e\"\211", "e`\12", "i\"\13",
- X "i^\14", "i`\15", "A\"\16", "A@\17",
- X "E'\20", "ae\21", "AE\22", "o^\23",
- X "o\"\24", "o`\25", "u^\26", "u`\27",
- X "y\"\30", "O\"\31", "U\"\32", "a'\240",
- X "i'!", "o'\"", "u'#", "n~$",
- X "N~%", "a-&", "o-'", "~?(",
- X "~!-", "\"<.", "\">/",
- X# if CS_SPECIAL
- X "2/+", "4/,", "^+;", "^q<",
- X "^c=", "^r>", "^t?", "pp]",
- X "^^^", "oo_", "*a`", "*ba",
- X "*pc", "*Sd", "*se", "*uf",
- X "*tg", "*Ph", "*Ti", "*Oj",
- X "*dk", "*Hl", "*hm", "*En",
- X "*No", "eqp", "pmq", "ger",
- X "les", "*It", "*iu", "*/v",
- X "*=w", "sq{", "^n|", "^2}",
- X "^3~", "^_\377",
- X# endif /* CS_SPECIAL */
- X# endif /* CS_IBMPC */
- X# if CS_LATIN1
- X "~!!", "a-*", "\">+", "o-:",
- X "\"<>", "~??",
- X
- X "A`@", "A'A", "A^B", "A~C",
- X "A\"D", "A@E", "AEF", "C,G",
- X "E`H", "E'I", "E^J", "E\"K",
- X "I`L", "I'M", "I^N", "I\"O",
- X "-DP", "N~Q", "O`R", "O'S",
- X "O^T", "O~U", "O\"V", "O/X",
- X "U`Y", "U'Z", "U^[", "U\"\\",
- X "Y'_",
- X
- X "a``", "a'a", "a^b", "a~c",
- X "a\"d", "a@e", "aef", "c,g",
- X "e`h", "e'i", "e^j", "e\"k",
- X "i`l", "i'm", "i^n", "i\"o",
- X "-dp", "n~q", "o`r", "o's",
- X "o^t", "o~u", "o\"v", "o/x",
- X "u`y", "u'z", "u^{", "u\"|",
- X "y'~",
- X# endif /* CS_LATIN1 */
- X ""
- X};
- X
- Xstatic init_digraphs()
- X{
- X int i;
- X
- X for (i = 0; *digtable[i]; i++)
- X {
- X do_digraph(FALSE, digtable[i]);
- X }
- X do_digraph(FALSE, (char *)0);
- X}
- X#endif /* NO_DIGRAPH */
- eof
- if test `wc -c <main.c` -ne 7778
- then
- echo main.c damaged!
- fi
- fi
-
- if test -f misc.c -a "$1" != -f
- then
- echo Will not overwrite misc.c
- else
- echo Extracting misc.c
- sed 's/^X//' >misc.c <<\eof
- X/* misc.c */
- X
- X/* Author:
- X * Steve Kirkendall
- X * 14407 SW Teal Blvd. #C
- X * Beaverton, OR 97005
- X * kirkenda@cs.pdx.edu
- X */
- X
- X
- X/* This file contains functions which didn't seem happy anywhere else */
- X
- X#include "config.h"
- X#include "vi.h"
- X
- X
- X/* find a particular line & return a pointer to a copy of its text */
- Xchar *fetchline(line)
- X long line; /* line number of the line to fetch */
- X{
- X int i;
- X REG char *scan; /* used to search for the line in a BLK */
- X long l; /* line number counter */
- X static BLK buf; /* holds ONLY the selected line (as string) */
- X REG char *cpy; /* used while copying the line */
- X static long nextline; /* } These four variables are used */
- X static long chglevel; /* } to implement a shortcut when */
- X static char *nextscan; /* } consecutive lines are fetched */
- X static long nextlnum; /* } */
- X
- X /* can we do a shortcut? */
- X if (changes == chglevel && line == nextline)
- X {
- X scan = nextscan;
- X }
- X else
- X {
- X /* scan lnum[] to determine which block its in */
- X for (i = 1; line > lnum[i]; i++)
- X {
- X }
- X nextlnum = lnum[i];
- X
- X /* fetch text of the block containing that line */
- X scan = blkget(i)->c;
- X
- X /* find the line in the block */
- X for (l = lnum[i - 1]; ++l < line; )
- X {
- X while (*scan++ != '\n')
- X {
- X }
- X }
- X }
- X
- X /* copy it into a block by itself, with no newline */
- X for (cpy = buf.c; *scan != '\n'; )
- X {
- X *cpy++ = *scan++;
- X }
- X *cpy = '\0';
- X
- X /* maybe speed up the next call to fetchline() ? */
- X if (line < nextlnum)
- X {
- X nextline = line + 1;
- X chglevel = changes;
- X nextscan = scan + 1;
- X }
- X else
- X {
- X nextline = 0;
- X }
- X
- X /* Calls to fetchline() interfere with calls to pfetch(). Make sure
- X * that pfetch() resets itself on its next invocation.
- X */
- X pchgs = 0L;
- X
- X /* Return a pointer to the line's text */
- X return buf.c;
- X}
- X
- X
- X/* error message from the regexp code */
- Xvoid regerror(txt)
- X char *txt; /* an error message */
- X{
- X msg("RE error: %s", txt);
- X}
- X
- X/* This function is equivelent to the pfetch() macro */
- Xvoid pfetch(l)
- X long l; /* line number of line to fetch */
- X{
- X if(l != pline || changes != pchgs)
- X {
- X pline = (l);
- X ptext = fetchline(pline);
- X plen = strlen(ptext);
- X pchgs = changes;
- X }
- X}
- eof
- if test `wc -c <misc.c` -ne 2166
- then
- echo misc.c damaged!
- fi
- fi
-
- exit 0
- -------------------------------------------------------------------------------
- Steve Kirkendall kirkenda@cs.pdx.edu Grad student at Portland State U.
-