elvis 1.3 - a clone of vi/ex, part 6 of 6
Steve Kirkendall
kirkenda at eecs.cs.pdx.edu
Sat Aug 25 04:00:44 AEST 1990
Archive-name: elvis1.3/part6
#! /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:
# vars.c
# vcmd.c
# vi.c
# vi.h
# ctags.c
# ref.c
# virec.c
# wildcard.c
# shell.c
# This archive created: Fri Aug 24 10:30:00 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'vars.c'
then
echo shar: "will not over-write existing file 'vars.c'"
else
cat << \SHAR_EOF > 'vars.c'
/* vars.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains variables which weren't happy anyplace else */
#include "config.h"
#include "vi.h"
/*------------------------------------------------------------------------*/
/* used to remember whether the file has been modified */
struct _viflags viflags;
/* used to access the tmp file */
long lnum[MAXBLKS];
long nlines;
int tmpfd = -1;
/* used to keep track of the current file & alternate file */
long origtime;
char origname[256];
char prevorig[256];
long prevline = 1;
/* used to track various places in the text */
MARK mark[NMARKS]; /* marks 'a through 'z, plus mark '' */
MARK cursor; /* the cursor position within the file */
/* which mode of the editor we're in */
int mode; /* vi mode? ex mode? quitting? */
/* used to manage the args list */
char args[BLKSIZE]; /* list of filenames to edit */
int argno; /* index of current file in args list */
int nargs; /* number of filenames in args[] */
/* dummy var, never explicitly referenced */
int bavar; /* used only in BeforeAfter macros */
/* have we made a multi-line change? */
int mustredraw; /* must we redraw the whole screen? */
long redrawafter; /* line# of first line that must be redrawn */
long preredraw; /* line# of last line changed, before change */
long postredraw; /* line# of last line changed, after change */
/* (postredraw - preredraw) = #lines added */
/* used to detect changes that invalidate cached text/blocks */
long changes; /* incremented when file is changed */
/* used to support the pfetch() macro */
int plen; /* length of the line */
long pline; /* line number that len refers to */
long pchgs; /* "changes" level that len refers to */
char *ptext; /* text of previous line, if valid */
/* misc temporary storage - mostly for strings */
BLK tmpblk; /* a block used to accumulate changes */
/* screen oriented stuff */
long topline; /* file line number of top line */
int leftcol; /* column number of left col */
int physcol; /* physical column number that cursor is on */
int physrow; /* physical row number that cursor is on */
/* used to help minimize that "[Hit a key to continue]" message */
int exwrote; /* Boolean: was the last ex command wordy? */
/* This variable affects the behaviour of certain functions -- most importantly
* the input function.
*/
int doingdot; /* boolean: are we doing the "." command? */
/* These are used for reporting multi-line changes to the user */
long rptlines; /* number of lines affected by a command */
char *rptlabel; /* description of how lines were affected */
/* These store info that pertains to the shift-U command */
long U_line; /* line# of the undoable line, or 0l for none */
char U_text[BLKSIZE]; /* contents of the undoable line */
/* Bigger stack req'ed for TOS */
#if TOS
long _stksize = 16384;
#endif
SHAR_EOF
fi
if test -f 'vcmd.c'
then
echo shar: "will not over-write existing file 'vcmd.c'"
else
cat << \SHAR_EOF > 'vcmd.c'
/* vcmd.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the functions that handle VI commands */
#include "config.h"
#include "vi.h"
#if MSDOS
#include <process.h>
#include <string.h>
#endif
#if TOS
#include <osbind.h>
#include <string.h>
#endif
/* This function puts the editor in EX mode */
MARK v_quit()
{
mode = MODE_EX;
return cursor;
}
/* This function causes the screen to be redrawn */
MARK v_redraw()
{
redraw(MARK_UNSET, FALSE);
return cursor;
}
/* This function executes a single EX command, and waits for a user keystroke
* before returning to the VI screen. If that keystroke is another ':', then
* another EX command is read and executed.
*/
/*ARGSUSED*/
MARK v_1ex(m, text)
MARK m; /* the current line */
char *text; /* the first command to execute */
{
/* scroll up, so we don't overwrite the command */
if (mode == MODE_COLON)
{
addch('\n');
refresh();
}
/* run the command. be careful about modes & output */
exwrote = (mode == MODE_COLON);
doexcmd(text);
exrefresh();
/* if mode is no longer MODE_VI, then we should quit right away! */
if (mode != MODE_VI && mode != MODE_COLON)
return cursor;
/* The command did some output. Wait for a keystoke. */
if (exwrote)
{
mode = MODE_VI;
msg("[Hit any key to continue]");
if (getkey(0) == ':')
{ mode = MODE_COLON;
addch('\n');
}
else
redraw(MARK_UNSET, FALSE);
}
return cursor;
}
/* This function undoes the last change */
/*ARGSUSED*/
MARK v_undo(m)
MARK m; /* (ignored) */
{
undo();
redraw(MARK_UNSET, FALSE);
return cursor;
}
/* This function deletes the character(s) that the cursor is on */
MARK v_xchar(m, cnt)
MARK m; /* where to start deletions */
long cnt; /* number of chars to delete */
{
DEFAULT(1);
pfetch(markline(m));
if (markidx(m + cnt) > plen)
{
cnt = plen - markidx(m);
}
if (cnt == 0L)
{
return MARK_UNSET;
}
ChangeText
{
cut(m, m + cnt);
delete(m, m + cnt);
}
return m;
}
/* This function deletes character to the left of the cursor */
MARK v_Xchar(m, cnt)
MARK m; /* where deletions end */
long cnt; /* number of chars to delete */
{
DEFAULT(1);
/* if we're at the first char of the line, error! */
if (markidx(m) == 0)
{
return MARK_UNSET;
}
/* make sure we don't try to delete more chars than there are */
if (cnt > markidx(m))
{
cnt = markidx(m);
}
/* delete 'em */
ChangeText
{
cut(m - cnt, m);
delete(m - cnt, m);
}
return m - cnt;
}
/* This function defines a mark */
/*ARGSUSED*/
MARK v_mark(m, count, key)
MARK m; /* where the mark will be */
long count; /* (ignored) */
int key; /* the ASCII label of the mark */
{
if (key < 'a' || key > 'z')
{
msg("Marks must be from a to z");
}
else
{
mark[key - 'a'] = m;
}
return m;
}
/* This function toggles upper & lower case letters */
MARK v_ulcase(m)
MARK m; /* where to make the change */
{
char new[2];
#if MSDOS || TOS
char *pos;
char *lower="\207\201\202\204\206\221\224\244";
char *upper="\200\232\220\216\217\222\231\245";
#endif
/* extract the char that's there now */
pfetch(markline(m));
new[0] = ptext[markidx(m)];
new[1] = '\0';
/* change it if necessary */
if (new[0] >= 'a' && new[0] <= 'z' || new[0] >= 'A' && new[0] <= 'Z')
{
new[0] ^= ('A' ^ 'a');
ChangeText
{
change(m, m + 1, new);
}
}
#if MSDOS || TOS
if ((pos=strchr(lower, new[0]))!=0)
new[0]=upper[(int)(pos-lower)];
else if ((pos=strchr(upper, new[0]))!=0)
new[0]=lower[(int)(pos-upper)];
else
goto nochange; /* Urghh - GB */
ChangeText
{
change(m, m + 1, new);
}
nochange:
#endif
if (new[0] && ptext[markidx(m) + 1])
{
m++;
}
return m;
}
MARK v_replace(m, cnt, key)
MARK m; /* first char to be replaced */
long cnt; /* number of chars to replace */
int key; /* what to replace them with */
{
register char *text;
register int i;
static int samekey;
DEFAULT(1);
/* map ^M to '\n' */
if (key == '\r')
{
key = '\n';
}
else if (key == ctrl('V'))
{
if (doingdot)
key = samekey;
else
key = samekey = getkey(0);
if (key == 0)
return MARK_UNSET;
}
else if (!doingdot && key == ctrl('['))
{
samekey = 0;
return MARK_UNSET;
}
/* make sure the resulting line isn't too long */
if (cnt > BLKSIZE - 2 - markidx(m))
{
cnt = BLKSIZE - 2 - markidx(m);
}
/* build a string of the desired character with the desired length */
for (text = tmpblk.c, i = cnt; i > 0; i--)
{
*text++ = key;
}
*text = '\0';
/* make sure cnt doesn't extend past EOL */
pfetch(markline(m));
key = markidx(m);
if (key + cnt > plen)
{
cnt = plen - key;
}
/* do the replacement */
ChangeText
{
change(m, m + cnt, tmpblk.c);
}
if (*tmpblk.c == '\n')
{
return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
}
else
{
return m + cnt - 1;
}
}
MARK v_overtype(m)
MARK m; /* where to start overtyping */
{
MARK end; /* end of a substitution */
static long width; /* width of a single-line replace */
/* the "doingdot" version of replace is really a substitution */
if (doingdot)
{
/* was the last one really repeatable? */
if (width < 0)
{
msg("Can't repeat a multi-line overtype command");
return MARK_UNSET;
}
/* replacing nothing by nothing? Don't bother */
if (width == 0)
{
return m;
}
/* replace some chars by repeated text */
return v_subst(m, width);
}
/* Normally, we input starting here, in replace mode */
ChangeText
{
end = input(m, m, WHEN_VIREP);
}
/* if we ended on the same line we started on, then this
* overtype is repeatable via the dot key.
*/
if (markline(end) == markline(m) && end >= m - 1L)
{
width = end - m + 1L;
}
else /* it isn't repeatable */
{
width = -1L;
}
return end;
}
/* This function selects which cut buffer to use */
/*ARGSUSED*/
MARK v_selcut(m, cnt, key)
MARK m;
long cnt;
int key;
{
cutname(key);
return m;
}
/* This function pastes text from a cut buffer */
/*ARGSUSED*/
MARK v_paste(m, cnt, cmd)
MARK m; /* where to paste the text */
long cnt; /* (ignored) */
int cmd; /* either 'p' or 'P' */
{
ChangeText
{
m = paste(m, cmd == 'p', FALSE);
}
return m;
}
/* This function yanks text into a cut buffer */
MARK v_yank(m, n)
MARK m, n; /* range of text to yank */
{
cut(m, n);
return m;
}
/* This function deletes a range of text */
MARK v_delete(m, n)
MARK m, n; /* range of text to delete */
{
/* illegal to try and delete nothing */
if (n <= m)
{
return MARK_UNSET;
}
/* Do it */
ChangeText
{
cut(m, n);
delete(m, n);
}
return m;
}
/* This starts input mode without deleting anything */
MARK v_insert(m, cnt, key)
MARK m; /* where to start (sort of) */
long cnt; /* repeat how many times? */
int key; /* what command is this for? {a,A,i,I,o,O} */
{
int wasdot;
long reps;
DEFAULT(1);
ChangeText
{
/* tweak the insertion point, based on command key */
switch (key)
{
case 'i':
break;
case 'a':
pfetch(markline(m));
if (plen > 0)
{
m++;
}
break;
case 'I':
m = m_front(m, 1L);
break;
case 'A':
pfetch(markline(m));
m = (m & ~(BLKSIZE - 1)) + plen;
break;
case 'O':
m &= ~(BLKSIZE - 1);
add(m, "\n");
break;
case 'o':
m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
add(m, "\n");
break;
}
/* insert the same text once or more */
for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
{
m = input(m, m, WHEN_VIINP);
}
/* compensate for inaccurate redraw clues from input() */
if ((key == 'O' || key == 'o') && wasdot)
{
redraw(MARK_UNSET);
}
doingdot = FALSE;
}
return m;
}
/* This starts input mode with some text deleted */
MARK v_change(m, n)
MARK m, n; /* the range of text to change */
{
int lnmode; /* is this a line-mode change? */
/* swap them if they're in reverse order */
if (m > n)
{
MARK tmp;
tmp = m;
m = n;
n = tmp;
}
/* for line mode, retain the last newline char */
lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
if (lnmode)
{
n -= BLKSIZE;
pfetch(markline(n));
n = (n & ~(BLKSIZE - 1)) + plen;
}
ChangeText
{
cut(m, n);
m = input(m, n, WHEN_VIINP);
}
/* compensate for inaccurate redraw clues from paste() */
if (doingdot)
{
preredraw = markline(n);
if (lnmode)
{
preredraw++;
postredraw++;
}
}
return m;
}
/* This function replaces a given number of characters with input */
MARK v_subst(m, cnt)
MARK m; /* where substitutions start */
long cnt; /* number of chars to replace */
{
DEFAULT(1);
/* make sure we don't try replacing past EOL */
pfetch(markline(m));
if (markidx(m) + cnt > plen)
{
cnt = plen - markidx(m);
}
/* Go for it! */
ChangeText
{
cut(m, m + cnt);
m = input(m, m + cnt, WHEN_VIINP);
}
return m;
}
/* This calls the ex "join" command to join some lines together */
MARK v_join(m, cnt)
MARK m; /* the first line to be joined */
long cnt; /* number of other lines to join */
{
MARK joint; /* where the lines were joined */
DEFAULT(1);
/* figure out where the joint will be */
pfetch(markline(m));
joint = (m & ~(BLKSIZE - 1)) + plen;
/* join the lines */
cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
mustredraw = TRUE;
/* the cursor should be left at the joint */
return joint;
}
/* This calls the ex shifter command to shift some lines */
static MARK shift_help(m, n, excmd)
MARK m, n; /* range of lines to shift */
CMD excmd; /* which way do we shift? */
{
/* make sure our endpoints aren't in reverse order */
if (m > n)
{
MARK tmp;
tmp = n;
n = m;
m = tmp;
}
/* linemode? adjust for inclusive endmarks in ex */
if (markidx(m) == 0 && markidx(n) == 0)
{
n -= BLKSIZE;
}
cmd_shift(m, n, excmd, 0, "");
return m;
}
/* This calls the ex "<" command to shift some lines left */
MARK v_lshift(m, n)
MARK m, n; /* range of lines to shift */
{
return shift_help(m, n, CMD_SHIFTL);
}
/* This calls the ex ">" command to shift some lines right */
MARK v_rshift(m, n)
MARK m, n; /* range of lines to shift */
{
return shift_help(m, n, CMD_SHIFTR);
}
/* This runs some lines through a filter program */
MARK v_filter(m, n)
MARK m, n; /* range of lines to shift */
{
char cmdln[100]; /* a shell command line */
/* linemode? adjust for inclusive endmarks in ex */
if (markidx(m) == 0 && markidx(n) == 0)
{
n -= BLKSIZE;
}
if (vgets('!', cmdln, sizeof(cmdln)) > 0)
{
filter(m, n, cmdln);
}
redraw(MARK_UNSET, FALSE);
return m;
}
/* This function runs the ex "file" command to show the file's status */
MARK v_status()
{
cmd_file(cursor, cursor, CMD_FILE, 0, "");
return cursor;
}
/* This function switches to the previous file, if possible */
MARK v_switch()
{
if (!*prevorig)
msg("No previous file");
else
{ strcpy(tmpblk.c, prevorig);
cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
}
return cursor;
}
/* This function does a tag search on a keyword */
/*ARGSUSED*/
MARK v_tag(keyword, m, cnt)
char *keyword;
MARK m;
long cnt;
{
/* remember the initial change level */
cnt = changes;
/* move the cursor to the start of the tag name, where m is */
cursor = m;
/* perform the tag search */
cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
return cursor;
}
#ifndef NO_EXTENSIONS
/* This function looks up a keyword by calling the helpprog program */
/*ARGSUSED*/
MARK v_keyword(keyword, m, cnt)
char *keyword;
MARK m;
long cnt;
{
int status;
#if TOS
char cmdline[130];
#endif
move(LINES - 1, 0);
addstr("---------------------------------------------------------\n");
clrtoeol();
refresh();
suspend_curses();
#if ANY_UNIX
switch (fork())
{
case -1: /* error */
break;
case 0: /* child */
execl(o_keywordprg, o_keywordprg, keyword, (char *)0);
exit(2); /* if we get here, the exec failed */
default: /* parent */
wait(&status);
if (status > 0)
{
write(2, "<<< failed >>>\n", 15);
}
}
#endif
#if MSDOS
if ((status=spawnlp(P_WAIT, o_keywordprg, o_keywordprg, keyword,
(char *)0))==-1)
write(2, "<<< failed >>>\n", 15);
#endif
#if TOS
strcpy(cmdline+1, keyword);
cmdline[0]=strlen(keyword);
if ((status=Pexec(0, o_keywordprg, cmdline, "\0"))<0)
write(2, "<<< failed >>>\n", 15);
#endif
resume_curses(FALSE); /* "resume, but not quietly" */
redraw(MARK_UNSET, FALSE);
return m;
}
MARK v_increment(keyword, m, cnt)
char *keyword;
MARK m;
long cnt;
{
static sign;
char newval[12];
long atol();
DEFAULT(1);
/* get one more keystroke, unless doingdot */
if (!doingdot)
{
sign = getkey(0);
}
/* adjust the number, based on that second keystroke */
switch (sign)
{
case '+':
case '#':
cnt = atol(keyword) + cnt;
break;
case '-':
cnt = atol(keyword) - cnt;
break;
case '=':
break;
default:
return MARK_UNSET;
}
sprintf(newval, "%ld", cnt);
ChangeText
{
change(m, m + strlen(keyword), newval);
}
return m;
}
#endif
/* This function acts like the EX command "xit" */
/*ARGSUSED*/
MARK v_xit(m, cnt, key)
MARK m; /* ignored */
long cnt; /* ignored */
int key; /* must be a second 'Z' */
{
/* if second char wasn't 'Z', fail */
if (key != 'Z')
{
return MARK_UNSET;
}
/* move the physical cursor to the end of the screen */
move(LINES - 1, 0);
clrtoeol();
refresh();
/* do the xit command */
cmd_xit(m, m, CMD_XIT, FALSE, "");
/* if we're really going to quit, then scroll the screen up 1 line */
if (mode == MODE_QUIT)
{
addch('\n');
refresh();
}
/* regardless of whether we succeeded or failed, return the cursor */
return m;
}
/* This function undoes changes to a single line, if possible */
MARK v_undoline(m)
MARK m; /* where we hope to undo the change */
{
if (markline(m) != U_line)
{
return MARK_UNSET;
}
ChangeText
{
changeline(U_line, U_text);
}
return m & ~(BLKSIZE - 1);
}
SHAR_EOF
fi
if test -f 'vi.c'
then
echo shar: "will not over-write existing file 'vi.c'"
else
cat << \SHAR_EOF > 'vi.c'
/* vi.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
#include "config.h"
#include <ctype.h>
#include "vi.h"
/* This array describes what each key does */
#define NO_FUNC (MARK (*)())0
#define NO_ARGS 0
#define CURSOR_COUNT 1
#define CURSOR 2
#define CURSOR_CNT_KEY 3
#define CURSOR_MOVED 4
#define CURSOR_EOL 5
#define ZERO 6
#define DIGIT 7
#define CURSOR_TEXT 8
#define CURSOR_CNT_CMD 9
#define KEYWORD 10
#define NO_FLAGS 0x00
#define MVMT 0x01 /* this is a movement command */
#define PTMV 0x02 /* this can be *part* of a movement command */
#define FRNT 0x04 /* after move, go to front of line */
#define INCL 0x08 /* include last char when used with c/d/y */
#define LNMD 0x10 /* use line mode of c/d/y */
#define NCOL 0x20 /* this command can't change the column# */
#define NREL 0x40 /* this is "non-relative" -- set the '' mark */
#define SDOT 0x80 /* set the "dot" variables, for the "." cmd */
static struct keystru
{
MARK (*func)(); /* the function to run */
char args; /* description of the args needed */
char flags; /* other stuff */
}
vikeys[] =
{
/* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^B page backward */ {m_scroll, CURSOR_CNT_CMD, FRNT},
/* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^D scroll dn 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL},
/* ^E scroll up */ {m_scroll, CURSOR_CNT_CMD, NCOL},
/* ^F page forward */ {m_scroll, CURSOR_CNT_CMD, FRNT},
/* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS},
/* ^H move left, like h*/ {m_left, CURSOR_COUNT, MVMT},
/* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^J move down */ {m_down, CURSOR_COUNT, MVMT|LNMD},
/* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS},
/* ^M mv front next ln */ {m_down, CURSOR_COUNT, MVMT|FRNT|LNMD},
/* ^N move down */ {m_down, CURSOR_COUNT, MVMT|LNMD},
/* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^P not defined */ {m_up, CURSOR_COUNT, MVMT|LNMD},
/* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS},
/* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^U scroll up 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL},
/* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^X not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^Y scroll down */ {m_scroll, CURSOR_CNT_CMD, NCOL},
/* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS},
/* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS},
/* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* SPC move right,like l*/ {m_right, CURSOR_COUNT, MVMT},
/* ! run thru filter */ {v_filter, CURSOR_MOVED, NO_FLAGS},
/* " select cut buffer*/ {v_selcut, CURSOR_CNT_KEY, PTMV},
#ifndef NO_EXTENSIONS
/* # increment number */ {v_increment, KEYWORD, SDOT},
#else
/* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* $ move to rear */ {m_rear, CURSOR, MVMT|INCL},
/* % move to match */ {m_match, CURSOR, MVMT|INCL},
/* & not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ' move to a mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|FRNT|NREL|LNMD},
#ifndef NO_SENTENCE
/* ( mv back sentence */ {m_bsentence, CURSOR_COUNT, MVMT},
/* ) mv fwd sentence */ {m_fsentence, CURSOR_COUNT, MVMT},
#else
/* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* + mv front next ln */ {m_down, CURSOR_COUNT, MVMT|FRNT|LNMD},
#ifndef NO_CHARSEARCH
/* , reverse [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL},
#else
/* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* - mv front prev ln */ {m_up, CURSOR_COUNT, MVMT|FRNT|LNMD},
/* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL},
/* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV},
/* 1 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 2 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 3 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 4 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 5 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 6 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 7 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 8 part of count */ {NO_FUNC, DIGIT, PTMV},
/* 9 part of count */ {NO_FUNC, DIGIT, PTMV},
/* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS},
#ifndef NO_CHARSEARCH
/* ; repeat [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL},
#else
/* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT},
/* = not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT},
/* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL},
/* @ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* A append at EOL */ {v_insert, CURSOR_CNT_CMD, SDOT},
/* B move back Word */ {m_bWord, CURSOR_COUNT, MVMT},
/* C change to EOL */ {v_change, CURSOR_EOL, SDOT},
/* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT},
/* E move end of Word */ {m_eWord, CURSOR_COUNT, MVMT|INCL},
#ifndef NO_CHARSEARCH
/* F move bk to char */ {m_Fch, CURSOR_CNT_KEY, MVMT|INCL},
#else
/* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* G move to line # */ {m_toline, CURSOR_COUNT, MVMT|NREL|LNMD},
/* H move to row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT},
/* I insert at front */ {v_insert, CURSOR_CNT_CMD, SDOT},
/* J join lines */ {v_join, CURSOR_COUNT, SDOT},
#ifndef NO_EXTENSIONS
/* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS},
#else
/* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* L move to last row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT},
/* M move to mid row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT},
/* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT},
/* O insert above line*/ {v_insert, CURSOR_CNT_CMD, SDOT},
/* P paste before */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS},
/* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS},
/* R overtype */ {v_overtype, CURSOR, SDOT},
/* S change line */ {v_change, CURSOR_MOVED, SDOT},
#ifndef NO_CHARSEARCH
/* T move bk to char */ {m_Tch, CURSOR_CNT_KEY, MVMT|INCL},
#else
/* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* U undo whole line */ {v_undoline, CURSOR, FRNT},
/* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* W move forward Word*/ {m_fWord, CURSOR_COUNT, MVMT},
/* X delete to left */ {v_Xchar, CURSOR_COUNT, SDOT},
/* Y yank text */ {v_yank, CURSOR_MOVED, NO_FLAGS},
/* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS},
/* [ move back section*/ {m_bsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL},
/* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ] move fwd section */ {m_fsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL},
/* ^ move to front */ {m_front, CURSOR, MVMT},
/* _ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* ` move to mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|NREL},
/* a append at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT},
/* b move back word */ {m_bword, CURSOR_COUNT, MVMT},
/* c change text */ {v_change, CURSOR_MOVED, SDOT},
/* d delete op */ {v_delete, CURSOR_MOVED, SDOT},
/* e move end word */ {m_eword, CURSOR_COUNT, MVMT|INCL},
#ifndef NO_CHARSEARCH
/* f move fwd for char*/ {m_fch, CURSOR_CNT_KEY, MVMT|INCL},
#else
/* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* h move left */ {m_left, CURSOR_COUNT, MVMT},
/* i insert at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT},
/* j move down */ {m_down, CURSOR_COUNT, MVMT|NCOL|LNMD},
/* k move up */ {m_up, CURSOR_COUNT, MVMT|NCOL|LNMD},
/* l move right */ {m_right, CURSOR_COUNT, MVMT},
/* m define a mark */ {v_mark, CURSOR_CNT_KEY, NO_FLAGS},
/* n repeat prev srch */ {m_nsrch, CURSOR, MVMT},
/* o insert below line*/ {v_insert, CURSOR_CNT_CMD, SDOT},
/* p paste after */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS},
/* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* r replace chars */ {v_replace, CURSOR_CNT_KEY, SDOT},
/* s subst N chars */ {v_subst, CURSOR_COUNT, SDOT},
#ifndef NO_CHARSEARCH
/* t move fwd to char */ {m_tch, CURSOR_CNT_KEY, MVMT|INCL},
#else
/* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
#endif
/* u undo */ {v_undo, CURSOR, NO_FLAGS},
/* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
/* w move fwd word */ {m_fword, CURSOR_COUNT, MVMT},
/* x delete character */ {v_xchar, CURSOR_COUNT, SDOT},
/* y yank text */ {v_yank, CURSOR_MOVED, NO_FLAGS},
/* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL},
/* { back paragraph */ {m_bparagraph, CURSOR_COUNT, MVMT|LNMD},
/* | move to column */ {m_tocol, CURSOR_COUNT, NREL},
/* } fwd paragraph */ {m_fparagraph, CURSOR_COUNT, MVMT|LNMD},
/* ~ upper/lowercase */ {v_ulcase, CURSOR, SDOT},
/* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
};
vi()
{
register int key; /* keystroke from user */
long count; /* numeric argument to some functions */
register struct keystru *keyptr;/* pointer to vikeys[] element */
MARK tcurs; /* temporary cursor */
int prevkey;/* previous key, if d/c/y/</>/! */
MARK range; /* start of range for d/c/y/</>/! */
char text[100];
int dotkey; /* last "key" of a change */
int dotpkey;/* last "prevkey" of a change */
int dotkey2;/* last extra "getkey()" of a change */
int dotcnt; /* last "count" of a change */
int firstkey;
register int i;
/* tell the redraw() function to start from scratch */
redraw(MARK_UNSET, FALSE);
msg((char *)0);
#ifdef lint
/* lint says that "range" might be used before it is set. This
* can't really happen due to the way "range" and "prevkey" are used,
* but lint doesn't know that. This line is here ONLY to keep lint
* happy.
*/
range = 0L;
#endif
/* safeguard against '.' with no previous command */
dotkey = 0;
#ifndef NO_EXTENSIONS
/* go immediately into insert mode, if ":set inputmode" */
firstkey = 0;
if (*o_inputmode)
{
firstkey = 'i';
}
#endif
/* Repeatedly handle VI commands */
for (count = 0, prevkey = '\0'; mode == MODE_VI; )
{
/* if we've moved off the undoable line, then we can't undo it at all */
if (markline(cursor) != U_line)
{
U_line = 0L;
}
/* report any changes from the previous command */
if (rptlines >= *o_report)
{
redraw(cursor, FALSE);
msg("%ld lines %s", rptlines, rptlabel);
}
rptlines = 0L;
/* get the next command key. It must be ASCII */
if (firstkey)
{
key = firstkey;
firstkey = 0;
}
else
{
do
{
key = getkey(WHEN_VICMD);
} while (key < 0 || key > 127);
}
/* change cw and cW commands to ce and cE, respectively */
/* (Why? because the real vi does it that way!) */
if (prevkey == 'c')
{
if (key == 'w')
key = 'e';
else if (key == 'W')
key = 'E';
/* wouldn't work right at the end of a word unless we
* backspace one character before doing the move. This
* will fix most cases.
*/
if (markidx(cursor) > 0 && (key == 'e' || key == 'E'))
{
cursor--;
}
}
/* look up the structure describing this command */
keyptr = &vikeys[key];
/* if we're in the middle of a d/c/y/</>/! command, reject
* anything but movement or a doubled version like "dd".
*/
if (prevkey && key != prevkey && !(keyptr->flags & (MVMT|PTMV)))
{
beep();
prevkey = 0;
count = 0;
continue;
}
/* set the "dot" variables, if we're supposed to */
if ((keyptr->flags & SDOT)
|| (prevkey && vikeys[prevkey].flags & SDOT))
{
dotkey = key;
dotpkey = prevkey;
dotkey2 = '\0';
dotcnt = count;
/* remember the line before any changes are made */
if (U_line != markline(cursor))
{
U_line = markline(cursor);
strcpy(U_text, fetchline(U_line));
}
}
/* if this is "." then set other vars from the "dot" vars */
if (key == '.')
{
key = dotkey;
keyptr = &vikeys[key];
prevkey = dotpkey;
if (prevkey)
{
range = cursor;
}
if (count == 0)
{
count = dotcnt;
}
doingdot = TRUE;
/* remember the line before any changes are made */
if (U_line != markline(cursor))
{
U_line = markline(cursor);
strcpy(U_text, fetchline(U_line));
}
}
else
{
doingdot = FALSE;
}
/* process the key as a command */
tcurs = cursor;
switch (keyptr->args)
{
case ZERO:
if (count == 0)
{
tcurs = cursor & ~(BLKSIZE - 1);
break;
}
/* else fall through & treat like other digits... */
case DIGIT:
count = count * 10 + key - '0';
break;
case KEYWORD:
/* if not on a keyword, fail */
pfetch(markline(cursor));
key = markidx(cursor);
if (isascii(ptext[key])
&& !isalnum(ptext[key]) && ptext[key] != '_')
{
tcurs = MARK_UNSET;
break;
}
/* find the start of the keyword */
while (key > 0 && (!isascii(ptext[key-1]) ||
isalnum(ptext[key - 1]) || ptext[key - 1] == '_'))
{
key--;
}
tcurs = (cursor & ~(BLKSIZE - 1)) + key;
/* copy it into a buffer, and NUL-terminate it */
i = 0;
do
{
text[i++] = ptext[key++];
} while (!isascii(ptext[key]) || isalnum(ptext[key]) || ptext[key] == '_');
text[i] = '\0';
/* call the function */
tcurs = (*keyptr->func)(text, tcurs, count);
count = 0L;
break;
case NO_ARGS:
if (keyptr->func)
{
(*keyptr->func)();
}
else
{
beep();
}
count = 0L;
break;
case CURSOR_COUNT:
tcurs = (*keyptr->func)(cursor, count);
count = 0L;
break;
case CURSOR:
tcurs = (*keyptr->func)(cursor);
count = 0L;
break;
case CURSOR_CNT_KEY:
if (doingdot)
{
tcurs = (*keyptr->func)(cursor, count, dotkey2);
}
else if (keyptr->flags & SDOT
|| (prevkey && vikeys[prevkey].flags & SDOT))
{
dotkey2 = getkey(0);
tcurs = (*keyptr->func)(cursor, count, dotkey2);
}
else
{
tcurs = (*keyptr->func)(cursor, count, getkey(0));
}
count = 0L;
break;
case CURSOR_MOVED:
/* uppercase keys always act like doubled */
if (isascii(key) && isupper(key))
{
prevkey = key;
range = cursor;
}
if (prevkey)
{
/* doubling up a command, use complete lines */
range &= ~(BLKSIZE - 1);
if (count)
{
tcurs = range + MARK_AT_LINE(count);
count = 0;
}
else
{
tcurs = range + BLKSIZE;
}
}
else
{
prevkey = key;
range = cursor;
key = -1; /* so we don't think we doubled yet */
}
break;
case CURSOR_EOL:
prevkey = key;
/* a zero-length line needs special treatment */
pfetch(markline(cursor));
if (plen == 0)
{
/* act on a zero-length section of text */
range = tcurs = cursor;
key = ' ';
}
else
{
/* act like CURSOR_MOVED with '$' movement */
range = cursor;
tcurs = m_rear(cursor, 1L);
key = '$';
}
count = 0L;
keyptr = &vikeys[key];
break;
case CURSOR_TEXT:
do
{
if (vgets(key, text, sizeof text) >= 0)
{
/* reassure user that <CR> was hit */
qaddch('\r');
refresh();
/* call the function with the text */
tcurs = (*keyptr->func)(cursor, text);
}
else
mode = MODE_VI;
} while (mode == MODE_COLON);
count = 0L;
break;
case CURSOR_CNT_CMD:
tcurs = (*keyptr->func)(cursor, count, key);
count = 0L;
break;
}
/* if that command took us out of vi mode, then exit the loop
* NOW, without tweaking the cursor or anything. This is very
* important when mode == MODE_QUIT.
*/
if (mode != MODE_VI)
{
break;
}
/* now move the cursor, as appropriate */
if (prevkey && markline(tcurs) > nlines)
{
/* destination for operator may be nlines + 1 */
cursor = MARK_AT_LINE(nlines + 1);
}
else if (keyptr->args == CURSOR_MOVED)
{
/* the < and > keys have FRNT,
* but it shouldn't be applied yet
*/
cursor = adjmove(cursor, tcurs, 0);
}
else
{
cursor = adjmove(cursor, tcurs, keyptr->flags);
}
/* was that the end of a d/c/y/</>/! command? */
if (prevkey && (prevkey == key || (keyptr->flags & MVMT)))
{
/* if the movement command failed, cancel operation */
if (tcurs == MARK_UNSET)
{
prevkey = 0;
count = 0;
continue;
}
/* make sure range=front and tcurs=rear */
if (cursor < range)
{
tcurs = range;
range = cursor;
}
else
{
tcurs = cursor;
}
/* adjust for line mode */
if (keyptr->flags & LNMD)
{
range &= ~(BLKSIZE - 1);
tcurs &= ~(BLKSIZE - 1);
tcurs += BLKSIZE;
}
/* adjust for inclusion of last char */
if (keyptr->flags & INCL)
{
tcurs++;
}
/* temporarily move the cursor to "range" so that
* beforedo() remembers the cursor's real location.
* This is important if the user later does undo()
*/
cursor = range;
/* run the function */
tcurs = (*vikeys[prevkey].func)(range, tcurs);
cursor = adjmove(cursor, tcurs, vikeys[prevkey].flags);
/* cleanup */
prevkey = 0;
}
}
}
/* This function adjusts the MARK value that they return; here we make sure
* it isn't past the end of the line, and that the column hasn't been
* *accidentally* changed.
*/
MARK adjmove(old, new, flags)
MARK old; /* the cursor position before the command */
register MARK new; /* the cursor position after the command */
int flags; /* various flags regarding cursor mvmt */
{
static int colno; /* the column number that we want */
register char *text; /* used to scan through the line's text */
register int i;
/* if the command failed, bag it! */
if (new == MARK_UNSET)
{
beep();
return old;
}
/* if this is a non-relative movement, set the '' mark */
if (flags & NREL)
{
mark[26] = old;
}
/* make sure it isn't past the end of the file */
if (markline(new) < 1)
{
new = MARK_FIRST;
}
else if (markline(new) > nlines)
{
new = MARK_LAST;
}
/* fetch the new line */
pfetch(markline(new));
/* move to the front, if we're supposed to */
if (flags & FRNT)
{
new = m_front(new, 1L);
}
/* change the column#, or change the mark to suit the column# */
if (!(flags & NCOL))
{
/* change the column# */
i = markidx(new);
if (i == BLKSIZE - 1)
{
new &= ~(BLKSIZE - 1);
if (plen > 0)
{
new += plen - 1;
}
colno = BLKSIZE * 8; /* one heck of a big colno */
}
else if (plen > 0)
{
if (i >= plen)
{
new = (new & ~(BLKSIZE - 1)) + plen - 1;
}
colno = idx2col(new, ptext, FALSE);
}
else
{
new &= ~(BLKSIZE - 1);
colno = 0;
}
}
else
{
/* adjust the mark to get as close as possible to column# */
for (i = 0, text = ptext; i <= colno && *text; text++)
{
if (*text == '\t' && !*o_list)
{
i += *o_tabstop - (i % *o_tabstop);
}
else if (UCHAR(*text) < ' ' || *text == 127)
{
i += 2;
}
#ifndef NO_CHARATTR
else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
{
text += 2; /* plus one more in "for()" stmt */
}
#endif
else
{
i++;
}
}
if (text > ptext)
{
text--;
}
new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
}
return new;
}
SHAR_EOF
fi
if test -f 'vi.h'
then
echo shar: "will not over-write existing file 'vi.h'"
else
cat << \SHAR_EOF > 'vi.h'
/* vi.h */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This is the header file for my version of vi. */
#define VERSION "ELVIS 1.3, by Steve Kirkendall"
#define COPYING "This version of ELVIS is freely redistributable."
#include <errno.h>
extern int errno;
#if TOS
#define ENOENT (-AEFILNF)
#endif
#if TOS
# include <types.h>
# define O_RDONLY 0
# define O_WRONLY 1
# define O_RDWR 2
#else
# include <sys/types.h>
# include <fcntl.h>
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
#include "curses.h"
/*------------------------------------------------------------------------*/
/* Miscellaneous constants. */
#define INFINITY 2000000001L /* a very large integer */
#if MSDOS
# define MAXMAPS 50 /* then we have lots of specials */
#else
# define MAXMAPS 20 /* number of :map keys */
#endif
#define LONGKEY 10 /* longest possible raw :map key */
#define MAXDIGS 30 /* number of :digraph combos */
#define MAXRCLEN 1000 /* longest possible .exrc file */
/*------------------------------------------------------------------------*/
/* These describe how temporary files are divided into blocks */
#define BLKSIZE 1024 /* size of blocks */
#define MAXBLKS (BLKSIZE / sizeof(unsigned short))
typedef union
{
char c[BLKSIZE]; /* for text blocks */
unsigned short n[MAXBLKS]; /* for the header block */
}
BLK;
/*------------------------------------------------------------------------*/
/* These are used manipulate BLK buffers. */
extern BLK hdr; /* buffer for the header block */
extern BLK blkbuf[2]; /* buffers for text blocks */
extern BLK *blkget(); /* given index into hdr.c[], reads block */
extern BLK *blkadd(); /* inserts a new block into hdr.c[] */
/*------------------------------------------------------------------------*/
/* These are used to keep track of various flags */
extern struct _viflags
{
short file; /* file flags */
}
viflags;
/* file flags */
#define NEWFILE 0x0001 /* the file was just created */
#define READONLY 0x0002 /* the file is read-only */
#define HADNUL 0x0004 /* the file contained NUL characters */
#define MODIFIED 0x0008 /* the file has been modified */
#define NOFILE 0x0010 /* no name is known for the current text */
#define ADDEDNL 0x0020 /* newlines were added to the file */
/* macros used to set/clear/test flags */
#define setflag(x,y) viflags.x |= y
#define clrflag(x,y) viflags.x &= ~y
#define tstflag(x,y) (viflags.x & y)
#define initflags() viflags.file = 0;
/* The options */
extern char o_autoindent[1];
extern char o_autowrite[1];
#ifndef NO_CHARATTR
extern char o_charattr[1];
#endif
extern char o_columns[3];
extern char o_directory[30];
extern char o_errorbells[1];
extern char o_exrefresh[1];
#ifndef NO_SENTENCE
extern char o_hideformat[1];
#endif
extern char o_ignorecase[1];
#ifndef NO_EXTENSIONS
extern char o_inputmode[1];
#endif
extern char o_keytime[3];
extern char o_keywordprg[80];
extern char o_lines[3];
extern char o_list[1];
#ifndef NO_MAGIC
extern char o_magic[1];
#endif
#ifndef NO_SENTENCE
extern char o_paragraphs[30];
#endif
#if MSDOS
extern char o_pcbios[1];
#endif
extern char o_readonly[1];
extern char o_report[3];
extern char o_scroll[3];
#ifndef NO_SENTENCE
extern char o_sections[30];
#endif
extern char o_shell[60];
extern char o_showmode[1];
extern char o_shiftwidth[3];
extern char o_sidescroll[3];
extern char o_sync[1];
extern char o_tabstop[3];
extern char o_term[30];
extern char o_vbell[1];
extern char o_warn[1];
extern char o_wrapmargin[3];
extern char o_wrapscan[1];
/*------------------------------------------------------------------------*/
/* These help support the single-line multi-change "undo" -- shift-U */
extern char U_text[BLKSIZE];
extern long U_line;
/*------------------------------------------------------------------------*/
/* These are used to refer to places in the text */
typedef long MARK;
#define markline(x) (long)((x) / BLKSIZE)
#define markidx(x) (int)((x) & (BLKSIZE - 1))
#define MARK_UNSET ((MARK)0)
#define MARK_FIRST ((MARK)BLKSIZE)
#define MARK_LAST ((MARK)(nlines * BLKSIZE))
#define MARK_AT_LINE(x) ((MARK)((x) * BLKSIZE))
#define NMARKS 28
extern MARK mark[NMARKS]; /* marks 'a through 'z, plus mark '' */
extern MARK cursor; /* mark where line is */
/*------------------------------------------------------------------------*/
/* These are used to keep track of the current & previous files. */
extern long origtime; /* modification date&time of the current file */
extern char origname[256]; /* name of the current file */
extern char prevorig[256]; /* name of the preceding file */
extern long prevline; /* line number from preceding file */
/*------------------------------------------------------------------------*/
/* misc housekeeping variables & functions */
extern int tmpfd; /* fd used to access the tmp file */
extern long lnum[MAXBLKS]; /* last line# of each block */
extern long nlines; /* number of lines in the file */
extern char args[BLKSIZE]; /* file names given on the command line */
extern int argno; /* the current element of args[] */
extern int nargs; /* number of filenames in args */
extern long changes; /* counts changes, to prohibit short-cuts */
extern int mustredraw; /* boolean: force total redraw of screen? */
extern long redrawafter; /* line# of first line to redraw */
extern long preredraw; /* line# of last line changed, before change */
extern long postredraw; /* line# of last line changed, after change */
extern BLK tmpblk; /* a block used to accumulate changes */
extern long topline; /* file line number of top line */
extern int leftcol; /* column number of left col */
#define botline (topline + LINES - 2)
#define rightcol (leftcol + COLS - 1)
extern int physcol; /* physical column number that cursor is on */
extern int physrow; /* physical row number that cursor is on */
extern int exwrote; /* used to detect verbose ex commands */
extern int doingdot; /* boolean: are we doing the "." command? */
extern long rptlines; /* number of lines affected by a command */
extern char *rptlabel; /* description of how lines were affected */
extern char *fetchline(); /* read a given line from tmp file */
extern char *parseptrn(); /* isolate a regexp in a line */
extern MARK paste(); /* paste from cut buffer to a given point */
extern char *wildcard(); /* expand wildcards in filenames */
extern MARK input(); /* inserts characters from keyboard */
extern char *linespec(); /* finds the end of a /regexp/ string */
#define ctrl(ch) ((ch)&037)
#ifndef NO_RECYCLE
extern long allocate(); /* allocate a free block of the tmp file */
#endif
extern int trapint(); /* trap handler for SIGINT */
/*------------------------------------------------------------------------*/
/* macros that are used as control structures */
#define BeforeAfter(before, after) for((before),bavar=1;bavar;(after),bavar=0)
#define ChangeText BeforeAfter(beforedo(FALSE),afterdo())
extern int bavar; /* used only in BeforeAfter macros */
/*------------------------------------------------------------------------*/
/* These are the movement commands. Each accepts a mark for the starting */
/* location & number and returns a mark for the destination. */
extern MARK m_up(); /* k */
extern MARK m_down(); /* j */
extern MARK m_right(); /* h */
extern MARK m_left(); /* l */
extern MARK m_toline(); /* G */
extern MARK m_tocol(); /* | */
extern MARK m_front(); /* ^ */
extern MARK m_rear(); /* $ */
extern MARK m_fword(); /* w */
extern MARK m_bword(); /* b */
extern MARK m_eword(); /* e */
extern MARK m_fWord(); /* W */
extern MARK m_bWord(); /* B */
extern MARK m_eWord(); /* E */
extern MARK m_fparagraph(); /* } */
extern MARK m_bparagraph(); /* { */
extern MARK m_fsection(); /* ]] */
extern MARK m_bsection(); /* [[ */
extern MARK m_match(); /* % */
#ifndef NO_SENTENCE
extern MARK m_fsentence(); /* ) */
extern MARK m_bsentence(); /* ( */
#endif
extern MARK m_tomark(); /* 'm */
extern MARK m_nsrch(); /* n */
extern MARK m_Nsrch(); /* N */
extern MARK m_fsrch(); /* /regexp */
extern MARK m_bsrch(); /* ?regexp */
extern MARK m__ch(); /* ; , */
extern MARK m_fch(); /* f */
extern MARK m_tch(); /* t */
extern MARK m_Fch(); /* F */
extern MARK m_Tch(); /* T */
extern MARK m_row(); /* H L M */
extern MARK m_z(); /* z */
extern MARK m_scroll(); /* ^B ^F ^E ^Y ^U ^D */
/* Some stuff that is used by movement functions... */
extern MARK adjmove(); /* a helper fn, used by move fns */
/* This macro is used to set the default value of cnt */
#define DEFAULT(val) if (cnt < 1) cnt = (val)
/* These are used to minimize calls to fetchline() */
extern int plen; /* length of the line */
extern long pline; /* line number that len refers to */
extern long pchgs; /* "changes" level that len refers to */
extern char *ptext; /* text of previous line, if valid */
extern void pfetch();
/* This is used to build a MARK that corresponds to a specific point in the
* line that was most recently pfetch'ed.
*/
#define buildmark(text) (MARK)(BLKSIZE * pline + (int)((text) - ptext))
/*------------------------------------------------------------------------*/
/* These are used to handle EX commands. */
#define CMD_NULL 0 /* NOT A VALID COMMAND */
#define CMD_ABBR 1 /* "define an abbreviation" */
#define CMD_ARGS 2 /* "show me the args" */
#define CMD_APPEND 3 /* "insert lines after this line" */
#define CMD_BANG 4 /* "run a single shell command" */
#define CMD_COPY 5 /* "copy the selected text to a given place" */
#define CMD_CD 6 /* "change directories" */
#define CMD_CHANGE 7 /* "change some lines" */
#define CMD_DELETE 8 /* "delete the selected text" */
#define CMD_DIGRAPH 9 /* "add a digraph, or display them all" */
#define CMD_EDIT 10 /* "switch to a different file" */
#define CMD_FILE 11 /* "show the file's status" */
#define CMD_GLOBAL 12 /* "globally search & do a command" */
#define CMD_INSERT 13 /* "insert lines before the current line" */
#define CMD_JOIN 14 /* "join the selected line & the one after" */
#define CMD_LIST 15 /* "print lines, making control chars visible" */
#define CMD_MAP 16 /* "adjust the keyboard map" */
#define CMD_MARK 17 /* "mark this line" */
#define CMD_MKEXRC 18 /* "make a .exrc file" */
#define CMD_MOVE 19 /* "move the selected text to a given place" */
#define CMD_NEXT 20 /* "switch to next file in args" */
#define CMD_PRESERVE 21 /* "act as though vi crashed" */
#define CMD_PREVIOUS 22 /* "switch to the previous file in args" */
#define CMD_PRINT 23 /* "print the selected text" */
#define CMD_PUT 24 /* "insert any cut lines before this line" */
#define CMD_QUIT 25 /* "quit without writing the file" */
#define CMD_READ 26 /* "append the given file after this line */
#define CMD_RECOVER 27 /* "recover file after vi crashes" - USE -r FLAG */
#define CMD_REWIND 28 /* "rewind to first file" */
#define CMD_SET 29 /* "set a variable's value" */
#define CMD_SHELL 30 /* "run some lines through a command" */
#define CMD_SHIFTL 31 /* "shift lines left" */
#define CMD_SHIFTR 32 /* "shift lines right" */
#define CMD_SOURCE 33 /* "interpret a file's contents as ex commands" */
#define CMD_STOP 34 /* same as CMD_SUSPEND */
#define CMD_SUSPEND 35 /* "suspend the vi session" */
#define CMD_SUBSTITUTE 36 /* "substitute text in this line" */
#define CMD_TR 37 /* "transliterate chars in the selected lines" */
#define CMD_TAG 38 /* "go to a particular tag" */
#define CMD_UNABBR 39 /* "remove an abbreviation definition" */
#define CMD_UNDO 40 /* "undo the previous command" */
#define CMD_UNMAP 41 /* "remove a key sequence map */
#define CMD_VERSION 42 /* "describe which version this is" */
#define CMD_VGLOBAL 43 /* "apply a cmd to lines NOT containing an RE" */
#define CMD_VISUAL 44 /* "go into visual mode" */
#define CMD_WQUIT 45 /* "write this file out (any case) & quit" */
#define CMD_WRITE 46 /* "write the selected(?) text to a given file" */
#define CMD_XIT 47 /* "write this file out (if modified) & quit" */
#define CMD_YANK 48 /* "copy the selected text into the cut buffer" */
#ifdef DEBUG
# define CMD_DEBUG 49 /* access to internal data structures */
# define CMD_VALIDATE 50 /* check for internal consistency */
#endif
typedef int CMD;
extern ex();
extern vi();
extern doexcmd();
extern void cmd_append();
extern void cmd_args();
extern void cmd_cd();
extern void cmd_delete();
#ifndef NO_DIGRAPH
extern void cmd_digraph();
#endif
extern void cmd_edit();
extern void cmd_file();
extern void cmd_global();
extern void cmd_join();
extern void cmd_mark();
extern void cmd_list();
extern void cmd_map();
#ifndef NO_EXTENSIONS
extern void cmd_mkexrc();
#endif
extern void cmd_next();
extern void cmd_print();
extern void cmd_put();
extern void cmd_quit();
extern void cmd_read();
extern void cmd_rewind();
extern void cmd_set();
extern void cmd_shell();
extern void cmd_shift();
extern void cmd_source();
extern void cmd_substitute();
extern void cmd_tag();
extern void cmd_undo();
extern void cmd_version();
extern void cmd_visual();
extern void cmd_write();
extern void cmd_xit();
extern void cmd_move();
#ifdef DEBUG
extern void cmd_debug();
extern void cmd_validate();
#endif
/*----------------------------------------------------------------------*/
/* These are used to handle VI commands */
extern MARK v_1ex(); /* : */
extern MARK v_mark(); /* m */
extern MARK v_quit(); /* Q */
extern MARK v_redraw(); /* ^L ^R */
extern MARK v_ulcase(); /* ~ */
extern MARK v_undo(); /* u */
extern MARK v_xchar(); /* x */
extern MARK v_Xchar(); /* X */
extern MARK v_replace(); /* r */
extern MARK v_overtype(); /* R */
extern MARK v_selcut(); /* " */
extern MARK v_paste(); /* p P */
extern MARK v_yank(); /* y Y */
extern MARK v_delete(); /* d D */
extern MARK v_join(); /* J */
extern MARK v_insert(); /* a A i I o O */
extern MARK v_change(); /* c C */
extern MARK v_subst(); /* s */
extern MARK v_lshift(); /* < */
extern MARK v_rshift(); /* > */
extern MARK v_filter(); /* ! */
extern MARK v_status(); /* ^G */
extern MARK v_switch(); /* ^^ */
extern MARK v_tag(); /* ^] */
#ifndef NO_EXTENSIONS
extern MARK v_keyword(); /* ^K */
extern MARK v_increment(); /* * */
#endif
extern MARK v_xit(); /* ZZ */
extern MARK v_undoline(); /* U */
/*----------------------------------------------------------------------*/
/* These describe what mode we're in */
#define MODE_EX 1 /* executing ex commands */
#define MODE_VI 2 /* executing vi commands */
#define MODE_COLON 3 /* executing an ex command from vi mode */
#define MODE_QUIT 4
extern int mode;
#define WHEN_VICMD 1 /* getkey: we're reading a VI command */
#define WHEN_VIINP 2 /* getkey: we're in VI's INPUT mode */
#define WHEN_VIREP 4 /* getkey: we're in VI's REPLACE mode */
#define WHEN_EX 8 /* getkey: we're in EX mode */
#define WHEN_INMV 256 /* in input mode, interpret the key in VICMD mode */
SHAR_EOF
fi
if test -f 'ctags.c'
then
echo shar: "will not over-write existing file 'ctags.c'"
else
cat << \SHAR_EOF > 'ctags.c'
/* ctags.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains the complete source to the ctags program. */
/* Special abilities:
* Can also make a "refs" file for use by the "ref" program.
*/
/* Limitations:
* This version of ctags always writes its output to the file "tags".
* It assumes that every command-line argument (but "-r") is a C source file.
* It does not sort the list of tags.
* It does not recognize duplicate definitions.
* It does not try to handle "static" functions in a clever way.
* It probably won't scan ANSI-C source code very well.
*/
/* Implementation:
* Lines are scanned one-at-a-time.
* The context of lines is tracked via a finite state machine.
* Contexts are:
* EXPECTFN - we're looking for a function name.
* ARGS - between function name and its opening {
* BODY - we found a function name, skip to end of body.
*
* Function tags are referenced by a search string, so that lines may be
* inserted or deleted without mucking up the tag search.
*
* Macro tags are referenced by their line number, because 1) they usually
* occur near the top of a file, so their line# won't change much; 2) They
* often contain characters that are hard to search for; and 3) Their #define
* line is likely to be altered.
*
* Each line of the resulting "tags" file describes one tag. Lines begin with
* the tag name, then a tab, then the file name, then a tab, and then either
* a line number or a slash-delimited search string.
*/
#include <ctype.h>
#include <stdio.h>
#include "config.h"
#define REFS "refs"
#define NUMFMT "%.*s\t%s\t%ld\n"
#define SRCHFMT "%.*s\t%s\t/^%s$/\n"
#define MAINFMT "M%.*s\t%s\t/^%s$/\n"
#ifdef VERBOSE
# define SAY(x) fprintf(stderr, "%s\n", x);
#else
# define SAY(x)
#endif
#define EXPECTFN 1
#define ARGS 2
#define BODY 3
extern char *fgets();
char *progname; /* argv[0], used for diagnostic output */
main(argc, argv)
int argc;
char **argv;
{
FILE *fp;
int i;
FILE *refs; /* used to write to the refs file */
#if MSDOS || TOS
char **wildexpand();
argv=wildexpand(&argc, argv);
#endif
/* notice the program name */
progname = argv[0];
/* create the "refs" file if first arg is "-r" */
if (argc > 1 && !strcmp(argv[1], "-r"))
{
/* delete the "-r" flag from the args list */
argc--;
argv++;
/* open the "refs" file for writing */
refs = fopen(REFS, "w");
if (!refs)
{
fprintf(stderr, "%s: could not create \"%s\"\n", progname, REFS);
exit(2);
}
}
else
{
refs = (FILE *)0;
}
/* process each file named on the command line, or complain if none */
if (argc > 1)
{
/* redirect stdout to go to the "tags" file */
if (!freopen("tags", "w", stdout))
{
fprintf(stderr, "%s: could not create \"%s\"\n", progname, TAGS);
exit(2);
}
for (i = 1; i < argc; i++)
{
/* process this named file */
fp = fopen(argv[i], "r");
if (!fp)
{
fprintf(stderr, "%s: could not read \"%s\"\n", progname, argv[i]);
continue;
}
ctags(fp, argv[i], refs);
fclose(fp);
}
#ifdef SORT
/* This is a hack which will sort the tags list. It should
* on UNIX and Minix. You may have trouble with csh. Note
* that the tags list only has to be sorted if you intend to
* use it with the real vi; elvis permits unsorted tags.
*/
fflush(stdout);
system("sort tags >_tags$$; mv _tags$$ tags");
#endif
exit(0);
}
else
{
fprintf(stderr, "usage: %s *.[ch]\n", progname);
exit(2);
}
}
/* this function finds all tags in a given file */
ctags(fp, name, refs)
FILE *fp; /* stream of the file to scan */
char *name; /* name of the file being scanned */
FILE *refs; /* NULL, or where to write refs lines */
{
int context; /* context - either EXPECTFN, ARGS, or BODY */
long lnum; /* line number */
char text[1000]; /* a line of text from the file */
char *scan; /* used for searching through text */
int len; /* length of the line */
/* for each line of the file... */
for (context = EXPECTFN, lnum = 1; fgets(text, sizeof text, fp); lnum++)
{
#ifdef VERBOSE
switch(context)
{
case EXPECTFN: scan = "EXPECTFN"; break;
case ARGS: scan = "ARGS "; break;
case BODY: scan = "BODY "; break;
default: scan = "context?";
}
fprintf(stderr, "%s:%s", scan, text);
#endif
/* start of body? */
if (text[0] == '{')
{
context = BODY;
SAY("Start of BODY");
continue;
}
/* argument line, to be written to "refs" ? */
if (refs && context == ARGS)
{
if (text[0] != '\t')
{
putc('\t', refs);
}
fputs(text, refs);
SAY("Argument line");
continue;
}
/* ignore empty or indented lines */
if (text[0] <= ' ')
{
SAY("Empty or indented");
continue;
}
/* end of body? */
if (text[0] == '}')
{
context = EXPECTFN;
SAY("End of BODY");
continue;
}
/* ignore lines in the body of a function */
if (context != EXPECTFN)
{
SAY("BODY or ARGS");
continue;
}
/* strip the newline */
len = strlen(text);
text[--len] = '\0';
/* a preprocessor line? */
if (text[0] == '#')
{
/* find the preprocessor directive */
for (scan = &text[1]; isspace(*scan); scan++)
{
}
/* if it's a #define, make a tag out of it */
if (!strncmp(scan, "define", 6))
{
/* find the start of the symbol name */
for (scan += 6; isspace(*scan); scan++)
{
}
/* find the length of the symbol name */
for (len = 1;
isalnum(scan[len]) || scan[len] == '_';
len++)
{
}
printf(NUMFMT, len, scan, name, lnum);
}
SAY("Preprocessor line");
continue;
}
/* an extern or static declaration? */
if (text[len - 1] == ';'
|| !strncmp(text, "extern", 6)
|| !strncmp(text, "EXTERN", 6)
|| !strncmp(text, "static", 6)
|| !strncmp(text, "PRIVATE", 7))
{
SAY("Extern or static");
continue;
}
/* if we get here & the first punctuation other than "*" is
* a "(" which is immediately preceded by a name, then
* assume the name is that of a function.
*/
for (scan = text; *scan; scan++)
{
if (ispunct(*scan)
&& !isspace(*scan) /* in BSD, spaces are punctuation?*/
&& *scan != '*' && *scan != '_' && *scan != '(')
{
SAY("Funny punctuation");
goto ContinueContinue;
}
if (*scan == '(')
{
/* permit 0 or 1 spaces between name & '(' */
if (scan > text && scan[-1] == ' ')
{
scan--;
}
/* find the start & length of the name */
for (len = 0, scan--;
scan >= text && (isalnum(*scan) || *scan == '_');
scan--, len++)
{
}
scan++;
/* did we find a function? */
if (len > 0)
{
/* found a function! */
if (len == 4 && !strncmp(scan, "main", 4))
{
printf(MAINFMT, strlen(name) - 2, name, name, text);
}
printf(SRCHFMT, len, scan, name, text);
context = ARGS;
/* add a line to refs, if needed */
if (refs)
{
fputs(text, refs);
putc('\n', refs);
}
goto ContinueContinue;
}
}
else
{
SAY("No parenthesis");
}
}
SAY("No punctuation");
ContinueContinue:;
}
}
#if MSDOS || TOS
#define WILDCARD_NO_MAIN
#include "wildcard.c"
#endif
SHAR_EOF
fi
if test -f 'ref.c'
then
echo shar: "will not over-write existing file 'ref.c'"
else
cat << \SHAR_EOF > 'ref.c'
/* ref.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This program looks up the declarations of library functions. */
#include <stdio.h>
/* This is the list of files that are searched. */
char *refslist[] = {
"refs",
"/usr/src/lib/refs",
"../lib/refs",
"/usr/local/lib/refs",
};
#define NREFS (sizeof refslist / sizeof(char *))
main(argc, argv)
int argc;
char **argv;
{
int i; /* used to step through the refslist */
/* make sure our arguments are OK */
if (argc != 2)
{
fprintf(stderr, "usage: %s function_name\n", *argv);
exit(2);
}
/* check for the function in each database */
for (i = 0; i < NREFS; i++)
{
if (lookinfor(refslist[i], argv[1]))
{
exit(0);
}
}
fprintf(stderr, "%s: don't know about %s\n", argv[0], argv[1]);
exit(2);
}
/* This function checks a single file for the function. Returns 1 if found */
int lookinfor(filename, func)
char *filename; /* name of file to look in */
char *func; /* name of function to look for */
{
FILE *fp; /* stream used to access the database */
char linebuf[300];
/* NOTE: in actual use, the first character of linebuf is */
/* set to ' ' and then we use all EXCEPT the 1st character */
/* everywhere in this function. This is because the func */
/* which examines the linebuf could, in some circumstances */
/* examine the character before the used part of linebuf; */
/* we need to control what happens then. */
/* open the database file */
fp = fopen(filename, "r");
if (!fp)
{
return 0;
}
/* find the desired entry */
*linebuf = ' ';
do
{
if (!fgets(linebuf + 1, (sizeof linebuf) - 1, fp))
{
fclose(fp);
return 0;
}
} while (!desired(linebuf + 1, func));
/* print it */
do
{
fputs(linebuf + 1, stdout);
} while (fgets(linebuf + 1, sizeof linebuf, fp) && linebuf[1] == '\t');
/* cleanup & exit */
fclose(fp);
return 1;
}
/* This function checks to see if a given line is the first line of the */
/* entry the user wants to see. If it is, return non-0 else return 0 */
desired(line, word)
char *line; /* the line buffer */
char *word; /* the string it should contain */
{
static wlen = -1;/* length of the "word" variable's value */
register char *scan;
/* if this line starts with a tab, it couldn't be desired */
if (*line == '\t')
{
return 0;
}
/* if we haven't found word's length yet, do so */
if (wlen < 0)
{
wlen = strlen(word);
}
/* search for the word in the line */
for (scan = line; *scan != '('; scan++)
{
}
while (*--scan == ' ')
{
}
scan -= wlen;
if (scan < line - 1 || *scan != ' ' && *scan != '\t' && *scan != '*')
{
return 0;
}
scan++;
return !strncmp(scan, word, wlen);
}
SHAR_EOF
fi
if test -f 'virec.c'
then
echo shar: "will not over-write existing file 'virec.c'"
else
cat << \SHAR_EOF > 'virec.c'
/* virec.c */
/* This file contains the file recovery program */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda at jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
#include <stdio.h>
#include "config.h"
#include "vi.h"
#if TOS
#include <stat.h>
#else
#include <sys/stat.h>
#endif
extern char *getenv();
struct stat stbuf;
BLK hdr;
BLK text;
/* the name of the directory where tmp files are stored. */
char o_directory[30] = TMPDIR;
char *progname;
main(argc, argv)
int argc;
char **argv;
{
char *tmp;
#if MSDOS || TOS
char **wildexpand();
argv = wildexpand(&argc, argv);
#endif
progname = argv[0];
/* set the o_directory variable */
if ((tmp = getenv("TMP")) /* yes, ASSIGNMENT! */
|| (tmp = getenv("TEMP"))) /* yes, ASSIGNMENT! */
{
strcpy(o_directory, tmp);
}
if (argc >= 3 && !strcmp(argv[1], "-d"))
{
strcpy(o_directory, argv[2]);
argc -= 2;
argv += 2;
}
/* process the arguments */
if (argc < 2)
{
/* maybe stdin comes from a file? */
if (fstat(0, &stbuf) < 0 || (S_IFMT & stbuf.st_mode) != S_IFREG)
{
fprintf(stderr, "usage: %s [-d tmpdir] lostfile...\n", progname);
}
else if (read(0, &hdr, BLKSIZE) != BLKSIZE)
{
fprintf(stderr, "couldn't get header\n");
}
else
{
copytext(0, stdout);
}
}
else
{
while (--argc > 0)
{
recover(*++argv);
}
}
exit(0);
}
/* This function recovers a single file */
recover(filename)
char *filename;
{
char tmpname[100];
int tmpfd;
FILE *fp;
long mtime;
int i, j;
/* get the file's status info */
if (stat(filename, &stbuf) < 0)
{
/* if serious error, give up on this file */
if (errno != ENOENT)
{
perror(filename);
return;
}
/* else fake it for a new file */
stat(".", &stbuf);
stbuf.st_mode = S_IFREG;
stbuf.st_mtime = 0L;
}
/* find the tmp file */
sprintf(tmpname, TMPNAME, o_directory, stbuf.st_ino, stbuf.st_dev);
tmpfd = open(tmpname, O_RDONLY);
if (tmpfd < 0)
{
perror(tmpname);
return;
}
/* make sure the file hasn't been modified more recently */
mtime = stbuf.st_mtime;
fstat(tmpfd, &stbuf);
if (stbuf.st_mtime < mtime)
{
printf("\"%s\" has been modified more recently than its recoverable version\n", filename);
puts("Do you still want to recover it?\n");
puts("\ty - Yes, discard the current version and recover it.\n");
puts("\tn - No, discard the recoverable version and keep the current version\n");
puts("\tq - Quit without doing anything for this file.\n");
puts("Enter y, n, or q --> ");
fflush(stdout);
for (;;)
{
switch (getchar())
{
case 'y':
case 'Y':
goto BreakBreak;
case 'n':
case 'N':
close(tmpfd);
unlink(tmpname);
return;
case 'q':
case 'Q':
close(tmpfd);
return;
}
}
BreakBreak:;
}
/* make sure this tmp file is intact */
if (read(tmpfd, &hdr, BLKSIZE) != BLKSIZE)
{
fprintf(stderr, "%s: bad header in tmp file\n", filename);
close(tmpfd);
unlink(tmpname);
return;
}
for (i = j = 1; i < MAXBLKS && hdr.n[i]; i++)
{
if (hdr.n[i] > j)
{
j = hdr.n[i];
}
}
lseek(tmpfd, (long)j * (long)BLKSIZE, 0);
if (read(tmpfd, &text, BLKSIZE) != BLKSIZE)
{
fprintf(stderr, "%s: bad data block in tmp file\n", filename);
close(tmpfd);
unlink(tmpname);
return;
}
/* open the normal text file for writing */
fp = fopen(filename, "w");
if (!fp)
{
perror(filename);
close(tmpfd);
return;
}
/* copy the text */
copytext(tmpfd, fp);
/* cleanup */
close(tmpfd);
fclose(fp);
unlink(tmpname);
}
/* This function moves text from the tmp file to the normal file */
copytext(tmpfd, fp)
int tmpfd; /* fd of the tmp file */
FILE *fp; /* the stream to write it to */
{
int i;
/* write the data blocks to the normal text file */
for (i = 1; i < MAXBLKS && hdr.n[i]; i++)
{
lseek(tmpfd, (long)hdr.n[i] * (long)BLKSIZE, 0);
read(tmpfd, &text, BLKSIZE);
fputs(text.c, fp);
}
}
#if MSDOS || TOS
#define WILDCARD_NO_MAIN
#include "wildcard.c"
#endif
SHAR_EOF
fi
if test -f 'wildcard.c'
then
echo shar: "will not over-write existing file 'wildcard.c'"
else
cat << \SHAR_EOF > 'wildcard.c'
/* wildcard.c */
/* Author:
* Guntram Blohm
* Buchenstrasse 19
* 7904 Erbach, West Germany
* Tel. ++49-7305-6997
* sorry - no regular network connection
*/
/* this program implements wildcard expansion for elvis/dos. It works
* like UNIX echo, but uses the dos wildcard conventions
* (*.* matches all files, * matches files without extension only,
* filespecs may contain drive letters, wildcards not allowed in directory
* names).
*
* It is also #included into ctags.c, ref.c, ...; in this case,
* we don't want a main function here.
*/
#include <stdio.h>
#include <ctype.h>
#ifdef __TURBOC__
#include <dir.h>
#endif
#ifdef M_I86
#define findfirst(a,b,c) _dos_findfirst(a,c,b)
#define findnext _dos_findnext
#define ffblk find_t
#define ff_name name
#include <dos.h>
#endif
#ifdef M68000
#include <stat.h>
#include <osbind.h>
#define findfirst(a,b,c) (Fsetdta(b), (Fsfirst(a,c)))
#define findnext(x) (Fsnext())
#define ff_name d_fname
#endif
#define MAXFILES 1000
int pstrcmp();
extern char *calloc();
char *files[MAXFILES];
int nfiles;
#ifndef WILDCARD_NO_MAIN
main(argc, argv)
char **argv;
{
int i;
for (i=1; i<argc; i++)
expand(argv[i]);
if (nfiles)
printf("%s", files[0]);
for (i=1; i<nfiles; i++)
{
printf(" %s", files[i]);
}
putchar('\n');
return 0;
}
#else
char **wildexpand(argc, argv)
int *argc;
char **argv;
{
int i;
for (i=0; i<*argc; i++)
expand(argv[i]);
*argc=nfiles;
return files;
}
#endif
expand(name)
char *name;
{
char *filespec;
int wildcard=0;
#ifdef M68000
DMABUFFER findbuf;
#else
struct ffblk findbuf;
#endif
int err;
char buf[80];
int lastn;
strcpy(buf, name);
for (filespec=buf; *filespec; filespec++)
;
while (--filespec>=buf)
{ if (*filespec=='?' || *filespec=='*')
wildcard=1;
if (*filespec=='/' || *filespec=='\\' || *filespec==':')
break;
}
if (!wildcard)
addfile(buf);
else
{
lastn=nfiles;
filespec++;
if ((err=findfirst(buf, &findbuf, 0))!=0)
addfile(buf);
while (!err)
{
strcpy(filespec, findbuf.ff_name);
addfile(buf);
err=findnext(&findbuf);
}
if (lastn!=nfiles)
qsort(files+lastn, nfiles-lastn, sizeof(char *), pstrcmp);
}
}
addfile(buf)
char *buf;
{
char *p;
for (p=buf; *p; p++)
*p=tolower(*p);
if (nfiles<MAXFILES && (files[nfiles]=calloc(strlen(buf)+1, 1))!=0)
strcpy(files[nfiles++], buf);
}
int pstrcmp(a, b)
char **a, **b;
{
return strcmp(*a, *b);
}
SHAR_EOF
fi
if test -f 'shell.c'
then
echo shar: "will not over-write existing file 'shell.c'"
else
cat << \SHAR_EOF > 'shell.c'
/* shell.c */
/* Author:
* Guntram Blohm
* Buchenstrasse 19
* 7904 Erbach, West Germany
* Tel. ++49-7305-6997
* sorry - no regular network connection
*/
/*
* This file contains a minimal version of a shell for TOS. It allows the
* setting of an environment, calling programs, and exiting.
* If you don't have another one, this might be sufficient, but you should
* prefer *any* other shell.
* You may, however, want to set your SHELL environment variable to this
* shell: it implements the -c switch, which is required by Elvis, and
* not supported by most other atari shells.
*/
#include <stdio.h>
#include <string.h>
#include <osbind.h>
extern char *getenv(), *malloc();
extern char **environ;
long _stksize=16384;
#define MAXENV 50
struct
{
char *name;
char *value;
} myenv[MAXENV];
int cmd_set(), cmd_exit();
struct buildins
{
char *name;
int (*func)();
} buildins[]=
{ "exit", cmd_exit,
"set", cmd_set,
0,
};
main(argc, argv)
int argc;
char **argv;
{
char buf[128];
int i;
for (i=0; environ[i] && strncmp(environ[i],"ARGV=",5); i++)
cmd_set(environ[i]);
script("profile.sh");
if (argc>1 && !strcmp(argv[1], "-c"))
{
buf[0]='\0';
for (i=2; i<argc; i++)
{ if (i>2)
strcat(buf, " ");
strcat(buf, argv[i]);
}
execute(buf);
}
else
while (fputs("$ ", stdout), gets(buf))
execute(buf);
}
execute(buf)
char *buf;
{
char *scan=buf;
char cmd[80];
char line[128];
char env[4096], *ep=env;
int i;
while (*scan==' ')
scan++;
if (!*scan)
return;
while (*scan && *scan!=' ')
scan++;
if (*scan)
*scan++='\0';
for (i=0; buildins[i].name; i++)
if (!strcmp(buf, buildins[i].name))
return (*buildins[i].func)(scan);
if (!searchpath(buf, cmd))
{ printf("%s: not found\n", buf);
return -1;
}
strcpy(line+1, scan);
line[0]=strlen(scan);
for (i=0; i<MAXENV && myenv[i].name; i++)
{ strcpy(ep, myenv[i].name);
strcat(ep, "=");
strcat(ep, myenv[i].value);
ep+=strlen(ep)+1;
}
*ep='\0';
return Pexec(0, cmd, line, env);
}
searchpath(from, to)
char *from, *to;
{
char *path="";
char *scan;
char *end;
char *q;
int i;
for (i=0; i<MAXENV && myenv[i].name; i++)
if (!strcmp(myenv[i].name,"PATH"))
path=myenv[i].value;
for (scan=from; *scan; scan++)
if (*scan==':' || *scan=='\\')
{ path=0;
break;
}
if (!path)
{ strcpy(to, from);
end=to+strlen(to);
strcpy(end, ".prg"); if (try(to)) return 1;
strcpy(end, ".ttp"); if (try(to)) return 1;
strcpy(end, ".tos"); if (try(to)) return 1;
*to='\0'; return 0;
}
for (scan=path; *scan; )
{
for (q=to; *scan && *scan!=';' && *scan!=','; scan++)
*q++=*scan;
if (*scan==';' || *scan==',')
scan++;
*q++='\\';
*q='\0';
strcpy(q, from);
end=q+strlen(q);
strcpy(end, ".prg"); if (try(to)) return 1;
strcpy(end, ".ttp"); if (try(to)) return 1;
strcpy(end, ".tos"); if (try(to)) return 1;
}
*to='\0';
return 0;
}
try(name)
char *name;
{
if (Fattrib(name, 0, 0) < 0)
return 0;
return 1;
}
cmd_exit()
{
exit(0);
}
cmd_set(line)
char *line;
{
char *value;
int i;
if (!*line)
{
for (i=0; i<MAXENV && myenv[i].name; i++)
printf("%s=%s\n", myenv[i].name, myenv[i].value);
return 0;
}
for (value=line; *value && *value!='='; value++)
;
if (!*value)
{ printf("Usage: set name=var\n");
return -1;
}
*value++='\0';
doset(line, value);
}
doset(line, value)
char *line, *value;
{
int i;
for (i=0; i<MAXENV && myenv[i].name && strcmp(myenv[i].name, line); i++)
;
if (i==MAXENV)
{ printf("No Space\n");
return -1;
}
if (!myenv[i].name)
{ myenv[i].name=malloc(strlen(line)+1);
strcpy(myenv[i].name, line);
}
if (myenv[i].value)
free(myenv[i].value);
myenv[i].value=malloc(strlen(value)+1);
strcpy(myenv[i].value, value);
return 0;
}
script(name)
char *name;
{
FILE *fp;
char buf[128], *p;
if ((fp=fopen(name, "r"))==0)
return;
while (fgets(buf, sizeof buf, fp))
{
if ((p=strchr(buf, '\n'))!=0)
*p='\0';
execute(buf);
}
fclose(fp);
}
SHAR_EOF
fi
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