ELvis 1.4, part 6 of 8
Steve Kirkendall
kirkenda at eecs.cs.pdx.edu
Tue Dec 4 08:33:56 AEST 1990
# --------------------------- 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 9893 Dec 2 17:57 modify.c
# -rw-r--r-- 1 kirkenda 10230 Dec 2 17:57 move1.c
# -rw-r--r-- 1 kirkenda 4445 Dec 2 17:57 move2.c
# -rw-r--r-- 1 kirkenda 2697 Dec 2 17:57 move3.c
# -rw-r--r-- 1 kirkenda 3699 Dec 2 17:57 move4.c
# -rw-r--r-- 1 kirkenda 3940 Dec 2 17:57 move5.c
# -rw-r--r-- 1 kirkenda 14362 Dec 2 17:57 opts.c
# -rw-r--r-- 1 kirkenda 2306 Dec 2 17:57 recycle.c
# -rw-r--r-- 1 kirkenda 19816 Dec 2 17:57 redraw.c
#
if test -f modify.c -a "$1" != -f
then
echo Will not overwrite modify.c
else
echo Extracting modify.c
sed 's/^X//' >modify.c <<\eof
X/* modify.c */
X
X/* This file contains the low-level file modification functions:
X * delete(frommark, tomark) - removes line or portions of lines
X * add(frommark, text) - inserts new text
X * change(frommark, tomark, text) - delete, then add
X */
X
X#include "config.h"
X#include "vi.h"
X
X#ifdef DEBUG
X# include <stdio.h>
Xstatic FILE *dbg;
X
X/*VARARGS1*/
Xdebout(msg, arg1, arg2, arg3, arg4, arg5)
X char *msg, *arg1, *arg2, *arg3, *arg4, *arg5;
X{
X if (!dbg)
X {
X dbg = fopen("debug.out", "w");
X setbuf(dbg, (FILE *)0);
X }
X fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5);
X}
X#endif /* DEBUG */
X
X/* delete a range of text from the file */
Xvoid delete(frommark, tomark)
X MARK frommark; /* first char to be deleted */
X MARK tomark; /* AFTER last char to be deleted */
X{
X int i; /* used to move thru logical blocks */
X REG char *scan; /* used to scan thru text of the blk */
X REG char *cpy; /* used when copying chars */
X BLK *blk; /* a text block */
X long l; /* a line number */
X MARK m; /* a traveling version of frommark */
X
X#ifdef DEBUG
X debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark));
X#endif
X
X /* if not deleting anything, quit now */
X if (frommark == tomark)
X {
X return;
X }
X
X /* This is a change */
X changes++;
X significant = TRUE;
X
X /* if this is a multi-line change, then we'll have to redraw */
X if (markline(frommark) != markline(tomark))
X {
X mustredraw = TRUE;
X redrawrange(markline(frommark), markline(tomark), markline(frommark));
X }
X
X /* adjust marks 'a through 'z and '' as needed */
X l = markline(tomark);
X for (i = 0; i < NMARKS; i++)
X {
X if (mark[i] < frommark)
X {
X continue;
X }
X else if (mark[i] < tomark)
X {
X mark[i] = MARK_UNSET;
X }
X else if (markline(mark[i]) == l)
X {
X if (markline(frommark) == l)
X {
X mark[i] -= markidx(tomark) - markidx(frommark);
X }
X else
X {
X mark[i] -= markidx(tomark);
X }
X }
X else
X {
X mark[i] -= MARK_AT_LINE(l - markline(frommark));
X }
X }
X
X /* Reporting... */
X if (markidx(frommark) == 0 && markidx(tomark) == 0)
X {
X rptlines = markline(tomark) - markline(frommark);
X rptlabel = "deleted";
X }
X
X /* find the block containing frommark */
X l = markline(frommark);
X for (i = 1; lnum[i] < l; i++)
X {
X }
X
X /* process each affected block... */
X for (m = frommark;
X m < tomark && lnum[i] < INFINITY;
X m = MARK_AT_LINE(lnum[i - 1] + 1))
X {
X /* fetch the block */
X blk = blkget(i);
X
X /* find the mark in the block */
X scan = blk->c;
X for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
X {
X while (*scan++ != '\n')
X {
X }
X }
X scan += markidx(m);
X
X /* figure out where the changes to this block end */
X if (markline(tomark) > lnum[i])
X {
X cpy = blk->c + BLKSIZE;
X }
X else if (markline(tomark) == markline(m))
X {
X cpy = scan - markidx(m) + markidx(tomark);
X }
X else
X {
X cpy = scan;
X for (l = markline(tomark) - markline(m);
X l > 0;
X l--)
X {
X while (*cpy++ != '\n')
X {
X }
X }
X cpy += markidx(tomark);
X }
X
X /* delete the stuff by moving chars within this block */
X while (cpy < blk->c + BLKSIZE)
X {
X *scan++ = *cpy++;
X }
X while (scan < blk->c + BLKSIZE)
X {
X *scan++ = '\0';
X }
X
X /* adjust tomark to allow for lines deleted from this block */
X tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
X
X /* if this block isn't empty now, then advance i */
X if (*blk->c)
X {
X i++;
X }
X
X /* the buffer has changed. Update hdr and lnum. */
X blkdirty(blk);
X }
X
X /* must have at least 1 line */
X if (nlines == 0)
X {
X blk = blkadd(1);
X blk->c[0] = '\n';
X blkdirty(blk);
X cursor = MARK_FIRST;
X }
X}
X
X
X/* add some text at a specific place in the file */
Xvoid add(atmark, newtext)
X MARK atmark; /* where to insert the new text */
X char *newtext; /* NUL-terminated string to insert */
X{
X REG char *scan; /* used to move through string */
X REG char *build; /* used while copying chars */
X int addlines; /* number of lines we're adding */
X int lastpart; /* size of last partial line */
X BLK *blk; /* the block to be modified */
X int blkno; /* the logical block# of (*blk) */
X REG char *newptr; /* where new text starts in blk */
X BLK buf; /* holds chars from orig blk */
X BLK linebuf; /* holds part of line that didn't fit */
X BLK *following; /* the BLK following the last BLK */
X int i;
X long l;
X
X#ifdef DEBUG
X debout("add(%ld.%d, \"%s\")\n", markline(atmark), markidx(atmark), newtext);
X#endif
X#ifdef lint
X buf.c[0] = 0;
X#endif
X /* if not adding anything, return now */
X if (!*newtext)
X {
X return;
X }
X
X /* This is a change */
X changes++;
X significant = TRUE;
X
X /* count the number of lines in the new text */
X for (scan = newtext, lastpart = addlines = 0; *scan; )
X {
X if (*scan++ == '\n')
X {
X addlines++;
X lastpart = 0;
X }
X else
X {
X lastpart++;
X }
X }
X
X /* Reporting... */
X if (lastpart == 0 && markidx(atmark) == 0)
X {
X rptlines = addlines;
X rptlabel = "added";
X }
X
X /* extract the line# from atmark */
X l = markline(atmark);
X
X /* if more than 0 lines, then we'll have to redraw the screen */
X if (addlines > 0)
X {
X mustredraw = TRUE;
X if (markidx(atmark) == 0 && lastpart == 0)
X {
X redrawrange(l, l, l + addlines);
X }
X else
X {
X /* make sure the last line gets redrawn -- it was
X * split, so its appearance has changed
X */
X redrawrange(l, l + 1L, l + addlines + 1L);
X }
X }
X
X /* adjust marks 'a through 'z and '' as needed */
X for (i = 0; i < NMARKS; i++)
X {
X if (mark[i] < atmark)
X {
X /* earlier line, or earlier in same line: no change */
X continue;
X }
X else if (markline(mark[i]) > l)
X {
X /* later line: move down a whole number of lines */
X mark[i] += MARK_AT_LINE(addlines);
X }
X else
X {
X /* later in same line */
X if (addlines > 0)
X {
X /* multi-line add, which split this line:
X * move down, and possibly left or right,
X * depending on where the split was and how
X * much text was inserted after the last \n
X */
X mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark);
X }
X else
X {
X /* totally within this line: move right */
X mark[i] += lastpart;
X }
X }
X }
X
X /* get the block to be modified */
X for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
X {
X }
X blk = blkget(blkno);
X buf = *blk;
X
X /* figure out where the new text starts */
X for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1;
X l > 0;
X l--)
X {
X while (*newptr++ != '\n')
X {
X }
X }
X newptr += markidx(atmark);
X
X /* keep start of old block */
X build = blk->c + (newptr - buf.c);
X
X /* fill this block (or blocks) from the newtext string */
X while (*newtext)
X {
X while (*newtext && build < blk->c + BLKSIZE - 1)
X {
X *build++ = *newtext++;
X }
X if (*newtext)
X {
X /* save the excess */
X for (scan = linebuf.c + BLKSIZE;
X build > blk->c && build[-1] != '\n';
X )
X {
X *--scan = *--build;
X }
X
X /* write the block */
X while (build < blk->c + BLKSIZE)
X {
X *build++ = '\0';
X }
X blkdirty(blk);
X
X /* add another block */
X blkno++;
X blk = blkadd(blkno);
X
X /* copy in the excess from last time */
X for (build = blk->c; scan < linebuf.c + BLKSIZE; )
X {
X *build++ = *scan++;
X }
X }
X }
X
X /* fill this block(s) from remainder of orig block */
X while (newptr < buf.c + BLKSIZE && *newptr)
X {
X while (newptr < buf.c + BLKSIZE
X && *newptr
X && build < blk->c + BLKSIZE - 1)
X {
X *build++ = *newptr++;
X }
X if (newptr < buf.c + BLKSIZE && *newptr)
X {
X /* save the excess */
X for (scan = linebuf.c + BLKSIZE;
X build > blk->c && build[-1] != '\n';
X )
X {
X *--scan = *--build;
X }
X
X /* write the block */
X while (build < blk->c + BLKSIZE)
X {
X *build++ = '\0';
X }
X blkdirty(blk);
X
X /* add another block */
X blkno++;
X blk = blkadd(blkno);
X
X /* copy in the excess from last time */
X for (build = blk->c; scan < linebuf.c + BLKSIZE; )
X {
X *build++ = *scan++;
X }
X }
X }
X
X /* see if we can combine our last block with the following block */
X if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6))
X {
X /* hey, we probably can! Get the following block & see... */
X following = blkget(blkno + 1);
X if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1)
X {
X /* we can! Copy text from following to blk */
X for (scan = following->c; *scan; )
X {
X *build++ = *scan++;
X }
X while (build < blk->c + BLKSIZE)
X {
X *build++ = '\0';
X }
X blkdirty(blk);
X
X /* pretend the following was the last blk */
X blk = following;
X build = blk->c;
X }
X }
X
X /* that last block is dirty by now */
X while (build < blk->c + BLKSIZE)
X {
X *build++ = '\0';
X }
X blkdirty(blk);
X}
X
X
X/* change the text of a file */
Xvoid change(frommark, tomark, newtext)
X MARK frommark, tomark;
X char *newtext;
X{
X int i;
X long l;
X char *text;
X BLK *blk;
X
X#ifdef DEBUG
X debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext);
X#endif
X
X /* optimize for single-character replacement */
X if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
X {
X /* find the block containing frommark */
X l = markline(frommark);
X for (i = 1; lnum[i] < l; i++)
X {
X }
X
X /* get the block */
X blk = blkget(i);
X
X /* find the line within the block */
X for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
X {
X if (*text == '\n')
X {
X i--;
X }
X }
X
X /* replace the char */
X text += markidx(frommark);
X if (*text == newtext[0])
X {
X /* no change was needed - same char */
X return;
X }
X else if (*text != '\n')
X {
X /* This is a change */
X changes++;
X significant = TRUE;
X ChangeText
X {
X *text = newtext[0];
X blkdirty(blk);
X }
X return;
X }
X /* else it is a complex change involving newline... */
X }
X
X /* couldn't optimize, so do delete & add */
X ChangeText
X {
X delete(frommark, tomark);
X add(frommark, newtext);
X rptlabel = "changed";
X }
X}
eof
if test `wc -c <modify.c` -ne 9893
then
echo modify.c damaged!
fi
fi
if test -f move1.c -a "$1" != -f
then
echo Will not overwrite move1.c
else
echo Extracting move1.c
sed 's/^X//' >move1.c <<\eof
X/* move1.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains most movement functions */
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
XMARK m_updnto(m, cnt, cmd)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X DEFAULT(cmd == 'G' ? nlines : 1L);
X
X /* move up or down 'cnt' lines */
X switch (cmd)
X {
X case ('P'&0x1f):
X case '-':
X case 'k':
X m -= MARK_AT_LINE(cnt);
X break;
X
X case 'G':
X if (cnt < 1L || cnt > nlines)
X {
X msg("Only %ld lines", nlines);
X return MARK_UNSET;
X }
X m = MARK_AT_LINE(cnt);
X break;
X
X default:
X m += MARK_AT_LINE(cnt);
X }
X
X /* if that left us screwed up, then fail */
X if (m < MARK_FIRST || markline(m) > nlines)
X {
X return MARK_UNSET;
X }
X
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_right(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X int idx; /* index of the new cursor position */
X
X DEFAULT(1);
X
X /* move to right, if that's OK */
X pfetch(markline(m));
X idx = markidx(m) + cnt;
X if (idx < plen)
X {
X m += cnt;
X }
X else
X {
X return MARK_UNSET;
X }
X
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_left(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X DEFAULT(1);
X
X /* move to the left, if that's OK */
X if (markidx(m) >= cnt)
X {
X m -= cnt;
X }
X else
X {
X return MARK_UNSET;
X }
X
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_tocol(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X char *text; /* text of the line */
X int col; /* column number */
X int idx; /* index into the line */
X
X DEFAULT(1);
X
X /* internally, columns are numbered 0..COLS-1, not 1..COLS */
X cnt--;
X
X /* if 0, that's easy */
X if (cnt == 0)
X {
X m &= ~(BLKSIZE - 1);
X return m;
X }
X
X /* find that column within the line */
X pfetch(markline(m));
X text = ptext;
X for (col = idx = 0; col < cnt && *text; text++, idx++)
X {
X if (*text == '\t' && !*o_list)
X {
X col += *o_tabstop;
X col -= col % *o_tabstop;
X }
X else if (UCHAR(*text) < ' ' || *text == '\177')
X {
X col += 2;
X }
X#ifndef NO_CHARATTR
X else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
X {
X text += 2; /* plus one more as part of for loop */
X }
X#endif
X else
X {
X col++;
X }
X }
X if (!*text)
X {
X return MARK_UNSET;
X }
X else
X {
X m = (m & ~(BLKSIZE - 1)) + idx;
X }
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_front(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument (ignored) */
X{
X char *scan;
X
X /* move to the first non-whitespace character */
X pfetch(markline(m));
X scan = ptext;
X m &= ~(BLKSIZE - 1);
X while (*scan == ' ' || *scan == '\t')
X {
X scan++;
X m++;
X }
X
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_rear(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument (ignored) */
X{
X /* Try to move *EXTREMELY* far to the right. It is fervently hoped
X * that other code will convert this to a more reasonable MARK before
X * anything tries to actually use it. (See adjmove() in vi.c)
X */
X return m | (BLKSIZE - 1);
X}
X
X#ifndef NO_SENTENCE
X/*ARGSUSED*/
XMARK m_fsentence(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X REG char *text;
X REG long l;
X
X DEFAULT(1);
X
X /* get the current line */
X l = markline(m);
X pfetch(l);
X text = ptext + markidx(m);
X
X /* for each requested sentence... */
X while (cnt-- > 0)
X {
X /* search forward for one of [.?!] followed by spaces or EOL */
X do
X {
X /* wrap at end of line */
X if (!text[0])
X {
X if (l >= nlines)
X {
X return MARK_UNSET;
X }
X l++;
X pfetch(l);
X text = ptext;
X }
X else
X {
X text++;
X }
X } while (text[0] != '.' && text[0] != '?' && text[0] != '!'
X || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
X }
X
X /* construct a mark for this location */
X m = buildmark(text);
X
X /* move forward to the first word of the next sentence */
X m = m_fword(m, 1L);
X
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_bsentence(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X REG char *text; /* used to scan thru text */
X REG long l; /* current line number */
X int flag; /* have we passed at least one word? */
X
X DEFAULT(1);
X
X /* get the current line */
X l = markline(m);
X pfetch(l);
X text = ptext + markidx(m);
X
X /* for each requested sentence... */
X flag = TRUE;
X while (cnt-- > 0)
X {
X /* search backward for one of [.?!] followed by spaces or EOL */
X do
X {
X /* wrap at beginning of line */
X if (text == ptext)
X {
X do
X {
X if (l <= 1)
X {
X return MARK_UNSET;
X }
X l--;
X pfetch(l);
X } while (!*ptext);
X text = ptext + plen - 1;
X }
X else
X {
X text--;
X }
X
X /* are we moving past a "word"? */
X if (text[0] >= '0')
X {
X flag = FALSE;
X }
X } while (flag || text[0] != '.' && text[0] != '?' && text[0] != '!'
X || text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
X }
X
X /* construct a mark for this location */
X m = buildmark(text);
X
X /* move to the front of the following sentence */
X m = m_fword(m, 1L);
X
X return m;
X}
X#endif
X
X/*ARGSUSED*/
XMARK m_fparagraph(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X char *text;
X char *pscn; /* used to scan thru value of "paragraphs" option */
X long l;
X
X DEFAULT(1);
X
X for (l = markline(m); cnt > 0 && l++ < nlines; )
X {
X text = fetchline(l);
X if (!*text)
X {
X cnt--;
X }
X#ifndef NO_SENTENCE
X else if (*text == '.')
X {
X for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
X {
X if (pscn[0] == text[1] && pscn[1] == text[2])
X {
X cnt--;
X break;
X }
X }
X }
X#endif
X }
X if (l <= nlines)
X {
X m = MARK_AT_LINE(l);
X }
X else
X {
X m = MARK_LAST;
X }
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_bparagraph(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X{
X char *text;
X char *pscn; /* used to scan thru value of "paragraph" option */
X long l;
X
X DEFAULT(1);
X
X for (l = markline(m); cnt > 0 && l-- > 1; )
X {
X text = fetchline(l);
X if (!*text)
X {
X cnt--;
X }
X#ifndef NO_SENTENCE
X else if (*text == '.')
X {
X for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
X {
X if (pscn[0] == text[1] && pscn[1] == text[2])
X {
X cnt--;
X break;
X }
X }
X }
X#endif
X }
X if (l >= 1)
X {
X m = MARK_AT_LINE(l);
X }
X else
X {
X m = MARK_FIRST;
X }
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_fsection(m, cnt, key)
X MARK m; /* movement is relative to this mark */
X long cnt; /* (ignored) */
X int key; /* second key stroke - must be ']' */
X{
X char *text;
X char *sscn; /* used to scan thru value of "sections" option */
X long l;
X
X /* make sure second key was ']' */
X if (key != ']')
X {
X return MARK_UNSET;
X }
X
X for (l = markline(m); l++ < nlines; )
X {
X text = fetchline(l);
X if (*text == '{')
X {
X break;
X }
X#ifndef NO_SENTENCE
X else if (*text == '.')
X {
X for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
X {
X if (sscn[0] == text[1] && sscn[1] == text[2])
X {
X goto BreakBreak;
X }
X }
X }
X#endif
X }
XBreakBreak:
X if (l <= nlines)
X {
X m = MARK_AT_LINE(l);
X }
X else
X {
X m = MARK_LAST;
X }
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_bsection(m, cnt, key)
X MARK m; /* movement is relative to this mark */
X long cnt; /* (ignored) */
X int key; /* second key stroke - must be '[' */
X{
X char *text;
X char *sscn; /* used to scan thru value of "sections" option */
X long l;
X
X /* make sure second key was '[' */
X if (key != '[')
X {
X return MARK_UNSET;
X }
X
X for (l = markline(m); l-- > 1; )
X {
X text = fetchline(l);
X if (*text == '{')
X {
X break;
X }
X#ifndef NO_SENTENCE
X else if (*text == '.')
X {
X for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
X {
X if (sscn[0] == text[1] && sscn[1] == text[2])
X {
X goto BreakBreak;
X }
X }
X }
X#endif
X }
XBreakBreak:
X if (l >= 1)
X {
X m = MARK_AT_LINE(l);
X }
X else
X {
X m = MARK_FIRST;
X }
X return m;
X}
X
X
X/*ARGSUSED*/
XMARK m_match(m, cnt)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument (ignored) */
X{
X long l;
X REG char *text;
X REG char match;
X REG char nest;
X REG int count;
X
X /* get the current line */
X l = markline(m);
X pfetch(l);
X text = ptext + markidx(m);
X
X /* search forward within line for one of "[](){}" */
X for (match = '\0'; !match && *text; text++)
X {
X /* tricky way to recognize 'em in ASCII */
X nest = *text;
X if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
X {
X match = nest ^ ('[' ^ ']');
X }
X else if ((nest & 0xfe) == '(')
X {
X match = nest ^ ('(' ^ ')');
X }
X else
X {
X match = 0;
X }
X }
X if (!match)
X {
X return MARK_UNSET;
X }
X text--;
X
X /* search forward or backward for match */
X if (match == '(' || match == '[' || match == '{')
X {
X /* search backward */
X for (count = 1; count > 0; )
X {
X /* wrap at beginning of line */
X if (text == ptext)
X {
X do
X {
X if (l <= 1L)
X {
X return MARK_UNSET;
X }
X l--;
X pfetch(l);
X } while (!*ptext);
X text = ptext + plen - 1;
X }
X else
X {
X text--;
X }
X
X /* check the char */
X if (*text == match)
X count--;
X else if (*text == nest)
X count++;
X }
X }
X else
X {
X /* search forward */
X for (count = 1; count > 0; )
X {
X /* wrap at end of line */
X if (!*text)
X {
X if (l >= nlines)
X {
X return MARK_UNSET;
X }
X l++;
X pfetch(l);
X text = ptext;
X }
X else
X {
X text++;
X }
X
X /* check the char */
X if (*text == match)
X count--;
X else if (*text == nest)
X count++;
X }
X }
X
X /* construct a mark for this place */
X m = buildmark(text);
X return m;
X}
X
X/*ARGSUSED*/
XMARK m_tomark(m, cnt, key)
X MARK m; /* movement is relative to this mark */
X long cnt; /* (ignored) */
X int key; /* keystroke - the mark to move to */
X{
X /* mark '' is a special case */
X if (key == '\'' || key == '`')
X {
X if (mark[26] == MARK_UNSET)
X {
X return MARK_FIRST;
X }
X else
X {
X return mark[26];
X }
X }
X
X /* if not a valid mark number, don't move */
X if (key < 'a' || key > 'z')
X {
X return MARK_UNSET;
X }
X
X /* return the selected mark -- may be MARK_UNSET */
X if (!mark[key - 'a'])
X {
X msg("mark '%c is unset", key);
X }
X return mark[key - 'a'];
X}
X
eof
if test `wc -c <move1.c` -ne 10230
then
echo move1.c damaged!
fi
fi
if test -f move2.c -a "$1" != -f
then
echo Will not overwrite move2.c
else
echo Extracting move2.c
sed 's/^X//' >move2.c <<\eof
X/* move2.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This function contains the movement functions that perform RE searching */
X
X#include "config.h"
X#include "vi.h"
X#include "regexp.h"
X
Xextern long atol();
X
Xstatic regexp *re; /* compiled version of the pattern to search for */
Xstatic prevsf; /* boolean: previous search direction was forward? */
X
XMARK m_nsrch(m)
X MARK m; /* where to start searching */
X{
X if (prevsf)
X {
X m = m_fsrch(m, (char *)0);
X prevsf = TRUE;
X }
X else
X {
X m = m_bsrch(m, (char *)0);
X prevsf = FALSE;
X }
X return m;
X}
X
XMARK m_Nsrch(m)
X MARK m; /* where to start searching */
X{
X if (prevsf)
X {
X m = m_bsrch(m, (char *)0);
X prevsf = TRUE;
X }
X else
X {
X m = m_fsrch(m, (char *)0);
X prevsf = FALSE;
X }
X return m;
X}
X
XMARK m_fsrch(m, ptrn)
X MARK m; /* where to start searching */
X char *ptrn; /* pattern to search for */
X{
X long l; /* line# of line to be searched */
X char *line; /* text of line to be searched */
X int wrapped;/* boolean: has our search wrapped yet? */
X int pos; /* where we are in the line */
X long delta; /* line offset, for things like "/foo/+1" */
X
X /* remember: "previous search was forward" */
X prevsf = TRUE;
X
X delta = 0L;
X if (ptrn && *ptrn)
X {
X /* locate the closing '/', if any */
X line = parseptrn(ptrn);
X if (*line)
X {
X delta = atol(line);
X }
X ptrn++;
X
X /* free the previous pattern */
X if (re) free(re);
X
X /* compile the pattern */
X re = regcomp(ptrn);
X if (!re)
X {
X return MARK_UNSET;
X }
X }
X else if (!re)
X {
X msg("No previous expression");
X return MARK_UNSET;
X }
X
X /* search forward for the pattern */
X pos = markidx(m) + 1;
X pfetch(markline(m));
X if (pos >= plen)
X {
X pos = 0;
X m = (m | (BLKSIZE - 1)) + 1;
X }
X wrapped = FALSE;
X for (l = markline(m); l != markline(m) + 1 || !wrapped; l++)
X {
X /* wrap search */
X if (l > nlines)
X {
X /* if we wrapped once already, then the search failed */
X if (wrapped)
X {
X break;
X }
X
X /* else maybe we should wrap now? */
X if (*o_wrapscan)
X {
X l = 0;
X wrapped = TRUE;
X continue;
X }
X else
X {
X break;
X }
X }
X
X /* get this line */
X line = fetchline(l);
X
X /* check this line */
X if (regexec(re, &line[pos], (pos == 0)))
X {
X /* match! */
X if (wrapped && *o_warn)
X msg("(wrapped)");
X if (delta != 0L)
X {
X l += delta;
X if (l < 1 || l > nlines)
X {
X msg("search offset too big");
X return MARK_UNSET;
X }
X return m_front(MARK_AT_LINE(l), 0L);
X }
X return MARK_AT_LINE(l) + (int)(re->startp[0] - line);
X }
X pos = 0;
X }
X
X /* not found */
X msg(*o_wrapscan ? "Not found" : "Hit bottom without finding RE");
X return MARK_UNSET;
X}
X
XMARK m_bsrch(m, ptrn)
X MARK m; /* where to start searching */
X char *ptrn; /* pattern to search for */
X{
X long l; /* line# of line to be searched */
X char *line; /* text of line to be searched */
X int wrapped;/* boolean: has our search wrapped yet? */
X int pos; /* last acceptable idx for a match on this line */
X int last; /* remembered idx of the last acceptable match on this line */
X int try; /* an idx at which we strat searching for another match */
X
X /* remember: "previous search was not forward" */
X prevsf = FALSE;
X
X if (ptrn && *ptrn)
X {
X /* locate the closing '?', if any */
X line = parseptrn(ptrn);
X ptrn++;
X
X /* free the previous pattern, if any */
X if (re) free(re);
X
X /* compile the pattern */
X re = regcomp(ptrn);
X if (!re)
X {
X return MARK_UNSET;
X }
X }
X else if (!re)
X {
X msg("No previous expression");
X return MARK_UNSET;
X }
X
X /* search backward for the pattern */
X pos = markidx(m);
X wrapped = FALSE;
X for (l = markline(m); l != markline(m) - 1 || !wrapped; l--)
X {
X /* wrap search */
X if (l < 1)
X {
X if (*o_wrapscan)
X {
X l = nlines + 1;
X wrapped = TRUE;
X continue;
X }
X else
X {
X break;
X }
X }
X
X /* get this line */
X line = fetchline(l);
X
X /* check this line */
X if (regexec(re, line, 1) && (int)(re->startp[0] - line) < pos)
X {
X /* match! now find the last acceptable one in this line */
X do
X {
X last = (int)(re->startp[0] - line);
X try = (int)(re->endp[0] - line);
X } while (try > 0
X && regexec(re, &line[try], FALSE)
X && (int)(re->startp[0] - line) < pos);
X
X if (wrapped && *o_warn)
X msg("(wrapped)");
X return MARK_AT_LINE(l) + last;
X }
X pos = BLKSIZE;
X }
X
X /* not found */
X msg(*o_wrapscan ? "Not found" : "Hit top without finding RE");
X return MARK_UNSET;
X}
X
eof
if test `wc -c <move2.c` -ne 4445
then
echo move2.c damaged!
fi
fi
if test -f move3.c -a "$1" != -f
then
echo Will not overwrite move3.c
else
echo Extracting move3.c
sed 's/^X//' >move3.c <<\eof
X/* move3.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains movement functions that perform character searches */
X
X#include "config.h"
X#include "vi.h"
X
X#ifndef NO_CHARSEARCH
Xstatic MARK (*prevfwdfn)(); /* function to search in same direction */
Xstatic MARK (*prevrevfn)(); /* function to search in opposite direction */
Xstatic char prev_key; /* sought cvhar from previous [fFtT] */
X
XMARK m__ch(m, cnt, cmd)
X MARK m; /* current position */
X long cnt;
X char cmd; /* command: either ',' or ';' */
X{
X MARK (*tmp)();
X
X if (!prevfwdfn)
X {
X msg("No previous f, F, t, or T command");
X return MARK_UNSET;
X }
X
X if (cmd == ',')
X {
X m = (*prevrevfn)(m, cnt, prev_key);
X
X /* Oops! we didn't want to change the prev*fn vars! */
X tmp = prevfwdfn;
X prevfwdfn = prevrevfn;
X prevrevfn = tmp;
X
X return m;
X }
X else
X {
X return (*prevfwdfn)(m, cnt, prev_key);
X }
X}
X
X/* move forward within this line to next occurrence of key */
XMARK m_fch(m, cnt, key)
X MARK m; /* where to search from */
X long cnt;
X char key; /* what to search for */
X{
X REG char *text;
X
X DEFAULT(1);
X
X prevfwdfn = m_fch;
X prevrevfn = m_Fch;
X prev_key = key;
X
X pfetch(markline(m));
X text = ptext + markidx(m);
X while (cnt-- > 0)
X {
X do
X {
X m++;
X text++;
X } while (*text && *text != key);
X }
X if (!*text)
X {
X return MARK_UNSET;
X }
X return m;
X}
X
X/* move backward within this line to previous occurrence of key */
XMARK m_Fch(m, cnt, key)
X MARK m; /* where to search from */
X long cnt;
X char key; /* what to search for */
X{
X REG char *text;
X
X DEFAULT(1);
X
X prevfwdfn = m_Fch;
X prevrevfn = m_fch;
X prev_key = key;
X
X pfetch(markline(m));
X text = ptext + markidx(m);
X while (cnt-- > 0)
X {
X do
X {
X m--;
X text--;
X } while (text >= ptext && *text != key);
X }
X if (text < ptext)
X {
X return MARK_UNSET;
X }
X return m;
X}
X
X/* move forward within this line almost to next occurrence of key */
XMARK m_tch(m, cnt, key)
X MARK m; /* where to search from */
X long cnt;
X char key; /* what to search for */
X{
X /* skip the adjacent char */
X pfetch(markline(m));
X if (plen <= markidx(m))
X {
X return MARK_UNSET;
X }
X m++;
X
X m = m_fch(m, cnt, key);
X if (m == MARK_UNSET)
X {
X return MARK_UNSET;
X }
X
X prevfwdfn = m_tch;
X prevrevfn = m_Tch;
X
X return m - 1;
X}
X
X/* move backward within this line almost to previous occurrence of key */
XMARK m_Tch(m, cnt, key)
X MARK m; /* where to search from */
X long cnt;
X char key; /* what to search for */
X{
X /* skip the adjacent char */
X if (markidx(m) == 0)
X {
X return MARK_UNSET;
X }
X m--;
X
X m = m_Fch(m, cnt, key);
X if (m == MARK_UNSET)
X {
X return MARK_UNSET;
X }
X
X prevfwdfn = m_Tch;
X prevrevfn = m_tch;
X
X return m + 1;
X}
X#endif
eof
if test `wc -c <move3.c` -ne 2697
then
echo move3.c damaged!
fi
fi
if test -f move4.c -a "$1" != -f
then
echo Will not overwrite move4.c
else
echo Extracting move4.c
sed 's/^X//' >move4.c <<\eof
X/* move4.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains movement functions which are screen-relative */
X
X#include "config.h"
X#include "vi.h"
X
X/* This moves the cursor to a particular row on the screen */
X/*ARGSUSED*/
XMARK m_row(m, cnt, key)
X MARK m; /* the cursor position */
X long cnt; /* the row we'll move to */
X int key; /* the keystroke of this move - H/L/M */
X{
X DEFAULT(1);
X
X /* calculate destination line based on key */
X cnt--;
X switch (key)
X {
X case 'H':
X cnt = topline + cnt;
X break;
X
X case 'M':
X cnt = topline + (LINES - 1) / 2;
X break;
X
X case 'L':
X cnt = botline - cnt;
X break;
X }
X
X /* return the mark of the destination line */
X return MARK_AT_LINE(cnt);
X}
X
X
X/* This function repositions the current line to show on a given row */
X/*ARGSUSED*/
XMARK m_z(m, cnt, key)
X MARK m; /* the cursor */
X long cnt; /* the line number we're repositioning */
X int key; /* key struck after the z */
X{
X long newtop;
X
X /* Which line are we talking about? */
X if (cnt < 0 || cnt > nlines)
X {
X return MARK_UNSET;
X }
X if (cnt)
X {
X m = MARK_AT_LINE(cnt);
X newtop = cnt;
X }
X else
X {
X newtop = markline(m);
X }
X
X /* allow a "window size" number to be entered, but ignore it */
X while (key >= '0' && key <= '9')
X {
X key = getkey(0);
X }
X
X /* figure out which line will have to be at the top of the screen */
X switch (key)
X {
X case '\n':
X#if OSK
X case '\l':
X#else
X case '\r':
X#endif
X case '+':
X break;
X
X case '.':
X case 'z':
X newtop -= LINES / 2;
X break;
X
X case '-':
X newtop -= LINES - 1;
X break;
X
X default:
X return MARK_UNSET;
X }
X
X /* make the new topline take effect */
X if (newtop >= 1)
X {
X topline = newtop;
X }
X else
X {
X topline = 1L;
X }
X mustredraw = TRUE;
X
X /* The cursor doesn't move */
X return m;
X}
X
X
X/* This function scrolls the screen. It does this by calling redraw() with
X * an off-screen line as the argument. It will move the cursor if necessary
X * so that the cursor is on the new screen.
X */
X/*ARGSUSED*/
XMARK m_scroll(m, cnt, key)
X MARK m; /* the cursor position */
X long cnt; /* for some keys: the number of lines to scroll */
X int key; /* keystroke that causes this movement */
X{
X MARK tmp; /* a temporary mark, used as arg to redraw() */
X
X /* adjust cnt, and maybe *o_scroll, depending of key */
X switch (key)
X {
X case ctrl('F'):
X case ctrl('B'):
X DEFAULT(1);
X mustredraw = TRUE;
X cnt = cnt * (LINES - 1) - 1; /* keeps one old line on screen */
X break;
X
X case ctrl('E'):
X case ctrl('Y'):
X DEFAULT(1);
X break;
X
X case ctrl('U'):
X case ctrl('D'):
X if (cnt == 0) /* default */
X {
X cnt = *o_scroll;
X }
X else
X {
X if (cnt > LINES - 1)
X {
X cnt = LINES - 1;
X }
X *o_scroll = cnt;
X }
X break;
X }
X
X /* scroll up or down, depending on key */
X switch (key)
X {
X case ctrl('B'):
X case ctrl('Y'):
X case ctrl('U'):
X cnt = topline - cnt;
X if (cnt < 1L)
X {
X cnt = 1L;
X m = MARK_FIRST;
X }
X tmp = MARK_AT_LINE(cnt) + markidx(m);
X redraw(tmp, FALSE);
X if (markline(m) > botline)
X {
X m = MARK_AT_LINE(botline);
X }
X break;
X
X case ctrl('F'):
X case ctrl('E'):
X case ctrl('D'):
X cnt = botline + cnt;
X if (cnt > nlines)
X {
X cnt = nlines;
X m = MARK_LAST;
X }
X tmp = MARK_AT_LINE(cnt) + markidx(m);
X redraw(tmp, FALSE);
X if (markline(m) < topline)
X {
X m = MARK_AT_LINE(topline);
X }
X break;
X }
X
X /* arrange for ctrl-B and ctrl-F to redraw the smart line */
X if (key == ctrl('B') || key == ctrl('F'))
X {
X changes++;
X
X /* also, erase the statusline. This happens naturally for
X * the scrolling commands, but the paging commands need to
X * explicitly clear the statusline.
X */
X msg("");
X }
X
X return m;
X}
eof
if test `wc -c <move4.c` -ne 3699
then
echo move4.c damaged!
fi
fi
if test -f move5.c -a "$1" != -f
then
echo Will not overwrite move5.c
else
echo Extracting move5.c
sed 's/^X//' >move5.c <<\eof
X/* move5.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains the word-oriented movement functions */
X
X#include <ctype.h>
X#include "config.h"
X#include "vi.h"
X
X#ifndef isascii
X# define isascii(c) !((c) & ~0x7f)
X#endif
X
X
XMARK m_fword(m, cnt, cmd)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X int cmd; /* either 'w' or 'W' */
X{
X REG long l;
X REG char *text;
X REG int i;
X
X DEFAULT(1);
X
X l = markline(m);
X pfetch(l);
X text = ptext + markidx(m);
X while (cnt-- > 0) /* yes, ASSIGNMENT! */
X {
X i = *text++;
X
X if (cmd == 'W')
X {
X /* include any non-whitespace */
X while (i && (!isascii(i) || !isspace(i)))
X {
X i = *text++;
X }
X }
X else if (!isascii(i) || isalnum(i) || i == '_')
X {
X /* include an alphanumeric word */
X while (i && (!isascii(i) || isalnum(i) || i == '_'))
X {
X i = *text++;
X }
X }
X else
X {
X /* include contiguous punctuation */
X while (i && isascii(i) && !isalnum(i) && !isspace(i))
X {
X i = *text++;
X }
X }
X
X /* include trailing whitespace */
X while (!i || isascii(i) && isspace(i))
X {
X /* did we hit the end of this line? */
X if (!i)
X {
X /* move to next line, if there is one */
X l++;
X if (l > nlines)
X {
X return MARK_UNSET;
X }
X pfetch(l);
X text = ptext;
X }
X
X i = *text++;
X }
X text--;
X }
X
X /* construct a MARK for this place */
X m = buildmark(text);
X return m;
X}
X
X
XMARK m_bword(m, cnt, cmd)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X int cmd; /* either 'b' or 'B' */
X{
X REG long l;
X REG char *text;
X
X DEFAULT(1);
X
X l = markline(m);
X pfetch(l);
X text = ptext + markidx(m);
X while (cnt-- > 0) /* yes, ASSIGNMENT! */
X {
X text--;
X
X /* include preceding whitespace */
X while (text < ptext || isascii(*text) && isspace(*text))
X {
X /* did we hit the end of this line? */
X if (text < ptext)
X {
X /* move to preceding line, if there is one */
X l--;
X if (l <= 0)
X {
X return MARK_UNSET;
X }
X pfetch(l);
X text = ptext + plen - 1;
X }
X else
X {
X text--;
X }
X }
X
X if (cmd == 'B')
X {
X /* include any non-whitespace */
X while (text >= ptext && (!isascii(*text) || !isspace(*text)))
X {
X text--;
X }
X }
X else if (!isascii(*text) || isalnum(*text) || *text == '_')
X {
X /* include an alphanumeric word */
X while (text >= ptext && (!isascii(*text) || isalnum(*text) || *text == '_'))
X {
X text--;
X }
X }
X else
X {
X /* include contiguous punctuation */
X while (text >= ptext && isascii(*text) && !isalnum(*text) && !isspace(*text))
X {
X text--;
X }
X }
X text++;
X }
X
X /* construct a MARK for this place */
X m = buildmark(text);
X return m;
X}
X
XMARK m_eword(m, cnt, cmd)
X MARK m; /* movement is relative to this mark */
X long cnt; /* a numeric argument */
X int cmd; /* either 'e' or 'E' */
X{
X REG long l;
X REG char *text;
X REG int i;
X
X DEFAULT(1);
X
X l = markline(m);
X pfetch(l);
X text = ptext + markidx(m);
X while (cnt-- > 0) /* yes, ASSIGNMENT! */
X {
X text++;
X i = *text++;
X
X /* include preceding whitespace */
X while (!i || isascii(i) && isspace(i))
X {
X /* did we hit the end of this line? */
X if (!i)
X {
X /* move to next line, if there is one */
X l++;
X if (l > nlines)
X {
X return MARK_UNSET;
X }
X pfetch(l);
X text = ptext;
X }
X
X i = *text++;
X }
X
X if (cmd == 'E')
X {
X /* include any non-whitespace */
X while (i && (!isascii(i) || !isspace(i)))
X {
X i = *text++;
X }
X }
X else if (!isascii(i) || isalnum(i) || i == '_')
X {
X /* include an alphanumeric word */
X while (i && (!isascii(i) || isalnum(i) || i == '_'))
X {
X i = *text++;
X }
X }
X else
X {
X /* include contiguous punctuation */
X while (i && isascii(i) && !isalnum(i) && !isspace(i))
X {
X i = *text++;
X }
X }
X text -= 2;
X }
X
X /* construct a MARK for this place */
X m = buildmark(text);
X return m;
X}
eof
if test `wc -c <move5.c` -ne 3940
then
echo move5.c damaged!
fi
fi
if test -f opts.c -a "$1" != -f
then
echo Will not overwrite opts.c
else
echo Extracting opts.c
sed 's/^X//' >opts.c <<\eof
X/* opts.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains the code that manages the run-time options -- The
X * values that can be modified via the "set" command.
X */
X
X#include "config.h"
X#include "vi.h"
X#ifndef NULL
X#define NULL (char *)0
X#endif
Xextern char *getenv();
X
X/* maximum width to permit for strings, including ="" */
X#define MAXWIDTH 20
X
X/* These are the default values of all options */
Xchar o_autoindent[1] = {FALSE};
Xchar o_autoprint[1] = {TRUE};
Xchar o_autowrite[1] = {FALSE};
X#ifndef NO_ERRLIST
Xchar o_cc[30] = {CC_COMMAND};
X#endif
X#ifndef NO_CHARATTR
Xchar o_charattr[1] = {FALSE};
X#endif
Xchar o_columns[3] = {80, 32, 255};
X#ifndef NO_DIGRAPH
Xchar o_digraph[1] = {FALSE};
X#endif
Xchar o_directory[30] = TMPDIR;
Xchar o_edcompatible[1] = {FALSE};
Xchar o_errorbells[1] = {TRUE};
Xchar o_exrefresh[1] = {TRUE};
X#ifndef NO_DIGRAPH
Xchar o_flipcase[80]
X# if CS_IBMPC
X = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"}
X# endif
X# if CS_LATIN1
X /* initialized by initopts() */
X# endif
X ;
X#endif
X#ifndef NO_SENTENCE
Xchar o_hideformat[1] = {FALSE};
X#endif
Xchar o_ignorecase[1] = {FALSE};
X#ifndef NO_EXTENSIONS
Xchar o_inputmode[1] = {FALSE};
X#endif
Xchar o_keytime[3] = {2, 0, 5};
Xchar o_keywordprg[80] = {KEYWORDPRG};
Xchar o_lines[3] = {25, 2, 50}; /* More lines? Enlarge kbuf */
Xchar o_list[1] = {FALSE};
X#ifndef NO_MAGIC
Xchar o_magic[1] = {TRUE};
X#endif
X#ifndef NO_ERRLIST
Xchar o_make[30] = {MAKE_COMMAND};
X#endif
X#ifndef NO_MODELINE
Xchar o_modeline[1] = {FALSE};
X#endif
X#ifndef NO_SENTENCE
Xchar o_paragraphs[30] = "PPppIPLPQP";
X#endif
X#if MSDOS
Xchar o_pcbios[1] = {TRUE};
X#endif
Xchar o_readonly[1] = {FALSE};
Xchar o_report[3] = {5, 1, 127};
Xchar o_scroll[3] = {12, 1, 127};
X#ifndef NO_SENTENCE
Xchar o_sections[30] = "NHSHSSSEse";
X#endif
Xchar o_shell[60] = SHELL;
Xchar o_shiftwidth[3] = {8, 1, 255};
X#ifndef NO_SHOWMATCH
Xchar o_showmatch[1] = {FALSE};
X#endif
X#ifndef NO_SHOWMODE
Xchar o_smd[1] = {FALSE};
X#endif
Xchar o_sidescroll[3] = {8, 1, 40};
Xchar o_sync[1] = {NEEDSYNC};
Xchar o_tabstop[3] = {8, 1, 40};
Xchar o_term[30] = "?";
Xchar o_vbell[1] = {TRUE};
Xchar o_warn[1] = {TRUE};
Xchar o_wrapmargin[3] = {0, 0, 255};
Xchar o_wrapscan[1] = {TRUE};
X
X
X/* The following describes the names & types of all options */
X#define BOOL 0
X#define NUM 1
X#define STR 2
X#define SET 0x01 /* this option has had its value altered */
X#define CANSET 0x02 /* this option can be set at any time */
X#define RCSET 0x06 /* this option can be set in a .exrc file only */
X#define MR 0x40 /* does this option affect the way text is displayed? */
Xstruct
X{
X char *name; /* name of an option */
X char *nm; /* short name of an option */
X char type; /* type of an option */
X char flags; /* boolean: has this option been set? */
X char *value; /* value */
X}
X opts[] =
X{
X /* name type flags redraw value */
X { "autoindent", "ai", BOOL, CANSET , o_autoindent },
X { "autoprint", "ap", BOOL, CANSET , o_autoprint },
X { "autowrite", "aw", BOOL, CANSET , o_autowrite },
X#ifndef NO_ERRLIST
X { "cc", "cc", STR, CANSET , o_cc },
X#endif
X#ifndef NO_CHARATTR
X { "charattr", "ca", BOOL, CANSET | MR, o_charattr },
X#endif
X { "columns", "co", NUM, SET , o_columns },
X#ifndef NO_DIGRAPH
X { "digraph", "dig", BOOL, CANSET , o_digraph },
X#endif
X { "directory", "dir", STR, RCSET , o_directory },
X { "edcompatible","ed", BOOL, CANSET , o_edcompatible },
X { "errorbells", "eb", BOOL, CANSET , o_errorbells },
X { "exrefresh", "er", BOOL, CANSET , o_exrefresh },
X#ifndef NO_DIGRAPH
X { "flipcase", "fc", STR, CANSET , o_flipcase },
X#endif
X#ifndef NO_SENTENCE
X { "hideformat", "hf", BOOL, CANSET | MR, o_hideformat },
X#endif
X { "ignorecase", "ic", BOOL, CANSET , o_ignorecase },
X#ifndef NO_EXTENSIONS
X { "inputmode", "im", BOOL, CANSET , o_inputmode },
X#endif
X { "keytime", "kt", NUM, CANSET , o_keytime },
X { "keywordprg", "kp", STR, CANSET , o_keywordprg },
X { "lines", "ls", NUM, SET , o_lines },
X { "list", "li", BOOL, CANSET | MR, o_list },
X#ifndef NO_MAGIC
X { "magic", "ma", BOOL, CANSET , o_magic },
X#endif
X#ifndef NO_ERRLIST
X { "make", "mk", STR, CANSET , o_make },
X#endif
X#ifndef NO_MODELINE
X { "modeline", "ml", BOOL, CANSET , o_modeline },
X#endif
X#ifndef NO_SENTENCE
X { "paragraphs", "pa", STR, CANSET , o_paragraphs },
X#endif
X#if MSDOS
X { "pcbios", "pc", BOOL, SET , o_pcbios },
X#endif
X { "readonly", "ro", BOOL, CANSET , o_readonly },
X { "report", "re", NUM, CANSET , o_report },
X { "scroll", "sc", NUM, CANSET , o_scroll },
X#ifndef NO_SENTENCE
X { "sections", "se", STR, CANSET , o_sections },
X#endif
X { "shell", "sh", STR, CANSET , o_shell },
X#ifndef NO_SHOWMATCH
X { "showmatch", "sm", BOOL, CANSET , o_showmatch },
X#endif
X#ifndef NO_SHOWMODE
X { "showmode", "smd", BOOL, CANSET , o_smd },
X#endif
X { "shiftwidth", "sw", NUM, CANSET , o_shiftwidth },
X { "sidescroll", "ss", NUM, CANSET , o_sidescroll },
X { "sync", "sy", BOOL, CANSET , o_sync },
X { "tabstop", "ts", NUM, CANSET | MR, o_tabstop },
X { "term", "te", STR, SET , o_term },
X { "vbell", "vb", BOOL, CANSET , o_vbell },
X { "warn", "wa", BOOL, CANSET , o_warn },
X { "wrapmargin", "wm", NUM, CANSET , o_wrapmargin },
X { "wrapscan", "ws", BOOL, CANSET , o_wrapscan },
X { NULL, NULL, 0, CANSET, NULL }
X};
X
X
X/* This function initializes certain options from environment variables, etc. */
Xvoid initopts()
X{
X char *val;
X int i;
X
X /* set some stuff from environment variables */
X#if MSDOS
X if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
X#else
X if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
X#endif
X {
X strcpy(o_shell, val);
X }
X
X#if ANY_UNIX
X if (val = getenv("TERM")) /* yes, ASSIGNMENT! */
X {
X strcpy(o_term, val);
X }
X#endif
X#if TOS
X val = "vt52";
X strcpy(o_term, val);
X#endif
X#if MSDOS
X if ((val = getenv("TERM")) /* yes, ASSIGNMENT! */
X && strcmp(val, "pcbios"))
X {
X strcpy(o_term, val);
X o_pcbios[0] = 0;
X }
X else
X {
X strcpy(o_term, "pcbios");
X o_pcbios[0] = 1;
X }
X#endif
X#if MSDOS || TOS
X if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
X || (val = getenv("TEMP")))
X strcpy(o_directory, val);
X#endif
X
X *o_scroll = LINES / 2 - 1;
X
X /* disable the vbell option if we don't know how to do a vbell */
X if (!has_VB)
X {
X for (i = 0; opts[i].value != o_vbell; i++)
X {
X }
X opts[i].flags &= ~CANSET;
X *o_vbell = FALSE;
X }
X
X#ifndef NO_DIGRAPH
X# ifdef CS_LATIN1
X for (i = 0, val = o_flipcase; i < 32; i++)
X {
X /* leave out the multiply/divide symbols */
X if (i == 23)
X continue;
X
X /* add upper/lowercase pair */
X *val++ = i + 0xc0;
X *val++ = i + 0xe0;
X }
X *val = '\0';
X# endif /* CS_LATIN1 */
X#endif /* not NO_DIGRAPH */
X}
X
X/* This function lists the current values of all options */
Xvoid dumpopts(all)
X int all; /* boolean: dump all options, or just set ones? */
X{
X#ifndef NO_OPTCOLS
X int i, j, k;
X char nbuf[4]; /* used for converting numbers to ASCII */
X int widths[5]; /* width of each column, including gap */
X int ncols; /* number of columns */
X int nrows; /* number of options per column */
X int nset; /* number of options to be output */
X int width; /* width of a particular option */
X int todump[50]; /* indicies of options to be dumped */
X
X /* step 1: count the number of set options */
X for (nset = i = 0; opts[i].name; i++)
X {
X if (all || (opts[i].flags & SET))
X {
X todump[nset++] = i;
X }
X }
X
X /* step two: try to use as many columns as possible */
X for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
X {
X /* how many would go in this column? */
X nrows = (nset + ncols - 1) / ncols;
X
X /* figure out the width of each column */
X for (i = 0; i < ncols; i++)
X {
X widths[i] = 0;
X for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
X {
X /* figure out the width of a particular option */
X switch (opts[todump[k]].type)
X {
X case BOOL:
X if (!*opts[todump[k]].value)
X width = 2;
X else
X width = 0;
X break;
X
X case STR:
X width = 3 + strlen(opts[todump[k]].value);
X if (width > MAXWIDTH)
X width = MAXWIDTH;
X break;
X
X case NUM:
X width = 4;
X break;
X }
X width += strlen(opts[todump[k]].name);
X
X /* if this is the widest so far, widen col */
X if (width > widths[i])
X {
X widths[i] = width;
X }
X }
X
X }
X
X /* if the total width is narrow enough, then use it */
X for (width = -2, i = 0; i < ncols; i++)
X {
X width += widths[i] + 2;
X }
X if (width < COLS - 1)
X {
X break;
X }
X }
X
X /* step 3: output the columns */
X nrows = (nset + ncols - 1) / ncols;
X for (i = 0; i < nrows; i++)
X {
X for (j = 0; j < ncols; j++)
X {
X /* if we hit the end of the options, quit */
X k = i + j * nrows;
X if (k >= nset)
X {
X break;
X }
X
X /* output this option's value */
X width = 0;
X switch (opts[todump[k]].type)
X {
X case BOOL:
X if (!*opts[todump[k]].value)
X {
X qaddch('n');
X qaddch('o');
X width = 2;
X }
X qaddstr(opts[todump[k]].name);
X width += strlen(opts[todump[k]].name);
X break;
X
X case NUM:
X sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
X qaddstr(opts[todump[k]].name);
X qaddch('=');
X qaddstr(nbuf);
X width = 4 + strlen(opts[todump[k]].name);
X break;
X
X case STR:
X qaddstr(opts[todump[k]].name);
X qaddch('=');
X qaddch('"');
X strcpy(tmpblk.c, opts[todump[k]].value);
X width = 3 + strlen(tmpblk.c);
X if (width > MAXWIDTH)
X {
X width = MAXWIDTH;
X strcpy(tmpblk.c + MAXWIDTH - 6, "...");
X }
X qaddstr(tmpblk.c);
X qaddch('"');
X width += strlen(opts[todump[k]].name);
X break;
X }
X
X /* pad the field to the correct size */
X if (k + nrows <= nset)
X {
X while (width < widths[j] + 2)
X {
X qaddch(' ');
X width++;
X }
X }
X }
X addch('\n');
X exrefresh();
X }
X#else
X int i;
X int col;
X char nbuf[4];
X
X for (i = col = 0; opts[i].name; i++)
X {
X /* if not set and not all, ignore this option */
X if (!all && !(opts[i].flags & SET))
X {
X continue;
X }
X
X /* align this option in one of the columns */
X if (col > 52)
X {
X addch('\n');
X col = 0;
X }
X else if (col > 26)
X {
X while (col < 52)
X {
X qaddch(' ');
X col++;
X }
X }
X else if (col > 0)
X {
X while (col < 26)
X {
X qaddch(' ');
X col++;
X }
X }
X
X switch (opts[i].type)
X {
X case BOOL:
X if (!*opts[i].value)
X {
X qaddch('n');
X qaddch('o');
X col += 2;
X }
X qaddstr(opts[i].name);
X col += strlen(opts[i].name);
X break;
X
X case NUM:
X sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
X qaddstr(opts[i].name);
X qaddch('=');
X qaddstr(nbuf);
X col += 4 + strlen(opts[i].name);
X break;
X
X case STR:
X qaddstr(opts[i].name);
X qaddch('=');
X qaddch('"');
X qaddstr(opts[i].value);
X qaddch('"');
X col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
X break;
X }
X exrefresh();
X }
X if (col > 0)
X {
X addch('\n');
X exrefresh();
X }
X#endif
X}
X
X#ifndef NO_MKEXRC
X/* This function saves the current configuarion of options to a file */
Xvoid saveopts(fd)
X int fd; /* file descriptor to write to */
X{
X int i;
X char buf[256], *pos;
X
X /* write each set options */
X for (i = 0; opts[i].name; i++)
X {
X /* if unset or unsettable, ignore this option */
X if (!(opts[i].flags & SET) || !(opts[i].flags & CANSET))
X {
X continue;
X }
X
X strcpy(buf, "set ");
X pos = &buf[4];
X switch (opts[i].type)
X {
X case BOOL:
X if (!*opts[i].value)
X {
X *pos++='n';
X *pos++='o';
X }
X strcpy(pos, opts[i].name);
X strcat(pos, "\n");
X break;
X
X case NUM:
X sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
X break;
X
X case STR:
X sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
X break;
X }
X twrite(fd, buf, strlen(buf));
X }
X}
X#endif
X
X
X/* This function changes the values of one or more options. */
Xvoid setopts(assignments)
X char *assignments; /* a string containing option assignments */
X{
X char *name; /* name of variable in assignments */
X char *value; /* value of the variable */
X char *scan; /* used for moving through strings */
X int i, j;
X
X /* for each assignment... */
X for (name = assignments; *name; )
X {
X /* skip whitespace */
X if (*name == ' ' || *name == '\t')
X {
X name++;
X continue;
X }
X
X /* find the value, if any */
X for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++)
X {
X }
X if (*scan == '=')
X {
X *scan++ = '\0';
X if (*scan == '"')
X {
X value = ++scan;
X while (*scan && *scan != '"')
X {
X scan++;
X }
X if (*scan)
X {
X *scan++ = '\0';
X }
X }
X else
X {
X value = scan;
X while (*scan && *scan != ' ' && *scan != '\t')
X {
X scan++;
X }
X if (*scan)
X {
X *scan++ = '\0';
X }
X }
X }
X else
X {
X if (*scan)
X {
X *scan++ = '\0';
X }
X value = NULL;
X if (name[0] == 'n' && name[1] == 'o')
X {
X name += 2;
X }
X }
X
X /* find the variable */
X for (i = 0;
X opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
X i++)
X {
X }
X
X /* change the variable */
X if (!opts[i].name)
X {
X msg("invalid option name \"%s\"", name);
X }
X else if ((opts[i].flags & CANSET) != CANSET)
X {
X msg("option \"%s\" can't be altered", name);
X }
X else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
X {
X msg("option \"%s\" can only be set in a %s file", name, EXRC);
X }
X else if (value)
X {
X switch (opts[i].type)
X {
X case BOOL:
X msg("option \"[no]%s\" is boolean", name);
X break;
X
X case NUM:
X j = atoi(value);
X if (j == 0 && *value != '0')
X {
X msg("option \"%s\" must have a numeric value", name);
X }
X else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
X {
X msg("option \"%s\" must have a value between %d and %d",
X name, opts[i].value[1], opts[i].value[2] & 0xff);
X }
X else
X {
X *opts[i].value = atoi(value);
X opts[i].flags |= SET;
X }
X break;
X
X case STR:
X strcpy(opts[i].value, value);
X opts[i].flags |= SET;
X break;
X }
X if (opts[i].flags & MR)
X {
X mustredraw = TRUE;
X }
X }
X else /* valid option, no value */
X {
X if (opts[i].type == BOOL)
X {
X *opts[i].value = (name[-1] != 'o');
X opts[i].flags |= SET;
X if (opts[i].flags & MR)
X {
X mustredraw = TRUE;
X }
X }
X else
X {
X msg("option \"%s\" must be given a value", name);
X }
X }
X
X /* move on to the next option */
X name = scan;
X }
X
X /* special processing ... */
X
X /* if "readonly" then set the READONLY flag for this file */
X if (*o_readonly)
X {
X setflag(file, READONLY);
X }
X}
eof
if test `wc -c <opts.c` -ne 14362
then
echo opts.c damaged!
fi
fi
if test -f recycle.c -a "$1" != -f
then
echo Will not overwrite recycle.c
else
echo Extracting recycle.c
sed 's/^X//' >recycle.c <<\eof
X/* recycle.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains the functions perform garbage collection and allocate
X * reusable blocks.
X */
X
X#include "config.h"
X#include "vi.h"
X
X#ifndef NO_RECYCLE
X/* this whole file would have be skipped if NO_RECYCLE is defined */
X
Xextern long lseek();
X
X#define BTST(bitno, byte) ((byte) & (1 << (bitno)))
X#define BSET(bitno, byte) ((byte) |= (1 << (bitno)))
X#define BCLR(bitno, byte) ((byte) &= ~(1 << (bitno)))
X
X#define TST(blkno) ((blkno) < MAXBIT ? BTST((blkno) & 7, bitmap[(blkno) >> 3]) : 1)
X#define SET(blkno) if ((blkno) < MAXBIT) BSET((blkno) & 7, bitmap[(blkno) >> 3])
X#define CLR(blkno) if ((blkno) < MAXBIT) BCLR((blkno) & 7, bitmap[(blkno) >> 3])
X
X/* bitmap of free blocks in first 4096k of tmp file */
Xstatic unsigned char bitmap[512];
X#define MAXBIT (sizeof bitmap << 3)
X
X/* this function locates all free blocks in the current tmp file */
Xvoid garbage()
X{
X int i;
X BLK oldhdr;
X
X /* start by assuming every block is free */
X for (i = 0; i < sizeof bitmap; i++)
X {
X bitmap[i] = 255;
X }
X
X /* header block isn't free */
X#ifndef lint
X CLR(0);
X#endif
X
X /* blocks needed for current hdr aren't free */
X for (i = 1; i < MAXBLKS; i++)
X {
X CLR(hdr.n[i]);
X }
X
X /* blocks needed for undo version aren't free */
X lseek(tmpfd, 0L, 0);
X if (read(tmpfd, &oldhdr, (unsigned)sizeof oldhdr) != sizeof oldhdr)
X {
X msg("garbage() failed to read oldhdr??");
X for (i = 0; i < sizeof bitmap; i++)
X {
X bitmap[i] = 0;
X }
X return;
X }
X for (i = 1; i < MAXBLKS; i++)
X {
X CLR(oldhdr.n[i]);
X }
X
X /* blocks needed for cut buffers aren't free */
X for (i = cutneeds(&oldhdr) - 1; i >= 0; i--)
X {
X CLR(oldhdr.n[i]);
X }
X}
X
X/* This function allocates the first available block in the tmp file */
Xlong allocate()
X{
X int i;
X long offset;
X
X /* search for the first byte with a free bit set */
X for (i = 0; i < sizeof bitmap && bitmap[i] == 0; i++)
X {
X }
X
X /* if we hit the end of the bitmap, return the end of the file */
X if (i == sizeof bitmap)
X {
X offset = lseek(tmpfd, 0L, 2);
X }
X else /* compute the offset for the free block */
X {
X for (i <<= 3; TST(i) == 0; i++)
X {
X }
X offset = (long)i * (long)BLKSIZE;
X
X /* mark the block as "allocated" */
X CLR(i);
X }
X
X return offset;
X}
X
X#endif
eof
if test `wc -c <recycle.c` -ne 2306
then
echo recycle.c damaged!
fi
fi
if test -f redraw.c -a "$1" != -f
then
echo Will not overwrite redraw.c
else
echo Extracting redraw.c
sed 's/^X//' >redraw.c <<\eof
X/* redraw.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains functions that draw text on the screen. The major entry
X * points are:
X * redrawrange() - called from modify.c to give hints about what parts
X * of the screen need to be redrawn.
X * redraw() - redraws the screen (or part of it) and positions
X * the cursor where it belongs.
X * idx2col() - converts a markidx() value to a logical column number.
X */
X
X#include "config.h"
X#include "vi.h"
X
X/* This variable contains the line number that smartdrawtext() knows best */
Xstatic long smartlno;
X
X/* This function remebers where changes were made, so that the screen can be
X * redraw in a more efficient manner.
X */
Xstatic long redrawafter; /* line# of first line that must be redrawn */
Xstatic long preredraw; /* line# of last line changed, before change */
Xstatic long postredraw; /* line# of last line changed, after change */
Xvoid redrawrange(after, pre, post)
X long after; /* lower bound of redrawafter */
X long pre; /* upper bound of preredraw */
X long post; /* upper bound of postredraw */
X{
X if (after == redrawafter)
X {
X /* multiple insertions/deletions at the same place -- combine
X * them
X */
X preredraw -= (post - pre);
X if (postredraw < post)
X {
X preredraw += (post - postredraw);
X postredraw = post;
X }
X if (redrawafter > preredraw)
X {
X redrawafter = preredraw;
X }
X if (redrawafter < 1L)
X {
X redrawafter = 0L;
X preredraw = postredraw = INFINITY;
X }
X }
X else if (postredraw > 0L)
X {
X /* multiple changes in different places -- redraw everything
X * after "after".
X */
X postredraw = preredraw = INFINITY;
X if (after < redrawafter)
X redrawafter = after;
X }
X else
X {
X /* first change */
X redrawafter = after;
X preredraw = pre;
X postredraw = post;
X }
X}
X
X
X#ifndef NO_CHARATTR
X/* see if a given line uses character attribute strings */
Xstatic int hasattr(lno, text)
X long lno; /* the line# of the cursor */
X REG char *text; /* the text of the line, from fetchline */
X{
X static long plno; /* previous line number */
X static long chgs; /* previous value of changes counter */
X static int panswer;/* previous answer */
X char *scan;
X
X /* if charattr is off, then the answer is "no, it doesn't" */
X if (!*o_charattr)
X {
X chgs = 0; /* <- forces us to check if charattr is later set */
X return FALSE;
X }
X
X /* if we already know the answer, return it... */
X if (lno == plno && chgs == changes)
X {
X return panswer;
X }
X
X /* get the line & look for "\fX" */
X if (!text[0] || !text[1] || !text[2])
X {
X panswer = FALSE;
X }
X else
X {
X for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++)
X {
X }
X panswer = (scan[2] != '\0');
X }
X
X /* save the results */
X plno = lno;
X chgs = changes;
X
X /* return the results */
X return panswer;
X}
X#endif
X
X
X
X/* This function converts a MARK to a column number. It doesn't automatically
X * adjust for leftcol; that must be done by the calling function
X */
Xint idx2col(curs, text, inputting)
X MARK curs; /* the line# & index# of the cursor */
X REG char *text; /* the text of the line, from fetchline */
X int inputting; /* boolean: called from input() ? */
X{
X static MARK pcursor;/* previous cursor, for possible shortcut */
X static MARK pcol; /* column number for pcol */
X static long chgs; /* previous value of changes counter */
X REG int col; /* used to count column numbers */
X REG int idx; /* used to count down the index */
X REG int i;
X
X /* for now, assume we have to start counting at the left edge */
X col = 0;
X idx = markidx(curs);
X
X /* if the file hasn't changed & line number is the same & it has no
X * embedded character attribute strings, can we do shortcuts?
X */
X if (chgs == changes
X && !((curs ^ pcursor) & ~(BLKSIZE - 1))
X#ifndef NO_CHARATTR
X && !hasattr(markline(curs), text)
X#endif
X )
X {
X /* no movement? */
X if (curs == pcursor)
X {
X /* return the column of the char; for tabs, return its last column */
X if (text[idx] == '\t' && !inputting && !*o_list)
X {
X return pcol + *o_tabstop - (pcol % *o_tabstop) - 1;
X }
X else
X {
X return pcol;
X }
X }
X
X /* movement to right? */
X if (curs > pcursor)
X {
X /* start counting from previous place */
X col = pcol;
X idx = markidx(curs) - markidx(pcursor);
X text += markidx(pcursor);
X }
X }
X
X /* count over to the char after the idx position */
X while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */
X {
X if (i == '\t' && !*o_list)
X {
X col += *o_tabstop;
X col -= col % *o_tabstop;
X }
X else if (i >= '\0' && i < ' ' || i == '\177')
X {
X col += 2;
X }
X#ifndef NO_CHARATTR
X else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
X {
X text += 2; /* plus one more at bottom of loop */
X idx -= 2;
X }
X#endif
X else
X {
X col++;
X }
X text++;
X idx--;
X }
X
X /* save stuff to speed next call */
X pcursor = curs;
X pcol = col;
X chgs = changes;
X
X /* return the column of the char; for tabs, return its last column */
X if (*text == '\t' && !inputting && !*o_list)
X {
X return col + *o_tabstop - (col % *o_tabstop) - 1;
X }
X else
X {
X return col;
X }
X}
X
X
X/* This function is similar to idx2col except that it takes care of sideways
X * scrolling - for the given line, at least.
X */
Xint mark2phys(m, text, inputting)
X MARK m; /* a mark to convert */
X char *text; /* the line that m refers to */
X int inputting; /* boolean: caled from input() ? */
X{
X int i;
X
X i = idx2col(m, text, inputting);
X while (i < leftcol)
X {
X leftcol -= *o_sidescroll;
X mustredraw = TRUE;
X redrawrange(1L, INFINITY, INFINITY);
X qaddch('\r');
X /* drawtext(text); */
X }
X while (i > rightcol)
X {
X leftcol += *o_sidescroll;
X mustredraw = TRUE;
X redrawrange(1L, INFINITY, INFINITY);
X qaddch('\r');
X /* drawtext(text); */
X }
X physcol = i - leftcol;
X physrow = markline(m) - topline;
X
X return physcol;
X}
X
X/* This function draws a single line of text on the screen. The screen's
X * cursor is assumed to be located at the leftmost column of the appropriate
X * row.
X */
Xstatic void drawtext(text, clr)
X REG char *text; /* the text to draw */
X int clr; /* boolean: do a clrtoeol? */
X{
X REG int col; /* column number */
X REG int i;
X REG int tabstop; /* *o_tabstop */
X REG int limitcol; /* leftcol or leftcol + COLS */
X int abnormal; /* boolean: charattr != A_NORMAL? */
X
X#ifndef NO_SENTENCE
X /* if we're hiding format lines, and this is one of them, then hide it */
X if (*o_hideformat && *text == '.')
X {
X clrtoeol();
X#if OSK
X qaddch('\l');
X#else
X qaddch('\n');
X#endif
X return;
X }
X#endif
X
X /* move some things into registers... */
X limitcol = leftcol;
X tabstop = *o_tabstop;
X abnormal = FALSE;
X
X#ifndef CRUNCH
X if (clr)
X clrtoeol();
X#endif
X /* skip stuff that was scrolled off left edge */
X for (col = 0;
X (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
X text++)
X {
X if (i == '\t' && !*o_list)
X {
X col = col + tabstop - (col % tabstop);
X }
X else if (i >= 0 && i < ' ' || i == '\177')
X {
X col += 2;
X }
X#ifndef NO_CHARATTR
X else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
X {
X text += 2; /* plus one more as part of "for" loop */
X
X /* since this attribute might carry over, we need it */
X switch (*text)
X {
X case 'R':
X case 'P':
X attrset(A_NORMAL);
X abnormal = FALSE;
X break;
X
X case 'B':
X attrset(A_BOLD);
X abnormal = TRUE;
X break;
X
X case 'U':
X attrset(A_UNDERLINE);
X abnormal = TRUE;
X break;
X
X case 'I':
X attrset(A_ALTCHARSET);
X abnormal = TRUE;
X break;
X }
X }
X#endif
X else
X {
X col++;
X }
X }
X
X /* adjust for control char that was partially visible */
X while (col > limitcol)
X {
X qaddch(' ');
X limitcol++;
X }
X
X /* now for the visible characters */
X for (limitcol = leftcol + COLS;
X (i = *text) && col < limitcol;
X text++)
X {
X if (i == '\t' && !*o_list)
X {
X i = col + tabstop - (col % tabstop);
X if (i < limitcol)
X {
X#ifdef CRUNCH
X if (!clr && has_PT && !((i - leftcol) & 7))
X#else
X if (has_PT && !((i - leftcol) & 7))
X#endif
X {
X do
X {
X qaddch('\t');
X col += 8; /* not exact! */
X } while (col < i);
X col = i; /* NOW it is exact */
X }
X else
X {
X do
X {
X qaddch(' ');
X col++;
X } while (col < i);
X }
X }
X else /* tab ending after screen? next line! */
X {
X col = limitcol;
X if (has_AM)
X {
X addch('\n'); /* GB */
X }
X }
X }
X else if (i >= 0 && i < ' ' || i == '\177')
X {
X col += 2;
X qaddch('^');
X if (col <= limitcol)
X {
X qaddch(i ^ '@');
X }
X }
X#ifndef NO_CHARATTR
X else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
X {
X text += 2; /* plus one more as part of "for" loop */
X switch (*text)
X {
X case 'R':
X case 'P':
X attrset(A_NORMAL);
X abnormal = FALSE;
X break;
X
X case 'B':
X attrset(A_BOLD);
X abnormal = TRUE;
X break;
X
X case 'U':
X attrset(A_UNDERLINE);
X abnormal = TRUE;
X break;
X
X case 'I':
X attrset(A_ALTCHARSET);
X abnormal = TRUE;
X break;
X }
X }
X#endif
X else
X {
X col++;
X qaddch(i);
X }
X }
X
X /* get ready for the next line */
X#ifndef NO_CHARATTR
X if (abnormal)
X {
X attrset(A_NORMAL);
X }
X#endif
X if (*o_list && col < limitcol)
X {
X qaddch('$');
X col++;
X }
X#ifdef CRUNCH
X if (clr && col < limitcol)
X {
X clrtoeol();
X }
X#endif
X if (!has_AM || col < limitcol)
X {
X addch('\n');
X }
X}
X
X
X#ifndef CRUNCH
Xstatic void nudgecursor(same, scan, new, lno)
X int same; /* number of chars to be skipped over */
X char *scan; /* where the same chars end */
X char *new; /* where the visible part of the line starts */
X long lno; /* line number of this line */
X{
X if (same > 0)
X {
X if (same < 5)
X {
X /* move the cursor by overwriting */
X while (same > 0)
X {
X qaddch(scan[-same]);
X same--;
X }
X }
X else
X {
X /* move the cursor by calling move() */
X move((int)(lno - topline), (int)(scan - new));
X }
X }
X}
X#endif /* not CRUNCH */
X
X/* This function draws a single line of text on the screen, possibly with
X * some cursor optimization. The cursor is repositioned before drawing
X * begins, so its position before doesn't really matter.
X */
Xstatic void smartdrawtext(text, lno)
X REG char *text; /* the text to draw */
X long lno; /* line number of the text */
X{
X#ifdef CRUNCH
X move((int)(lno - topline), 0);
X drawtext(text, TRUE);
X#else /* not CRUNCH */
X static char old[256]; /* how the line looked last time */
X char new[256]; /* how it looks now */
X char *build; /* used to put chars into new[] */
X char *scan; /* used for moving thru new[] or old[] */
X char *end; /* last non-blank changed char */
X char *shift; /* used to insert/delete chars */
X int same; /* length of a run of unchanged chars */
X int limitcol;
X int col;
X int i;
X
X# ifndef NO_CHARATTR
X /* if this line has attributes, do it the dumb way instead */
X if (hasattr(lno, text))
X {
X move((int)(lno - topline), 0);
X drawtext(text, TRUE);
X return;
X }
X# endif
X# ifndef NO_SENTENCE
X /* if this line is a format line, & we're hiding format lines, then
X * let the dumb drawtext() function handle it
X */
X if (*o_hideformat && *text == '.')
X {
X move((int)(lno - topline), 0);
X drawtext(text, TRUE);
X return;
X }
X# endif
X
X /* skip stuff that was scrolled off left edge */
X limitcol = leftcol;
X for (col = 0;
X (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
X text++)
X {
X if (i == '\t' && !*o_list)
X {
X col = col + *o_tabstop - (col % *o_tabstop);
X }
X else if (i >= 0 && i < ' ' || i == '\177')
X {
X col += 2;
X }
X else
X {
X col++;
X }
X }
X
X /* adjust for control char that was partially visible */
X build = new;
X while (col > limitcol)
X {
X *build++ = ' ';
X limitcol++;
X }
X
X /* now for the visible characters */
X for (limitcol = leftcol + COLS;
X (i = *text) && col < limitcol;
X text++)
X {
X if (i == '\t' && !*o_list)
X {
X i = col + *o_tabstop - (col % *o_tabstop);
X while (col < i && col < limitcol)
X {
X *build++ = ' ';
X col++;
X }
X }
X else if (i >= 0 && i < ' ' || i == '\177')
X {
X col += 2;
X *build++ = '^';
X if (col <= limitcol)
X {
X *build++ = (i ^ '@');
X }
X }
X else
X {
X col++;
X *build++ = i;
X }
X }
X if (col < limitcol && *o_list)
X {
X *build++ = '$';
X col++;
X }
X end = build;
X while (col < limitcol)
X {
X *build++ = ' ';
X col++;
X }
X
X /* locate the last non-blank character */
X while (end > new && end[-1] == ' ')
X {
X end--;
X }
X
X /* can we optimize the displaying of this line? */
X if (lno != smartlno)
X {
X /* nope, can't optimize - different line */
X move((int)(lno - topline), 0);
X for (scan = new, build = old; scan < end; )
X {
X qaddch(*scan);
X *build++ = *scan++;
X }
X if (end < new + COLS)
X {
X clrtoeol();
X while (build < old + COLS)
X {
X *build++ = ' ';
X }
X }
X smartlno = lno;
X return;
X }
X
X /* skip any initial unchanged characters */
X for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
X {
X }
X move((int)(lno - topline), (int)(scan - new));
X
X /* The in-between characters must be changed */
X same = 0;
X while (scan < end)
X {
X /* is this character a match? */
X if (scan[0] == build[0])
X {
X same++;
X }
X else /* do we want to insert? */
X if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM))
X {
X nudgecursor(same, scan, new, lno);
X same = 0;
X
X insch(*scan);
X for (shift = old + COLS; --shift > build; )
X {
X shift[0] = shift[-1];
X }
X *build = *scan;
X }
X else /* do we want to delete? */
X if (build < old + COLS - 1 && scan[0] == build[1] && has_DC)
X {
X nudgecursor(same, scan, new, lno);
X same = 0;
X
X delch();
X same++;
X for (shift = build; shift < old + COLS - 1; shift++)
X {
X shift[0] = shift[1];
X }
X *shift = ' ';
X }
X else /* we must overwrite */
X {
X nudgecursor(same, scan, new, lno);
X same = 0;
X
X addch(*scan);
X *build = *scan;
X }
X
X build++;
X scan++;
X }
X
X /* maybe clear to EOL */
X while (build < old + COLS && *build == ' ')
X {
X build++;
X }
X if (build < old + COLS)
X {
X nudgecursor(same, scan, new, lno);
X same = 0;
X
X clrtoeol();
X while (build < old + COLS)
X {
X *build++ = ' ';
X }
X }
X#endif /* not CRUNCH */
X}
X
X
X/* This function is used in visual mode for drawing the screen (or just parts
X * of the screen, if that's all thats needed). It also takes care of
X * scrolling.
X */
Xvoid redraw(curs, inputting)
X MARK curs; /* where to leave the screen's cursor */
X int inputting; /* boolean: being called from input() ? */
X{
X char *text; /* a line of text to display */
X static long chgs; /* previous changes level */
X long l;
X int i;
X
X /* if curs == MARK_UNSET, then we should reset internal vars */
X if (curs == MARK_UNSET)
X {
X if (topline < 1 || topline > nlines)
X {
X topline = 1L;
X }
X else
X {
X move(LINES - 1, 0);
X clrtoeol();
X }
X leftcol = 0;
X mustredraw = TRUE;
X redrawafter = INFINITY;
X preredraw = 0L;
X postredraw = 0L;
X chgs = 0;
X smartlno = 0L;
X return;
X }
X
X /* figure out which column the cursor will be in */
X l = markline(curs);
X text = fetchline(l);
X mark2phys(curs, text, inputting);
X
X /* adjust topline, if necessary, to get the cursor on the screen */
X if (l >= topline && l <= botline)
X {
X /* it is on the screen already */
X
X /* if the file was changed but !mustredraw, then redraw line */
X if (chgs != changes && !mustredraw)
X {
X smartdrawtext(text, l);
X }
X }
X else if (l < topline && l > topline - LINES && (has_SR || has_AL))
X {
X /* near top - scroll down */
X if (!mustredraw)
X {
X move(0,0);
X while (l < topline)
X {
X topline--;
X if (has_SR)
X {
X do_SR();
X }
X else
X {
X insertln();
X }
X text = fetchline(topline);
X drawtext(text, FALSE);
X do_UP();
X }
X
X /* blank out the last line */
X move(LINES - 1, 0);
X clrtoeol();
X }
X else
X {
X topline = l;
X redrawafter = INFINITY;
X preredraw = 0L;
X postredraw = 0L;
X }
X }
X else if (l > topline && l < botline + LINES)
X {
X /* near bottom -- scroll up */
X if (!mustredraw
X#if 1
X || redrawafter == preredraw && preredraw == botline && postredraw == l
X#endif
X )
X {
X move(LINES - 1,0);
X clrtoeol();
X while (l > botline)
X {
X topline++; /* <-- also adjusts botline */
X text = fetchline(botline);
X drawtext(text, FALSE);
X }
X mustredraw = FALSE;
X }
X else
X {
X topline = l - (LINES - 2);
X redrawafter = INFINITY;
X preredraw = 0L;
X postredraw = 0L;
X }
X }
X else
X {
X /* distant line - center it & force a redraw */
X topline = l - (LINES / 2) - 1;
X if (topline < 1)
X {
X topline = 1;
X }
X mustredraw = TRUE;
X redrawafter = INFINITY;
X preredraw = 0L;
X postredraw = 0L;
X }
X
X /* Now... do we really have to redraw? */
X if (mustredraw)
X {
X /* If redrawfter (and friends) aren't set, assume we should
X * redraw everything.
X */
X if (redrawafter == INFINITY)
X {
X redrawafter = 0L;
X preredraw = postredraw = INFINITY;
X }
X
X /* adjust smartlno to correspond with inserted/deleted lines */
X if (smartlno >= redrawafter)
X {
X if (smartlno < preredraw)
X {
X smartlno = 0L;
X }
X else
X {
X smartlno += (postredraw - preredraw);
X }
X }
X
X /* should we insert some lines into the screen? */
X if (preredraw < postredraw && preredraw <= botline)
X {
X /* lines were inserted into the file */
X
X /* decide where insertion should start */
X if (preredraw < topline)
X {
X l = topline;
X }
X else
X {
X l = preredraw;
X }
X
X /* insert the lines... maybe */
X if (l + postredraw - preredraw > botline || !has_AL)
X {
X /* Whoa! a whole screen full - just redraw */
X preredraw = postredraw = INFINITY;
X }
X else
X {
X /* really insert 'em */
X move((int)(l - topline), 0);
X for (i = postredraw - preredraw; i > 0; i--)
X {
X insertln();
X }
X
X /* NOTE: the contents of those lines will be
X * drawn as part of the regular redraw loop.
X */
X
X /* clear the last line */
X move(LINES - 1, 0);
X clrtoeol();
X }
X }
X
X /* do we want to delete some lines from the screen? */
X if (preredraw > postredraw && postredraw <= botline)
X {
X if (preredraw > botline || !has_DL)
X {
X postredraw = preredraw = INFINITY;
X }
X else /* we'd best delete some lines from the screen */
X {
X /* clear the last line, so it doesn't look
X * ugly as it gets pulled up into the screen
X */
X move(LINES - 1, 0);
X clrtoeol();
X
X /* delete the lines */
X move((int)(postredraw - topline), 0);
X for (l = postredraw;
X l < preredraw && l <= botline;
X l++)
X {
X deleteln();
X }
X
X /* draw the lines that are now newly visible
X * at the bottom of the screen
X */
X i = LINES - 1 + (postredraw - preredraw);
X move(i, 0);
X for (l = topline + i; l <= botline; l++)
X {
X /* clear this line */
X clrtoeol();
X
X /* draw the line, or ~ for non-lines */
X if (l <= nlines)
X {
X text = fetchline(l);
X drawtext(text, FALSE);
X }
X else
X {
X addstr("~\n");
X }
X }
X }
X }
X
X /* redraw the current line */
X l = markline(curs);
X pfetch(l);
X smartdrawtext(ptext, l);
X
X /* decide where we should start redrawing from */
X if (redrawafter < topline)
X {
X l = topline;
X }
X else
X {
X l = redrawafter;
X }
X move((int)(l - topline), 0);
X
X /* draw the other lines */
X for (; l <= botline && l < postredraw; l++)
X {
X /* we already drew the current line, so skip it now */
X if (l == smartlno)
X {
X#if OSK
X qaddch('\l');
X#else
X qaddch('\n');
X#endif
X continue;
X }
X
X /* draw the line, or ~ for non-lines */
X if (l <= nlines)
X {
X text = fetchline(l);
X drawtext(text, TRUE);
X }
X else
X {
X qaddch('~');
X clrtoeol();
X addch('\n');
X }
X }
X
X mustredraw = FALSE;
X }
X
X /* force total (non-partial) redraw next time if not set */
X redrawafter = INFINITY;
X preredraw = 0L;
X postredraw = 0L;
X
X /* move the cursor to where it belongs */
X move((int)(markline(curs) - topline), physcol);
X wqrefresh(stdscr);
X
X chgs = changes;
X}
eof
if test `wc -c <redraw.c` -ne 19816
then
echo redraw.c damaged!
fi
fi
exit 0
-------------------------------------------------------------------------------
Steve Kirkendall kirkenda at cs.pdx.edu Grad student at Portland State U.
More information about the Alt.sources
mailing list