elvis 1.3 - a clone of vi/ex, part 4 of 6
Steve Kirkendall
kirkenda at eecs.cs.pdx.edu
Sat Aug 25 03:57:13 AEST 1990
Archive-name: elvis1.3/part4
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# modify.c
# move1.c
# move2.c
# move3.c
# move4.c
# move5.c
# nomagic.c
# opts.c
# pc.c
# recycle.c
# redraw.c
# This archive created: Fri Aug 24 10:29:57 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'modify.c'
then
echo shar: "will not over-write existing file 'modify.c'"
else
cat << \SHAR_EOF > 'modify.c'
/* modify.c */
/* This file contains the low-level file modification functions:
* delete(frommark, tomark) - removes line or portions of lines
* add(frommark, text) - inserts new text
* change(frommark, tomark, text) - delete, then add
*/
#include "config.h"
#include "vi.h"
/* delete a range of text from the file */
delete(frommark, tomark)
MARK frommark; /* first char to be deleted */
MARK tomark; /* AFTER last char to be deleted */
{
int i; /* used to move thru logical blocks */
register char *scan; /* used to scan thru text of the blk */
register char *cpy; /* used when copying chars */
BLK *blk; /* a text block */
long l; /* a line number */
MARK m; /* a traveling version of frommark */
/* if not deleting anything, quit now */
if (frommark == tomark)
{
return;
}
/* This is a change */
changes++;
/* if this is a multi-line change, then we'll have to redraw */
if (markline(frommark) != markline(tomark))
{
mustredraw = TRUE;
redrawrange(markline(frommark), markline(tomark), markline(frommark));
}
/* adjust marks 'a through 'z and '' as needed */
l = markline(tomark);
for (i = 0; i < NMARKS; i++)
{
if (mark[i] < frommark)
{
continue;
}
else if (mark[i] < tomark)
{
mark[i] = MARK_UNSET;
}
else if (markline(mark[i]) == l)
{
if (markline(frommark) == l)
{
mark[i] -= markidx(tomark) - markidx(frommark);
}
else
{
mark[i] -= markidx(tomark);
}
}
else
{
mark[i] -= MARK_AT_LINE(l - markline(frommark));
}
}
/* Reporting... */
if (markidx(frommark) == 0 && markidx(tomark) == 0)
{
rptlines = markline(tomark) - markline(frommark);
rptlabel = "deleted";
}
/* find the block containing frommark */
l = markline(frommark);
for (i = 1; lnum[i] < l; i++)
{
}
/* process each affected block... */
for (m = frommark;
m < tomark && lnum[i] < INFINITY;
m = MARK_AT_LINE(lnum[i - 1] + 1))
{
/* fetch the block */
blk = blkget(i);
/* find the mark in the block */
scan = blk->c;
for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
{
while (*scan++ != '\n')
{
}
}
scan += markidx(m);
/* figure out where the changes to this block end */
if (markline(tomark) > lnum[i])
{
cpy = blk->c + BLKSIZE;
}
else if (markline(tomark) == markline(m))
{
cpy = scan - markidx(m) + markidx(tomark);
}
else
{
cpy = scan;
for (l = markline(tomark) - markline(m);
l > 0;
l--)
{
while (*cpy++ != '\n')
{
}
}
cpy += markidx(tomark);
}
/* delete the stuff by moving chars within this block */
while (cpy < blk->c + BLKSIZE)
{
*scan++ = *cpy++;
}
while (scan < blk->c + BLKSIZE)
{
*scan++ = '\0';
}
/* adjust tomark to allow for lines deleted from this block */
tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
/* if this block isn't empty now, then advance i */
if (*blk->c)
{
i++;
}
/* the buffer has changed. Update hdr and lnum. */
blkdirty(blk);
}
/* must have at least 1 line */
if (nlines == 0)
{
blk = blkadd(1);
blk->c[0] = '\n';
blkdirty(blk);
cursor = MARK_FIRST;
}
}
/* add some text at a specific place in the file */
add(atmark, newtext)
MARK atmark; /* where to insert the new text */
char *newtext; /* NUL-terminated string to insert */
{
register char *scan; /* used to move through string */
register char *build; /* used while copying chars */
int addlines; /* number of lines we're adding */
int lastpart; /* size of last partial line */
BLK *blk; /* the block to be modified */
int blkno; /* the logical block# of (*blk) */
register char *newptr; /* where new text starts in blk */
BLK buf; /* holds chars from orig blk */
BLK linebuf; /* holds part of line that didn't fit */
BLK *following; /* the BLK following the last BLK */
int i;
long l;
/* if not adding anything, return now */
if (!*newtext)
{
return;
}
/* This is a change */
changes++;
/* count the number of lines in the new text */
for (scan = newtext, lastpart = addlines = 0; *scan; )
{
if (*scan++ == '\n')
{
addlines++;
lastpart = 0;
}
else
{
lastpart++;
}
}
/* Reporting... */
if (lastpart == 0 && markidx(atmark) == 0)
{
rptlines = addlines;
rptlabel = "added";
}
/* extract the line# from atmark */
l = markline(atmark);
/* if more than 0 lines, then we'll have to redraw the screen */
if (addlines > 0)
{
mustredraw = TRUE;
if (markidx(atmark) == 0)
{
redrawrange(l, l, l + addlines);
}
else
{
/* make sure the last line gets redrawn -- it was
* split, so its appearance has changed
*/
redrawrange(l, l + 1L, l + addlines + 1L);
}
}
/* adjust marks 'a through 'z and '' as needed */
for (i = 0; i < NMARKS; i++)
{
if (mark[i] < atmark)
{
continue;
}
else if (markline(mark[i]) > l)
{
mark[i] += MARK_AT_LINE(addlines);
}
else
{
mark[i] += MARK_AT_LINE(addlines) + lastpart;
}
}
/* get the block to be modified */
for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
{
}
blk = blkget(blkno);
buf = *blk;
/* figure out where the new text starts */
for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1;
l > 0;
l--)
{
while (*newptr++ != '\n')
{
}
}
newptr += markidx(atmark);
/* keep start of old block */
build = blk->c + (newptr - buf.c);
/* fill this block (or blocks) from the newtext string */
while (*newtext)
{
while (*newtext && build < blk->c + BLKSIZE - 1)
{
*build++ = *newtext++;
}
if (*newtext)
{
/* save the excess */
for (scan = linebuf.c + BLKSIZE;
build > blk->c && build[-1] != '\n';
)
{
*--scan = *--build;
}
/* write the block */
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
/* add another block */
blkno++;
blk = blkadd(blkno);
/* copy in the excess from last time */
for (build = blk->c; scan < linebuf.c + BLKSIZE; )
{
*build++ = *scan++;
}
}
}
/* fill this block(s) from remainder of orig block */
while (newptr < buf.c + BLKSIZE && *newptr)
{
while (newptr < buf.c + BLKSIZE
&& *newptr
&& build < blk->c + BLKSIZE - 1)
{
*build++ = *newptr++;
}
if (newptr < buf.c + BLKSIZE && *newptr)
{
/* save the excess */
for (scan = linebuf.c + BLKSIZE;
build > blk->c && build[-1] != '\n';
)
{
*--scan = *--build;
}
/* write the block */
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
/* add another block */
blkno++;
blk = blkadd(blkno);
/* copy in the excess from last time */
for (build = blk->c; scan < linebuf.c + BLKSIZE; )
{
*build++ = *scan++;
}
}
}
/* see if we can combine our last block with the following block */
if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6))
{
/* hey, we probably can! Get the following block & see... */
following = blkget(blkno + 1);
if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1)
{
/* we can! Copy text from following to blk */
for (scan = following->c; *scan; )
{
*build++ = *scan++;
}
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
/* pretend the following was the last blk */
blk = following;
build = blk->c;
}
}
/* that last block is dirty by now */
while (build < blk->c + BLKSIZE)
{
*build++ = '\0';
}
blkdirty(blk);
}
/* change the text of a file */
change(frommark, tomark, newtext)
MARK frommark, tomark;
char *newtext;
{
int i;
long l;
char *text;
BLK *blk;
/* optimize for single-character replacement */
if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
{
/* find the block containing frommark */
l = markline(frommark);
for (i = 1; lnum[i] < l; i++)
{
}
/* get the block */
blk = blkget(i);
/* find the line within the block */
for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
{
if (*text == '\n')
{
i--;
}
}
/* replace the char */
text += markidx(frommark);
if (*text == newtext[0])
{
/* no change was needed - same char */
return;
}
else if (*text != '\n')
{
/* This is a change */
changes++;
ChangeText
{
*text = newtext[0];
blkdirty(blk);
}
return;
}
/* else it is a complex change involving newline... */
}
/* couldn't optimize, so do delete & add */
ChangeText
{
delete(frommark, tomark);
add(frommark, newtext);
rptlabel = "changed";
}
}
SHAR_EOF
fi
if test -f 'move1.c'
then
echo shar: "will not over-write existing file 'move1.c'"
else
cat << \SHAR_EOF > 'move1.c'
/* m_1.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains most movement functions */
#include "config.h"
#include <ctype.h>
#include "vi.h"
#ifndef isascii
# define isascii(c) !((c) & ~0x7f)
#endif
/*ARGSUSED*/
MARK m_up(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
DEFAULT(1);
/* if at top already, don't move */
if (markline(m) - cnt < 1)
{
return MARK_UNSET;
}
/* else move up one line */
m -= MARK_AT_LINE(cnt);
return m;
}
/*ARGSUSED*/
MARK m_down(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
DEFAULT(1);
/* if at bottom already, don't move */
if (markline(m) + cnt > nlines)
{
return MARK_UNSET;
}
/* else move down one line */
m += MARK_AT_LINE(cnt);
/* adjust column number */
if (markidx(m) >= plen)
{
m = (m & ~(BLKSIZE - 1));
if (plen > 0)
{
m += plen - 1;
}
}
return m;
}
/*ARGSUSED*/
MARK m_right(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
int idx; /* index of the new cursor position */
DEFAULT(1);
/* move to right, if that's OK */
pfetch(markline(m));
idx = markidx(m) + cnt;
if (idx < plen)
{
m += cnt;
}
else
{
return MARK_UNSET;
}
return m;
}
/*ARGSUSED*/
MARK m_left(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
DEFAULT(1);
/* move to the left, if that's OK */
if (markidx(m) >= cnt)
{
m -= cnt;
}
else
{
return MARK_UNSET;
}
return m;
}
/*ARGSUSED*/
MARK m_toline(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric line number */
{
/* if no number specified, assume last line */
DEFAULT(nlines);
/* if invalid line number, don't move */
if (cnt > nlines)
{
msg("Line numbers range from 1 to %ld", nlines);
return MARK_UNSET;
}
/* move to first character of the selected line */
m = MARK_AT_LINE(cnt);
return m;
}
/*ARGSUSED*/
MARK m_tocol(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
char *text; /* text of the line */
int col; /* column number */
int idx; /* index into the line */
DEFAULT(1);
/* internally, columns are numbered 0..COLS-1, not 1..COLS */
cnt--;
/* if 0, that's easy */
if (cnt == 0)
{
m &= ~(BLKSIZE - 1);
return m;
}
/* find that column within the line */
pfetch(markline(m));
text = ptext;
for (col = idx = 0; col < cnt && *text; text++, idx++)
{
if (*text == '\t' && !*o_list)
{
col += *o_tabstop;
col -= col % *o_tabstop;
}
else if (UCHAR(*text) < ' ' || *text == '\177')
{
col += 2;
}
#ifndef NO_CHARATTR
else if (text[0] == '\\' && text[1] == 'f' && text[2] && *o_charattr)
{
text += 2; /* plus one more as part of for loop */
}
#endif
else
{
col++;
}
}
if (!*text)
{
return MARK_UNSET;
}
else
{
m = (m & ~(BLKSIZE - 1)) + idx;
}
return m;
}
/*ARGSUSED*/
MARK m_front(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument (ignored) */
{
char *scan;
/* move to the first non-whitespace character */
pfetch(markline(m));
scan = ptext;
m &= ~(BLKSIZE - 1);
while (*scan == ' ' || *scan == '\t')
{
scan++;
m++;
}
return m;
}
/*ARGSUSED*/
MARK m_rear(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument (ignored) */
{
/* Try to move *EXTREMELY* far to the right. It is fervently hoped
* that other code will convert this to a more reasonable MARK before
* anything tries to actually use it. (See adjmove() in vi.c)
*/
return m | (BLKSIZE - 1);
}
#ifndef NO_SENTENCE
/*ARGSUSED*/
MARK m_fsentence(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register char *text;
register long l;
DEFAULT(1);
/* get the current line */
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
/* for each requested sentence... */
while (cnt-- > 0)
{
/* search forward for one of [.?!] followed by spaces or EOL */
do
{
/* wrap at end of line */
if (!text[0])
{
if (l >= nlines)
{
return MARK_UNSET;
}
l++;
pfetch(l);
text = ptext;
}
else
{
text++;
}
} while (text[0] != '.' && text[0] != '?' && text[0] != '!'
|| text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
}
/* construct a mark for this location */
m = buildmark(text);
/* move forward to the first word of the next sentence */
m = m_fword(m, 1L);
return m;
}
/*ARGSUSED*/
MARK m_bsentence(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register char *text; /* used to scan thru text */
register long l; /* current line number */
int flag; /* have we passed at least one word? */
DEFAULT(1);
/* get the current line */
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
/* for each requested sentence... */
flag = TRUE;
while (cnt-- > 0)
{
/* search backward for one of [.?!] followed by spaces or EOL */
do
{
/* wrap at beginning of line */
if (text == ptext)
{
do
{
if (l <= 1)
{
return MARK_UNSET;
}
l--;
pfetch(l);
} while (!*ptext);
text = ptext + plen - 1;
}
else
{
text--;
}
/* are we moving past a "word"? */
if (text[0] >= '0')
{
flag = FALSE;
}
} while (flag || text[0] != '.' && text[0] != '?' && text[0] != '!'
|| text[1] && (text[1] != ' ' || text[2] && text[2] != ' '));
}
/* construct a mark for this location */
m = buildmark(text);
/* move to the front of the following sentence */
m = m_fword(m, 1L);
return m;
}
#endif
/*ARGSUSED*/
MARK m_fparagraph(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
char *text;
char *pscn; /* used to scan thru value of "paragraphs" option */
long l;
DEFAULT(1);
for (l = markline(m); cnt > 0 && l++ < nlines; )
{
text = fetchline(l);
if (!*text)
{
cnt--;
}
#ifndef NO_SENTENCE
else if (*text == '.')
{
for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
{
if (pscn[0] == text[1] && pscn[1] == text[2])
{
cnt--;
break;
}
}
}
#endif
}
if (l <= nlines)
{
m = MARK_AT_LINE(l);
}
else
{
m = MARK_LAST;
}
return m;
}
/*ARGSUSED*/
MARK m_bparagraph(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
char *text;
char *pscn; /* used to scan thru value of "paragraph" option */
long l;
DEFAULT(1);
for (l = markline(m); cnt > 0 && l-- > 1; )
{
text = fetchline(l);
if (!*text)
{
cnt--;
}
#ifndef NO_SENTENCE
else if (*text == '.')
{
for (pscn = o_paragraphs; pscn[0] && pscn[1]; pscn += 2)
{
if (pscn[0] == text[1] && pscn[1] == text[2])
{
cnt--;
break;
}
}
}
#endif
}
if (l >= 1)
{
m = MARK_AT_LINE(l);
}
else
{
m = MARK_FIRST;
}
return m;
}
/*ARGSUSED*/
MARK m_fsection(m, cnt, key)
MARK m; /* movement is relative to this mark */
long cnt; /* (ignored) */
int key; /* second key stroke - must be ']' */
{
char *text;
char *sscn; /* used to scan thru value of "sections" option */
long l;
/* make sure second key was ']' */
if (key != ']')
{
return MARK_UNSET;
}
for (l = markline(m); l++ < nlines; )
{
text = fetchline(l);
if (*text == '{')
{
break;
}
#ifndef NO_SENTENCE
else if (*text == '.')
{
for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
{
if (sscn[0] == text[1] && sscn[1] == text[2])
{
goto BreakBreak;
}
}
}
#endif
}
BreakBreak:
if (l <= nlines)
{
m = MARK_AT_LINE(l);
}
else
{
m = MARK_LAST;
}
return m;
}
/*ARGSUSED*/
MARK m_bsection(m, cnt, key)
MARK m; /* movement is relative to this mark */
long cnt; /* (ignored) */
int key; /* second key stroke - must be '[' */
{
char *text;
char *sscn; /* used to scan thru value of "sections" option */
long l;
/* make sure second key was '[' */
if (key != '[')
{
return MARK_UNSET;
}
for (l = markline(m); l-- > 1; )
{
text = fetchline(l);
if (*text == '{')
{
break;
}
#ifndef NO_SENTENCE
else if (*text == '.')
{
for (sscn = o_sections; sscn[0] && sscn[1]; sscn += 2)
{
if (sscn[0] == text[1] && sscn[1] == text[2])
{
goto BreakBreak;
}
}
}
#endif
}
BreakBreak:
if (l >= 1)
{
m = MARK_AT_LINE(l);
}
else
{
m = MARK_FIRST;
}
return m;
}
/*ARGSUSED*/
MARK m_match(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
long l;
register char *text;
register char match;
register char nest;
register int count;
/* get the current line */
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
/* search forward within line for one of "[](){}" */
for (match = '\0'; !match && *text; text++)
{
/* tricky way to recognize 'em in ASCII */
nest = *text;
if ((nest & 0xdf) == ']' || (nest & 0xdf) == '[')
{
match = nest ^ ('[' ^ ']');
}
else if ((nest & 0xfe) == '(')
{
match = nest ^ ('(' ^ ')');
}
else
{
match = 0;
}
}
if (!match)
{
return MARK_UNSET;
}
text--;
/* search forward or backward for match */
if (match == '(' || match == '[' || match == '{')
{
/* search backward */
for (count = 1; count > 0; )
{
/* wrap at beginning of line */
if (text == ptext)
{
do
{
if (l <= 1L)
{
return MARK_UNSET;
}
l--;
pfetch(l);
} while (!*ptext);
text = ptext + plen - 1;
}
else
{
text--;
}
/* check the char */
if (*text == match)
count--;
else if (*text == nest)
count++;
}
}
else
{
/* search forward */
for (count = 1; count > 0; )
{
/* wrap at end of line */
if (!*text)
{
if (l >= nlines)
{
return MARK_UNSET;
}
l++;
pfetch(l);
text = ptext;
}
else
{
text++;
}
/* check the char */
if (*text == match)
count--;
else if (*text == nest)
count++;
}
}
/* construct a mark for this place */
m = buildmark(text);
return m;
}
/*ARGSUSED*/
MARK m_tomark(m, cnt, key)
MARK m; /* movement is relative to this mark */
long cnt; /* (ignored) */
int key; /* keystroke - the mark to move to */
{
/* mark '' is a special case */
if (key == '\'' || key == '`')
{
if (mark[26] == MARK_UNSET)
{
return MARK_FIRST;
}
else
{
return mark[26];
}
}
/* if not a valid mark number, don't move */
if (key < 'a' || key > 'z')
{
return MARK_UNSET;
}
/* return the selected mark -- may be MARK_UNSET */
if (!mark[key - 'a'])
{
msg("mark '%c is unset", key);
}
return mark[key - 'a'];
}
SHAR_EOF
fi
if test -f 'move2.c'
then
echo shar: "will not over-write existing file 'move2.c'"
else
cat << \SHAR_EOF > 'move2.c'
/* m_2.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This function contains the mvoement functions that perform RE searching */
#include "config.h"
#include "vi.h"
#include "regexp.h"
static regexp *re; /* compiled version of the pattern to search for */
static prevsf; /* boolean: previous search direction was forward? */
MARK m_nsrch(m)
MARK m; /* where to start searching */
{
if (prevsf)
{
m = m_fsrch(m, "");
prevsf = TRUE;
}
else
{
m = m_bsrch(m, "");
prevsf = FALSE;
}
return m;
}
MARK m_Nsrch(m)
MARK m; /* where to start searching */
{
if (prevsf)
{
m = m_bsrch(m, "");
prevsf = TRUE;
}
else
{
m = m_fsrch(m, "");
prevsf = FALSE;
}
return m;
}
MARK m_fsrch(m, ptrn)
MARK m; /* where to start searching */
char *ptrn; /* pattern to search for */
{
long l; /* line# of line to be searched */
char *line; /* text of line to be searched */
int wrapped;/* boolean: has our search wrapped yet? */
int pos; /* where we are in the line */
/* remember: "previous search was forward" */
prevsf = TRUE;
if (ptrn && *ptrn)
{
/* free the previous pattern */
if (re) free(re);
/* compile the pattern */
re = regcomp(ptrn);
if (!re)
{
return MARK_UNSET;
}
}
else if (!re)
{
msg("No previous expression");
return MARK_UNSET;
}
/* search forward for the pattern */
pos = markidx(m) + 1;
pfetch(markline(m));
if (pos >= plen)
{
pos = 0;
m = (m | (BLKSIZE - 1)) + 1;
}
wrapped = FALSE;
for (l = markline(m); l != markline(m) + 1 || !wrapped; l++)
{
/* wrap search */
if (l > nlines)
{
/* if we wrapped once already, then the search failed */
if (wrapped)
{
break;
}
/* else maybe we should wrap now? */
if (*o_wrapscan)
{
l = 0;
wrapped = TRUE;
continue;
}
else
{
break;
}
}
/* get this line */
line = fetchline(l);
/* check this line */
if (regexec(re, &line[pos], (pos == 0)))
{
/* match! */
if (wrapped && *o_warn)
msg("(wrapped)");
return MARK_AT_LINE(l) + (int)(re->startp[0] - line);
}
pos = 0;
}
/* not found */
msg(*o_wrapscan ? "Not found" : "Hit bottom without finding RE");
return MARK_UNSET;
}
MARK m_bsrch(m, ptrn)
MARK m; /* where to start searching */
char *ptrn; /* pattern to search for */
{
long l; /* line# of line to be searched */
char *line; /* text of line to be searched */
int wrapped;/* boolean: has our search wrapped yet? */
int pos; /* last acceptable idx for a match on this line */
int last; /* remembered idx of the last acceptable match on this line */
int try; /* an idx at which we strat searching for another match */
/* remember: "previous search was not forward" */
prevsf = FALSE;
if (ptrn && *ptrn)
{
/* free the previous pattern, if any */
if (re) free(re);
/* compile the pattern */
re = regcomp(ptrn);
if (!re)
{
return MARK_UNSET;
}
}
else if (!re)
{
msg("No previous expression");
return MARK_UNSET;
}
/* search backward for the pattern */
pos = markidx(m);
wrapped = FALSE;
for (l = markline(m); l != markline(m) - 1 || !wrapped; l--)
{
/* wrap search */
if (l < 1)
{
if (*o_wrapscan)
{
l = nlines + 1;
wrapped = TRUE;
continue;
}
else
{
break;
}
}
/* get this line */
line = fetchline(l);
/* check this line */
if (regexec(re, line, 1) && (int)(re->startp[0] - line) < pos)
{
/* match! now find the last acceptable one in this line */
do
{
last = (int)(re->startp[0] - line);
try = (int)(re->endp[0] - line);
} while (try > 0
&& regexec(re, &line[try], FALSE)
&& (int)(re->startp[0] - line) < pos);
if (wrapped && *o_warn)
msg("(wrapped)");
return MARK_AT_LINE(l) + last;
}
pos = BLKSIZE;
}
/* not found */
msg(*o_wrapscan ? "Not found" : "Hit top without finding RE");
return MARK_UNSET;
}
SHAR_EOF
fi
if test -f 'move3.c'
then
echo shar: "will not over-write existing file 'move3.c'"
else
cat << \SHAR_EOF > 'move3.c'
/* m_3.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains movement functions that perform character searches */
#include "config.h"
#include "vi.h"
#ifndef NO_CHARSEARCH
static MARK (*prevfwdfn)(); /* function to search in same direction */
static MARK (*prevrevfn)(); /* function to search in opposite direction */
static char prev_key; /* sought cvhar from previous [fFtT] */
MARK m__ch(m, cnt, cmd)
MARK m; /* current position */
long cnt;
char cmd; /* command: either ',' or ';' */
{
MARK (*tmp)();
if (!prevfwdfn)
{
msg("No previous f, F, t, or T command");
return MARK_UNSET;
}
if (cmd == ',')
{
m = (*prevrevfn)(m, cnt, prev_key);
/* Oops! we didn't want to change the prev*fn vars! */
tmp = prevfwdfn;
prevfwdfn = prevrevfn;
prevrevfn = tmp;
return m;
}
else
{
return (*prevfwdfn)(m, cnt, prev_key);
}
}
/* move forward within this line to next occurrence of key */
MARK m_fch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
register char *text;
DEFAULT(1);
prevfwdfn = m_fch;
prevrevfn = m_Fch;
prev_key = key;
pfetch(markline(m));
text = ptext + markidx(m);
while (cnt-- > 0)
{
do
{
m++;
text++;
} while (*text && *text != key);
}
if (!*text)
{
return MARK_UNSET;
}
return m;
}
/* move backward within this line to previous occurrence of key */
MARK m_Fch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
register char *text;
DEFAULT(1);
prevfwdfn = m_Fch;
prevrevfn = m_fch;
prev_key = key;
pfetch(markline(m));
text = ptext + markidx(m);
while (cnt-- > 0)
{
do
{
m--;
text--;
} while (text >= ptext && *text != key);
}
if (text < ptext)
{
return MARK_UNSET;
}
return m;
}
/* move forward within this line almost to next occurrence of key */
MARK m_tch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
/* skip the adjacent char */
pfetch(markline(m));
if (plen <= markidx(m))
{
return MARK_UNSET;
}
m++;
m = m_fch(m, cnt, key);
if (m == MARK_UNSET)
{
return MARK_UNSET;
}
prevfwdfn = m_tch;
prevrevfn = m_Tch;
return m - 1;
}
/* move backward within this line almost to previous occurrence of key */
MARK m_Tch(m, cnt, key)
MARK m; /* where to search from */
long cnt;
char key; /* what to search for */
{
/* skip the adjacent char */
if (markidx(m) == 0)
{
return MARK_UNSET;
}
m--;
m = m_Fch(m, cnt, key);
if (m == MARK_UNSET)
{
return MARK_UNSET;
}
prevfwdfn = m_Tch;
prevrevfn = m_tch;
return m + 1;
}
#endif
SHAR_EOF
fi
if test -f 'move4.c'
then
echo shar: "will not over-write existing file 'move4.c'"
else
cat << \SHAR_EOF > 'move4.c'
/* m_4.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains movement functions which are screen-relative */
#include "config.h"
#include "vi.h"
/* This m_s the cursor to a particular row on the screen */
/*ARGSUSED*/
MARK m_row(m, cnt, key)
MARK m; /* the cursor position */
long cnt; /* the row we'll move to */
int key; /* the keystroke of this move - H/L/M */
{
DEFAULT(1);
/* calculate destination line based on key */
cnt--;
switch (key)
{
case 'H':
cnt = topline + cnt;
break;
case 'M':
cnt = topline + (LINES - 1) / 2;
break;
case 'L':
cnt = botline - cnt;
break;
}
/* return the mark of the destination line */
return MARK_AT_LINE(cnt);
}
/* This function repositions the current line to show on a given row */
/*ARGSUSED*/
MARK m_z(m, cnt, key)
MARK m; /* the cursor */
long cnt; /* the line number we're repositioning */
int key; /* key struck after the z */
{
long newtop;
/* Which line are we talking about? */
if (cnt < 0 || cnt > nlines)
{
return MARK_UNSET;
}
if (cnt)
{
m = MARK_AT_LINE(cnt);
newtop = cnt;
}
else
{
newtop = markline(m);
}
/* allow a "window size" number to be entered, but ignore it */
while (key >= '0' && key <= '9')
{
key = getkey(0);
}
/* figure out which line will have to be at the top of the screen */
switch (key)
{
case '\n':
case '\r':
case '+':
break;
case '.':
case 'z':
newtop -= LINES / 2;
break;
case '-':
newtop -= LINES - 1;
break;
default:
return MARK_UNSET;
}
/* make the new topline take effect */
if (newtop >= 1)
{
topline = newtop;
}
else
{
topline = 1L;
}
mustredraw = TRUE;
/* The cursor doesn't move */
return m;
}
/* This function scrolls the screen. It does this by calling redraw() with
* an off-screen line as the argument. It will move the cursor if necessary
* so that the cursor is on the new screen.
*/
/*ARGSUSED*/
MARK m_scroll(m, cnt, key)
MARK m; /* the cursor position */
long cnt; /* for some keys: the number of lines to scroll */
int key; /* keystroke that causes this movement */
{
MARK tmp; /* a temporary mark, used as arg to redraw() */
/* adjust cnt, and maybe *o_scroll, depending of key */
switch (key)
{
case ctrl('F'):
case ctrl('B'):
DEFAULT(1);
mustredraw = TRUE;
cnt = cnt * (LINES - 1) - 1; /* keeps one old line on screen */
break;
case ctrl('E'):
case ctrl('Y'):
DEFAULT(1);
break;
case ctrl('U'):
case ctrl('D'):
if (cnt == 0) /* default */
{
cnt = *o_scroll;
}
else
{
if (cnt > LINES - 1)
{
cnt = LINES - 1;
}
*o_scroll = cnt;
}
break;
}
/* scroll up or down, depending on key */
switch (key)
{
case ctrl('B'):
case ctrl('Y'):
case ctrl('U'):
cnt = topline - cnt;
if (cnt < 1L)
{
cnt = 1L;
m = MARK_FIRST;
}
tmp = MARK_AT_LINE(cnt) + markidx(m);
redraw(tmp, FALSE);
if (markline(m) > botline)
{
m = MARK_AT_LINE(botline);
}
break;
case ctrl('F'):
case ctrl('E'):
case ctrl('D'):
cnt = botline + cnt;
if (cnt > nlines)
{
cnt = nlines;
m = MARK_LAST;
}
tmp = MARK_AT_LINE(cnt) + markidx(m);
redraw(tmp, FALSE);
if (markline(m) < topline)
{
m = MARK_AT_LINE(topline);
}
break;
}
/* arrange for ctrl-B and ctrl-F to redraw the smart line */
if (key == ctrl('B') || key == ctrl('F'))
{
changes++;
}
return m;
}
SHAR_EOF
fi
if test -f 'move5.c'
then
echo shar: "will not over-write existing file 'move5.c'"
else
cat << \SHAR_EOF > 'move5.c'
/* m_5.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the word-oriented movement functions */
#include <ctype.h>
#include "config.h"
#include "vi.h"
#ifndef isascii
# define isascii(c) !((c) & ~0x7f)
#endif
MARK m_fword(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register long l;
register char *text;
register int i;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
i = *text++;
/* if we hit the end of the line, continue with next line */
if (!isascii(i) || isalnum(i) || i == '_')
{
/* include an alphanumeric word */
while (i && (!isascii(i) || isalnum(i) || i == '_'))
{
i = *text++;
}
}
else
{
/* include contiguous punctuation */
while (i && isascii(i) && !isalnum(i) && !isspace(i))
{
i = *text++;
}
}
/* include trailing whitespace */
while (!i || isascii(i) && isspace(i))
{
/* did we hit the end of this line? */
if (!i)
{
/* move to next line, if there is one */
l++;
if (l > nlines)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext;
}
i = *text++;
}
text--;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
MARK m_bword(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register long l;
register char *text;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
text--;
/* include preceding whitespace */
while (text < ptext || isascii(*text) && isspace(*text))
{
/* did we hit the end of this line? */
if (text < ptext)
{
/* move to preceding line, if there is one */
l--;
if (l <= 0)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext + plen - 1;
}
else
{
text--;
}
}
if (!isascii(*text) || isalnum(*text) || *text == '_')
{
/* include an alphanumeric word */
while (text >= ptext && (!isascii(*text) || isalnum(*text) || *text == '_'))
{
text--;
}
}
else
{
/* include contiguous punctuation */
while (text >= ptext && isascii(*text) && !isalnum(*text) && !isspace(*text))
{
text--;
}
}
text++;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
MARK m_eword(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register long l;
register char *text;
register int i;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
text++;
i = *text++;
/* include preceding whitespace */
while (!i || isascii(i) && isspace(i))
{
/* did we hit the end of this line? */
if (!i)
{
/* move to next line, if there is one */
l++;
if (l > nlines)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext;
}
i = *text++;
}
if (!isascii(i) || isalnum(i) || i == '_')
{
/* include an alphanumeric word */
while (i && (!isascii(i) || isalnum(i) || i == '_'))
{
i = *text++;
}
}
else
{
/* include contiguous punctuation */
while (i && isascii(i) && !isalnum(i) && !isspace(i))
{
i = *text++;
}
}
text -= 2;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
MARK m_fWord(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register long l;
register char *text;
register int i;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
i = *text++;
/* if we hit the end of the line, continue with next line */
/* include contiguous non-space characters */
while (i && !isspace(i))
{
i = *text++;
}
/* include trailing whitespace */
while (!i || isascii(i) && isspace(i))
{
/* did we hit the end of this line? */
if (!i)
{
/* move to next line, if there is one */
l++;
if (l > nlines)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext;
}
i = *text++;
}
text--;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
MARK m_bWord(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register long l;
register char *text;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
text--;
/* include trailing whitespace */
while (text < ptext || isascii(*text) && isspace(*text))
{
/* did we hit the end of this line? */
if (text < ptext)
{
/* move to next line, if there is one */
l--;
if (l <= 0)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext + plen - 1;
}
else
{
text--;
}
}
/* include contiguous non-whitespace */
while (text >= ptext && (!isascii(*text) || !isspace(*text)))
{
text--;
}
text++;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
MARK m_eWord(m, cnt)
MARK m; /* movement is relative to this mark */
long cnt; /* a numeric argument */
{
register long l;
register char *text;
register int i;
DEFAULT(1);
l = markline(m);
pfetch(l);
text = ptext + markidx(m);
while (cnt-- > 0) /* yes, ASSIGNMENT! */
{
text++;
i = *text++;
/* include preceding whitespace */
while (!i || isascii(i) && isspace(i))
{
/* did we hit the end of this line? */
if (!i)
{
/* move to next line, if there is one */
l++;
if (l > nlines)
{
return MARK_UNSET;
}
pfetch(l);
text = ptext;
}
i = *text++;
}
/* include contiguous non-whitespace */
while (i && (!isascii(i) || !isspace(i)))
{
i = *text++;
}
text -= 2;
}
/* construct a MARK for this place */
m = buildmark(text);
return m;
}
SHAR_EOF
fi
if test -f 'nomagic.c'
then
echo shar: "will not over-write existing file 'nomagic.c'"
else
cat << \SHAR_EOF > 'nomagic.c'
/* nomagic.c */
/* This contains versions of the regcomp() and regexec() functions which
* do not recognize any metacharacters except ^ $ and \. They use the same
* data structure Henry Spencer's package, so they can continue to use his
* regsub() function.
*
* This file is meant to be #included in regexp.c; it should *NOT* be
* compiled separately. The regexp.c file will check to see if NO_MAGIC
* is defined, and if so then this file is used; if not, then the real
* regexp functions are used.
*/
regexp *regcomp(exp)
char *exp;
{
char *src;
char *dest;
regexp *re;
int i;
/* allocate a big enough regexp structure */
re = (regexp *)malloc(strlen(exp) + 1 + sizeof(struct regexp));
if (!re)
{
regerror("could not malloc a regexp structure");
return (regexp *)0;
}
/* initialize all fields of the structure */
for (i = 0; i < NSUBEXP; i++)
{
re->startp[i] = (char *)0;
re->endp[i] = (char *)0;
}
re->regstart = 0;
re->reganch = 0;
re->regmust = &re->program[1];
re->regmlen = 0;
re->program[0] = MAGIC;
/* copy the string into it, translating ^ and $ as needed */
for (src = exp, dest = re->program + 1; *src; src++)
{
switch (*src)
{
case '^':
if (src == exp)
re->regstart = 1;
else
*dest++ = '^';
break;
case '$':
if (!src[1])
re->reganch = 1;
else
*dest++ = '$';
break;
case '\\':
if (src[1])
*dest++ = *++src;
else
{
regerror("extra \\ at end of regular expression");
}
break;
default:
*dest++ = *src;
}
}
*dest = '\0';
re->regmlen = strlen(&re->program[1]);
return re;
}
/* This "helper" function checks for a match at a given location. It returns
* 1 if it matches, 0 if it doesn't match here but might match later on in the
* string, or -1 if it could not possibly match
*/
static int reghelp(prog, string, bolflag)
struct regexp *prog;
char *string;
int bolflag;
{
char *scan;
char *str;
/* if ^, then require bolflag */
if (prog->regstart && !bolflag)
{
return -1;
}
/* if it matches, then it will start here */
prog->startp[0] = string;
/* compare, possibly ignoring case */
if (*o_ignorecase)
{
for (scan = &prog->program[1]; *scan; scan++, string++)
if (tolower(*scan) != tolower(*string))
return *string ? 0 : -1;
}
else
{
for (scan = &prog->program[1]; *scan; scan++, string++)
if (*scan != *string)
return *string ? 0 : -1;
}
/* if $, then require string to end here, too */
if (prog->reganch && *string)
{
return 0;
}
/* if we get to here, it matches */
prog->endp[0] = string;
return 1;
}
int regexec(prog, string, bolflag)
struct regexp *prog;
char *string;
int bolflag;
{
int rc;
/* keep trying to match it */
for (rc = reghelp(prog, string, bolflag); rc == 0; rc = reghelp(prog, string, 0))
{
string++;
}
/* did we match? */
return rc == 1;
}
SHAR_EOF
fi
if test -f 'opts.c'
then
echo shar: "will not over-write existing file 'opts.c'"
else
cat << \SHAR_EOF > 'opts.c'
/* opts.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the code that manages the run-time options -- The
* values that can be modified via the "set" command.
*/
#include "config.h"
#include "vi.h"
#ifndef NULL
#define NULL (char *)0
#endif
extern char *getenv();
/* These are the default values of all options */
char o_autoindent[1] = {FALSE};
char o_autowrite[1] = {FALSE};
#ifndef NO_CHARATTR
char o_charattr[1] = {FALSE};
#endif
char o_columns[3] = {80, 32, 255};
char o_directory[30] = TMPDIR;
char o_errorbells[1] = {TRUE};
char o_exrefresh[1] = {TRUE};
#ifndef NO_SENTENCE
char o_hideformat[1] = {FALSE};
#endif
char o_ignorecase[1] = {FALSE};
#ifndef NO_EXTENSIONS
char o_inputmode[1] = {FALSE};
#endif
char o_keytime[3] = {2, 0, 5};
char o_keywordprg[80] = KEYWORDPRG;
char o_lines[3] = {25, 2, 50}; /* More lines? Enlarge kbuf */
char o_list[1] = {FALSE};
#ifndef NO_MAGIC
char o_magic[1] = {TRUE};
#endif
#ifndef NO_SENTENCE
char o_paragraphs[30] = "PPppPApa";
#endif
#if MSDOS
char o_pcbios[1] = {TRUE};
#endif
char o_readonly[1] = {FALSE};
char o_report[3] = {5, 1, 127};
char o_scroll[3] = {12, 1, 127};
#ifndef NO_SENTENCE
char o_sections[30] = "SEseSHsh";
#endif
char o_shell[60] = "/bin/sh";
char o_shiftwidth[3] = {8, 1, 255};
#ifndef NO_SHOWMODE
char o_showmode[1] = {FALSE};
#endif
char o_sidescroll[3] = {8, 1, 40};
char o_sync[1] = {FALSE};
char o_tabstop[3] = {8, 1, 40};
char o_term[30] = "?";
char o_vbell[1] = {TRUE};
char o_warn[1] = {TRUE};
char o_wrapmargin[3] = {0, 0, 255};
char o_wrapscan[1] = {TRUE};
/* The following describes the names & types of all options */
#define BOOL 0
#define NUM 1
#define STR 2
#define SET 0x01 /* this option has had its value altered */
#define CANSET 0x02 /* this option can be set at any time */
#define RCSET 0x06 /* this option can be set in a .exrc file only */
#define MR 0x40 /* does this option affect the way text is displayed? */
struct
{
char *name; /* name of an option */
char *nm; /* short name of an option */
char type; /* type of an option */
char flags; /* boolean: has this option been set? */
char *value; /* value */
}
opts[] =
{
/* name type flags redraw value */
{ "autoindent", "ai", BOOL, CANSET , o_autoindent },
{ "autowrite", "aw", BOOL, CANSET , o_autowrite },
#ifndef NO_CHARATTR
{ "charattr", "ca", BOOL, CANSET | MR, o_charattr },
#endif
{ "columns", "co", NUM, SET , o_columns },
{ "directory", "dir", STR, RCSET , o_directory },
{ "errorbells", "eb", BOOL, CANSET , o_errorbells },
{ "exrefresh", "er", BOOL, CANSET , o_exrefresh },
#ifndef NO_SENTENCE
{ "hideformat", "hf", BOOL, CANSET | MR, o_hideformat },
#endif
{ "ignorecase", "ic", BOOL, CANSET , o_ignorecase },
#ifndef NO_EXTENSIONS
{ "inputmode", "im", BOOL, CANSET , o_inputmode },
#endif
{ "keytime", "kt", NUM, CANSET , o_keytime },
{ "keywordprg", "kp", STR, CANSET , o_keywordprg },
{ "lines", "ls", NUM, SET , o_lines },
{ "list", "li", BOOL, CANSET | MR, o_list },
#ifndef NO_MAGIC
{ "magic", "ma", BOOL, CANSET , o_magic },
#endif
#ifndef NO_SENTENCE
{ "paragraphs", "pa", STR, CANSET , o_paragraphs },
#endif
#if MSDOS
{ "pcbios", "pc", BOOL, SET , o_pcbios },
#endif
{ "readonly", "ro", BOOL, CANSET , o_readonly },
{ "report", "re", NUM, CANSET , o_report },
{ "scroll", "sc", NUM, CANSET , o_scroll },
#ifndef NO_SENTENCE
{ "sections", "se", STR, CANSET , o_sections },
#endif
{ "shell", "sh", STR, CANSET , o_shell },
#ifndef NO_SHOWMODE
{ "showmode", "sho", BOOL, CANSET , o_showmode },
#endif
{ "shiftwidth", "sw", NUM, CANSET , o_shiftwidth },
{ "sidescroll", "ss", NUM, CANSET , o_sidescroll },
{ "sync", "sy", BOOL, CANSET , o_sync },
{ "tabstop", "ts", NUM, CANSET | MR, o_tabstop },
{ "term", "te", STR, SET , o_term },
{ "vbell", "vb", BOOL, CANSET , o_vbell },
{ "warn", "wa", BOOL, CANSET , o_warn },
{ "wrapmargin", "wm", NUM, CANSET , o_wrapmargin },
{ "wrapscan", "ws", BOOL, CANSET , o_wrapscan },
{ NULL, NULL, 0, CANSET, NULL }
};
/* This function initializes certain options from environment variables, etc. */
initopts()
{
char *val;
int i;
/* set some stuff from environment variables */
#if ANY_UNIX || TOS
if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
{
strcpy(o_shell, val);
}
if (val = getenv("TERM")) /* yes, ASSIGNMENT! */
{
strcpy(o_term, val);
}
#endif
#if MSDOS
if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
{
strcpy(o_shell, val);
}
if ((val = getenv("TERM")) /* yes, ASSIGNMENT! */
&& strcmp(val, "pcbios"))
{
strcpy(o_term, val);
o_pcbios[0] = 0;
}
else
{
strcpy(o_term, "pcbios");
o_pcbios[0] = 1;
}
#endif
#if MSDOS || TOS
if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
|| (val = getenv("TEMP")))
strcpy(o_directory, val);
#endif
*o_scroll = LINES / 2 - 1;
/* disable the vbell option if we don't know how to do a vbell */
if (!has_VB)
{
for (i = 0; opts[i].value != o_vbell; i++)
{
}
opts[i].flags &= ~CANSET;
*o_vbell = FALSE;
}
}
/* This function lists the current values of all options */
dumpopts(all)
int all; /* boolean: dump all options, or just set ones? */
{
int i;
int col;
char nbuf[4];
for (i = col = 0; opts[i].name; i++)
{
/* if not set and not all, ignore this option */
if (!all && !(opts[i].flags & SET))
{
continue;
}
/* align this option in one of the columns */
if (col > 52)
{
addch('\n');
col = 0;
}
else if (col > 26)
{
while (col < 52)
{
qaddch(' ');
col++;
}
}
else if (col > 0)
{
while (col < 26)
{
qaddch(' ');
col++;
}
}
switch (opts[i].type)
{
case BOOL:
if (!*opts[i].value)
{
qaddch('n');
qaddch('o');
col += 2;
}
qaddstr(opts[i].name);
col += strlen(opts[i].name);
break;
case NUM:
sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
qaddstr(opts[i].name);
qaddch('=');
qaddstr(nbuf);
col += 4 + strlen(opts[i].name);
break;
case STR:
qaddstr(opts[i].name);
qaddch('=');
qaddch('"');
qaddstr(opts[i].value);
qaddch('"');
col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
break;
}
exrefresh();
}
if (col > 0)
{
addch('\n');
exrefresh();
}
}
/* This function saves the current configuarion of options to a file */
saveopts(fd)
int fd; /* file descriptor to write to */
{
int i;
char buf[256], *pos;
/* write each set options */
for (i = 0; opts[i].name; i++)
{
/* if unset or unsettable, ignore this option */
if (!(opts[i].flags & SET) || !(opts[i].flags & CANSET))
{
continue;
}
strcpy(buf, "set ");
pos = &buf[4];
switch (opts[i].type)
{
case BOOL:
if (!*opts[i].value)
{
*pos++='n';
*pos++='o';
}
strcpy(pos, opts[i].name);
strcat(pos, "\n");
break;
case NUM:
sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
break;
case STR:
sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
break;
}
twrite(fd, buf, strlen(buf));
}
}
/* This function changes the values of one or more options. */
setopts(assignments)
char *assignments; /* a string containing option assignments */
{
char *name; /* name of variable in assignments */
char *value; /* value of the variable */
char *scan; /* used for moving through strings */
int i, j;
/* for each assignment... */
for (name = assignments; *name; )
{
/* skip whitespace */
if (*name == ' ' || *name == '\t')
{
name++;
continue;
}
/* find the value, if any */
for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++)
{
}
if (*scan == '=')
{
*scan++ = '\0';
if (*scan == '"')
{
value = ++scan;
while (*scan && *scan != '"')
{
scan++;
}
if (*scan)
{
*scan++ = '\0';
}
}
else
{
value = scan;
while (*scan && *scan != ' ' && *scan != '\t')
{
scan++;
}
if (*scan)
{
*scan++ = '\0';
}
}
}
else
{
if (*scan)
{
*scan++ = '\0';
}
value = NULL;
if (name[0] == 'n' && name[1] == 'o')
{
name += 2;
}
}
/* find the variable */
for (i = 0;
opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
i++)
{
}
/* change the variable */
if (!opts[i].name)
{
msg("invalid option name \"%s\"", name);
}
else if ((opts[i].flags & CANSET) != CANSET)
{
msg("option \"%s\" can't be altered", name);
}
else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
{
msg("option \"%s\" can only be set in a %s file", name, EXRC);
}
else if (value)
{
switch (opts[i].type)
{
case BOOL:
msg("option \"[no]%s\" is boolean", name);
break;
case NUM:
j = atoi(value);
if (j == 0 && *value != '0')
{
msg("option \"%s\" must have a numeric value", name);
}
else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
{
msg("option \"%s\" must have a value between %d and %d",
name, opts[i].value[1], opts[i].value[2] & 0xff);
}
else
{
*opts[i].value = atoi(value);
opts[i].flags |= SET;
}
break;
case STR:
strcpy(opts[i].value, value);
opts[i].flags |= SET;
break;
}
if (opts[i].flags & MR)
{
mustredraw = TRUE;
}
}
else /* valid option, no value */
{
if (opts[i].type == BOOL)
{
*opts[i].value = (name[-1] != 'o');
opts[i].flags |= SET;
if (opts[i].flags & MR)
{
mustredraw = TRUE;
}
}
else
{
msg("option \"%s\" must be given a value", name);
}
}
/* move on to the next option */
name = scan;
}
}
SHAR_EOF
fi
if test -f 'pc.c'
then
echo shar: "will not over-write existing file 'pc.c'"
else
cat << \SHAR_EOF > 'pc.c'
/* pc.c */
/* Author:
* Guntram Blohm
* Buchenstrasse 19
* 7904 Erbach, West Germany
* Tel. ++49-7305-6997
* sorry - no regular network connection
*/
/* This file implements the ibm pc bios interface. See IBM documentation
* for details.
* If TERM is set upon invocation of elvis, this code is ignored completely,
* and the standard termcap functions are used, thus, even not-so-close
* compatibles can run elvis. For close compatibles however, bios output
* is much faster (and permits reverse scrolling, adding and deleting lines,
* and much more ansi.sys isn't capable of). GB.
*/
#include "config.h"
#include "vi.h"
#if MSDOS
#include <dos.h>
static void video();
/* vmode contains the screen attribute index and is set by attrset.*/
int vmode;
/* The following array contains attribute definitions for
* color/monochrome attributes. Screen selects one of the sets.
* Maybe i'll put them into elvis options one day.
*/
static int screen;
static char attr[2][5] =
{
/* :se: :so: :VB: :ul: :as: */
{ 0x17, 0x1d, 0x1e, 0x1a, 0x1c, }, /* color */
{ 0x07, 0x70, 0x0f, 0x01, 0x0f, }, /* monochrome */
};
/*
* bios interface functions for elvis - pc version
*/
/* cursor up: determine current position, decrement row, set position */
void v_up()
{
int dx;
video(0x300,(int *)0,&dx);
dx-=0x100;
video(0x200,(int *)0,&dx);
}
#ifndef NO_CURSORSHAPE
/* cursor big: set begin scan to end scan - 4 */
void v_cb()
{
int cx;
video(0x300, &cx, (int *)0);
cx=((cx&0xff)|(((cx&0xff)-4)<<8));
video(0x100, &cx, (int *)0);
}
/* cursor small: set begin scan to end scan - 1 */
void v_cs()
{
int cx;
video(0x300, &cx, (int *)0);
cx=((cx&0xff)|(((cx&0xff)-1)<<8));
video(0x100, &cx, (int *)0);
}
#endif
/* clear to end: get cursor position and emit the aproppriate number
* of spaces, without moving cursor.
*/
void v_ce()
{
int cx, dx;
video(0x300,(int *)0,&dx);
cx=COLS-(dx&0xff);
video(0x920,&cx,(int *)0);
}
/* clear screen: clear all and set cursor home */
void v_cl()
{
int cx=0, dx=((LINES-1)<<8)+COLS-1;
video(0x0600,&cx,&dx);
dx=0;
video(0x0200,&cx,&dx);
}
/* clear to bottom: get position, clear to eol, clear next line to end */
void v_cd()
{
int cx, dx, dxtmp;
video(0x0300,(int *)0,&dx);
dxtmp=(dx&0xff00)|(COLS-1);
cx=dx;
video(0x0600,&cx,&dxtmp);
cx=(dx&0xff00)+0x100;
dx=((LINES-1)<<8)+COLS-1;
video(0x600,&cx,&dx);
}
/* add line: scroll rest of screen down */
void v_al()
{
int cx,dx;
video(0x0300,(int *)0,&dx);
cx=(dx&0xff00);
dx=((LINES-1)<<8)+COLS-1;
video(0x701,&cx,&dx);
}
/* delete line: scroll rest up */
void v_dl()
{
int cx,dx;
video(0x0300,(int *)0,&dx);
cx=(dx&0xff00)/*+0x100*/;
dx=((LINES-1)<<8)+COLS-1;
video(0x601,&cx,&dx);
}
/* scroll reverse: scroll whole screen */
void v_sr()
{
int cx=0, dx=((LINES-1)<<8)+COLS-1;
video(0x0701,&cx,&dx);
}
/* set cursor */
void v_move(x,y)
int x, y;
{
int dx=(y<<8)+x;
video(0x200,(int *)0,&dx);
}
/* put character: set attribute first, then execute char.
* Also remember if current line has changed.
*/
int v_put(ch)
int ch;
{
int cx=1;
ch&=0xff;
if (ch>=' ')
video(0x900|ch,&cx,(int *)0);
video(0xe00|ch,(int *)0, (int *)0);
if (ch=='\n')
{ exwrote = TRUE;
video(0xe0d, (int *)0, (int *)0);
}
return ch;
}
/* determine number of screen columns. Also set attrset according
* to monochrome/color screen.
*/
int v_cols()
{
union REGS regs;
regs.h.ah=0x0f;
int86(0x10, ®s, ®s);
if (regs.h.al==7) /* monochrome mode ? */
screen=1;
else
screen=0;
return regs.h.ah;
}
/* Getting the number of rows is hard. Most screens support 25 only,
* EGA/VGA also support 43/50 lines, and some OEM's even more.
* Unfortunately, there is no standard bios variable for the number
* of lines, and the bios screen memory size is always rounded up
* to 0x1000. So, we'll really have to cheat.
* When using the screen memory size, keep in mind that each character
* byte has an associated attribute byte.
*
* uses: word at 40:4c contains memory size
* byte at 40:84 # of rows-1 (sometimes)
* byte at 40:4a # of columns
*/
int v_rows()
{
int line, oldline;
/* screen size less then 4K? then we have 25 lines only */
if (*(int far *)(0x0040004cl)<=4096)
return 25;
/* VEGA vga uses the bios byte at 0x40:0x84 for # of rows.
* Use that byte, if it makes sense together with memory size.
*/
if ((((*(unsigned char far *)(0x0040004aL)*2*
(*(unsigned char far *)(0x00400084L)+1))+0xfff)&(~0xfff))==
*(unsigned int far *)(0x0040004cL))
return *(unsigned char far *)(0x00400084L)+1;
/* uh oh. Emit '\n's until screen starts scrolling. */
v_move(oldline=0, 0);
for (;;)
{
video(0xe0a,(int *)0,(int *)0);
video(0x300,(int *)0,&line);
line>>=8;
if (oldline==line)
return line+1;
oldline=line;
}
}
/* the REAL bios interface -- used internally only. */
static void video(ax, cx, dx)
int ax, *cx, *dx;
{
union REGS regs;
regs.x.ax=ax;
if ((ax&0xff00)==0x600 || (ax&0xff00)==0x700)
regs.h.bh=attr[screen][vmode];
else
{
regs.h.bh=0;
regs.h.bl=attr[screen][vmode];
}
if (cx) regs.x.cx=*cx;
if (dx) regs.x.dx=*dx;
int86(0x10, ®s, ®s);
if (dx) *dx=regs.x.dx;
if (cx) *cx=regs.x.cx;
}
/* The following function determines which character is used for
* commandline-options by command.com. This system call is undocumented
* and valid for versions < 4.00 only.
*/
int switchar()
{
union REGS regs;
regs.x.ax=0x3700;
int86(0x21, ®s, ®s);
return regs.h.dl;
}
#endif
SHAR_EOF
fi
if test -f 'recycle.c'
then
echo shar: "will not over-write existing file 'recycle.c'"
else
cat << \SHAR_EOF > 'recycle.c'
/* recycle.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the functions perform garbage collection and allocate
* reusable blocks.
*/
#include "config.h"
#include "vi.h"
#ifndef NO_RECYCLE
/* this whole file would have be skipped if NO_RECYCLE is defined */
extern long lseek();
#define BTST(bitno, byte) ((byte) & (1 << (bitno)))
#define BSET(bitno, byte) ((byte) |= (1 << (bitno)))
#define BCLR(bitno, byte) ((byte) &= ~(1 << (bitno)))
#define TST(blkno) ((blkno) < MAXBIT ? BTST((blkno) & 7, bitmap[(blkno) >> 3]) : 1)
#define SET(blkno) if ((blkno) < MAXBIT) BSET((blkno) & 7, bitmap[(blkno) >> 3])
#define CLR(blkno) if ((blkno) < MAXBIT) BCLR((blkno) & 7, bitmap[(blkno) >> 3])
/* bitmap of free blocks in first 4096k of tmp file */
static unsigned char bitmap[512];
#define MAXBIT (sizeof bitmap << 3)
/* this function locates all free blocks in the current tmp file */
garbage()
{
int i;
BLK oldhdr;
/* start by assuming every block is free */
for (i = 0; i < sizeof bitmap; i++)
{
bitmap[i] = 255;
}
/* header block isn't free */
CLR(0);
/* blocks needed for current hdr aren't free */
for (i = 1; i < MAXBLKS; i++)
{
CLR(hdr.n[i]);
}
/* blocks needed for undo version aren't free */
lseek(tmpfd, 0L, 0);
if (read(tmpfd, &oldhdr, sizeof oldhdr) != sizeof oldhdr)
{
msg("garbage() failed to read oldhdr??");
for (i = 0; i < sizeof bitmap; i++)
{
bitmap[i] = 0;
}
return;
}
for (i = 1; i < MAXBLKS; i++)
{
CLR(oldhdr.n[i]);
}
/* blocks needed for cut buffers aren't free */
for (i = cutneeds(&oldhdr) - 1; i >= 0; i--)
{
CLR(oldhdr.n[i]);
}
}
/* This function allocates the first available block in the tmp file */
long allocate()
{
int i;
long offset;
/* search for the first byte with a free bit set */
for (i = 0; i < sizeof bitmap && bitmap[i] == 0; i++)
{
}
/* if we hit the end of the bitmap, return the end of the file */
if (i == sizeof bitmap)
{
offset = lseek(tmpfd, 0L, 2);
}
else /* compute the offset for the free block */
{
for (i <<= 3; TST(i) == 0; i++)
{
}
offset = (long)i * (long)BLKSIZE;
/* mark the block as "allocated" */
CLR(i);
}
return offset;
}
#endif
SHAR_EOF
fi
if test -f 'redraw.c'
then
echo shar: "will not over-write existing file 'redraw.c'"
else
cat << \SHAR_EOF > 'redraw.c'
/* redraw.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains functions that draw text on the screen. The major entry
* points are:
* redrawrange() - called from modify.c to give hints about what parts
* of the screen need to be redrawn.
* redraw() - redraws the screen (or part of it) and positions
* the cursor where it belongs.
* idx2col() - converts a markidx() value to a logical column number.
*/
#include "config.h"
#include "vi.h"
/* This variable contains the line number that smartdrawtext() knows best */
static long smartlno;
/* This function remebers where changes were made, so that the screen can be
* redraw in a more efficient manner.
*/
redrawrange(after, pre, post)
long after; /* lower bound of redrawafter */
long pre; /* upper bound of preredraw */
long post; /* upper bound of postredraw */
{
long l;
if (after < redrawafter)
redrawafter = after;
l = preredraw - postredraw + pre - post;
if (post > postredraw)
postredraw = post;
preredraw = postredraw + l;
}
/* This function is used in visual mode for drawing the screen (or just parts
* of the screen, if that's all thats needed). It also takes care of
* scrolling.
*/
redraw(curs, inputting)
MARK curs; /* where to leave the screen's cursor */
int inputting; /* boolean: being called from input() ? */
{
char *text; /* a line of text to display */
static long chgs; /* previous changes level */
long l;
int i;
/* if curs == MARK_UNSET, then we should reset internal vars */
if (curs == MARK_UNSET)
{
if (topline < 1 || topline > nlines)
{
topline = 1L;
}
else
{
move(LINES - 1, 0);
clrtoeol();
}
leftcol = 0;
mustredraw = TRUE;
redrawafter = INFINITY;
preredraw = 0L;
postredraw = 0L;
chgs = 0;
smartlno = 0L;
return;
}
/* figure out which column the cursor will be in */
l = markline(curs);
text = fetchline(l);
mark2phys(curs, text, inputting);
/* adjust topline, if necessary, to get the cursor on the screen */
if (l >= topline && l <= botline)
{
/* it is on the screen already */
/* if the file was changed but !mustredraw, then redraw line */
if (chgs != changes && !mustredraw)
{
smartdrawtext(text, l);
}
}
else if (l < topline && l > topline - LINES && (has_SR || has_AL))
{
/* near top - scroll down */
if (!mustredraw)
{
move(0,0);
while (l < topline)
{
topline--;
if (has_SR)
{
do_SR();
}
else
{
insertln();
}
text = fetchline(topline);
drawtext(text);
do_UP();
}
/* blank out the last line */
move(LINES - 1, 0);
clrtoeol();
}
else
{
topline = l;
redrawafter = INFINITY;
preredraw = 0L;
postredraw = 0L;
}
}
else if (l > topline && l < botline + LINES)
{
/* near bottom -- scroll up */
if (!mustredraw
#if 1
|| redrawafter == preredraw && preredraw == botline && postredraw == l
#endif
)
{
move(LINES - 1,0);
clrtoeol();
while (l > botline)
{
topline++; /* <-- also adjusts botline */
text = fetchline(botline);
drawtext(text);
}
mustredraw = FALSE;
}
else
{
topline = l - (LINES - 2);
redrawafter = INFINITY;
preredraw = 0L;
postredraw = 0L;
}
}
else
{
/* distant line - center it & force a redraw */
topline = l - (LINES / 2) - 1;
if (topline < 1)
{
topline = 1;
}
mustredraw = TRUE;
redrawafter = INFINITY;
preredraw = 0L;
postredraw = 0L;
}
/* Now... do we really have to redraw? */
if (mustredraw)
{
/* If redrawfter (and friends) aren't set, assume we should
* redraw everything.
*/
if (redrawafter == INFINITY)
{
redrawafter = 0L;
preredraw = postredraw = INFINITY;
}
/* adjust smartlno to correspond with inserted/deleted lines */
if (smartlno >= redrawafter)
{
if (smartlno < preredraw)
{
smartlno = 0L;
}
else
{
smartlno += (postredraw - preredraw);
}
}
/* should we insert some lines into the screen? */
if (preredraw < postredraw && preredraw <= botline)
{
/* lines were inserted into the file */
/* decide where insertion should start */
if (preredraw < topline)
{
l = topline;
}
else
{
l = preredraw;
}
/* insert the lines... maybe */
if (l + postredraw - preredraw > botline || !has_AL)
{
/* Whoa! a whole screen full - just redraw */
preredraw = postredraw = INFINITY;
}
else
{
/* really insert 'em */
move((int)(l - topline), 0);
for (i = postredraw - preredraw; i > 0; i--)
{
insertln();
}
/* NOTE: the contents of those lines will be
* drawn as part of the regular redraw loop.
*/
/* clear the last line */
move(LINES - 1, 0);
clrtoeol();
}
}
/* do we want to delete some lines from the screen? */
if (preredraw > postredraw && postredraw <= botline)
{
if (preredraw > botline || !has_DL)
{
postredraw = preredraw = INFINITY;
}
else /* we'd best delete some lines from the screen */
{
/* clear the last line, so it doesn't look
* ugly as it gets pulled up into the screen
*/
move(LINES - 1, 0);
clrtoeol();
/* delete the lines */
move((int)(postredraw - topline), 0);
for (l = postredraw;
l < preredraw && l <= botline;
l++)
{
deleteln();
}
/* draw the lines that are now newly visible
* at the bottom of the screen
*/
i = LINES - 1 + (postredraw - preredraw);
move(i, 0);
for (l = topline + i; l <= botline; l++)
{
/* clear this line */
clrtoeol();
/* draw the line, or ~ for non-lines */
if (l <= nlines)
{
text = fetchline(l);
drawtext(text);
}
else
{
addstr("~\n");
}
}
}
}
/* redraw the current line */
l = markline(curs);
pfetch(l);
smartdrawtext(ptext, l);
/* decide where we should start redrawing from */
if (redrawafter < topline)
{
l = topline;
}
else
{
l = redrawafter;
}
move((int)(l - topline), 0);
/* draw the other lines */
for (; l <= botline && l < postredraw; l++)
{
/* we already drew the current line, so skip it now */
if (l == smartlno)
{
qaddch('\n');
continue;
}
/* clear this line */
clrtoeol();
/* draw the line, or ~ for non-lines */
if (l <= nlines)
{
text = fetchline(l);
drawtext(text);
}
else
{
addstr("~\n");
}
}
mustredraw = FALSE;
}
/* force total (non-partial) redraw next time if not set */
redrawafter = INFINITY;
preredraw = 0L;
postredraw = 0L;
/* move the cursor to where it belongs */
move((int)(markline(curs) - topline), physcol);
wqrefresh(stdscr);
chgs = changes;
}
/* This function converts a MARK to a column number. It doesn't automatically
* adjust for leftcol; that must be done by the calling function
*/
int idx2col(curs, text, inputting)
MARK curs; /* the line# & index# of the cursor */
register char *text; /* the text of the line, from fetchline */
int inputting; /* boolean: called from input() ? */
{
static MARK pcursor;/* previous cursor, for possible shortcut */
static MARK pcol; /* column number for pcol */
static long chgs; /* previous value of changes counter */
register int col; /* used to count column numbers */
register int idx; /* used to count down the index */
register int i;
/* for now, assume we have to start counting at the left edge */
col = 0;
idx = markidx(curs);
/* if the file hasn't changed & line number is the same & it has no
* embedded character attribute strings, can we do shortcuts?
*/
if (chgs == changes
&& !((curs ^ pcursor) & ~(BLKSIZE - 1))
#ifndef NO_CHARATTR
&& !hasattr(markline(curs), text)
#endif
)
{
/* no movement? */
if (curs == pcursor)
{
/* return the column of the char; for tabs, return its last column */
if (text[idx] == '\t' && !inputting && !*o_list)
{
return pcol + *o_tabstop - (pcol % *o_tabstop) - 1;
}
else
{
return pcol;
}
}
/* movement to right? */
if (curs > pcursor)
{
/* start counting from previous place */
col = pcol;
idx = markidx(curs) - markidx(pcursor);
text += markidx(pcursor);
}
}
/* count over to the char after the idx position */
while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */
{
if (i == '\t' && !*o_list)
{
col += *o_tabstop;
col -= col % *o_tabstop;
}
else if (i >= '\0' && i < ' ' || i == '\177')
{
col += 2;
}
#ifndef NO_CHARATTR
else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
{
text += 2; /* plus one more at bottom of loop */
idx -= 2;
}
#endif
else
{
col++;
}
text++;
idx--;
}
/* save stuff to speed next call */
pcursor = curs;
pcol = col;
chgs = changes;
/* return the column of the char; for tabs, return its last column */
if (*text == '\t' && !inputting && !*o_list)
{
return col + *o_tabstop - (col % *o_tabstop) - 1;
}
else
{
return col;
}
}
/* This function is similar to idx2col except that it takes care of sideways
* scrolling - for the given line, at least.
*/
mark2phys(m, text, inputting)
MARK m; /* a mark to convert */
char *text; /* the line that m refers to */
int inputting; /* boolean: caled from input() ? */
{
int i;
i = idx2col(cursor, text, inputting);
while (i < leftcol)
{
leftcol -= *o_sidescroll;
mustredraw = TRUE;
redrawrange(1L, INFINITY, INFINITY);
qaddch('\r');
/* drawtext(text); */
}
while (i > rightcol)
{
leftcol += *o_sidescroll;
mustredraw = TRUE;
redrawrange(1L, INFINITY, INFINITY);
qaddch('\r');
/* drawtext(text); */
}
physcol = i - leftcol;
physrow = markline(m) - topline;
return physcol;
}
/* This function draws a single line of text on the screen. The screen's
* cursor is assumed to be located at the leftmost column of the appropriate
* row.
*/
drawtext(text)
register char *text; /* the text to draw */
{
register int col; /* column number */
register int i;
register int tabstop; /* *o_tabstop */
register int limitcol; /* leftcol or leftcol + COLS */
int abnormal; /* boolean: charattr != A_NORMAL? */
#ifndef NO_SENTENCE
/* if we're hiding format lines, and this is one of them, then hide it */
if (*o_hideformat && *text == '.')
{
clrtoeol();
qaddch('\n');
return;
}
#endif
/* move some things into registers... */
limitcol = leftcol;
tabstop = *o_tabstop;
abnormal = FALSE;
/* skip stuff that was scrolled off left edge */
for (col = 0;
(i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
text++)
{
if (i == '\t' && !*o_list)
{
col = col + tabstop - (col % tabstop);
}
else if (i >= 0 && i < ' ' || i == '\177')
{
col += 2;
}
#ifndef NO_CHARATTR
else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
{
text += 2; /* plus one more as part of "for" loop */
/* since this attribute might carry over, we need it */
switch (*text)
{
case 'R':
case 'P':
attrset(A_NORMAL);
abnormal = FALSE;
break;
case 'B':
attrset(A_BOLD);
abnormal = TRUE;
break;
case 'U':
attrset(A_UNDERLINE);
abnormal = TRUE;
break;
case 'I':
attrset(A_ALTCHARSET);
abnormal = TRUE;
break;
}
}
#endif
else
{
col++;
}
}
/* adjust for control char that was partially visible */
while (col > limitcol)
{
qaddch(' ');
limitcol++;
}
/* now for the visible characters */
for (limitcol = leftcol + COLS;
(i = *text) && col < limitcol;
text++)
{
if (i == '\t' && !*o_list)
{
i = col + tabstop - (col % tabstop);
if (i < limitcol)
{
if (has_PT && !((i - leftcol) & 7))
{
do
{
qaddch('\t');
col += 8; /* not exact! */
} while (col < i);
col = i; /* NOW it is exact */
}
else
{
do
{
qaddch(' ');
col++;
} while (col < i);
}
}
else /* tab ending after screen? next line! */
{
col = limitcol;
if (has_AM)
{
qaddch('\r'); /* GB */
qaddch('\n'); /* GB */
}
}
}
else if (i >= 0 && i < ' ' || i == '\177')
{
col += 2;
if (col < limitcol)
{
qaddch('^');
qaddch(i ^ '@');
}
}
#ifndef NO_CHARATTR
else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
{
text += 2; /* plus one more as part of "for" loop */
switch (*text)
{
case 'R':
case 'P':
attrset(A_NORMAL);
abnormal = FALSE;
break;
case 'B':
attrset(A_BOLD);
abnormal = TRUE;
break;
case 'U':
attrset(A_UNDERLINE);
abnormal = TRUE;
break;
case 'I':
attrset(A_ALTCHARSET);
abnormal = TRUE;
break;
}
}
#endif
else
{
col++;
qaddch(i);
}
}
/* get ready for the next line */
#ifndef NO_CHARATTR
if (abnormal)
{
attrset(A_NORMAL);
}
#endif
if (*o_list && col < limitcol)
{
qaddch('$');
col++;
}
if (!has_AM || col < limitcol)
{
qaddch('\r');
qaddch('\n');
}
}
static nudgecursor(same, scan, new, lno)
int same; /* number of chars to be skipped over */
char *scan; /* where the same chars end */
char *new; /* where the visible part of the line starts */
long lno; /* line number of this line */
{
if (same > 0)
{
if (same < 5)
{
/* move the cursor by overwriting */
while (same > 0)
{
qaddch(scan[-same]);
same--;
}
}
else
{
/* move the cursor by calling move() */
move((int)(lno - topline), (int)(scan - new));
}
}
}
/* This function draws a single line of text on the screen, possibly with
* some cursor optimization. The cursor is repositioned before drawing
* begins, so its position before doesn't really matter.
*/
smartdrawtext(text, lno)
register char *text; /* the text to draw */
long lno; /* line number of the text */
{
static char old[256]; /* how the line looked last time */
char new[256]; /* how it looks now */
char *build; /* used to put chars into new[] */
char *scan; /* used for moving thru new[] or old[] */
char *end; /* last non-blank changed char */
char *shift; /* used to insert/delete chars */
int same; /* length of a run of unchanged chars */
int limitcol;
int col;
int i;
#ifndef NO_CHARATTR
/* if this line has attributes, do it the dumb way instead */
if (hasattr(lno, text))
{
move((int)(lno - topline), 0);
clrtoeol();
drawtext(text);
return;
}
#endif
#ifndef NO_SENTENCE
/* if this line is a format line, & we're hiding format lines, then
* let the dumb drawtext() function handle it
*/
if (*o_hideformat && *text == '.')
{
move((int)(lno - topline), 0);
clrtoeol();
drawtext(text);
return;
}
#endif
/* skip stuff that was scrolled off left edge */
limitcol = leftcol;
for (col = 0;
(i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
text++)
{
if (i == '\t' && !*o_list)
{
col = col + *o_tabstop - (col % *o_tabstop);
}
else if (i >= 0 && i < ' ' || i == '\177')
{
col += 2;
}
else
{
col++;
}
}
/* adjust for control char that was partially visible */
build = new;
while (col > limitcol)
{
*build++ = ' ';
limitcol++;
}
/* now for the visible characters */
for (limitcol = leftcol + COLS;
(i = *text) && col < limitcol;
text++)
{
if (i == '\t' && !*o_list)
{
i = col + *o_tabstop - (col % *o_tabstop);
while (col < i && col < limitcol)
{
*build++ = ' ';
col++;
}
}
else if (i >= 0 && i < ' ' || i == '\177')
{
col += 2;
*build++ = '^';
if (col < limitcol)
{
*build++ = (i ^ '@');
}
}
else
{
col++;
*build++ = i;
}
}
if (col < limitcol && *o_list)
{
*build++ = '$';
col++;
}
end = build;
while (col < limitcol)
{
*build++ = ' ';
col++;
}
/* locate the last non-blank character */
while (end > new && end[-1] == ' ')
{
end--;
}
/* can we optimize the displaying of this line? */
if (lno != smartlno)
{
/* nope, can't optimize - different line */
move((int)(lno - topline), 0);
for (scan = new, build = old; scan < end; )
{
qaddch(*scan);
*build++ = *scan++;
}
if (end < new + COLS)
{
clrtoeol();
while (build < old + COLS)
{
*build++ = ' ';
}
}
smartlno = lno;
return;
}
/* skip any initial unchanged characters */
for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
{
}
move((int)(lno - topline), (int)(scan - new));
/* The in-between characters must be changed */
same = 0;
while (scan < end)
{
/* is this character a match? */
if (scan[0] == build[0])
{
same++;
}
else /* do we want to insert? */
if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM))
{
nudgecursor(same, scan, new, lno);
same = 0;
insch(*scan);
for (shift = old + COLS; --shift > build; )
{
shift[0] = shift[-1];
}
*build = *scan;
}
else /* do we want to delete? */
if (build < old + COLS - 1 && scan[0] == build[1] && has_DC)
{
nudgecursor(same, scan, new, lno);
same = 0;
delch();
same++;
for (shift = build; shift < old + COLS - 1; shift++)
{
shift[0] = shift[1];
}
*shift = ' ';
}
else /* we must overwrite */
{
nudgecursor(same, scan, new, lno);
same = 0;
addch(*scan);
*build = *scan;
}
build++;
scan++;
}
/* maybe clear to EOL */
while (build < old + COLS && *build == ' ')
{
build++;
}
if (build < old + COLS)
{
nudgecursor(same, scan, new, lno);
same = 0;
clrtoeol();
while (build < old + COLS)
{
*build++ = ' ';
}
}
}
#ifndef NO_CHARATTR
/* see if a given line uses character attribute strings */
int hasattr(lno, text)
long lno; /* the line# of the cursor */
register char *text; /* the text of the line, from fetchline */
{
static long plno; /* previous line number */
static long chgs; /* previous value of changes counter */
static int panswer;/* previous answer */
char *scan;
/* if charattr is off, then the answer is "no, it doesn't" */
if (!*o_charattr)
{
chgs = 0; /* <- forces us to check if charattr is later set */
return FALSE;
}
/* if we already know the answer, return it... */
if (lno == plno && chgs == changes)
{
return panswer;
}
/* get the line & look for "\fX" */
if (!text[0] || !text[1] || !text[2])
{
panswer = FALSE;
}
else
{
for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++)
{
}
panswer = (scan[2] != '\0');
}
/* save the results */
plno = lno;
chgs = changes;
/* return the results */
return panswer;
}
#endif
SHAR_EOF
fi
exit 0
# End of shell archive
-------------------------------------------------------------------------------
Steve Kirkendall kirkenda at cs.pdx.edu uunet!tektronix!psueea!eecs!kirkenda
More information about the Alt.sources
mailing list