home *** CD-ROM | disk | FTP | other *** search
- From: kirkenda@eecs.cs.pdx.edu (Steve Kirkendall)
- Newsgroups: alt.sources
- Subject: Elvis 1.4, part 4 of 8
- Message-ID: <828@pdxgate.UUCP>
- Date: 3 Dec 90 21:31:07 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 9230 Dec 2 17:57 blk.c
- # -rw-r--r-- 1 kirkenda 23975 Dec 2 17:57 cmd1.c
- # -rw-r--r-- 1 kirkenda 16797 Dec 2 17:57 cmd2.c
- # -rw-r--r-- 1 kirkenda 7951 Dec 2 17:57 config.h
- # -rw-r--r-- 1 kirkenda 14196 Dec 2 17:57 curses.c
- #
-
- if test -f blk.c -a "$1" != -f
- then
- echo Will not overwrite blk.c
- else
- echo Extracting blk.c
- sed 's/^X//' >blk.c <<\eof
- X/* blk.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 functions that get/put blocks from the temp file.
- X * It also contains the "do" and "undo" functions.
- X */
- X
- X#include "config.h"
- X#include "vi.h"
- X
- X#ifndef NBUFS
- X# define NBUFS 5 /* must be at least 3 -- more is better */
- X#endif
- X
- Xextern long lseek();
- X
- X/*------------------------------------------------------------------------*/
- X
- XBLK hdr; /* buffer for the header block */
- X
- Xstatic int b4cnt; /* used to count context of beforedo/afterdo */
- Xstatic struct _blkbuf
- X{
- X BLK buf; /* contents of a text block */
- X unsigned short logical; /* logical block number */
- X int dirty; /* must the buffer be rewritten? */
- X}
- X blk[NBUFS], /* buffers for text[?] blocks */
- X *toonew, /* buffer which shouldn't be recycled yet */
- X *newtoo, /* another buffer which should be recycled */
- X *recycle = blk; /* next block to be recycled */
- X
- X
- X
- X
- X
- X/* This function wipes out all buffers */
- Xvoid blkinit()
- X{
- X int i;
- X
- X for (i = 0; i < NBUFS; i++)
- X {
- X blk[i].logical = 0;
- X blk[i].dirty = FALSE;
- X }
- X for (i = 0; i < MAXBLKS; i++)
- X {
- X hdr.n[i] = 0;
- X }
- X}
- X
- X/* This function allocates a buffer and fills it with a given block's text */
- XBLK *blkget(logical)
- X int logical; /* logical block number to fetch */
- X{
- X REG struct _blkbuf *this; /* used to step through blk[] */
- X REG int i;
- X
- X /* if logical is 0, just return the hdr buffer */
- X if (logical == 0)
- X {
- X return &hdr;
- X }
- X
- X /* see if we have that block in mem already */
- X for (this = blk; this < &blk[NBUFS]; this++)
- X {
- X if (this->logical == logical)
- X {
- X newtoo = toonew;
- X toonew = this;
- X return &this->buf;
- X }
- X }
- X
- X /* choose a block to be recycled */
- X do
- X {
- X this = recycle++;
- X if (recycle == &blk[NBUFS])
- X {
- X recycle = blk;
- X }
- X } while (this == toonew || this == newtoo);
- X
- X /* if it contains a block, flush that block */
- X blkflush(this);
- X
- X /* fill this buffer with the desired block */
- X this->logical = logical;
- X if (hdr.n[logical])
- X {
- X /* it has been used before - fill it from tmp file */
- X lseek(tmpfd, (long)hdr.n[logical] * (long)BLKSIZE, 0);
- X if (read(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE)
- X {
- X msg("Error reading back from tmp file!");
- X }
- X }
- X else
- X {
- X /* it is new - zero it */
- X for (i = 0; i < BLKSIZE; i++)
- X {
- X this->buf.c[i] = 0;
- X }
- X }
- X
- X /* This isn't really a change, but it does potentially invalidate
- X * the kinds of shortcuts that the "changes" variable is supposed
- X * to protect us from... so count it as a change.
- X */
- X changes++;
- X
- X /* mark it as being "not dirty" */
- X this->dirty = 0;
- X
- X /* return it */
- X newtoo = toonew;
- X toonew = this;
- X return &this->buf;
- X}
- X
- X
- X
- X/* This function writes a block out to the temporary file */
- Xvoid blkflush(this)
- X REG struct _blkbuf *this; /* the buffer to flush */
- X{
- X long seekpos; /* seek position of the new block */
- X unsigned short physical; /* physical block number */
- X
- X /* if its empty (an orphan blkadd() maybe?) then make it dirty */
- X if (this->logical && !*this->buf.c)
- X {
- X blkdirty(&this->buf);
- X }
- X
- X /* if it's an empty buffer or a clean version is on disk, quit */
- X if (!this->logical || hdr.n[this->logical] && !this->dirty)
- X {
- X return;
- X }
- X
- X /* find a free place in the file */
- X#ifndef NO_RECYCLE
- X seekpos = allocate();
- X lseek(tmpfd, seekpos, 0);
- X#else
- X seekpos = lseek(tmpfd, 0L, 2);
- X#endif
- X physical = seekpos / BLKSIZE;
- X
- X /* put the block there */
- X if (write(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE)
- X {
- X msg("Trouble writing to tmp file");
- X }
- X this->dirty = FALSE;
- X
- X /* update the header so it knows we put it there */
- X hdr.n[this->logical] = physical;
- X}
- X
- X
- X/* This function sets a block's "dirty" flag or deletes empty blocks */
- Xvoid blkdirty(bp)
- X BLK *bp; /* buffer returned by blkget() */
- X{
- X REG int i, j;
- X REG char *scan;
- X REG int k;
- X
- X /* find the buffer */
- X for (i = 0; i < NBUFS && bp != &blk[i].buf; i++)
- X {
- X }
- X#ifdef DEBUG
- X if (i >= NBUFS)
- X {
- X msg("blkdirty() called with unknown buffer at 0x%lx", bp);
- X return;
- X }
- X if (blk[i].logical == 0)
- X {
- X msg("blkdirty called with freed buffer");
- X return;
- X }
- X#endif
- X
- X /* if this block ends with line# INFINITY, then it must have been
- X * allocated unnecessarily during tmpstart(). Forget it.
- X */
- X if (lnum[blk[i].logical] == INFINITY)
- X {
- X#ifdef DEBUG
- X if (blk[i].buf.c[0])
- X {
- X msg("bkldirty called with non-empty extra BLK");
- X }
- X#endif
- X blk[i].logical = 0;
- X blk[i].dirty = FALSE;
- X return;
- X }
- X
- X /* count lines in this block */
- X for (j = 0, scan = bp->c; *scan && scan < bp->c + BLKSIZE; scan++)
- X {
- X if (*scan == '\n')
- X {
- X j++;
- X }
- X }
- X
- X /* adjust lnum, if necessary */
- X k = blk[i].logical;
- X j += (lnum[k - 1] - lnum[k]);
- X if (j != 0)
- X {
- X nlines += j;
- X while (k < MAXBLKS && lnum[k] != INFINITY)
- X {
- X lnum[k++] += j;
- X }
- X }
- X
- X /* if it still has text, mark it as dirty */
- X if (*bp->c)
- X {
- X blk[i].dirty = TRUE;
- X }
- X else /* empty block, so delete it */
- X {
- X /* adjust the cache */
- X k = blk[i].logical;
- X for (j = 0; j < NBUFS; j++)
- X {
- X if (blk[j].logical >= k)
- X {
- X blk[j].logical--;
- X }
- X }
- X
- X /* delete it from hdr.n[] and lnum[] */
- X blk[i].logical = 0;
- X blk[i].dirty = FALSE;
- X while (k < MAXBLKS - 1)
- X {
- X hdr.n[k] = hdr.n[k + 1];
- X lnum[k] = lnum[k + 1];
- X k++;
- X }
- X hdr.n[MAXBLKS - 1] = 0;
- X lnum[MAXBLKS - 1] = INFINITY;
- X }
- X}
- X
- X
- X/* insert a new block into hdr, and adjust the cache */
- XBLK *blkadd(logical)
- X int logical; /* where to insert the new block */
- X{
- X REG int i;
- X
- X /* adjust hdr and lnum[] */
- X for (i = MAXBLKS - 1; i > logical; i--)
- X {
- X hdr.n[i] = hdr.n[i - 1];
- X lnum[i] = lnum[i - 1];
- X }
- X hdr.n[logical] = 0;
- X lnum[logical] = lnum[logical - 1];
- X
- X /* adjust the cache */
- X for (i = 0; i < NBUFS; i++)
- X {
- X if (blk[i].logical >= logical)
- X {
- X blk[i].logical++;
- X }
- X }
- X
- X /* return the new block, via blkget() */
- X return blkget(logical);
- X}
- X
- X
- X/* This function forces all dirty blocks out to disk */
- Xvoid blksync()
- X{
- X int i;
- X
- X for (i = 0; i < NBUFS; i++)
- X {
- X /* blk[i].dirty = TRUE; */
- X blkflush(&blk[i]);
- X }
- X if (*o_sync)
- X {
- X sync();
- X }
- X}
- X
- X/*------------------------------------------------------------------------*/
- X
- Xstatic MARK undocurs; /* where the cursor should go if undone */
- Xstatic long oldnlines;
- Xstatic long oldlnum[MAXBLKS];
- X
- X
- X/* This function should be called before each command that changes the text.
- X * It defines the state that undo() will reset the file to.
- X */
- Xvoid beforedo(forundo)
- X int forundo; /* boolean: is this for an undo? */
- X{
- X REG int i;
- X REG long l;
- X
- X /* if this is a nested call to beforedo, quit! Use larger context */
- X if (b4cnt++ > 0)
- X {
- X return;
- X }
- X
- X /* force all block buffers to disk */
- X blksync();
- X
- X#ifndef NO_RECYCLE
- X /* perform garbage collection on blocks from tmp file */
- X garbage();
- X#endif
- X
- X /* force the header out to disk */
- X lseek(tmpfd, 0L, 0);
- X if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) != BLKSIZE)
- X {
- X msg("Trouble writing header to tmp file ");
- X }
- X
- X /* copy or swap oldnlines <--> nlines, oldlnum <--> lnum */
- X if (forundo)
- X {
- X for (i = 0; i < MAXBLKS; i++)
- X {
- X l = lnum[i];
- X lnum[i] = oldlnum[i];
- X oldlnum[i] = l;
- X }
- X l = nlines;
- X nlines = oldnlines;
- X oldnlines = l;
- X }
- X else
- X {
- X for (i = 0; i < MAXBLKS; i++)
- X {
- X oldlnum[i] = lnum[i];
- X }
- X oldnlines = nlines;
- X }
- X
- X /* save the cursor position */
- X undocurs = cursor;
- X
- X /* upon return, the calling function continues and makes changes... */
- X}
- X
- X/* This function marks the end of a (nested?) change to the file */
- Xvoid afterdo()
- X{
- X if (--b4cnt)
- X {
- X /* after abortdo(), b4cnt may decribe nested beforedo/afterdo
- X * pairs incorrectly. If it is decremented to often, then
- X * keep b4cnt sane but don't do anything else.
- X */
- X if (b4cnt < 0)
- X b4cnt = 0;
- X
- X return;
- X }
- X
- X /* make sure the cursor wasn't left stranded in deleted text */
- X if (markline(cursor) > nlines)
- X {
- X cursor = MARK_LAST;
- X }
- X /* NOTE: it is still possible that markidx(cursor) is after the
- X * end of a line, so the Vi mode will have to take care of that
- X * itself */
- X
- X /* if a significant change has been made to this file, then set the
- X * MODIFIED flag.
- X */
- X if (significant)
- X {
- X setflag(file, MODIFIED);
- X }
- X}
- X
- X/* This function cuts short the current set of changes. It is called after
- X * a SIGINT.
- X */
- Xvoid abortdo()
- X{
- X /* finish the operation immediately. */
- X if (b4cnt > 0)
- X {
- X b4cnt = 1;
- X afterdo();
- X }
- X
- X /* in visual mode, the screen is probably screwed up */
- X if (mode == MODE_COLON)
- X {
- X mode = MODE_VI;
- X }
- X if (mode == MODE_VI)
- X {
- X redraw(MARK_UNSET, FALSE);
- X }
- X}
- X
- X/* This function discards all changes made since the last call to beforedo() */
- Xint undo()
- X{
- X BLK oldhdr;
- X
- X /* if beforedo() has never been run, fail */
- X if (!tstflag(file, MODIFIED))
- X {
- X msg("You haven't modified this file yet.");
- X return FALSE;
- X }
- X
- X /* read the old header form the tmp file */
- X lseek(tmpfd, 0L, 0);
- X if (read(tmpfd, oldhdr.c, (unsigned)BLKSIZE) != BLKSIZE)
- X {
- X msg("Trouble rereading the old header from tmp file");
- X }
- X
- X /* "do" the changed version, so we can undo the "undo" */
- X cursor = undocurs;
- X beforedo(TRUE);
- X afterdo();
- X
- X /* wipe out the block buffers - we can't assume they're correct */
- X blkinit();
- X
- X /* use the old header -- and therefore the old text blocks */
- X hdr = oldhdr;
- X
- X /* This is a change */
- X changes++;
- X
- X return TRUE;
- X}
- eof
- if test `wc -c <blk.c` -ne 9230
- then
- echo blk.c damaged!
- fi
- fi
-
- if test -f cmd1.c -a "$1" != -f
- then
- echo Will not overwrite cmd1.c
- else
- echo Extracting cmd1.c
- sed 's/^X//' >cmd1.c <<\eof
- X/* cmd1.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 some of the EX commands - mostly ones that deal with
- X * files, options, etc. -- anything except text.
- X */
- X
- X#include "config.h"
- X#include <ctype.h>
- X#include "vi.h"
- X#include "regexp.h"
- X
- X#if MSDOS
- X#define DATE __DATE__
- X#endif
- X
- X#ifdef DEBUG
- X/* print the selected lines with info on the blocks */
- X/*ARGSUSED*/
- Xvoid cmd_debug(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X REG char *scan;
- X REG long l;
- X REG int i;
- X int len;
- X
- X /* scan lnum[] to determine which block its in */
- X l = markline(frommark);
- X for (i = 1; l > lnum[i]; i++)
- X {
- X }
- X
- X do
- X {
- X /* fetch text of the block containing that line */
- X scan = blkget(i)->c;
- X
- X /* calculate its length */
- X if (scan[BLKSIZE - 1])
- X {
- X len = BLKSIZE;
- X }
- X else
- X {
- X len = strlen(scan);
- X }
- X
- X /* print block stats */
- X msg("##### hdr[%d]=%d, lnum[%d-1]=%ld, lnum[%d]=%ld (%ld lines)",
- X i, hdr.n[i], i, lnum[i-1], i, lnum[i], lnum[i] - lnum[i - 1]);
- X msg("##### len=%d, buf=0x%lx, %sdirty",
- X len, scan, ((int *)scan)[MAXBLKS + 1] ? "" : "not ");
- X if (bang)
- X {
- X while (--len >= 0)
- X {
- X addch(*scan);
- X scan++;
- X }
- X }
- X exrefresh();
- X
- X /* next block */
- X i++;
- X } while (i < MAXBLKS && lnum[i] && lnum[i - 1] < markline(tomark));
- X}
- X
- X
- X/* This function checks a lot of conditions to make sure they aren't screwy */
- X/*ARGSUSED*/
- Xvoid cmd_validate(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X char *scan;
- X int i;
- X int nlcnt; /* used to count newlines */
- X int len; /* counts non-NUL characters */
- X
- X /* check lnum[0] */
- X if (lnum[0] != 0L)
- X {
- X msg("lnum[0] = %ld", lnum[0]);
- X }
- X
- X /* check each block */
- X for (i = 1; lnum[i] <= nlines; i++)
- X {
- X scan = blkget(i)->c;
- X if (scan[BLKSIZE - 1])
- X {
- X msg("block %d has no NUL at the end", i);
- X }
- X else
- X {
- X for (nlcnt = len = 0; *scan; scan++, len++)
- X {
- X if (*scan == '\n')
- X {
- X nlcnt++;
- X }
- X }
- X if (scan[-1] != '\n')
- X {
- X msg("block %d doesn't end with '\\n' (length %d)", i, len);
- X }
- X if (bang || nlcnt != lnum[i] - lnum[i - 1])
- X {
- X msg("block %d (line %ld?) has %d lines, but should have %ld",
- X i, lnum[i - 1] + 1L, nlcnt, lnum[i] - lnum[i - 1]);
- X }
- X }
- X exrefresh();
- X }
- X
- X /* check lnum again */
- X if (lnum[i] != INFINITY)
- X {
- X msg("hdr.n[%d] = %d, but lnum[%d] = %ld",
- X i, hdr.n[i], i, lnum[i]);
- X }
- X
- X msg("# = \"%s\", %% = \"%s\"", prevorig, origname);
- X}
- X#endif /* DEBUG */
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_mark(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X /* validate the name of the mark */
- X if (!extra || *extra < 'a' || *extra > 'z' || extra[1])
- X {
- X msg("Invalid mark name");
- X return;
- X }
- X
- X mark[*extra - 'a'] = tomark;
- X}
- X
- X/*ARGSUSED*/
- Xvoid cmd_write(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X int fd;
- X int append; /* boolean: write in "append" mode? */
- X REG long l;
- X REG char *scan;
- X REG int i;
- X
- X /* if all lines are to be written, use tmpsave() */
- X if (frommark == MARK_FIRST && tomark == MARK_LAST)
- X {
- X tmpsave(extra, bang);
- X return;
- X }
- X
- X /* see if we're going to do this in append mode or not */
- X append = FALSE;
- X if (extra[0] == '>' && extra[1] == '>')
- X {
- X extra += 2;
- X append = TRUE;
- X }
- X
- X /* either the file must not exist, or we must have a ! or be appending */
- X if (access(extra, 0) == 0 && !bang && !append)
- X {
- X msg("File already exists - Use :w! to overwrite");
- X return;
- X }
- X
- X /* else do it line-by-line, like cmd_print() */
- X if (append)
- X {
- X#ifdef O_APPEND
- X fd = open(extra, O_WRONLY|O_APPEND);
- X#else
- X fd = open(extra, O_WRONLY);
- X if (fd >= 0)
- X {
- X lseek(fd, 0L, 2);
- X }
- X#endif
- X }
- X else
- X {
- X fd = -1; /* so we know the file isn't open yet */
- X }
- X
- X if (fd < 0)
- X {
- X fd = creat(extra, FILEPERMS);
- X if (fd < 0)
- X {
- X msg("Can't write to \"%s\"", extra);
- X return;
- X }
- X }
- X for (l = markline(frommark); l <= markline(tomark); l++)
- X {
- X /* get the next line */
- X scan = fetchline(l);
- X i = strlen(scan);
- X scan[i++] = '\n';
- X
- X /* print the line */
- X twrite(fd, scan, i);
- X }
- X close(fd);
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_shell(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X static char prevextra[80];
- X
- X /* special case: ":sh" means ":!sh" */
- X if (cmd == CMD_SHELL)
- X {
- X extra = o_shell;
- X frommark = tomark = 0L;
- X }
- X
- X /* if extra is "!", substute previous command */
- X if (*extra == '!')
- X {
- X if (!*prevextra)
- X {
- X msg("No previous shell command to substitute for '!'");
- X return;
- X }
- X extra = prevextra;
- X }
- X else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1)
- X {
- X strcpy(prevextra, extra);
- X }
- X
- X /* if no lines were specified, just run the command */
- X suspend_curses();
- X if (frommark == 0L)
- X {
- X system(extra);
- X }
- X else /* pipe lines from the file through the command */
- X {
- X filter(frommark, tomark, extra);
- X }
- X
- X /* resume curses quietly for MODE_EX, but noisily otherwise */
- X resume_curses(mode == MODE_EX);
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_global(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra; /* rest of the command line */
- X{
- X char *cmdptr; /* the command from the command line */
- X char cmdln[100]; /* copy of the command from the command line */
- X char *line; /* a line from the file */
- X long l; /* used as a counter to move through lines */
- X long lqty; /* quantity of lines to be scanned */
- X long nchanged; /* number of lines changed */
- X regexp *re; /* the compiled search expression */
- X
- X /* can't nest global commands */
- X if (doingglobal)
- X {
- X msg("Can't nest global commands.");
- X rptlines = -1L;
- X return;
- X }
- X
- X /* ":g! ..." is the same as ":v ..." */
- X if (bang)
- X {
- X cmd = CMD_VGLOBAL;
- X }
- X
- X /* make sure we got a search pattern */
- X if (*extra != '/' && *extra != '?')
- X {
- X msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v');
- X return;
- X }
- X
- X /* parse & compile the search pattern */
- X cmdptr = parseptrn(extra);
- X if (!extra[1])
- X {
- X msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
- X return;
- X }
- X re = regcomp(extra + 1);
- X if (!re)
- X {
- X /* regcomp found & described an error */
- X return;
- X }
- X
- X /* for each line in the range */
- X doingglobal = TRUE;
- X ChangeText
- X {
- X /* NOTE: we have to go through the lines in a forward order,
- X * otherwise "g/re/p" would look funny. *BUT* for "g/re/d"
- X * to work, simply adding 1 to the line# on each loop won't
- X * work. The solution: count lines relative to the end of
- X * the file. Think about it.
- X */
- X for (l = nlines - markline(frommark),
- X lqty = markline(tomark) - markline(frommark) + 1L,
- X nchanged = 0L;
- X lqty > 0 && nlines - l >= 0 && nchanged >= 0L;
- X l--, lqty--)
- X {
- X /* fetch the line */
- X line = fetchline(nlines - l);
- X
- X /* if it contains the search pattern... */
- X if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
- X {
- X /* move the cursor to that line */
- X cursor = MARK_AT_LINE(nlines - l);
- X
- X /* do the ex command (without mucking up
- X * the original copy of the command line)
- X */
- X strcpy(cmdln, cmdptr);
- X rptlines = 0L;
- X doexcmd(cmdln);
- X nchanged += rptlines;
- X }
- X }
- X }
- X doingglobal = FALSE;
- X
- X /* free the regexp */
- X free(re);
- X
- X /* Reporting...*/
- X rptlines = nchanged;
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_file(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X#ifndef CRUNCH
- X /* if we're given a new filename, use it as this file's name */
- X if (extra && *extra)
- X {
- X strcpy(origname, extra);
- X }
- X#endif
- X if (cmd == CMD_FILE)
- X {
- X msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]",
- X *origname ? origname : "[NO FILE]",
- X tstflag(file, MODIFIED) ? "[MODIFIED]" : "",
- X tstflag(file, READONLY) ? "[READONLY]" : "",
- X nlines,
- X markline(frommark),
- X markline(frommark) * 100 / nlines);
- X }
- X else if (markline(frommark) == markline(tomark))
- X {
- X msg("%ld", markline(frommark));
- X }
- X else
- X {
- X msg("range \"%ld,%ld\" contains %ld lines",
- X markline(frommark),
- X markline(tomark),
- X markline(tomark) - markline(frommark) + 1L);
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_edit(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X long line = 1L; /* might be set to prevline */
- X
- X /* Editing previous file? Then start at previous line */
- X if (!strcmp(extra, prevorig))
- X {
- X line = prevline;
- X }
- X
- X#ifndef CRUNCH
- X /* if we were given an explicit starting line, then start there */
- X if (*extra == '+')
- X {
- X for (extra++, line = 0L; *extra >= '0' && *extra <= '9'; extra++)
- X {
- X line *= 10L;
- X line += (*extra - '0');
- X }
- X while (isascii(*extra) && isspace(*extra))
- X {
- X extra++;
- X }
- X }
- X#endif /* not CRUNCH */
- X
- X /* switch files */
- X if (tmpabort(bang))
- X {
- X tmpstart(extra);
- X if (line <= nlines && line >= 1L)
- X {
- X cursor = MARK_AT_LINE(line);
- X }
- X }
- X else
- X {
- X msg("Use edit! to abort changes, or w to save changes");
- X
- X /* so we can say ":e!#" next time... */
- X strcpy(prevorig, extra);
- X prevline = 1L;
- X }
- X}
- X
- X/* This code is also used for rewind -- GB */
- X
- X/*ARGSUSED*/
- Xvoid cmd_next(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X int i, j;
- X char *scan;
- X char *build;
- X
- X /* if extra stuff given, use ":args" to define a new args list */
- X if (cmd == CMD_NEXT && extra && *extra)
- X {
- X cmd_args(frommark, tomark, cmd, bang, extra);
- X }
- X
- X /* move to the next arg */
- X if (cmd == CMD_NEXT)
- X {
- X i = argno + 1;
- X }
- X else if (cmd == CMD_PREVIOUS)
- X {
- X i = argno - 1;
- X }
- X else /* cmd == CMD_REWIND */
- X {
- X i = 0;
- X }
- X if (i < 0 || i >= nargs)
- X {
- X msg("No %sfiles to edit", cmd == CMD_REWIND ? "" : "more ");
- X return;
- X }
- X
- X /* find & isolate the name of the file to edit */
- X for (j = i, scan = args; j > 0; j--)
- X {
- X while(!isascii(*scan) || !isspace(*scan))
- X {
- X scan++;
- X }
- X while (isascii(*scan) && isspace(*scan))
- X {
- X scan++;
- X }
- X }
- X for (build = tmpblk.c; *scan && (!isascii(*scan) || !isspace(*scan)); )
- X {
- X *build++ = *scan++;
- X }
- X *build = '\0';
- X
- X /* switch to the next file */
- X if (tmpabort(bang))
- X {
- X tmpstart(tmpblk.c);
- X argno = i;
- X }
- X else
- X {
- X msg("Use :%s! to abort changes, or w to save changes",
- X cmd == CMD_NEXT ? "next" :
- X cmd == CMD_PREVIOUS ? "previous" :
- X "rewind");
- X }
- X}
- X
- X/* also called from :wq -- always writes back in this case */
- X
- X/*ARGSUSED*/
- Xvoid cmd_xit(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X static long whenwarned; /* when the user was last warned of extra files */
- X int oldflag;
- X
- X /* if there are more files to edit, then warn user */
- X if (argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT))
- X {
- X msg("More files to edit -- Use \":n\" to go to next file");
- X whenwarned = changes;
- X return;
- X }
- X
- X if (cmd == CMD_QUIT)
- X {
- X if (tmpabort(bang))
- X {
- X mode = MODE_QUIT;
- X }
- X else
- X {
- X msg("Use q! to abort changes, or wq to save changes");
- X }
- X }
- X else
- X {
- X /* else try to save this file */
- X oldflag = tstflag(file, MODIFIED);
- X if (cmd == CMD_WQUIT)
- X setflag(file, MODIFIED);
- X if (tmpend(bang))
- X {
- X mode = MODE_QUIT;
- X }
- X else
- X {
- X msg("Could not save file -- use quit! to abort changes, or w filename");
- X }
- X if (!oldflag)
- X clrflag(file, MODIFIED);
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_args(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X char *scan;
- X char *eow;
- X int col;
- X int arg;
- X int addcols;
- X int scrolled = 0;
- X
- X /* if no extra names given, or just current name, then report the args
- X * we have now.
- X */
- X if (!extra || !*extra)
- X {
- X for (scan = args, col=arg=0; *scan; )
- X {
- X while (*scan && isascii(*scan) && isspace(*scan))
- X scan++;
- X eow = scan;
- X while (*eow && (!isascii(*++eow) || !isspace(*eow)))
- X ;
- X if (arg == argno)
- X addcols = 2;
- X else
- X addcols = 0;
- X if (col+addcols+(int)(eow-scan)+1>=COLS)
- X {
- X addch('\n');
- X scrolled=1;
- X col=0;
- X }
- X else if (arg)
- X { qaddch(' ');
- X col++;
- X }
- X if (arg == argno)
- X qaddch('[');
- X while (scan < eow)
- X { qaddch(*scan++);
- X col++;
- X }
- X if (arg == argno)
- X qaddch(']');
- X arg++;
- X col+=addcols;
- X }
- X /* write a trailing newline */
- X if ((mode == MODE_EX || mode == MODE_COLON || scrolled) && col)
- X addch('\n');
- X exrefresh();
- X }
- X else /* new args list given */
- X {
- X strcpy(args, extra);
- X argno = -1; /* before the first, so :next will go to first */
- X
- X /* count the names */
- X for (nargs = 0, scan = args; *scan; nargs++)
- X {
- X while (*scan && (!isascii(*scan) || !isspace(*scan)))
- X {
- X scan++;
- X }
- X while (isascii(*scan) && isspace(*scan))
- X {
- X scan++;
- X }
- X }
- X msg("%d files to edit", nargs);
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_cd(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X char *getenv();
- X
- X /* default directory name is $HOME */
- X if (!*extra)
- X {
- X extra = getenv("HOME");
- X if (!extra)
- X {
- X msg("environment variable $HOME not set");
- X return;
- X }
- X }
- X
- X /* go to the directory */
- X if (chdir(extra) < 0)
- X {
- X perror(extra);
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_map(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X char *mapto;
- X
- X /* "map" with no extra will dump the map table contents */
- X if (!*extra)
- X {
- X dumpkey(bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD);
- X }
- X else
- X {
- X /* "extra" is key to map, followed my what it maps to */
- X for (mapto = extra; *mapto && *mapto != ' ' && *mapto!= '\t'; mapto++)
- X {
- X }
- X while (*mapto == ' ' || *mapto == '\t')
- X {
- X *mapto++ = '\0';
- X }
- X
- X mapkey(extra, mapto, bang ? WHEN_VIINP|WHEN_VIREP : WHEN_VICMD, (char *)0);
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_set(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X if (!*extra)
- X {
- X dumpopts(FALSE);/* "FALSE" means "don't dump all" - only set */
- X }
- X else if (!strcmp(extra, "all"))
- X {
- X dumpopts(TRUE); /* "TRUE" means "dump all" - even unset vars */
- X }
- X else
- X {
- X setopts(extra);
- X
- X /* That option may have affected the appearence of text */
- X changes++;
- X }
- X}
- X
- X/*ARGSUSED*/
- Xvoid cmd_tag(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X char *scan; /* used to scan through the tmpblk.c */
- X char *cmp; /* char of tag name we're comparing, or NULL */
- X char *end; /* marks the end of chars in tmpblk.c */
- X int fd; /* file descriptor used to read the file */
- X#ifndef NO_MAGIC
- X char wasmagic; /* preserves the original state of o_magic */
- X#endif
- X static char prevtag[30];
- X
- X /* if no tag is given, use the previous tag */
- X if (!extra || !*extra)
- X {
- X if (!*prevtag)
- X {
- X msg("No previous tag");
- X return;
- X }
- X extra = prevtag;
- X }
- X else
- X {
- X strncpy(prevtag, extra, sizeof prevtag);
- X }
- X
- X /* open the tags file */
- X fd = open(TAGS, O_RDONLY);
- X if (fd < 0)
- X {
- X msg("No tags file");
- X return;
- X }
- X
- X /* Hmmm... this would have been a lot easier with <stdio.h> */
- X
- X /* find the line with our tag in it */
- X for(scan = end = tmpblk.c, cmp = extra; ; scan++)
- X {
- X /* read a block, if necessary */
- X if (scan >= end)
- X {
- X end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE);
- X scan = tmpblk.c;
- X if (scan >= end)
- X {
- X msg("tag \"%s\" not found", extra);
- X close(fd);
- X return;
- X }
- X }
- X
- X /* if we're comparing, compare... */
- X if (cmp)
- X {
- X /* matched??? wow! */
- X if (!*cmp && *scan == '\t')
- X {
- X break;
- X }
- X if (*cmp++ != *scan)
- X {
- X /* failed! skip to newline */
- X cmp = (char *)0;
- X }
- X }
- X
- X /* if we're skipping to newline, do it fast! */
- X if (!cmp)
- X {
- X while (scan < end && *scan != '\n')
- X {
- X scan++;
- X }
- X if (scan < end)
- X {
- X cmp = extra;
- X }
- X }
- X }
- X
- X /* found it! get the rest of the line into memory */
- X for (cmp = tmpblk.c, scan++; scan < end && *scan != '\n'; )
- X {
- X *cmp++ = *scan++;
- X }
- X if (scan == end)
- X {
- X tread(fd, cmp, BLKSIZE - (cmp - tmpblk.c));
- X }
- X
- X /* we can close the tags file now */
- X close(fd);
- X
- X /* extract the filename from the line, and edit the file */
- X for (cmp = tmpblk.c; *cmp != '\t'; cmp++)
- X {
- X }
- X *cmp++ = '\0';
- X if (strcmp(origname, tmpblk.c) != 0)
- X {
- X if (!tmpabort(bang))
- X {
- X msg("Use :tag! to abort changes, or :w to save changes");
- X return;
- X }
- X tmpstart(tmpblk.c);
- X }
- X
- X /* move to the desired line (or to line 1 if that fails) */
- X#ifndef NO_MAGIC
- X wasmagic = *o_magic;
- X *o_magic = FALSE;
- X#endif
- X cursor = MARK_FIRST;
- X linespec(cmp, &cursor);
- X if (cursor == MARK_UNSET)
- X {
- X cursor = MARK_FIRST;
- X }
- X#ifndef NO_MAGIC
- X *o_magic = wasmagic;
- X#endif
- X}
- X
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_visual(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X mode = MODE_VI;
- X msg("");
- X}
- X
- X
- X
- X
- X
- X/* describe this version of the program */
- X/*ARGSUSED*/
- Xvoid cmd_version(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X#ifndef DATE
- X msg("%s", VERSION);
- X#else
- X msg("%s (%s)", VERSION, DATE);
- X#endif
- X#ifdef COMPILED_BY
- X msg("Compiled by %s", COMPILED_BY);
- X#endif
- X#ifdef CREDIT
- X msg("%s", CREDIT);
- X#endif
- X#ifdef COPYING
- X msg("%s", COPYING);
- X#endif
- X}
- X
- X
- X#ifndef NO_MKEXRC
- X/* make a .exrc file which describes the current configuration */
- X/*ARGSUSED*/
- Xvoid cmd_mkexrc(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X int fd;
- X
- X /* the default name for the .exrc file EXRC */
- X if (!*extra)
- X {
- X extra = EXRC;
- X }
- X
- X /* create the .exrc file */
- X fd = creat(extra, FILEPERMS);
- X if (fd < 0)
- X {
- X msg("Couldn't create a new \"%s\" file", extra);
- X return;
- X }
- X
- X /* save stuff */
- X savekeys(fd);
- X saveopts(fd);
- X#ifndef NO_DIGRAPH
- X savedigs(fd);
- X#endif
- X#ifndef NO_ABBR
- X saveabbr(fd);
- X#endif
- X
- X /* close the file */
- X close(fd);
- X msg("Created a new \"%s\" file", extra);
- X}
- X#endif
- X
- X#ifndef NO_DIGRAPH
- X/*ARGSUSED*/
- Xvoid cmd_digraph(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X do_digraph(bang, extra);
- X}
- X#endif
- X
- X
- X#ifndef NO_ERRLIST
- Xstatic char errfile[256]; /* the name of a file containing an error */
- Xstatic long errline; /* the line number for an error */
- X
- X/* This static function tries to parse an error message.
- X *
- X * For most compilers, the first word is taken to be the name of the erroneous
- X * file, and the first number after that is taken to be the line number where
- X * the error was detected. The description of the error follows, possibly
- X * preceded by an "error ... :" or "warning ... :" label which is skipped.
- X *
- X * For Coherent, error messages look like "line#: filename: message".
- X *
- X * For non-error lines, or unparsable error lines, this function returns NULL.
- X * Normally, though, it alters errfile and errline, and returns a pointer to
- X * the description.
- X */
- Xstatic char *parse_errmsg(text)
- X REG char *text;
- X{
- X REG char *cpy;
- X long atol();
- X# if COHERENT || TOS /* any Mark Williams compiler */
- X /* Get the line number. If no line number, then ignore this line. */
- X errline = atol(text);
- X if (errline == 0L)
- X return (char *)0;
- X
- X /* Skip to the start of the filename */
- X while (*text && *text++ != ':')
- X {
- X }
- X if (!*text++)
- X return (char *)0;
- X
- X /* copy the filename to errfile */
- X for (cpy = errfile; *text && (*cpy++ = *text++) != ':'; )
- X {
- X }
- X if (!*text++)
- X return (char *)0;
- X cpy[-1] = '\0';
- X
- X return text;
- X# else /* not a Mark Williams compiler */
- X char *errmsg;
- X
- X /* the error message is the whole line, by default */
- X errmsg = text;
- X
- X /* skip leading garbage */
- X while (*text && !(isascii(*text) && isalnum(*text)))
- X {
- X text++;
- X }
- X
- X /* copy over the filename */
- X cpy = errfile;
- X while(isascii(*text) && isalnum(*text) || *text == '.')
- X {
- X *cpy++ = *text++;
- X }
- X *cpy = '\0';
- X
- X /* ignore the name "Error" and filenames that contain a '/' */
- X if (*text == '/' || !strcmp(errfile + 1, "rror") || access(errfile, 0) < 0)
- X {
- X return (char *)0;
- X }
- X
- X /* skip garbage between filename and line number */
- X while (*text && !(isascii(*text) && isdigit(*text)))
- X {
- X text++;
- X }
- X
- X /* if the number is part of a larger word, then ignore this line */
- X if (*text && isascii(text[-1]) && isalpha(text[-1]))
- X {
- X return (char *)0;
- X }
- X
- X /* get the error line */
- X errline = 0L;
- X while (isascii(*text) && isdigit(*text))
- X {
- X errline *= 10;
- X errline += (*text - '0');
- X text++;
- X }
- X
- X /* any line which lacks a filename or line number should be ignored */
- X if (!errfile[0] || !errline)
- X {
- X return (char *)0;
- X }
- X
- X /* locate the beginning of the error description */
- X while (*text && isascii(*text) && !isspace(*text))
- X {
- X text++;
- X }
- X while (*text)
- X {
- X# ifndef CRUNCH
- X /* skip "error #:" and "warning #:" clauses */
- X if (!strncmp(text + 1, "rror ", 5)
- X || !strncmp(text + 1, "arning ", 7)
- X || !strncmp(text + 1, "atal error", 10))
- X {
- X do
- X {
- X text++;
- X } while (*text && *text != ':');
- X continue;
- X }
- X# endif
- X
- X /* anything other than whitespace or a colon is important */
- X if (!isascii(*text) || (!isspace(*text) && *text != ':'))
- X {
- X errmsg = text;
- X break;
- X }
- X
- X /* else keep looking... */
- X text++;
- X }
- X
- X return errmsg;
- X# endif /* not COHERENT */
- X}
- X
- X/*ARGSUSED*/
- Xvoid cmd_errlist(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X static long endline;/* original number of lines in this file */
- X static long offset; /* offset of the next line in the errlist file */
- X static int fd = -2;/* fd of the errlist file */
- X int i;
- X char *errmsg;
- X
- X /* if a new errlist file is named, open it */
- X if (extra && extra[0])
- X {
- X /* close the old one */
- X if (fd >= 0)
- X {
- X close(fd);
- X }
- X
- X fd = open(extra, O_RDONLY);
- X offset = 0L;
- X }
- X else if (fd < 0)
- X {
- X fd = open(ERRLIST, O_RDONLY);
- X offset = 0L;
- X }
- X
- X /* do we have an errlist file now? */
- X if (fd < 0)
- X {
- X msg("There is no errlist file");
- X beep();
- X return;
- X }
- X
- X /* find the next error message in the file */
- X do
- X {
- X /* read the next line from the errlist */
- X lseek(fd, offset, 0);
- X if (tread(fd, tmpblk.c, (unsigned)BLKSIZE) <= 0)
- X {
- X msg("No more errors");
- X beep();
- X close(fd);
- X return;
- X }
- X for (i = 0; tmpblk.c[i] != '\n'; i++)
- X {
- X }
- X tmpblk.c[i++] = 0;
- X
- X /* look for an error message in the line */
- X errmsg = parse_errmsg(tmpblk.c);
- X if (!errmsg)
- X {
- X offset += i;
- X }
- X
- X } while (!errmsg);
- X
- X /* switch to the file containing the error, if this isn't it */
- X if (strcmp(origname, errfile))
- X {
- X if (!tmpabort(bang))
- X {
- X msg("Use :er! to abort changes, or :w to save changes");
- X beep();
- X return;
- X }
- X tmpstart(errfile);
- X endline = nlines;
- X }
- X else if (endline == 0L)
- X {
- X endline = nlines;
- X }
- X
- X /* go to the line where the error was detected */
- X cursor = MARK_AT_LINE(errline + (nlines - endline));
- X if (cursor > MARK_LAST)
- X {
- X cursor = MARK_LAST;
- X }
- X if (mode == MODE_VI)
- X {
- X redraw(cursor, FALSE);
- X }
- X
- X /* display the error message */
- X if (nlines > endline)
- X {
- X msg("line %ld(+%ld): %.60s", errline, nlines - endline, errmsg);
- X }
- X else if (nlines < endline)
- X {
- X msg("line %ld(-%ld): %.60s", errline, endline - nlines, errmsg);
- X }
- X else
- X {
- X msg("line %ld: %.65s", errline, errmsg);
- X }
- X
- X /* remember where the NEXT error line will start */
- X offset += i;
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_make(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X BLK buf;
- X
- X /* if the file hasn't been saved, then complain unless ! */
- X if (tstflag(file, MODIFIED) && !bang)
- X {
- X msg("\"%s\" not saved yet", origname);
- X return;
- X }
- X
- X /* build the command */
- X sprintf(buf.c, "%s %s %s%s", (cmd == CMD_CC ? o_cc : o_make), extra, REDIRECT, ERRLIST);
- X qaddstr(buf.c);
- X addch('\n');
- X
- X /* run the command, with curses temporarily disabled */
- X suspend_curses();
- X system(buf.c);
- X resume_curses(mode == MODE_EX);
- X if (mode == MODE_COLON)
- X mode = MODE_VI;
- X
- X /* run the "errlist" command */
- X cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST);
- X}
- X#endif
- X
- X
- X#ifndef NO_ABBR
- X/*ARGSUSED*/
- Xvoid cmd_abbr(frommark, tomark, cmd, bang, extra)
- X MARK frommark, tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X do_abbr(extra);
- X}
- X#endif
- eof
- if test `wc -c <cmd1.c` -ne 23975
- then
- echo cmd1.c damaged!
- fi
- fi
-
- if test -f cmd2.c -a "$1" != -f
- then
- echo Will not overwrite cmd2.c
- else
- echo Extracting cmd2.c
- sed 's/^X//' >cmd2.c <<\eof
- X/* cmd2.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 some of the commands - mostly ones that change text */
- X
- X#include <ctype.h>
- X#include "config.h"
- X#include "vi.h"
- X#include "regexp.h"
- X#if TOS
- X# include <stat.h>
- X#else
- X# if OSK
- X# include "osk.h"
- X# else
- X# include <sys/stat.h>
- X# endif
- X#endif
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_substitute(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra; /* rest of the command line */
- X{
- X char *line; /* a line from the file */
- X regexp *re; /* the compiled search expression */
- X char *subst; /* the substitution string */
- X char *opt; /* substitution options */
- X long l; /* a line number */
- X char *s, *d; /* used during subtitutions */
- X char *conf; /* used during confirmation */
- X long chline; /* # of lines changed */
- X long chsub; /* # of substitutions made */
- X static optp; /* boolean option: print when done? */
- X static optg; /* boolean option: substitute globally in line? */
- X static optc; /* boolean option: confirm before subst? */
- X
- X
- X /* for now, assume this will fail */
- X rptlines = -1L;
- X
- X if (cmd == CMD_SUBAGAIN)
- X {
- X#ifndef NO_MAGIC
- X if (*o_magic)
- X subst = "~";
- X else
- X#endif
- X subst = "\\~";
- X re = regcomp("");
- X
- X /* if visual "&", then turn off the "p" and "c" options */
- X if (bang)
- X {
- X optp = optc = FALSE;
- X }
- X }
- X else
- X {
- X /* make sure we got a search pattern */
- X if (*extra != '/' && *extra != '?')
- X {
- X msg("Usage: s/regular expression/new text/");
- X return;
- X }
- X
- X /* parse & compile the search pattern */
- X subst = parseptrn(extra);
- X re = regcomp(extra + 1);
- X }
- X
- X /* abort if RE error -- error message already given by regcomp() */
- X if (!re)
- X {
- X return;
- X }
- X
- X if (cmd == CMD_SUBSTITUTE)
- X {
- X /* parse the substitution string & find the option string */
- X for (opt = subst; *opt && *opt != *extra; opt++)
- X {
- X if (*opt == '\\' && opt[1])
- X {
- X opt++;
- X }
- X }
- X if (*opt)
- X {
- X *opt++ = '\0';
- X }
- X
- X /* analyse the option string */
- X if (!*o_edcompatible)
- X {
- X optp = optg = optc = FALSE;
- X }
- X while (*opt)
- X {
- X switch (*opt++)
- X {
- X case 'p': optp = !optp; break;
- X case 'g': optg = !optg; break;
- X case 'c': optc = !optc; break;
- X case ' ':
- X case '\t': break;
- X default:
- X msg("Subst options are p, c, and g -- not %c", opt[-1]);
- X return;
- X }
- X }
- X }
- X
- X /* if "c" or "p" flag was given, and we're in visual mode, then NEWLINE */
- X if ((optc || optp) && mode == MODE_VI)
- X {
- X addch('\n');
- X exrefresh();
- X }
- X
- X ChangeText
- X {
- X /* reset the change counters */
- X chline = chsub = 0L;
- X
- X /* for each selected line */
- X for (l = markline(frommark); l <= markline(tomark); l++)
- X {
- X /* fetch the line */
- X line = fetchline(l);
- X
- X /* if it contains the search pattern... */
- X if (regexec(re, line, TRUE))
- X {
- X /* increment the line change counter */
- X chline++;
- X
- X /* initialize the pointers */
- X s = line;
- X d = tmpblk.c;
- X
- X /* do once or globally ... */
- X do
- X {
- X#ifndef CRUNCH
- X /* confirm, if necessary */
- X if (optc)
- X {
- X for (conf = line; conf < re->startp[0]; conf++)
- X addch(*conf);
- X standout();
- X for ( ; conf < re->endp[0]; conf++)
- X addch(*conf);
- X standend();
- X for (; *conf; conf++)
- X addch(*conf);
- X addch('\n');
- X exrefresh();
- X if (getkey(0) != 'y')
- X {
- X /* copy accross the original chars */
- X while (s < re->endp[0])
- X *d++ = *s++;
- X
- X /* skip to next match on this line, if any */
- X continue;
- X }
- X }
- X#endif /* not CRUNCH */
- X
- X /* increment the substitution change counter */
- X chsub++;
- X
- X /* this may be the first line to redraw */
- X redrawrange(l, l + 1L, l + 1L);
- X
- X /* copy stuff from before the match */
- X while (s < re->startp[0])
- X {
- X *d++ = *s++;
- X }
- X
- X /* substitute for the matched part */
- X regsub(re, subst, d);
- X s = re->endp[0];
- X d += strlen(d);
- X
- X } while (optg && regexec(re, s, FALSE));
- X
- X /* copy stuff from after the match */
- X while (*d++ = *s++) /* yes, ASSIGNMENT! */
- X {
- X }
- X
- X /* replace the old version of the line with the new */
- X d[-1] = '\n';
- X d[0] = '\0';
- X change(MARK_AT_LINE(l), MARK_AT_LINE(l + 1), tmpblk.c);
- X
- X /* if supposed to print it, do so */
- X if (optp)
- X {
- X addstr(tmpblk.c);
- X exrefresh();
- X }
- X
- X /* move the cursor to that line */
- X cursor = MARK_AT_LINE(l);
- X }
- X }
- X }
- X
- X /* tweak for redrawing */
- X mustredraw = TRUE;
- X
- X /* free the regexp */
- X free(re);
- X
- X /* if done from within a ":g" command, then finish silently */
- X if (doingglobal)
- X {
- X rptlines = chline;
- X rptlabel = "changed";
- X return;
- X }
- X
- X /* Reporting */
- X if (chsub == 0)
- X {
- X msg("Substitution failed");
- X }
- X else if (chline >= *o_report)
- X {
- X msg("%ld substitutions on %ld lines", chsub, chline);
- X }
- X}
- X
- X
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_delete(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X MARK curs2; /* an altered form of the cursor */
- X
- X /* choose your cut buffer */
- X if (*extra == '"')
- X {
- X extra++;
- X }
- X if (*extra)
- X {
- X cutname(*extra);
- X }
- X
- X /* make sure we're talking about whole lines here */
- X frommark = frommark & ~(BLKSIZE - 1);
- X tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
- X
- X /* yank the lines */
- X cut(frommark, tomark);
- X
- X /* if CMD_DELETE then delete the lines */
- X if (cmd != CMD_YANK)
- X {
- X curs2 = cursor;
- X ChangeText
- X {
- X /* delete the lines */
- X delete(frommark, tomark);
- X }
- X if (curs2 > tomark)
- X {
- X cursor = curs2 - tomark + frommark;
- X }
- X else if (curs2 > frommark)
- X {
- X cursor = frommark;
- X }
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_append(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X long l; /* line counter */
- X
- X ChangeText
- X {
- X /* if we're doing a change, delete the old version */
- X if (cmd == CMD_CHANGE)
- X {
- X /* delete 'em */
- X cmd_delete(frommark, tomark, cmd, bang, extra);
- X }
- X
- X /* new lines start at the frommark line, or after it */
- X l = markline(frommark);
- X if (cmd == CMD_APPEND)
- X {
- X l++;
- X }
- X
- X /* get lines until no more lines, or "." line, and insert them */
- X while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
- X {
- X addch('\n');
- X if (!strcmp(tmpblk.c, "."))
- X {
- X break;
- X }
- X
- X strcat(tmpblk.c, "\n");
- X add(MARK_AT_LINE(l), tmpblk.c);
- X l++;
- X }
- X }
- X
- X /* on the odd chance that we're calling this from vi mode ... */
- X redraw(MARK_UNSET, FALSE);
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_put(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X /* choose your cut buffer */
- X if (*extra == '"')
- X {
- X extra++;
- X }
- X if (*extra)
- X {
- X cutname(*extra);
- X }
- X
- X /* paste it */
- X ChangeText
- X {
- X cursor = paste(frommark, TRUE, FALSE);
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_join(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X long l;
- X char *scan;
- X int len; /* length of the new line */
- X
- X /* if only one line is specified, assume the following one joins too */
- X if (markline(frommark) == nlines)
- X {
- X msg("Nothing to join with this line");
- X return;
- X }
- X if (markline(frommark) == markline(tomark))
- X {
- X tomark += BLKSIZE;
- X }
- X
- X /* get the first line */
- X l = markline(frommark);
- X strcpy(tmpblk.c, fetchline(l));
- X len = strlen(tmpblk.c);
- X
- X /* build the longer line */
- X while (++l <= markline(tomark))
- X {
- X /* get the next line */
- X scan = fetchline(l);
- X
- X /* remove any leading whitespace */
- X while (*scan == '\t' || *scan == ' ')
- X {
- X scan++;
- X }
- X
- X /* see if the line will fit */
- X if (strlen(scan) + len + 3 > BLKSIZE)
- X {
- X msg("Can't join -- the resulting line would be too long");
- X return;
- X }
- X
- X /* catenate it, with a space (or two) in between */
- X if (len >= 1 &&
- X (tmpblk.c[len - 1] == '.'
- X || tmpblk.c[len - 1] == '?'
- X || tmpblk.c[len - 1] == '!'))
- X {
- X tmpblk.c[len++] = ' ';
- X }
- X tmpblk.c[len++] = ' ';
- X strcpy(tmpblk.c + len, scan);
- X len += strlen(scan);
- X }
- X tmpblk.c[len++] = '\n';
- X tmpblk.c[len] = '\0';
- X
- X /* make the change */
- X ChangeText
- X {
- X frommark &= ~(BLKSIZE - 1);
- X tomark &= ~(BLKSIZE - 1);
- X tomark += BLKSIZE;
- X change(frommark, tomark, tmpblk.c);
- X }
- X
- X /* Reporting... */
- X rptlines = markline(tomark) - markline(frommark) - 1L;
- X rptlabel = "joined";
- X}
- X
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_shift(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X long l; /* line number counter */
- X int oldidx; /* number of chars previously used for indent */
- X int newidx; /* number of chars in the new indent string */
- X int oldcol; /* previous indent amount */
- X int newcol; /* new indent amount */
- X char *text; /* pointer to the old line's text */
- X
- X /* figure out how much of the screen we must redraw (for vi mode) */
- X if (markline(frommark) != markline(tomark))
- X {
- X mustredraw = TRUE;
- X redrawrange(markline(frommark), markline(tomark) + 1L, markline(tomark) + 1L);
- X }
- X
- X ChangeText
- X {
- X /* for each line to shift... */
- X for (l = markline(frommark); l <= markline(tomark); l++)
- X {
- X /* get the line - ignore empty lines unless ! mode */
- X text = fetchline(l);
- X if (!*text && !bang)
- X continue;
- X
- X /* calc oldidx and oldcol */
- X for (oldidx = 0, oldcol = 0;
- X text[oldidx] == ' ' || text[oldidx] == '\t';
- X oldidx++)
- X {
- X if (text[oldidx] == ' ')
- X {
- X oldcol += 1;
- X }
- X else
- X {
- X oldcol += *o_tabstop - (oldcol % *o_tabstop);
- X }
- X }
- X
- X /* calc newcol */
- X if (cmd == CMD_SHIFTR)
- X {
- X newcol = oldcol + (*o_shiftwidth & 0xff);
- X }
- X else
- X {
- X newcol = oldcol - (*o_shiftwidth & 0xff);
- X if (newcol < 0)
- X newcol = 0;
- X }
- X
- X /* if no change, then skip to next line */
- X if (oldcol == newcol)
- X continue;
- X
- X /* build a new indent string */
- X newidx = 0;
- X while (newcol >= *o_tabstop)
- X {
- X tmpblk.c[newidx++] = '\t';
- X newcol -= *o_tabstop;
- X }
- X while (newcol > 0)
- X {
- X tmpblk.c[newidx++] = ' ';
- X newcol--;
- X }
- X tmpblk.c[newidx] = '\0';
- X
- X /* change the old indent string into the new */
- X change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c);
- X }
- X }
- X
- X /* Reporting... */
- X rptlines = markline(tomark) - markline(frommark) + 1L;
- X if (cmd == CMD_SHIFTR)
- X {
- X rptlabel = ">ed";
- X }
- X else
- X {
- X rptlabel = "<ed";
- X }
- X}
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_read(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X int fd, rc; /* used while reading from the file */
- X char *scan; /* used for finding NUL characters */
- X int hadnul; /* boolean: any NULs found? */
- X int addnl; /* boolean: forced to add newlines? */
- X int len; /* number of chars in current line */
- X long lines; /* number of lines in current block */
- X struct stat statb;
- X
- X /* special case: if ":r !cmd" then let the filter() function do it */
- X if (extra[0] == '!')
- X {
- X filter(frommark, MARK_UNSET, extra + 1);
- X return;
- X }
- X
- X /* open the file */
- X fd = open(extra, O_RDONLY);
- X if (fd < 0)
- X {
- X msg("Can't open \"%s\"", extra);
- X return;
- X }
- X
- X#ifndef CRUNCH
- X if (stat(extra, &statb) < 0)
- X {
- X msg("Can't stat \"%s\"", extra);
- X }
- X# if TOS
- X if (statb.st_mode & S_IJDIR)
- X# else
- X# if OSK
- X if (statb.st_mode & S_IFDIR)
- X# else
- X if ((statb.st_mode & S_IFMT) != S_IFREG)
- X# endif
- X# endif
- X {
- X msg("\"%s\" is not a regular file", extra);
- X return;
- X }
- X#endif /* not CRUNCH */
- X
- X /* get blocks from the file, and add them */
- X ChangeText
- X {
- X /* insertion starts at the line following frommark */
- X tomark = frommark = (frommark | (BLKSIZE - 1L)) + 1L;
- X len = 0;
- X hadnul = addnl = FALSE;
- X
- X /* add an extra newline, so partial lines at the end of
- X * the file don't trip us up
- X */
- X add(tomark, "\n");
- X
- X /* for each chunk of text... */
- X while ((rc = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0)
- X {
- X /* count newlines, convert NULs, etc. ... */
- X for (lines = 0, scan = tmpblk.c; rc > 0; rc--, scan++)
- X {
- X /* break up long lines */
- X if (*scan != '\n' && len + 2 > BLKSIZE)
- X {
- X *scan = '\n';
- X addnl = TRUE;
- X }
- X
- X /* protect against NUL chars in file */
- X if (!*scan)
- X {
- X *scan = 0x80;
- X hadnul = TRUE;
- X }
- X
- X /* starting a new line? */
- X if (*scan == '\n')
- X {
- X /* reset length at newline */
- X len = 0;
- X lines++;
- X }
- X else
- X {
- X len++;
- X }
- X }
- X
- X /* add the text */
- X *scan = '\0';
- X add(tomark, tmpblk.c);
- X tomark += MARK_AT_LINE(lines) + len - markidx(tomark);
- X }
- X
- X /* if partial last line, then retain that first newline */
- X if (len > 0)
- X {
- X msg("Last line had no newline");
- X tomark += BLKSIZE; /* <- for the rptlines calc */
- X }
- X else /* delete that first newline */
- X {
- X delete(tomark, (tomark | (BLKSIZE - 1L)) + 1L);
- X }
- X }
- X
- X /* close the file */
- X close(fd);
- X
- X /* Reporting... */
- X rptlines = markline(tomark) - markline(frommark);
- X rptlabel = "read";
- X
- X if (addnl)
- X msg("Newlines were added to break up long lines");
- X if (hadnul)
- X msg("NULs were converted to 0x80");
- X}
- X
- X
- X
- X/*ARGSUSED*/
- Xvoid cmd_undo(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X undo();
- X}
- X
- X
- X/* print the selected lines */
- X/*ARGSUSED*/
- Xvoid cmd_print(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X REG char *scan;
- X REG long l;
- X REG int col;
- X
- X for (l = markline(frommark); l <= markline(tomark); l++)
- X {
- X /* display a line number, if CMD_NUMBER */
- X if (cmd == CMD_NUMBER)
- X {
- X sprintf(tmpblk.c, "%6ld ", l);
- X qaddstr(tmpblk.c);
- X col = 8;
- X }
- X else
- X {
- X col = 0;
- X }
- X
- X /* get the next line & display it */
- X for (scan = fetchline(l); *scan; scan++)
- X {
- X /* expand tabs to the proper width */
- X if (*scan == '\t' && cmd != CMD_LIST)
- X {
- X do
- X {
- X qaddch(' ');
- X col++;
- X } while (col % *o_tabstop != 0);
- X }
- X else if (*scan >= 0 && *scan < ' ' || *scan == '\177')
- X {
- X qaddch('^');
- X qaddch(*scan ^ 0x40);
- X col += 2;
- X }
- X else if ((*scan & 0x80) && cmd == CMD_LIST)
- X {
- X sprintf(tmpblk.c, "\\%03o", *scan);
- X qaddstr(tmpblk.c);
- X col += 4;
- X }
- X else
- X {
- X qaddch(*scan);
- X col++;
- X }
- X
- X /* wrap at the edge of the screen */
- X if (!has_AM && col >= COLS)
- X {
- X addch('\n');
- X col -= COLS;
- X }
- X }
- X if (cmd == CMD_LIST)
- X {
- X qaddch('$');
- X }
- X addch('\n');
- X exrefresh();
- X }
- X}
- X
- X
- X/* move or copy selected lines */
- X/*ARGSUSED*/
- Xvoid cmd_move(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X MARK destmark;
- X
- X /* parse the destination linespec. No defaults. Line 0 is okay */
- X destmark = cursor;
- X if (!strcmp(extra, "0"))
- X {
- X destmark = 0L;
- X }
- X else if (linespec(extra, &destmark) == extra || !destmark)
- X {
- X msg("invalid destination address");
- X return;
- X }
- X
- X /* flesh the marks out to encompass whole lines */
- X frommark &= ~(BLKSIZE - 1);
- X tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
- X destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE;
- X
- X /* make sure the destination is valid */
- X if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark)
- X {
- X msg("invalid destination address");
- X }
- X
- X /* Do it */
- X ChangeText
- X {
- X /* save the text to a cut buffer */
- X cutname('\0');
- X cut(frommark, tomark);
- X
- X /* if we're not copying, delete the old text & adjust destmark */
- X if (cmd != CMD_COPY)
- X {
- X delete(frommark, tomark);
- X if (destmark >= frommark)
- X {
- X destmark -= (tomark - frommark);
- X }
- X }
- X
- X /* add the new text */
- X paste(destmark, FALSE, FALSE);
- X }
- X
- X /* move the cursor to the last line of the moved text */
- X cursor = destmark + (tomark - frommark) - BLKSIZE;
- X if (cursor < MARK_FIRST || cursor >= MARK_LAST + BLKSIZE)
- X {
- X cursor = MARK_LAST;
- X }
- X
- X /* Reporting... */
- X rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" );
- X}
- X
- X
- X
- X/* execute EX commands from a file */
- X/*ARGSUSED*/
- Xvoid cmd_source(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X /* must have a filename */
- X if (!*extra)
- X {
- X msg("\"source\" requires a filename");
- X return;
- X }
- X
- X doexrc(extra);
- X}
- X
- X
- X#ifndef NO_AT
- X/*ARGSUSED*/
- Xvoid cmd_at(frommark, tomark, cmd, bang, extra)
- X MARK frommark;
- X MARK tomark;
- X CMD cmd;
- X int bang;
- X char *extra;
- X{
- X static nest = FALSE;
- X int result;
- X char buf[MAXRCLEN];
- X
- X /* don't allow nested macros */
- X if (nest)
- X {
- X msg("@ macros can't be nested");
- X return;
- X }
- X nest = TRUE;
- X
- X /* require a buffer name */
- X if (*extra == '"')
- X extra++;
- X if (!*extra || !isascii(*extra) ||!islower(*extra))
- X {
- X msg("@ requires a cut buffer name (a-z)");
- X }
- X
- X /* get the contents of the buffer */
- X result = cb2str(*extra, buf, (unsigned)(sizeof buf));
- X if (result <= 0)
- X {
- X msg("buffer \"%c is empty", *extra);
- X }
- X else if (result >= sizeof buf)
- X {
- X msg("buffer \"%c is too large to execute", *extra);
- X }
- X else
- X {
- X /* execute the contents of the buffer as ex commands */
- X exstring(buf, result);
- X }
- X
- X nest = FALSE;
- X}
- X#endif
- eof
- if test `wc -c <cmd2.c` -ne 16797
- then
- echo cmd2.c damaged!
- fi
- fi
-
- if test -f config.h -a "$1" != -f
- then
- echo Will not overwrite config.h
- else
- echo Extracting config.h
- sed 's/^X//' >config.h <<\eof
- X/*
- X * vi configuration file
- X * We try to automatically configure to various compilers and operating
- X * systems. Extend the autoconf section as needed.
- X */
- X
- X/*************************** autoconf section ************************/
- X
- X/* standard unix V (?) */
- X#ifdef M_SYSV
- X# define UNIXV 1
- X#endif
- X
- X/* xelos system, University of Ulm */
- X#ifdef xelos
- X# define UNIXV 1
- X#endif
- X
- X/* BSD UNIX? */
- X#ifdef bsd
- X# define BSD 1
- X#endif
- X
- X/* Microsoft C: sorry, Watcom does the same thing */
- X#ifdef M_I86
- X# ifndef M_SYSV
- X# define MSDOS 1
- X# define MICROSOFT 1
- X# define COMPILED_BY "Microsoft C 5.10"
- X# endif
- X#endif
- X
- X/* Borlands Turbo C */
- X#ifdef __TURBOC__
- X# define MSDOS 1
- X# define TURBOC 1
- X# define COMPILED_BY "Turbo C 2.00"
- X#endif
- X
- X/* Tos Mark-Williams */
- X#ifdef M68000
- X# define TOS 1
- X# define COMPILED_BY "Mark Williams C"
- X#endif
- X
- X/* OS9/68000 */
- X#ifdef OSK
- X# define COMPILED_BY "Microware C V2.3 Edition 40"
- X#endif
- X
- X/*************************** end of autoconf section ************************/
- X
- X/* All undefined symbols are defined to zero here, to allow for older */
- X/* compilers which dont understand #if defined() or #if UNDEFINED_SYMBOL */
- X
- X/*************************** operating systems *****************************/
- X
- X#ifndef BSD
- X# define BSD 0 /* UNIX - Berkeley 4.x */
- X#endif
- X
- X#ifndef UNIXV
- X# define UNIXV 0 /* UNIX - AT&T SYSV */
- X#endif
- X
- X#ifndef UNIX7
- X# define UNIX7 0 /* UNIX - version 7 */
- X#endif
- X
- X#ifndef MSDOS
- X# define MSDOS 0 /* PC */
- X#endif
- X
- X#ifndef TOS
- X# define TOS 0 /* Atari ST */
- X#endif
- X
- X#ifndef AMIGA
- X# define AMIGA 0 /* Commodore Amiga */
- X#endif
- X
- X#ifndef OSK
- X# define OSK 0 /* OS-9 / 68k */
- X#endif
- X
- X#ifndef COHERENT
- X# define COHERENT 0 /* Coherent */
- X#endif
- X
- X /* Minix has no predefines */
- X#if !BSD && !UNIXV && !UNIX7 && !MSDOS && !TOS && !AMIGA && !OSK && !COHERENT
- X# define MINIX 1
- X#else
- X# define MINIX 0
- X#endif
- X
- X /* generic combination of Unices */
- X#if UNIXV || UNIX7 || BSD || MINIX || COHERENT
- X# define ANY_UNIX 1
- X#else
- X# define ANY_UNIX 0
- X#endif
- X
- X/*************************** compilers **************************************/
- X
- X#ifndef MICROSOFT
- X# define MICROSOFT 0
- X#endif
- X
- X#ifndef TURBOC
- X# define TURBOC 0
- X#endif
- X
- X/******************************* Credit ************************************/
- X
- X#if MSDOS
- X# define CREDIT "Ported to MS-DOS by Guntram Blohm & Martin Patzel"
- X#endif
- X
- X#if TOS
- X# define CREDIT "Ported to Atari/TOS by Guntram Blohm & Martin Patzel"
- X#endif
- X
- X#if OSK
- X# define CREDIT "Ported to Microware OS9/68k by Peter Reinig"
- X#endif
- X
- X#if COHERENT
- X# define CREDIT "Ported to Coherent by Esa Ahola"
- X#endif
- X
- X/*************************** functions depending on OS *********************/
- X
- X/* Only MSDOS, TOS, and OS9 need a special function for reading from the
- X * keyboard. All others just read from file descriptor 0.
- X */
- X#if !MSDOS && !TOS && !OSK
- X# define ttyread(buf, len) read(0, buf, (unsigned)len) /* raw read */
- X#endif
- X#if !TOS
- X# define ttywrite(buf, len) write(1, buf, (unsigned)(len)) /* raw write */
- X#endif
- X
- X/* The strchr() function is an official standard now, so everybody has it
- X * except Unix version 7 (which is old) and BSD Unix (which is academic).
- X * Those guys use something called index() to do the same thing.
- X */
- X#if BSD || UNIX7 || OSK
- X# define strchr index
- X#endif
- Xextern char *strchr();
- X
- X/* BSD uses bcopy() instead of memcpy() */
- X#if BSD
- X#define memcpy(dest, src, siz) bcopy(src, dest, siz)
- X#endif
- X
- X/* text versa binary mode for read/write */
- X#if !TOS
- X#define tread(fd,buf,n) read(fd,buf,(unsigned)(n))
- X#define twrite(fd,buf,n) write(fd,buf,(unsigned)(n))
- X#endif
- X
- X/**************************** Compiler quirks *********************************/
- X
- X/* the UNIX version 7 and (some) TOS compilers, don't allow "void" */
- X#if UNIX7 || TOS
- X# define void int
- X#endif
- X
- X/* as far as I know, all compilers except version 7 support unsigned char */
- X/* NEWFLASH: the Minix-ST compiler has subtle problems with unsigned char */
- X#if UNIX7 || MINIX
- X# define UCHAR(c) ((c) & 0xff)
- X# define uchar char
- X#else
- X# define UCHAR(c) ((unsigned char)(c))
- X# define uchar unsigned char
- X#endif
- X
- X/* Some compilers prefer to have malloc declared as returning a (void *) */
- X#if BSD
- Xextern void *malloc();
- X#else
- Xextern char *malloc();
- X#endif
- X
- X/* Most compilers could benefit from using the "register" storage class */
- X#if 1
- X# define REG register
- X#endif
- X
- X/******************* Names of files and environment vars **********************/
- X
- X#if ANY_UNIX
- X# ifndef TMPDIR
- X# if MINIX
- X# define TMPDIR "/usr/tmp" /* Keep elvis' temp files off RAM disk! */
- X# else
- X# define TMPDIR "/tmp" /* directory where temp files live */
- X# endif
- X# endif
- X# define TMPNAME "%s/elv%x%04x%03x" /* temp file */
- X# define CUTNAME "%s/elv_%04x%03x" /* cut buffer's temp file */
- X# ifndef EXRC
- X# define EXRC ".exrc" /* init file in current directory */
- X# endif
- X# define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */
- X# ifndef EXINIT
- X# define EXINIT "EXINIT"
- X# endif
- X# ifndef SHELL
- X# define SHELL "/bin/sh" /* default shell */
- X# endif
- X# if COHERENT
- X# ifndef REDIRECT
- X# define REDIRECT ">" /* Coherent CC writes errors to stdout */
- X# endif
- X# endif
- X#endif
- X
- X#if MSDOS || TOS
- X/* do not change TMPNAME, CUTNAME and SCRATCH*: they MUST begin with '%s\\'! */
- X# ifndef TMPDIR
- X# define TMPDIR "C:\\tmp" /* directory where temp files live */
- X# endif
- X# define TMPNAME "%s\\elv%x%04x.%03x" /* temp file */
- X# define CUTNAME "%s\\elv_%04x.%03x" /* cut buffer's temp file */
- X# if MSDOS
- X# if MICROSOFT
- X# define CC_COMMAND "cl -c" /* C compiler */
- X# else /* TURBO_C */
- X# define CC_COMMAND "tc" /* C compiler */
- X# endif
- X# endif
- X# define SCRATCHIN "%s\\siXXXXXX" /* DOS ONLY - output of filter program */
- X# define SCRATCHOUT "%s\\soXXXXXX" /* temp file used as input to filter */
- X# define SLASH '\\'
- X# ifndef SHELL
- X# if TOS
- X# define SHELL "shell.ttp" /* default shell */
- X# else
- X# define SHELL "command.com" /* default shell */
- X# endif
- X# endif
- X# define NEEDSYNC TRUE /* assume ":se sync" by default */
- X# define REDIRECT ">" /* shell's redirection of stderr */
- X# ifndef MAXMAPS
- X# define MAXMAPS 40
- X# endif
- X# ifndef EXINIT
- X# define EXINIT "EXINIT"
- X# endif
- X#endif
- X
- X#if OSK
- X# ifndef TMPDIR
- X# define TMPDIR "/dd/tmp" /* directory where temp files live */
- X# endif
- X# define TMPNAME "%s/elv%x%04x%03x" /* temp file */
- X# define CUTNAME "%s/elv_%04x%03x" /* cut buffer's temp file */
- X# ifndef CC_COMMAND
- X# define CC_COMMAND "cc -r" /* name of the compiler */
- X# endif
- X# ifndef EXRC
- X# define EXRC ".exrc" /* init file in current directory */
- X# endif
- X# define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */
- X# ifndef SHELL
- X# define SHELL "shell" /* default shell */
- X# endif
- X# define FILEPERMS (S_IREAD|S_IWRITE) /* file permissions used for creat() */
- X# define REDIRECT ">>-" /* shell's redirection of stderr */
- X#endif
- X
- X#ifndef TAGS
- X# define TAGS "tags" /* tags file */
- X#endif
- X
- X#ifndef TMPNAME
- X# define TMPNAME "%s/elv%x%04x.%03x" /* temp file */
- X#endif
- X
- X#ifndef CUTNAME
- X# define CUTNAME "%s/elv_%04x.%03x" /* cut buffer's temp file */
- X#endif
- X
- X#ifndef EXRC
- X# define EXRC "elvis.rc"
- X#endif
- X
- X#ifndef HMEXRC
- X# if !MSDOS && !TOS
- X# define HMEXRC EXRC
- X# endif
- X#endif
- X
- X#ifndef KEYWORDPRG
- X# define KEYWORDPRG "ref"
- X#endif
- X
- X#ifndef SCRATCHOUT
- X# define SCRATCHIN "%s/SIXXXXXX"
- X# define SCRATCHOUT "%s/SOXXXXXX"
- X#endif
- X
- X#ifndef ERRLIST
- X# define ERRLIST "errlist"
- X#endif
- X
- X#ifndef SLASH
- X# define SLASH '/'
- X#endif
- X
- X#ifndef SHELL
- X# define SHELL "shell"
- X#endif
- X
- X#ifndef REG
- X# define REG
- X#endif
- X
- X#ifndef NEEDSYNC
- X# define NEEDSYNC FALSE
- X#endif
- X
- X#ifndef FILEPERMS
- X# define FILEPERMS 0666
- X#endif
- X
- X#ifndef CC_COMMAND
- X# define CC_COMMAND "cc -c"
- X#endif
- X
- X#ifndef MAKE_COMMAND
- X# define MAKE_COMMAND "make"
- X#endif
- X
- X#ifndef REDIRECT
- X# define REDIRECT "2>"
- X#endif
- X
- X#ifndef MAXMAPS
- X# define MAXMAPS 20 /* number of :map keys */
- X#endif
- X#ifndef MAXDIGS
- X# define MAXDIGS 30 /* number of :digraph combos */
- X#endif
- X#ifndef MAXABBR
- X# define MAXABBR 20 /* number of :abbr entries */
- X#endif
- eof
- if test `wc -c <config.h` -ne 7951
- then
- echo config.h damaged!
- fi
- fi
-
- if test -f curses.c -a "$1" != -f
- then
- echo Will not overwrite curses.c
- else
- echo Extracting curses.c
- sed 's/^X//' >curses.c <<\eof
- X/* curses.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 functions & variables needed for a tiny subset of
- X * curses. The principle advantage of this version of curses is its
- X * extreme speed. Disadvantages are potentially larger code, few supported
- X * functions, limited compatibility with full curses, and only stdscr.
- X */
- X
- X#include "config.h"
- X#include "vi.h"
- X
- X#if ANY_UNIX
- X# if UNIXV
- X# include <termio.h>
- X# undef TIOCWINSZ /* we can't handle it correctly yet */
- X# else
- X# include <sgtty.h>
- X# endif
- X#endif
- X
- X#if TOS
- X# include <osbind.h>
- X#endif
- X
- X#if OSK
- X# include <sgstat.h>
- X#endif
- X
- X#include <signal.h>
- X
- Xextern char *getenv();
- Xstatic void starttcap();
- X
- X/* variables, publicly available & used in the macros */
- Xshort ospeed; /* speed of the tty, eg B2400 */
- X#if OSK
- Xchar PC_; /* Pad char */
- Xchar *BC; /* backspace character string */
- X#else
- Xchar PC; /* Pad char */
- X#endif
- XWINDOW *stdscr; /* pointer into kbuf[] */
- XWINDOW kbuf[KBSIZ]; /* a very large output buffer */
- Xint LINES; /* :li#: number of rows */
- Xint COLS; /* :co#: number of columns */
- Xint AM; /* :am: boolean: auto margins? */
- Xint PT; /* :pt: boolean: physical tabs? */
- Xchar *VB; /* :vb=: visible bell */
- Xchar *UP; /* :up=: move cursor up */
- Xchar *SO; /* :so=: standout start */
- Xchar *SE; /* :se=: standout end */
- Xchar *US = ""; /* :us=: underline start */
- Xchar *UE = ""; /* :ue=: underline end */
- Xchar *MD = ""; /* :md=: bold start */
- Xchar *ME = ""; /* :me=: bold end */
- Xchar *AS; /* :as=: alternate (italic) start */
- Xchar *AE; /* :ae=: alternate (italic) end */
- Xchar *CM; /* :cm=: cursor movement */
- Xchar *CE; /* :ce=: clear to end of line */
- Xchar *CD; /* :cd=: clear to end of screen */
- Xchar *AL; /* :al=: add a line */
- Xchar *DL; /* :dl=: delete a line */
- X#if OSK
- Xchar *SR_; /* :sr=: scroll reverse */
- X#else
- Xchar *SR; /* :sr=: scroll reverse */
- X#endif
- Xchar *KS; /* :ks=: init string for cursor */
- Xchar *KE; /* :ke=: restore string for cursor */
- Xchar *KU; /* :ku=: key sequence sent by up arrow */
- Xchar *KD; /* :kd=: key sequence sent by down arrow */
- Xchar *KL; /* :kl=: key sequence sent by left arrow */
- Xchar *KR; /* :kr=: key sequence sent by right arrow */
- Xchar *HM; /* :HM=: key sequence sent by the <Home> key */
- Xchar *EN; /* :EN=: key sequence sent by the <End> key */
- Xchar *PU; /* :PU=: key sequence sent by the <PgUp> key */
- Xchar *PD; /* :PD=: key sequence sent by the <PgDn> key */
- Xchar *IM; /* :im=: insert mode start */
- Xchar *IC = ""; /* :ic=: insert the following character */
- Xchar *EI; /* :ei=: insert mode end */
- Xchar *DC; /* :dc=: delete a character */
- Xchar *TI; /* :ti=: terminal init */ /* GB */
- Xchar *TE; /* :te=: terminal exit */ /* GB */
- X#ifndef NO_CURSORSHAPE
- Xchar *CQ = (char *)0;/* :cQ=: normal cursor */
- Xchar *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
- Xchar *CV = (char *)2;/* :cV=: cursor used for VI command mode */
- Xchar *CI = (char *)3;/* :cI=: cursor used for VI input mode */
- Xchar *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
- X#endif
- Xchar *aend = ""; /* end an attribute -- either UE or ME */
- Xchar ERASEKEY; /* backspace key taken from ioctl structure */
- X
- X#if ANY_UNIX
- X# if UNIXV
- Xstatic struct termio oldtermio; /* original tty mode */
- Xstatic struct termio newtermio; /* cbreak/noecho tty mode */
- X# else
- Xstatic struct sgttyb oldsgttyb; /* original tty mode */
- Xstatic struct sgttyb newsgttyb; /* cbreak/nl/noecho tty mode */
- Xstatic int oldint; /* ^C or DEL, the "intr" character */
- X# ifdef TIOCSLTC
- Xstatic int oldswitch; /* ^Z, the "suspend" character */
- Xstatic int oldquote; /* ^V, the "quote next char" char */
- X# endif
- X# endif
- X#endif
- X
- X#if OSK
- Xstatic struct sgbuf oldsgttyb; /* orginal tty mode */
- Xstatic struct sgbuf newsgttyb; /* noecho tty mode */
- X#endif
- X
- Xstatic char *capbuf; /* capability string buffer */
- X
- X
- Xvoid initscr()
- X{
- X /* make sure TERM variable is set */
- X#if MSDOS
- X char *val;
- X if (! (val = getenv("TERM"))
- X || !strcmp(val, "pcbios"))
- X#else
- X if (!getenv("TERM"))
- X#endif
- X {
- X#if ANY_UNIX
- X write(2, "Environment variable TERM must be set\n", (unsigned)38);
- X exit(1);
- X#endif
- X#if OSK
- X writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
- X exit(1);
- X#endif
- X#if MSDOS || TOS
- X getsize(0);
- X#endif
- X }
- X else
- X {
- X#if MSDOS
- X *o_pcbios=0;
- X#endif
- X /* start termcap stuff */
- X starttcap();
- X }
- X
- X /* create stdscr and curscr */
- X stdscr = kbuf;
- X
- X /* change the terminal mode to cbreak/noecho */
- X#if ANY_UNIX
- X# if UNIXV
- X ioctl(2, TCGETA, &oldtermio);
- X# else
- X ioctl(2, TIOCGETP, &oldsgttyb);
- X# endif
- X#endif
- X
- X#if OSK
- X _gs_opt(0, &oldsgttyb);
- X#endif
- X resume_curses(TRUE);
- X}
- X
- X
- Xvoid endwin()
- X{
- X /* change the terminal mode back the way it was */
- X suspend_curses();
- X}
- X
- X
- Xstatic int curses_active = FALSE;
- X
- Xvoid suspend_curses()
- X{
- X#if ANY_UNIX && !UNIXV
- X struct tchars tbuf;
- X# ifdef TIOCSLTC
- X struct ltchars ltbuf;
- X# endif
- X#endif
- X#ifndef NO_CURSORSHAPE
- X if (has_CQ)
- X {
- X do_CQ();
- X }
- X#endif
- X if (has_TE) /* GB */
- X {
- X do_TE();
- X }
- X if (has_KE)
- X {
- X do_KE();
- X }
- X refresh();
- X
- X /* change the terminal mode back the way it was */
- X#if ANY_UNIX
- X# if UNIXV
- X ioctl(2, TCSETAW, &oldtermio);
- X# else
- X ioctl(2, TIOCSETP, &oldsgttyb);
- X
- X ioctl(2, TIOCGETC, &tbuf);
- X tbuf.t_intrc = oldint;
- X ioctl(2, TIOCSETC, &tbuf);
- X
- X# ifdef TIOCSLTC
- X ioctl(2, TIOCGLTC, <buf);
- X ltbuf.t_suspc = oldswitch;
- X ltbuf.t_lnextc = oldquote;
- X ioctl(2, TIOCSLTC, <buf);
- X# endif
- X# endif
- X#endif
- X#if OSK
- X _ss_opt(0, &oldsgttyb);
- X#endif
- X curses_active = FALSE;
- X}
- X
- Xvoid resume_curses(quietly)
- X int quietly;
- X{
- X if (!curses_active)
- X {
- X /* change the terminal mode to cbreak/noecho */
- X#if ANY_UNIX
- X# if UNIXV
- X ospeed = (oldtermio.c_cflag & CBAUD);
- X ERASEKEY = oldtermio.c_cc[VERASE];
- X newtermio = oldtermio;
- X newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
- X newtermio.c_oflag &= ~OPOST;
- X newtermio.c_lflag &= ISIG;
- X newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
- X newtermio.c_cc[VMIN] = 1;
- X newtermio.c_cc[VTIME] = 0;
- X# ifdef VSWTCH
- X newtermio.c_cc[VSWTCH] = 0;
- X# endif
- X ioctl(2, TCSETAW, &newtermio);
- X# else /* BSD or V7 or Coherent or Minix */
- X struct tchars tbuf;
- X# ifdef TIOCSLTC
- X struct ltchars ltbuf;
- X# endif
- X
- X ospeed = oldsgttyb.sg_ospeed;
- X ERASEKEY = oldsgttyb.sg_erase;
- X newsgttyb = oldsgttyb;
- X newsgttyb.sg_flags |= CBREAK;
- X newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
- X ioctl(2, TIOCSETP, &newsgttyb);
- X
- X ioctl(2, TIOCGETC, &tbuf);
- X oldint = tbuf.t_intrc;
- X tbuf.t_intrc = ctrl('C'); /* always use ^C for interrupts */
- X ioctl(2, TIOCSETC, &tbuf);
- X
- X# ifdef TIOCSLTC
- X ioctl(2, TIOCGLTC, <buf);
- X oldswitch = ltbuf.t_suspc;
- X ltbuf.t_suspc = 0; /* disable ^Z for elvis */
- X oldquote = ltbuf.t_lnextc;
- X ltbuf.t_lnextc = 0; /* disable ^V for elvis */
- X ioctl(2, TIOCSLTC, <buf);
- X# endif
- X
- X# endif
- X#endif
- X#if OSK
- X newsgttyb = oldsgttyb;
- X newsgttyb.sg_echo = 0;
- X newsgttyb.sg_eofch = 0;
- X newsgttyb.sg_kbach = 0;
- X newsgttyb.sg_kbich = ctrl('C');
- X _ss_opt(0, &newsgttyb);
- X ospeed = oldsgttyb.sg_baud;
- X ERASEKEY = oldsgttyb.sg_bspch;
- X#endif
- X
- X if (has_TI) /* GB */
- X {
- X do_TI();
- X }
- X if (has_KS)
- X {
- X do_KS();
- X }
- X
- X curses_active = TRUE;
- X }
- X
- X /* If we're supposed to quit quietly, then we're done */
- X if (quietly)
- X {
- X return;
- X }
- X
- X signal(SIGINT, SIG_IGN);
- X
- X move(LINES - 1, 0);
- X do_SO();
- X qaddstr("[Press <RETURN> to continue]");
- X do_SE();
- X refresh();
- X ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */
- X if (kbuf[0] == ':')
- X {
- X mode = MODE_COLON;
- X addch('\n');
- X refresh();
- X }
- X else
- X {
- X mode = MODE_VI;
- X redraw(MARK_UNSET, FALSE);
- X }
- X exwrote = FALSE;
- X
- X#if TURBOC
- X signal(SIGINT, (void(*)()) trapint);
- X#else
- X signal(SIGINT, trapint);
- X#endif
- X}
- X
- Xstatic void lacking(s)
- X char *s;
- X{
- X write(2, "This termcap entry lacks the :", (unsigned)30);
- X write(2, s, (unsigned)2);
- X write(2, "=: capability\n", (unsigned)14);
- X#if OSK
- X write(2, "\l", 1);
- X#endif
- X exit(1);
- X}
- X
- Xstatic void starttcap()
- X{
- X char *str;
- X static char cbmem[800];
- X#define MUSTHAVE(T,s) if (!(T = tgetstr(s, &capbuf))) lacking(s)
- X#define MAYHAVE(T,s) if (str = tgetstr(s, &capbuf)) T = str
- X#define PAIR(T,U,sT,sU) T=tgetstr(sT,&capbuf);U=tgetstr(sU,&capbuf);if (!T||!U)T=U=""
- X
- X /* allocate memory for capbuf */
- X capbuf = cbmem;
- X
- X /* get the termcap entry */
- X switch (tgetent(kbuf, getenv("TERM")))
- X {
- X case -1:
- X write(2, "Can't read /etc/termcap\n", (unsigned)24);
- X#if OSK
- X write(2, "\l", 1);
- X#endif
- X exit(2);
- X
- X case 0:
- X write(2, "Unrecognized TERM type\n", (unsigned)23);
- X#if OSK
- X write(2, "\l", 1);
- X#endif
- X exit(3);
- X }
- X
- X /* get strings */
- X MUSTHAVE(UP, "up");
- X MAYHAVE(VB, "vb");
- X MUSTHAVE(CM, "cm");
- X PAIR(SO, SE, "so", "se");
- X PAIR(TI, TE, "ti", "te");
- X if (tgetnum("ug") <= 0)
- X {
- X PAIR(US, UE, "us", "ue");
- X PAIR(MD, ME, "md", "me");
- X
- X /* get italics, or have it default to underline */
- X PAIR(AS, AE, "as", "ae");
- X if (!*AS)
- X {
- X AS = US;
- X AE = UE;
- X }
- X }
- X MAYHAVE(AL, "al");
- X MAYHAVE(DL, "dl");
- X MUSTHAVE(CE, "ce");
- X MAYHAVE(CD, "cd");
- X#if OSK
- X MAYHAVE(SR_, "sr");
- X#else
- X MAYHAVE(SR, "sr");
- X#endif
- X PAIR(IM, EI, "im", "ei");
- X MAYHAVE(IC, "ic");
- X MAYHAVE(DC, "dc");
- X
- X /* other termcap stuff */
- X AM = tgetflag("am");
- X PT = tgetflag("pt");
- X getsize(0);
- X
- X /* Key sequences */
- X PAIR(KS, KE, "ks", "ke");
- X MAYHAVE(KU, "ku"); /* up */
- X MAYHAVE(KD, "kd"); /* down */
- X MAYHAVE(KL, "kl"); /* left */
- X MAYHAVE(KR, "kr"); /* right */
- X MAYHAVE(PU, "kP"); /* PgUp */
- X MAYHAVE(PD, "kN"); /* PgDn */
- X MAYHAVE(HM, "kh"); /* Home */
- X MAYHAVE(EN, "kH"); /* End */
- X#ifndef CRUNCH
- X if (!PU) MAYHAVE(PU, "K2"); /* "3x3 pad" names for PgUp, etc. */
- X if (!PD) MAYHAVE(PD, "K5");
- X if (!HM) MAYHAVE(HM, "K1");
- X if (!EN) MAYHAVE(EN, "K4");
- X
- X MAYHAVE(PU, "PU"); /* old XENIX names for PgUp, etc. */
- X MAYHAVE(PD, "PD"); /* (overrides others, if used.) */
- X MAYHAVE(HM, "HM");
- X MAYHAVE(EN, "EN");
- X#endif
- X
- X#ifndef NO_CURSORSHAPE
- X /* cursor shapes */
- X CQ = tgetstr("cQ", &capbuf);
- X if (has_CQ)
- X {
- X CX = tgetstr("cX", &capbuf);
- X if (!CX) CX = CQ;
- X CV = tgetstr("cV", &capbuf);
- X if (!CV) CV = CQ;
- X CI = tgetstr("cI", &capbuf);
- X if (!CI) CI = CQ;
- X CR = tgetstr("cR", &capbuf);
- X if (!CR) CR = CQ;
- X }
- X# ifndef CRUNCH
- X else
- X {
- X PAIR(CQ, CV, "ve", "vs");
- X CX = CI = CR = CQ;
- X }
- X# endif /* !CRUNCH */
- X#endif /* !NO_CURSORSHAPE */
- X
- X#undef MUSTHAVE
- X#undef MAYHAVE
- X#undef PAIR
- X}
- X
- X
- X/* This function gets the window size. It uses the TIOCGWINSZ ioctl call if
- X * your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
- X * This function is called once during initialization, and thereafter it is
- X * called whenever the SIGWINCH signal is sent to this process.
- X */
- Xint getsize(signo)
- X int signo;
- X{
- X int lines;
- X int cols;
- X#ifdef TIOCGWINSZ
- X struct winsize size;
- X#endif
- X
- X#ifdef SIGWINCH
- X /* reset the signal vector */
- X signal(SIGWINCH, getsize);
- X#endif
- X
- X /* get the window size, one way or another. */
- X lines = cols = 0;
- X#ifdef TIOCGWINSZ
- X if (ioctl(2, TIOCGWINSZ, &size) >= 0)
- X {
- X lines = size.ws_row;
- X cols = size.ws_col;
- X }
- X#endif
- X if ((lines == 0 || cols == 0) && signo == 0)
- X {
- X LINES = CHECKBIOS(v_rows(), tgetnum("li"));
- X COLS = CHECKBIOS(v_cols(), tgetnum("co"));
- X }
- X if (lines >= 2 && cols >= 30)
- X {
- X LINES = lines;
- X COLS = cols;
- X }
- X
- X /* Make sure we got values that we can live with */
- X if (LINES < 2 || COLS < 30)
- X {
- X write(2, "Screen too small\n", (unsigned)17);
- X#if OSK
- X write(2, "\l", 1);
- X#endif
- X endwin();
- X exit(2);
- X }
- X
- X /* !!! copy the new values into Elvis' options */
- X {
- X extern char o_columns[], o_lines[];
- X
- X *o_columns = COLS;
- X *o_lines = LINES;
- X }
- X
- X return 0;
- X}
- X
- X
- X/* This is a function version of addch() -- it is used by tputs() */
- Xint faddch(ch)
- X int ch;
- X{
- X addch(ch);
- X
- X return 0;
- X}
- X
- X/* These functions are equivelent to the macros of the same names... */
- X
- Xvoid qaddstr(str)
- X char *str;
- X{
- X REG char *s_, *d_;
- X
- X#if MSDOS
- X if (o_pcbios[0])
- X {
- X while (*str)
- X qaddch(*str++);
- X return;
- X }
- X#endif
- X for (s_=(str), d_=stdscr; *d_++ = *s_++; )
- X {
- X }
- X stdscr = d_ - 1;
- X}
- X
- Xvoid attrset(a)
- X int a;
- X{
- X do_aend();
- X if (a == A_BOLD)
- X {
- X do_MD();
- X aend = ME;
- X }
- X else if (a == A_UNDERLINE)
- X {
- X do_US();
- X aend = UE;
- X }
- X else if (a == A_ALTCHARSET)
- X {
- X do_AS();
- X aend = AE;
- X }
- X else
- X {
- X aend = "";
- X }
- X}
- X
- X
- Xvoid insch(ch)
- X int ch;
- X{
- X if (has_IM)
- X do_IM();
- X do_IC();
- X qaddch(ch);
- X if (has_EI)
- X do_EI();
- X}
- X
- X#if MSDOS
- X
- Xstatic int alarmtime;
- X
- X/* raw read - #defined to read (0, ...) on non-MSDOS.
- X * With MSDOS, am maximum of 1 byte is read.
- X * If more bytes should be read, just change the loop.
- X * The following code uses the IBM-PC-System-Timer, so probably wont't work
- X * on non-compatibles.
- X */
- X/*ARGSUSED*/
- Xttyread(buf, len)
- X char *buf;
- X int len;
- X{
- X volatile char far *biostimer;
- X char oldtime;
- X int nticks = 0;
- X int pos = 0;
- X
- X biostimer = (char far *)0x0040006cl;
- X oldtime = *biostimer;
- X
- X while (!pos && (!alarmtime || nticks<alarmtime))
- X { if (kbhit())
- X if ((buf[pos++] = getch()) == 0) /* function key */
- X buf[pos-1] = '#';
- X if (oldtime != *biostimer)
- X { nticks++;
- X oldtime = *biostimer;
- X }
- X }
- X return pos;
- X}
- X
- Xalarm(time)
- X int time;
- X{
- X alarmtime = 2 * time; /* ticks are 1/18 sec. */
- X}
- X
- Xsleep(seconds)
- X unsigned seconds;
- X{
- X volatile char far *biostimer = (char far *)0x0040006cl;
- X char stop;
- X
- X stop = *biostimer + 18 * seconds;
- X while (*biostimer != stop)
- X {
- X }
- X}
- X#endif
- X
- X#if TOS
- X
- Xstatic int alarmtime;
- Xstatic long timer;
- X
- Xstatic gettime()
- X{
- X timer = *(long *)(0x4ba);
- X}
- X
- X/*ARGSUSED*/
- Xttyread(buf, len)
- X char *buf;
- X int len;
- X{
- X int pos=0;
- X long l;
- X long endtime;
- X
- X Supexec(gettime);
- X endtime = timer+alarmtime;
- X
- X while (!pos && (!alarmtime || timer<endtime))
- X {
- X if (Bconstat(2))
- X {
- X l = Bconin(2);
- X if ((buf[pos++]=l) == '\0')
- X {
- X buf[pos-1]='#';
- X buf[pos++]=l>>16;
- X }
- X }
- X Supexec(gettime);
- X }
- X return pos;
- X}
- X
- Xalarm(time)
- X int time;
- X{
- X alarmtime = 50 * time; /* ticks are 1/200 sec. */
- X}
- X
- Xttywrite(buf, len)
- X char *buf;
- X int len;
- X{
- X while (len--)
- X Bconout(2, *buf++);
- X}
- X#endif
- X
- X#if OSK
- Xttyread(buf, len)
- X char *buf;
- X int len;
- X{
- X REG int i;
- X if ((i = _gs_rdy(0)) > 0)
- X return read(0, buf, i < len ? i : len);
- X else
- X return read(0, buf, 1);
- X}
- X
- Xalarm(time)
- X int time;
- X{
- X#define TIME(secs) ((secs << 8) | 0x80000000)
- X static int alrmid;
- X
- X if (time)
- X alrmid = alm_set(SIGQUIT, TIME(time));
- X else
- X alm_delete(alrmid);
- X}
- X#endif /* OSK */
- eof
- if test `wc -c <curses.c` -ne 14196
- then
- echo curses.c damaged!
- fi
- fi
-
- exit 0
- -------------------------------------------------------------------------------
- Steve Kirkendall kirkenda@cs.pdx.edu Grad student at Portland State U.
-